Clocks are now configurable via the common clock framework, however,
users have the option use the legacy clocks if desired. The intent is to
keep the changes minimal for this old SoC.

Signed-off-by: Brian Ruley <[email protected]>
---

 drivers/video/imx/ipu_common.c   |  76 ++++++++++++++---
 drivers/video/imx/ipu_disp.c     | 142 +++++++++++++++++++++++++------
 drivers/video/imx/mxc_ipuv3_fb.c |  17 ++++
 3 files changed, 197 insertions(+), 38 deletions(-)

diff --git a/drivers/video/imx/ipu_common.c b/drivers/video/imx/ipu_common.c
index d994053394f..ccd4a58b4b4 100644
--- a/drivers/video/imx/ipu_common.c
+++ b/drivers/video/imx/ipu_common.c
@@ -14,6 +14,7 @@
  *
  * (C) Copyright 2005-2010 Freescale Semiconductor, Inc.
  */
+#define DEBUG
 
 #include "ipu.h"
 #include "ipu_regs.h"
@@ -101,7 +102,18 @@ struct ipu_ch_param {
  */
 static int ipu_clk_init(struct ipu_ctx *ctx)
 {
+#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
        return ipu_clk_init_legacy(ctx);
+#else
+       struct clk *clk;
+
+       clk = devm_clk_get(ctx->dev, "bus");
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       ctx->ipu_clk = clk;
+       return 0;
+#endif
 }
 
 /*
@@ -113,7 +125,13 @@ static int ipu_clk_init(struct ipu_ctx *ctx)
  */
 static int ipu_ldb_clk_init(struct ipu_ctx *ctx)
 {
+#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
        return ipu_ldb_clk_init_legacy(ctx);
+#else
+       /* Set this in the FB driver where we know the display id */
+       ctx->ldb_clk = NULL;
+       return 0;
+#endif
 }
 
 /* Static functions */
@@ -150,6 +168,29 @@ static inline void ipu_ch_param_set_buffer(u32 ch, int 
buf_num,
 #define idma_mask(ch) (idma_is_valid(ch) ? (1UL << (ch & 0x1F)) : 0)
 #define idma_is_set(reg, dma) (__raw_readl(reg(dma)) & idma_mask(dma))
 
+/*
+ * Function to initialize the display clocks
+ *
+ * @param   ctx            The ipu context for which the function is called
+ *
+ * Return:  Returns 0 on success or negative error code on error
+ */
+static int ipu_di_clk_init(struct ipu_ctx *ctx, int id)
+{
+#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
+       ctx->di_clk[id] = NULL;
+       return 0;
+#else
+       struct clk *clk;
+
+       clk = devm_clk_get(ctx->dev, id ? "di1" : "di0");
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       ctx->di_clk[id] = clk;
+       return 0;
+#endif
+}
 /*
  * Function to initialize the pixel clock
  *
@@ -159,7 +200,12 @@ static inline void ipu_ch_param_set_buffer(u32 ch, int 
buf_num,
  */
 static int ipu_pixel_clk_init(struct ipu_ctx *ctx, int id)
 {
+#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
        return ipu_pixel_clk_init_legacy(ctx, id);
+#else
+       ctx->pixel_clk[id] = ctx->ipu_clk;
+       return 0;
+#endif
 }
 
 /*
@@ -230,33 +276,39 @@ struct ipu_ctx *ipu_probe(struct udevice *dev)
        ipu_cpmem_base = (u32 *)(ipu_base + IPU_CPMEM_REG_BASE);
        ipu_dc_tmpl_reg = (u32 *)(ipu_base + IPU_DC_TMPL_REG_BASE);
 
-       ret = ipu_pixel_clk_init(ctx, 0);
-       if (ret)
-               goto err;
-
-       ret = ipu_pixel_clk_init(ctx, 1);
-       if (ret)
-               goto err;
+       for (int i = 0; i <= 1; i++) {
+               ret = ipu_pixel_clk_init(ctx, i);
+               if (ret)
+                       goto err;
+       }
 
        ret = ipu_clk_init(ctx);
        if (ret)
                goto err;
 
-       debug("ipu_clk = %u\n", clk_get_rate(ctx->ipu_clk));
+       debug("ipu_clk = %lu\n", (ulong)clk_get_rate(ctx->ipu_clk));
 
        ret = ipu_ldb_clk_init(ctx);
        if (ret)
                goto err;
 
-       debug("ldb_clk = %u\n", clk_get_rate(ctx->ldb_clk));
+       if (ctx->ldb_clk)
+               debug("ldb_clk = %lu\n", (ulong)clk_get_rate(ctx->ldb_clk));
+
        ipu_reset();
 
+#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
        clk_set_parent(ctx->pixel_clk[0], ctx->ipu_clk);
        clk_set_parent(ctx->pixel_clk[1], ctx->ipu_clk);
+
        clk_enable(ctx->ipu_clk);
+#endif
 
-       ctx->di_clk[0] = NULL;
-       ctx->di_clk[1] = NULL;
+       for (int i = 0; i <= 1; i++) {
+               ret = ipu_di_clk_init(ctx, i);
+               if (ret)
+                       goto err;
+       }
 
        __raw_writel(0x807FFFFF, IPU_MEM_RST);
        while (__raw_readl(IPU_MEM_RST) & 0x80000000)
@@ -278,7 +330,9 @@ struct ipu_ctx *ipu_probe(struct udevice *dev)
        /* Set MCU_T to divide MCU access window into 2 */
        __raw_writel(0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN);
 
+#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
        clk_disable(ctx->ipu_clk);
+#endif
 
        return ctx;
 err:
diff --git a/drivers/video/imx/ipu_disp.c b/drivers/video/imx/ipu_disp.c
index 6a337b13af6..5e78574da9b 100644
--- a/drivers/video/imx/ipu_disp.c
+++ b/drivers/video/imx/ipu_disp.c
@@ -612,6 +612,11 @@ void ipu_dp_dc_enable(struct ipu_ctx *ctx, ipu_channel_t 
channel)
        __raw_writel(reg, DC_WR_CH_CONF(dc_chan));
 
        clk_enable(ctx->pixel_clk[di]);
+#if !CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
+       reg = __raw_readl(IPU_DISP_GEN);
+       reg |= di ? DI1_COUNTER_RELEASE : DI0_COUNTER_RELEASE;
+       __raw_writel(reg, IPU_DISP_GEN);
+#endif
 }
 
 static unsigned char dc_swap;
@@ -702,6 +707,12 @@ void ipu_dp_dc_disable(struct ipu_ctx *ctx, ipu_channel_t 
channel,
 
                /* Clock is already off because it must be done quickly, but
                   we need to fix the ref count */
+#if !CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
+               reg = __raw_readl(IPU_DISP_GEN);
+               reg &= ctx->dc_di_assignment[dc_chan] ? ~DI1_COUNTER_RELEASE :
+                                                       ~DI0_COUNTER_RELEASE;
+               __raw_writel(reg, IPU_DISP_GEN);
+#endif
                clk_disable(ctx->pixel_clk[ctx->dc_di_assignment[dc_chan]]);
        }
 }
