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