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 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2 of 12 * the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22 * MA 02111-1307 USA 23 */ 24 25 #include <common.h> 26 #include <div64.h> 27 #include <netdev.h> 28 #include <asm/io.h> 29 #include <asm/arch/imx-regs.h> 30 #include <asm/arch/clock.h> 31 32 #ifdef CONFIG_FSL_ESDHC 33 #include <fsl_esdhc.h> 34 35 DECLARE_GLOBAL_DATA_PTR; 36 #endif 37 38 /* 39 * get the system pll clock in Hz 40 * 41 * mfi + mfn / (mfd +1) 42 * f = 2 * f_ref * -------------------- 43 * pd + 1 44 */ 45 static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref) 46 { 47 unsigned int mfi = (pll >> CCM_PLL_MFI_SHIFT) 48 & CCM_PLL_MFI_MASK; 49 int mfn = (pll >> CCM_PLL_MFN_SHIFT) 50 & CCM_PLL_MFN_MASK; 51 unsigned int mfd = (pll >> CCM_PLL_MFD_SHIFT) 52 & CCM_PLL_MFD_MASK; 53 unsigned int pd = (pll >> CCM_PLL_PD_SHIFT) 54 & CCM_PLL_PD_MASK; 55 56 mfi = mfi <= 5 ? 5 : mfi; 57 mfn = mfn >= 512 ? mfn - 1024 : mfn; 58 mfd += 1; 59 pd += 1; 60 61 return lldiv(2 * (u64) f_ref * (mfi * mfd + mfn), 62 mfd * pd); 63 } 64 65 static ulong imx_get_mpllclk(void) 66 { 67 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 68 ulong fref = MXC_HCLK; 69 70 return imx_decode_pll(readl(&ccm->mpctl), fref); 71 } 72 73 static ulong imx_get_armclk(void) 74 { 75 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 76 ulong cctl = readl(&ccm->cctl); 77 ulong fref = imx_get_mpllclk(); 78 ulong div; 79 80 if (cctl & CCM_CCTL_ARM_SRC) 81 fref = lldiv((u64) fref * 3, 4); 82 83 div = ((cctl >> CCM_CCTL_ARM_DIV_SHIFT) 84 & CCM_CCTL_ARM_DIV_MASK) + 1; 85 86 return fref / div; 87 } 88 89 static ulong imx_get_ahbclk(void) 90 { 91 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 92 ulong cctl = readl(&ccm->cctl); 93 ulong fref = imx_get_armclk(); 94 ulong div; 95 96 div = ((cctl >> CCM_CCTL_AHB_DIV_SHIFT) 97 & CCM_CCTL_AHB_DIV_MASK) + 1; 98 99 return fref / div; 100 } 101 102 static ulong imx_get_ipgclk(void) 103 { 104 return imx_get_ahbclk() / 2; 105 } 106 107 static ulong imx_get_perclk(int clk) 108 { 109 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 110 ulong fref = imx_get_ahbclk(); 111 ulong div; 112 113 div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]); 114 div = ((div >> CCM_PERCLK_SHIFT(clk)) & CCM_PERCLK_MASK) + 1; 115 116 return fref / div; 117 } 118 119 unsigned int mxc_get_clock(enum mxc_clock clk) 120 { 121 if (clk >= MXC_CLK_NUM) 122 return -1; 123 switch (clk) { 124 case MXC_ARM_CLK: 125 return imx_get_armclk(); 126 case MXC_AHB_CLK: 127 return imx_get_ahbclk(); 128 case MXC_IPG_CLK: 129 case MXC_CSPI_CLK: 130 case MXC_FEC_CLK: 131 return imx_get_ipgclk(); 132 default: 133 return imx_get_perclk(clk); 134 } 135 } 136 137 u32 get_cpu_rev(void) 138 { 139 u32 srev; 140 u32 system_rev = 0x25000; 141 142 /* read SREV register from IIM module */ 143 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 144 srev = readl(&iim->iim_srev); 145 146 switch (srev) { 147 case 0x00: 148 system_rev |= CHIP_REV_1_0; 149 break; 150 case 0x01: 151 system_rev |= CHIP_REV_1_1; 152 break; 153 case 0x02: 154 system_rev |= CHIP_REV_1_2; 155 break; 156 default: 157 system_rev |= 0x8000; 158 break; 159 } 160 161 return system_rev; 162 } 163 164 #if defined(CONFIG_DISPLAY_CPUINFO) 165 static char *get_reset_cause(void) 166 { 167 /* read RCSR register from CCM module */ 168 struct ccm_regs *ccm = 169 (struct ccm_regs *)IMX_CCM_BASE; 170 171 u32 cause = readl(&ccm->rcsr) & 0x0f; 172 173 if (cause == 0) 174 return "POR"; 175 else if (cause == 1) 176 return "RST"; 177 else if ((cause & 2) == 2) 178 return "WDOG"; 179 else if ((cause & 4) == 4) 180 return "SW RESET"; 181 else if ((cause & 8) == 8) 182 return "JTAG"; 183 else 184 return "unknown reset"; 185 186 } 187 188 int print_cpuinfo(void) 189 { 190 char buf[32]; 191 u32 cpurev = get_cpu_rev(); 192 193 printf("CPU: Freescale i.MX25 rev%d.%d%s at %s MHz\n", 194 (cpurev & 0xF0) >> 4, (cpurev & 0x0F), 195 ((cpurev & 0x8000) ? " unknown" : ""), 196 strmhz(buf, imx_get_armclk())); 197 printf("Reset cause: %s\n\n", get_reset_cause()); 198 return 0; 199 } 200 #endif 201 202 void enable_caches(void) 203 { 204 #ifndef CONFIG_SYS_DCACHE_OFF 205 /* Enable D-cache. I-cache is already enabled in start.S */ 206 dcache_enable(); 207 #endif 208 } 209 210 #if defined(CONFIG_FEC_MXC) 211 /* 212 * Initializes on-chip ethernet controllers. 213 * to override, implement board_eth_init() 214 */ 215 int cpu_eth_init(bd_t *bis) 216 { 217 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 218 ulong val; 219 220 val = readl(&ccm->cgr0); 221 val |= (1 << 23); 222 writel(val, &ccm->cgr0); 223 return fecmxc_initialize(bis); 224 } 225 #endif 226 227 int get_clocks(void) 228 { 229 #ifdef CONFIG_FSL_ESDHC 230 #if CONFIG_SYS_FSL_ESDHC_ADDR == IMX_MMC_SDHC2_BASE 231 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); 232 #else 233 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK); 234 #endif 235 #endif 236 return 0; 237 } 238 239 #ifdef CONFIG_FSL_ESDHC 240 /* 241 * Initializes on-chip MMC controllers. 242 * to override, implement board_mmc_init() 243 */ 244 int cpu_mmc_init(bd_t *bis) 245 { 246 return fsl_esdhc_mmc_init(bis); 247 } 248 #endif 249 250 #ifdef CONFIG_FEC_MXC 251 void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) 252 { 253 int i; 254 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 255 struct fuse_bank *bank = &iim->bank[0]; 256 struct fuse_bank0_regs *fuse = 257 (struct fuse_bank0_regs *)bank->fuse_regs; 258 259 for (i = 0; i < 6; i++) 260 mac[i] = readl(&fuse->mac_addr[i]) & 0xff; 261 } 262 #endif /* CONFIG_FEC_MXC */ 263