]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
ENGR00209846 MX6SL-Enable DVFS_CORE on all MX6 platforms
authorRanjani Vaidyanathan <ra5478@freescale.com>
Mon, 14 May 2012 21:12:59 +0000 (16:12 -0500)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:34:40 +0000 (08:34 +0200)
Add support DVFS-CORE to MX6Sololite.
Set PLL1 in bypass mode when ARM freq drops below 400MHz.
ARM will be sourced from PLL2_PFD2_400M in this case.

Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
arch/arm/mach-mx6/board-mx6sl_arm2.c
arch/arm/mach-mx6/clock_mx6sl.c
arch/arm/plat-mxc/dvfs_core.c

index 0cea2c8ec2ff8922fdd6b341cb780e72e7c78edb..4e0b7f5119ddca8a6858e0f81049da669d15ef3f 100755 (executable)
@@ -356,6 +356,29 @@ static struct i2c_board_info mxc_i2c2_board_info[] __initdata = {
        },
 };
 
+static struct mxc_dvfs_platform_data mx6sl_arm2_dvfscore_data = {
+       .reg_id                 = "cpu_vddgp",
+       .clk1_id                = "cpu_clk",
+       .clk2_id                = "gpc_dvfs_clk",
+       .gpc_cntr_offset        = MXC_GPC_CNTR_OFFSET,
+       .ccm_cdcr_offset        = MXC_CCM_CDCR_OFFSET,
+       .ccm_cacrr_offset       = MXC_CCM_CACRR_OFFSET,
+       .ccm_cdhipr_offset      = MXC_CCM_CDHIPR_OFFSET,
+       .prediv_mask            = 0x1F800,
+       .prediv_offset          = 11,
+       .prediv_val             = 3,
+       .div3ck_mask            = 0xE0000000,
+       .div3ck_offset          = 29,
+       .div3ck_val             = 2,
+       .emac_val               = 0x08,
+       .upthr_val              = 25,
+       .dnthr_val              = 9,
+       .pncthr_val             = 33,
+       .upcnt_val              = 10,
+       .dncnt_val              = 10,
+       .delay_time             = 80,
+};
+
 void __init early_console_setup(unsigned long base, struct clk *clk);
 
 static inline void mx6_arm2_init_uart(void)
@@ -733,6 +756,8 @@ static void __init mx6_arm2_init(void)
        imx6dl_add_imx_pxp_client();
        mxc_register_device(&max17135_sensor_device, NULL);
        imx6dl_add_imx_epdc(&epdc_data);
+
+       imx6q_add_dvfs_core(&mx6sl_arm2_dvfscore_data);
 }
 
 extern void __iomem *twd_base;
index 70ea1200cfda1cd78eeedb2e49253c6bbbe3fd5c..1d485c39ed38eb9e3d06161878079c998e25824b 100755 (executable)
@@ -69,7 +69,10 @@ static struct clk ipg_clk;
 
 static struct cpu_op *cpu_op_tbl;
 static int cpu_op_nr;
+static bool pll1_enabled;
+static bool arm_needs_pll2_400;
 
+DEFINE_SPINLOCK(mx6sl_clk_lock);
 #define SPIN_DELAY     1200000 /* in nanoseconds */
 
 #define AUDIO_VIDEO_MIN_CLK_FREQ       650000000
@@ -482,13 +485,39 @@ static int _clk_pll1_main_set_rate(struct clk *clk, unsigned long rate)
        return 0;
 }
 
