]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - arch/arm/cpu/armv7/mx6/clock.c
mx6: clock: use setup_gpmi_io_clk() to change nfc clk divider for CONFIG_NAND_MXS
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / mx6 / clock.c
index 8e2086eed45e3bbe75ac968edd9b2b563a489506..c3c9c5e6512ba13ebacd96181056e915db9e14da 100644 (file)
@@ -116,6 +116,24 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
        return 0;
 }
 
+#define PLL_LOCK_BIT           (1 << 31)
+
+static inline int wait_pll_lock(u32 *reg)
+{
+       int loops = 0;
+       u32 val;
+
+       while (!((val = readl(reg)) & PLL_LOCK_BIT)) {
+               loops++;
+               if (loops > 1000)
+                       break;
+               udelay(1);
+       }
+       if (!(val & PLL_LOCK_BIT) && !(readl(reg) & PLL_LOCK_BIT))
+               return -ETIMEDOUT;
+       return 0;
+}
+
 #ifdef CONFIG_MXC_OCOTP
 void enable_ocotp_clk(unsigned char enable)
 {
@@ -175,43 +193,37 @@ void enable_usboh3_clk(unsigned char enable)
 #if defined(CONFIG_FEC_MXC) && !defined(CONFIG_SOC_MX6SX)
 void enable_enet_clk(unsigned char enable)
 {
-       u32 mask = MXC_CCM_CCGR1_ENET_CLK_ENABLE_MASK;
+       u32 mask, *addr;
+
+       if (is_cpu_type(MXC_CPU_MX6UL)) {
+               mask = MXC_CCM_CCGR3_ENET_MASK;
+               addr = &imx_ccm->CCGR3;
+       } else {
+               mask = MXC_CCM_CCGR1_ENET_MASK;
+               addr = &imx_ccm->CCGR1;
+       }
 
        if (enable)
-               setbits_le32(&imx_ccm->CCGR1, mask);
+               setbits_le32(addr, mask);
        else
-               clrbits_le32(&imx_ccm->CCGR1, mask);
+               clrbits_le32(addr, mask);
 }
 #endif
 
 #ifdef CONFIG_MXC_UART
 void enable_uart_clk(unsigned char enable)
-{
-       u32 mask = MXC_CCM_CCGR5_UART_MASK | MXC_CCM_CCGR5_UART_SERIAL_MASK;
-
-       if (enable)
-               setbits_le32(&imx_ccm->CCGR5, mask);
-       else
-               clrbits_le32(&imx_ccm->CCGR5, mask);
-}
-#endif
-
-#ifdef CONFIG_SPI
-/* spi_num can be from 0 - 4 */
-int enable_cspi_clock(unsigned char enable, unsigned spi_num)
 {
        u32 mask;
 
-       if (spi_num > 4)
-               return -EINVAL;
+       if (is_cpu_type(MXC_CPU_MX6UL))
+               mask = MXC_CCM_CCGR5_UART_MASK;
+       else
+               mask = MXC_CCM_CCGR5_UART_MASK | MXC_CCM_CCGR5_UART_SERIAL_MASK;
 
-       mask = MXC_CCM_CCGR_CG_MASK << (spi_num * 2);
        if (enable)
-               setbits_le32(&imx_ccm->CCGR1, mask);
+               setbits_le32(&imx_ccm->CCGR5, mask);
        else
-               clrbits_le32(&imx_ccm->CCGR1, mask);
-
-       return 0;
+               clrbits_le32(&imx_ccm->CCGR5, mask);
 }
 #endif
 
@@ -239,6 +251,7 @@ int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
 {
        u32 reg;
        u32 mask;
+       u32 *addr;
 
        if (i2c_num > 3)
                return -EINVAL;
@@ -253,14 +266,19 @@ int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
                        reg &= ~mask;
                __raw_writel(reg, &imx_ccm->CCGR2);
        } else {
-               mask = MXC_CCM_CCGR_CG_MASK
-                       << (MXC_CCM_CCGR1_I2C4_SERIAL_OFFSET);
-               reg = __raw_readl(&imx_ccm->CCGR1);
+               if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL)) {
+                       mask = MXC_CCM_CCGR6_I2C4_MASK;
+                       addr = &imx_ccm->CCGR6;
+               } else {
+                       mask = MXC_CCM_CCGR1_I2C4_SERIAL_MASK;
+                       addr = &imx_ccm->CCGR1;
+               }
+               reg = __raw_readl(addr);
                if (enable)
                        reg |= mask;
                else
                        reg &= ~mask;
-               __raw_writel(reg, &imx_ccm->CCGR1);
+               __raw_writel(reg, addr);
        }
        return 0;
 }
@@ -284,9 +302,12 @@ int enable_spi_clk(unsigned char enable, unsigned spi_num)
        __raw_writel(reg, &imx_ccm->CCGR1);
        return 0;
 }
