diff mbox

[59/72] imx-drm: hdmi: set DI clock source to DI pre clock

Message ID 1414796095-10107-60-git-send-email-steve_longerbeam@mentor.com (mailing list archive)
State New, archived
Headers show

Commit Message

Steve Longerbeam Oct. 31, 2014, 10:54 p.m. UTC
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@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@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 mbox

Patch

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@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@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);