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_armclk(void) 62 { 63 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 64 ulong cctl = readl(&ccm->cctl); 65 ulong fref = imx_get_mpllclk(); 66 ulong div; 67 68 if (cctl & CCM_CCTL_ARM_SRC) 69 fref = lldiv((u64) fref * 3, 4); 70 71 div = ((cctl >> CCM_CCTL_ARM_DIV_SHIFT) 72 & CCM_CCTL_ARM_DIV_MASK) + 1; 73 74 return fref / div; 75 } 76 77 static ulong imx_get_ahbclk(void) 78 { 79 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 80 ulong cctl = readl(&ccm->cctl); 81 ulong fref = imx_get_armclk(); 82 ulong div; 83 84 div = ((cctl >> CCM_CCTL_AHB_DIV_SHIFT) 85 & CCM_CCTL_AHB_DIV_MASK) + 1; 86 87 return fref / div; 88 } 89 90 static ulong imx_get_ipgclk(void) 91 { 92 return imx_get_ahbclk() / 2; 93 } 94 95 static ulong imx_get_perclk(int clk) 96 { 97 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 98 ulong fref = imx_get_ahbclk(); 99 ulong div; 100 101 div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]); 102 div = ((div >> CCM_PERCLK_SHIFT(clk)) & CCM_PERCLK_MASK) + 1; 103 104 return fref / div; 105 } 106 107 unsigned int mxc_get_clock(enum mxc_clock clk) 108 { 109 if (clk >= MXC_CLK_NUM) 110 return -1; 111 switch (clk) { 112 case MXC_ARM_CLK: 113 return imx_get_armclk(); 114 case MXC_AHB_CLK: 115 return imx_get_ahbclk(); 116 case MXC_IPG_CLK: 117 case MXC_CSPI_CLK: 118 case MXC_FEC_CLK: 119 return imx_get_ipgclk(); 120 default: 121 return imx_get_perclk(clk); 122 } 123 } 124 125 u32 get_cpu_rev(void) 126 { 127 u32 srev; 128 u32 system_rev = 0x25000; 129 130 /* read SREV register from IIM module */ 131 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 132 srev = readl(&iim->iim_srev); 133 134 switch (srev) { 135 case 0x00: 136 system_rev |= CHIP_REV_1_0; 137 break; 138 case 0x01: 139 system_rev |= CHIP_REV_1_1; 140 break; 141 case 0x02: 142 system_rev |= CHIP_REV_1_2; 143 break; 144 default: 145 system_rev |= 0x8000; 146 break; 147 } 148 149 return system_rev; 150 } 151 152 #if defined(CONFIG_DISPLAY_CPUINFO) 153 static char *get_reset_cause(void) 154 { 155 /* read RCSR register from CCM module */ 156 struct ccm_regs *ccm = 157 (struct ccm_regs *)IMX_CCM_BASE; 158 159 u32 cause = readl(&ccm->rcsr) & 0x0f; 160 161 if (cause == 0) 162 return "POR"; 163 else if (cause == 1) 164 return "RST"; 165 else if ((cause & 2) == 2) 166 return "WDOG"; 167 else if ((cause & 4) == 4) 168 return "SW RESET"; 169 else if ((cause & 8) == 8) 170 return "JTAG"; 171 else 172 return "unknown reset"; 173 174 } 175 176 int print_cpuinfo(void) 177 { 178 char buf[32]; 179 u32 cpurev = get_cpu_rev(); 180 181 printf("CPU: Freescale i.MX25 rev%d.%d%s at %s MHz\n", 182 (cpurev & 0xF0) >> 4, (cpurev & 0x0F), 183 ((cpurev & 0x8000) ? " unknown" : ""), 184 strmhz(buf, imx_get_armclk())); 185 printf("Reset cause: %s\n", get_reset_cause()); 186 return 0; 187 } 188 #endif 189 190 void enable_caches(void) 191 { 192 #ifndef CONFIG_SYS_DCACHE_OFF 193 /* Enable D-cache. I-cache is already enabled in start.S */ 194 dcache_enable(); 195 #endif 196 } 197 198 #if defined(CONFIG_FEC_MXC) 199 /* 200 * Initializes on-chip ethernet controllers. 201 * to override, implement board_eth_init() 202 */ 203 int cpu_eth_init(bd_t *bis) 204 { 205 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 206 ulong val; 207 208 val = readl(&ccm->cgr0); 209 val |= (1 << 23); 210 writel(val, &ccm->cgr0); 211 return fecmxc_initialize(bis); 212 } 213 #endif 214 215 int get_clocks(void) 216 { 217 #ifdef CONFIG_FSL_ESDHC 218 #if CONFIG_SYS_FSL_ESDHC_ADDR == IMX_MMC_SDHC2_BASE 219 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); 220 #else 221 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK); 222 #endif 223 #endif 224 return 0; 225 } 226 227 #ifdef CONFIG_FSL_ESDHC 228 /* 229 * Initializes on-chip MMC controllers. 230 * to override, implement board_mmc_init() 231 */ 232 int cpu_mmc_init(bd_t *bis) 233 { 234 return fsl_esdhc_mmc_init(bis); 235 } 236 #endif 237 238 #ifdef CONFIG_FEC_MXC 239 void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) 240 { 241 int i; 242 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 243 struct fuse_bank *bank = &iim->bank[0]; 244 struct fuse_bank0_regs *fuse = 245 (struct fuse_bank0_regs *)bank->fuse_regs; 246 247 for (i = 0; i < 6; i++) 248 mac[i] = readl(&fuse->mac_addr[i]) & 0xff; 249 } 250 #endif /* CONFIG_FEC_MXC */ 251