video: tegra: YUV overlay support
authorAri Hirvonen <ahirvonen@nvidia.com>
Wed, 17 Nov 2010 12:17:40 +0000 (14:17 +0200)
committerErik Gilling <konkers@android.com>
Fri, 19 Nov 2010 00:06:46 +0000 (16:06 -0800)
Change-Id: I4bed4d37bc275cca9ef69390c217498529121db0
Signed-off-by: Erik Gilling <konkers@android.com>
arch/arm/mach-tegra/include/mach/dc.h
drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/dc_reg.h
drivers/video/tegra/fb.c
include/video/tegrafb.h

index 7b674220c3eeaf8215a5dfdaaf6a12fda1f04ee7..77a9f15bc0bf696d72a53b6a1e07ae795c38da81 100644 (file)
@@ -86,7 +86,10 @@ struct tegra_dc_win {
 
        void                    *virt_addr;
        dma_addr_t              phys_addr;
+       unsigned                offset_u;
+       unsigned                offset_v;
        unsigned                stride;
+       unsigned                stride_uv;
        unsigned                x;
        unsigned                y;
        unsigned                w;
index 1c54da6672a51844c893a712d13198726438ea00..f7875e91ddf54e591656216d4f56120b94d6e092 100644 (file)
@@ -75,12 +75,15 @@ static inline int tegra_dc_fmt_bpp(int fmt)
        case TEGRA_WIN_FMT_R6x2G6x2B6x2A8:
                return 32;
 
-       case TEGRA_WIN_FMT_YCbCr422:
-       case TEGRA_WIN_FMT_YUV422:
+       /* for planar formats, size of the Y plane, 8bit */
        case TEGRA_WIN_FMT_YCbCr420P:
        case TEGRA_WIN_FMT_YUV420P:
        case TEGRA_WIN_FMT_YCbCr422P:
        case TEGRA_WIN_FMT_YUV422P:
+               return 8;
+
+       case TEGRA_WIN_FMT_YCbCr422:
+       case TEGRA_WIN_FMT_YUV422:
        case TEGRA_WIN_FMT_YCbCr422R:
        case TEGRA_WIN_FMT_YUV422R:
        case TEGRA_WIN_FMT_YCbCr422RA:
@@ -91,6 +94,18 @@ static inline int tegra_dc_fmt_bpp(int fmt)
        return 0;
 }
 
+static inline int tegra_dc_is_yuv_planar(int fmt)
+{
+       switch (fmt) {
+       case TEGRA_WIN_FMT_YUV420P:
+       case TEGRA_WIN_FMT_YCbCr420P:
+       case TEGRA_WIN_FMT_YCbCr422P:
+       case TEGRA_WIN_FMT_YUV422P:
+               return 1;
+       }
+       return 0;
+}
+
 #define DUMP_REG(a) do {                       \
        snprintf(buff, sizeof(buff), "%-32s\t%03x\t%08lx\n", \
                 #a, a, tegra_dc_readl(dc, a));               \
@@ -219,15 +234,26 @@ static void _dump_regs(struct tegra_dc *dc, void *data,
                DUMP_REG(DC_WIN_DDA_INCREMENT);
                DUMP_REG(DC_WIN_LINE_STRIDE);
                DUMP_REG(DC_WIN_BUF_STRIDE);
+               DUMP_REG(DC_WIN_UV_BUF_STRIDE);
                DUMP_REG(DC_WIN_BLEND_NOKEY);
                DUMP_REG(DC_WIN_BLEND_1WIN);
                DUMP_REG(DC_WIN_BLEND_2WIN_X);
                DUMP_REG(DC_WIN_BLEND_2WIN_Y);
                DUMP_REG(DC_WIN_BLEND_3WIN_XY);
                DUMP_REG(DC_WINBUF_START_ADDR);
+               DUMP_REG(DC_WINBUF_START_ADDR_U);
+               DUMP_REG(DC_WINBUF_START_ADDR_V);
                DUMP_REG(DC_WINBUF_ADDR_H_OFFSET);
                DUMP_REG(DC_WINBUF_ADDR_V_OFFSET);
                DUMP_REG(DC_WINBUF_UFLOW_STATUS);
+               DUMP_REG(DC_WIN_CSC_YOF);
+               DUMP_REG(DC_WIN_CSC_KYRGB);
+               DUMP_REG(DC_WIN_CSC_KUR);
+               DUMP_REG(DC_WIN_CSC_KVR);
+               DUMP_REG(DC_WIN_CSC_KUG);
+               DUMP_REG(DC_WIN_CSC_KVG);
+               DUMP_REG(DC_WIN_CSC_KUB);
+               DUMP_REG(DC_WIN_CSC_KVB);
        }
 
        tegra_dc_io_end(dc);
@@ -414,6 +440,35 @@ static void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *bl
        }
 }
 
