xref: /rk3399_rockchip-uboot/arch/arm/cpu/arm926ejs/mx25/generic.c (revision fc5ad4778d91dabbeca3bc05a78cb669686f0a9c)
184ad6884SPeter Tyser /*
284ad6884SPeter Tyser  * (C) Copyright 2009 DENX Software Engineering
384ad6884SPeter Tyser  * Author: John Rigby <jrigby@gmail.com>
484ad6884SPeter Tyser  *
584ad6884SPeter Tyser  * Based on mx27/generic.c:
684ad6884SPeter Tyser  *  Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org>
784ad6884SPeter Tyser  *  Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com>
884ad6884SPeter Tyser  *
91a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
1084ad6884SPeter Tyser  */
1184ad6884SPeter Tyser 
1284ad6884SPeter Tyser #include <common.h>
1384ad6884SPeter Tyser #include <div64.h>
1484ad6884SPeter Tyser #include <netdev.h>
1584ad6884SPeter Tyser #include <asm/io.h>
16*fc5ad477SAdrian Alonso #include <asm/arch-imx/cpu.h>
1784ad6884SPeter Tyser #include <asm/arch/imx-regs.h>
1842d25327STimo Ketola #include <asm/arch/clock.h>
1984ad6884SPeter Tyser 
2042d25327STimo Ketola #ifdef CONFIG_FSL_ESDHC
216be58005SBenoît Thébaudeau #include <fsl_esdhc.h>
226be58005SBenoît Thébaudeau 
2342d25327STimo Ketola DECLARE_GLOBAL_DATA_PTR;
2442d25327STimo Ketola #endif
2542d25327STimo Ketola 
2684ad6884SPeter Tyser /*
2784ad6884SPeter Tyser  *  get the system pll clock in Hz
2884ad6884SPeter Tyser  *
2984ad6884SPeter Tyser  *                  mfi + mfn / (mfd +1)
3084ad6884SPeter Tyser  *  f = 2 * f_ref * --------------------
3184ad6884SPeter Tyser  *                        pd + 1
3284ad6884SPeter Tyser  */
3384ad6884SPeter Tyser static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref)
3484ad6884SPeter Tyser {
3584ad6884SPeter Tyser 	unsigned int mfi = (pll >> CCM_PLL_MFI_SHIFT)
3684ad6884SPeter Tyser 	    & CCM_PLL_MFI_MASK;
373c76add2SBenoît Thébaudeau 	int mfn = (pll >> CCM_PLL_MFN_SHIFT)
3884ad6884SPeter Tyser 	    & CCM_PLL_MFN_MASK;
3984ad6884SPeter Tyser 	unsigned int mfd = (pll >> CCM_PLL_MFD_SHIFT)
4084ad6884SPeter Tyser 	    & CCM_PLL_MFD_MASK;
4184ad6884SPeter Tyser 	unsigned int pd = (pll >> CCM_PLL_PD_SHIFT)
4284ad6884SPeter Tyser 	    & CCM_PLL_PD_MASK;
4384ad6884SPeter Tyser 
4484ad6884SPeter Tyser 	mfi = mfi <= 5 ? 5 : mfi;
453c76add2SBenoît Thébaudeau 	mfn = mfn >= 512 ? mfn - 1024 : mfn;
463c76add2SBenoît Thébaudeau 	mfd += 1;
473c76add2SBenoît Thébaudeau 	pd += 1;
4884ad6884SPeter Tyser 
493c76add2SBenoît Thébaudeau 	return lldiv(2 * (u64) f_ref * (mfi * mfd + mfn),
503c76add2SBenoît Thébaudeau 		     mfd * pd);
5184ad6884SPeter Tyser }
5284ad6884SPeter Tyser 
5384ad6884SPeter Tyser static ulong imx_get_mpllclk(void)
5484ad6884SPeter Tyser {
5584ad6884SPeter Tyser 	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
561b2080f3SBenoît Thébaudeau 	ulong fref = MXC_HCLK;
5784ad6884SPeter Tyser 
5884ad6884SPeter Tyser 	return imx_decode_pll(readl(&ccm->mpctl), fref);
5984ad6884SPeter Tyser }
6084ad6884SPeter Tyser 
619baefa46SBenoît Thébaudeau static ulong imx_get_armclk(void)
6284ad6884SPeter Tyser {
6384ad6884SPeter Tyser 	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
6484ad6884SPeter Tyser 	ulong cctl = readl(&ccm->cctl);
6584ad6884SPeter Tyser 	ulong fref = imx_get_mpllclk();
6684ad6884SPeter Tyser 	ulong div;
6784ad6884SPeter Tyser 
6884ad6884SPeter Tyser 	if (cctl & CCM_CCTL_ARM_SRC)
69fac7c817SBenoît Thébaudeau 		fref = lldiv((u64) fref * 3, 4);
7084ad6884SPeter Tyser 
7184ad6884SPeter Tyser 	div = ((cctl >> CCM_CCTL_ARM_DIV_SHIFT)
7284ad6884SPeter Tyser 	       & CCM_CCTL_ARM_DIV_MASK) + 1;
7384ad6884SPeter Tyser 
74fac7c817SBenoît Thébaudeau 	return fref / div;
7584ad6884SPeter Tyser }
7684ad6884SPeter Tyser 
779baefa46SBenoît Thébaudeau static ulong imx_get_ahbclk(void)
7884ad6884SPeter Tyser {
7984ad6884SPeter Tyser 	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
8084ad6884SPeter Tyser 	ulong cctl = readl(&ccm->cctl);
8184ad6884SPeter Tyser 	ulong fref = imx_get_armclk();
8284ad6884SPeter Tyser 	ulong div;
8384ad6884SPeter Tyser 
8484ad6884SPeter Tyser 	div = ((cctl >> CCM_CCTL_AHB_DIV_SHIFT)
8584ad6884SPeter Tyser 	       & CCM_CCTL_AHB_DIV_MASK) + 1;
8684ad6884SPeter Tyser 
87fac7c817SBenoît Thébaudeau 	return fref / div;
8884ad6884SPeter Tyser }
8984ad6884SPeter Tyser 
90c3b51890SBenoît Thébaudeau static ulong imx_get_ipgclk(void)
91c3b51890SBenoît Thébaudeau {
92c3b51890SBenoît Thébaudeau 	return imx_get_ahbclk() / 2;
93c3b51890SBenoît Thébaudeau }
94c3b51890SBenoît Thébaudeau 
959baefa46SBenoît Thébaudeau static ulong imx_get_perclk(int clk)
9684ad6884SPeter Tyser {
9784ad6884SPeter Tyser 	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
9884ad6884SPeter Tyser 	ulong fref = imx_get_ahbclk();
9984ad6884SPeter Tyser 	ulong div;
10084ad6884SPeter Tyser 
10184ad6884SPeter Tyser 	div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]);
10284ad6884SPeter Tyser 	div = ((div >> CCM_PERCLK_SHIFT(clk)) & CCM_PERCLK_MASK) + 1;
10384ad6884SPeter Tyser 
104fac7c817SBenoît Thébaudeau 	return fref / div;
10584ad6884SPeter Tyser }
10684ad6884SPeter Tyser 
10742d25327STimo Ketola unsigned int mxc_get_clock(enum mxc_clock clk)
10842d25327STimo Ketola {
10942d25327STimo Ketola 	if (clk >= MXC_CLK_NUM)
11042d25327STimo Ketola 		return -1;
11142d25327STimo Ketola 	switch (clk) {
11242d25327STimo Ketola 	case MXC_ARM_CLK:
11342d25327STimo Ketola 		return imx_get_armclk();
114c3b51890SBenoît Thébaudeau 	case MXC_AHB_CLK:
115c3b51890SBenoît Thébaudeau 		return imx_get_ahbclk();
116c3b51890SBenoît Thébaudeau 	case MXC_IPG_CLK:
117c3b51890SBenoît Thébaudeau 	case MXC_CSPI_CLK:
11842d25327STimo Ketola 	case MXC_FEC_CLK:
11917c7cf71SBenoît Thébaudeau 		return imx_get_ipgclk();
12042d25327STimo Ketola 	default:
12142d25327STimo Ketola 		return imx_get_perclk(clk);
12242d25327STimo Ketola 	}
12342d25327STimo Ketola }
12442d25327STimo Ketola 
125986d0d1bSFabio Estevam u32 get_cpu_rev(void)
126986d0d1bSFabio Estevam {
127986d0d1bSFabio Estevam 	u32 srev;
128986d0d1bSFabio Estevam 	u32 system_rev = 0x25000;
129986d0d1bSFabio Estevam 
130986d0d1bSFabio Estevam 	/* read SREV register from IIM module */
131986d0d1bSFabio Estevam 	struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
132986d0d1bSFabio Estevam 	srev = readl(&iim->iim_srev);
133986d0d1bSFabio Estevam 
134986d0d1bSFabio Estevam 	switch (srev) {
135986d0d1bSFabio Estevam 	case 0x00:
136986d0d1bSFabio Estevam 		system_rev |= CHIP_REV_1_0;
137986d0d1bSFabio Estevam 		break;
138986d0d1bSFabio Estevam 	case 0x01:
139986d0d1bSFabio Estevam 		system_rev |= CHIP_REV_1_1;
140986d0d1bSFabio Estevam 		break;
1418a57fdc6SEric Benard 	case 0x02:
1428a57fdc6SEric Benard 		system_rev |= CHIP_REV_1_2;
1438a57fdc6SEric Benard 		break;
144986d0d1bSFabio Estevam 	default:
145986d0d1bSFabio Estevam 		system_rev |= 0x8000;
146986d0d1bSFabio Estevam 		break;
147986d0d1bSFabio Estevam 	}
148986d0d1bSFabio Estevam 
149986d0d1bSFabio Estevam 	return system_rev;
150986d0d1bSFabio Estevam }
151986d0d1bSFabio Estevam 
15284ad6884SPeter Tyser #if defined(CONFIG_DISPLAY_CPUINFO)
153e6ec1761SFabio Estevam static char *get_reset_cause(void)
154e6ec1761SFabio Estevam {
155e6ec1761SFabio Estevam 	/* read RCSR register from CCM module */
156e6ec1761SFabio Estevam 	struct ccm_regs *ccm =
157e6ec1761SFabio Estevam 		(struct ccm_regs *)IMX_CCM_BASE;
158e6ec1761SFabio Estevam 
159e6ec1761SFabio Estevam 	u32 cause = readl(&ccm->rcsr) & 0x0f;
160e6ec1761SFabio Estevam 
161e6ec1761SFabio Estevam 	if (cause == 0)
162e6ec1761SFabio Estevam 		return "POR";
163e6ec1761SFabio Estevam 	else if (cause == 1)
164e6ec1761SFabio Estevam 		return "RST";
165e6ec1761SFabio Estevam 	else if ((cause & 2) == 2)
166e6ec1761SFabio Estevam 		return "WDOG";
167e6ec1761SFabio Estevam 	else if ((cause & 4) == 4)
168e6ec1761SFabio Estevam 		return "SW RESET";
169e6ec1761SFabio Estevam 	else if ((cause & 8) == 8)
170e6ec1761SFabio Estevam 		return "JTAG";
171e6ec1761SFabio Estevam 	else
172e6ec1761SFabio Estevam 		return "unknown reset";
173e6ec1761SFabio Estevam 
174e6ec1761SFabio Estevam }
175e6ec1761SFabio Estevam 
17684ad6884SPeter Tyser int print_cpuinfo(void)
17784ad6884SPeter Tyser {
17884ad6884SPeter Tyser 	char buf[32];
179986d0d1bSFabio Estevam 	u32 cpurev = get_cpu_rev();
18084ad6884SPeter Tyser 
181957dc024SFabio Estevam 	printf("CPU:   Freescale i.MX25 rev%d.%d%s at %s MHz\n",
182986d0d1bSFabio Estevam 		(cpurev & 0xF0) >> 4, (cpurev & 0x0F),
183986d0d1bSFabio Estevam 		((cpurev & 0x8000) ? " unknown" : ""),
18434196b0aSJohn Rigby 		strmhz(buf, imx_get_armclk()));
1858ed5e4ceSFabio Estevam 	printf("Reset cause: %s\n", get_reset_cause());
18684ad6884SPeter Tyser 	return 0;
18784ad6884SPeter Tyser }
18884ad6884SPeter Tyser #endif
18984ad6884SPeter Tyser 
190e107c7e9SBenoît Thébaudeau void enable_caches(void)
191e107c7e9SBenoît Thébaudeau {
192e107c7e9SBenoît Thébaudeau #ifndef CONFIG_SYS_DCACHE_OFF
193e107c7e9SBenoît Thébaudeau 	/* Enable D-cache. I-cache is already enabled in start.S */
194e107c7e9SBenoît Thébaudeau 	dcache_enable();
195e107c7e9SBenoît Thébaudeau #endif
196e107c7e9SBenoît Thébaudeau }
197e107c7e9SBenoît Thébaudeau 
198f7542638SBenoît Thébaudeau #if defined(CONFIG_FEC_MXC)
199f7542638SBenoît Thébaudeau /*
200f7542638SBenoît Thébaudeau  * Initializes on-chip ethernet controllers.
201f7542638SBenoît Thébaudeau  * to override, implement board_eth_init()
202f7542638SBenoît Thébaudeau  */
20384ad6884SPeter Tyser int cpu_eth_init(bd_t *bis)
20484ad6884SPeter Tyser {
20584ad6884SPeter Tyser 	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
20684ad6884SPeter Tyser 	ulong val;
20784ad6884SPeter Tyser 
20884ad6884SPeter Tyser 	val = readl(&ccm->cgr0);
20984ad6884SPeter Tyser 	val |= (1 << 23);
21084ad6884SPeter Tyser 	writel(val, &ccm->cgr0);
21184ad6884SPeter Tyser 	return fecmxc_initialize(bis);
21284ad6884SPeter Tyser }
213f7542638SBenoît Thébaudeau #endif
21484ad6884SPeter Tyser 
21542d25327STimo Ketola int get_clocks(void)
21642d25327STimo Ketola {
21742d25327STimo Ketola #ifdef CONFIG_FSL_ESDHC
2186be58005SBenoît Thébaudeau #if CONFIG_SYS_FSL_ESDHC_ADDR == IMX_MMC_SDHC2_BASE
219e9adeca3SSimon Glass 	gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
2206be58005SBenoît Thébaudeau #else
221e9adeca3SSimon Glass 	gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK);
2226be58005SBenoît Thébaudeau #endif
22342d25327STimo Ketola #endif
22442d25327STimo Ketola 	return 0;
22542d25327STimo Ketola }
22642d25327STimo Ketola 
2276be58005SBenoît Thébaudeau #ifdef CONFIG_FSL_ESDHC
22884ad6884SPeter Tyser /*
22984ad6884SPeter Tyser  * Initializes on-chip MMC controllers.
23084ad6884SPeter Tyser  * to override, implement board_mmc_init()
23184ad6884SPeter Tyser  */
23284ad6884SPeter Tyser int cpu_mmc_init(bd_t *bis)
23384ad6884SPeter Tyser {
2346be58005SBenoît Thébaudeau 	return fsl_esdhc_mmc_init(bis);
23584ad6884SPeter Tyser }
2366be58005SBenoît Thébaudeau #endif
23784ad6884SPeter Tyser 
23884ad6884SPeter Tyser #ifdef CONFIG_FEC_MXC
239be252b65SFabio Estevam void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
240565e39c5SLiu Hui-R64343 {
241565e39c5SLiu Hui-R64343 	int i;
242565e39c5SLiu Hui-R64343 	struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
243565e39c5SLiu Hui-R64343 	struct fuse_bank *bank = &iim->bank[0];
244565e39c5SLiu Hui-R64343 	struct fuse_bank0_regs *fuse =
245565e39c5SLiu Hui-R64343 			(struct fuse_bank0_regs *)bank->fuse_regs;
246565e39c5SLiu Hui-R64343 
247565e39c5SLiu Hui-R64343 	for (i = 0; i < 6; i++)
248565e39c5SLiu Hui-R64343 		mac[i] = readl(&fuse->mac_addr[i]) & 0xff;
249565e39c5SLiu Hui-R64343 }
25084ad6884SPeter Tyser #endif /* CONFIG_FEC_MXC */
251