1 /* 2 * (C) Copyright 2009 DENX Software Engineering 3 * Author: John Rigby <jrigby@gmail.com> 4 * 5 * Based on mx27/generic.c: 6 * Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org> 7 * Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com> 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <div64.h> 14 #include <netdev.h> 15 #include <asm/io.h> 16 #include <asm/arch-imx/cpu.h> 17 #include <asm/arch/imx-regs.h> 18 #include <asm/arch/clock.h> 19 20 #ifdef CONFIG_FSL_ESDHC 21 #include <fsl_esdhc.h> 22 23 DECLARE_GLOBAL_DATA_PTR; 24 #endif 25 26 /* 27 * get the system pll clock in Hz 28 * 29 * mfi + mfn / (mfd +1) 30 * f = 2 * f_ref * -------------------- 31 * pd + 1 32 */ 33 static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref) 34 { 35 unsigned int mfi = (pll >> CCM_PLL_MFI_SHIFT) 36 & CCM_PLL_MFI_MASK; 37 int mfn = (pll >> CCM_PLL_MFN_SHIFT) 38 & CCM_PLL_MFN_MASK; 39 unsigned int mfd = (pll >> CCM_PLL_MFD_SHIFT) 40 & CCM_PLL_MFD_MASK; 41 unsigned int pd = (pll >> CCM_PLL_PD_SHIFT) 42 & CCM_PLL_PD_MASK; 43 44 mfi = mfi <= 5 ? 5 : mfi; 45 mfn = mfn >= 512 ? mfn - 1024 : mfn; 46 mfd += 1; 47 pd += 1; 48 49 return lldiv(2 * (u64) f_ref * (mfi * mfd + mfn), 50 mfd * pd); 51 } 52 53 static ulong imx_get_mpllclk(void) 54 { 55 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 56 ulong fref = MXC_HCLK; 57 58 return imx_decode_pll(readl(&ccm->mpctl), fref); 59 } 60 61 static ulong imx_get_upllclk(void) 62 { 63 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 64 ulong fref = MXC_HCLK; 65 66 return imx_decode_pll(readl(&ccm->upctl), fref); 67 } 68 69 static ulong imx_get_armclk(void) 70 { 71 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 72 ulong cctl = readl(&ccm->cctl); 73 ulong fref = imx_get_mpllclk(); 74 ulong div; 75 76 if (cctl & CCM_CCTL_ARM_SRC) 77 fref = lldiv((u64) fref * 3, 4); 78 79 div = ((cctl >> CCM_CCTL_ARM_DIV_SHIFT) 80 & CCM_CCTL_ARM_DIV_MASK) + 1; 81 82 return fref / div; 83 } 84 85 static ulong imx_get_ahbclk(void) 86 { 87 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 88 ulong cctl = readl(&ccm->cctl); 89 ulong fref = imx_get_armclk(); 90 ulong div; 91 92 div = ((cctl >> CCM_CCTL_AHB_DIV_SHIFT) 93 & CCM_CCTL_AHB_DIV_MASK) + 1; 94 95 return fref / div; 96 } 97 98 static ulong imx_get_ipgclk(void) 99 { 100 return imx_get_ahbclk() / 2; 101 } 102 103 static ulong imx_get_perclk(int clk) 104 { 105 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 106 ulong fref = readl(&ccm->mcr) & (1 << clk) ? imx_get_upllclk() : 107 imx_get_ahbclk(); 108 ulong div; 109 110 div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]); 111 div = ((div >> CCM_PERCLK_SHIFT(clk)) & CCM_PERCLK_MASK) + 1; 112 113 return fref / div; 114 } 115 116 int imx_set_perclk(enum mxc_clock clk, bool from_upll, unsigned int freq) 117 { 118 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 119 ulong fref = from_upll ? imx_get_upllclk() : imx_get_ahbclk(); 120 ulong div = (fref + freq - 1) / freq; 121 122 if (clk > MXC_UART_CLK || !div || --div > CCM_PERCLK_MASK) 123 return -EINVAL; 124 125 clrsetbits_le32(&ccm->pcdr[CCM_PERCLK_REG(clk)], 126 CCM_PERCLK_MASK << CCM_PERCLK_SHIFT(clk), 127 div << CCM_PERCLK_SHIFT(clk)); 128 if (from_upll) 129 setbits_le32(&ccm->mcr, 1 << clk); 130 else 131 clrbits_le32(&ccm->mcr, 1 << clk); 132 return 0; 133 } 134 135 unsigned int mxc_get_clock(enum mxc_clock clk) 136 { 137 if (clk >= MXC_CLK_NUM) 138 return -1; 139 switch (clk) { 140 case MXC_ARM_CLK: 141 return imx_get_armclk(); 142 case MXC_AHB_CLK: 143 return imx_get_ahbclk(); 144 case MXC_IPG_CLK: 145 case MXC_CSPI_CLK: 146 case MXC_FEC_CLK: 147 return imx_get_ipgclk(); 148 default: 149 return imx_get_perclk(clk); 150 } 151 } 152 153 u32 get_cpu_rev(void) 154 { 155 u32 srev; 156 u32 system_rev = 0x25000; 157 158 /* read SREV register from IIM module */ 159 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 160 srev = readl(&iim->iim_srev); 161 162 switch (srev) { 163 case 0x00: 164 system_rev |= CHIP_REV_1_0; 165 break; 166 case 0x01: 167 system_rev |= CHIP_REV_1_1; 168 break; 169 case 0x02: 170 system_rev |= CHIP_REV_1_2; 171 break; 172 default: 173 system_rev |= 0x8000; 174 break; 175 } 176 177 return system_rev; 178 } 179 180 #if defined(CONFIG_DISPLAY_CPUINFO) 181 static char *get_reset_cause(void) 182 { 183 /* read RCSR register from CCM module */ 184 struct ccm_regs *ccm = 185 (struct ccm_regs *)IMX_CCM_BASE; 186 187 u32 cause = readl(&ccm->rcsr) & 0x0f; 188 189 if (cause == 0) 190 return "POR"; 191 else if (cause == 1) 192 return "RST"; 193 else if ((cause & 2) == 2) 194 return "WDOG"; 195 else if ((cause & 4) == 4) 196 return "SW RESET"; 197 else if ((cause & 8) == 8) 198 return "JTAG"; 199 else 200 return "unknown reset"; 201 202 } 203 204 int print_cpuinfo(void) 205 { 206 char buf[32]; 207 u32 cpurev = get_cpu_rev(); 208 209 printf("CPU: Freescale i.MX25 rev%d.%d%s at %s MHz\n", 210 (cpurev & 0xF0) >> 4, (cpurev & 0x0F), 211 ((cpurev & 0x8000) ? " unknown" : ""), 212 strmhz(buf, imx_get_armclk())); 213 printf("Reset cause: %s\n", get_reset_cause()); 214 return 0; 215 } 216 #endif 217 218 void enable_caches(void) 219 { 220 #ifndef CONFIG_SYS_DCACHE_OFF 221 /* Enable D-cache. I-cache is already enabled in start.S */ 222 dcache_enable(); 223 #endif 224 } 225 226 #if defined(CONFIG_FEC_MXC) 227 /* 228 * Initializes on-chip ethernet controllers. 229 * to override, implement board_eth_init() 230 */ 231 int cpu_eth_init(bd_t *bis) 232 { 233 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 234 ulong val; 235 236 val = readl(&ccm->cgr0); 237 val |= (1 << 23); 238 writel(val, &ccm->cgr0); 239 return fecmxc_initialize(bis); 240 } 241 #endif 242 243 int get_clocks(void) 244 { 245 #ifdef CONFIG_FSL_ESDHC 246 #if CONFIG_SYS_FSL_ESDHC_ADDR == IMX_MMC_SDHC2_BASE 247 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); 248 #else 249 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK); 250 #endif 251 #endif 252 return 0; 253 } 254 255 #ifdef CONFIG_FSL_ESDHC 256 /* 257 * Initializes on-chip MMC controllers. 258 * to override, implement board_mmc_init() 259 */ 260 int cpu_mmc_init(bd_t *bis) 261 { 262 return fsl_esdhc_mmc_init(bis); 263 } 264 #endif 265 266 #ifdef CONFIG_FEC_MXC 267 void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) 268 { 269 int i; 270 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 271 struct fuse_bank *bank = &iim->bank[0]; 272 struct fuse_bank0_regs *fuse = 273 (struct fuse_bank0_regs *)bank->fuse_regs; 274 275 for (i = 0; i < 6; i++) 276 mac[i] = readl(&fuse->mac_addr[i]) & 0xff; 277 } 278 #endif /* CONFIG_FEC_MXC */ 279