+static void tegra_dc_set_csc(struct tegra_dc *dc)
+{
+       tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF);
+       tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB);
+       tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR);
+       tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR);
+       tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG);
+       tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG);
+       tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB);
+       tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB);
+}
+
+static void tegra_dc_set_scaling_filter(struct tegra_dc *dc)
+{
+       unsigned i;
+       unsigned v0 = 128;
+       unsigned v1 = 0;
+       /* linear horizontal and vertical filters */
+       for (i = 0; i < 16; i++) {
+               tegra_dc_writel(dc, (v1 << 16) | (v0 << 8),
+                               DC_WIN_H_FILTER_P(i));
+
+               tegra_dc_writel(dc, v0,
+                               DC_WIN_V_FILTER_P(i));
+               v0 -= 8;
+               v1 += 8;
+       }
+}
+
 /* does not support updating windows on multiple dcs in one call */
 int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
 {
@@ -441,6 +496,7 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
                struct tegra_dc_win *win = windows[i];
                unsigned h_dda;
                unsigned v_dda;
+               int yuvp = tegra_dc_is_yuv_planar(win->fmt);
 
                if (win->z != dc->blend.z[win->idx]) {
                        dc->blend.z[win->idx] = win->z;
@@ -467,10 +523,6 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
                tegra_dc_writel(dc, win->fmt, DC_WIN_COLOR_DEPTH);
                tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP);
 
-               /* TODO: implement filter on settings */
-               h_dda = (win->w * 0x1000) / max_t(int, win->out_w - 1, 1);
-               v_dda = (win->h * 0x1000) / max_t(int, win->out_h - 1, 1);
-
                tegra_dc_writel(dc,
                                V_POSITION(win->out_y) | H_POSITION(win->out_x),
                                DC_WIN_POSITION);
@@ -479,24 +531,53 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
                                DC_WIN_SIZE);
                tegra_dc_writel(dc,
                                V_PRESCALED_SIZE(win->h) |
-                               H_PRESCALED_SIZE(win->w*tegra_dc_fmt_bpp(win->fmt)/8),
+                               H_PRESCALED_SIZE(win->w * tegra_dc_fmt_bpp(win->fmt) / 8),
                                DC_WIN_PRESCALED_SIZE);
-               tegra_dc_writel(dc, 0, DC_WIN_H_INITIAL_DDA);
-               tegra_dc_writel(dc, 0, DC_WIN_V_INITIAL_DDA);
+
+               h_dda = ((win->w - 1) * 0x1000) / max_t(int, win->out_w - 1, 1);
+               v_dda = ((win->h - 1) * 0x1000) / max_t(int, win->out_h - 1, 1);
                tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
                                DC_WIN_DDA_INCREMENT);
-               tegra_dc_writel(dc, win->stride, DC_WIN_LINE_STRIDE);
-               tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
-
+               tegra_dc_writel(dc, 0, DC_WIN_H_INITIAL_DDA);
+               tegra_dc_writel(dc, 0, DC_WIN_V_INITIAL_DDA);
 
+               tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
+               tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
                tegra_dc_writel(dc, (unsigned long)win->phys_addr,
                                DC_WINBUF_START_ADDR);
