[v2,01/10] video: stm32: stm32_ltdc: add bridge to display controller
diff mbox

Message ID 1520005451-23217-2-git-send-email-yannick.fertre@st.com
State New
Headers show

Commit Message

Yannick Fertre March 2, 2018, 3:44 p.m. UTC
Manage a bridge insert between the display controller & a panel.

Signed-off-by: yannick fertre <yannick.fertre@st.com>
---
 drivers/video/stm32/stm32_ltdc.c | 107 ++++++++++++++++++++++++++-------------
 1 file changed, 71 insertions(+), 36 deletions(-)

Comments

Patrice CHOTARD March 13, 2018, 8:44 a.m. UTC | #1
Hi Yannick

On 03/02/2018 04:44 PM, yannick fertre wrote:
> Manage a bridge insert between the display controller & a panel.

> 

> Signed-off-by: yannick fertre <yannick.fertre@st.com>

> ---

>   drivers/video/stm32/stm32_ltdc.c | 107 ++++++++++++++++++++++++++-------------

>   1 file changed, 71 insertions(+), 36 deletions(-)

> 

> diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c

> index e160c77..bd9c0de 100644

> --- a/drivers/video/stm32/stm32_ltdc.c

> +++ b/drivers/video/stm32/stm32_ltdc.c

> @@ -8,6 +8,7 @@

>   

>   #include <common.h>

>   #include <clk.h>

> +#include <display.h>

>   #include <dm.h>

>   #include <panel.h>

>   #include <reset.h>

> @@ -15,12 +16,12 @@

>   #include <asm/io.h>

>   #include <asm/arch/gpio.h>

>   #include <dm/device-internal.h>

> +#include <video_bridge.h>

>   

>   DECLARE_GLOBAL_DATA_PTR;

>   

>   struct stm32_ltdc_priv {

>   	void __iomem *regs;

> -	struct display_timing timing;

>   	enum video_log2_bpp l2bpp;

>   	u32 bg_col_argb;

>   	u32 crop_x, crop_y, crop_w, crop_h;

> @@ -210,23 +211,23 @@ static void stm32_ltdc_enable(struct stm32_ltdc_priv *priv)

>   	setbits_le32(priv->regs + LTDC_GCR, GCR_LTDCEN);

>   }

>   

> -static void stm32_ltdc_set_mode(struct stm32_ltdc_priv *priv)

> +static void stm32_ltdc_set_mode(struct stm32_ltdc_priv *priv,

> +				struct display_timing *timings)

>   {

>   	void __iomem *regs = priv->regs;

> -	struct display_timing *timing = &priv->timing;

>   	u32 hsync, vsync, acc_hbp, acc_vbp, acc_act_w, acc_act_h;

>   	u32 total_w, total_h;

>   	u32 val;

>   

>   	/* Convert video timings to ltdc timings */

> -	hsync = timing->hsync_len.typ - 1;

> -	vsync = timing->vsync_len.typ - 1;

> -	acc_hbp = hsync + timing->hback_porch.typ;

> -	acc_vbp = vsync + timing->vback_porch.typ;

> -	acc_act_w = acc_hbp + timing->hactive.typ;

> -	acc_act_h = acc_vbp + timing->vactive.typ;

> -	total_w = acc_act_w + timing->hfront_porch.typ;

> -	total_h = acc_act_h + timing->vfront_porch.typ;

> +	hsync = timings->hsync_len.typ - 1;

> +	vsync = timings->vsync_len.typ - 1;

> +	acc_hbp = hsync + timings->hback_porch.typ;

> +	acc_vbp = vsync + timings->vback_porch.typ;

> +	acc_act_w = acc_hbp + timings->hactive.typ;

> +	acc_act_h = acc_vbp + timings->vactive.typ;

> +	total_w = acc_act_w + timings->hfront_porch.typ;

> +	total_h = acc_act_h + timings->vfront_porch.typ;

>   

>   	/* Synchronization sizes */

>   	val = (hsync << 16) | vsync;

> @@ -248,14 +249,14 @@ static void stm32_ltdc_set_mode(struct stm32_ltdc_priv *priv)

>   

>   	/* Signal polarities */

>   	val = 0;

> -	debug("%s: timing->flags 0x%08x\n", __func__, timing->flags);

> -	if (timing->flags & DISPLAY_FLAGS_HSYNC_HIGH)

> +	debug("%s: timing->flags 0x%08x\n", __func__, timings->flags);

> +	if (timings->flags & DISPLAY_FLAGS_HSYNC_HIGH)

>   		val |= GCR_HSPOL;

> -	if (timing->flags & DISPLAY_FLAGS_VSYNC_HIGH)

> +	if (timings->flags & DISPLAY_FLAGS_VSYNC_HIGH)

>   		val |= GCR_VSPOL;

> -	if (timing->flags & DISPLAY_FLAGS_DE_HIGH)

> +	if (timings->flags & DISPLAY_FLAGS_DE_HIGH)

>   		val |= GCR_DEPOL;

> -	if (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)

> +	if (timings->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)

>   		val |= GCR_PCPOL;

>   	clrsetbits_le32(regs + LTDC_GCR,

>   			GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val);

> @@ -331,7 +332,11 @@ static int stm32_ltdc_probe(struct udevice *dev)

>   	struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);