+
 static u32 decode_pll(enum pll_clocks pll, u32 infreq)
 {
-       u32 div;
+       u32 div, post_div;
+       u32 pll_num, pll_denom;
+       u64 freq;
 
        switch (pll) {
        case PLL_ARM:
@@ -306,25 +327,53 @@ static u32 decode_pll(enum pll_clocks pll, u32 infreq)
                return infreq * (20 + div * 2);
        case PLL_USBOTG:
                div = __raw_readl(&anatop->usb1_pll_480_ctrl);
-               if (div & BM_ANADIG_USB_PLL_480_CTRL_BYPASS)
+               if (div & BM_ANADIG_USB1_PLL_480_CTRL_BYPASS)
                        return infreq;
-               div &= BM_ANADIG_USB_PLL_480_CTRL_DIV_SELECT;
+               div &= BM_ANADIG_USB1_PLL_480_CTRL_DIV_SELECT;
 
                return infreq * (20 + div * 2);
        case PLL_AUDIO:
                div = __raw_readl(&anatop->pll_audio);
+               /* BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC is ignored */
                if (div & BM_ANADIG_PLL_AUDIO_BYPASS)
                        return infreq;
+
+               pll_num = __raw_readl(&anatop->pll_audio_num);
+               pll_denom = __raw_readl(&anatop->pll_audio_denom);
+
+               post_div = (div & BM_ANADIG_PLL_AUDIO_POST_DIV_SELECT) >>
+                       BP_ANADIG_PLL_AUDIO_POST_DIV_SELECT;
+               if (post_div == 3) {
+                       printf("Invalid post divider value for PLL_AUDIO\n");
+                       return 0;
+               }
+               post_div = 1 << (2 - post_div);
                div &= BM_ANADIG_PLL_AUDIO_DIV_SELECT;
 
-               return infreq * div;
+               freq = (u64)infreq * pll_num / pll_denom;
+               freq += infreq * div;
+               return lldiv(freq, post_div);
        case PLL_VIDEO:
                div = __raw_readl(&anatop->pll_video);
+               /* BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC is ignored */
                if (div & BM_ANADIG_PLL_VIDEO_BYPASS)
                        return infreq;
+
+               pll_num = __raw_readl(&anatop->pll_video_num);
+               pll_denom = __raw_readl(&anatop->pll_video_denom);
+
+               post_div = (div & BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT) >>
+                       BP_ANADIG_PLL_VIDEO_POST_DIV_SELECT;
+               if (post_div == 3) {
+                       printf("Invalid post divider value for PLL_VIDEO\n");
+                       return 0;
+               }
+               post_div = 1 << (2 - post_div);
                div &= BM_ANADIG_PLL_VIDEO_DIV_SELECT;
 
-               return infreq * div;
+               freq = (u64)infreq * pll_num / pll_denom;
+               freq += infreq * div;
+               return lldiv(freq, post_div);
        case PLL_ENET:
                div = __raw_readl(&anatop->pll_enet);
                if (div & BM_ANADIG_PLL_ENET_BYPASS)
@@ -334,31 +383,34 @@ static u32 decode_pll(enum pll_clocks pll, u32 infreq)
                return 25000000 * (div + (div >> 1) + 1);
        case PLL_USB2:
                div = __raw_readl(&anatop->usb2_pll_480_ctrl);
-               if (div & BM_ANADIG_USB_PLL_480_CTRL_BYPASS)
+               if (div & BM_ANADIG_USB1_PLL_480_CTRL_BYPASS)
                        return infreq;
-               div &= BM_ANADIG_USB_PLL_480_CTRL_DIV_SELECT;
+               div &= BM_ANADIG_USB1_PLL_480_CTRL_DIV_SELECT;
 
                return infreq * (20 + div * 2);
        case PLL_MLB:
                div = __raw_readl(&anatop->pll_mlb);
                if (div & BM_ANADIG_PLL_MLB_BYPASS)
                        return infreq;
-               /* unknown external clock provided on MLB_CLK pin */
+               /* fallthru: unknown external clock provided on MLB_CLK pin */
+       default:
                return 0;
        }
-       return 0;
+       /* NOTREACHED */
 }
+
 static u32 mxc_get_pll_pfd(enum pll_clocks pll, int pfd_num)
 {
        u32 div;
        u64 freq;
-       struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
 
        switch (pll) {
        case PLL_528:
-               if (pfd_num == 3) {
-                       /* No PFD3 on PLL2 */
-                       return 0;
+               if (!is_cpu_type(MXC_CPU_MX6UL)) {
+                       if (pfd_num == 3) {
+                               /* No PFD3 on PPL2 */
+                               return 0;
+                       }
                }
                div = __raw_readl(&anatop->pfd_528);
                freq = (u64)decode_pll(PLL_528, MXC_HCLK);
@@ -390,10 +442,12 @@ static u32 get_mcu_main_clk(void)
 
 u32 get_periph_clk(void)
 {
-       u32 reg, freq = 0;
+       u32 reg, div = 0, freq = 0;
 
        reg = __raw_readl(&imx_ccm->cbcdr);
        if (reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL) {
+               div = (reg & MXC_CCM_CBCDR_PERIPH_CLK2_PODF_MASK) >>
+                      MXC_CCM_CBCDR_PERIPH_CLK2_PODF_OFFSET;
                reg = __raw_readl(&imx_ccm->cbcmr);
                reg &= MXC_CCM_CBCMR_PERIPH_CLK2_SEL_MASK;
                reg >>= MXC_CCM_CBCMR_PERIPH_CLK2_SEL_OFFSET;
@@ -429,7 +483,7 @@ u32 get_periph_clk(void)
                }
        }
 
-       return freq;
+       return freq / (div + 1);
 }
 
 static u32 get_ipg_clk(void)
@@ -448,10 +502,12 @@ static u32 get_ipg_per_clk(void)
        u32 reg, perclk_podf;
 
        reg = __raw_readl(&imx_ccm->cscmr1);
-#if (defined(CONFIG_SOC_MX6SL) || defined(CONFIG_SOC_MX6SX))
-       if (reg & MXC_CCM_CSCMR1_PER_CLK_SEL_MASK)
-               return MXC_HCLK; /* OSC 24Mhz */
-#endif
+       if (is_cpu_type(MXC_CPU_MX6SL) || is_cpu_type(MXC_CPU_MX6SX) ||
+           is_mx6dqp() || is_cpu_type(MXC_CPU_MX6UL)) {
+               if (reg & MXC_CCM_CSCMR1_PER_CLK_SEL_MASK)
+                       return MXC_HCLK; /* OSC 24Mhz */
+       }
+
        perclk_podf = reg & MXC_CCM_CSCMR1_PERCLK_PODF_MASK;
 
        return get_ipg_clk() / (perclk_podf + 1);
@@ -462,10 +518,13 @@ static u32 get_uart_clk(void)
        u32 reg, uart_podf;
        u32 freq = decode_pll(PLL_USBOTG, MXC_HCLK) / 6; /* static divider */
        reg = __raw_readl(&imx_ccm->cscdr1);
-#if (defined(CONFIG_SOC_MX6SL) || defined(CONFIG_SOC_MX6SX))
-       if (reg & MXC_CCM_CSCDR1_UART_CLK_SEL)
-               freq = MXC_HCLK;
-#endif
+
+       if (is_cpu_type(MXC_CPU_MX6SL) || is_cpu_type(MXC_CPU_MX6SX) ||
+           is_mx6dqp() || is_cpu_type(MXC_CPU_MX6UL)) {
+               if (reg & MXC_CCM_CSCDR1_UART_CLK_SEL)
+                       freq = MXC_HCLK;
+       }
+
        reg &= MXC_CCM_CSCDR1_UART_CLK_PODF_MASK;
        uart_podf = reg >> MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
 
@@ -477,8 +536,14 @@ static u32 get_cspi_clk(void)
        u32 reg, cspi_podf;
 
        reg = __raw_readl(&imx_ccm->cscdr2);
-       reg &= MXC_CCM_CSCDR2_ECSPI_CLK_PODF_MASK;
-       cspi_podf = reg >> MXC_CCM_CSCDR2_ECSPI_CLK_PODF_OFFSET;
+       cspi_podf = (reg & MXC_CCM_CSCDR2_ECSPI_CLK_PODF_MASK) >>
+                    MXC_CCM_CSCDR2_ECSPI_CLK_PODF_OFFSET;
+
+       if (is_mx6dqp() || is_cpu_type(MXC_CPU_MX6SL) ||
+           is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL)) {
+               if (reg & MXC_CCM_CSCDR2_ECSPI_CLK_SEL_MASK)
+                       return MXC_HCLK / (cspi_podf + 1);
+       }
 
        return  decode_pll(PLL_USBOTG, MXC_HCLK) / (8 * (cspi_podf + 1));
 }
