summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilippe Langlais <philippe.langlais@linaro.org>2011-05-11 10:04:48 +0200
committerHenrik Aberg <henrik.aberg@stericsson.com>2011-05-18 09:40:12 +0200
commit428e324db4b71e5e85b74fb9c5c1a5851c5b7c55 (patch)
tree2c2213cbd9218d3c0a37575e47d239d405ba3366
parentf123fcd6bcd2033cb1c96eedacbaf765957fd6b6 (diff)
video: mcde: Add tripple buffer support
This patch adds tripple buffer support to the mcde driver. Useful for video mode devices (e.g. HDMI) where a missed v-sync leads to half frame rate (the client has to wait for the next v-sync). Tripple buffering solves this problem since there are two back buffers the client can use. Tripple buffering for HDMI is activated in menuconfig by enabling: System Type -> Display selection -> Enable tripple buffer for HDMI display ST-Ericsson ID: 335004 ST-Ericsson Linux next: Not tested, ER 282779 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Ice1f936a8a00e2fbc8fdf7e8c6621c539efe0ac4 Signed-off-by: Jimmy Rubin <jimmy.rubin@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/21839 Reviewed-by: QATOOLS Reviewed-by: Per PERSSON <per.xb.persson@stericsson.com> Reviewed-by: QATEST Reviewed-by: Marcel TUNNISSEN <marcel.tuennissen@stericsson.com> Conflicts: arch/arm/configs/u8500_defconfig drivers/misc/dispdev/dispdev.c
-rw-r--r--arch/arm/mach-ux500/Kconfig-arch6
-rw-r--r--arch/arm/mach-ux500/board-mop500-mcde.c6
-rw-r--r--drivers/video/mcde/mcde_display.c8
-rw-r--r--drivers/video/mcde/mcde_dss.c5
-rw-r--r--drivers/video/mcde/mcde_fb.c5
-rw-r--r--drivers/video/mcde/mcde_hw.c29
-rw-r--r--include/video/mcde.h3
-rw-r--r--include/video/mcde_display.h2
-rw-r--r--include/video/mcde_dss.h2
9 files changed, 45 insertions, 21 deletions
diff --git a/arch/arm/mach-ux500/Kconfig-arch b/arch/arm/mach-ux500/Kconfig-arch
index cfdf0ea1265..d16bf788392 100644
--- a/arch/arm/mach-ux500/Kconfig-arch
+++ b/arch/arm/mach-ux500/Kconfig-arch
@@ -143,6 +143,12 @@ config DISPLAY_AV8100_TERTIARY
help
Say yes here if HDMI output support
+config DISPLAY_AV8100_TRIPPLE_BUFFER
+ bool "Enable tripple buffer for HDMI display"
+ depends on DISPLAY_AV8100_TERTIARY
+ help
+ Say yes to enable tripple buffer. You'll get double buffer otherwise
+
endmenu
endif
diff --git a/arch/arm/mach-ux500/board-mop500-mcde.c b/arch/arm/mach-ux500/board-mop500-mcde.c
index bc7d596d88f..edf603dd0ce 100644
--- a/arch/arm/mach-ux500/board-mop500-mcde.c
+++ b/arch/arm/mach-ux500/board-mop500-mcde.c
@@ -462,6 +462,7 @@ static int display_postregistered_callback(struct notifier_block *nb,
virtual_width = width;
virtual_height = height * 2;
+
#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC
if (ddev->id == PRIMARY_DISPLAY_ID)
virtual_height = height;
@@ -472,6 +473,11 @@ static int display_postregistered_callback(struct notifier_block *nb,
virtual_height = height;
#endif
+#ifdef CONFIG_DISPLAY_AV8100_TRIPPLE_BUFFER
+ if (ddev->id == TERTIARY_DISPLAY_ID)
+ virtual_height = height * 3;
+#endif
+
if (ddev->id == TERTIARY_DISPLAY_ID) {
#ifdef CONFIG_MCDE_DISPLAY_HDMI_FB_AUTO_CREATE
hdmi_fb_onoff(ddev, 1, 0, 0);
diff --git a/drivers/video/mcde/mcde_display.c b/drivers/video/mcde/mcde_display.c
index 521446dc26f..144a1a67d02 100644
--- a/drivers/video/mcde/mcde_display.c
+++ b/drivers/video/mcde/mcde_display.c
@@ -328,9 +328,10 @@ static int mcde_display_invalidate_area_default(
return 0;
}
-static int mcde_display_update_default(struct mcde_display_device *ddev)
+static int mcde_display_update_default(struct mcde_display_device *ddev,
+ bool tripple_buffer)
{
- int ret;
+ int ret = 0;
/* TODO: Dirty */
if (ddev->prepare_for_update) {
@@ -344,7 +345,8 @@ static int mcde_display_update_default(struct mcde_display_device *ddev)
}
}
/* TODO: Calculate & set update rect */
- ret = mcde_chnl_update(ddev->chnl_state, &ddev->update_area);
+ ret = mcde_chnl_update(ddev->chnl_state, &ddev->update_area,
+ tripple_buffer);
if (ret < 0) {
dev_warn(&ddev->dev, "%s:Failed to update channel\n", __func__);
return ret;
diff --git a/drivers/video/mcde/mcde_dss.c b/drivers/video/mcde/mcde_dss.c
index a53040f48e1..361510b46fc 100644
--- a/drivers/video/mcde/mcde_dss.c
+++ b/drivers/video/mcde/mcde_dss.c
@@ -242,10 +242,9 @@ void mcde_dss_disable_overlay(struct mcde_overlay *ovly)
}
EXPORT_SYMBOL(mcde_dss_disable_overlay);
-int mcde_dss_update_overlay(struct mcde_overlay *ovly)
+int mcde_dss_update_overlay(struct mcde_overlay *ovly, bool tripple_buffer)
{
int ret;
-
dev_vdbg(&ovly->ddev->dev, "Overlay update, chnl=%d\n",
ovly->ddev->chnl_id);
@@ -256,7 +255,7 @@ int mcde_dss_update_overlay(struct mcde_overlay *ovly)
if (ovly->ddev->get_power_mode(ovly->ddev) == MCDE_DISPLAY_PM_OFF)
return 0;
- ret = ovly->ddev->update(ovly->ddev);
+ ret = ovly->ddev->update(ovly->ddev, tripple_buffer);
if (ret)
return ret;
diff --git a/drivers/video/mcde/mcde_fb.c b/drivers/video/mcde/mcde_fb.c
index 039a60ad05c..dc0812761c7 100644
--- a/drivers/video/mcde/mcde_fb.c
+++ b/drivers/video/mcde/mcde_fb.c
@@ -507,10 +507,13 @@ static int apply_var(struct fb_info *fbi, struct mcde_display_device *ddev)
for (i = 0; i < mfb->num_ovlys; i++) {
struct mcde_overlay *ovly = mfb->ovlys[i];
struct mcde_overlay_info info;
+ int num_buffers;
get_ovly_info(fbi, ovly, &info);
(void) mcde_dss_apply_overlay(ovly, &info);
- ret = mcde_dss_update_overlay(ovly);
+
+ num_buffers = var->yres_virtual / var->yres;
+ mcde_dss_update_overlay(ovly, num_buffers == 3);
}
return 0;
diff --git a/drivers/video/mcde/mcde_hw.c b/drivers/video/mcde/mcde_hw.c
index 7a0208df66e..9844dc1b2f7 100644
--- a/drivers/video/mcde/mcde_hw.c
+++ b/drivers/video/mcde/mcde_hw.c
@@ -964,18 +964,19 @@ static irqreturn_t mcde_irq_handler(int irq, void *dev)
static void wait_for_channel(struct mcde_chnl_state *chnl)
{
int ret;
+ u32 id = chnl->transactionid_regs;
- if (chnl->transactionid_hw >= chnl->transactionid_regs)
+ if (chnl->transactionid_hw >= id)
return;
ret = wait_event_timeout(chnl->waitq_hw,
- chnl->transactionid_hw == chnl->transactionid_regs,
+ chnl->transactionid_hw == id,
msecs_to_jiffies(CHNL_TIMEOUT));
if (!ret)
dev_warn(&mcde_dev->dev,
"Wait for channel timeout (chnl=%d,%d<%d)!\n",
chnl->id, chnl->transactionid_hw,
- chnl->transactionid_regs);
+ id);
}
static int update_channel_static_registers(struct mcde_chnl_state *chnl)
@@ -2318,12 +2319,14 @@ static void chnl_update_registers(struct mcde_chnl_state *chnl)
chnl->transactionid_regs = chnl->transactionid;
}
-static void chnl_update_continous(struct mcde_chnl_state *chnl)
+static void chnl_update_continous(struct mcde_chnl_state *chnl,
+ bool tripple_buffer)
{
if (chnl->continous_running) {
chnl->transactionid_regs = chnl->transactionid;
- wait_for_channel(chnl);
+ if (!tripple_buffer)
+ wait_for_channel(chnl);
}
if (!chnl->continous_running) {
@@ -2410,7 +2413,8 @@ static void chnl_update_overlay(struct mcde_chnl_state *chnl,
}
static int _mcde_chnl_update(struct mcde_chnl_state *chnl,
- struct mcde_rectangle *update_area)
+ struct mcde_rectangle *update_area,
+ bool tripple_buffer)
{
dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
@@ -2420,6 +2424,9 @@ static int _mcde_chnl_update(struct mcde_chnl_state *chnl,
return -EINVAL;
}
+ if (chnl->port.update_auto_trig && tripple_buffer)
+ wait_for_channel(chnl);
+
chnl->regs.x = update_area->x;
chnl->regs.y = update_area->y;
/* TODO Crop against video_mode.xres and video_mode.yres */
@@ -2439,7 +2446,7 @@ static int _mcde_chnl_update(struct mcde_chnl_state *chnl,
chnl_update_overlay(chnl, chnl->ovly1);
if (chnl->port.update_auto_trig)
- chnl_update_continous(chnl);
+ chnl_update_continous(chnl, tripple_buffer);
else
chnl_update_non_continous(chnl);
@@ -2608,10 +2615,10 @@ int mcde_chnl_apply(struct mcde_chnl_state *chnl)
}
int mcde_chnl_update(struct mcde_chnl_state *chnl,
- struct mcde_rectangle *update_area)
+ struct mcde_rectangle *update_area,
+ bool tripple_buffer)
{
int ret;
-
dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
if (!chnl->reserved)
@@ -2623,7 +2630,6 @@ int mcde_chnl_update(struct mcde_chnl_state *chnl,
(void)update_channel_static_registers(chnl);
if (chnl->regs.roten && !chnl->esram_is_enabled) {
- int ret;
ret = regulator_enable(chnl->port.reg_esram);
if (ret < 0) {
dev_warn(&mcde_dev->dev, "%s: disable failed\n",
@@ -2632,7 +2638,8 @@ int mcde_chnl_update(struct mcde_chnl_state *chnl,
chnl->esram_is_enabled = true;
}
- ret = _mcde_chnl_update(chnl, update_area);
+ ret = _mcde_chnl_update(chnl, update_area, tripple_buffer);
+
mutex_unlock(&mcde_hw_lock);
dev_vdbg(&mcde_dev->dev, "%s exit with ret %d\n", __func__, ret);
diff --git a/include/video/mcde.h b/include/video/mcde.h
index ef828f0d560..4803779b36f 100644
--- a/include/video/mcde.h
+++ b/include/video/mcde.h
@@ -332,7 +332,8 @@ int mcde_chnl_set_power_mode(struct mcde_chnl_state *chnl,
int mcde_chnl_apply(struct mcde_chnl_state *chnl);
int mcde_chnl_update(struct mcde_chnl_state *chnl,
- struct mcde_rectangle *update_area);
+ struct mcde_rectangle *update_area,
+ bool tripple_buffer);
void mcde_chnl_put(struct mcde_chnl_state *chnl);
void mcde_chnl_stop_flow(struct mcde_chnl_state *chnl);
diff --git a/include/video/mcde_display.h b/include/video/mcde_display.h
index 69ff1de4ef2..524e62904fc 100644
--- a/include/video/mcde_display.h
+++ b/include/video/mcde_display.h
@@ -97,7 +97,7 @@ struct mcde_display_device {
int (*apply_config)(struct mcde_display_device *dev);
int (*invalidate_area)(struct mcde_display_device *dev,
struct mcde_rectangle *area);
- int (*update)(struct mcde_display_device *dev);
+ int (*update)(struct mcde_display_device *dev, bool tripple_buffer);
int (*prepare_for_update)(struct mcde_display_device *dev,
u16 x, u16 y, u16 w, u16 h);
int (*on_first_update)(struct mcde_display_device *dev);
diff --git a/include/video/mcde_dss.h b/include/video/mcde_dss.h
index 6a149a5dee6..c2603b87235 100644
--- a/include/video/mcde_dss.h
+++ b/include/video/mcde_dss.h
@@ -30,7 +30,7 @@ int mcde_dss_enable_overlay(struct mcde_overlay *ovl);
void mcde_dss_disable_overlay(struct mcde_overlay *ovl);
int mcde_dss_apply_overlay(struct mcde_overlay *ovl,
struct mcde_overlay_info *info);
-int mcde_dss_update_overlay(struct mcde_overlay *ovl);
+int mcde_dss_update_overlay(struct mcde_overlay *ovl, bool tripple_buffer);
void mcde_dss_get_native_resolution(struct mcde_display_device *ddev,
u16 *x_res, u16 *y_res);