aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Tunnissen <Marcel.Tuennissen@stericsson.com>2011-05-10 12:00:52 +0200
committerPhilippe Langlais <philippe.langlais@linaro.org>2011-07-22 15:49:02 +0200
commit3eaec5dade2dddc8b96d84392e1372da123e452f (patch)
tree0bc5ffde8700f743720c6a270c35507f0dc84441
parentbf58a1e639bd40fc066b3c9a4bf1b378abdfbd45 (diff)
video: mcde: Support YUV 422 overlay pixel format
This patch adds support for converting an overlay with YUV 422 pixel format. ST-Ericsson ID: 339423 ST-Ericsson Linux next: Not tested, ER 282779 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I5a8536c12f12b6cf69f7053cc236e274d13295b4 Signed-off-by: Marcel Tunnissen <Marcel.Tuennissen@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/22867 Reviewed-by: Jimmy RUBIN <jimmy.rubin@stericsson.com> Tested-by: Marcel TUNNISSEN <marcel.tuennissen@stericsson.com> Reviewed-by: QATOOLS Reviewed-by: Per PERSSON <per.xb.persson@stericsson.com>
-rw-r--r--arch/arm/mach-ux500/board-mop500-mcde.c30
-rw-r--r--arch/arm/mach-ux500/board-u5500-mcde.c20
-rw-r--r--drivers/video/mcde/display-ab8500.c6
-rw-r--r--drivers/video/mcde/display-av8100.c6
-rw-r--r--drivers/video/mcde/mcde_hw.c176
-rw-r--r--include/video/mcde.h14
-rw-r--r--include/video/mcde_display-ab8500.h2
-rw-r--r--include/video/mcde_display-av8100.h2
8 files changed, 186 insertions, 70 deletions
diff --git a/arch/arm/mach-ux500/board-mop500-mcde.c b/arch/arm/mach-ux500/board-mop500-mcde.c
index 56201ccfffc..b553ba9db2c 100644
--- a/arch/arm/mach-ux500/board-mop500-mcde.c
+++ b/arch/arm/mach-ux500/board-mop500-mcde.c
@@ -67,6 +67,18 @@ static int __init startup_graphics_setup(char *str)
}
__setup("startup_graphics=", startup_graphics_setup);
+#if defined(CONFIG_DISPLAY_AB8500_TERTIARY) ||\
+ defined(CONFIG_DISPLAY_AV8100_TERTIARY)
+static struct mcde_col_transform rgb_2_yCbCr_transform = {
+ .matrix = {
+ {0x0042, 0x0081, 0x0019},
+ {0xffda, 0xffb6, 0x0070},
+ {0x0070, 0xffa2, 0xffee},
+ },
+ .offset = {0x10, 0x80, 0x80},
+};
+#endif
+
#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY
static struct mcde_port port0 = {
.type = MCDE_PORTTYPE_DSI,
@@ -277,14 +289,7 @@ static struct mcde_port port_tvout1 = {
static struct ab8500_display_platform_data ab8500_display_pdata = {
.nr_regulators = 2,
.regulator_id = {"v-tvout", "v-ab8500-AV-switch"},
- .rgb_2_yCbCr_transform = {
- .matrix = {
- {0x42, 0x81, 0x19},
- {0xffda, 0xffb6, 0x70},
- {0x70, 0xffa2, 0xffee},
- },
- .offset = {0x10, 0x80, 0x80},
- }
+ .rgb_2_yCbCr_transform = &rgb_2_yCbCr_transform,
};
static struct ux500_pins *tvout_pins;
@@ -389,14 +394,7 @@ static struct mcde_display_hdmi_platform_data av8100_hdmi_pdata = {
.regulator_id = NULL, /* TODO: "display_main" */
.cvbs_regulator_id = "v-av8100-AV-switch",
.ddb_id = 1,
- .rgb_2_yCbCr_transform = {
- .matrix = {
- {0x42, 0x81, 0x19},
- {0xffda, 0xffb6, 0x70},
- {0x70, 0xffa2, 0xffee},
- },
- .offset = {0x10, 0x80, 0x80},
- }
+ .rgb_2_yCbCr_transform = &rgb_2_yCbCr_transform,
};
static struct mcde_display_device av8100_hdmi = {
diff --git a/arch/arm/mach-ux500/board-u5500-mcde.c b/arch/arm/mach-ux500/board-u5500-mcde.c
index 7394058881d..6c3bbe606fe 100644
--- a/arch/arm/mach-ux500/board-u5500-mcde.c
+++ b/arch/arm/mach-ux500/board-u5500-mcde.c
@@ -56,6 +56,17 @@ static int __init startup_graphics_setup(char *str)
}
__setup("startup_graphics=", startup_graphics_setup);
+#ifdef CONFIG_DISPLAY_AV8100_TERTIARY
+static struct mcde_col_transform rgb_2_yCbCr_transform = {
+ .matrix = {
+ {0x0042, 0x0081, 0x0019},
+ {0xffda, 0xffb6, 0x0070},
+ {0x0070, 0xffa2, 0xffee},
+ },
+ .offset = {0x10, 0x80, 0x80},
+};
+#endif
+
#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY
static struct mcde_port port0 = {
.type = MCDE_PORTTYPE_DSI,
@@ -158,14 +169,7 @@ static struct mcde_display_hdmi_platform_data av8100_hdmi_pdata = {
.regulator_id = NULL,
.cvbs_regulator_id = "v-av8100-AV-switch",
.ddb_id = 1,
- .rgb_2_yCbCr_transform = {
- .matrix = {
- {0x42, 0x81, 0x19},
- {0xffda, 0xffb6, 0x70},
- {0x70, 0xffa2, 0xffee},
- },
- .offset = {0x10, 0x80, 0x80},
- }
+ .rgb_2_yCbCr_transform = &rgb_2_yCbCr_transform,
};
static struct mcde_display_device av8100_hdmi = {
diff --git a/drivers/video/mcde/display-ab8500.c b/drivers/video/mcde/display-ab8500.c
index bd6126d8a20..5d7f1bb92a6 100644
--- a/drivers/video/mcde/display-ab8500.c
+++ b/drivers/video/mcde/display-ab8500.c
@@ -337,8 +337,10 @@ static int set_video_mode(
driver_data->denc_conf.act_dc_output = true;
set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY);
- mcde_chnl_set_col_convert(ddev->chnl_state,
- &pdata->rgb_2_yCbCr_transform);
+ if (pdata->rgb_2_yCbCr_transform)
+ mcde_chnl_set_col_convert(ddev->chnl_state,
+ pdata->rgb_2_yCbCr_transform,
+ MCDE_CONVERT_RGB_2_YCBCR);
mcde_chnl_stop_flow(ddev->chnl_state);
res = mcde_chnl_set_video_mode(ddev->chnl_state, &ddev->video_mode);
if (res < 0) {
diff --git a/drivers/video/mcde/display-av8100.c b/drivers/video/mcde/display-av8100.c
index d5e1857a290..9134e4bf33f 100644
--- a/drivers/video/mcde/display-av8100.c
+++ b/drivers/video/mcde/display-av8100.c
@@ -823,9 +823,11 @@ static int hdmi_set_video_mode(
memset(&(dev->video_mode), 0, sizeof(struct mcde_video_mode));
memcpy(&(dev->video_mode), video_mode, sizeof(struct mcde_video_mode));
- if (dev->port->pixel_format == MCDE_PORTPIXFMT_DSI_YCBCR422)
+ if (dev->port->pixel_format == MCDE_PORTPIXFMT_DSI_YCBCR422 &&
+ pdata->rgb_2_yCbCr_transform)
mcde_chnl_set_col_convert(dev->chnl_state,
- &pdata->rgb_2_yCbCr_transform);
+ pdata->rgb_2_yCbCr_transform,
+ MCDE_CONVERT_RGB_2_YCBCR);
mcde_chnl_stop_flow(dev->chnl_state);
ret = mcde_chnl_set_video_mode(dev->chnl_state, &dev->video_mode);
diff --git a/drivers/video/mcde/mcde_hw.c b/drivers/video/mcde/mcde_hw.c
index 05759bffd94..c320670b5dd 100644
--- a/drivers/video/mcde/mcde_hw.c
+++ b/drivers/video/mcde/mcde_hw.c
@@ -266,6 +266,10 @@ struct mcde_chnl_state {
u32 rotbuf1;
u32 rotbuf2;
+ struct mcde_col_transform rgb_2_ycbcr;
+ struct mcde_col_transform ycbcr_2_rgb;
+ struct mcde_col_transform *transform;
+
/* Blending */
u8 blend_ctrl;
bool blend_en;
@@ -1306,6 +1310,82 @@ clk_dpi_err:
return -EINVAL;
}
+void mcde_chnl_col_convert_apply(struct mcde_chnl_state *chnl,
+ struct mcde_col_transform *transform)
+{
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+
+ if (chnl->transform != transform) {
+
+ chnl->col_regs.y_red = transform->matrix[0][0];
+ chnl->col_regs.y_green = transform->matrix[0][1];
+ chnl->col_regs.y_blue = transform->matrix[0][2];
+ chnl->col_regs.cb_red = transform->matrix[1][0];
+ chnl->col_regs.cb_green = transform->matrix[1][1];
+ chnl->col_regs.cb_blue = transform->matrix[1][2];
+ chnl->col_regs.cr_red = transform->matrix[2][0];
+ chnl->col_regs.cr_green = transform->matrix[2][1];
+ chnl->col_regs.cr_blue = transform->matrix[2][2];
+ chnl->col_regs.off_y = transform->offset[0];
+ chnl->col_regs.off_cb = transform->offset[1];
+ chnl->col_regs.off_cr = transform->offset[2];
+
+ chnl->transform = transform;
+ }
+
+ dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__);
+}
+
+static void chnl_ovly_pixel_format_apply(struct mcde_chnl_state *chnl,
+ struct mcde_ovly_state *ovly)
+{
+ struct mcde_port *port = &chnl->port;
+ struct ovly_regs *regs = &ovly->regs;
+
+ /* Note: YUV -> YUV: blending YUV overlays will not make sense. */
+ static struct mcde_col_transform crycb_2_ycbcr = {
+ /* Note that in MCDE YUV 422 pixels come as VYU pixels */
+ .matrix = {
+ {0x0000, 0x0100, 0x0000},
+ {0x0000, 0x0000, 0x0100},
+ {0x0100, 0x0000, 0x0000},
+ },
+ .offset = {0, 0, 0},
+ };
+
+ if (port->type == MCDE_PORTTYPE_DSI) {
+ if (port->pixel_format != MCDE_PORTPIXFMT_DSI_YCBCR422) {
+ if (ovly->pix_fmt != MCDE_OVLYPIXFMT_YCbCr422) {
+ /* standard case: DSI: RGB -> RGB */
+ regs->col_conv = MCDE_OVL0CR_COLCCTRL_DISABLED;
+ } else {
+ /* DSI: YUV -> RGB */
+ /* TODO change matrix */
+ regs->col_conv =
+ MCDE_OVL0CR_COLCCTRL_ENABLED_SAT;
+ mcde_chnl_col_convert_apply(chnl,
+ &chnl->ycbcr_2_rgb);
+ }
+ } else {
+ if (ovly->pix_fmt != MCDE_OVLYPIXFMT_YCbCr422)
+ /* DSI: RGB -> YUV */
+ mcde_chnl_col_convert_apply(chnl,
+ &chnl->rgb_2_ycbcr);
+ else
+ /* DSI: YUV -> YUV */
+ mcde_chnl_col_convert_apply(chnl,
+ &crycb_2_ycbcr);
+ regs->col_conv = MCDE_OVL0CR_COLCCTRL_ENABLED_NO_SAT;
+ }
+ } else if (port->type == MCDE_PORTTYPE_DPI && port->phy.dpi.tv_mode) {
+ regs->col_conv = MCDE_OVL0CR_COLCCTRL_ENABLED_NO_SAT;
+ if (ovly->pix_fmt != MCDE_OVLYPIXFMT_YCbCr422)
+ mcde_chnl_col_convert_apply(chnl, &chnl->rgb_2_ycbcr);
+ else
+ mcde_chnl_col_convert_apply(chnl, &crycb_2_ycbcr);
+ }
+}
+
/* REVIEW: Make update_* an mcde_rectangle? */
static void update_overlay_registers(u8 idx, struct ovly_regs *regs,
struct mcde_port *port, enum mcde_fifo fifo,
@@ -1330,25 +1410,13 @@ static void update_overlay_registers(u8 idx, struct ovly_regs *regs,
}
/*
- * TODO: Preferably most of this is done in some apply function instead
- * of every update. Problem is however that at overlay apply
- * there is no port type info available (and the question is
- * whether it is appropriate to add a port type there).
- * Note that lpf has a dependency on update_y.
- */
- if (port->type == MCDE_PORTTYPE_DPI && port->phy.dpi.tv_mode)
- /* REVIEW: Why not for DSI? enable in regs? */
- regs->col_conv = MCDE_OVL0CR_COLCCTRL_ENABLED_NO_SAT;
- else if (port->type == MCDE_PORTTYPE_DSI) {
- if (port->pixel_format == MCDE_PORTPIXFMT_DSI_YCBCR422)
- regs->col_conv = MCDE_OVL0CR_COLCCTRL_ENABLED_NO_SAT;
- else
- regs->col_conv = MCDE_OVL0CR_COLCCTRL_DISABLED;
- if (interlaced) {
- nr_of_bufs = 2;
- lpf = lpf / 2;
- ljinc *= 2;
- }
+ * Preferably most of this is done in some apply function instead of for
+ * every update. However lpf has a dependency on update_y.
+ */
+ if (interlaced && port->type == MCDE_PORTTYPE_DSI) {
+ nr_of_bufs = 2;
+ lpf = lpf / 2;
+ ljinc *= 2;
}
fifo_size = get_output_fifo_size(fifo);
@@ -2205,6 +2273,25 @@ static struct mcde_chnl_state *_mcde_chnl_get(enum mcde_chnl chnl_id,
enum mcde_chnl_path path;
const struct chnl_config *cfg = NULL;
+ static struct mcde_col_transform ycbcr_2_rgb = {
+ /* Note that in MCDE YUV 422 pixels come as VYU pixels */
+ .matrix = {
+ {0xff30, 0x012a, 0xff9c},
+ {0x0000, 0x012a, 0x0204},
+ {0x0199, 0x012a, 0x0000},
+ },
+ .offset = {0x0088, 0xfeeb, 0xff21},
+ };
+
+ static struct mcde_col_transform rgb_2_ycbcr = {
+ .matrix = {
+ {0x0042, 0x0081, 0x0019},
+ {0xffda, 0xffb6, 0x0070},
+ {0x0070, 0xffa2, 0xffee},
+ },
+ .offset = {0x0010, 0x0080, 0x0080},
+ };
+
/* Allocate channel */
for (i = 0; i < num_channels; i++) {
if (chnl_id == channels[i].id)
@@ -2242,6 +2329,8 @@ static struct mcde_chnl_state *_mcde_chnl_get(enum mcde_chnl chnl_id,
chnl->port = *port;
chnl->fifo = fifo;
chnl->formatter_updated = false;
+ chnl->ycbcr_2_rgb = ycbcr_2_rgb;
+ chnl->rgb_2_ycbcr = rgb_2_ycbcr;
chnl->blend_en = true;
chnl->blend_ctrl = MCDE_CRA0_BLENDCTRL_SOURCE;
@@ -2439,6 +2528,7 @@ static void chnl_update_overlay(struct mcde_chnl_state *chnl,
update_overlay_registers_on_the_fly(ovly->idx, &ovly->regs);
if (ovly->regs.update) {
+ chnl_ovly_pixel_format_apply(chnl, ovly);
update_overlay_registers(ovly->idx, &ovly->regs, &chnl->port,
chnl->fifo, chnl->regs.x, chnl->regs.y,
chnl->regs.ppl, chnl->regs.lpf, ovly->stride,
@@ -2540,24 +2630,36 @@ int mcde_chnl_set_palette(struct mcde_chnl_state *chnl,
}
void mcde_chnl_set_col_convert(struct mcde_chnl_state *chnl,
- struct mcde_col_convert *col_convert)
-{
- dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
-
- chnl->col_regs.y_red = col_convert->matrix[0][0];
- chnl->col_regs.y_green = col_convert->matrix[0][1];
- chnl->col_regs.y_blue = col_convert->matrix[0][2];
- chnl->col_regs.cb_red = col_convert->matrix[1][0];
- chnl->col_regs.cb_green = col_convert->matrix[1][1];
- chnl->col_regs.cb_blue = col_convert->matrix[1][2];
- chnl->col_regs.cr_red = col_convert->matrix[2][0];
- chnl->col_regs.cr_green = col_convert->matrix[2][1];
- chnl->col_regs.cr_blue = col_convert->matrix[2][2];
- chnl->col_regs.off_y = col_convert->offset[0];
- chnl->col_regs.off_cb = col_convert->offset[1];
- chnl->col_regs.off_cr = col_convert->offset[2];
-
- dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__);
+ struct mcde_col_transform *transform,
+ enum mcde_col_convert convert)
+{
+ switch (convert) {
+ case MCDE_CONVERT_RGB_2_YCBCR:
+ memcpy(&chnl->rgb_2_ycbcr, transform,
+ sizeof(struct mcde_col_transform));
+ /* force update: */
+ if (chnl->transform == &chnl->rgb_2_ycbcr) {
+ chnl->transform = NULL;
+ chnl->ovly0->update = true;
+ chnl->ovly1->update = true;
+ }
+ break;
+ case MCDE_CONVERT_YCBCR_2_RGB:
+ memcpy(&chnl->ycbcr_2_rgb, transform,
+ sizeof(struct mcde_col_transform));
+ /* force update: */
+ if (chnl->transform == &chnl->ycbcr_2_rgb) {
+ chnl->transform = NULL;
+ chnl->ovly0->update = true;
+ chnl->ovly1->update = true;
+ }
+ break;
+ default:
+ /* Trivial transforms are handled internally */
+ dev_warn(&mcde_dev->dev,
+ "%s: unsupported col convert\n", __func__);
+ break;
+ }
}
int mcde_chnl_set_video_mode(struct mcde_chnl_state *chnl,
diff --git a/include/video/mcde.h b/include/video/mcde.h
index 7476b7b32f4..97eeef01c19 100644
--- a/include/video/mcde.h
+++ b/include/video/mcde.h
@@ -141,7 +141,14 @@ enum mcde_hdmi_sdtv_switch {
DVI_SWITCH
};
-struct mcde_col_convert {
+enum mcde_col_convert {
+ MCDE_CONVERT_RGB_2_RGB,
+ MCDE_CONVERT_RGB_2_YCBCR,
+ MCDE_CONVERT_YCBCR_2_RGB,
+ MCDE_CONVERT_YCBCR_2_YCBCR,
+};
+
+struct mcde_col_transform {
u16 matrix[3][3];
u16 offset[3];
};
@@ -197,7 +204,7 @@ enum mcde_ovly_pix_fmt {
MCDE_OVLYPIXFMT_RGB888 = 4,
MCDE_OVLYPIXFMT_RGBX8888 = 5,
MCDE_OVLYPIXFMT_RGBA8888 = 6,
- MCDE_OVLYPIXFMT_YCbCr422 = 7,/* REVIEW: Capitalize */
+ MCDE_OVLYPIXFMT_YCbCr422 = 7,
};
/* Display power modes */
@@ -320,7 +327,8 @@ int mcde_chnl_set_pixel_format(struct mcde_chnl_state *chnl,
int mcde_chnl_set_palette(struct mcde_chnl_state *chnl,
struct mcde_palette_table *palette);
void mcde_chnl_set_col_convert(struct mcde_chnl_state *chnl,
- struct mcde_col_convert *col_convert);
+ struct mcde_col_transform *transform,
+ enum mcde_col_convert convert);
int mcde_chnl_set_video_mode(struct mcde_chnl_state *chnl,
struct mcde_video_mode *vmode);
/* TODO: Remove rotbuf* parameters when ESRAM allocator is implemented*/
diff --git a/include/video/mcde_display-ab8500.h b/include/video/mcde_display-ab8500.h
index 336fe441f42..ffebe62af92 100644
--- a/include/video/mcde_display-ab8500.h
+++ b/include/video/mcde_display-ab8500.h
@@ -15,7 +15,7 @@
struct ab8500_display_platform_data {
/* Platform info */
- struct mcde_col_convert rgb_2_yCbCr_transform;
+ struct mcde_col_transform *rgb_2_yCbCr_transform;
int nr_regulators;
const char *regulator_id[];
};
diff --git a/include/video/mcde_display-av8100.h b/include/video/mcde_display-av8100.h
index b0bbc02c1f8..52578a675f1 100644
--- a/include/video/mcde_display-av8100.h
+++ b/include/video/mcde_display-av8100.h
@@ -32,7 +32,7 @@ struct mcde_display_hdmi_platform_data {
const char *cvbs_regulator_id;
int reset_delay; /* ms */
u32 ddb_id;
- struct mcde_col_convert rgb_2_yCbCr_transform;
+ struct mcde_col_transform *rgb_2_yCbCr_transform;
/* Driver data */ /* TODO: move to driver data instead */
bool hdmi_platform_enable;