If DI is firstly bound to ldb and then re-bound to HDMI,
DI clock source will still be routed to LDB clock by ldb driver.
In HDMI driver's encoder_prepare, we have to set DI clock source to
the parent di_pre clock mux to ensure we are having correct clock
chain to drive HDMI display.

Signed-off-by: Steve Longerbeam <steve_longerbeam at mentor.com>
Signed-off-by: Jiada Wang <jiada_wang at mentor.com>
---
 arch/arm/boot/dts/imx6dl.dtsi      |    8 ++++++++
 arch/arm/boot/dts/imx6q.dtsi       |   12 ++++++++++++
 arch/arm/boot/dts/imx6qdl.dtsi     |    3 ---
 drivers/staging/imx-drm/imx-hdmi.c |   32 +++++++++++++++++++++++++++++++-
 4 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 05af0f4..7d1a1bf 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -104,6 +104,14 @@

 &hdmi {
        compatible = "fsl,imx6dl-hdmi";
+       clocks = <&clks IMX6QDL_CLK_HDMI_IAHB>, <&clks IMX6QDL_CLK_HDMI_ISFR>,
+                <&clks IMX6QDL_CLK_IPU1_DI0_PRE_SEL>,
+                <&clks IMX6QDL_CLK_IPU1_DI1_PRE_SEL>,
+                <&clks IMX6QDL_CLK_IPU1_DI0_SEL>,
+                <&clks IMX6QDL_CLK_IPU1_DI1_SEL>;
+       clock-names = "iahb", "isfr",
+                     "di0_pre_sel", "di1_pre_sel",
+                     "di0_sel", "di1_sel";
 };

 &ldb {
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 9d1f88c..7d0a7bc 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -235,6 +235,18 @@

 &hdmi {
        compatible = "fsl,imx6q-hdmi";
+       clocks = <&clks IMX6QDL_CLK_HDMI_IAHB>, <&clks IMX6QDL_CLK_HDMI_ISFR>,
+                <&clks IMX6QDL_CLK_IPU1_DI0_PRE_SEL>,
+                <&clks IMX6QDL_CLK_IPU1_DI1_PRE_SEL>,
+                <&clks IMX6QDL_CLK_IPU2_DI0_PRE_SEL>,
+                <&clks IMX6QDL_CLK_IPU2_DI1_PRE_SEL>,
+                <&clks IMX6QDL_CLK_IPU1_DI0_SEL>,
+                <&clks IMX6QDL_CLK_IPU1_DI1_SEL>,
+                <&clks IMX6QDL_CLK_IPU2_DI0_SEL>,
+                <&clks IMX6QDL_CLK_IPU2_DI1_SEL>;
+       clock-names = "iahb", "isfr",
+                     "di0_pre_sel", "di1_pre_sel", "di2_pre_sel", 
"di3_pre_sel",
+                     "di0_sel", "di1_sel", "di2_sel", "di3_sel";

        port at 2 {
                reg = <2>;
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 13d6b50..4e3a3e8 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -810,9 +810,6 @@
                                reg = <0x00120000 0x9000>;
                                interrupts = <0 115 0x04>;
                                gpr = <&gpr>;
-                               clocks = <&clks IMX6QDL_CLK_HDMI_IAHB>,
-                                        <&clks IMX6QDL_CLK_HDMI_ISFR>;
-                               clock-names = "iahb", "isfr";
                                status = "disabled";

                                port at 0 {
diff --git a/drivers/staging/imx-drm/imx-hdmi.c 
b/drivers/staging/imx-drm/imx-hdmi.c
index 4ef1c0a..d97fa18 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -118,6 +118,8 @@ struct imx_hdmi {
        struct device *dev;
        struct clk *isfr_clk;
        struct clk *iahb_clk;
+       struct clk *di_pre_sel[4];
+       struct clk *di_sel[4];

        struct hdmi_data_info hdmi_data;
        int vic;
@@ -1452,8 +1454,13 @@ static void imx_hdmi_encoder_dpms(struct drm_encoder 
*encoder, int mode)
 static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
 {
        struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+       int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);

        imx_hdmi_poweroff(hdmi);
+
+       /* set DI clock mux to DI pre clock mux */
+       clk_set_parent(hdmi->di_sel[mux], hdmi->di_pre_sel[mux]);
+
        imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24, NULL);
 }

@@ -1593,7 +1600,7 @@ static int imx_hdmi_bind(struct device *dev, struct 
device *master, void *data)
        struct device_node *ddc_node;
        struct imx_hdmi *hdmi;
        struct resource *iores;
-       int ret;
+       int i, ret;

        hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
        if (!hdmi)
@@ -1629,6 +1636,29 @@ static int imx_hdmi_bind(struct device *dev, struct 
device *master, void *data)
        if (IS_ERR(hdmi->regmap))
                return PTR_ERR(hdmi->regmap);

+       for (i = 0; i < 4; i++) {
+               char clkname[16];
+
+               sprintf(clkname, "di%d_pre_sel", i);
+               hdmi->di_pre_sel[i] = devm_clk_get(hdmi->dev, clkname);
+               if (IS_ERR(hdmi->di_pre_sel[i])) {
+                       ret = PTR_ERR(hdmi->di_pre_sel[i]);
+                       hdmi->di_pre_sel[i] = NULL;
+                       break;
+               }
+
+               sprintf(clkname, "di%d_sel", i);
+               hdmi->di_sel[i] = devm_clk_get(hdmi->dev, clkname);
+               if (IS_ERR(hdmi->di_sel[i])) {
+                       ret = PTR_ERR(hdmi->di_sel[i]);
+                       hdmi->di_pre_sel[i] = NULL;
+                       hdmi->di_sel[i] = NULL;
+                       break;
+               }
+       }
+       if (i == 0)
+               return ret;
+
        hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
        if (IS_ERR(hdmi->isfr_clk)) {
                ret = PTR_ERR(hdmi->isfr_clk);
-- 
1.7.9.5

Reply via email to