[U-Boot,v2,3/7] sunxi: video: Convert lcdc to use struct display_timing

Message ID 20170320220128.21535-4-jernej.skrabec@siol.net
State Superseded
Delegated to: Jagannadha Sutradharudu Teki
Headers show

Commit Message

Jernej Škrabec March 20, 2017, 10:01 p.m.
Video driver for older Allwinner SoCs uses cfb console framework which
in turn uses struct ctfb_res_modes to hold timing informations. However,
DM video framework uses different structure - struct display_timing.

It makes more sense to convert lcdc to use new timing structure because
all new drivers should use DM video framework and older drivers might be
rewritten to use new framework too.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
Changes in v2:
- new patch

 arch/arm/include/asm/arch-sunxi/lcdc.h |  6 ++--
 drivers/video/sunxi/lcdc.c             | 64 ++++++++++++++++------------------
 drivers/video/sunxi/sunxi_display.c    | 35 +++++++++++++++++--
 3 files changed, 67 insertions(+), 38 deletions(-)

Comments

Maxime Ripard March 21, 2017, 7:33 p.m. | #1
On Mon, Mar 20, 2017 at 11:01:24PM +0100, Jernej Skrabec wrote:
> Video driver for older Allwinner SoCs uses cfb console framework which
> in turn uses struct ctfb_res_modes to hold timing informations. However,
> DM video framework uses different structure - struct display_timing.
> 
> It makes more sense to convert lcdc to use new timing structure because
> all new drivers should use DM video framework and older drivers might be
> rewritten to use new framework too.
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Thanks!
Maxime
Simon Glass April 1, 2017, 4:20 a.m. | #2
On 20 March 2017 at 16:01, Jernej Skrabec <jernej.skrabec@siol.net> wrote:
> Video driver for older Allwinner SoCs uses cfb console framework which
> in turn uses struct ctfb_res_modes to hold timing informations. However,
> DM video framework uses different structure - struct display_timing.
>
> It makes more sense to convert lcdc to use new timing structure because
> all new drivers should use DM video framework and older drivers might be
> rewritten to use new framework too.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
> Changes in v2:
> - new patch
>
>  arch/arm/include/asm/arch-sunxi/lcdc.h |  6 ++--
>  drivers/video/sunxi/lcdc.c             | 64 ++++++++++++++++------------------
>  drivers/video/sunxi/sunxi_display.c    | 35 +++++++++++++++++--
>  3 files changed, 67 insertions(+), 38 deletions(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

Patch

diff --git a/arch/arm/include/asm/arch-sunxi/lcdc.h b/arch/arm/include/asm/arch-sunxi/lcdc.h
index e4c8c160ed..a751698b4f 100644
--- a/arch/arm/include/asm/arch-sunxi/lcdc.h
+++ b/arch/arm/include/asm/arch-sunxi/lcdc.h
@@ -10,7 +10,7 @@ 
 #ifndef _LCDC_H
 #define _LCDC_H
 
-struct ctfb_res_modes;
+#include <fdtdec.h>
 
 struct sunxi_lcdc_reg {
 	u32 ctrl;			/* 0x00 */
@@ -118,11 +118,11 @@  struct sunxi_lcdc_reg {
 void lcdc_init(struct sunxi_lcdc_reg * const lcdc);
 void lcdc_enable(struct sunxi_lcdc_reg * const lcdc, int depth);
 void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc,
-			 const struct ctfb_res_modes *mode,
+			 const struct display_timing *mode,
 			 int clk_div, bool for_ext_vga_dac,
 			 int depth, int dclk_phase);
 void lcdc_tcon1_mode_set(struct sunxi_lcdc_reg * const lcdc,
-			 const struct ctfb_res_modes *mode,
+			 const struct display_timing *mode,
 			 bool ext_hvsync, bool is_composite);
 
 #endif /* _LCDC_H */
diff --git a/drivers/video/sunxi/lcdc.c b/drivers/video/sunxi/lcdc.c
index caf1859b0d..8c8fb2e4ee 100644
--- a/drivers/video/sunxi/lcdc.c
+++ b/drivers/video/sunxi/lcdc.c
@@ -13,15 +13,13 @@ 
 #include <asm/arch/lcdc.h>
 #include <asm/io.h>
 
-#include "../videomodes.h"
-
-static int lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
+static int lcdc_get_clk_delay(const struct display_timing *mode, int tcon)
 {
 	int delay;
 
-	delay = mode->lower_margin + mode->vsync_len +
-		mode->upper_margin;
-	if (mode->vmode == FB_VMODE_INTERLACED)
+	delay = mode->vfront_porch.typ + mode->vsync_len.typ +
+		mode->vback_porch.typ;
+	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
 		delay /= 2;
 	if (tcon == 1)
 		delay -= 2;
@@ -70,7 +68,7 @@  void lcdc_enable(struct sunxi_lcdc_reg * const lcdc, int depth)
 }
 
 void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc,
-			 const struct ctfb_res_modes *mode,
+			 const struct display_timing *mode,
 			 int clk_div, bool for_ext_vga_dac,
 			 int depth, int dclk_phase)
 {
@@ -87,22 +85,22 @@  void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc,
 	writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
 	       SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
 
-	writel(SUNXI_LCDC_X(mode->xres) |
-	       SUNXI_LCDC_Y(mode->yres), &lcdc->tcon0_timing_active);
+	writel(SUNXI_LCDC_X(mode->hactive.typ) |
+	       SUNXI_LCDC_Y(mode->vactive.typ), &lcdc->tcon0_timing_active);
 
-	bp = mode->hsync_len + mode->left_margin;
-	total = mode->xres + mode->right_margin + bp;
+	bp = mode->hsync_len.typ + mode->hback_porch.typ;
+	total = mode->hactive.typ + mode->hfront_porch.typ + bp;
 	writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
 	       SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
 
-	bp = mode->vsync_len + mode->upper_margin;
-	total = mode->yres + mode->lower_margin + bp;
+	bp = mode->vsync_len.typ + mode->vback_porch.typ;
+	total = mode->vactive.typ + mode->vfront_porch.typ + bp;
 	writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
 	       SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
 
 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
-	writel(SUNXI_LCDC_X(mode->hsync_len) |
-	       SUNXI_LCDC_Y(mode->vsync_len), &lcdc->tcon0_timing_sync);
+	writel(SUNXI_LCDC_X(mode->hsync_len.typ) |
+	       SUNXI_LCDC_Y(mode->vsync_len.typ), &lcdc->tcon0_timing_sync);
 
 	writel(0, &lcdc->tcon0_hv_intf);
 	writel(0, &lcdc->tcon0_cpu_intf);
@@ -131,9 +129,9 @@  void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc,
 	}
 
 	val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(dclk_phase);
-	if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
+	if (mode->flags & DISPLAY_FLAGS_HSYNC_LOW)
 		val |= SUNXI_LCDC_TCON_HSYNC_MASK;
-	if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
+	if (mode->flags & DISPLAY_FLAGS_VSYNC_LOW)
 		val |= SUNXI_LCDC_TCON_VSYNC_MASK;
 
 #ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
@@ -146,7 +144,7 @@  void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc,
 }
 
 void lcdc_tcon1_mode_set(struct sunxi_lcdc_reg * const lcdc,
-			 const struct ctfb_res_modes *mode,
+			 const struct display_timing *mode,
 			 bool ext_hvsync, bool is_composite)
 {
 	int bp, clk_delay, total, val, yres;
@@ -157,40 +155,40 @@  void lcdc_tcon1_mode_set(struct sunxi_lcdc_reg * const lcdc,
 
 	clk_delay = lcdc_get_clk_delay(mode, 1);
 	writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
-	       ((mode->vmode == FB_VMODE_INTERLACED) ?
+	       ((mode->flags & DISPLAY_FLAGS_INTERLACED) ?
 			SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
 	       SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
 
-	yres = mode->yres;
-	if (mode->vmode == FB_VMODE_INTERLACED)
+	yres = mode->vactive.typ;
+	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
 		yres /= 2;
-	writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
+	writel(SUNXI_LCDC_X(mode->hactive.typ) | SUNXI_LCDC_Y(yres),
 	       &lcdc->tcon1_timing_source);
-	writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
+	writel(SUNXI_LCDC_X(mode->hactive.typ) | SUNXI_LCDC_Y(yres),
 	       &lcdc->tcon1_timing_scale);
-	writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
+	writel(SUNXI_LCDC_X(mode->hactive.typ) | SUNXI_LCDC_Y(yres),
 	       &lcdc->tcon1_timing_out);
 
-	bp = mode->hsync_len + mode->left_margin;
-	total = mode->xres + mode->right_margin + bp;
+	bp = mode->hsync_len.typ + mode->hback_porch.typ;
+	total = mode->hactive.typ + mode->hfront_porch.typ + bp;
 	writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
 	       SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
 
-	bp = mode->vsync_len + mode->upper_margin;
-	total = mode->yres + mode->lower_margin + bp;
-	if (mode->vmode == FB_VMODE_NONINTERLACED)
+	bp = mode->vsync_len.typ + mode->vback_porch.typ;
+	total = mode->vactive.typ + mode->vfront_porch.typ + bp;
+	if (!(mode->flags & DISPLAY_FLAGS_INTERLACED))
 		total *= 2;
 	writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
 	       SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
 
-	writel(SUNXI_LCDC_X(mode->hsync_len) |
-	       SUNXI_LCDC_Y(mode->vsync_len), &lcdc->tcon1_timing_sync);
+	writel(SUNXI_LCDC_X(mode->hsync_len.typ) |
+	       SUNXI_LCDC_Y(mode->vsync_len.typ), &lcdc->tcon1_timing_sync);
 
 	if (ext_hvsync) {
 		val = 0;
-		if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
+		if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
 			val |= SUNXI_LCDC_TCON_HSYNC_MASK;
-		if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
+		if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
 			val |= SUNXI_LCDC_TCON_VSYNC_MASK;
 		writel(val, &lcdc->tcon1_io_polarity);
 
diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c
index 48192ef87e..92c9d06054 100644
--- a/drivers/video/sunxi/sunxi_display.c
+++ b/drivers/video/sunxi/sunxi_display.c
@@ -721,12 +721,40 @@  static void sunxi_lcdc_backlight_enable(void)
 		gpio_direction_output(pin, PWM_ON);
 }
 
+static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
+					      struct display_timing *timing)
+{
+	timing->pixelclock.typ = mode->pixclock_khz * 1000;
+
+	timing->hactive.typ = mode->xres;
+	timing->hfront_porch.typ = mode->right_margin;
+	timing->hback_porch.typ = mode->left_margin;
+	timing->hsync_len.typ = mode->hsync_len;
+
+	timing->vactive.typ = mode->yres;
+	timing->vfront_porch.typ = mode->lower_margin;
+	timing->vback_porch.typ = mode->upper_margin;
+	timing->vsync_len.typ = mode->vsync_len;
+
+	if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
+		timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
+	else
+		timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
+	if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
+		timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
+	else
+		timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
+	if (mode->vmode == FB_VMODE_INTERLACED)
+		timing->flags |= DISPLAY_FLAGS_INTERLACED;
+}
+
 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
 				      bool for_ext_vga_dac)
 {
 	struct sunxi_lcdc_reg * const lcdc =
 		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
 	int clk_div, clk_double, pin;
+	struct display_timing timing;
 
 #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
 	for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
@@ -746,7 +774,8 @@  static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
 
 	sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
 
-	lcdc_tcon0_mode_set(lcdc, mode, clk_div, for_ext_vga_dac,
+	sunxi_ctfb_mode_to_display_timing(mode, &timing);
+	lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
 			    sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
 }
 
@@ -757,8 +786,10 @@  static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
 {
 	struct sunxi_lcdc_reg * const lcdc =
 		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
+	struct display_timing timing;
 
-	lcdc_tcon1_mode_set(lcdc, mode, use_portd_hvsync,
+	sunxi_ctfb_mode_to_display_timing(mode, &timing);
+	lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
 			    sunxi_is_composite());
 
 	if (use_portd_hvsync) {