-               tegra_dc_writel(dc, win->x, DC_WINBUF_ADDR_H_OFFSET);
+
+               if (!yuvp) {
+                       tegra_dc_writel(dc, win->stride, DC_WIN_LINE_STRIDE);
+               } else {
+                       tegra_dc_writel(dc,
+                                       (unsigned long)win->phys_addr +
+                                       (unsigned long)win->offset_u,
+                                       DC_WINBUF_START_ADDR_U);
+                       tegra_dc_writel(dc,
+                                       (unsigned long)win->phys_addr +
+                                       (unsigned long)win->offset_v,
+                                       DC_WINBUF_START_ADDR_V);
+                       tegra_dc_writel(dc,
+                                       LINE_STRIDE(win->stride) |
+                                       UV_LINE_STRIDE(win->stride_uv),
+                                       DC_WIN_LINE_STRIDE);
+               }
+
+               tegra_dc_writel(dc, win->x * tegra_dc_fmt_bpp(win->fmt) / 8,
+                               DC_WINBUF_ADDR_H_OFFSET);
                tegra_dc_writel(dc, win->y, DC_WINBUF_ADDR_V_OFFSET);
 
                val = WIN_ENABLE;
-               if (tegra_dc_fmt_bpp(win->fmt) < 24)
+               if (yuvp)
+                       val |= CSC_ENABLE;
+               else if (tegra_dc_fmt_bpp(win->fmt) < 24)
                        val |= COLOR_EXPAND;
+
+               if (win->w != win->out_w)
+                       val |= H_FILTER_ENABLE;
+               if (win->h != win->out_h)
+                       val |= V_FILTER_ENABLE;
+
                tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
 
                win->dirty = no_vsync ? 0 : 1;
@@ -812,6 +893,7 @@ static void tegra_dc_init(struct tegra_dc *dc)
 {
        u32 disp_syncpt;
        u32 vblank_syncpt;
+       int i;
 
        tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
        if (dc->ndev->id == 0) {
@@ -855,6 +937,13 @@ static void tegra_dc_init(struct tegra_dc *dc)
        tegra_dc_writel(dc, 0x00000000, DC_DISP_BORDER_COLOR);
 
        tegra_dc_set_color_control(dc);
+       for (i = 0; i < DC_N_WINDOWS; i++) {
+               tegra_dc_writel(dc, WINDOW_A_SELECT << i,
+                               DC_CMD_DISPLAY_WINDOW_HEADER);
+               tegra_dc_set_csc(dc);
+               tegra_dc_set_scaling_filter(dc);
+       }
+
 
        dc->syncpt_id = disp_syncpt;
 
index 360eda69e0dd54d6078502b39e65e8a587fa2e6a..5ae3cc4c1dec5ba3ab057cbe06967ade5577f4f9 100644 (file)
 #define DC_DISP_DAC_CRT_CTRL                   0x4c0
 #define DC_DISP_DISP_MISC_CONTROL              0x4c1
 
-#define DC_WINC_COLOR_PALETTE(x)               (0x500 + (x))
-
-#define DC_WINC_PALETTE_COLOR_EXT              0x600
-#define DC_WINC_H_FILTER_P(x)                  (0x601 + (x))
-#define DC_WINC_CSC_YOF                                0x611
-#define DC_WINC_CSC_KYRGB                      0x612
-#define DC_WINC_CSC_KUR                                0x613
-#define DC_WINC_CSC_KVR                                0x614
-#define DC_WINC_CSC_KUG                                0x615
-#define DC_WINC_CSC_KVG                                0x616
-#define DC_WINC_CSC_KUB                                0x617
-#define DC_WINC_CSC_KVB                                0x618
-#define DC_WINC_V_FILTER_P(x)                  (0x619 + (x))
+#define DC_WIN_COLOR_PALETTE(x)                        (0x500 + (x))
+
+#define DC_WIN_PALETTE_COLOR_EXT               0x600
+#define DC_WIN_H_FILTER_P(x)                   (0x601 + (x))
+#define DC_WIN_CSC_YOF                         0x611
+#define DC_WIN_CSC_KYRGB                       0x612
+#define DC_WIN_CSC_KUR                         0x613
+#define DC_WIN_CSC_KVR                         0x614
+#define DC_WIN_CSC_KUG                         0x615
+#define DC_WIN_CSC_KVG                         0x616
+#define DC_WIN_CSC_KUB                         0x617
+#define DC_WIN_CSC_KVB                         0x618
+#define DC_WIN_V_FILTER_P(x)                   (0x619 + (x))
 #define DC_WIN_WIN_OPTIONS                     0x700
 #define  H_DIRECTION_INCREMENT         (0 << 0)
 #define  H_DIRECTION_DECREMENTT                (1 << 0)
 #define  V_DIRECTION_INCREMENT         (0 << 2)
 #define  V_DIRECTION_DECREMENTT                (1 << 2)
 #define  COLOR_EXPAND                  (1 << 6)
+#define  H_FILTER_ENABLE               (1 << 8)
+#define  V_FILTER_ENABLE               (1 << 10)
 #define  CP_ENABLE                     (1 << 16)
+#define  CSC_ENABLE                    (1 << 18)
 #define  DV_ENABLE                     (1 << 20)
 #define  WIN_ENABLE                    (1 << 30)
 
 #define  V_DDA_INC(x)          (((x) & 0xffff) << 16)
 
 #define DC_WIN_LINE_STRIDE                     0x70a
+#define  LINE_STRIDE(x)                (x)
+#define  UV_LINE_STRIDE(x)     (((x) & 0xffff) << 16)
 #define DC_WIN_BUF_STRIDE                      0x70b
 #define DC_WIN_UV_BUF_STRIDE                   0x70c
 #define DC_WIN_BUFFER_ADDR_MODE                        0x70d
index 47756e4225bb65922978ac0e08b9dc6770bff1fd..15a4f5b472a8333152d79ae1c2cac6bd0af04674 100644 (file)
@@ -149,6 +149,9 @@ static int tegra_fb_set_par(struct fb_info *info)
                }
                info->fix.line_length = var->xres * var->bits_per_pixel / 8;
                tegra_fb->win->stride = info->fix.line_length;
+               tegra_fb->win->stride_uv = 0;
+               tegra_fb->win->offset_u = 0;
+               tegra_fb->win->offset_v = 0;
        }
 
        if (var->pixclock) {
@@ -176,9 +179,9 @@ static int tegra_fb_set_par(struct fb_info *info)
                tegra_dc_set_mode(tegra_fb->win->dc, &mode);
 
                tegra_fb->win->w = info->mode->xres;
-               tegra_fb->win->h = info->mode->xres;
+               tegra_fb->win->h = info->mode->yres;
                tegra_fb->win->out_w = info->mode->xres;
-               tegra_fb->win->out_h = info->mode->xres;
+               tegra_fb->win->out_h = info->mode->yres;
        }
        return 0;
 }
