1 /* 2 * Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org> 3 * Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com> 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of 8 * the License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 18 * MA 02111-1307 USA 19 */ 20 21 #include <common.h> 22 #include <div64.h> 23 #include <netdev.h> 24 #include <asm/io.h> 25 #include <asm/arch/imx-regs.h> 26 #include <asm/arch/clock.h> 27 #include <asm/arch/gpio.h> 28 #ifdef CONFIG_MXC_MMC 29 #include <asm/arch/mxcmmc.h> 30 #endif 31 32 /* 33 * get the system pll clock in Hz 34 * 35 * mfi + mfn / (mfd +1) 36 * f = 2 * f_ref * -------------------- 37 * pd + 1 38 */ 39 static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref) 40 { 41 unsigned int mfi = (pll >> 10) & 0xf; 42 unsigned int mfn = pll & 0x3ff; 43 unsigned int mfd = (pll >> 16) & 0x3ff; 44 unsigned int pd = (pll >> 26) & 0xf; 45 46 mfi = mfi <= 5 ? 5 : mfi; 47 48 return lldiv(2 * (u64)f_ref * (mfi * (mfd + 1) + mfn), 49 (mfd + 1) * (pd + 1)); 50 } 51 52 static ulong clk_in_32k(void) 53 { 54 return 1024 * CONFIG_MX27_CLK32; 55 } 56 57 static ulong clk_in_26m(void) 58 { 59 struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 60 61 if (readl(&pll->cscr) & CSCR_OSC26M_DIV1P5) { 62 /* divide by 1.5 */ 63 return 26000000 * 2 / 3; 64 } else { 65 return 26000000; 66 } 67 } 68 69 static ulong imx_get_mpllclk(void) 70 { 71 struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 72 ulong cscr = readl(&pll->cscr); 73 ulong fref; 74 75 if (cscr & CSCR_MCU_SEL) 76 fref = clk_in_26m(); 77 else 78 fref = clk_in_32k(); 79 80 return imx_decode_pll(readl(&pll->mpctl0), fref); 81 } 82 83 static ulong imx_get_armclk(void) 84 { 85 struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 86 ulong cscr = readl(&pll->cscr); 87 ulong fref = imx_get_mpllclk(); 88 ulong div; 89 90 if (!(cscr & CSCR_ARM_SRC_MPLL)) 91 fref = lldiv((fref * 2), 3); 92 93 div = ((cscr >> 12) & 0x3) + 1; 94 95 return lldiv(fref, div); 96 } 97 98 static ulong imx_get_ahbclk(void) 99 { 100 struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 101 ulong cscr = readl(&pll->cscr); 102 ulong fref = imx_get_mpllclk(); 103 ulong div; 104 105 div = ((cscr >> 8) & 0x3) + 1; 106 107 return lldiv(fref * 2, 3 * div); 108 } 109 110 static __attribute__((unused)) ulong imx_get_spllclk(void) 111 { 112 struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 113 ulong cscr = readl(&pll->cscr); 114 ulong fref; 115 116 if (cscr & CSCR_SP_SEL) 117 fref = clk_in_26m(); 118 else 119 fref = clk_in_32k(); 120 121 return imx_decode_pll(readl(&pll->spctl0), fref); 122 } 123 124 static ulong imx_decode_perclk(ulong div) 125 { 126 return lldiv((imx_get_mpllclk() * 2), (div * 3)); 127 } 128 129 static ulong imx_get_perclk1(void) 130 { 131 struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 132 133 return imx_decode_perclk((readl(&pll->pcdr1) & 0x3f) + 1); 134 } 135 136 static ulong imx_get_perclk2(void) 137 { 138 struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 139 140 return imx_decode_perclk(((readl(&pll->pcdr1) >> 8) & 0x3f) + 1); 141 } 142 143 static __attribute__((unused)) ulong imx_get_perclk3(void) 144 { 145 struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 146 147 return imx_decode_perclk(((readl(&pll->pcdr1) >> 16) & 0x3f) + 1); 148 } 149 150 static __attribute__((unused)) ulong imx_get_perclk4(void) 151 { 152 struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 153 154 return imx_decode_perclk(((readl(&pll->pcdr1) >> 24) & 0x3f) + 1); 155 } 156 157 unsigned int mxc_get_clock(enum mxc_clock clk) 158 { 159 switch (clk) { 160 case MXC_ARM_CLK: 161 return imx_get_armclk(); 162 case MXC_I2C_CLK: 163 return imx_get_ahbclk()/2; 164 case MXC_UART_CLK: 165 return imx_get_perclk1(); 166 case MXC_FEC_CLK: 167 return imx_get_ahbclk(); 168 case MXC_ESDHC_CLK: 169 return imx_get_perclk2(); 170 } 171 return -1; 172 } 173 174 175 #if defined(CONFIG_DISPLAY_CPUINFO) 176 int print_cpuinfo (void) 177 { 178 char buf[32]; 179 180 printf("CPU: Freescale i.MX27 at %s MHz\n\n", 181 strmhz(buf, imx_get_mpllclk())); 182 return 0; 183 } 184 #endif 185 186 int cpu_eth_init(bd_t *bis) 187 { 188 #if defined(CONFIG_FEC_MXC) 189 struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 190 191 /* enable FEC clock */ 192 writel(readl(&pll->pccr1) | PCCR1_HCLK_FEC, &pll->pccr1); 193 writel(readl(&pll->pccr0) | PCCR0_FEC_EN, &pll->pccr0); 194 return fecmxc_initialize(bis); 195 #else 196 return 0; 197 #endif 198 } 199 200 /* 201 * Initializes on-chip MMC controllers. 202 * to override, implement board_mmc_init() 203 */ 204 int cpu_mmc_init(bd_t *bis) 205 { 206 #ifdef CONFIG_MXC_MMC 207 return mxc_mmc_init(bis); 208 #else 209 return 0; 210 #endif 211 } 212 213 void imx_gpio_mode(int gpio_mode) 214 { 215 struct gpio_port_regs *regs = (struct gpio_port_regs *)IMX_GPIO_BASE; 216 unsigned int pin = gpio_mode & GPIO_PIN_MASK; 217 unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; 218 unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT; 219 unsigned int aout = (gpio_mode & GPIO_AOUT_MASK) >> GPIO_AOUT_SHIFT; 220 unsigned int bout = (gpio_mode & GPIO_BOUT_MASK) >> GPIO_BOUT_SHIFT; 221 unsigned int tmp; 222 223 /* Pullup enable */ 224 if (gpio_mode & GPIO_PUEN) { 225 writel(readl(®s->port[port].puen) | (1 << pin), 226 ®s->port[port].puen); 227 } else { 228 writel(readl(®s->port[port].puen) & ~(1 << pin), 229 ®s->port[port].puen); 230 } 231 232 /* Data direction */ 233 if (gpio_mode & GPIO_OUT) { 234 writel(readl(®s->port[port].gpio_dir) | 1 << pin, 235 ®s->port[port].gpio_dir); 236 } else { 237 writel(readl(®s->port[port].gpio_dir) & ~(1 << pin), 238 ®s->port[port].gpio_dir); 239 } 240 241 /* Primary / alternate function */ 242 if (gpio_mode & GPIO_AF) { 243 writel(readl(®s->port[port].gpr) | (1 << pin), 244 ®s->port[port].gpr); 245 } else { 246 writel(readl(®s->port[port].gpr) & ~(1 << pin), 247 ®s->port[port].gpr); 248 } 249 250 /* use as gpio? */ 251 if (!(gpio_mode & (GPIO_PF | GPIO_AF))) { 252 writel(readl(®s->port[port].gius) | (1 << pin), 253 ®s->port[port].gius); 254 } else { 255 writel(readl(®s->port[port].gius) & ~(1 << pin), 256 ®s->port[port].gius); 257 } 258 259 /* Output / input configuration */ 260 if (pin < 16) { 261 tmp = readl(®s->port[port].ocr1); 262 tmp &= ~(3 << (pin * 2)); 263 tmp |= (ocr << (pin * 2)); 264 writel(tmp, ®s->port[port].ocr1); 265 266 writel(readl(®s->port[port].iconfa1) & ~(3 << (pin * 2)), 267 ®s->port[port].iconfa1); 268 writel(readl(®s->port[port].iconfa1) | aout << (pin * 2), 269 ®s->port[port].iconfa1); 270 writel(readl(®s->port[port].iconfb1) & ~(3 << (pin * 2)), 271 ®s->port[port].iconfb1); 272 writel(readl(®s->port[port].iconfb1) | bout << (pin * 2), 273 ®s->port[port].iconfb1); 274 } else { 275 pin -= 16; 276 277 tmp = readl(®s->port[port].ocr2); 278 tmp &= ~(3 << (pin * 2)); 279 tmp |= (ocr << (pin * 2)); 280 writel(tmp, ®s->port[port].ocr2); 281 282 writel(readl(®s->port[port].iconfa2) & ~(3 << (pin * 2)), 283 ®s->port[port].iconfa2); 284 writel(readl(®s->port[port].iconfa2) | aout << (pin * 2), 285 ®s->port[port].iconfa2); 286 writel(readl(®s->port[port].iconfb2) & ~(3 << (pin * 2)), 287 ®s->port[port].iconfb2); 288 writel(readl(®s->port[port].iconfb2) | bout << (pin * 2), 289 ®s->port[port].iconfb2); 290 } 291 } 292 293 #ifdef CONFIG_MXC_UART 294 void mx27_uart1_init_pins(void) 295 { 296 int i; 297 unsigned int mode[] = { 298 PE12_PF_UART1_TXD, 299 PE13_PF_UART1_RXD, 300 }; 301 302 for (i = 0; i < ARRAY_SIZE(mode); i++) 303 imx_gpio_mode(mode[i]); 304 305 } 306 #endif /* CONFIG_MXC_UART */ 307 308 #ifdef CONFIG_FEC_MXC 309 void mx27_fec_init_pins(void) 310 { 311 int i; 312 unsigned int mode[] = { 313 PD0_AIN_FEC_TXD0, 314 PD1_AIN_FEC_TXD1, 315 PD2_AIN_FEC_TXD2, 316 PD3_AIN_FEC_TXD3, 317 PD4_AOUT_FEC_RX_ER, 318 PD5_AOUT_FEC_RXD1, 319 PD6_AOUT_FEC_RXD2, 320 PD7_AOUT_FEC_RXD3, 321 PD8_AF_FEC_MDIO, 322 PD9_AIN_FEC_MDC | GPIO_PUEN, 323 PD10_AOUT_FEC_CRS, 324 PD11_AOUT_FEC_TX_CLK, 325 PD12_AOUT_FEC_RXD0, 326 PD13_AOUT_FEC_RX_DV, 327 PD14_AOUT_FEC_CLR, 328 PD15_AOUT_FEC_COL, 329 PD16_AIN_FEC_TX_ER, 330 PF23_AIN_FEC_TX_EN, 331 }; 332 333 for (i = 0; i < ARRAY_SIZE(mode); i++) 334 imx_gpio_mode(mode[i]); 335 } 336 337 void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) 338 { 339 int i; 340 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 341 struct fuse_bank *bank = &iim->bank[0]; 342 struct fuse_bank0_regs *fuse = 343 (struct fuse_bank0_regs *)bank->fuse_regs; 344 345 for (i = 0; i < 6; i++) 346 mac[6 - 1 - i] = readl(&fuse->mac_addr[i]) & 0xff; 347 } 348 #endif /* CONFIG_FEC_MXC */ 349 350 #ifdef CONFIG_MXC_MMC 351 void mx27_sd1_init_pins(void) 352 { 353 int i; 354 unsigned int mode[] = { 355 PE18_PF_SD1_D0, 356 PE19_PF_SD1_D1, 357 PE20_PF_SD1_D2, 358 PE21_PF_SD1_D3, 359 PE22_PF_SD1_CMD, 360 PE23_PF_SD1_CLK, 361 }; 362 363 for (i = 0; i < ARRAY_SIZE(mode); i++) 364 imx_gpio_mode(mode[i]); 365 366 } 367 368 void mx27_sd2_init_pins(void) 369 { 370 int i; 371 unsigned int mode[] = { 372 PB4_PF_SD2_D0, 373 PB5_PF_SD2_D1, 374 PB6_PF_SD2_D2, 375 PB7_PF_SD2_D3, 376 PB8_PF_SD2_CMD, 377 PB9_PF_SD2_CLK, 378 }; 379 380 for (i = 0; i < ARRAY_SIZE(mode); i++) 381 imx_gpio_mode(mode[i]); 382 383 } 384 #endif /* CONFIG_MXC_MMC */ 385 386 #ifndef CONFIG_SYS_DCACHE_OFF 387 void enable_caches(void) 388 { 389 /* Enable D-cache. I-cache is already enabled in start.S */ 390 dcache_enable(); 391 } 392 #endif /* CONFIG_SYS_DCACHE_OFF */ 393