]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/arm/mach-mx6/clock.c
ENGR00176655:mx6:remove openvg_axi_clk from gpu2d_axi_clk's secondary
[karo-tx-linux.git] / arch / arm / mach-mx6 / clock.c
index a837918a1417a6f8ec8fad1bc5e697a2ca33343c..813c55432d708aea873e1c65ee069aa23b9c2e8b 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
  */
 
 /*
@@ -23,6 +23,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/clkdev.h>
+#include <linux/regulator/consumer.h>
 #include <asm/div64.h>
 #include <mach/hardware.h>
 #include <mach/common.h>
@@ -30,6 +31,7 @@
 #include <mach/mxc_dvfs.h>
 #include "crm_regs.h"
 #include "cpu_op-mx6.h"
+#include "regs-anadig.h"
 
 #ifdef CONFIG_CLK_DEBUG
 #define __INIT_CLK_DEBUG(n)    .name = #n,
 #define __INIT_CLK_DEBUG(n)
 #endif
 
+extern u32 arm_max_freq;
 extern int mxc_jtag_enabled;
+extern struct regulator *cpu_regulator;
 extern struct cpu_op *(*get_cpu_op)(int *op);
 extern int lp_high_freq;
 extern int lp_med_freq;
+extern int mx6q_revision(void);
 
 void __iomem *apll_base;
 static struct clk pll1_sys_main_clk;
@@ -49,24 +54,28 @@ static struct clk pll2_pfd_400M;
 static struct clk pll3_usb_otg_main_clk;
 static struct clk pll4_audio_main_clk;
 static struct clk pll5_video_main_clk;
-static struct clk pll6_MLB_main_clk;
+static struct clk pll6_mlb150_main_clk;
 static struct clk pll7_usb_host_main_clk;
 static struct clk pll8_enet_main_clk;
 static struct clk apbh_dma_clk;
 static struct clk openvg_axi_clk;
 static struct clk enfc_clk;
-static struct clk ipu1_di_clk_root;
-static struct clk ipu2_di_clk_root;
 static struct clk usdhc3_clk;
 
 static struct cpu_op *cpu_op_tbl;
 static int cpu_op_nr;
 
-#define SPIN_DELAY     1000000 /* in nanoseconds */
+#define SPIN_DELAY     1200000 /* in nanoseconds */
 
 #define AUDIO_VIDEO_MIN_CLK_FREQ       650000000
 #define AUDIO_VIDEO_MAX_CLK_FREQ       1300000000
 