@@ -372,7 +375,10 @@ static int tegra_fb_set_windowattr(struct tegra_fb_info *tegra_fb,
 
        /* STOPSHIP verify that this won't read outside of the surface */
        win->phys_addr = flip_win->phys_addr + flip_win->attr.offset;
+       win->offset_u = flip_win->attr.offset_u + flip_win->attr.offset;
+       win->offset_v = flip_win->attr.offset_v + flip_win->attr.offset;
        win->stride = flip_win->attr.stride;
+       win->stride_uv = flip_win->attr.stride_uv;
 
        if ((s32)flip_win->attr.pre_syncpt_id >= 0) {
                nvhost_syncpt_wait_timeout(&tegra_fb->ndev->host->syncpt,
@@ -737,7 +743,10 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
        win->z = 0;
        win->phys_addr = fb_phys;
        win->virt_addr = fb_base;
+       win->offset_u = 0;
+       win->offset_v = 0;
        win->stride = fb_data->xres * fb_data->bits_per_pixel / 8;
+       win->stride_uv = 0;
        win->flags = TEGRA_WIN_FLAG_ENABLED;
 
        if (fb_mem)
index 79578c3d7bd4f846eaf23f66aba6ae69a0a1e484..b9861bc7953aecc906992431b942cbe633705d2e 100644 (file)
@@ -55,7 +55,10 @@ struct tegra_fb_windowattr {
        __u32   buff_id;
        __u32   blend;
        __u32   offset;
+       __u32   offset_u;
+       __u32   offset_v;
        __u32   stride;
+       __u32   stride_uv;
        __u32   pixformat;
        __u32   x;
        __u32   y;