s3c-fb: add support for DMA channel control on S5PV210
[deliverable/linux.git] / drivers / video / s3c-fb.c
index 6cbddc445f03126c72458a478df357eb27c064c3..8ea974dd92c51f7826d52a6175dfb74882d719bf 100644 (file)
@@ -79,6 +79,7 @@ struct s3c_fb;
  * @osd: The base for the OSD registers.
  * @palette: Address of palette memory, or 0 if none.
  * @has_prtcon: Set if has PRTCON register.
+ * @has_shadowcon: Set if has SHADOWCON register.
  */
 struct s3c_fb_variant {
        unsigned int    is_2443:1;
@@ -95,14 +96,18 @@ struct s3c_fb_variant {
        unsigned short  palette[S3C_FB_MAX_WIN];
 
        unsigned int    has_prtcon:1;
+       unsigned int    has_shadowcon:1;
 };
 
 /**
  * struct s3c_fb_win_variant
  * @has_osd_c: Set if has OSD C register.
  * @has_osd_d: Set if has OSD D register.
+ * @has_osd_alpha: Set if can change alpha transparency for a window.
  * @palette_sz: Size of palette in entries.
  * @palette_16bpp: Set if palette is 16bits wide.
+ * @osd_size_off: If != 0, supports setting up OSD for a window; the appropriate
+ *                register is located at the given offset from OSD_BASE.
  * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel.
  *
  * valid_bpp bit x is set if (x+1)BPP is supported.
@@ -110,7 +115,9 @@ struct s3c_fb_variant {
 struct s3c_fb_win_variant {
        unsigned int    has_osd_c:1;
        unsigned int    has_osd_d:1;
+       unsigned int    has_osd_alpha:1;
        unsigned int    palette_16bpp:1;
+       unsigned short  osd_size_off;
        unsigned short  palette_sz;
        u32             valid_bpp;
 };
@@ -362,6 +369,66 @@ static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
        return ALIGN(pix, pix_per_word);
 }
 
+/**
+ * vidosd_set_size() - set OSD size for a window
+ *
+ * @win: the window to set OSD size for
+ * @size: OSD size register value
+ */
+static void vidosd_set_size(struct s3c_fb_win *win, u32 size)
+{
+       struct s3c_fb *sfb = win->parent;
+
+       /* OSD can be set up if osd_size_off != 0 for this window */
+       if (win->variant.osd_size_off)
+               writel(size, sfb->regs + OSD_BASE(win->index, sfb->variant)
+                               + win->variant.osd_size_off);
+}
+
+/**
+ * vidosd_set_alpha() - set alpha transparency for a window
+ *
+ * @win: the window to set OSD size for
+ * @alpha: alpha register value
+ */
+static void vidosd_set_alpha(struct s3c_fb_win *win, u32 alpha)
+{
+       struct s3c_fb *sfb = win->parent;
+
+       if (win->variant.has_osd_alpha)
+               writel(alpha, sfb->regs + VIDOSD_C(win->index, sfb->variant));
+}
+
+/**
+ * shadow_protect_win() - disable updating values from shadow registers at vsync
+ *
+ * @win: window to protect registers for
+ * @protect: 1 to protect (disable updates)
+ */
+static void shadow_protect_win(struct s3c_fb_win *win, bool protect)
+{
+       struct s3c_fb *sfb = win->parent;
+       u32 reg;
+
+       if (protect) {
+               if (sfb->variant.has_prtcon) {
+                       writel(PRTCON_PROTECT, sfb->regs + PRTCON);
+               } else if (sfb->variant.has_shadowcon) {
+                       reg = readl(sfb->regs + SHADOWCON);
+                       writel(reg | SHADOWCON_WINx_PROTECT(win->index),
+                               sfb->regs + SHADOWCON);
+               }
+       } else {
+               if (sfb->variant.has_prtcon) {
+                       writel(0, sfb->regs + PRTCON);
+               } else if (sfb->variant.has_shadowcon) {
+                       reg = readl(sfb->regs + SHADOWCON);
+                       writel(reg & ~SHADOWCON_WINx_PROTECT(win->index),
+                               sfb->regs + SHADOWCON);
+               }
+       }
+}
+
 /**
  * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
  * @info: The framebuffer to change.
@@ -376,13 +443,15 @@ static int s3c_fb_set_par(struct fb_info *info)
        void __iomem *regs = sfb->regs;
        void __iomem *buf = regs;
        int win_no = win->index;
-       u32 osdc_data = 0;
+       u32 alpha = 0;
        u32 data;
        u32 pagewidth;
        int clkdiv;
 
        dev_dbg(sfb->dev, "setting framebuffer parameters\n");
 
+       shadow_protect_win(win, 1);
+
        switch (var->bits_per_pixel) {
        case 32:
        case 24:
@@ -479,15 +548,12 @@ static int s3c_fb_set_par(struct fb_info *info)
 
        data = var->xres * var->yres;
 
-       osdc_data = VIDISD14C_ALPHA1_R(0xf) |
+       alpha = VIDISD14C_ALPHA1_R(0xf) |
                VIDISD14C_ALPHA1_G(0xf) |
                VIDISD14C_ALPHA1_B(0xf);
 
-       if (win->variant.has_osd_d) {
-               writel(data, regs + VIDOSD_D(win_no, sfb->variant));
-               writel(osdc_data, regs + VIDOSD_C(win_no, sfb->variant));
-       } else
-               writel(data, regs + VIDOSD_C(win_no, sfb->variant));
+       vidosd_set_alpha(win, alpha);
+       vidosd_set_size(win, data);
 
        data = WINCONx_ENWIN;
 
@@ -568,6 +634,15 @@ static int s3c_fb_set_par(struct fb_info *info)
        writel(data, regs + sfb->variant.wincon + (win_no * 4));
        writel(0x0, regs + sfb->variant.winmap + (win_no * 4));
 
+       /* Enable DMA channel for this window */
+       if (sfb->variant.has_shadowcon) {
+               data = readl(sfb->regs + SHADOWCON);
+               data |= SHADOWCON_CHx_ENABLE(win_no);
+               writel(data, sfb->regs + SHADOWCON);
+       }
+
+       shadow_protect_win(win, 0);
+
        return 0;
 }
 
