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/imx25-pinmux.h> 31 #include <asm/arch/clock.h> 32 33 #ifdef CONFIG_FSL_ESDHC 34 #include <fsl_esdhc.h> 35 36 DECLARE_GLOBAL_DATA_PTR; 37 #endif 38 39 /* 40 * get the system pll clock in Hz 41 * 42 * mfi + mfn / (mfd +1) 43 * f = 2 * f_ref * -------------------- 44 * pd + 1 45 */ 46 static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref) 47 { 48 unsigned int mfi = (pll >> CCM_PLL_MFI_SHIFT) 49 & CCM_PLL_MFI_MASK; 50 int mfn = (pll >> CCM_PLL_MFN_SHIFT) 51 & CCM_PLL_MFN_MASK; 52 unsigned int mfd = (pll >> CCM_PLL_MFD_SHIFT) 53 & CCM_PLL_MFD_MASK; 54 unsigned int pd = (pll >> CCM_PLL_PD_SHIFT) 55 & CCM_PLL_PD_MASK; 56 57 mfi = mfi <= 5 ? 5 : mfi; 58 mfn = mfn >= 512 ? mfn - 1024 : mfn; 59 mfd += 1; 60 pd += 1; 61 62 return lldiv(2 * (u64) f_ref * (mfi * mfd + mfn), 63 mfd * pd); 64 } 65 66 static ulong imx_get_mpllclk(void) 67 { 68 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 69 ulong fref = MXC_HCLK; 70 71 return imx_decode_pll(readl(&ccm->mpctl), fref); 72 } 73 74 static ulong imx_get_armclk(void) 75 { 76 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 77 ulong cctl = readl(&ccm->cctl); 78 ulong fref = imx_get_mpllclk(); 79 ulong div; 80 81 if (cctl & CCM_CCTL_ARM_SRC) 82 fref = lldiv((u64) fref * 3, 4); 83 84 div = ((cctl >> CCM_CCTL_ARM_DIV_SHIFT) 85 & CCM_CCTL_ARM_DIV_MASK) + 1; 86 87 return fref / div; 88 } 89 90 static ulong imx_get_ahbclk(void) 91 { 92 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 93 ulong cctl = readl(&ccm->cctl); 94 ulong fref = imx_get_armclk(); 95 ulong div; 96 97 div = ((cctl >> CCM_CCTL_AHB_DIV_SHIFT) 98 & CCM_CCTL_AHB_DIV_MASK) + 1; 99 100 return fref / div; 101 } 102 103 static ulong imx_get_ipgclk(void) 104 { 105 return imx_get_ahbclk() / 2; 106 } 107 108 static ulong imx_get_perclk(int clk) 109 { 110 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 111 ulong fref = imx_get_ahbclk(); 112 ulong div; 113 114 div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]); 115 div = ((div >> CCM_PERCLK_SHIFT(clk)) & CCM_PERCLK_MASK) + 1; 116 117 return fref / div; 118 } 119 120 unsigned int mxc_get_clock(enum mxc_clock clk) 121 { 122 if (clk >= MXC_CLK_NUM) 123 return -1; 124 switch (clk) { 125 case MXC_ARM_CLK: 126 return imx_get_armclk(); 127 case MXC_AHB_CLK: 128 return imx_get_ahbclk(); 129 case MXC_IPG_CLK: 130 case MXC_CSPI_CLK: 131 case MXC_FEC_CLK: 132 return imx_get_ipgclk(); 133 default: 134 return imx_get_perclk(clk); 135 } 136 } 137 138 u32 get_cpu_rev(void) 139 { 140 u32 srev; 141 u32 system_rev = 0x25000; 142 143 /* read SREV register from IIM module */ 144 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 145 srev = readl(&iim->iim_srev); 146 147 switch (srev) { 148 case 0x00: 149 system_rev |= CHIP_REV_1_0; 150 break; 151 case 0x01: 152 system_rev |= CHIP_REV_1_1; 153 break; 154 case 0x02: 155 system_rev |= CHIP_REV_1_2; 156 break; 157 default: 158 system_rev |= 0x8000; 159 break; 160 } 161 162 return system_rev; 163 } 164 165 #if defined(CONFIG_DISPLAY_CPUINFO) 166 static char *get_reset_cause(void) 167 { 168 /* read RCSR register from CCM module */ 169 struct ccm_regs *ccm = 170 (struct ccm_regs *)IMX_CCM_BASE; 171 172 u32 cause = readl(&ccm->rcsr) & 0x0f; 173 174 if (cause == 0) 175 return "POR"; 176 else if (cause == 1) 177 return "RST"; 178 else if ((cause & 2) == 2) 179 return "WDOG"; 180 else if ((cause & 4) == 4) 181 return "SW RESET"; 182 else if ((cause & 8) == 8) 183 return "JTAG"; 184 else 185 return "unknown reset"; 186 187 } 188 189 int print_cpuinfo(void) 190 { 191 char buf[32]; 192 u32 cpurev = get_cpu_rev(); 193 194 printf("CPU: Freescale i.MX25 rev%d.%d%s at %s MHz\n", 195 (cpurev & 0xF0) >> 4, (cpurev & 0x0F), 196 ((cpurev & 0x8000) ? " unknown" : ""), 197 strmhz(buf, imx_get_armclk())); 198 printf("Reset cause: %s\n\n", get_reset_cause()); 199 return 0; 200 } 201 #endif 202 203 void enable_caches(void) 204 { 205 #ifndef CONFIG_SYS_DCACHE_OFF 206 /* Enable D-cache. I-cache is already enabled in start.S */ 207 dcache_enable(); 208 #endif 209 } 210 211 #if defined(CONFIG_FEC_MXC) 212 /* 213 * Initializes on-chip ethernet controllers. 214 * to override, implement board_eth_init() 215 */ 216 int cpu_eth_init(bd_t *bis) 217 { 218 struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; 219 ulong val; 220 221 val = readl(&ccm->cgr0); 222 val |= (1 << 23); 223 writel(val, &ccm->cgr0); 224 return fecmxc_initialize(bis); 225 } 226 #endif 227 228 int get_clocks(void) 229 { 230 #ifdef CONFIG_FSL_ESDHC 231 #if CONFIG_SYS_FSL_ESDHC_ADDR == IMX_MMC_SDHC2_BASE 232 gd->sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); 233 #else 234 gd->sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK); 235 #endif 236 #endif 237 return 0; 238 } 239 240 #ifdef CONFIG_FSL_ESDHC 241 /* 242 * Initializes on-chip MMC controllers. 243 * to override, implement board_mmc_init() 244 */ 245 int cpu_mmc_init(bd_t *bis) 246 { 247 return fsl_esdhc_mmc_init(bis); 248 } 249 #endif 250 251 #ifdef CONFIG_MXC_UART 252 void mx25_uart1_init_pins(void) 253 { 254 struct iomuxc_mux_ctl *muxctl; 255 struct iomuxc_pad_ctl *padctl; 256 u32 inpadctl; 257 u32 outpadctl; 258 u32 muxmode0; 259 260 muxctl = (struct iomuxc_mux_ctl *)IMX_IOPADMUX_BASE; 261 padctl = (struct iomuxc_pad_ctl *)IMX_IOPADCTL_BASE; 262 muxmode0 = MX25_PIN_MUX_MODE(0); 263 /* 264 * set up input pins with hysteresis and 100K pull-ups 265 */ 266 inpadctl = MX25_PIN_PAD_CTL_HYS 267 | MX25_PIN_PAD_CTL_PKE 268 | MX25_PIN_PAD_CTL_PUE | MX25_PIN_PAD_CTL_100K_PU; 269 270 /* 271 * set up output pins with 100K pull-downs 272 * FIXME: need to revisit this 273 * PUE is ignored if PKE is not set 274 * so the right value here is likely 275 * 0x0 for no pull up/down 276 * or 277 * 0xc0 for 100k pull down 278 */ 279 outpadctl = MX25_PIN_PAD_CTL_PUE | MX25_PIN_PAD_CTL_100K_PD; 280 281 /* UART1 */ 282 /* rxd */ 283 writel(muxmode0, &muxctl->pad_uart1_rxd); 284 writel(inpadctl, &padctl->pad_uart1_rxd); 285 286 /* txd */ 287 writel(muxmode0, &muxctl->pad_uart1_txd); 288 writel(outpadctl, &padctl->pad_uart1_txd); 289 290 /* rts */ 291 writel(muxmode0, &muxctl->pad_uart1_rts); 292 writel(outpadctl, &padctl->pad_uart1_rts); 293 294 /* cts */ 295 writel(muxmode0, &muxctl->pad_uart1_cts); 296 writel(inpadctl, &padctl->pad_uart1_cts); 297 } 298 #endif /* CONFIG_MXC_UART */ 299 300 #ifdef CONFIG_FEC_MXC 301 void mx25_fec_init_pins(void) 302 { 303 struct iomuxc_mux_ctl *muxctl; 304 struct iomuxc_pad_ctl *padctl; 305 u32 inpadctl_100kpd; 306 u32 inpadctl_22kpu; 307 u32 outpadctl; 308 u32 muxmode0; 309 310 muxctl = (struct iomuxc_mux_ctl *)IMX_IOPADMUX_BASE; 311 padctl = (struct iomuxc_pad_ctl *)IMX_IOPADCTL_BASE; 312 muxmode0 = MX25_PIN_MUX_MODE(0); 313 inpadctl_100kpd = MX25_PIN_PAD_CTL_HYS 314 | MX25_PIN_PAD_CTL_PKE 315 | MX25_PIN_PAD_CTL_PUE | MX25_PIN_PAD_CTL_100K_PD; 316 inpadctl_22kpu = MX25_PIN_PAD_CTL_HYS 317 | MX25_PIN_PAD_CTL_PKE 318 | MX25_PIN_PAD_CTL_PUE | MX25_PIN_PAD_CTL_22K_PU; 319 /* 320 * set up output pins with 100K pull-downs 321 * FIXME: need to revisit this 322 * PUE is ignored if PKE is not set 323 * so the right value here is likely 324 * 0x0 for no pull 325 * or 326 * 0xc0 for 100k pull down 327 */ 328 outpadctl = MX25_PIN_PAD_CTL_PUE | MX25_PIN_PAD_CTL_100K_PD; 329 330 /* FEC_TX_CLK */ 331 writel(muxmode0, &muxctl->pad_fec_tx_clk); 332 writel(inpadctl_100kpd, &padctl->pad_fec_tx_clk); 333 334 /* FEC_RX_DV */ 335 writel(muxmode0, &muxctl->pad_fec_rx_dv); 336 writel(inpadctl_100kpd, &padctl->pad_fec_rx_dv); 337 338 /* FEC_RDATA0 */ 339 writel(muxmode0, &muxctl->pad_fec_rdata0); 340 writel(inpadctl_100kpd, &padctl->pad_fec_rdata0); 341 342 /* FEC_TDATA0 */ 343 writel(muxmode0, &muxctl->pad_fec_tdata0); 344 writel(outpadctl, &padctl->pad_fec_tdata0); 345 346 /* FEC_TX_EN */ 347 writel(muxmode0, &muxctl->pad_fec_tx_en); 348 writel(outpadctl, &padctl->pad_fec_tx_en); 349 350 /* FEC_MDC */ 351 writel(muxmode0, &muxctl->pad_fec_mdc); 352 writel(outpadctl, &padctl->pad_fec_mdc); 353 354 /* FEC_MDIO */ 355 writel(muxmode0, &muxctl->pad_fec_mdio); 356 writel(inpadctl_22kpu, &padctl->pad_fec_mdio); 357 358 /* FEC_RDATA1 */ 359 writel(muxmode0, &muxctl->pad_fec_rdata1); 360 writel(inpadctl_100kpd, &padctl->pad_fec_rdata1); 361 362 /* FEC_TDATA1 */ 363 writel(muxmode0, &muxctl->pad_fec_tdata1); 364 writel(outpadctl, &padctl->pad_fec_tdata1); 365 366 } 367 368 void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) 369 { 370 int i; 371 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 372 struct fuse_bank *bank = &iim->bank[0]; 373 struct fuse_bank0_regs *fuse = 374 (struct fuse_bank0_regs *)bank->fuse_regs; 375 376 for (i = 0; i < 6; i++) 377 mac[i] = readl(&fuse->mac_addr[i]) & 0xff; 378 } 379 #endif /* CONFIG_FEC_MXC */ 380