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 unsigned int mxc_get_clock(enum mxc_clock clk) 117 { 118 if (clk >= MXC_CLK_NUM) 119 return -1; 120 switch (clk) { 121 case MXC_ARM_CLK: 122 return imx_get_armclk(); 123 case MXC_AHB_CLK: 124 return imx_get_ahbclk(); 125 case MXC_IPG_CLK: 126 case MXC_CSPI_CLK: 127 case MXC_FEC_CLK: 128 return imx_get_ipgclk(); 129 default: 130 return imx_get_perclk(clk); 131 } 132 } 133 134 u32 get_cpu_rev(void) 135 { 136 u32 srev; 137 u32 system_rev = 0x25000; 138 139 /* read SREV register from IIM module */ 140 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 141 srev = readl(&iim->iim_srev); 142 143 switch (srev) { 144 case 0x00: 145 system_rev |= CHIP_REV_1_0; 146 break; 147 case 0x01: 148 system_rev |= CHIP_REV_1_1; 149 break; 150 case 0x02: 151 system_rev |= CHIP_REV_1_2; 152 break; 153 default: 154 system_rev |= 0x8000; 155 break; 156 } 157 158 return system_rev; 159 } 160 161 #if defined(CONFIG_DISPLAY_CPUINFO) 162 static char *get_reset_cause(void) 163 { 164 /* read RCSR register from CCM module */ 165 struct ccm_regs *ccm = 166 (struct ccm_regs *)IMX_CCM_BASE; 167 168 u32 cause = readl(&ccm->rcsr) & 0x0f; 169 170 if (cause == 0) 171 return "POR"; 172 else if (cause == 1) 173 return "RST"; 174 else if ((cause & 2) == 2) 175 return "WDOG"; 176 else if ((cause & 4) == 4) 177 return "SW RESET"; 178 else if ((cause & 8) == 8) 179 return "JTAG"; 180 else 181 return "unknown reset"; 182 183 } 184 185 int print_cpuinfo(void) 186 { 187 char buf[32]; 188 u32 cpurev = get_cpu_rev(); 189 190 printf("CPU: Freescale i.MX25 rev%d.%d%s at %s MHz\n", 191 (cpurev & 0xF0) >> 4, (cpurev & 0x0F), 192 ((cpurev & 0x8000) ? " unknown" : ""), 193 strmhz(buf, imx_get_armclk())); 194 printf("Reset cause: %s\n", get_reset_cause()); 195 return 0; 196 } 197 #endif 198 199 void enable_caches(void) 200 { 201 #ifndef CONFIG_SYS_DCACHE_OFF 202 /* Enable D-cache. I-cache is already enabled in start.S */ 203 dcache_enable(); 204 #endif 205 } 206 207 #if defined(CONFIG_FEC_MXC) 208 /* 209 * Initializes on-chip ethernet controllers. 210 * to override, implement board_eth_init() 211 */ 212 int cpu_eth_init(bd_t *bis) 213 { 214 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 215 ulong val; 216 217 val = readl(&ccm->cgr0); 218 val |= (1 << 23); 219 writel(val, &ccm->cgr0); 220 return fecmxc_initialize(bis); 221 } 222 #endif 223 224 int get_clocks(void) 225 { 226 #ifdef CONFIG_FSL_ESDHC 227 #if CONFIG_SYS_FSL_ESDHC_ADDR == IMX_MMC_SDHC2_BASE 228 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); 229 #else 230 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK); 231 #endif 232 #endif 233 return 0; 234 } 235 236 #ifdef CONFIG_FSL_ESDHC 237 /* 238 * Initializes on-chip MMC controllers. 239 * to override, implement board_mmc_init() 240 */ 241 int cpu_mmc_init(bd_t *bis) 242 { 243 return fsl_esdhc_mmc_init(bis); 244 } 245 #endif 246 247 #ifdef CONFIG_FEC_MXC 248 void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) 249 { 250 int i; 251 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 252 struct fuse_bank *bank = &iim->bank[0]; 253 struct fuse_bank0_regs *fuse = 254 (struct fuse_bank0_regs *)bank->fuse_regs; 255 256 for (i = 0; i < 6; i++) 257 mac[i] = readl(&fuse->mac_addr[i]) & 0xff; 258 } 259 #endif /* CONFIG_FEC_MXC */ 260