184ad6884SPeter Tyser /* 284ad6884SPeter Tyser * Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org> 384ad6884SPeter Tyser * Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com> 484ad6884SPeter Tyser * 584ad6884SPeter Tyser * This program is free software; you can redistribute it and/or 684ad6884SPeter Tyser * modify it under the terms of the GNU General Public License as 784ad6884SPeter Tyser * published by the Free Software Foundation; either version 2 of 884ad6884SPeter Tyser * the License, or (at your option) any later version. 984ad6884SPeter Tyser * 1084ad6884SPeter Tyser * This program is distributed in the hope that it will be useful, 1184ad6884SPeter Tyser * but WITHOUT ANY WARRANTY; without even the implied warranty of 1284ad6884SPeter Tyser * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1384ad6884SPeter Tyser * GNU General Public License for more details. 1484ad6884SPeter Tyser * 1584ad6884SPeter Tyser * You should have received a copy of the GNU General Public License 1684ad6884SPeter Tyser * along with this program; if not, write to the Free Software 1784ad6884SPeter Tyser * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 1884ad6884SPeter Tyser * MA 02111-1307 USA 1984ad6884SPeter Tyser */ 2084ad6884SPeter Tyser 2184ad6884SPeter Tyser #include <common.h> 2284ad6884SPeter Tyser #include <div64.h> 2384ad6884SPeter Tyser #include <netdev.h> 2484ad6884SPeter Tyser #include <asm/io.h> 2584ad6884SPeter Tyser #include <asm/arch/imx-regs.h> 2684ad6884SPeter Tyser #ifdef CONFIG_MXC_MMC 2784ad6884SPeter Tyser #include <asm/arch/mxcmmc.h> 2884ad6884SPeter Tyser #endif 2984ad6884SPeter Tyser 3084ad6884SPeter Tyser /* 3184ad6884SPeter Tyser * get the system pll clock in Hz 3284ad6884SPeter Tyser * 3384ad6884SPeter Tyser * mfi + mfn / (mfd +1) 3484ad6884SPeter Tyser * f = 2 * f_ref * -------------------- 3584ad6884SPeter Tyser * pd + 1 3684ad6884SPeter Tyser */ 3784ad6884SPeter Tyser unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref) 3884ad6884SPeter Tyser { 3984ad6884SPeter Tyser unsigned int mfi = (pll >> 10) & 0xf; 4084ad6884SPeter Tyser unsigned int mfn = pll & 0x3ff; 4184ad6884SPeter Tyser unsigned int mfd = (pll >> 16) & 0x3ff; 4284ad6884SPeter Tyser unsigned int pd = (pll >> 26) & 0xf; 4384ad6884SPeter Tyser 4484ad6884SPeter Tyser mfi = mfi <= 5 ? 5 : mfi; 4584ad6884SPeter Tyser 4684ad6884SPeter Tyser return lldiv(2 * (u64)f_ref * (mfi * (mfd + 1) + mfn), 4784ad6884SPeter Tyser (mfd + 1) * (pd + 1)); 4884ad6884SPeter Tyser } 4984ad6884SPeter Tyser 5084ad6884SPeter Tyser static ulong clk_in_32k(void) 5184ad6884SPeter Tyser { 5284ad6884SPeter Tyser return 1024 * CONFIG_MX27_CLK32; 5384ad6884SPeter Tyser } 5484ad6884SPeter Tyser 5584ad6884SPeter Tyser static ulong clk_in_26m(void) 5684ad6884SPeter Tyser { 5784ad6884SPeter Tyser struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 5884ad6884SPeter Tyser 5984ad6884SPeter Tyser if (readl(&pll->cscr) & CSCR_OSC26M_DIV1P5) { 6084ad6884SPeter Tyser /* divide by 1.5 */ 6184ad6884SPeter Tyser return 26000000 * 2 / 3; 6284ad6884SPeter Tyser } else { 6384ad6884SPeter Tyser return 26000000; 6484ad6884SPeter Tyser } 6584ad6884SPeter Tyser } 6684ad6884SPeter Tyser 6784ad6884SPeter Tyser ulong imx_get_mpllclk(void) 6884ad6884SPeter Tyser { 6984ad6884SPeter Tyser struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 7084ad6884SPeter Tyser ulong cscr = readl(&pll->cscr); 7184ad6884SPeter Tyser ulong fref; 7284ad6884SPeter Tyser 7384ad6884SPeter Tyser if (cscr & CSCR_MCU_SEL) 7484ad6884SPeter Tyser fref = clk_in_26m(); 7584ad6884SPeter Tyser else 7684ad6884SPeter Tyser fref = clk_in_32k(); 7784ad6884SPeter Tyser 7884ad6884SPeter Tyser return imx_decode_pll(readl(&pll->mpctl0), fref); 7984ad6884SPeter Tyser } 8084ad6884SPeter Tyser 8184ad6884SPeter Tyser ulong imx_get_armclk(void) 8284ad6884SPeter Tyser { 8384ad6884SPeter Tyser struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 8484ad6884SPeter Tyser ulong cscr = readl(&pll->cscr); 8584ad6884SPeter Tyser ulong fref = imx_get_mpllclk(); 8684ad6884SPeter Tyser ulong div; 8784ad6884SPeter Tyser 8884ad6884SPeter Tyser if (!(cscr & CSCR_ARM_SRC_MPLL)) 8984ad6884SPeter Tyser fref = lldiv((fref * 2), 3); 9084ad6884SPeter Tyser 9184ad6884SPeter Tyser div = ((cscr >> 12) & 0x3) + 1; 9284ad6884SPeter Tyser 9384ad6884SPeter Tyser return lldiv(fref, div); 9484ad6884SPeter Tyser } 9584ad6884SPeter Tyser 9684ad6884SPeter Tyser ulong imx_get_ahbclk(void) 9784ad6884SPeter Tyser { 9884ad6884SPeter Tyser struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 9984ad6884SPeter Tyser ulong cscr = readl(&pll->cscr); 10084ad6884SPeter Tyser ulong fref = imx_get_mpllclk(); 10184ad6884SPeter Tyser ulong div; 10284ad6884SPeter Tyser 10384ad6884SPeter Tyser div = ((cscr >> 8) & 0x3) + 1; 10484ad6884SPeter Tyser 10584ad6884SPeter Tyser return lldiv(fref * 2, 3 * div); 10684ad6884SPeter Tyser } 10784ad6884SPeter Tyser 10884ad6884SPeter Tyser ulong imx_get_spllclk(void) 10984ad6884SPeter Tyser { 11084ad6884SPeter Tyser struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 11184ad6884SPeter Tyser ulong cscr = readl(&pll->cscr); 11284ad6884SPeter Tyser ulong fref; 11384ad6884SPeter Tyser 11484ad6884SPeter Tyser if (cscr & CSCR_SP_SEL) 11584ad6884SPeter Tyser fref = clk_in_26m(); 11684ad6884SPeter Tyser else 11784ad6884SPeter Tyser fref = clk_in_32k(); 11884ad6884SPeter Tyser 11984ad6884SPeter Tyser return imx_decode_pll(readl(&pll->spctl0), fref); 12084ad6884SPeter Tyser } 12184ad6884SPeter Tyser 12284ad6884SPeter Tyser static ulong imx_decode_perclk(ulong div) 12384ad6884SPeter Tyser { 12484ad6884SPeter Tyser return lldiv((imx_get_mpllclk() * 2), (div * 3)); 12584ad6884SPeter Tyser } 12684ad6884SPeter Tyser 12784ad6884SPeter Tyser ulong imx_get_perclk1(void) 12884ad6884SPeter Tyser { 12984ad6884SPeter Tyser struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 13084ad6884SPeter Tyser 13184ad6884SPeter Tyser return imx_decode_perclk((readl(&pll->pcdr1) & 0x3f) + 1); 13284ad6884SPeter Tyser } 13384ad6884SPeter Tyser 13484ad6884SPeter Tyser ulong imx_get_perclk2(void) 13584ad6884SPeter Tyser { 13684ad6884SPeter Tyser struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 13784ad6884SPeter Tyser 13884ad6884SPeter Tyser return imx_decode_perclk(((readl(&pll->pcdr1) >> 8) & 0x3f) + 1); 13984ad6884SPeter Tyser } 14084ad6884SPeter Tyser 14184ad6884SPeter Tyser ulong imx_get_perclk3(void) 14284ad6884SPeter Tyser { 14384ad6884SPeter Tyser struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 14484ad6884SPeter Tyser 14584ad6884SPeter Tyser return imx_decode_perclk(((readl(&pll->pcdr1) >> 16) & 0x3f) + 1); 14684ad6884SPeter Tyser } 14784ad6884SPeter Tyser 14884ad6884SPeter Tyser ulong imx_get_perclk4(void) 14984ad6884SPeter Tyser { 15084ad6884SPeter Tyser struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 15184ad6884SPeter Tyser 15284ad6884SPeter Tyser return imx_decode_perclk(((readl(&pll->pcdr1) >> 24) & 0x3f) + 1); 15384ad6884SPeter Tyser } 15484ad6884SPeter Tyser 15584ad6884SPeter Tyser #if defined(CONFIG_DISPLAY_CPUINFO) 15684ad6884SPeter Tyser int print_cpuinfo (void) 15784ad6884SPeter Tyser { 15884ad6884SPeter Tyser char buf[32]; 15984ad6884SPeter Tyser 16084ad6884SPeter Tyser printf("CPU: Freescale i.MX27 at %s MHz\n\n", 16184ad6884SPeter Tyser strmhz(buf, imx_get_mpllclk())); 16284ad6884SPeter Tyser return 0; 16384ad6884SPeter Tyser } 16484ad6884SPeter Tyser #endif 16584ad6884SPeter Tyser 16684ad6884SPeter Tyser int cpu_eth_init(bd_t *bis) 16784ad6884SPeter Tyser { 16884ad6884SPeter Tyser #if defined(CONFIG_FEC_MXC) 16984ad6884SPeter Tyser struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; 17084ad6884SPeter Tyser 17184ad6884SPeter Tyser /* enable FEC clock */ 17284ad6884SPeter Tyser writel(readl(&pll->pccr1) | PCCR1_HCLK_FEC, &pll->pccr1); 17384ad6884SPeter Tyser writel(readl(&pll->pccr0) | PCCR0_FEC_EN, &pll->pccr0); 17484ad6884SPeter Tyser return fecmxc_initialize(bis); 17584ad6884SPeter Tyser #else 17684ad6884SPeter Tyser return 0; 17784ad6884SPeter Tyser #endif 17884ad6884SPeter Tyser } 17984ad6884SPeter Tyser 18084ad6884SPeter Tyser /* 18184ad6884SPeter Tyser * Initializes on-chip MMC controllers. 18284ad6884SPeter Tyser * to override, implement board_mmc_init() 18384ad6884SPeter Tyser */ 18484ad6884SPeter Tyser int cpu_mmc_init(bd_t *bis) 18584ad6884SPeter Tyser { 18684ad6884SPeter Tyser #ifdef CONFIG_MXC_MMC 18784ad6884SPeter Tyser return mxc_mmc_init(bis); 18884ad6884SPeter Tyser #else 18984ad6884SPeter Tyser return 0; 19084ad6884SPeter Tyser #endif 19184ad6884SPeter Tyser } 19284ad6884SPeter Tyser 19384ad6884SPeter Tyser void imx_gpio_mode(int gpio_mode) 19484ad6884SPeter Tyser { 19584ad6884SPeter Tyser struct gpio_regs *regs = (struct gpio_regs *)IMX_GPIO_BASE; 19684ad6884SPeter Tyser unsigned int pin = gpio_mode & GPIO_PIN_MASK; 19784ad6884SPeter Tyser unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; 19884ad6884SPeter Tyser unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT; 19984ad6884SPeter Tyser unsigned int aout = (gpio_mode & GPIO_AOUT_MASK) >> GPIO_AOUT_SHIFT; 20084ad6884SPeter Tyser unsigned int bout = (gpio_mode & GPIO_BOUT_MASK) >> GPIO_BOUT_SHIFT; 20184ad6884SPeter Tyser unsigned int tmp; 20284ad6884SPeter Tyser 20384ad6884SPeter Tyser /* Pullup enable */ 20484ad6884SPeter Tyser if (gpio_mode & GPIO_PUEN) { 20584ad6884SPeter Tyser writel(readl(®s->port[port].puen) | (1 << pin), 20684ad6884SPeter Tyser ®s->port[port].puen); 20784ad6884SPeter Tyser } else { 20884ad6884SPeter Tyser writel(readl(®s->port[port].puen) & ~(1 << pin), 20984ad6884SPeter Tyser ®s->port[port].puen); 21084ad6884SPeter Tyser } 21184ad6884SPeter Tyser 21284ad6884SPeter Tyser /* Data direction */ 21384ad6884SPeter Tyser if (gpio_mode & GPIO_OUT) { 21484ad6884SPeter Tyser writel(readl(®s->port[port].ddir) | 1 << pin, 21584ad6884SPeter Tyser ®s->port[port].ddir); 21684ad6884SPeter Tyser } else { 21784ad6884SPeter Tyser writel(readl(®s->port[port].ddir) & ~(1 << pin), 21884ad6884SPeter Tyser ®s->port[port].ddir); 21984ad6884SPeter Tyser } 22084ad6884SPeter Tyser 22184ad6884SPeter Tyser /* Primary / alternate function */ 22284ad6884SPeter Tyser if (gpio_mode & GPIO_AF) { 22384ad6884SPeter Tyser writel(readl(®s->port[port].gpr) | (1 << pin), 22484ad6884SPeter Tyser ®s->port[port].gpr); 22584ad6884SPeter Tyser } else { 22684ad6884SPeter Tyser writel(readl(®s->port[port].gpr) & ~(1 << pin), 22784ad6884SPeter Tyser ®s->port[port].gpr); 22884ad6884SPeter Tyser } 22984ad6884SPeter Tyser 23084ad6884SPeter Tyser /* use as gpio? */ 23184ad6884SPeter Tyser if (!(gpio_mode & (GPIO_PF | GPIO_AF))) { 23284ad6884SPeter Tyser writel(readl(®s->port[port].gius) | (1 << pin), 23384ad6884SPeter Tyser ®s->port[port].gius); 23484ad6884SPeter Tyser } else { 23584ad6884SPeter Tyser writel(readl(®s->port[port].gius) & ~(1 << pin), 23684ad6884SPeter Tyser ®s->port[port].gius); 23784ad6884SPeter Tyser } 23884ad6884SPeter Tyser 23984ad6884SPeter Tyser /* Output / input configuration */ 24084ad6884SPeter Tyser if (pin < 16) { 24184ad6884SPeter Tyser tmp = readl(®s->port[port].ocr1); 24284ad6884SPeter Tyser tmp &= ~(3 << (pin * 2)); 24384ad6884SPeter Tyser tmp |= (ocr << (pin * 2)); 24484ad6884SPeter Tyser writel(tmp, ®s->port[port].ocr1); 24584ad6884SPeter Tyser 24684ad6884SPeter Tyser writel(readl(®s->port[port].iconfa1) & ~(3 << (pin * 2)), 24784ad6884SPeter Tyser ®s->port[port].iconfa1); 24884ad6884SPeter Tyser writel(readl(®s->port[port].iconfa1) | aout << (pin * 2), 24984ad6884SPeter Tyser ®s->port[port].iconfa1); 25084ad6884SPeter Tyser writel(readl(®s->port[port].iconfb1) & ~(3 << (pin * 2)), 25184ad6884SPeter Tyser ®s->port[port].iconfb1); 25284ad6884SPeter Tyser writel(readl(®s->port[port].iconfb1) | bout << (pin * 2), 25384ad6884SPeter Tyser ®s->port[port].iconfb1); 25484ad6884SPeter Tyser } else { 25584ad6884SPeter Tyser pin -= 16; 25684ad6884SPeter Tyser 25784ad6884SPeter Tyser tmp = readl(®s->port[port].ocr2); 25884ad6884SPeter Tyser tmp &= ~(3 << (pin * 2)); 25984ad6884SPeter Tyser tmp |= (ocr << (pin * 2)); 26084ad6884SPeter Tyser writel(tmp, ®s->port[port].ocr2); 26184ad6884SPeter Tyser 26284ad6884SPeter Tyser writel(readl(®s->port[port].iconfa2) & ~(3 << (pin * 2)), 26384ad6884SPeter Tyser ®s->port[port].iconfa2); 26484ad6884SPeter Tyser writel(readl(®s->port[port].iconfa2) | aout << (pin * 2), 26584ad6884SPeter Tyser ®s->port[port].iconfa2); 26684ad6884SPeter Tyser writel(readl(®s->port[port].iconfb2) & ~(3 << (pin * 2)), 26784ad6884SPeter Tyser ®s->port[port].iconfb2); 26884ad6884SPeter Tyser writel(readl(®s->port[port].iconfb2) | bout << (pin * 2), 26984ad6884SPeter Tyser ®s->port[port].iconfb2); 27084ad6884SPeter Tyser } 27184ad6884SPeter Tyser } 27284ad6884SPeter Tyser 27384ad6884SPeter Tyser #ifdef CONFIG_MXC_UART 27484ad6884SPeter Tyser void mx27_uart_init_pins(void) 27584ad6884SPeter Tyser { 27684ad6884SPeter Tyser int i; 27784ad6884SPeter Tyser unsigned int mode[] = { 27884ad6884SPeter Tyser PE12_PF_UART1_TXD, 27984ad6884SPeter Tyser PE13_PF_UART1_RXD, 28084ad6884SPeter Tyser }; 28184ad6884SPeter Tyser 28284ad6884SPeter Tyser for (i = 0; i < ARRAY_SIZE(mode); i++) 28384ad6884SPeter Tyser imx_gpio_mode(mode[i]); 28484ad6884SPeter Tyser 28584ad6884SPeter Tyser } 28684ad6884SPeter Tyser #endif /* CONFIG_MXC_UART */ 28784ad6884SPeter Tyser 28884ad6884SPeter Tyser #ifdef CONFIG_FEC_MXC 28984ad6884SPeter Tyser void mx27_fec_init_pins(void) 29084ad6884SPeter Tyser { 29184ad6884SPeter Tyser int i; 29284ad6884SPeter Tyser unsigned int mode[] = { 29384ad6884SPeter Tyser PD0_AIN_FEC_TXD0, 29484ad6884SPeter Tyser PD1_AIN_FEC_TXD1, 29584ad6884SPeter Tyser PD2_AIN_FEC_TXD2, 29684ad6884SPeter Tyser PD3_AIN_FEC_TXD3, 29784ad6884SPeter Tyser PD4_AOUT_FEC_RX_ER, 29884ad6884SPeter Tyser PD5_AOUT_FEC_RXD1, 29984ad6884SPeter Tyser PD6_AOUT_FEC_RXD2, 30084ad6884SPeter Tyser PD7_AOUT_FEC_RXD3, 30184ad6884SPeter Tyser PD8_AF_FEC_MDIO, 30284ad6884SPeter Tyser PD9_AIN_FEC_MDC | GPIO_PUEN, 30384ad6884SPeter Tyser PD10_AOUT_FEC_CRS, 30484ad6884SPeter Tyser PD11_AOUT_FEC_TX_CLK, 30584ad6884SPeter Tyser PD12_AOUT_FEC_RXD0, 30684ad6884SPeter Tyser PD13_AOUT_FEC_RX_DV, 30784ad6884SPeter Tyser PD14_AOUT_FEC_CLR, 30884ad6884SPeter Tyser PD15_AOUT_FEC_COL, 30984ad6884SPeter Tyser PD16_AIN_FEC_TX_ER, 31084ad6884SPeter Tyser PF23_AIN_FEC_TX_EN, 31184ad6884SPeter Tyser }; 31284ad6884SPeter Tyser 31384ad6884SPeter Tyser for (i = 0; i < ARRAY_SIZE(mode); i++) 31484ad6884SPeter Tyser imx_gpio_mode(mode[i]); 31584ad6884SPeter Tyser } 316*565e39c5SLiu Hui-R64343 317*565e39c5SLiu Hui-R64343 void imx_get_mac_from_fuse(unsigned char *mac) 318*565e39c5SLiu Hui-R64343 { 319*565e39c5SLiu Hui-R64343 int i; 320*565e39c5SLiu Hui-R64343 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 321*565e39c5SLiu Hui-R64343 struct fuse_bank *bank = &iim->bank[0]; 322*565e39c5SLiu Hui-R64343 struct fuse_bank0_regs *fuse = 323*565e39c5SLiu Hui-R64343 (struct fuse_bank0_regs *)bank->fuse_regs; 324*565e39c5SLiu Hui-R64343 325*565e39c5SLiu Hui-R64343 for (i = 0; i < 6; i++) 326*565e39c5SLiu Hui-R64343 mac[6 - 1 - i] = readl(&fuse->mac_addr[i]) & 0xff; 327*565e39c5SLiu Hui-R64343 } 32884ad6884SPeter Tyser #endif /* CONFIG_FEC_MXC */ 32984ad6884SPeter Tyser 33084ad6884SPeter Tyser #ifdef CONFIG_MXC_MMC 3311e65c2beSHeiko Schocher void mx27_sd1_init_pins(void) 3321e65c2beSHeiko Schocher { 3331e65c2beSHeiko Schocher int i; 3341e65c2beSHeiko Schocher unsigned int mode[] = { 3351e65c2beSHeiko Schocher PE18_PF_SD1_D0, 3361e65c2beSHeiko Schocher PE19_PF_SD1_D1, 3371e65c2beSHeiko Schocher PE20_PF_SD1_D2, 3381e65c2beSHeiko Schocher PE21_PF_SD1_D3, 3391e65c2beSHeiko Schocher PE22_PF_SD1_CMD, 3401e65c2beSHeiko Schocher PE23_PF_SD1_CLK, 3411e65c2beSHeiko Schocher }; 3421e65c2beSHeiko Schocher 3431e65c2beSHeiko Schocher for (i = 0; i < ARRAY_SIZE(mode); i++) 3441e65c2beSHeiko Schocher imx_gpio_mode(mode[i]); 3451e65c2beSHeiko Schocher 3461e65c2beSHeiko Schocher } 3471e65c2beSHeiko Schocher 34884ad6884SPeter Tyser void mx27_sd2_init_pins(void) 34984ad6884SPeter Tyser { 35084ad6884SPeter Tyser int i; 35184ad6884SPeter Tyser unsigned int mode[] = { 35284ad6884SPeter Tyser PB4_PF_SD2_D0, 35384ad6884SPeter Tyser PB5_PF_SD2_D1, 35484ad6884SPeter Tyser PB6_PF_SD2_D2, 35584ad6884SPeter Tyser PB7_PF_SD2_D3, 35684ad6884SPeter Tyser PB8_PF_SD2_CMD, 35784ad6884SPeter Tyser PB9_PF_SD2_CLK, 35884ad6884SPeter Tyser }; 35984ad6884SPeter Tyser 36084ad6884SPeter Tyser for (i = 0; i < ARRAY_SIZE(mode); i++) 36184ad6884SPeter Tyser imx_gpio_mode(mode[i]); 36284ad6884SPeter Tyser 36384ad6884SPeter Tyser } 36484ad6884SPeter Tyser #endif /* CONFIG_MXC_MMC */ 365