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:
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)); \
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);
}
}
+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)
{
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;
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);
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;
{
u32 disp_syncpt;
u32 vblank_syncpt;
+ int i;
tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
if (dc->ndev->id == 0) {
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;
#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