>   	struct video_priv *uc_priv = dev_get_uclass_priv(dev);

>   	struct stm32_ltdc_priv *priv = dev_get_priv(dev);

> -	struct udevice *panel;

> +#ifdef CONFIG_VIDEO_BRIDGE

> +	struct udevice *bridge = NULL;

> +#endif

> +	struct udevice *panel = NULL;

> +	struct display_timing timings;

>   	struct clk pclk;

>   	struct reset_ctl rst;

>   	int rate, ret;

> @@ -364,63 +369,93 @@ static int stm32_ltdc_probe(struct udevice *dev)

>   	/* Reset */

>   	reset_deassert(&rst);

>   

> -	ret = uclass_first_device(UCLASS_PANEL, &panel);

> +#ifdef CONFIG_VIDEO_BRIDGE

> +	ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge);

>   	if (ret) {

> -		debug("%s: panel device error %d\n", __func__, ret);

> -		return ret;

> +		debug("%s: No video bridge, or no backlight on bridge\n",

> +		      __func__);

>   	}

>   

> -	ret = panel_enable_backlight(panel);

> +	if (bridge) {

> +		ret = video_bridge_attach(bridge);

> +		if (ret) {

> +			debug("%s: fail to attach bridge\n", __func__);


I would replace debug by dev_err() here.

> +			return ret;

> +		}

> +	}

> +#endif

> +	ret = uclass_first_device(UCLASS_PANEL, &panel);

>   	if (ret) {

> -		debug("%s: panel %s enable backlight error %d\n",

> -		      __func__, panel->name, ret);

> +		debug("%s: panel device error %d\n", __func__, ret);


Ditto

>   		return ret;

>   	}

>   

> -	ret = fdtdec_decode_display_timing(gd->fdt_blob,

> -					   dev_of_offset(dev), 0,

> -					   &priv->timing);

> +	ret = fdtdec_decode_display_timing(gd->fdt_blob, dev_of_offset(panel),

> +					   0, &timings);

>   	if (ret) {

>   		debug("%s: decode display timing error %d\n",

>   		      __func__, ret);

> -		return -EINVAL;


Ditto

> +		return ret;

>   	}

>   

> -	rate = clk_set_rate(&pclk, priv->timing.pixelclock.typ);

> +	rate = clk_set_rate(&pclk, timings.pixelclock.typ);

>   	if (rate < 0) {

>   		debug("%s: fail to set pixel clock %d hz %d hz\n",

> -		      __func__, priv->timing.pixelclock.typ, rate);

> +		      __func__, timings.pixelclock.typ, rate);