+static int _clk_pll1_main_enable(struct clk *clk)
+{
+       pll1_enabled = true;
+       _clk_pll_enable(clk);
+       return 0;
+}
+
+static void _clk_pll1_main_disable(struct clk *clk)
+{
+       unsigned int reg;
+       void __iomem *pllbase;
+
+       pll1_enabled = false;
+       pllbase = _get_pll_base(clk);
+
+       /* Set the PLL is bypass mode only.
+         * We need to be able to set the ARM_PODF bit
+         * in WAIT mode. Setting the ARM_PODF bit
+         * requires PLL1 to be enabled.
+         */
+       reg = __raw_readl(pllbase);
+       reg |= ANADIG_PLL_BYPASS;
+
+       __raw_writel(reg, pllbase);
+}
+
 static struct clk pll1_sys_main_clk = {
        __INIT_CLK_DEBUG(pll1_sys_main_clk)
        .parent = &osc_clk,
        .get_rate = _clk_pll1_main_get_rate,
        .set_rate = _clk_pll1_main_set_rate,
-       .enable = _clk_pll_enable,
-       .disable = _clk_pll_disable,
+       .enable = _clk_pll1_main_enable,
+       .disable = _clk_pll1_main_disable,
 };
 
 static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent)
@@ -521,6 +550,7 @@ static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent)
                reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL;
        }
        __raw_writel(reg, MXC_CCM_CCSR);
+
        return 0;
 }
 
@@ -580,13 +610,19 @@ static struct clk pll2_528_bus_main_clk = {
        .disable = _clk_pll_disable,
 };
 
