]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00180919 [MX6]Update clock tree if BUS freq is changed
authorAnson Huang <b20788@freescale.com>
Wed, 13 Jun 2012 12:20:01 +0000 (20:20 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:34:48 +0000 (08:34 +0200)
As DDR freq change is by modifying CCM register directly,
we need to update the clock tree as well, or the clock
tree will be broken. Also, we need to make sure the clock
rate counting is right.

Signed-off-by: Anson Huang <b20788@freescale.com>
arch/arm/mach-mx6/bus_freq.c
arch/arm/mach-mx6/clock.c
arch/arm/mach-mx6/crm_regs.h
arch/arm/mach-mx6/mx6_ddr_freq.S
arch/arm/plat-mxc/clock.c

index c7f8fef30923de8c549b18197f3025112429e1b1..b573f09c8920064324e63a1627db417d3eb9c453 100644 (file)
@@ -91,12 +91,25 @@ struct timeval end_time;
 static int cpu_op_nr;
 static struct cpu_op *cpu_op_tbl;
 static struct clk *pll2_400;
+static struct clk *pll2_200;
 static struct clk *cpu_clk;
 static unsigned int org_ldo;
 static struct clk *pll3;
+static struct clk *pll2;
+static struct clk *periph_clk;
+static struct clk *osc;
 
 static struct delayed_work low_bus_freq_handler;
+extern void update_usecount(struct clk *clk, bool flag);
 
+static inline void update_periph_clk_parent(struct clk *new_parent)
+{
+       update_usecount(periph_clk->parent, false);
+
+       periph_clk->parent = new_parent;
+
+       update_usecount(periph_clk->parent, true);
+}
 static void reduce_bus_freq_handler(struct work_struct *work)
 {
        unsigned long reg;
@@ -128,10 +141,15 @@ static void reduce_bus_freq_handler(struct work_struct *work)
                /* Need to ensure that PLL2_PFD_400M is kept ON. */
                clk_enable(pll2_400);
                update_ddr_freq(50000000);
+               /* Make sure periph clk's parent also got updated */
+               update_periph_clk_parent(pll2_200);
+
                audio_bus_freq_mode = 1;
                low_bus_freq_mode = 0;
        } else {
                update_ddr_freq(24000000);
+               /* Make sure periph clk's parent also got updated */
+               update_periph_clk_parent(osc);
                if (audio_bus_freq_mode)
                        clk_disable(pll2_400);
                low_bus_freq_mode = 1;
@@ -230,6 +248,7 @@ int set_high_bus_freq(int high_bus_freq)
        }
        clk_enable(pll3);
 
+
        /* Enable the PU LDO */
        if (cpu_is_mx6q() && low_bus_freq_mode) {
                __raw_writel(org_ldo, ANADIG_REG_CORE);
@@ -257,6 +276,8 @@ int set_high_bus_freq(int high_bus_freq)
 
        if (high_bus_freq) {
                update_ddr_freq(ddr_normal_rate);
+               /* Make sure periph clk's parent also got updated */
+               update_periph_clk_parent(pll2);
                if (med_bus_freq_mode)
                        clk_disable(pll2_400);
                high_bus_freq_mode = 1;
@@ -264,6 +285,8 @@ int set_high_bus_freq(int high_bus_freq)
        } else {
                clk_enable(pll2_400);
                update_ddr_freq(ddr_med_rate);
+               /* Make sure periph clk's parent also got updated */
+               update_periph_clk_parent(pll2_400);
                high_bus_freq_mode = 0;
                med_bus_freq_mode = 1;
        }
@@ -372,6 +395,20 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
                return PTR_ERR(pll2_400);
        }
 
+       pll2_200 = clk_get(NULL, "pll2_200M");
+       if (IS_ERR(pll2_400)) {
+               printk(KERN_DEBUG "%s: failed to get pll2_200M\n",
+                      __func__);
+               return PTR_ERR(pll2_200);
+       }
+
+       pll2 = clk_get(NULL, "pll2");
+       if (IS_ERR(pll2_400)) {
+               printk(KERN_DEBUG "%s: failed to get pll2\n",
+                      __func__);
+               return PTR_ERR(pll2);
+       }
+
        cpu_clk = clk_get(NULL, "cpu_clk");
        if (IS_ERR(cpu_clk)) {
                printk(KERN_DEBUG "%s: failed to get cpu_clk\n",
@@ -383,7 +420,21 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
        if (IS_ERR(pll3)) {
                printk(KERN_DEBUG "%s: failed to get pll3\n",
                       __func__);
-               return PTR_ERR(cpu_clk);
+               return PTR_ERR(pll3);
+       }
+
+       periph_clk = clk_get(NULL, "periph_clk");
+       if (IS_ERR(periph_clk)) {
+               printk(KERN_DEBUG "%s: failed to get periph\n",
+                      __func__);
+               return PTR_ERR(periph_clk);
+       }
+
+       osc = clk_get(NULL, "osc");
+       if (IS_ERR(osc)) {
+               printk(KERN_DEBUG "%s: failed to get osc\n",
+                      __func__);
+               return PTR_ERR(osc);
        }
 
        err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr);
index 2f58ca3b882f9375317d536174d011fa858114c5..975f22cc22632202abd541628620d5e58c968057 100644 (file)
@@ -499,6 +499,9 @@ static void _clk_pll_disable(struct clk *clk)
        unsigned int reg;
        void __iomem *pllbase;
 
+       if ((arm_needs_pll2_400) && (clk == &pll2_528_bus_main_clk))
+               return;
+
        pllbase = _get_pll_base(clk);
 
        reg = __raw_readl(pllbase);
@@ -520,6 +523,10 @@ static unsigned long  _clk_pll1_main_get_rate(struct clk *clk)
        unsigned int div;
        unsigned long val;
 
+       /* If PLL1 is bypassed, its rate will be from OSC directly */
+       if (__raw_readl(PLL1_SYS_BASE_ADDR) & ANADIG_PLL_SYS_BYPASS_MASK)
+               return clk_get_rate(clk->parent);
+
        div = __raw_readl(PLL1_SYS_BASE_ADDR) & ANADIG_PLL_SYS_DIV_SELECT_MASK;
        val = (clk_get_rate(clk->parent) * div) / 2;
        return val;
@@ -5288,7 +5295,6 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
        /* keep correct count. */
        clk_enable(&cpu_clk);
        clk_enable(&periph_clk);
-
        /* Disable un-necessary PFDs & PLLs */
        if (pll2_pfd_400M.usecount == 0 && cpu_is_mx6q())
                pll2_pfd_400M.disable(&pll2_pfd_400M);
index 188dbaebd57f5521f061de4a0828c7ce3c2d2c22..52fd75db9eb067badfdb432eefcbacca1670990a 100644 (file)
@@ -76,6 +76,8 @@
 /* PLL1_SYS defines */
 #define ANADIG_PLL_SYS_DIV_SELECT_MASK         (0x7F)
 #define ANADIG_PLL_SYS_DIV_SELECT_OFFSET       (0)
+#define ANADIG_PLL_SYS_BYPASS_MASK             (0x10000)
+#define ANADIG_PLL_SYS_BYPASS_OFFSET   (16)
 
 /* PLL2_528 defines */
 #define ANADIG_PLL_528_DIV_SELECT              (1)
index fbaa44df8cdc9d0943e07023cf400651b0e6fa0a..770b9cf1ba7280f397b5e52578dc2e6c570ab281 100644 (file)
@@ -77,6 +77,9 @@ set_ahb_podf_before_switch:
        ldr     r2, =0x381D00
        bic     r0, r0, r2
        orr     r0, r0, #0xD00
+       /* Make sure AXI clock divider is 1 */
+       bic     r0, r0, #0x70000
+       orr     r0, r0, #0x10000
        str     r0, [r6, #0x14]
 
 wait_div_update528_1:
@@ -182,6 +185,9 @@ periph_clk_switch6:
        ldr     r2, =0x381D00
        bic     r0, r0, r2
        orr     r0, r0, #0x900
+       /* Make sure AXI clock divider is 1 */
+       bic     r0, r0, #0x70000
+       orr     r0, r0, #0x10000
        str     r0, [r6, #0x14]
 
 wait_div_update400_2:
index 43d33376b52ddf11ba04e140a67549bf3e19c1a6..a55b3fbfb94a36678254b644aedffa1071416d7b 100755 (executable)
@@ -209,6 +209,37 @@ int clk_get_usecount(struct clk *clk)
 
 EXPORT_SYMBOL(clk_get_usecount);
 
+/*!
+ * @brief Function to update the usage count for the requested clock.
+ *
+ * This function returns none.
+ *
+ * @param clk  clk we want to update.
+ * @param flag         Increase or decrease usecount.
+ *
+ * @return Returns none.
+ */
+void update_usecount(struct clk *clk, bool flag)
+{
+       if (!flag) {
+               if (clk_get_usecount(clk) > 1) {
+                       mutex_lock(&clocks_mutex);
+                       clk->usecount--;
+                       mutex_unlock(&clocks_mutex);
+               } else
+                       clk_disable(clk);
+       } else {
+               if (clk_get_usecount(clk) < 1)
+                       clk_enable(clk);
+               else {
+                       mutex_lock(&clocks_mutex);
+                       clk->usecount++;
+                       mutex_unlock(&clocks_mutex);
+               }
+       }
+}
+EXPORT_SYMBOL(update_usecount);
+
 /* Retrieve the *current* clock rate. If the clock itself
  * does not provide a special calculation routine, ask
  * its parent and so on, until one is able to return