sunxi: display: Add support for interlaced modes
authorHans de Goede <hdegoede@redhat.com>
Sun, 2 Aug 2015 14:49:29 +0000 (16:49 +0200)
committerLothar Waßmann <LW@KARO-electronics.de>
Thu, 10 Sep 2015 06:17:39 +0000 (08:17 +0200)
Add support for interlaced modes, this is a preparation patch for adding
composite out support.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Ian Campbell <ijc@hellion.org.uk>
drivers/video/sunxi_display.c

index 74a4280..f3cc06e 100644 (file)
@@ -445,6 +445,10 @@ static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
        writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
 
        setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
+       if (mode->vmode == FB_VMODE_INTERLACED)
+               setbits_le32(&de_be->mode,
+                            SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
+                            SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
 }
 
 static void sunxi_composer_enable(void)
@@ -668,6 +672,8 @@ static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
        int delay;
 
        delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
+       if (mode->vmode == FB_VMODE_INTERLACED)
+               delay /= 2;
        if (tcon == 1)
                delay -= 2;
 
@@ -767,7 +773,7 @@ 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;
-       int bp, clk_delay, total, val;
+       int bp, clk_delay, total, val, yres;
 
        /* Use tcon1 */
        clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
@@ -775,13 +781,18 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
 
        clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
        writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
+              ((mode->vmode == FB_VMODE_INTERLACED) ?
+                       SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
               SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
 
-       writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+       yres = mode->yres;
+       if (mode->vmode == FB_VMODE_INTERLACED)
+               yres /= 2;
+       writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
               &lcdc->tcon1_timing_source);
-       writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+       writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
               &lcdc->tcon1_timing_scale);
-       writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+       writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
               &lcdc->tcon1_timing_out);
 
        bp = mode->hsync_len + mode->left_margin;
@@ -791,7 +802,9 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
 
        bp = mode->vsync_len + mode->upper_margin;
        total = mode->yres + mode->lower_margin + bp;
-       writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(2 * total) |
+       if (mode->vmode == FB_VMODE_NONINTERLACED)
+               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),
@@ -1223,14 +1236,6 @@ void *video_hw_init(void)
                break;
        }
 
-       if (mode->vmode != FB_VMODE_NONINTERLACED) {
-               printf("Only non-interlaced modes supported, falling back to 1024x768\n");
-               mode = &res_mode_init[RES_MODE_1024x768];
-       } else {
-               printf("Setting up a %dx%d %s console\n", mode->xres,
-                      mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
-       }
-
        sunxi_display.fb_size =
                (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
        if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
@@ -1240,6 +1245,10 @@ void *video_hw_init(void)
                return NULL;
        }
 
+       printf("Setting up a %dx%d%s %s console\n", mode->xres, mode->yres,
+              (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
+              sunxi_get_mon_desc(sunxi_display.monitor));
+
        gd->fb_base = gd->bd->bi_dram[0].start +
                      gd->bd->bi_dram[0].size - sunxi_display.fb_size;
        sunxi_engines_init();