+static void _clk_pll2_pfd2_400M_disable(struct clk *clk)
+{
+       if (!arm_needs_pll2_400)
+               _clk_pfd_disable(clk);
+}
+
 static struct clk pll2_pfd2_400M = {
        __INIT_CLK_DEBUG(pll2_pfd2_400M)
        .parent = &pll2_528_bus_main_clk,
        .enable_reg = (void *)PFD_528_BASE_ADDR,
        .enable_shift = ANADIG_PFD2_FRAC_OFFSET,
        .enable = _clk_pfd_enable,
-       .disable = _clk_pfd_disable,
+       .disable = _clk_pll2_pfd2_400M_disable,
        .get_rate = pfd_get_rate,
        .set_rate = pfd_set_rate,
        .get_rate = pfd_get_rate,
@@ -1070,6 +1106,7 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
        u32 div;
        u32 parent_rate;
        unsigned long ipg_clk_rate, max_arm_wait_clk;
+       unsigned long flags;
 
        for (i = 0; i < cpu_op_nr; i++) {
                if (rate == cpu_op_tbl[i].cpu_rate)
@@ -1078,16 +1115,40 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
        if (i >= cpu_op_nr)
                return -EINVAL;
 
-       if (cpu_op_tbl[i].pll_rate != clk_get_rate(&pll1_sys_main_clk)) {
-               /* Change the PLL1 rate. */
-               if (pll2_pfd2_400M.usecount != 0)
+       spin_lock_irqsave(&mx6sl_clk_lock, flags);
+
+       if (rate <= clk_get_rate(&pll2_pfd2_400M)) {
+               /* Source pll1_sw_clk from step_clk which is sourced from
+                 * PLL2_PFD2_400M.
+                 */
+               if (pll1_sw_clk.parent != &pll2_pfd2_400M) {
+                       pll2_pfd2_400M.enable(&pll2_pfd2_400M);
+                       arm_needs_pll2_400 = true;
                        pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd2_400M);
-               else
-                       pll1_sw_clk.set_parent(&pll1_sw_clk, &osc_clk);
-               pll1_sys_main_clk.set_rate(&pll1_sys_main_clk, cpu_op_tbl[i].pll_rate);
-               pll1_sw_clk.set_parent(&pll1_sw_clk, &pll1_sys_main_clk);
+                       pll1_sw_clk.parent = &pll2_pfd2_400M;
+               }
+       } else {
+               if (pll1_sw_clk.parent != &pll1_sys_main_clk) {
+                       /* pll1_sw_clk was being sourced from pll2_400M. */
+                       /* Enable PLL1 and set pll1_sw_clk parent as PLL1 */
+                       if (!pll1_enabled)
+                               pll1_sys_main_clk.enable(&pll1_sys_main_clk);
+                       pll1_sw_clk.set_parent(&pll1_sw_clk, &pll1_sys_main_clk);
+                       pll1_sw_clk.parent = &pll1_sys_main_clk;
+                       arm_needs_pll2_400 = false;
+                       if (pll2_pfd2_400M.usecount == 0)
+                               pll2_pfd2_400M.disable(&pll2_pfd2_400M);
+               }
+               if (cpu_op_tbl[i].pll_rate != clk_get_rate(&pll1_sys_main_clk)) {
+                       /* Change the PLL1 rate. */
+                       if (pll2_pfd2_400M.usecount != 0)
+                               pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd2_400M);
+                       else
+                               pll1_sw_clk.set_parent(&pll1_sw_clk, &osc_clk);
+                       pll1_sys_main_clk.set_rate(&pll1_sys_main_clk, cpu_op_tbl[i].pll_rate);
+                       pll1_sw_clk.set_parent(&pll1_sw_clk, &pll1_sys_main_clk);
+               }
        }
-
        parent_rate = clk_get_rate(clk->parent);
        div = parent_rate / rate;
        /* Calculate the ARM_PODF to be applied when the system
@@ -1117,8 +1178,13 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
        if ((parent_rate / div) > rate)
                div++;
 
-       if (div > 8)
+       if (div > 8) {
+               spin_unlock_irqrestore(&mx6sl_clk_lock, flags);
                return -1;
+       }
+
+       if (!pll1_enabled)
+               pll1_sys_main_clk.enable(&pll1_sys_main_clk);
 
        cur_arm_podf = div;
 
@@ -1127,6 +1193,11 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
        while (__raw_readl(MXC_CCM_CDHIPR))
                ;
 
+       if (pll1_sys_main_clk.usecount == 1 && arm_needs_pll2_400)
+               pll1_sys_main_clk.disable(&pll1_sys_main_clk);
+
+       spin_unlock_irqrestore(&mx6sl_clk_lock, flags);
+
        return 0;
 }
 
@@ -3626,7 +3697,7 @@ static void clk_tree_init(void)
         * in this case, periph clk will set to 400MHz in uboot,
         * so in clock init, we need to check whether the ddr clock
         * is set to 400MHz, if yes, then we should set periph clk
-        * parent to pll2_pfd_400M.
+        * parent to pll2_pfd2_400M.
         */
        if ((reg & MMDC_MDMISC_DDR_TYPE_MASK) ==
                (0x1 << MMDC_MDMISC_DDR_TYPE_OFFSET)) {
index d52f7b6eb0393f728709bedf11af5b13de45a2c0..a31ee9a7194097dfe1d674dde302e9328a19e9dd 100755 (executable)
@@ -427,7 +427,7 @@ static int set_cpu_freq(int op)
 {
        int ret = 0;
 
-       if (cpu_is_mx6q() || cpu_is_mx6dl())
+       if (cpu_is_mx6())
                ret = mx6_set_cpu_freq(op);
        else
                ret = mx5_set_cpu_freq(op);
@@ -476,7 +476,7 @@ static int start_dvfs(void)
        /* GPCIRQ=1, select ARM IRQ */
        reg |= MXC_GPCCNTR_GPCIRQ_ARM;
        /* ADU=1, select ARM domain */
-       if (!(cpu_is_mx6q() || cpu_is_mx6dl()))
+       if (!cpu_is_mx6())
                reg |= MXC_GPCCNTR_ADU;
        __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);
 
@@ -509,7 +509,7 @@ static int start_dvfs(void)
        __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR);
 
        /* Enable DVFS */
-       if (cpu_is_mx6q() || cpu_is_mx6dl()) {
+       if (cpu_is_mx6()) {
                unsigned long cpu_wfi = 0;
                int num_cpus = num_possible_cpus();
                reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_EMAC);
@@ -947,7 +947,7 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev)
                printk(KERN_ERR "%s: failed to get cpu clock\n", __func__);
                return PTR_ERR(cpu_clk);
        }
-       if (!(cpu_is_mx6q() || cpu_is_mx6dl())) {
+       if (!cpu_is_mx6()) {
                dvfs_clk = clk_get(NULL, dvfs_data->clk2_id);
                if (IS_ERR(dvfs_clk)) {
                        printk(KERN_ERR "%s: failed to get dvfs clock\n", __func__);