summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Gilling <konkers@android.com>2010-11-18 16:36:48 -0800
committerErik Gilling <konkers@android.com>2010-11-18 16:36:54 -0800
commit899ac49afad4ea0449750e5f76b640c248d5eaba (patch)
tree5e4683a63e81983c65435bb96c2c1f93854a56c2
parent8bcf057fe5b414e4893d757fb8c4fee4e206fd13 (diff)
parenta60ea58ebe901e3d61de0b31edcadd13dc61d719 (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.h3
-rw-r--r--drivers/video/tegra/dc/dc.c117
-rw-r--r--drivers/video/tegra/dc/dc_reg.h31
-rw-r--r--drivers/video/tegra/fb.c13
-rw-r--r--include/video/tegrafb.h3
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;