@@ -765,40 +776,21 @@ static int ipu_pixfmt_to_map(u32 fmt)
  *
  * @param      sig     Bitfield of signal polarities for LCD interface.
  *
- * Return:     This function returns 0 on success or negative error code on
- *             fail.
+ * Return:     The integer portion of the divider set for the pixel clock.
  */
-
-int32_t ipu_init_sync_panel(struct ipu_di_config *di, ipu_di_signal_cfg_t sig)
+static u32 ipu_di_clk_config(struct ipu_di_config *di, ipu_di_signal_cfg_t sig)
 {
        struct ipu_ctx *ctx = di->ctx;
        int disp = di->disp;
-       u32 reg;
-       u32 di_gen, vsync_cnt;
-       u32 div, rounded_pixel_clk;
-       u32 h_total, v_total;
-       int map;
-       struct clk *di_parent;
-
-       debug("panel size = %d x %d\n", di->width, di->height);
-
-       if ((di->v_sync_width == 0) || (di->h_sync_width == 0))
-               return -EINVAL;
-
-       /* adapt panel to ipu restricitions */
-       if (di->v_end_width < 2) {
-               di->v_end_width = 2;
-               puts("WARNING: v_end_width (lower_margin) must be >= 2, 
adjusted\n");
-       }
-
-       h_total = di->width + di->h_sync_width + di->h_start_width +
-                 di->h_end_width;
-       v_total = di->height + di->v_sync_width + di->v_start_width +
-                 di->v_end_width;
+       u32 div;
 
        /* Init clocking */
        debug("pixel clk = %dHz\n", di->pixel_clk_rate);
 
+#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
+       u32 rounded_pixel_clk;
+       struct clk *di_parent;
+
        if (sig.ext_clk) {
                if (!(g_di1_tvout && (disp == 1))) { /*not round div for tvout*/
                        /*
@@ -830,13 +822,109 @@ int32_t ipu_init_sync_panel(struct ipu_di_config *di, 
ipu_di_signal_cfg_t sig)
                if (clk_get_usecount(ctx->pixel_clk[disp]) != 0)
                        clk_set_parent(ctx->pixel_clk[disp], ctx->ipu_clk);
        }
+
        rounded_pixel_clk =
                clk_round_rate(ctx->pixel_clk[disp], di->pixel_clk_rate);
        clk_set_rate(ctx->pixel_clk[disp], rounded_pixel_clk);
-       udelay(5000);
+
        /* Get integer portion of divider */
        div = clk_get_rate(clk_get_parent(ctx->pixel_clk[disp])) /
              rounded_pixel_clk;
+#else
+       struct clk *clk;
+       u32 clkgen0, di_gen;
+       ulong id;
+
+       if (sig.ext_clk) {
+               /*
+                * Bypass the divider, assuming synchronous mode
+                */
+               clk = ctx->di_clk[disp];
+               div = 1;
+       } else {
+
+               ulong clk_rate = clk_get_rate(ctx->ipu_clk);
+               u32 error;
+
+               div = DIV_ROUND_CLOSEST(clk_rate, di->pixel_clk_rate);
+               div = clamp(div, 1U, 255U);
+
+               error = (clk_rate / div) / (di->pixel_clk_rate / 1000);
+
+               /*
+                 * Select IPU if the rate is within 1% of requested pixel
+                 * clock, otherwise, use the DI clock
+                 */
+               if (990 <= error && error < 1010) {
+                       clk = ctx->ipu_clk;
+               } else {
+                       clk = ctx->di_clk[disp];
+
+                       clk_set_rate(clk, di->pixel_clk_rate);
+                       div = DIV_ROUND_CLOSEST(clk_get_rate(clk),
+                                               di->pixel_clk_rate);
+                       div = clamp(div, 1U, 255U);
+               }
+       }
+
+       clkgen0 = div << 4;
+
+       ctx->pixel_clk[disp] = clk;
+       debug("new pixel rate: %lu Hz\n", clk_get_rate(clk));
+
+       id = clk_get_id(clk);
+       __raw_writel(clkgen0, DI_BS_CLKGEN0(id));
+       __raw_writel((clkgen0 & 0xFFF0) << 12, DI_BS_CLKGEN1(id));
+
+       di_gen = __raw_readl(DI_GENERAL(id)) & ~DI_GEN_DI_CLK_EXT;
+       if (clk == ctx->di_clk[disp])
+               di_gen |= DI_GEN_DI_CLK_EXT;
+
+       __raw_writel(di_gen, DI_GENERAL(id));
+#endif
+
+       udelay(5000);
+       return div;
+}
+
+/*
+ * This function is called to initialize a synchronous LCD panel.
+ *
+ * @param      di      Pointer to display data.
+ *
+ * @param      sig     Bitfield of signal polarities for LCD interface.
+ *
+ * Return:     This function returns 0 on success or negative error code on
+ *             fail.
+ */
+int32_t ipu_init_sync_panel(struct ipu_di_config *di, ipu_di_signal_cfg_t sig)
+{
+       int disp = di->disp;
+       u32 reg;
+       u32 di_gen, vsync_cnt;
+       u32 div;
+       u32 h_total, v_total;
+       int map;
+
+       debug("panel size = %d x %d\n", di->width, di->height);
+
+       if ((di->v_sync_width == 0) || (di->h_sync_width == 0))
+               return -EINVAL;
+
+       /* adapt panel to ipu restricitions */
+       if (di->v_end_width < 2) {
+               di->v_end_width = 2;
+               puts("WARNING: v_end_width (lower_margin) must be >= 2, 
adjusted\n");
+       }
+
+       h_total = di->width + di->h_sync_width + di->h_start_width +
+                 di->h_end_width;
+       v_total = di->height + di->v_sync_width + di->v_start_width +
+                 di->v_end_width;
+
+       div = ipu_di_clk_config(di, sig);
+       if (div < 0)
+               return div;
 
        ipu_di_data_wave_config(disp, SYNC_WAVE, div - 1, div - 1);
        ipu_di_data_pin_config(disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
diff --git a/drivers/video/imx/mxc_ipuv3_fb.c b/drivers/video/imx/mxc_ipuv3_fb.c
index ab416fdd33c..cfc34972ad1 100644
--- a/drivers/video/imx/mxc_ipuv3_fb.c
+++ b/drivers/video/imx/mxc_ipuv3_fb.c
@@ -36,6 +36,7 @@
 #include <dm.h>
 #include <dm/devres.h>
 #include <video.h>
+#include <dt-bindings/clock/imx6qdl-clock.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -602,6 +603,22 @@ static int ipuv3_video_probe(struct udevice *dev)
        if (ret < 0)
                return ret;
 
+#if !CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
+       if (of_machine_is_compatible("fsl,imx6qp"))
+               ret = clk_get_by_id(gdisp ? IMX6QDL_CLK_LDB_DI1_PODF :
+                                           IMX6QDL_CLK_LDB_DI0_PODF,
+                                   &ctx->ldb_clk);
+       else
+               ret = clk_get_by_id(gdisp ? IMX6QDL_CLK_LDB_DI1 :
+                                           IMX6QDL_CLK_LDB_DI0,
+                                   &ctx->ldb_clk);
+
+       if (ret < 0)
+               return ret;
+
+       debug("ldb_clk = %lu\n", clk_get_rate(ctx->ldb_clk));
+#endif
+
        ret = mxcfb_probe(dev, gpixfmt, gdisp, gmode);
        if (ret < 0)
                return ret;
-- 
2.39.5

Reply via email to