]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - arch/arm/cpu/armv7/am33xx/clock.c
Unified codebase for TX28, TX48, TX51, TX53
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / am33xx / clock.c
index bbb9c1353f211fd563c8bf1807c087f8662a60cc..b489da084e234fa90dc447f3421ff0ea8cf78b1b 100644 (file)
 #define CLK_DIV_MASK           0x1f
 #define CLK_DIV2_MASK          0x7f
 #define CLK_SEL_SHIFT          0x8
+#define CLK_MODE_MASK          0x7
 #define CLK_MODE_SEL           0x7
-#define CLK_MODE_MASK          0xfffffff8
-#define CLK_DIV_SEL            0xFFFFFFE0
 
 
 const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER;
 const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP;
 const struct cm_dpll *cmdpll = (struct cm_dpll *)CM_DPLL;
 
+#ifdef CONFIG_SPL_BUILD
+#define enable_clk(reg, val) __enable_clk(#reg, &reg, val)
+
+static void __enable_clk(const char *name, const void *reg, u32 mask)
+{
+       unsigned long timeout = 10000000;
+
+       writel(mask, reg);
+       while (readl(reg) != mask)
+               /* poor man's timeout, since timers not initialized */
+               if (timeout-- == 0)
+                       /* no error message, since console not yet available */
+                       break;
+}
+
 static void enable_interface_clocks(void)
 {
        /* Enable all the Interconnect Modules */
-       writel(PRCM_MOD_EN, &cmper->l3clkctrl);
-       while (readl(&cmper->l3clkctrl) != PRCM_MOD_EN)
-               ;
-
-       writel(PRCM_MOD_EN, &cmper->l4lsclkctrl);
-       while (readl(&cmper->l4lsclkctrl) != PRCM_MOD_EN)
-               ;
-
-       writel(PRCM_MOD_EN, &cmper->l4fwclkctrl);
-       while (readl(&cmper->l4fwclkctrl) != PRCM_MOD_EN)
-               ;
-
-       writel(PRCM_MOD_EN, &cmwkup->wkl4wkclkctrl);
-       while (readl(&cmwkup->wkl4wkclkctrl) != PRCM_MOD_EN)
-               ;
-
-       writel(PRCM_MOD_EN, &cmper->l3instrclkctrl);
-       while (readl(&cmper->l3instrclkctrl) != PRCM_MOD_EN)
-               ;
-
-       writel(PRCM_MOD_EN, &cmper->l4hsclkctrl);
-       while (readl(&cmper->l4hsclkctrl) != PRCM_MOD_EN)
-               ;
+       enable_clk(cmper->l3clkctrl, PRCM_MOD_EN);
+       enable_clk(cmper->l4lsclkctrl, PRCM_MOD_EN);
+       enable_clk(cmper->l4fwclkctrl, PRCM_MOD_EN);
+       enable_clk(cmwkup->wkl4wkclkctrl, PRCM_MOD_EN);
+       enable_clk(cmper->l3instrclkctrl, PRCM_MOD_EN);
+       enable_clk(cmper->l4hsclkctrl, PRCM_MOD_EN);
+#ifdef CONFIG_HW_WATCHDOG
+       enable_clk(cmwkup->wdtimer1ctrl, PRCM_MOD_EN);
+#endif
+       /* GPIO0 */
+       enable_clk(cmwkup->gpio0clkctrl, PRCM_MOD_EN);
 }
 
 /*
@@ -92,32 +94,58 @@ static void power_domain_wkup_transition(void)
 static void enable_per_clocks(void)
 {
        /* Enable the control module though RBL would have done it*/
