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