diff options
author | Marcel Tunnissen <Marcel.Tuennissen@stericsson.com> | 2011-05-10 12:00:52 +0200 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@linaro.org> | 2011-07-22 15:49:02 +0200 |
commit | 3eaec5dade2dddc8b96d84392e1372da123e452f (patch) | |
tree | 0bc5ffde8700f743720c6a270c35507f0dc84441 | |
parent | bf58a1e639bd40fc066b3c9a4bf1b378abdfbd45 (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.c | 30 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-u5500-mcde.c | 20 | ||||
-rw-r--r-- | drivers/video/mcde/display-ab8500.c | 6 | ||||
-rw-r--r-- | drivers/video/mcde/display-av8100.c | 6 | ||||
-rw-r--r-- | drivers/video/mcde/mcde_hw.c | 176 | ||||
-rw-r--r-- | include/video/mcde.h | 14 | ||||
-rw-r--r-- | include/video/mcde_display-ab8500.h | 2 | ||||
-rw-r--r-- | include/video/mcde_display-av8100.h | 2 |
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; |