-       writel(PRCM_MOD_EN, &cmwkup->wkctrlclkctrl);
-       while (readl(&cmwkup->wkctrlclkctrl) != PRCM_MOD_EN)
-               ;
-
-       /* Enable the module clock */
-       writel(PRCM_MOD_EN, &cmper->timer2clkctrl);
-       while (readl(&cmper->timer2clkctrl) != PRCM_MOD_EN)
-               ;
-
+       enable_clk(cmwkup->wkctrlclkctrl, PRCM_MOD_EN);
+       /* Enable the timer2 clock */
+       enable_clk(cmper->timer2clkctrl, PRCM_MOD_EN);
        /* Select the Master osc 24 MHZ as Timer2 clock source */
        writel(0x1, &cmdpll->clktimer2clk);
 
+#ifdef CONFIG_SYS_NS16550_COM1
        /* UART0 */
-       writel(PRCM_MOD_EN, &cmwkup->wkup_uart0ctrl);
-       while (readl(&cmwkup->wkup_uart0ctrl) != PRCM_MOD_EN)
-               ;
-
-       /* MMC0*/
-       writel(PRCM_MOD_EN, &cmper->mmc0clkctrl);
-       while (readl(&cmper->mmc0clkctrl) != PRCM_MOD_EN)
-               ;
-
+       enable_clk(cmwkup->wkup_uart0ctrl, PRCM_MOD_EN);
+#endif
+#ifdef CONFIG_SYS_NS16550_COM2
+       enable_clk(cmper->uart1clkctrl, PRCM_MOD_EN);
+#endif
+#ifdef CONFIG_SYS_NS16550_COM3
+       enable_clk(cmper->uart2clkctrl, PRCM_MOD_EN);
+#endif
+#ifdef CONFIG_SYS_NS16550_COM4
+       enable_clk(cmper->uart3clkctrl, PRCM_MOD_EN);
+#endif
+#ifdef CONFIG_SYS_NS16550_COM5
+       enable_clk(cmper->uart4clkctrl, PRCM_MOD_EN);
+#endif
+#ifdef CONFIG_SYS_NS16550_COM6
+       enable_clk(cmper->uart5clkctrl, PRCM_MOD_EN);
+#endif
+       /* GPMC */
+       enable_clk(cmper->gpmcclkctrl, PRCM_MOD_EN);
+
+       /* ELM */
+       enable_clk(cmper->elmclkctrl, PRCM_MOD_EN);
+
+       /* Ethernet */
+       enable_clk(cmper->cpswclkctrl, PRCM_MOD_EN);
+       enable_clk(cmper->cpgmac0clkctrl, PRCM_MOD_EN);
+
+       /* MMC */
+#ifndef CONFIG_OMAP_MMC_DEV_0
+       enable_clk(cmper->mmc0clkctrl, PRCM_MOD_EN);
+#endif
+#ifdef CONFIG_OMAP_MMC_DEV_1
+       enable_clk(cmper->mmc1clkctrl, PRCM_MOD_EN);
+#endif
+#ifdef CONFIG_LCD
+       enable_clk(cmper->lcdcclkctrl, PRCM_MOD_EN);
+#endif
        /* i2c0 */
-       writel(PRCM_MOD_EN, &cmwkup->wkup_i2c0ctrl);
-       while (readl(&cmwkup->wkup_i2c0ctrl) != PRCM_MOD_EN)
-               ;
+       enable_clk(cmwkup->wkup_i2c0ctrl, PRCM_MOD_EN);
+
+       /* GPIO1-3 */
+       enable_clk(cmper->gpio1clkctrl, PRCM_MOD_EN);
+       enable_clk(cmper->gpio2clkctrl, PRCM_MOD_EN);
+       enable_clk(cmper->gpio3clkctrl, PRCM_MOD_EN);
 }
 
 static void mpu_pll_config(void)
@@ -133,15 +161,16 @@ static void mpu_pll_config(void)
        while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS)
                ;
 
-       clksel = clksel & (~CLK_SEL_MASK);
-       clksel = clksel | ((MPUPLL_M << CLK_SEL_SHIFT) | MPUPLL_N);
+       clksel &= ~CLK_SEL_MASK;
+       clksel |= (MPUPLL_M << CLK_SEL_SHIFT) | MPUPLL_N;
        writel(clksel, &cmwkup->clkseldpllmpu);
 
