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