Ditto

>   		return rate;

>   	}

>   

>   	debug("%s: Set pixel clock req %d hz get %d hz\n", __func__,

> -	      priv->timing.pixelclock.typ, rate);

> +	      timings.pixelclock.typ, rate);

>   

>   	/* TODO Below parameters are hard-coded for the moment... */

>   	priv->l2bpp = VIDEO_BPP16;

>   	priv->bg_col_argb = 0xFFFFFFFF; /* white no transparency */

>   	priv->crop_x = 0;

>   	priv->crop_y = 0;

> -	priv->crop_w = priv->timing.hactive.typ;

> -	priv->crop_h = priv->timing.vactive.typ;

> +	priv->crop_w = timings.hactive.typ;

> +	priv->crop_h = timings.vactive.typ;

>   	priv->alpha = 0xFF;

>   

>   	debug("%s: %dx%d %dbpp frame buffer at 0x%lx\n", __func__,

> -	      priv->timing.hactive.typ, priv->timing.vactive.typ,

> +	      timings.hactive.typ, timings.vactive.typ,

>   	      VNBITS(priv->l2bpp), uc_plat->base);

>   	debug("%s: crop %d,%d %dx%d bg 0x%08x alpha %d\n", __func__,

>   	      priv->crop_x, priv->crop_y, priv->crop_w, priv->crop_h,

>   	      priv->bg_col_argb, priv->alpha);

>   

>   	/* Configure & start LTDC */

> -	stm32_ltdc_set_mode(priv);

> +	stm32_ltdc_set_mode(priv, &timings);

>   	stm32_ltdc_set_layer1(priv, uc_plat->base);

>   	stm32_ltdc_enable(priv);

>   

> -	uc_priv->xsize = priv->timing.hactive.typ;

> -	uc_priv->ysize = priv->timing.vactive.typ;

> +	uc_priv->xsize = timings.hactive.typ;

> +	uc_priv->ysize = timings.vactive.typ;

>   	uc_priv->bpix = priv->l2bpp;

>   

> +#ifdef CONFIG_VIDEO_BRIDGE

> +	if (bridge) {

> +		ret = video_bridge_set_backlight(bridge, 80);

> +		if (ret) {

> +			debug("%s: fail to set backlight\n", __func__);


Ditto

> +			return ret;

> +		}

> +	} else {

> +		ret = panel_enable_backlight(panel);

> +		if (ret) {

> +			debug("%s: panel %s enable backlight error %d\n",

> +			      __func__, panel->name, ret);


Ditto

> +			return ret;

> +		}

> +	}

> +#else

> +	ret = panel_enable_backlight(panel);

> +	if (ret) {

> +		debug("%s: panel %s enable backlight error %d\n",

> +		      __func__, panel->name, ret);


Ditto

> +		return ret;

> +	}

> +#endif

>   	video_set_flush_dcache(dev, true);

>   

>   	return 0;

>

Patch
diff mbox

diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c
index e160c77..bd9c0de 100644
--- a/drivers/video/stm32/stm32_ltdc.c
+++ b/drivers/video/stm32/stm32_ltdc.c
@@ -8,6 +8,7 @@ 
 
 #include <common.h>
 #include <clk.h>
+#include <display.h>
 #include <dm.h>
 #include <panel.h>
 #include <reset.h>
@@ -15,12 +16,12 @@ 
 #include <asm/io.h>
 #include <asm/arch/gpio.h>
 #include <dm/device-internal.h>
+#include <video_bridge.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
 struct stm32_ltdc_priv {
 	void __iomem *regs;
-	struct display_timing timing;
 	enum video_log2_bpp l2bpp;
 	u32 bg_col_argb;
 	u32 crop_x, crop_y, crop_w, crop_h;
@@ -210,23 +211,23 @@  static void stm32_ltdc_enable(struct stm32_ltdc_priv *priv)
 	setbits_le32(priv->regs + LTDC_GCR, GCR_LTDCEN);
 }
 