-       div_m2 = div_m2 & ~CLK_DIV_MASK;
-       div_m2 = div_m2 | MPUPLL_M2;
+       div_m2 &= ~CLK_DIV_MASK;
+       div_m2 |= MPUPLL_M2;
        writel(div_m2, &cmwkup->divm2dpllmpu);
 
-       clkmode = clkmode | CLK_MODE_SEL;
+       clkmode &= ~CLK_MODE_MASK;
+       clkmode |= CLK_MODE_SEL;
        writel(clkmode, &cmwkup->clkmoddpllmpu);
 
        while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK)
@@ -164,23 +193,24 @@ static void core_pll_config(void)
        while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS)
                ;
 
-       clksel = clksel & (~CLK_SEL_MASK);
-       clksel = clksel | ((COREPLL_M << CLK_SEL_SHIFT) | COREPLL_N);
+       clksel &= ~CLK_SEL_MASK;
+       clksel |= ((COREPLL_M << CLK_SEL_SHIFT) | COREPLL_N);
        writel(clksel, &cmwkup->clkseldpllcore);
 
-       div_m4 = div_m4 & ~CLK_DIV_MASK;
-       div_m4 = div_m4 | COREPLL_M4;
+       div_m4 &= ~CLK_DIV_MASK;
+       div_m4 |= COREPLL_M4;
        writel(div_m4, &cmwkup->divm4dpllcore);
 
-       div_m5 = div_m5 & ~CLK_DIV_MASK;
-       div_m5 = div_m5 | COREPLL_M5;
+       div_m5 &= ~CLK_DIV_MASK;
+       div_m5 |= COREPLL_M5;
        writel(div_m5, &cmwkup->divm5dpllcore);
 
-       div_m6 = div_m6 & ~CLK_DIV_MASK;
-       div_m6 = div_m6 | COREPLL_M6;
+       div_m6 &= ~CLK_DIV_MASK;
+       div_m6 |= COREPLL_M6;
        writel(div_m6, &cmwkup->divm6dpllcore);
 
-       clkmode = clkmode | CLK_MODE_SEL;
+       clkmode &= ~CLK_MODE_MASK;
+       clkmode |= CLK_MODE_SEL;
        writel(clkmode, &cmwkup->clkmoddpllcore);
 
        while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK)
@@ -201,21 +231,54 @@ static void per_pll_config(void)
        while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS)
                ;
 
-       clksel = clksel & (~CLK_SEL_MASK);
-       clksel = clksel | ((PERPLL_M << CLK_SEL_SHIFT) | PERPLL_N);
+       clksel &= ~CLK_SEL_MASK;
+       clksel |= (PERPLL_M << CLK_SEL_SHIFT) | PERPLL_N;
        writel(clksel, &cmwkup->clkseldpllper);
 
-       div_m2 = div_m2 & ~CLK_DIV2_MASK;
-       div_m2 = div_m2 | PERPLL_M2;
+       div_m2 &= ~CLK_DIV2_MASK;
+       div_m2 |= PERPLL_M2;
        writel(div_m2, &cmwkup->divm2dpllper);
 
-       clkmode = clkmode | CLK_MODE_SEL;
+       clkmode &= ~CLK_MODE_MASK;
+       clkmode |= CLK_MODE_SEL;
        writel(clkmode, &cmwkup->clkmoddpllper);
 
        while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK)
                ;
 }
 