@@ -486,7 +551,7 @@ static u32 get_cspi_clk(void)
 static u32 get_axi_clk(void)
 {
        u32 root_freq, axi_podf;
-       u32 cbcdr =  __raw_readl(&imx_ccm->cbcdr);
+       u32 cbcdr = __raw_readl(&imx_ccm->cbcdr);
 
        axi_podf = cbcdr & MXC_CCM_CBCDR_AXI_PODF_MASK;
        axi_podf >>= MXC_CCM_CBCDR_AXI_PODF_OFFSET;
@@ -496,9 +561,9 @@ static u32 get_axi_clk(void)
                        root_freq = mxc_get_pll_pfd(PLL_528, 2);
                else
                        root_freq = mxc_get_pll_pfd(PLL_USBOTG, 1);
-       } else
+       } else {
                root_freq = get_periph_clk();
-
+       }
        return  root_freq / (axi_podf + 1);
 }
 
@@ -530,29 +595,38 @@ static u32 get_emi_slow_clk(void)
        return root_freq / (emi_slow_podf + 1);
 }
 
-static u32 get_nfc_clk(void)
+static inline unsigned long get_nfc_root_clk(int nfc_clk_sel)
 {
-       u32 cs2cdr = __raw_readl(&imx_ccm->cs2cdr);
-       u32 podf = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK) >> MXC_CCM_CS2CDR_ENFC_CLK_PODF_OFFSET;
-       u32 pred = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK) >> MXC_CCM_CS2CDR_ENFC_CLK_PRED_OFFSET;
-       int nfc_clk_sel = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK) >>
-               MXC_CCM_CS2CDR_ENFC_CLK_SEL_OFFSET;
-       u32 root_freq;
-
        switch (nfc_clk_sel) {
        case 0:
-               root_freq = mxc_get_pll_pfd(PLL_528, 0);
+               return mxc_get_pll_pfd(PLL_528, 0);
                break;
        case 1:
-               root_freq = decode_pll(PLL_528, MXC_HCLK);
+               return decode_pll(PLL_528, MXC_HCLK);
                break;
        case 2:
-               root_freq = decode_pll(PLL_USBOTG, MXC_HCLK);
+               return decode_pll(PLL_USBOTG, MXC_HCLK);
                break;
        case 3:
-               root_freq = mxc_get_pll_pfd(PLL_528, 2);
+               return mxc_get_pll_pfd(PLL_528, 2);
                break;
+       case 4:
+               return mxc_get_pll_pfd(PLL_USBOTG, 3);
+       default:
+               return 0;
        }
+}
+
+static u32 get_nfc_clk(void)
+{
+       u32 cs2cdr = __raw_readl(&imx_ccm->cs2cdr);
+       u32 podf = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK) >>
+               MXC_CCM_CS2CDR_ENFC_CLK_PODF_OFFSET;
+       u32 pred = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK) >>
+               MXC_CCM_CS2CDR_ENFC_CLK_PRED_OFFSET;
+       int nfc_clk_sel = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK) >>
+               MXC_CCM_CS2CDR_ENFC_CLK_SEL_OFFSET;
+       u32 root_freq = get_nfc_root_clk(nfc_clk_sel);
 
        return root_freq / (pred + 1) / (podf + 1);
 }
@@ -571,12 +645,13 @@ static int set_nfc_clk(u32 ref, u32 freq_khz)
        u32 min_err = ~0;
        u32 nfc_val = ~0;
        u32 freq = freq_khz * 1000;
+       int num_sel = is_mx6dqp() || is_cpu_type(MXC_CPU_MX6UL) ? 5 : 4;
 
