diff options
author | Erik Gilling <konkers@android.com> | 2010-11-18 16:36:48 -0800 |
---|---|---|
committer | Erik Gilling <konkers@android.com> | 2010-11-18 16:36:54 -0800 |
commit | 899ac49afad4ea0449750e5f76b640c248d5eaba (patch) | |
tree | 5e4683a63e81983c65435bb96c2c1f93854a56c2 | |
parent | 8bcf057fe5b414e4893d757fb8c4fee4e206fd13 (diff) | |
parent | a60ea58ebe901e3d61de0b31edcadd13dc61d719 (diff) |
Merge branch linux-tegra-2.6.36 into android-tegra-2.6.36
Change-Id: Iff6fb3eee3b96120f3973ccada4c0b0772dbc2b3
-rw-r--r-- | arch/arm/mach-tegra/include/mach/dc.h | 3 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 117 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc_reg.h | 31 | ||||
-rw-r--r-- | drivers/video/tegra/fb.c | 13 | ||||
-rw-r--r-- | include/video/tegrafb.h | 3 |
5 files changed, 138 insertions, 29 deletions
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index 7b674220c3ee..77a9f15bc0bf 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -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; diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index 1c54da6672a5..7ca78cd7c247 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -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 bool 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 true; + } + return false; +} + #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; + bool 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; diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h index 360eda69e0dd..5ae3cc4c1dec 100644 --- a/drivers/video/tegra/dc/dc_reg.h +++ b/drivers/video/tegra/dc/dc_reg.h @@ -309,26 +309,29 @@ #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) @@ -366,6 +369,8 @@ #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 diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index 47756e4225bb..15a4f5b472a8 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -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) diff --git a/include/video/tegrafb.h b/include/video/tegrafb.h index 79578c3d7bd4..b9861bc7953a 100644 --- a/include/video/tegrafb.h +++ b/include/video/tegrafb.h @@ -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; |