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>
16fc5ad477SAdrian 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 */
imx_decode_pll(unsigned int pll,unsigned int f_ref)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
imx_get_mpllclk(void)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
imx_get_upllclk(void)61f7c13e6aSBenoît Thébaudeau static ulong imx_get_upllclk(void)
62f7c13e6aSBenoît Thébaudeau {
63f7c13e6aSBenoît Thébaudeau struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
64f7c13e6aSBenoît Thébaudeau ulong fref = MXC_HCLK;
65f7c13e6aSBenoît Thébaudeau
66f7c13e6aSBenoît Thébaudeau return imx_decode_pll(readl(&ccm->upctl), fref);
67f7c13e6aSBenoît Thébaudeau }
68f7c13e6aSBenoît Thébaudeau
imx_get_armclk(void)699baefa46SBenoît Thébaudeau static ulong imx_get_armclk(void)
7084ad6884SPeter Tyser {
7184ad6884SPeter Tyser struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
7284ad6884SPeter Tyser ulong cctl = readl(&ccm->cctl);
7384ad6884SPeter Tyser ulong fref = imx_get_mpllclk();
7484ad6884SPeter Tyser ulong div;
7584ad6884SPeter Tyser
7684ad6884SPeter Tyser if (cctl & CCM_CCTL_ARM_SRC)
77fac7c817SBenoît Thébaudeau fref = lldiv((u64) fref * 3, 4);
7884ad6884SPeter Tyser
7984ad6884SPeter Tyser div = ((cctl >> CCM_CCTL_ARM_DIV_SHIFT)
8084ad6884SPeter Tyser & CCM_CCTL_ARM_DIV_MASK) + 1;
8184ad6884SPeter Tyser
82fac7c817SBenoît Thébaudeau return fref / div;
8384ad6884SPeter Tyser }
8484ad6884SPeter Tyser
imx_get_ahbclk(void)859baefa46SBenoît Thébaudeau static ulong imx_get_ahbclk(void)
8684ad6884SPeter Tyser {
8784ad6884SPeter Tyser struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
8884ad6884SPeter Tyser ulong cctl = readl(&ccm->cctl);
8984ad6884SPeter Tyser ulong fref = imx_get_armclk();
9084ad6884SPeter Tyser ulong div;
9184ad6884SPeter Tyser
9284ad6884SPeter Tyser div = ((cctl >> CCM_CCTL_AHB_DIV_SHIFT)
9384ad6884SPeter Tyser & CCM_CCTL_AHB_DIV_MASK) + 1;
9484ad6884SPeter Tyser
95fac7c817SBenoît Thébaudeau return fref / div;
9684ad6884SPeter Tyser }
9784ad6884SPeter Tyser
imx_get_ipgclk(void)98c3b51890SBenoît Thébaudeau static ulong imx_get_ipgclk(void)
99c3b51890SBenoît Thébaudeau {
100c3b51890SBenoît Thébaudeau return imx_get_ahbclk() / 2;
101c3b51890SBenoît Thébaudeau }
102c3b51890SBenoît Thébaudeau
imx_get_perclk(int clk)1039baefa46SBenoît Thébaudeau static ulong imx_get_perclk(int clk)
10484ad6884SPeter Tyser {
10584ad6884SPeter Tyser struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
106f7c13e6aSBenoît Thébaudeau ulong fref = readl(&ccm->mcr) & (1 << clk) ? imx_get_upllclk() :
107f7c13e6aSBenoît Thébaudeau imx_get_ahbclk();
10884ad6884SPeter Tyser ulong div;
10984ad6884SPeter Tyser
11084ad6884SPeter Tyser div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]);
11184ad6884SPeter Tyser div = ((div >> CCM_PERCLK_SHIFT(clk)) & CCM_PERCLK_MASK) + 1;
11284ad6884SPeter Tyser
113fac7c817SBenoît Thébaudeau return fref / div;
11484ad6884SPeter Tyser }
11584ad6884SPeter Tyser
imx_set_perclk(enum mxc_clock clk,bool from_upll,unsigned int freq)116*3e3aab33SBenoît Thébaudeau int imx_set_perclk(enum mxc_clock clk, bool from_upll, unsigned int freq)
117*3e3aab33SBenoît Thébaudeau {
118*3e3aab33SBenoît Thébaudeau struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
119*3e3aab33SBenoît Thébaudeau ulong fref = from_upll ? imx_get_upllclk() : imx_get_ahbclk();
120*3e3aab33SBenoît Thébaudeau ulong div = (fref + freq - 1) / freq;
121*3e3aab33SBenoît Thébaudeau
122*3e3aab33SBenoît Thébaudeau if (clk > MXC_UART_CLK || !div || --div > CCM_PERCLK_MASK)
123*3e3aab33SBenoît Thébaudeau return -EINVAL;
124*3e3aab33SBenoît Thébaudeau
125*3e3aab33SBenoît Thébaudeau clrsetbits_le32(&ccm->pcdr[CCM_PERCLK_REG(clk)],
126*3e3aab33SBenoît Thébaudeau CCM_PERCLK_MASK << CCM_PERCLK_SHIFT(clk),
127*3e3aab33SBenoît Thébaudeau div << CCM_PERCLK_SHIFT(clk));
128*3e3aab33SBenoît Thébaudeau if (from_upll)
129*3e3aab33SBenoît Thébaudeau setbits_le32(&ccm->mcr, 1 << clk);
130*3e3aab33SBenoît Thébaudeau else
131*3e3aab33SBenoît Thébaudeau clrbits_le32(&ccm->mcr, 1 << clk);
132*3e3aab33SBenoît Thébaudeau return 0;
133*3e3aab33SBenoît Thébaudeau }
134*3e3aab33SBenoît Thébaudeau
mxc_get_clock(enum mxc_clock clk)13542d25327STimo Ketola unsigned int mxc_get_clock(enum mxc_clock clk)
13642d25327STimo Ketola {
13742d25327STimo Ketola if (clk >= MXC_CLK_NUM)
13842d25327STimo Ketola return -1;
13942d25327STimo Ketola switch (clk) {
14042d25327STimo Ketola case MXC_ARM_CLK:
14142d25327STimo Ketola return imx_get_armclk();
142c3b51890SBenoît Thébaudeau case MXC_AHB_CLK:
143c3b51890SBenoît Thébaudeau return imx_get_ahbclk();
144c3b51890SBenoît Thébaudeau case MXC_IPG_CLK:
145c3b51890SBenoît Thébaudeau case MXC_CSPI_CLK:
14642d25327STimo Ketola case MXC_FEC_CLK:
14717c7cf71SBenoît Thébaudeau return imx_get_ipgclk();
14842d25327STimo Ketola default:
14942d25327STimo Ketola return imx_get_perclk(clk);
15042d25327STimo Ketola }
15142d25327STimo Ketola }
15242d25327STimo Ketola
get_cpu_rev(void)153986d0d1bSFabio Estevam u32 get_cpu_rev(void)
154986d0d1bSFabio Estevam {
155986d0d1bSFabio Estevam u32 srev;
156986d0d1bSFabio Estevam u32 system_rev = 0x25000;
157986d0d1bSFabio Estevam
158986d0d1bSFabio Estevam /* read SREV register from IIM module */
159986d0d1bSFabio Estevam struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
160986d0d1bSFabio Estevam srev = readl(&iim->iim_srev);
161986d0d1bSFabio Estevam
162986d0d1bSFabio Estevam switch (srev) {
163986d0d1bSFabio Estevam case 0x00:
164986d0d1bSFabio Estevam system_rev |= CHIP_REV_1_0;
165986d0d1bSFabio Estevam break;
166986d0d1bSFabio Estevam case 0x01:
167986d0d1bSFabio Estevam system_rev |= CHIP_REV_1_1;
168986d0d1bSFabio Estevam break;
1698a57fdc6SEric Benard case 0x02:
1708a57fdc6SEric Benard system_rev |= CHIP_REV_1_2;
1718a57fdc6SEric Benard break;
172986d0d1bSFabio Estevam default:
173986d0d1bSFabio Estevam system_rev |= 0x8000;
174986d0d1bSFabio Estevam break;
175986d0d1bSFabio Estevam }
176986d0d1bSFabio Estevam
177986d0d1bSFabio Estevam return system_rev;
178986d0d1bSFabio Estevam }
179986d0d1bSFabio Estevam
18084ad6884SPeter Tyser #if defined(CONFIG_DISPLAY_CPUINFO)
get_reset_cause(void)181e6ec1761SFabio Estevam static char *get_reset_cause(void)
182e6ec1761SFabio Estevam {
183e6ec1761SFabio Estevam /* read RCSR register from CCM module */
184e6ec1761SFabio Estevam struct ccm_regs *ccm =
185e6ec1761SFabio Estevam (struct ccm_regs *)IMX_CCM_BASE;
186e6ec1761SFabio Estevam
187e6ec1761SFabio Estevam u32 cause = readl(&ccm->rcsr) & 0x0f;
188e6ec1761SFabio Estevam
189e6ec1761SFabio Estevam if (cause == 0)
190e6ec1761SFabio Estevam return "POR";
191e6ec1761SFabio Estevam else if (cause == 1)
192e6ec1761SFabio Estevam return "RST";
193e6ec1761SFabio Estevam else if ((cause & 2) == 2)
194e6ec1761SFabio Estevam return "WDOG";
195e6ec1761SFabio Estevam else if ((cause & 4) == 4)
196e6ec1761SFabio Estevam return "SW RESET";
197e6ec1761SFabio Estevam else if ((cause & 8) == 8)
198e6ec1761SFabio Estevam return "JTAG";
199e6ec1761SFabio Estevam else
200e6ec1761SFabio Estevam return "unknown reset";
201e6ec1761SFabio Estevam
202e6ec1761SFabio Estevam }
203e6ec1761SFabio Estevam
print_cpuinfo(void)20484ad6884SPeter Tyser int print_cpuinfo(void)
20584ad6884SPeter Tyser {
20684ad6884SPeter Tyser char buf[32];
207986d0d1bSFabio Estevam u32 cpurev = get_cpu_rev();
20884ad6884SPeter Tyser
209957dc024SFabio Estevam printf("CPU: Freescale i.MX25 rev%d.%d%s at %s MHz\n",
210986d0d1bSFabio Estevam (cpurev & 0xF0) >> 4, (cpurev & 0x0F),
211986d0d1bSFabio Estevam ((cpurev & 0x8000) ? " unknown" : ""),
21234196b0aSJohn Rigby strmhz(buf, imx_get_armclk()));
2138ed5e4ceSFabio Estevam printf("Reset cause: %s\n", get_reset_cause());
21484ad6884SPeter Tyser return 0;
21584ad6884SPeter Tyser }
21684ad6884SPeter Tyser #endif
21784ad6884SPeter Tyser
enable_caches(void)218e107c7e9SBenoît Thébaudeau void enable_caches(void)
219e107c7e9SBenoît Thébaudeau {
220e107c7e9SBenoît Thébaudeau #ifndef CONFIG_SYS_DCACHE_OFF
221e107c7e9SBenoît Thébaudeau /* Enable D-cache. I-cache is already enabled in start.S */
222e107c7e9SBenoît Thébaudeau dcache_enable();
223e107c7e9SBenoît Thébaudeau #endif
224e107c7e9SBenoît Thébaudeau }
225e107c7e9SBenoît Thébaudeau
226f7542638SBenoît Thébaudeau #if defined(CONFIG_FEC_MXC)
227f7542638SBenoît Thébaudeau /*
228f7542638SBenoît Thébaudeau * Initializes on-chip ethernet controllers.
229f7542638SBenoît Thébaudeau * to override, implement board_eth_init()
230f7542638SBenoît Thébaudeau */
cpu_eth_init(bd_t * bis)23184ad6884SPeter Tyser int cpu_eth_init(bd_t *bis)
23284ad6884SPeter Tyser {
23384ad6884SPeter Tyser struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
23484ad6884SPeter Tyser ulong val;
23584ad6884SPeter Tyser
23684ad6884SPeter Tyser val = readl(&ccm->cgr0);
23784ad6884SPeter Tyser val |= (1 << 23);
23884ad6884SPeter Tyser writel(val, &ccm->cgr0);
23984ad6884SPeter Tyser return fecmxc_initialize(bis);
24084ad6884SPeter Tyser }
241f7542638SBenoît Thébaudeau #endif
24284ad6884SPeter Tyser
get_clocks(void)24342d25327STimo Ketola int get_clocks(void)
24442d25327STimo Ketola {
24542d25327STimo Ketola #ifdef CONFIG_FSL_ESDHC
2466be58005SBenoît Thébaudeau #if CONFIG_SYS_FSL_ESDHC_ADDR == IMX_MMC_SDHC2_BASE
247e9adeca3SSimon Glass gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
2486be58005SBenoît Thébaudeau #else
249e9adeca3SSimon Glass gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK);
2506be58005SBenoît Thébaudeau #endif
25142d25327STimo Ketola #endif
25242d25327STimo Ketola return 0;
25342d25327STimo Ketola }
25442d25327STimo Ketola
2556be58005SBenoît Thébaudeau #ifdef CONFIG_FSL_ESDHC
25684ad6884SPeter Tyser /*
25784ad6884SPeter Tyser * Initializes on-chip MMC controllers.
25884ad6884SPeter Tyser * to override, implement board_mmc_init()
25984ad6884SPeter Tyser */
cpu_mmc_init(bd_t * bis)26084ad6884SPeter Tyser int cpu_mmc_init(bd_t *bis)
26184ad6884SPeter Tyser {
2626be58005SBenoît Thébaudeau return fsl_esdhc_mmc_init(bis);
26384ad6884SPeter Tyser }
2646be58005SBenoît Thébaudeau #endif
26584ad6884SPeter Tyser
26684ad6884SPeter Tyser #ifdef CONFIG_FEC_MXC
imx_get_mac_from_fuse(int dev_id,unsigned char * mac)267be252b65SFabio Estevam void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
268565e39c5SLiu Hui-R64343 {
269565e39c5SLiu Hui-R64343 int i;
270565e39c5SLiu Hui-R64343 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
271565e39c5SLiu Hui-R64343 struct fuse_bank *bank = &iim->bank[0];
272565e39c5SLiu Hui-R64343 struct fuse_bank0_regs *fuse =
273565e39c5SLiu Hui-R64343 (struct fuse_bank0_regs *)bank->fuse_regs;
274565e39c5SLiu Hui-R64343
275565e39c5SLiu Hui-R64343 for (i = 0; i < 6; i++)
276565e39c5SLiu Hui-R64343 mac[i] = readl(&fuse->mac_addr[i]) & 0xff;
277565e39c5SLiu Hui-R64343 }
27884ad6884SPeter Tyser #endif /* CONFIG_FEC_MXC */
279