-       for (nfc_clk_sel = 0; nfc_clk_sel < 4; nfc_clk_sel++) {
+       for (nfc_clk_sel = 0; nfc_clk_sel < num_sel; nfc_clk_sel++) {
                u32 act_freq;
                u32 err;
 
-               if (ref < 4 && ref != nfc_clk_sel)
+               if (ref < num_sel && ref != nfc_clk_sel)
                        continue;
 
                switch (nfc_clk_sel) {
@@ -592,6 +667,9 @@ static int set_nfc_clk(u32 ref, u32 freq_khz)
                case 3:
                        root_freq = mxc_get_pll_pfd(PLL_528, 2);
                        break;
+               case 4:
+                       root_freq = mxc_get_pll_pfd(PLL_USBOTG, 3);
+                       break;
                }
                if (root_freq < freq)
                        continue;
@@ -599,7 +677,7 @@ static int set_nfc_clk(u32 ref, u32 freq_khz)
                podf = min(DIV_ROUND_UP(root_freq, freq), 1U << 6);
                pred = min(DIV_ROUND_UP(root_freq / podf, freq), 8U);
                act_freq = root_freq / pred / podf;
-               err = (freq - act_freq) * 100 / freq;
+               err = (freq - act_freq) / (freq / 1000);
                debug("root=%d[%u] freq=%u pred=%u podf=%u act=%u err=%d\n",
                        nfc_clk_sel, root_freq, freq, pred, podf, act_freq, err);
                if (act_freq > freq)
@@ -614,61 +692,78 @@ static int set_nfc_clk(u32 ref, u32 freq_khz)
                }
        }
 
-       if (nfc_val == ~0 || min_err > 10)
+       if (nfc_val == ~0 || min_err > 100)
                return -EINVAL;
 
        if ((cs2cdr & CS2CDR_ENFC_MASK) != nfc_val) {
                debug("changing cs2cdr from %08x to %08x\n", cs2cdr,
                        (cs2cdr & ~CS2CDR_ENFC_MASK) | nfc_val);
+#ifdef CONFIG_NAND_MXS
+               setup_gpmi_io_clk(nfc_val);
+#else
                __raw_writel((cs2cdr & ~CS2CDR_ENFC_MASK) | nfc_val,
                        &imx_ccm->cs2cdr);
+#endif
        } else {
                debug("Leaving cs2cdr unchanged [%08x]\n", cs2cdr);
        }
        return 0;
 }
 
-#if (defined(CONFIG_SOC_MX6SL) || defined(CONFIG_SOC_MX6SX))
 static u32 get_mmdc_ch0_clk(void)
 {
        u32 cbcmr = __raw_readl(&imx_ccm->cbcmr);
        u32 cbcdr = __raw_readl(&imx_ccm->cbcdr);
-       u32 freq, podf;
 
-       podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH1_PODF_MASK) \
-                       >> MXC_CCM_CBCDR_MMDC_CH1_PODF_OFFSET;
-
-       switch ((cbcmr & MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK) >>
-               MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET) {
-       case 0:
-               freq = decode_pll(PLL_528, MXC_HCLK);
-               break;
-       case 1:
-               freq = mxc_get_pll_pfd(PLL_528, 2);
-               break;
-       case 2:
-               freq = mxc_get_pll_pfd(PLL_528, 0);
-               break;
-       case 3:
-               /* static / 2 divider */
-               freq =  mxc_get_pll_pfd(PLL_528, 2) / 2;
+       u32 freq, podf, per2_clk2_podf;
+
+       if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL) ||
+           is_cpu_type(MXC_CPU_MX6SL)) {
+               podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH1_PODF_MASK) >>
+                       MXC_CCM_CBCDR_MMDC_CH1_PODF_OFFSET;
+               if (cbcdr & MXC_CCM_CBCDR_PERIPH2_CLK_SEL) {
+                       per2_clk2_podf = (cbcdr & MXC_CCM_CBCDR_PERIPH2_CLK2_PODF_MASK) >>
+                               MXC_CCM_CBCDR_PERIPH2_CLK2_PODF_OFFSET;
+                       if (is_cpu_type(MXC_CPU_MX6SL)) {
+                               if (cbcmr & MXC_CCM_CBCMR_PERIPH2_CLK2_SEL)
+                                       freq = MXC_HCLK;
+                               else
+                                       freq = decode_pll(PLL_USBOTG, MXC_HCLK);
+                       } else {
+                               if (cbcmr & MXC_CCM_CBCMR_PERIPH2_CLK2_SEL)
+                                       freq = decode_pll(PLL_528, MXC_HCLK);
+                               else
+                                       freq = decode_pll(PLL_USBOTG, MXC_HCLK);
+                       }
+               } else {
+                       per2_clk2_podf = 0;
+                       switch ((cbcmr &
+                               MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK) >>
+                               MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET) {
+                       case 0:
+                               freq = decode_pll(PLL_528, MXC_HCLK);
+                               break;
+                       case 1:
+                               freq = mxc_get_pll_pfd(PLL_528, 2);
+                               break;
+                       case 2:
+                               freq = mxc_get_pll_pfd(PLL_528, 0);
+                               break;
+                       case 3:
+                               /* static / 2 divider */
+                               freq =  mxc_get_pll_pfd(PLL_528, 2) / 2;
+                               break;
+                       }
+               }
+               return freq / (podf + 1) / (per2_clk2_podf + 1);
+       } else {
+               podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK) >>
+                       MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET;
+               return get_periph_clk() / (podf + 1);
        }
-
-       return freq / (podf + 1);
-
 }