+static void disp_pll_config(void)
+{
+#ifdef CONFIG_LCD
+       u32 clkmode, clksel, div_m2;
+
+       clkmode = readl(&cmwkup->clkmoddplldisp);
+       clksel = readl(&cmwkup->clkseldplldisp);
+       div_m2 = readl(&cmwkup->divm2dplldisp);
+
+       /* Set the PLL to bypass Mode */
+       writel(PLL_BYPASS_MODE, &cmwkup->clkmoddplldisp);
+
+       while (!(readl(&cmwkup->idlestdplldisp) & ST_MN_BYPASS))
+               ;
+
+       clksel &= ~CLK_SEL_MASK;
+       clksel |= (DISPPLL_M << CLK_SEL_SHIFT) | DISPPLL_N;
+       writel(clksel, &cmwkup->clkseldplldisp);
+
+       div_m2 &= ~CLK_DIV2_MASK;
+       div_m2 |= DISPPLL_M2;
+       writel(div_m2, &cmwkup->divm2dplldisp);
+
+       clkmode &= ~CLK_MODE_MASK;
+       clkmode |= CLK_MODE_SEL;
+       writel(clkmode, &cmwkup->clkmoddplldisp);
+
+       while (!(readl(&cmwkup->idlestdplldisp) & ST_DPLL_CLK))
+               ;
+#endif
+}
+
 static void ddr_pll_config(void)
 {
        u32 clkmode, clksel, div_m2;
@@ -225,23 +288,24 @@ static void ddr_pll_config(void)
        div_m2 = readl(&cmwkup->divm2dpllddr);
 
        /* Set the PLL to bypass Mode */
-       clkmode = (clkmode & CLK_MODE_MASK) | PLL_BYPASS_MODE;
+       clkmode &= ~CLK_MODE_MASK;
+       clkmode |= PLL_BYPASS_MODE;
        writel(clkmode, &cmwkup->clkmoddpllddr);
 
        /* Wait till bypass mode is enabled */
-       while ((readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS)
-                               != ST_MN_BYPASS)
+       while (!(readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS))
                ;
 
-       clksel = clksel & (~CLK_SEL_MASK);
-       clksel = clksel | ((DDRPLL_M << CLK_SEL_SHIFT) | DDRPLL_N);
+       clksel &= ~CLK_SEL_MASK;
+       clksel |= (DDRPLL_M << CLK_SEL_SHIFT) | DDRPLL_N;
        writel(clksel, &cmwkup->clkseldpllddr);
 
-       div_m2 = div_m2 & CLK_DIV_SEL;
-       div_m2 = div_m2 | DDRPLL_M2;
+       div_m2 &= ~CLK_DIV_MASK;
+       div_m2 |= DDRPLL_M2;
        writel(div_m2, &cmwkup->divm2dpllddr);
 
-       clkmode = (clkmode & CLK_MODE_MASK) | CLK_MODE_SEL;
+       clkmode &= ~CLK_MODE_MASK;
+       clkmode |= CLK_MODE_SEL;
        writel(clkmode, &cmwkup->clkmoddpllddr);
 
        /* Wait till dpll is locked */
@@ -274,6 +338,7 @@ void pll_init()
        core_pll_config();
        per_pll_config();
        ddr_pll_config();
+       disp_pll_config();
 
        /* Enable the required interconnect clocks */
        enable_interface_clocks();
@@ -284,3 +349,23 @@ void pll_init()
        /* Enable the required peripherals */
        enable_per_clocks();
 }
+#endif
+
+#define M(mn) (((mn) & CLK_SEL_MASK) >> CLK_SEL_SHIFT)
+#define N(mn) ((mn) & CLK_DIV2_MASK)
+
+unsigned long __clk_get_rate(u32 m_n, u32 div_m2)
+{
+       unsigned long rate;
+
+       div_m2 &= CLK_DIV_MASK;
+       debug("M=%u N=%u M2=%u\n", M(m_n), N(m_n), div_m2);
+       rate = V_OSCK / 1000 * M(m_n) / (N(m_n) + 1) / div_m2;
+       debug("CLK = %lu.%03luMHz\n", rate / 1000, rate % 1000);
+       return rate * 1000;
+}
+
+unsigned long lcdc_clk_rate(void)
+{
+       return clk_get_rate(cmwkup, disp);
+}