@@ -810,14 +885,12 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
 
        /* Temporarily turn off per-vsync update from shadow registers until
         * both start and end addresses are updated to prevent corruption */
-       if (sfb->variant.has_prtcon)
-               writel(PRTCON_PROTECT, sfb->regs + PRTCON);
+       shadow_protect_win(win, 1);
 
        writel(info->fix.smem_start + start_boff, buf + sfb->variant.buf_start);
        writel(info->fix.smem_start + end_boff, buf + sfb->variant.buf_end);
 
-       if (sfb->variant.has_prtcon)
-               writel(0, sfb->regs + PRTCON);
+       shadow_protect_win(win, 0);
 
        return 0;
 }
@@ -1025,7 +1098,15 @@ static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
  */
 static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
 {
+       u32 data;
+
        if (win->fbinfo) {
+               if (sfb->variant.has_shadowcon) {
+                       data = readl(sfb->regs + SHADOWCON);
+                       data &= ~SHADOWCON_CHx_ENABLE(win->index);
+                       data &= ~SHADOWCON_CHx_LOCAL_ENABLE(win->index);
+                       writel(data, sfb->regs + SHADOWCON);
+               }
                unregister_framebuffer(win->fbinfo);
                if (win->fbinfo->cmap.len)
                        fb_dealloc_cmap(&win->fbinfo->cmap);
@@ -1166,11 +1247,14 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
 static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
 {
        void __iomem *regs = sfb->regs;
+       u32 reg;
 
        writel(0, regs + sfb->variant.wincon + (win * 4));
        writel(0, regs + VIDOSD_A(win, sfb->variant));
        writel(0, regs + VIDOSD_B(win, sfb->variant));
        writel(0, regs + VIDOSD_C(win, sfb->variant));
+       reg = readl(regs + SHADOWCON);
+       writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON);
 }
 
 static int __devinit s3c_fb_probe(struct platform_device *pdev)
@@ -1409,15 +1493,18 @@ static int s3c_fb_resume(struct platform_device *pdev)
 #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
 #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
 
-static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] __devinitdata = {
+static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
        [0] = {
                .has_osd_c      = 1,
+               .osd_size_off   = 0x8,
                .palette_sz     = 256,
                .valid_bpp      = VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
        },
        [1] = {
                .has_osd_c      = 1,
                .has_osd_d      = 1,
+               .osd_size_off   = 0x12,
+               .has_osd_alpha  = 1,
                .palette_sz     = 256,
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
                                   VALID_BPP(18) | VALID_BPP(19) |
@@ -1426,6 +1513,8 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] __devinitdata = {
        [2] = {
                .has_osd_c      = 1,
                .has_osd_d      = 1,
+               .osd_size_off   = 0x12,
+               .has_osd_alpha  = 1,
                .palette_sz     = 16,
                .palette_16bpp  = 1,
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
@@ -1434,6 +1523,7 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] __devinitdata = {
        },
        [3] = {
                .has_osd_c      = 1,
+               .has_osd_alpha  = 1,
                .palette_sz     = 16,
                .palette_16bpp  = 1,
                .valid_bpp      = (VALID_BPP124  | VALID_BPP(16) |
@@ -1442,6 +1532,7 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] __devinitdata = {
        },
        [4] = {
                .has_osd_c      = 1,
+               .has_osd_alpha  = 1,
                .palette_sz     = 4,
                .palette_16bpp  = 1,
                .valid_bpp      = (VALID_BPP(1) | VALID_BPP(2) |
@@ -1450,7 +1541,7 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] __devinitdata = {
        },
 };
 
-static struct s3c_fb_driverdata s3c_fb_data_64xx __devinitdata = {
+static struct s3c_fb_driverdata s3c_fb_data_64xx = {
        .variant = {
                .nr_windows     = 5,
                .vidtcon        = VIDTCON0,
@@ -1480,7 +1571,7 @@ static struct s3c_fb_driverdata s3c_fb_data_64xx __devinitdata = {
        .win[4] = &s3c_fb_data_64xx_wins[4],
 };
 
-static struct s3c_fb_driverdata s3c_fb_data_s5pc100 __devinitdata = {
+static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
        .variant = {
                .nr_windows     = 5,
                .vidtcon        = VIDTCON0,
@@ -1510,7 +1601,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 __devinitdata = {
        .win[4] = &s3c_fb_data_64xx_wins[4],
 };
 
-static struct s3c_fb_driverdata s3c_fb_data_s5pv210 __devinitdata = {
+static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
        .variant = {
                .nr_windows     = 5,
                .vidtcon        = VIDTCON0,
@@ -1530,6 +1621,8 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 __devinitdata = {
                        [3] = 0x3000,
                        [4] = 0x3400,
                },
+
+               .has_shadowcon  = 1,
        },
        .win[0] = &s3c_fb_data_64xx_wins[0],
        .win[1] = &s3c_fb_data_64xx_wins[1],
@@ -1539,7 +1632,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 __devinitdata = {
 };
 
 /* S3C2443/S3C2416 style hardware */
-static struct s3c_fb_driverdata s3c_fb_data_s3c2443 __devinitdata = {
+static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
        .variant = {
                .nr_windows     = 2,
                .is_2443        = 1,
@@ -1565,6 +1658,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s3c2443 __devinitdata = {
        },
        .win[1] = &(struct s3c_fb_win_variant) {
                .has_osd_c      = 1,
+               .has_osd_alpha  = 1,
                .palette_sz     = 256,
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
                                   VALID_BPP(18) | VALID_BPP(19) |
This page took 0.02896 seconds and 5 git commands to generate.