-#else
-static u32 get_mmdc_ch0_clk(void)
-{
-       u32 cbcdr = __raw_readl(&imx_ccm->cbcdr);
-       u32 mmdc_ch0_podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK) >>
-                               MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET;
 
-       return get_periph_clk() / (mmdc_ch0_podf + 1);
-}
-#endif
-
-#ifdef CONFIG_SOC_MX6SX
+#ifdef CONFIG_FSL_QSPI
 /* qspi_num can be from 0 - 1 */
 void enable_qspi_clk(int qspi_num)
 {
@@ -724,9 +819,6 @@ int enable_fec_anatop_clock(enum enet_freq freq)
        u32 reg = 0;
        s32 timeout = 100000;
 
-       struct anatop_regs __iomem *anatop =
-               (struct anatop_regs __iomem *)ANATOP_BASE_ADDR;
-
        if (freq < ENET_25MHZ || freq > ENET_125MHZ)
                return -EINVAL;
 
@@ -829,6 +921,7 @@ u32 imx_get_fecclk(void)
        return mxc_get_clock(MXC_IPG_CLK);
 }
 
+#if defined(CONFIG_CMD_SATA) || defined(CONFIG_PCIE_IMX)
 static int enable_enet_pll(uint32_t en)
 {
        u32 reg;
@@ -851,28 +944,15 @@ static int enable_enet_pll(uint32_t en)
        writel(reg, &anatop->pll_enet);
        return 0;
 }
+#endif
 
-#ifndef CONFIG_SOC_MX6SX
+#ifdef CONFIG_CMD_SATA
 static void ungate_sata_clock(void)
 {
-       struct mxc_ccm_reg *const imx_ccm =
-               (struct mxc_ccm_reg *)CCM_BASE_ADDR;
-
        /* Enable SATA clock. */
        setbits_le32(&imx_ccm->CCGR5, MXC_CCM_CCGR5_SATA_MASK);
 }
-#endif
-
-static void ungate_pcie_clock(void)
-{
-       struct mxc_ccm_reg *const imx_ccm =
-               (struct mxc_ccm_reg *)CCM_BASE_ADDR;
 
-       /* Enable PCIe clock. */
-       setbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_PCIE_MASK);
-}
-
-#ifndef CONFIG_SOC_MX6SX
 int enable_sata_clock(void)
 {
        ungate_sata_clock();
@@ -881,18 +961,19 @@ int enable_sata_clock(void)
 
 void disable_sata_clock(void)
 {
-       struct mxc_ccm_reg *const imx_ccm =
-               (struct mxc_ccm_reg *)CCM_BASE_ADDR;
-
        clrbits_le32(&imx_ccm->CCGR5, MXC_CCM_CCGR5_SATA_MASK);
 }
 #endif
 
+#ifdef CONFIG_PCIE_IMX
+static void ungate_pcie_clock(void)
+{
+       /* Enable PCIe clock. */
+       setbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_PCIE_MASK);
+}
+
 int enable_pcie_clock(void)
 {
-       struct anatop_regs *anatop_regs =
-               (struct anatop_regs *)ANATOP_BASE_ADDR;
-       struct mxc_ccm_reg *ccm_regs = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
        u32 lvds1_clk_sel;
 
        /*
@@ -927,7 +1008,7 @@ int enable_pcie_clock(void)
        clrbits_le32(&ccm_regs->cbcmr, MXC_CCM_CBCMR_PCIE_AXI_CLK_SEL);
 
        /* Party time! Ungate the clock to the PCIe. */
-#ifndef CONFIG_SOC_MX6SX
+#ifdef CONFIG_CMD_SATA
        ungate_sata_clock();
 #endif
        ungate_pcie_clock();
@@ -935,6 +1016,7 @@ int enable_pcie_clock(void)
        return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_SATA |
                               BM_ANADIG_PLL_ENET_ENABLE_PCIE);
 }
+#endif
 
 #ifdef CONFIG_SECURE_BOOT
 void hab_caam_clock_enable(unsigned char enable)
@@ -965,25 +1047,22 @@ void hab_caam_clock_enable(unsigned char enable)
 
 static void enable_pll3(void)
 {
-       struct anatop_regs __iomem *anatop =
-               (struct anatop_regs __iomem *)ANATOP_BASE_ADDR;
-
        /* make sure pll3 is enabled */
        if ((readl(&anatop->usb1_pll_480_ctrl) &
-                       BM_ANADIG_USB_PLL_480_CTRL_LOCK) == 0) {
+                       BM_ANADIG_USB1_PLL_480_CTRL_LOCK) == 0) {
                /* enable pll's power */
-               writel(BM_ANADIG_USB_PLL_480_CTRL_POWER,
+               writel(BM_ANADIG_USB1_PLL_480_CTRL_POWER,
                       &anatop->usb1_pll_480_ctrl_set);
                writel(0x80, &anatop->ana_misc2_clr);
                /* wait for pll lock */
                while ((readl(&anatop->usb1_pll_480_ctrl) &
-                       BM_ANADIG_USB_PLL_480_CTRL_LOCK) == 0)
+                       BM_ANADIG_USB1_PLL_480_CTRL_LOCK) == 0)
                        ;
                /* disable bypass */
-               writel(BM_ANADIG_USB_PLL_480_CTRL_BYPASS,
+               writel(BM_ANADIG_USB1_PLL_480_CTRL_BYPASS,
                       &anatop->usb1_pll_480_ctrl_clr);
                /* enable pll output */
-               writel(BM_ANADIG_USB_PLL_480_CTRL_ENABLE,
+               writel(BM_ANADIG_USB1_PLL_480_CTRL_ENABLE,
                       &anatop->usb1_pll_480_ctrl_set);
        }
 }
@@ -1071,20 +1150,278 @@ void ldb_clk_disable(int ldb)
        }
 }
 
