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