-static void stm32_ltdc_set_mode(struct stm32_ltdc_priv *priv)
+static void stm32_ltdc_set_mode(struct stm32_ltdc_priv *priv,
+				struct display_timing *timings)
 {
 	void __iomem *regs = priv->regs;
-	struct display_timing *timing = &priv->timing;
 	u32 hsync, vsync, acc_hbp, acc_vbp, acc_act_w, acc_act_h;
 	u32 total_w, total_h;
 	u32 val;
 
 	/* Convert video timings to ltdc timings */
-	hsync = timing->hsync_len.typ - 1;
-	vsync = timing->vsync_len.typ - 1;
-	acc_hbp = hsync + timing->hback_porch.typ;
-	acc_vbp = vsync + timing->vback_porch.typ;
-	acc_act_w = acc_hbp + timing->hactive.typ;
-	acc_act_h = acc_vbp + timing->vactive.typ;
-	total_w = acc_act_w + timing->hfront_porch.typ;
-	total_h = acc_act_h + timing->vfront_porch.typ;
+	hsync = timings->hsync_len.typ - 1;
+	vsync = timings->vsync_len.typ - 1;
+	acc_hbp = hsync + timings->hback_porch.typ;
+	acc_vbp = vsync + timings->vback_porch.typ;
+	acc_act_w = acc_hbp + timings->hactive.typ;
+	acc_act_h = acc_vbp + timings->vactive.typ;
+	total_w = acc_act_w + timings->hfront_porch.typ;
+	total_h = acc_act_h + timings->vfront_porch.typ;
 
 	/* Synchronization sizes */
 	val = (hsync << 16) | vsync;
@@ -248,14 +249,14 @@  static void stm32_ltdc_set_mode(struct stm32_ltdc_priv *priv)
 
 	/* Signal polarities */
 	val = 0;
-	debug("%s: timing->flags 0x%08x\n", __func__, timing->flags);
-	if (timing->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+	debug("%s: timing->flags 0x%08x\n", __func__, timings->flags);
+	if (timings->flags & DISPLAY_FLAGS_HSYNC_HIGH)
 		val |= GCR_HSPOL;
-	if (timing->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+	if (timings->flags & DISPLAY_FLAGS_VSYNC_HIGH)
 		val |= GCR_VSPOL;
-	if (timing->flags & DISPLAY_FLAGS_DE_HIGH)
+	if (timings->flags & DISPLAY_FLAGS_DE_HIGH)
 		val |= GCR_DEPOL;
-	if (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+	if (timings->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
 		val |= GCR_PCPOL;
 	clrsetbits_le32(regs + LTDC_GCR,
 			GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val);
@@ -331,7 +332,11 @@  static int stm32_ltdc_probe(struct udevice *dev)
 	struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
 	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
 	struct stm32_ltdc_priv *priv = dev_get_priv(dev);
-	struct udevice *panel;
+#ifdef CONFIG_VIDEO_BRIDGE
+	struct udevice *bridge = NULL;
+#endif
+	struct udevice *panel = NULL;
+	struct display_timing timings;
 	struct clk pclk;
 	struct reset_ctl rst;
 	int rate, ret;
@@ -364,63 +369,93 @@  static int stm32_ltdc_probe(struct udevice *dev)
 	/* Reset */
 	reset_deassert(&rst);
 
-	ret = uclass_first_device(UCLASS_PANEL, &panel);
+#ifdef CONFIG_VIDEO_BRIDGE
+	ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge);
 	if (ret) {
-		debug("%s: panel device error %d\n", __func__, ret);
-		return ret;
+		debug("%s: No video bridge, or no backlight on bridge\n",
+		      __func__);
 	}
 
-	ret = panel_enable_backlight(panel);
+	if (bridge) {
+		ret = video_bridge_attach(bridge);
+		if (ret) {
+			debug("%s: fail to attach bridge\n", __func__);
+			return ret;
+		}
+	}
+#endif
+	ret = uclass_first_device(UCLASS_PANEL, &panel);
 	if (ret) {
-		debug("%s: panel %s enable backlight error %d\n",
-		      __func__, panel->name, ret);
+		debug("%s: panel device error %d\n", __func__, ret);
 		return ret;
 	}
 
-	ret = fdtdec_decode_display_timing(gd->fdt_blob,
-					   dev_of_offset(dev), 0,
-					   &priv->timing);
+	ret = fdtdec_decode_display_timing(gd->fdt_blob, dev_of_offset(panel),
+					   0, &timings);
 	if (ret) {
 		debug("%s: decode display timing error %d\n",
 		      __func__, ret);
-		return -EINVAL;
+		return ret;
 	}
 
-	rate = clk_set_rate(&pclk, priv->timing.pixelclock.typ);
+	rate = clk_set_rate(&pclk, timings.pixelclock.typ);
 	if (rate < 0) {
 		debug("%s: fail to set pixel clock %d hz %d hz\n",
-		      __func__, priv->timing.pixelclock.typ, rate);
+		      __func__, timings.pixelclock.typ, rate);
 		return rate;
 	}
 
 	debug("%s: Set pixel clock req %d hz get %d hz\n", __func__,
-	      priv->timing.pixelclock.typ, rate);
+	      timings.pixelclock.typ, rate);
 
 	/* TODO Below parameters are hard-coded for the moment... */
 	priv->l2bpp = VIDEO_BPP16;
 	priv->bg_col_argb = 0xFFFFFFFF; /* white no transparency */
 	priv->crop_x = 0;
 	priv->crop_y = 0;
-	priv->crop_w = priv->timing.hactive.typ;
-	priv->crop_h = priv->timing.vactive.typ;
+	priv->crop_w = timings.hactive.typ;
+	priv->crop_h = timings.vactive.typ;
 	priv->alpha = 0xFF;
 
 	debug("%s: %dx%d %dbpp frame buffer at 0x%lx\n", __func__,
-	      priv->timing.hactive.typ, priv->timing.vactive.typ,
+	      timings.hactive.typ, timings.vactive.typ,
 	      VNBITS(priv->l2bpp), uc_plat->base);
 	debug("%s: crop %d,%d %dx%d bg 0x%08x alpha %d\n", __func__,
 	      priv->crop_x, priv->crop_y, priv->crop_w, priv->crop_h,
 	      priv->bg_col_argb, priv->alpha);
 
 	/* Configure & start LTDC */
-	stm32_ltdc_set_mode(priv);
+	stm32_ltdc_set_mode(priv, &timings);
 	stm32_ltdc_set_layer1(priv, uc_plat->base);
 	stm32_ltdc_enable(priv);
 
-	uc_priv->xsize = priv->timing.hactive.typ;
-	uc_priv->ysize = priv->timing.vactive.typ;
+	uc_priv->xsize = timings.hactive.typ;
+	uc_priv->ysize = timings.vactive.typ;
 	uc_priv->bpix = priv->l2bpp;
 
+#ifdef CONFIG_VIDEO_BRIDGE
+	if (bridge) {
+		ret = video_bridge_set_backlight(bridge, 80);
+		if (ret) {
+			debug("%s: fail to set backlight\n", __func__);
+			return ret;
+		}
+	} else {
+		ret = panel_enable_backlight(panel);
+		if (ret) {
+			debug("%s: panel %s enable backlight error %d\n",
+			      __func__, panel->name, ret);
+			return ret;
+		}
+	}
+#else
+	ret = panel_enable_backlight(panel);
+	if (ret) {
+		debug("%s: panel %s enable backlight error %d\n",
+		      __func__, panel->name, ret);
+		return ret;
+	}
+#endif
 	video_set_flush_dcache(dev, true);
 
 	return 0;