+/* We need to check the exp status again after timer expiration,
+ * as there might be interrupt coming between the first time exp
+ * and the time reading, then the time reading may be several ms
+ * after the exp checking due to the irq handle, so we need to
+ * check it to make sure the exp return the right value after
+ * timer expiration. */
 #define WAIT(exp, timeout) \
 ({ \
        struct timespec nstimeofday; \
@@ -76,7 +85,8 @@ static int cpu_op_nr;
        while (!(exp)) { \
                getnstimeofday(&curtime); \
                if ((curtime.tv_nsec - nstimeofday.tv_nsec) > (timeout)) { \
-                       result = 0; \
+                       if (!(exp)) \
+                               result = 0; \
                        break; \
                } \
        } \
@@ -86,6 +96,22 @@ static int cpu_op_nr;
 /* External clock values passed-in by the board code */
 static unsigned long external_high_reference, external_low_reference;
 static unsigned long oscillator_reference, ckih2_reference;
+static unsigned long anaclk_1_reference, anaclk_2_reference;
+
+/* For MX 6DL/S, Video PLL may be used by synchronous display devices,
+ * such as HDMI or LVDS, and also by the EPDC.  If EPDC is in use,
+ * it must use the Video PLL to achieve the clock frequencies it needs.
+ * So if EPDC is in use, the "epdc" string should be added to kernel
+ * parameters, in order to set the EPDC parent clock to the Video PLL.
+ * This will have an impact on the behavior of HDMI and LVDS.
+ */
+int epdc_enabled;
+static int __init epdc_setup(char *__unused)
+{
+       epdc_enabled = 1;
+       return 1;
+}
+__setup("epdc", epdc_setup);
 
 static void __calc_pre_post_dividers(u32 max_podf, u32 div, u32 *pre, u32 *post)
 {
@@ -198,7 +224,7 @@ static inline void __iomem *_get_pll_base(struct clk *pll)
                return PLL4_AUDIO_BASE_ADDR;
        else if (pll == &pll5_video_main_clk)
                return PLL5_VIDEO_BASE_ADDR;
-       else if (pll == &pll6_MLB_main_clk)
+       else if (pll == &pll6_mlb150_main_clk)
                return PLL6_MLB_BASE_ADDR;
        else if (pll == &pll7_usb_host_main_clk)
                return PLL7_480_USB2_BASE_ADDR;
@@ -254,6 +280,28 @@ static unsigned long get_ckih2_reference_clock_rate(struct clk *clk)
        return ckih2_reference;
 }
 
+static unsigned long _clk_anaclk_1_get_rate(struct clk *clk)
+{
+       return anaclk_1_reference;
+}
+
+static int _clk_anaclk_1_set_rate(struct clk *clk, unsigned long rate)
+{
+       anaclk_1_reference = rate;
+       return 0;
+}
+
+static unsigned long _clk_anaclk_2_get_rate(struct clk *clk)
+{
+       return anaclk_2_reference;
+}
+
+static int _clk_anaclk_2_set_rate(struct clk *clk, unsigned long rate)
+{
+       anaclk_2_reference = rate;
+       return 0;
+}
+
 /* External high frequency clock */
 static struct clk ckih_clk = {
        __INIT_CLK_DEBUG(ckih_clk)
@@ -276,6 +324,18 @@ static struct clk ckil_clk = {
        .get_rate = get_low_reference_clock_rate,
 };
 
+static struct clk anaclk_1 = {
+       __INIT_CLK_DEBUG(anaclk_1)
+       .get_rate = _clk_anaclk_1_get_rate,
+       .set_rate = _clk_anaclk_1_set_rate,
+};
+
+static struct clk anaclk_2 = {
+       __INIT_CLK_DEBUG(anaclk_2)
+       .get_rate = _clk_anaclk_2_get_rate,
+       .set_rate = _clk_anaclk_2_set_rate,
+};
+
 static unsigned long pfd_round_rate(struct clk *clk, unsigned long rate)
 {
        u32 frac;
@@ -332,9 +392,6 @@ static int pfd_set_rate(struct clk *clk, unsigned long rate)
        __raw_writel(frac << clk->enable_shift,
                        (int)clk->enable_reg + 4);
 
-       tmp = (u64)clk_get_rate(clk->parent) * 18;
-       do_div(tmp, frac);
-
        if (apbh_dma_clk.usecount == 0)
                apbh_dma_clk.disable(&apbh_dma_clk);
        return 0;
@@ -385,6 +442,10 @@ static int _clk_pll_enable(struct clk *clk)
 
        __raw_writel(reg, pllbase);
 
+       /* It will power on pll3 */
+       if (clk == &pll3_usb_otg_main_clk)
+               __raw_writel(BM_ANADIG_ANA_MISC2_CONTROL0, apll_base + HW_ANADIG_ANA_MISC2_CLR);
+
        /* Wait for PLL to lock */
        if (!WAIT(__raw_readl(pllbase) & ANADIG_PLL_LOCK,
                                SPIN_DELAY))
@@ -407,14 +468,16 @@ static void _clk_pll_disable(struct clk *clk)
 
        reg = __raw_readl(pllbase);
        reg |= ANADIG_PLL_BYPASS;
-       reg |= ANADIG_PLL_POWER_DOWN;
+       reg &= ~ANADIG_PLL_ENABLE;
 
-       /* The 480MHz PLLs, pll3 & pll7, have the opposite
-        * definition for power bit.
-        */
-       if (clk == &pll3_usb_otg_main_clk || clk == &pll7_usb_host_main_clk)
-               reg &= ~ANADIG_PLL_POWER_DOWN;
        __raw_writel(reg, pllbase);
+
+       /*
+        * It will power off PLL3's power, it is the TO1.1 fix
+        * Please see TKT064178 for detail.
+        */
+       if (clk == &pll3_usb_otg_main_clk)
+               __raw_writel(BM_ANADIG_ANA_MISC2_CONTROL0, apll_base + HW_ANADIG_ANA_MISC2_SET);
 }
 
 static unsigned long  _clk_pll1_main_get_rate(struct clk *clk)
@@ -429,17 +492,23 @@ static unsigned long  _clk_pll1_main_get_rate(struct clk *clk)
 
 static int _clk_pll1_main_set_rate(struct clk *clk, unsigned long rate)
 {
-       unsigned int reg,  div;
+       unsigned int reg, div;
 
        if (rate < AUDIO_VIDEO_MIN_CLK_FREQ || rate > AUDIO_VIDEO_MAX_CLK_FREQ)
                return -EINVAL;
 
-       div = (rate * 2) / clk_get_rate(clk->parent) ;
+       div = (rate * 2) / clk_get_rate(clk->parent);
 
+       /* Update div */
        reg = __raw_readl(PLL1_SYS_BASE_ADDR) & ~ANADIG_PLL_SYS_DIV_SELECT_MASK;
        reg |= div;
        __raw_writel(reg, PLL1_SYS_BASE_ADDR);
 
+       /* Wait for PLL1 to lock */
+       if (!WAIT(__raw_readl(PLL1_SYS_BASE_ADDR) & ANADIG_PLL_LOCK,
+                               SPIN_DELAY))
+               panic("pll1 enable failed\n");
+
        return 0;
 }
 
@@ -634,6 +703,7 @@ static struct clk pll3_usb_otg_main_clk = {
        .get_rate = _clk_pll3_usb_otg_get_rate,
 };
 
+/* for USB OTG */
 static struct clk usb_phy1_clk = {
        __INIT_CLK_DEBUG(usb_phy1_clk)
        .parent = &pll3_usb_otg_main_clk,
@@ -641,6 +711,22 @@ static struct clk usb_phy1_clk = {
        .get_rate = _clk_pll3_usb_otg_get_rate,
 };
 
+/* For HSIC port 1 */
+static struct clk usb_phy3_clk = {
+       __INIT_CLK_DEBUG(usb_phy3_clk)
+       .parent = &pll3_usb_otg_main_clk,
+       .set_rate = _clk_pll3_usb_otg_set_rate,
+       .get_rate = _clk_pll3_usb_otg_get_rate,
+};
+
+/* For HSIC port 2 */
+static struct clk usb_phy4_clk = {
+       __INIT_CLK_DEBUG(usb_phy4_clk)
+       .parent = &pll3_usb_otg_main_clk,
+       .set_rate = _clk_pll3_usb_otg_set_rate,
+       .get_rate = _clk_pll3_usb_otg_get_rate,
+};
+
 static struct clk pll3_pfd_508M = {
        __INIT_CLK_DEBUG(pll3_pfd_508M)
        .parent = &pll3_usb_otg_main_clk,
@@ -741,17 +827,40 @@ static unsigned long  _clk_audio_video_get_rate(struct clk *clk)
        unsigned long rate;
        unsigned int parent_rate = clk_get_rate(clk->parent);
        void __iomem *pllbase;
+       int rev = mx6q_revision();
+       unsigned int test_div_sel, control3, post_div = 1;
 
        if (clk == &pll4_audio_main_clk)
                pllbase = PLL4_AUDIO_BASE_ADDR;
        else
                pllbase = PLL5_VIDEO_BASE_ADDR;
 
+       if ((rev >= IMX_CHIP_REVISION_1_1) || cpu_is_mx6dl()) {
+               test_div_sel = (__raw_readl(pllbase)
+                       & ANADIG_PLL_AV_TEST_DIV_SEL_MASK)
+                       >> ANADIG_PLL_AV_TEST_DIV_SEL_OFFSET;
+               if (test_div_sel == 0)
+                       post_div = 4;
+               else if (test_div_sel == 1)
+                       post_div = 2;
+
+               if (clk == &pll5_video_main_clk) {
+                       control3 = (__raw_readl(ANA_MISC2_BASE_ADDR)
+                               & ANADIG_ANA_MISC2_CONTROL3_MASK)
+                               >> ANADIG_ANA_MISC2_CONTROL3_OFFSET;
+                       if (control3 == 1)
+                               post_div *= 2;
+                       else if (control3 == 3)
+                               post_div *= 4;
+               }
+       }
+
        div = __raw_readl(pllbase) & ANADIG_PLL_SYS_DIV_SELECT_MASK;
        mfn = __raw_readl(pllbase + PLL_NUM_DIV_OFFSET);
        mfd = __raw_readl(pllbase + PLL_DENOM_DIV_OFFSET);
 
        rate = (parent_rate * div) + ((parent_rate / mfd) * mfn);
+       rate = rate / post_div;
 
        return rate;
 }
@@ -763,9 +872,19 @@ static int _clk_audio_video_set_rate(struct clk *clk, unsigned long rate)
        s64 temp64;
        unsigned int parent_rate = clk_get_rate(clk->parent);
        void __iomem *pllbase;
+       unsigned long min_clk_rate, pre_div_rate;
+       int rev = mx6q_revision();
+       u32 test_div_sel = 2;
+       u32 control3 = 0;
+
+       if ((rev < IMX_CHIP_REVISION_1_1) && !cpu_is_mx6dl())
+               min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ;
+       else if (clk == &pll4_audio_main_clk)
+               min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 4;
+       else
+               min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 16;
 
-       if ((rate < AUDIO_VIDEO_MIN_CLK_FREQ) ||
-               (rate > AUDIO_VIDEO_MAX_CLK_FREQ))
+       if ((rate < min_clk_rate) || (rate > AUDIO_VIDEO_MAX_CLK_FREQ))
                return -EINVAL;
 
        if (clk == &pll4_audio_main_clk)
@@ -773,33 +892,142 @@ static int _clk_audio_video_set_rate(struct clk *clk, unsigned long rate)
        else
                pllbase = PLL5_VIDEO_BASE_ADDR;
 
-       div = rate / parent_rate ;
-       temp64 = (u64) (rate - (div * parent_rate));
+       pre_div_rate = rate;
+       if ((rev >= IMX_CHIP_REVISION_1_1) || cpu_is_mx6dl()) {
+               while (pre_div_rate < AUDIO_VIDEO_MIN_CLK_FREQ) {
+                       pre_div_rate *= 2;
+                       /*
+                        * test_div_sel field values:
+                        * 2 -> Divide by 1
+                        * 1 -> Divide by 2
+                        * 0 -> Divide by 4
+                        *
+                        * control3 field values:
+                        * 0 -> Divide by 1
+                        * 1 -> Divide by 2
+                        * 3 -> Divide by 4
+                        */
+                       if (test_div_sel != 0)
+                               test_div_sel--;
+                       else {
+                               control3++;
+                               if (control3 == 2)
+                                       control3++;
+                       }
+               }
+       }
+
+       div = pre_div_rate / parent_rate;
+       temp64 = (u64) (pre_div_rate - (div * parent_rate));
        temp64 *= mfd;
        do_div(temp64, parent_rate);
        mfn = temp64;
 
-       reg = __raw_readl(pllbase) & ~ANADIG_PLL_SYS_DIV_SELECT_MASK;
-       reg |= div;
+       reg = __raw_readl(pllbase)
+                       & ~ANADIG_PLL_SYS_DIV_SELECT_MASK
+                       & ~ANADIG_PLL_AV_TEST_DIV_SEL_MASK;
+       reg |= div |
+               (test_div_sel << ANADIG_PLL_AV_TEST_DIV_SEL_OFFSET);
        __raw_writel(reg, pllbase);
        __raw_writel(mfn, pllbase + PLL_NUM_DIV_OFFSET);
        __raw_writel(mfd, pllbase + PLL_DENOM_DIV_OFFSET);
 
+       if (rev >= IMX_CHIP_REVISION_1_1) {
+               reg = __raw_readl(ANA_MISC2_BASE_ADDR)
+                       & ~ANADIG_ANA_MISC2_CONTROL3_MASK;
+               reg |= control3 << ANADIG_ANA_MISC2_CONTROL3_OFFSET;
+               __raw_writel(reg, ANA_MISC2_BASE_ADDR);
+       }
+
        return 0;
 }
 
 static unsigned long _clk_audio_video_round_rate(struct clk *clk,
                                                unsigned long rate)
 {
-       if (rate < AUDIO_VIDEO_MIN_CLK_FREQ)
-               return AUDIO_VIDEO_MIN_CLK_FREQ;
+       unsigned long min_clk_rate;
+       unsigned int div, post_div = 1;
+       unsigned int mfn, mfd = 1000000;
+       s64 temp64;
+       unsigned int parent_rate = clk_get_rate(clk->parent);
+       unsigned long pre_div_rate;
+       u32 test_div_sel = 2;
+       u32 control3 = 0;
+       unsigned long final_rate;
+       int rev = mx6q_revision();
+
+       if ((rev < IMX_CHIP_REVISION_1_1) && !cpu_is_mx6dl())
+               min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ;
+       else if (clk == &pll4_audio_main_clk)
+               min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 4;
+       else
+               min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 16;
+
+       if (rate < min_clk_rate)
+               return min_clk_rate;
 
        if (rate > AUDIO_VIDEO_MAX_CLK_FREQ)
                return AUDIO_VIDEO_MAX_CLK_FREQ;
 
-       return rate;
+       pre_div_rate = rate;
+       if ((rev >= IMX_CHIP_REVISION_1_1) || cpu_is_mx6dl()) {
+               while (pre_div_rate < AUDIO_VIDEO_MIN_CLK_FREQ) {
+                       pre_div_rate *= 2;
+                       post_div *= 2;
+                       if (test_div_sel != 0)
+                               test_div_sel--;
+                       else {
+                               control3++;
+                               if (control3 == 2)
+                                       control3++;
+                       }
+               }
+       }
+
+       div = pre_div_rate / parent_rate;
+       temp64 = (u64) (pre_div_rate - (div * parent_rate));
+       temp64 *= mfd;
+       do_div(temp64, parent_rate);
+       mfn = temp64;
+
+       final_rate = (parent_rate * div) + ((parent_rate / mfd) * mfn);
+       final_rate = final_rate / post_div;
+
+       return final_rate;
 }
 
+static int _clk_audio_video_set_parent(struct clk *clk, struct clk *parent)
+{
+       u32 reg;
+       int mux;
+       void __iomem *pllbase;
+
+       if (clk == &pll4_audio_main_clk)
+               pllbase = PLL4_AUDIO_BASE_ADDR;
+       else
+               pllbase = PLL5_VIDEO_BASE_ADDR;
+
+       reg = __raw_readl(pllbase) & ~ANADIG_PLL_BYPASS_CLK_SRC_MASK;
+       mux = _get_mux6(parent, &osc_clk, &anaclk_1, &anaclk_2,
+                               NULL, NULL, NULL);
+       reg |= mux << ANADIG_PLL_BYPASS_CLK_SRC_OFFSET;
+       __raw_writel(reg, pllbase);
+
+       /* Set anaclk_x as input */
+       if (parent == &anaclk_1) {
+               reg = __raw_readl(ANADIG_MISC1_REG);
+               reg |= (ANATOP_LVDS_CLK1_IBEN_MASK &
+                               ~ANATOP_LVDS_CLK1_OBEN_MASK);
+               __raw_writel(reg, ANADIG_MISC1_REG);
+       } else if (parent == &anaclk_2) {
+               reg = __raw_readl(ANADIG_MISC1_REG);
+               reg |= (ANATOP_LVDS_CLK2_IBEN_MASK &
+                               ~ANATOP_LVDS_CLK2_OBEN_MASK);
+               __raw_writel(reg, ANADIG_MISC1_REG);
+       }
+
+       return 0;
+}
 
 static struct clk pll4_audio_main_clk = {
        __INIT_CLK_DEBUG(pll4_audio_main_clk)
@@ -809,9 +1037,9 @@ static struct clk pll4_audio_main_clk = {
        .set_rate = _clk_audio_video_set_rate,
        .get_rate = _clk_audio_video_get_rate,
        .round_rate = _clk_audio_video_round_rate,
+       .set_parent = _clk_audio_video_set_parent,
 };
 
-
 static struct clk pll5_video_main_clk = {
        __INIT_CLK_DEBUG(pll5_video_main_clk)
        .parent = &osc_clk,
@@ -820,12 +1048,34 @@ static struct clk pll5_video_main_clk = {
        .set_rate = _clk_audio_video_set_rate,
        .get_rate = _clk_audio_video_get_rate,
        .round_rate = _clk_audio_video_round_rate,
+       .set_parent = _clk_audio_video_set_parent,
 };
 
-static struct clk pll6_MLB_main_clk = {
-       __INIT_CLK_DEBUG(pll6_MLB_main_clk)
+static int _clk_pll_mlb_main_enable(struct clk *clk)
+{
+       unsigned int reg;
+       void __iomem *pllbase;
+
+       pllbase = _get_pll_base(clk);
+
+       reg = __raw_readl(pllbase);
+       reg &= ~ANADIG_PLL_BYPASS;
+
+       reg = 0x0da20000;
+       __raw_writel(reg, pllbase);
+
+       /* Wait for PLL to lock */
+       if (!WAIT(__raw_readl(pllbase) & ANADIG_PLL_LOCK,
+               SPIN_DELAY))
+               panic("pll enable failed\n");
+
+       return 0;
+}
+
+static struct clk pll6_mlb150_main_clk = {
+       __INIT_CLK_DEBUG(pll6_mlb150_main_clk)
        .parent = &osc_clk,
-       .enable = _clk_pll_enable,
+       .enable = _clk_pll_mlb_main_enable,
        .disable = _clk_pll_disable,
 };
 
@@ -894,7 +1144,7 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
        int i;
        u32 div;
        u32 parent_rate;
-       struct clk *old_parent = pll1_sw_clk.parent;
+
 
        for (i = 0; i < cpu_op_nr; i++) {
                if (rate == cpu_op_tbl[i].cpu_rate)
@@ -903,23 +1153,14 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
        if (i >= cpu_op_nr)
                return -EINVAL;
 
-       if (rate <= clk_get_rate(&pll2_pfd_400M)) {
-               /*
-                 * Move pll1_sw_clk to PLL2_PFD_400M
-                 * so that we can disable PLL1.
-                 */
-               if (pll2_pfd_400M.usecount == 0)
-                       pll2_pfd_400M.enable(&pll2_pfd_400M);
-               pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd_400M);
-               pll1_sw_clk.parent = &pll2_pfd_400M;
-       } else {
-               /* Rate is above 400MHz.  We may need to relock PLL1. */
-               pll1_sw_clk.set_parent(&pll1_sw_clk, &osc_clk);
-               if (pll1_sys_main_clk.usecount == 0)
-                       pll1_sys_main_clk.enable(&pll1_sys_main_clk);
+       if (cpu_op_tbl[i].pll_rate != clk_get_rate(&pll1_sys_main_clk)) {
+               /* Change the PLL1 rate. */
+               if (pll2_pfd_400M.usecount != 0)
+                       pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd_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 = &pll1_sys_main_clk;
        }
 
        parent_rate = clk_get_rate(clk->parent);
@@ -936,15 +1177,6 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
 
        __raw_writel(div - 1, MXC_CCM_CACRR);
 
-       /* Increment current parent's usecount. */
-       pll1_sw_clk.parent->usecount++;
-
-       /* Decrement the current parent's usecount */
-       old_parent->usecount--;
-
-       if (old_parent->usecount == 0)
-               old_parent->disable(old_parent);
-
        return 0;
 }
 
@@ -955,6 +1187,17 @@ static struct clk cpu_clk = {
        .get_rate = _clk_arm_get_rate,
 };
 
+static unsigned long _clk_twd_get_rate(struct clk *clk)
+{
+       return clk_get_rate(clk->parent) / 2;
+}
+
+static struct clk twd_clk = {
+       __INIT_CLK_DEBUG(twd_clk)
+       .parent = &cpu_clk,
+       .get_rate = _clk_twd_get_rate,
+};
+
 static int _clk_periph_set_parent(struct clk *clk, struct clk *parent)
 {
        u32 reg;
@@ -1097,7 +1340,7 @@ static int _clk_axi_set_parent(struct clk *clk, struct clk *parent)
                /* Set the AXI_ALT_SEL mux. */
                reg = __raw_readl(MXC_CCM_CBCDR)
                        & ~MXC_CCM_CBCDR_AXI_ALT_SEL_MASK;
-               reg = ((mux - 1) << MXC_CCM_CBCDR_AXI_ALT_SEL_OFFSET);
+               reg |= ((mux - 1) << MXC_CCM_CBCDR_AXI_ALT_SEL_OFFSET);
                __raw_writel(reg, MXC_CCM_CBCDR);
 
                /* Set the AXI_SEL mux */
@@ -1522,7 +1765,6 @@ static int _clk_gpu2d_axi_set_parent(struct clk *clk, struct clk *parent)
 static struct clk gpu2d_axi_clk = {
        __INIT_CLK_DEBUG(gpu2d_axi_clk)
        .parent = &axi_clk,
-       .secondary = &mmdc_ch0_axi_clk[0],
        .set_parent = _clk_gpu2d_axi_set_parent,
 };
 
@@ -1596,15 +1838,30 @@ static struct clk vdoa_clk = {
        .disable = _clk_disable,
 };
 
+static unsigned long _clk_gpt_get_rate(struct clk *clk)
+{
+       unsigned long rate;
+
+       if (mx6q_revision() == IMX_CHIP_REVISION_1_0)
+               return clk_get_rate(clk->parent);
+
+       rate = mx6_timer_rate();
+       if (!rate)
+               return clk_get_rate(clk->parent);
+
+       return rate;
+}
+
 static struct clk gpt_clk[] = {
        {
        __INIT_CLK_DEBUG(gpt_clk)
-        .parent = &ipg_perclk,
+        .parent = &osc_clk,
         .id = 0,
         .enable_reg = MXC_CCM_CCGR1,
         .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET,
         .enable = _clk_enable,
         .disable = _clk_disable,
+        .get_rate = _clk_gpt_get_rate,
         .secondary = &gpt_clk[1],
         },
        {
@@ -1617,6 +1874,11 @@ static struct clk gpt_clk[] = {
         },
 };
 
+static unsigned long _clk_iim_get_rate(struct clk *clk)
+{
+       return clk_get_rate(clk->parent);
+}
+
 static struct clk iim_clk = {
        __INIT_CLK_DEBUG(iim_clk)
        .parent = &ipg_clk,
@@ -1624,6 +1886,7 @@ static struct clk iim_clk = {
        .enable_reg = MXC_CCM_CCGR2,
        .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET,
        .disable = _clk_disable,
+       .get_rate = _clk_iim_get_rate,
 };
 
 static struct clk i2c_clk[] = {
@@ -1828,123 +2091,6 @@ static struct clk ipu1_clk = {
        .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
 };
 
-static int _clk_cko1_clk0_set_parent(struct clk *clk, struct clk *parent)
-{
-       u32 sel, reg;
-
-       if (parent == &pll3_sw_clk)
-               sel = 0;
-       else if (parent == &pll2_528_bus_main_clk)
-               sel = 1;
-       else if (parent == &pll1_sys_main_clk)
-               sel = 2;
-       else if (parent == &pll5_video_main_clk)
-               sel = 3;
-       else if (parent == &axi_clk)
-               sel = 5;
-       else if (parent == &enfc_clk)
-               sel = 6;
-       else if (parent == &ipu1_di_clk_root)
-               sel = 7;
-       else if (parent == &ipu1_di_clk_root)
-               sel = 8;
-       else if (parent == &ipu2_di_clk_root)
-               sel = 9;
-       else if (parent == &ipu2_di_clk_root)
-               sel = 10;
-       else if (parent == &ahb_clk)
-               sel = 11;
-       else if (parent == &ipg_clk)
-               sel = 12;
-       else if (parent == &ipg_perclk)
-               sel = 13;
-       else if (parent == &ckil_clk)
-               sel = 14;
-       else if (parent == &pll4_audio_main_clk)
-               sel = 15;
-       else
-               return -EINVAL;
-
-       reg = __raw_readl(MXC_CCM_CCOSR);
-       reg &= ~MXC_CCM_CCOSR_CKOL_SEL_MASK;
-       reg |= sel << MXC_CCM_CCOSR_CKOL_SEL_OFFSET;
-       __raw_writel(reg, MXC_CCM_CCOSR);
-       return 0;
-}
-
-static unsigned long _clk_cko1_round_rate(struct clk *clk,
-                                               unsigned long rate)
-{
-       u32 div;
-       u32 parent_rate = clk_get_rate(clk->parent);
-
-       div = parent_rate / rate;
-
-       /* Make sure rate is not greater than the maximum value for the clock.
-        * Also prevent a div of 0.
-        */
-       if (div == 0)
-               div++;
-
-       if (div > 8)
-               div = 8;
-
-       return parent_rate / div;
-}
-
-static int _clk_cko1_set_rate(struct clk *clk, unsigned long rate)
-{
-       u32 reg, div;
-       u32 parent_rate = clk_get_rate(clk->parent);
-
-       div = parent_rate / rate;
-       if (div == 0)
-               div++;
-       if (((parent_rate / div) != rate) || (div > 8))
-               return -EINVAL;
-
-       reg = __raw_readl(MXC_CCM_CCOSR);
-       reg &= ~MXC_CCM_CCOSR_CKOL_DIV_MASK;
-       reg |= div << MXC_CCM_CCOSR_CKOL_DIV_OFFSET;
-       __raw_writel(reg, MXC_CCM_CCOSR);
-
-       return 0;
-}
-
-static unsigned long _clk_cko1_get_rate(struct clk *clk)
-{
-       u32 reg, div;
-
-       reg = __raw_readl(MXC_CCM_CCOSR);
-       div = ((reg & MXC_CCM_CCOSR_CKOL_DIV_MASK) >>
-                       MXC_CCM_CCOSR_CKOL_DIV_OFFSET) + 1;
-
-       return clk_get_rate(clk->parent) / div;
-}
-
-static int cko1_clk_enable(struct clk *clk)
-{
-       u32 reg;
-       reg = __raw_readl(clk->enable_reg);
-       reg |= clk->enable_shift;
-       __raw_writel(reg, clk->enable_reg);
-
-       return 0;
-}
-
-static struct clk cko1_clk0 = {
-       __INIT_CLK_DEBUG(cko1_clk0)
-       .parent = &ipg_clk,
-       .enable_reg = MXC_CCM_CCOSR,
-       .enable_shift = MXC_CCM_CCOSR_CKOL_EN,
-       .enable = cko1_clk_enable,
-       .disable = _clk_disable,
-       .set_parent = _clk_cko1_clk0_set_parent,
-       .round_rate = _clk_cko1_round_rate,
-       .set_rate = _clk_cko1_set_rate,
-       .get_rate = _clk_cko1_get_rate,
-};
-
 static int _clk_ipu2_set_parent(struct clk *clk, struct clk *parent)
 {
        int mux;
@@ -2656,6 +2802,9 @@ static unsigned long _clk_ipu_di_round_rate(struct clk *clk,
                return parent_rate;
 
        div = parent_rate / rate;
+       /* Round to closest divisor */
+       if ((parent_rate % rate) > (rate / 2))
+               div++;
 
        /* Make sure rate is not greater than the maximum value for the clock.
         * Also prevent a div of 0.
@@ -3026,11 +3175,70 @@ static struct clk ipu2_di_clk[] = {
        },
 };
 
+static unsigned long _clk_can_root_round_rate(struct clk *clk,
+                                               unsigned long rate)
+{
+       u32 div;
+       u32 parent_rate = clk_get_rate(clk->parent);
+
+       div = parent_rate / rate;
+
+       /* Make sure rate is not greater than the maximum value for the clock.
+        * Also prevent a div of 0.
+        */
+       if (div == 0)
+               div++;
+
+       if (div > 64)
+               div = 64;
+
+       return parent_rate / div;
+}
+
+static int _clk_can_root_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 reg, div;
+       u32 parent_rate = clk_get_rate(clk->parent);
+
+       div = parent_rate / rate;
+       if (div == 0)
+               div++;
+       if (((parent_rate / div) != rate) || (div > 64))
+               return -EINVAL;
+
+       reg = __raw_readl(MXC_CCM_CSCMR2) & MXC_CCM_CSCMR2_CAN_CLK_PODF_MASK;
+       reg |= ((div - 1) << MXC_CCM_CSCMR2_CAN_CLK_PODF_OFFSET);
+
+       __raw_writel(reg, MXC_CCM_CSCMR2);
+
+       return 0;
+}
+
+static unsigned long _clk_can_root_get_rate(struct clk *clk)
+{
+       u32 reg, div;
+       unsigned long val;
+
+       reg = __raw_readl(MXC_CCM_CSCMR2) & MXC_CCM_CSCMR2_CAN_CLK_PODF_MASK;
+       div = (reg >> MXC_CCM_CSCMR2_CAN_CLK_PODF_OFFSET) + 1;
+       val = clk_get_rate(clk->parent) / div;
+
+       return val;
+}
+
+static struct clk can_clk_root = {
+        __INIT_CLK_DEBUG(can_clk_root)
+       .parent = &pll3_60M,
+       .set_rate = _clk_can_root_set_rate,
+       .get_rate = _clk_can_root_get_rate,
+       .round_rate = _clk_can_root_round_rate,
+};
+
 static struct clk can2_clk[] = {
        {
         __INIT_CLK_DEBUG(can2_module_clk)
        .id = 0,
-       .parent = &pll3_60M,
+       .parent = &can_clk_root,
        .enable_reg = MXC_CCM_CCGR0,
        .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET,
        .enable = _clk_enable,
@@ -3041,7 +3249,7 @@ static struct clk can2_clk[] = {
        {
         __INIT_CLK_DEBUG(can2_serial_clk)
        .id = 1,
-       .parent = &pll3_60M,
+       .parent = &can_clk_root,
        .enable_reg = MXC_CCM_CCGR0,
        .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET,
        .enable = _clk_enable,
@@ -3054,7 +3262,7 @@ static struct clk can1_clk[] = {
        {
         __INIT_CLK_DEBUG(can1_module_clk)
        .id = 0,
-       .parent = &pll3_60M,
+       .parent = &can_clk_root,
        .enable_reg = MXC_CCM_CCGR0,
        .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET,
        .enable = _clk_enable,
@@ -3065,7 +3273,7 @@ static struct clk can1_clk[] = {
        {
         __INIT_CLK_DEBUG(can1_serial_clk)
        .id = 1,
-       .parent = &pll3_60M,
+       .parent = &can_clk_root,
        .enable_reg = MXC_CCM_CCGR0,
        .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET,
        .enable = _clk_enable,
@@ -3257,7 +3465,7 @@ static int _clk_enet_enable(struct clk *clk)
        /* Enable ENET ref clock */
        reg = __raw_readl(PLL8_ENET_BASE_ADDR);
        reg &= ~ANADIG_PLL_BYPASS;
-       reg &= ~ANADIG_PLL_ENABLE;
+       reg |= ANADIG_PLL_ENABLE;
        __raw_writel(reg, PLL8_ENET_BASE_ADDR);
 
        _clk_enable(clk);
@@ -3273,7 +3481,7 @@ static void _clk_enet_disable(struct clk *clk)
        /* Enable ENET ref clock */
        reg = __raw_readl(PLL8_ENET_BASE_ADDR);
        reg |= ANADIG_PLL_BYPASS;
-       reg |= ANADIG_PLL_ENABLE;
+       reg &= ~ANADIG_PLL_ENABLE;
        __raw_writel(reg, PLL8_ENET_BASE_ADDR);
 }
 
@@ -3312,7 +3520,22 @@ static unsigned long _clk_enet_get_rate(struct clk *clk)
        div = (__raw_readl(PLL8_ENET_BASE_ADDR))
                & ANADIG_PLL_ENET_DIV_SELECT_MASK;
 
-       return 500000000 / (div + 1);
+       switch (div) {
+       case 0:
+               div = 20;
+               break;
+       case 1:
+               div = 10;
+               break;
+       case 3:
+               div = 5;
+               break;
+       case 4:
+               div = 4;
+               break;
+       }
+
+       return 500000000 / div;
 }
 
 static struct clk enet_clk[] = {
@@ -3782,6 +4005,16 @@ static struct clk hsi_tx_clk[] = {
         },
 };
 
+static struct clk mipi_pllref_clk = {
+        __INIT_CLK_DEBUG(mipi_pllref_clk)
+       .id = 0,
+       .parent = &pll3_pfd_540M,
+       .enable_reg = MXC_CCM_CCGR3,
+       .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET,
+       .enable = _clk_enable,
+       .disable = _clk_disable,
+};
+
 static struct clk hdmi_clk[] = {
        {
         __INIT_CLK_DEBUG(hdmi_isfr_clk)
@@ -4081,21 +4314,28 @@ static int _clk_gpu2d_core_set_parent(struct clk *clk, struct clk *parent)
        u32 reg = __raw_readl(MXC_CCM_CBCMR) &
                                ~MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK;
 
-       mux = _get_mux6(parent, &axi_clk, &pll3_usb_otg_main_clk,
-               &pll2_pfd_352M, &pll2_pfd_400M, NULL, NULL);
-       reg |= (mux << MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET);
-       __raw_writel(reg, MXC_CCM_CBCMR);
+       /*on mx6dl, 2d core clock sources from 3d shader core clock*/
+       if (!cpu_is_mx6dl()) {
+               mux = _get_mux6(parent, &axi_clk, &pll3_usb_otg_main_clk,
+                       &pll2_pfd_352M, &pll2_pfd_400M, NULL, NULL);
+               reg |= (mux << MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET);
+               __raw_writel(reg, MXC_CCM_CBCMR);
+       }
 
        return 0;
 }
 
 static unsigned long _clk_gpu2d_core_get_rate(struct clk *clk)
 {
-       u32 reg, div;
+       u32 reg, div = 1;
 
        reg = __raw_readl(MXC_CCM_CBCMR);
-       div = ((reg & MXC_CCM_CBCMR_GPU2D_CORE_PODF_MASK) >>
-                       MXC_CCM_CBCMR_GPU2D_CORE_PODF_OFFSET) + 1;
+       if (cpu_is_mx6q())
+               div = ((reg & MXC_CCM_CBCMR_GPU2D_CORE_PODF_MASK) >>
+                               MXC_CCM_CBCMR_GPU2D_CORE_PODF_OFFSET) + 1;
+       else if (cpu_is_mx6dl())
+               /* on i.mx6dl, gpu2d_core_clk source from gpu3d_shader_clk */
+               return clk_get_rate(clk->parent);
 
        return clk_get_rate(clk->parent) / div;
 }
@@ -4112,8 +4352,8 @@ static int _clk_gpu2d_core_set_rate(struct clk *clk, unsigned long rate)
                return -EINVAL;
 
        reg = __raw_readl(MXC_CCM_CBCMR);
-       reg &= ~MXC_CCM_CBCMR_GPU3D_CORE_PODF_MASK;
-       reg |= (div - 1) << MXC_CCM_CBCMR_GPU3D_CORE_PODF_OFFSET;
+       reg &= ~MXC_CCM_CBCMR_GPU2D_CORE_PODF_MASK;
+       reg |= (div - 1) << MXC_CCM_CBCMR_GPU2D_CORE_PODF_OFFSET;
        __raw_writel(reg, MXC_CCM_CBCMR);
 
        return 0;
@@ -4130,12 +4370,8 @@ static struct clk gpu2d_core_clk[] = {
        .set_rate = _clk_gpu2d_core_set_rate,
        .get_rate = _clk_gpu2d_core_get_rate,
        .round_rate = _clk_gpu2d_core_round_rate,
-       .secondary = &gpu2d_core_clk[0],
-       .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
-       },
-       {
-       .parent = &gpu2d_axi_clk,
        .secondary = &mx6fast1_clk,
+       .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
        },
 };
 
@@ -4221,11 +4457,11 @@ static struct clk gpu3d_shader_clk = {
 };
 
 /* set the parent by the ipcg table */
-static struct clk gpmi_nfc_clk[] = {
+static struct clk gpmi_nand_clk[] = {
        {       /* gpmi_io_clk */
        __INIT_CLK_DEBUG(gpmi_io_clk)
        .parent = &enfc_clk,
-       .secondary = &gpmi_nfc_clk[1],
+       .secondary = &gpmi_nand_clk[1],
        .enable = _clk_enable,
        .enable_reg = MXC_CCM_CCGR4,
        .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET,
@@ -4234,7 +4470,7 @@ static struct clk gpmi_nfc_clk[] = {
        {       /* gpmi_apb_clk */
        __INIT_CLK_DEBUG(gpmi_apb_clk)
        .parent = &usdhc3_clk,
-       .secondary = &gpmi_nfc_clk[2],
+       .secondary = &gpmi_nand_clk[2],
        .enable = _clk_enable,
        .enable_reg = MXC_CCM_CCGR4,
        .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET,
@@ -4243,7 +4479,7 @@ static struct clk gpmi_nfc_clk[] = {
        {       /* bch_clk */
        __INIT_CLK_DEBUG(gpmi_bch_clk)
        .parent = &usdhc4_clk,
-       .secondary = &gpmi_nfc_clk[3],
+       .secondary = &gpmi_nand_clk[3],
        .enable = _clk_enable,
        .enable_reg = MXC_CCM_CCGR4,
        .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET,
@@ -4252,7 +4488,7 @@ static struct clk gpmi_nfc_clk[] = {
        {       /* bch_apb_clk */
        __INIT_CLK_DEBUG(gpmi_bch_apb_clk)
        .parent = &usdhc3_clk,
-       .secondary = &gpmi_nfc_clk[4],
+       .secondary = &gpmi_nand_clk[4],
        .enable = _clk_enable,
        .enable_reg = MXC_CCM_CCGR4,
        .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET,
@@ -4308,7 +4544,48 @@ static int _clk_pcie_enable(struct clk *clk)
 {
        unsigned int reg;
 
-       /* Enable SATA ref clock */
+       /* Clear Power Down and Enable PLLs */
+       reg = __raw_readl(PLL8_ENET_BASE_ADDR);
+       reg &= ~ANADIG_PLL_ENET_POWER_DOWN;
+       __raw_writel(reg, PLL8_ENET_BASE_ADDR);
+
+       reg = __raw_readl(PLL8_ENET_BASE_ADDR);
+       reg |= ANADIG_PLL_ENET_EN;
+       __raw_writel(reg, PLL8_ENET_BASE_ADDR);
+
+       /* Waiting for the PLL is locked */
+       if (!WAIT(ANADIG_PLL_ENET_LOCK & __raw_readl(PLL8_ENET_BASE_ADDR),
+                               SPIN_DELAY))
+               panic("pll8 lock failed\n");
+
+       /* Disable the bypass */
+       reg = __raw_readl(PLL8_ENET_BASE_ADDR);
+       reg &= ~ANADIG_PLL_ENET_BYPASS;
+       __raw_writel(reg, PLL8_ENET_BASE_ADDR);
+
+       /*
+        * Enable SATA ref clock.
+        * PCIe needs both sides to have the same source of refernce clock,
+        * The SATA reference clock is taken out on clk out
+        */
+       reg = __raw_readl(PLL8_ENET_BASE_ADDR);
+       reg |= ANADIG_PLL_ENET_EN_SATA;
+       __raw_writel(reg, PLL8_ENET_BASE_ADDR);
+
+       /* Activate LVDS CLK1 (the MiniPCIe slot clock input) */
+       reg = __raw_readl(ANADIG_MISC1_REG);
+       reg &= ~ANATOP_LVDS_CLK1_IBEN_MASK;
+       __raw_writel(reg, ANADIG_MISC1_REG);
+
+       reg = __raw_readl(ANADIG_MISC1_REG);
+       reg |= ANATOP_LVDS_CLK1_SRC_SATA;
+       __raw_writel(reg, ANADIG_MISC1_REG);
+
+       reg = __raw_readl(ANADIG_MISC1_REG);
+       reg |= ANATOP_LVDS_CLK1_OBEN_MASK;
+       __raw_writel(reg, ANADIG_MISC1_REG);
+
+       /* Enable PCIE ref clock */
        reg = __raw_readl(PLL8_ENET_BASE_ADDR);
        reg |= ANADIG_PLL_ENET_EN_PCIE;
        __raw_writel(reg, PLL8_ENET_BASE_ADDR);
@@ -4426,6 +4703,16 @@ static struct clk usboh3_clk[] = {
        },
 };
 
+static struct clk mlb150_clk = {
+       __INIT_CLK_DEBUG(mlb150_clk)
+       .id = 0,
+       .parent = &ipg_clk,
+       .enable_reg = MXC_CCM_CCGR3,
+       .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET,
+       .enable = _clk_enable,
+       .disable = _clk_disable,
+};
+
 static int _clk_enable1(struct clk *clk)
 {
        u32 reg;
@@ -4530,6 +4817,100 @@ static unsigned long _clk_clko_round_rate(struct clk *clk,
        return parent_rate / div;
 }
 
+static int _clk_clko2_set_parent(struct clk *clk, struct clk *parent)
+{
+       u32 sel, reg;
+
+       if (parent == &mmdc_ch0_axi_clk[0])
+               sel = 0;
+       else if (parent == &mmdc_ch1_axi_clk[0])
+               sel = 1;
+       else if (parent == &usdhc4_clk)
+               sel = 2;
+       else if (parent == &usdhc1_clk)
+               sel = 3;
+       else if (parent == &gpu2d_axi_clk)
+               sel = 4;
+       else if (parent == &ecspi_clk[0])
+               sel = 6;
+       else if (parent == &gpu3d_axi_clk)
+               sel = 7;
+       else if (parent == &usdhc3_clk)
+               sel = 8;
+       else if (parent == &pcie_clk[0])
+               sel = 9;
+       else if (parent == &ipu1_clk)
+               sel = 11;
+       else if (parent == &ipu2_clk)
+               sel = 12;
+       else if (parent == &vdo_axi_clk)
+               sel = 13;
+       else if (parent == &osc_clk)
+               sel = 14;
+       else if (parent == &gpu2d_core_clk[0])
+               sel = 15;
+       else if (parent == &gpu3d_core_clk[0])
+               sel = 16;
+       else if (parent == &usdhc2_clk)
+               sel = 17;
+       else if (parent == &ssi1_clk)
+               sel = 18;
+       else if (parent == &ssi2_clk)
+               sel = 19;
+       else if (parent == &ssi3_clk)
+               sel = 20;
+       else if (parent == &gpu3d_shader_clk)
+               sel = 21;
+       else if (parent == &can_clk_root)
+               sel = 23;
+       else if (parent == &ldb_di0_clk)
+               sel = 24;
+       else if (parent == &ldb_di1_clk)
+               sel = 25;
+       else if (parent == &esai_clk)
+               sel = 26;
+       else if (parent == &uart_clk[0])
+               sel = 28;
+       else if (parent == &spdif0_clk[0])
+               sel = 29;
+       else if (parent == &hsi_tx_clk[0])
+               sel = 31;
+       else
+               return -EINVAL;
+
+       reg = __raw_readl(MXC_CCM_CCOSR);
+       reg &= ~MXC_CCM_CCOSR_CKO2_SEL_MASK;
+       reg |= sel << MXC_CCM_CCOSR_CKO2_SEL_OFFSET;
+       __raw_writel(reg, MXC_CCM_CCOSR);
+       return 0;
+}
+
+static unsigned long _clk_clko2_get_rate(struct clk *clk)
+{
+       u32 reg = __raw_readl(MXC_CCM_CCOSR);
+       u32 div = ((reg & MXC_CCM_CCOSR_CKO2_DIV_MASK) >>
+                       MXC_CCM_CCOSR_CKO2_DIV_OFFSET) + 1;
+       return clk_get_rate(clk->parent) / div;
+}
+
+static int _clk_clko2_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 reg;
+       u32 parent_rate = clk_get_rate(clk->parent);
+       u32 div = parent_rate / rate;
+
+       if (div == 0)
+               div++;
+       if (((parent_rate / div) != rate) || (div > 8))
+               return -EINVAL;
+
+       reg = __raw_readl(MXC_CCM_CCOSR);
+       reg &= ~MXC_CCM_CCOSR_CKO2_DIV_MASK;
+       reg |= (div - 1) << MXC_CCM_CCOSR_CKO2_DIV_OFFSET;
+       __raw_writel(reg, MXC_CCM_CCOSR);
+       return 0;
+}
+
 static struct clk clko_clk = {
        __INIT_CLK_DEBUG(clko_clk)
        .parent = &pll2_528_bus_main_clk,
@@ -4543,6 +4924,46 @@ static struct clk clko_clk = {
        .round_rate = _clk_clko_round_rate,
 };
 
+static struct clk clko2_clk = {
+       __INIT_CLK_DEBUG(clko2_clk)
+       .parent = &usdhc4_clk,
+       .enable = _clk_enable1,
+       .enable_reg = MXC_CCM_CCOSR,
+       .enable_shift = MXC_CCM_CCOSR_CKO2_EN_OFFSET,
+       .disable = _clk_disable1,
+       .set_parent = _clk_clko2_set_parent,
+       .set_rate = _clk_clko2_set_rate,
+       .get_rate = _clk_clko2_get_rate,
+       .round_rate = _clk_clko_round_rate,
+};
+
+static struct clk perfmon0_clk = {
+       __INIT_CLK_DEBUG(perfmon0_clk)
+       .parent = &mmdc_ch0_axi_clk[0],
+       .enable = _clk_enable1,
+       .enable_reg = MXC_CCM_CCGR4,
+       .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET,
+       .disable = _clk_disable1,
+};
+
+static struct clk perfmon1_clk = {
+       __INIT_CLK_DEBUG(perfmon1_clk)
+       .parent = &ipu1_clk,
+       .enable = _clk_enable1,
+       .enable_reg = MXC_CCM_CCGR4,
+       .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET,
+       .disable = _clk_disable1,
+};
+
+static struct clk perfmon2_clk = {
+       __INIT_CLK_DEBUG(perfmon2_clk)
+       .parent = &mmdc_ch0_axi_clk[0],
+       .enable = _clk_enable1,
+       .enable_reg = MXC_CCM_CCGR4,
+       .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET,
+       .disable = _clk_disable1,
+};
+
 static struct clk dummy_clk = {
        .id = 0,
 };
@@ -4578,10 +4999,11 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "pll3_120M", pll3_60M),
        _REGISTER_CLOCK(NULL, "pll4", pll4_audio_main_clk),
        _REGISTER_CLOCK(NULL, "pll5", pll5_video_main_clk),
-       _REGISTER_CLOCK(NULL, "pll4", pll6_MLB_main_clk),
+       _REGISTER_CLOCK(NULL, "pll6", pll6_mlb150_main_clk),
        _REGISTER_CLOCK(NULL, "pll3", pll7_usb_host_main_clk),
        _REGISTER_CLOCK(NULL, "pll4", pll8_enet_main_clk),
        _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk),
+       _REGISTER_CLOCK("smp_twd", NULL, twd_clk),
        _REGISTER_CLOCK(NULL, "periph_clk", periph_clk),
        _REGISTER_CLOCK(NULL, "axi_clk", axi_clk),
        _REGISTER_CLOCK(NULL, "mmdc_ch0_axi", mmdc_ch0_axi_clk[0]),
@@ -4602,7 +5024,6 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "vpu_clk", vpu_clk[0]),
        _REGISTER_CLOCK(NULL, "ipu1_clk", ipu1_clk),
        _REGISTER_CLOCK(NULL, "ipu2_clk", ipu2_clk),
-       _REGISTER_CLOCK(NULL, "cko1_clk0", cko1_clk0),
        _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, usdhc1_clk),
        _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, usdhc2_clk),
        _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, usdhc3_clk),
@@ -4614,8 +5035,9 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "ipu1_di1_clk", ipu1_di_clk[1]),
        _REGISTER_CLOCK(NULL, "ipu2_di0_clk", ipu2_di_clk[0]),
        _REGISTER_CLOCK(NULL, "ipu2_di1_clk", ipu2_di_clk[1]),
-       _REGISTER_CLOCK("FlexCAN.0", "can_clk", can1_clk[0]),
-       _REGISTER_CLOCK("FlexCAN.1", "can_clk", can2_clk[0]),
+       _REGISTER_CLOCK(NULL, "can_root_clk", can_clk_root),
+       _REGISTER_CLOCK("imx6q-flexcan.0", NULL, can1_clk[0]),
+       _REGISTER_CLOCK("imx6q-flexcan.1", NULL, can2_clk[0]),
        _REGISTER_CLOCK(NULL, "ldb_di0_clk", ldb_di0_clk),
        _REGISTER_CLOCK(NULL, "ldb_di1_clk", ldb_di1_clk),
        _REGISTER_CLOCK("mxc_spdif.0", NULL, spdif0_clk[0]),
@@ -4642,11 +5064,11 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "gpu2d_clk", gpu2d_core_clk[0]),
        _REGISTER_CLOCK(NULL, "gpu3d_shader_clk", gpu3d_shader_clk),
        _REGISTER_CLOCK(NULL, "gpt", gpt_clk[0]),
-       _REGISTER_CLOCK("imx6q-gpmi-nfc.0", NULL, gpmi_nfc_clk[0]),
-       _REGISTER_CLOCK(NULL, "gpmi-apb", gpmi_nfc_clk[1]),
-       _REGISTER_CLOCK(NULL, "bch", gpmi_nfc_clk[2]),
-       _REGISTER_CLOCK(NULL, "bch-apb", gpmi_nfc_clk[3]),
-       _REGISTER_CLOCK(NULL, "pl301_mx6qperl-bch", gpmi_nfc_clk[4]),
+       _REGISTER_CLOCK("imx6q-gpmi-nand.0", NULL, gpmi_nand_clk[0]),
+       _REGISTER_CLOCK(NULL, "gpmi-apb", gpmi_nand_clk[1]),
+       _REGISTER_CLOCK(NULL, "bch", gpmi_nand_clk[2]),
+       _REGISTER_CLOCK(NULL, "bch-apb", gpmi_nand_clk[3]),
+       _REGISTER_CLOCK(NULL, "pl301_mx6qperl-bch", gpmi_nand_clk[4]),
        _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm_clk[0]),
        _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm_clk[1]),
        _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm_clk[2]),
@@ -4656,17 +5078,29 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "imx_sata_clk", sata_clk[0]),
        _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk[0]),
        _REGISTER_CLOCK(NULL, "usb_phy1_clk", usb_phy1_clk),
+       _REGISTER_CLOCK(NULL, "usb_phy3_clk", usb_phy3_clk),
+       _REGISTER_CLOCK(NULL, "usb_phy4_clk", usb_phy4_clk),
        _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk),
        _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk),
        _REGISTER_CLOCK(NULL, "hdmi_isfr_clk", hdmi_clk[0]),
        _REGISTER_CLOCK(NULL, "hdmi_iahb_clk", hdmi_clk[1]),
+       _REGISTER_CLOCK(NULL, "mipi_pllref_clk", mipi_pllref_clk),
        _REGISTER_CLOCK(NULL, NULL, vdoa_clk),
        _REGISTER_CLOCK(NULL, NULL, aips_tz2_clk),
        _REGISTER_CLOCK(NULL, NULL, aips_tz1_clk),
        _REGISTER_CLOCK(NULL, "clko_clk", clko_clk),
+       _REGISTER_CLOCK(NULL, "clko2_clk", clko2_clk),
+       _REGISTER_CLOCK(NULL, "pxp_axi", ipu2_clk),
+       _REGISTER_CLOCK(NULL, "epdc_axi", ipu2_clk),
+       _REGISTER_CLOCK(NULL, "epdc_pix", ipu2_di_clk[1]),
+       _REGISTER_CLOCK("mxs-perfmon.0", "perfmon", perfmon0_clk),
+       _REGISTER_CLOCK("mxs-perfmon.1", "perfmon", perfmon1_clk),
+       _REGISTER_CLOCK("mxs-perfmon.2", "perfmon", perfmon2_clk),
+       _REGISTER_CLOCK(NULL, "mlb150_clk", mlb150_clk),
+       _REGISTER_CLOCK(NULL, "anaclk_1", anaclk_1),
+       _REGISTER_CLOCK(NULL, "anaclk_2", anaclk_2),
 };
 
-
 static void clk_tree_init(void)
 
 {
@@ -4674,7 +5108,8 @@ static void clk_tree_init(void)
 
        reg = __raw_readl(MMDC_MDMISC_OFFSET);
        if ((reg & MMDC_MDMISC_DDR_TYPE_MASK) ==
-               (0x1 << MMDC_MDMISC_DDR_TYPE_OFFSET)) {
+               (0x1 << MMDC_MDMISC_DDR_TYPE_OFFSET) ||
+               cpu_is_mx6dl()) {
                clk_set_parent(&periph_clk, &pll2_pfd_400M);
                printk(KERN_INFO "Set periph_clk's parent to pll2_pfd_400M!\n");
        }
@@ -4707,20 +5142,22 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
 
        clk_tree_init();
 
-       if (pll2_pfd_400M.usecount == 0)
+       if (pll2_pfd_400M.usecount == 0 && cpu_is_mx6q())
                pll2_pfd_400M.disable(&pll2_pfd_400M);
        pll2_pfd_352M.disable(&pll2_pfd_352M);
        pll2_pfd_594M.disable(&pll2_pfd_594M);
 
+#if !defined(CONFIG_FEC_1588)
        pll3_pfd_454M.disable(&pll3_pfd_454M);
        pll3_pfd_508M.disable(&pll3_pfd_508M);
        pll3_pfd_540M.disable(&pll3_pfd_540M);
        pll3_pfd_720M.disable(&pll3_pfd_720M);
 
        pll3_usb_otg_main_clk.disable(&pll3_usb_otg_main_clk);
+#endif
        pll4_audio_main_clk.disable(&pll4_audio_main_clk);
        pll5_video_main_clk.disable(&pll5_video_main_clk);
-       pll6_MLB_main_clk.disable(&pll6_MLB_main_clk);
+       pll6_mlb150_main_clk.disable(&pll6_mlb150_main_clk);
        pll7_usb_host_main_clk.disable(&pll7_usb_host_main_clk);
        pll8_enet_main_clk.disable(&pll8_enet_main_clk);
 
@@ -4736,25 +5173,47 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
        clk_set_parent(&ipu2_di_clk[0], &pll5_video_main_clk);
        clk_set_parent(&ipu2_di_clk[1], &pll5_video_main_clk);
 
-       clk_set_parent(&cko1_clk0, &ipg_clk);
-       clk_set_rate(&cko1_clk0, 22000000);
-       clk_enable(&cko1_clk0);
+       clk_set_parent(&emi_clk, &pll2_pfd_400M);
+       clk_set_rate(&emi_clk, 200000000);
 
        clk_set_parent(&gpu3d_shader_clk, &pll2_pfd_594M);
        clk_set_rate(&gpu3d_shader_clk, 594000000);
        clk_set_parent(&gpu3d_core_clk[0], &mmdc_ch0_axi_clk[0]);
        clk_set_rate(&gpu3d_core_clk[0], 528000000);
+       if (cpu_is_mx6dl()) {
+               /*on mx6dl, 2d core clock sources from 3d shader core clock*/
+               clk_set_parent(&gpu2d_core_clk[0], &gpu3d_shader_clk);
+               /* on mx6dl gpu3d_axi_clk source from mmdc0 directly */
+               clk_set_parent(&gpu3d_axi_clk, &mmdc_ch0_axi_clk[0]);
+               /* on mx6dl gpu2d_axi_clk source from mmdc0 directly */
+               clk_set_parent(&gpu2d_axi_clk, &mmdc_ch0_axi_clk[0]);
+
+               /* set axi_clk parent to pll3_pfd_540M */
+               clk_set_parent(&axi_clk, &pll3_pfd_540M);
+
+               /* on mx6dl, max ipu clock is 274M */
+               clk_set_parent(&ipu1_clk, &pll3_pfd_540M);
+               clk_set_parent(&ldb_di0_clk, &pll2_pfd_352M);
+               clk_set_parent(&ldb_di1_clk, &pll2_pfd_352M);
+       }
+       if (cpu_is_mx6q())
+               clk_set_parent(&gpu2d_core_clk[0], &pll3_usb_otg_main_clk);
+
+       /* PCLK camera - J5 */
+       clk_set_parent(&clko2_clk, &osc_clk);
+       clk_set_rate(&clko2_clk, 2400000);
 
+       clk_set_parent(&clko_clk, &ipg_clk);
        /*
-        * FIXME: asrc needs to use asrc_serial(spdif1) clock to do sample rate convertion,
-        * however we found it only works when set to 1.5M clock and the
-        * parent is pll3_sw_clk.
+        * FIXME: asrc needs to use asrc_serial(spdif1) clock to do sample
+        * rate convertion and this clock frequency can not be too high, set
+        * it to the minimum value 7.5Mhz to make asrc work properly.
         */
        clk_set_parent(&asrc_clk[1], &pll3_sw_clk);
-       clk_set_rate(&asrc_clk[1], 1500000);
+       clk_set_rate(&asrc_clk[1], 7500000);
 
-       /* set the NAND to 11MHz. Too fast will cause dma timeout. */
-       clk_set_rate(&enfc_clk, enfc_clk.round_rate(&enfc_clk, 11000000));
+       /* set the GPMI clock to default frequency : 20MHz */
+       clk_set_rate(&enfc_clk, enfc_clk.round_rate(&enfc_clk, 20000000));
 
        mx6_cpu_op_init();
        cpu_op_tbl = get_cpu_op(&cpu_op_nr);
@@ -4795,6 +5254,26 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
        /* S/PDIF */
        clk_set_parent(&spdif0_clk[0], &pll3_pfd_454M);
 
+       /* pxp & epdc */
+       clk_set_parent(&ipu2_clk, &pll2_pfd_400M);
+       clk_set_rate(&ipu2_clk, 200000000);
+
+       if (mx6q_revision() == IMX_CHIP_REVISION_1_0) {
+               gpt_clk[0].parent = &ipg_perclk;
+               gpt_clk[0].get_rate = NULL;
+       } else {
+               /* Here we use OSC 24M as GPT's clock source, no need to
+               enable gpt serial clock*/
+               gpt_clk[0].secondary = NULL;
+       }
+
+       if (cpu_is_mx6dl()) {
+               if (epdc_enabled)
+                       clk_set_parent(&ipu2_di_clk[1], &pll5_video_main_clk);
+               else
+                       clk_set_parent(&ipu2_di_clk[1], &pll3_pfd_540M);
+       }
+
        base = ioremap(GPT_BASE_ADDR, SZ_4K);
        mxc_timer_init(&gpt_clk[0], base, MXC_INT_GPT);