-void ocotp_clk_enable(void)
+#ifdef CONFIG_VIDEO_MXS
+void lcdif_clk_enable(void)
 {
-       u32 reg = readl(&imx_ccm->CCGR2);
-       reg |= MXC_CCM_CCGR2_OCOTP_CTRL_MASK;
-       writel(reg, &imx_ccm->CCGR2);
+       setbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_LCDIF_MASK);
+       setbits_le32(&imx_ccm->CCGR2, MXC_CCM_CCGR2_LCD_MASK);
 }
 
-void ocotp_clk_disable(void)
+void lcdif_clk_disable(void)
 {
-       u32 reg = readl(&imx_ccm->CCGR2);
-       reg &= ~MXC_CCM_CCGR2_OCOTP_CTRL_MASK;
-       writel(reg, &imx_ccm->CCGR2);
+       clrbits_le32(&imx_ccm->CCGR2, MXC_CCM_CCGR2_LCD_MASK);
+       clrbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_LCDIF_MASK);
 }
 
+#define CBCMR_LCDIF_MASK       MXC_CCM_CBCMR_LCDIF_PODF_MASK
+#define CSCDR2_LCDIF_MASK      (MXC_CCM_CSCDR2_LCDIF_PRED_MASK |       \
+                               MXC_CCM_CSCDR2_LCDIF_CLK_SEL_MASK)
+
+static u32 get_lcdif_root_clk(u32 cscdr2)
+{
+       int lcdif_pre_clk_sel = (cscdr2 & MXC_CCM_CSCDR2_LCDIF_PRE_CLK_SEL_MASK) >>
+               MXC_CCM_CSCDR2_LCDIF_PRE_CLK_SEL_OFFSET;
+       int lcdif_clk_sel = (cscdr2 & MXC_CCM_CSCDR2_LCDIF_CLK_SEL_MASK) >>
+               MXC_CCM_CSCDR2_LCDIF_CLK_SEL_OFFSET;
+       u32 root_freq;
+
+       switch (lcdif_clk_sel) {
+       case 0:
+               switch (lcdif_pre_clk_sel) {
+               case 0:
+                       root_freq = decode_pll(PLL_528, MXC_HCLK);
+                       break;
+               case 1:
+                       root_freq = mxc_get_pll_pfd(PLL_USBOTG, 3);
+                       break;
+               case 2:
+                       root_freq = decode_pll(PLL_VIDEO, MXC_HCLK);
+                       break;
+               case 3:
+                       root_freq = mxc_get_pll_pfd(PLL_528, 0);
+                       break;
+               case 4:
+                       root_freq = mxc_get_pll_pfd(PLL_528, 1);
+                       break;
+               case 5:
+                       root_freq = mxc_get_pll_pfd(PLL_USBOTG, 1);
+                       break;
+               default:
+                       return 0;
+               }
+               break;
+       case 1:
+               root_freq = mxc_get_pll_pfd(PLL_VIDEO, 0);
+               break;
+       case 2:
+               root_freq = decode_pll(PLL_USBOTG, MXC_HCLK);
+               break;
+       case 3:
+               root_freq = mxc_get_pll_pfd(PLL_528, 2);
+               break;
+       default:
+               return 0;
+       }
+
+       return root_freq;
+}
+
+static int set_lcdif_pll(u32 ref, u32 freq_khz,
+                       unsigned post_div)
+{
+       int ret;
+       u64 freq = freq_khz * 1000;
+       u32 post_div_mask = 1 << (2 - post_div);
+       int mul = 1;
+       u32 min_err = ~0;
+       u32 reg;
+       int num = 0;
+       int denom = 1;
+       const int min_div = 27;
+       const int max_div = 54;
+       const int div_mask = 0x7f;
+       const u32 max_freq = ref * max_div / post_div;
+       const u32 min_freq = ref * min_div / post_div;
+
+       if (freq > max_freq || freq < min_freq) {
+               printf("Frequency %u.%03uMHz is out of range: %u.%03u..%u.%03uMHz\n",
+                       freq_khz / 1000, freq_khz % 1000,
+                       min_freq / 1000000, min_freq / 1000 % 1000,
+                       max_freq / 1000000, max_freq / 1000 % 1000);
+               return -EINVAL;
+       }
+       {
+               int d = post_div;
+               int m = lldiv(freq * d + ref - 1, ref);
+               u32 err;
+               u32 f;
+
+               debug("%s@%d: d=%d m=%d max_div=%u min_div=%u\n", __func__, __LINE__,
+                       d, m, max_div, min_div);
+               if (m > max_div || m < min_div)
+                       return -EINVAL;
+
+               f = ref * m / d;
+               if (f > freq) {
+                       debug("%s@%d: d=%d m=%d f=%u freq=%llu\n", __func__, __LINE__,
+                               d, m, f, freq);
+                       return -EINVAL;
+               }
+               err = freq - f;
+               debug("%s@%d: d=%d m=%d f=%u freq=%llu err=%d\n", __func__, __LINE__,
+                       d, m, f, freq, err);
+               if (err < min_err) {
+                       mul = m;
+                       min_err = err;
+               }
+       }
+       if (min_err == ~0) {
+               printf("Cannot set VIDEO PLL to %u.%03uMHz\n",
+                       freq_khz / 1000, freq_khz % 1000);
+               return -EINVAL;
+       }
+
+       debug("Setting M=%3u D=%u N=%d DE=%u for %u.%03uMHz (actual: %u.%03uMHz)\n",
+               mul, post_div, num, denom,
+               freq_khz / post_div / 1000, freq_khz / post_div % 1000,
+               ref * mul / post_div / 1000000,
+               ref * mul / post_div / 1000 % 1000);
+
+       reg = readl(&anatop->pll_video);
+       setbits_le32(&anatop->pll_video, BM_ANADIG_PLL_VIDEO_BYPASS);
+
+       reg = (reg & ~(div_mask |
+                       BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT)) |
+               mul | (post_div_mask << BP_ANADIG_PLL_VIDEO_POST_DIV_SELECT);
+       writel(reg, &anatop->pll_video);
+
+       ret = wait_pll_lock(&anatop->pll_video);
+       if (ret) {
+               printf("Video PLL failed to lock\n");
+               return ret;
+       }
+
+       clrbits_le32(&anatop->pll_video, BM_ANADIG_PLL_VIDEO_BYPASS);
+       return 0;
+}
+
+static int set_lcdif_clk(u32 ref, u32 freq_khz)
+{
+       u32 cbcmr = __raw_readl(&imx_ccm->cbcmr);
+       u32 cscdr2 = __raw_readl(&imx_ccm->cscdr2);
+       u32 cbcmr_val;
+       u32 cscdr2_val;
+       u32 freq = freq_khz * 1000;
+       u32 act_freq;
+       u32 err;
+       u32 min_div = 27;
+       u32 max_div = 54;
+       u32 min_pll_khz = ref * min_div / 4 / 1000;
+       u32 max_pll_khz = ref * max_div / 1000;
+       u32 pll_khz;
+       u32 post_div = 0;
+       u32 m;
+       u32 min_err = ~0;
+       u32 best_m = 0;
+       u32 best_pred = 1;
+       u32 best_podf = 1;
+       u32 div;
+       unsigned pd;
+
+       if (freq_khz > max_pll_khz)
+               return -EINVAL;
+
+       for (pd = 1; min_err && pd <= 4; pd <<= 1) {
+               for (m = max(min_div, DIV_ROUND_UP(648000 / pd, freq_khz * 64));
+                    m <= max_div; m++) {
+                       u32 err;
+                       int pred = 0;
+                       int podf = 0;
+                       u32 root_freq = ref * m / pd;
+
+                       div = DIV_ROUND_UP(root_freq, freq);
+
+                       while (pred * podf == 0 && div <= 64) {
+                               int p1, p2;
+
+                               for (p1 = 1; p1 <= 8; p1++) {
+                                       for (p2 = 1; p2 <= 8; p2++) {
+                                               if (p1 * p2 == div) {
+                                                       podf = p1;
+                                                       pred = p2;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               if (pred * podf == 0) {
+                                       div++;
+                               }
+                       }
+                       if (pred * podf == 0)
+                               continue;
+
+                       /* relative error in per mille */
+                       act_freq = root_freq / div;
+                       err = abs(act_freq - freq) / freq_khz;
+
+                       if (err < min_err) {
+                               best_m = m;
+                               best_pred = pred;
+                               best_podf = podf;
+                               post_div = pd;
+                               min_err = err;
+                               if (err <= 10)
+                                       break;
+                       }
+               }
+       }
+       if (min_err > 50)
+               return -EINVAL;
+
+       pll_khz = ref / 1000 * best_m;
+       if (pll_khz > max_pll_khz)
+               return -EINVAL;
+
+       if (pll_khz < min_pll_khz)
+               return -EINVAL;
+
+       err = set_lcdif_pll(ref, pll_khz / post_div, post_div);
+       if (err)
+               return err;
+
+       cbcmr_val = (best_podf - 1) << MXC_CCM_CBCMR_LCDIF_PODF_OFFSET;
+       cscdr2_val = (best_pred - 1) << MXC_CCM_CSCDR2_LCDIF_PRED_OFFSET;
+
+       if ((cbcmr & CBCMR_LCDIF_MASK) != cbcmr_val) {
+               debug("changing cbcmr from %08x to %08x\n", cbcmr,
+                       (cbcmr & ~CBCMR_LCDIF_MASK) | cbcmr_val);
+               clrsetbits_le32(&imx_ccm->cbcmr,
+                               CBCMR_LCDIF_MASK,
+                               cbcmr_val);
+       } else {
+               debug("Leaving cbcmr unchanged [%08x]\n", cbcmr);
+       }
+       if ((cscdr2 & CSCDR2_LCDIF_MASK) != cscdr2_val) {
+               debug("changing cscdr2 from %08x to %08x\n", cscdr2,
+                       (cscdr2 & ~CSCDR2_LCDIF_MASK) | cscdr2_val);
+               clrsetbits_le32(&imx_ccm->cscdr2,
+                               CSCDR2_LCDIF_MASK,
+                               cscdr2_val);
+       } else {
+               debug("Leaving cscdr2 unchanged [%08x]\n", cscdr2);
+       }
+       return 0;
+}
+
+void mxs_set_lcdclk(u32 khz)
+{
+       set_lcdif_clk(CONFIG_SYS_MX6_HCLK, khz);
+}
+
+static u32 get_lcdif_clk(void)
+{
+       u32 cbcmr = __raw_readl(&imx_ccm->cbcmr);
+       u32 podf = ((cbcmr & MXC_CCM_CBCMR_LCDIF_PODF_MASK) >>
+               MXC_CCM_CBCMR_LCDIF_PODF_OFFSET) + 1;
+       u32 cscdr2 = __raw_readl(&imx_ccm->cscdr2);
+       u32 pred = ((cscdr2 & MXC_CCM_CSCDR2_LCDIF_PRED_MASK) >>
+               MXC_CCM_CSCDR2_LCDIF_PRED_OFFSET) + 1;
+       u32 root_freq = get_lcdif_root_clk(cscdr2);
+
+       return root_freq / pred / podf;
+}
+#endif
+
 unsigned int mxc_get_clock(enum mxc_clock clk)
 {
        switch (clk) {
@@ -1121,6 +1458,10 @@ unsigned int mxc_get_clock(enum mxc_clock clk)
                return get_ahb_clk();
        case MXC_NFC_CLK:
                return get_nfc_clk();
+#ifdef CONFIG_VIDEO_MXS
+       case MXC_LCDIF_CLK:
+               return get_lcdif_clk();
+#endif
        default:
                printf("Unsupported MXC CLK: %d\n", clk);
        }
@@ -1128,34 +1469,26 @@ unsigned int mxc_get_clock(enum mxc_clock clk)
        return 0;
 }
 
-static inline int gcd(int m, int n)
-{
-       int t;
-       while (m > 0) {
-               if (n > m) {
-                       t = m;
-                       m = n;
-                       n = t;
-               } /* swap */
-               m -= n;
-       }
-       return n;
-}
-
 /* Config CPU clock */
 static int set_arm_clk(u32 ref, u32 freq_khz)
 {
+       int ret;
        int d;
        int div = 0;
        int mul = 0;
        u32 min_err = ~0;
        u32 reg;
+       const int min_div = 54;
+       const int max_div = 108;
+       const int div_mask = 0x7f;
+       const u32 max_freq = ref * max_div / 2;
+       const u32 min_freq = ref * min_div / 8 / 2;
 
-       if (freq_khz > ref / 1000 * 108 / 2 || freq_khz < ref / 1000 * 54 / 8 / 2) {
+       if (freq_khz > max_freq / 1000 || freq_khz < min_freq / 1000) {
                printf("Frequency %u.%03uMHz is out of range: %u.%03u..%u.%03u\n",
                        freq_khz / 1000, freq_khz % 1000,
-                       54 * ref / 1000000 / 8 / 2, 54 * ref / 1000 / 8 / 2 % 1000,
-                       108 * ref / 1000000 / 2, 108 * ref / 1000 / 2 % 1000);
+                       min_freq / 1000000, min_freq / 1000 % 1000,
+                       max_freq / 1000000, max_freq / 1000 % 1000);
                return -EINVAL;
        }
 
@@ -1164,7 +1497,7 @@ static int set_arm_clk(u32 ref, u32 freq_khz)
                u32 f;
                u32 err;
 
-               if (m > 108) {
+               if (m > max_div) {
                        debug("%s@%d: d=%d m=%d\n", __func__, __LINE__,
                                d, m);
                        break;
@@ -1174,7 +1507,7 @@ static int set_arm_clk(u32 ref, u32 freq_khz)
                if (f > freq_khz * 1000) {
                        debug("%s@%d: d=%d m=%d f=%u freq=%u\n", __func__, __LINE__,
                                d, m, f, freq_khz);
-                       if (--m < 54)
+                       if (--m < min_div)
                                return -EINVAL;
                        f = ref * m / d / 2;
                }
@@ -1196,19 +1529,20 @@ static int set_arm_clk(u32 ref, u32 freq_khz)
                ref * mul / 2 / div / 1000000, ref * mul / 2 / div / 1000 % 1000);
 
        reg = readl(&anatop->pll_arm);
-       debug("anadig_pll_arm=%08x -> %08x\n",
-               reg, (reg & ~0x7f) | mul);
+       setbits_le32(&anatop->pll_video, BM_ANADIG_PLL_ARM_BYPASS);
 
-       reg |= 1 << 16;
-       writel(reg, &anatop->pll_arm); /* bypass PLL */
-
-       reg = (reg & ~0x7f) | mul;
+       reg = (reg & ~div_mask) | mul;
        writel(reg, &anatop->pll_arm);
 
        writel(div - 1, &imx_ccm->cacrr);
 
-       reg &= ~(1 << 16);
-       writel(reg, &anatop->pll_arm); /* disable PLL bypass */
+       ret = wait_pll_lock(&anatop->pll_video);
+       if (ret) {
+               printf("ARM PLL failed to lock\n");
+               return ret;
+       }
+
+       clrbits_le32(&anatop->pll_video, BM_ANADIG_PLL_ARM_BYPASS);
 
        return 0;
 }
@@ -1227,11 +1561,6 @@ static int set_arm_clk(u32 ref, u32 freq_khz)
  *         so the caller has to make sure those values are sensible.
  *      2) Also adjust the NFC divider such that the NFC clock doesn't
  *         exceed NFC_CLK_MAX.
- *      3) IPU HSP clock is independent of AHB clock. Even it can go up to
- *         177MHz for higher voltage, this function fixes the max to 133MHz.
- *      4) This function should not have allowed diag_printf() calls since
- *         the serial driver has been stoped. But leave then here to allow
- *         easy debugging by NOT calling the cyg_hal_plf_serial_stop().
  */
 int mxc_set_clock(u32 ref, u32 freq, enum mxc_clock clk)
 {
@@ -1320,6 +1649,9 @@ static void do_mx6_showclocks(void)
        print_clk(NFC);
        print_clk(IPG_PER);
        print_clk(ARM);
+#ifdef CONFIG_VIDEO_MXS
+       print_clk(LCDIF);
+#endif
 }
 
 static struct clk_lookup {
@@ -1393,11 +1725,14 @@ int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 #ifndef CONFIG_SOC_MX6SX
 void enable_ipu_clock(void)
 {
-       struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
-       int reg;
-       reg = readl(&mxc_ccm->CCGR3);
+       int reg = readl(&imx_ccm->CCGR3);
        reg |= MXC_CCM_CCGR3_IPU1_IPU_MASK;
-       writel(reg, &mxc_ccm->CCGR3);
+       writel(reg, &imx_ccm->CCGR3);
+
+       if (is_mx6dqp()) {
+               setbits_le32(&imx_ccm->CCGR6, MXC_CCM_CCGR6_PRG_CLK0_MASK);
+               setbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_IPU2_IPU_MASK);
+       }
 }
 #endif
 /***************************************************/