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 */ 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 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 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 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 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 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 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 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 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) 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 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 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 */ 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 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 */ 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 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