]> 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 6a5117394e557ab8d0fc82d207bf5e719c672c5d..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)
 {
@@ -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:
@@ -313,18 +334,46 @@ static u32 decode_pll(enum pll_clocks pll, u32 infreq)
                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)
@@ -343,16 +392,17 @@ static u32 decode_pll(enum pll_clocks pll, u32 infreq)
                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:
@@ -545,31 +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);
 }
@@ -588,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) {
@@ -609,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;
@@ -616,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)
@@ -631,14 +692,18 @@ 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);
        }
@@ -754,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;
 
@@ -887,9 +949,6 @@ static int enable_enet_pll(uint32_t en)
 #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);
 }
@@ -902,9 +961,6 @@ 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
@@ -912,18 +968,12 @@ void disable_sata_clock(void)
 #ifdef CONFIG_PCIE_IMX
 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);
 }
 
 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;
 
        /*
@@ -997,9 +1047,6 @@ 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_USB1_PLL_480_CTRL_LOCK) == 0) {
@@ -1103,6 +1150,278 @@ void ldb_clk_disable(int ldb)
        }
 }
 
+#ifdef CONFIG_VIDEO_MXS
+void lcdif_clk_enable(void)
+{
+       setbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_LCDIF_MASK);
+       setbits_le32(&imx_ccm->CCGR2, MXC_CCM_CCGR2_LCD_MASK);
+}
+
+void lcdif_clk_disable(void)
+{
+       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) {
@@ -1139,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);
        }
@@ -1146,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;
        }
 
@@ -1182,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;
@@ -1192,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;
                }
@@ -1214,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;
 }
@@ -1245,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)
 {
@@ -1338,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 {
@@ -1411,15 +1725,13 @@ 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(&mxc_ccm->CCGR6, MXC_CCM_CCGR6_PRG_CLK0_MASK);
-               setbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_IPU2_IPU_MASK);
+               setbits_le32(&imx_ccm->CCGR6, MXC_CCM_CCGR6_PRG_CLK0_MASK);
+               setbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_IPU2_IPU_MASK);
        }
 }
 #endif