From mboxrd@z Thu Jan 1 00:00:00 1970 From: Archit Taneja Date: Wed, 07 Nov 2012 14:56:25 +0000 Subject: [RFC 07/11] OMAPDSS: writeback: add mechanism to do mem to mem updates Message-Id: <1352299469-17609-8-git-send-email-archit@ti.com> List-Id: References: <1352299469-17609-1-git-send-email-archit@ti.com> In-Reply-To: <1352299469-17609-1-git-send-email-archit@ti.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: tomi.valkeinen@ti.com Cc: linux-fbdev@vger.kernel.org, linux-omap@vger.kernel.org, Archit Taneja writeback in mem to mem mode works like an overlay manager connected to a display in stallmode. When we set ENABLE in DISPC_WB_ATTRIBUTES writeback, it starts a mem to mem transfer. On completion, we get a FRAMEDONEWB interrupt and the ENABLE bit is cleared by HW. In APPLY, we add dss_wb_start_update, this function is similar to dss_mgr_start_update, but is responsible for configuring both the manager(and the overlays connected to it) and the writeback registers. We add an updating field in the writeback private data which tells APPLY when we are busy and when we are done with a mem to mem transfer. We register to the framedone isr when needed and we update the updating field in dss_apply_irq_handler when we are done with the transfer. In the writeback output driver, we add a semaphore based way to lock the writeback resource as we do in DSI command mode. The writeback user is expected to lock the bus, call omapdss_writeback_update and mention a callback along with it, and unlock the bus in the callback. omapdss_writeback_update registers to the FRAMEDONE interrupt to trigger the callback and starts the update by calling the corresponding APPLY function. Signed-off-by: Archit Taneja --- drivers/video/omap2/dss/apply.c | 83 +++++++++++++++++++++++++++ drivers/video/omap2/dss/dss.h | 1 + drivers/video/omap2/dss/writeback.c | 106 +++++++++++++++++++++++++++++++++++ include/video/omapdss.h | 4 ++ 4 files changed, 194 insertions(+) diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index a205ed4..2fd08d8 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c @@ -114,6 +114,9 @@ struct wb_priv_data { bool info_dirty; struct omap_dss_writeback_info info; + /* If true, writeback output is enabled */ + bool updating; + /* * If true in memory to memory mode, a manager is connected to it. * However, it may not be active. @@ -285,6 +288,7 @@ static int dss_check_settings_apply(struct omap_overlay_manager *mgr) static bool need_isr(void) { const int num_mgrs = dss_feat_get_num_mgrs(); + const int num_wbs = dss_feat_get_num_wbs(); int i; for (i = 0; i < num_mgrs; ++i) { @@ -362,6 +366,20 @@ static bool need_isr(void) } } + for (i = 0; i < num_wbs; i++) { + struct omap_dss_output *wb = omap_dss_get_writeback(); + struct wb_priv_data *wp = get_wb_priv(wb); + + if (!wp->enabled) + continue; + + if (wb_manual_update(wb)) { + /* to catch FRAMEDONEWB */ + if (wp->updating) + return true; + } + } + return false; } @@ -841,6 +859,7 @@ static void dss_apply_irq_handler(void *data, u32 mask); static void dss_register_vsync_isr(void) { const int num_mgrs = dss_feat_get_num_mgrs(); + const int num_wbs = dss_feat_get_num_wbs(); u32 mask; int r, i; @@ -851,6 +870,9 @@ static void dss_register_vsync_isr(void) for (i = 0; i < num_mgrs; ++i) mask |= dispc_mgr_get_framedone_irq(i); + for (i = 0; i < num_wbs; i++) + mask |= dispc_wb_get_framedone_irq(); + r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); WARN_ON(r); @@ -860,6 +882,7 @@ static void dss_register_vsync_isr(void) static void dss_unregister_vsync_isr(void) { const int num_mgrs = dss_feat_get_num_mgrs(); + const int num_wbs = dss_feat_get_num_wbs(); u32 mask; int r, i; @@ -870,6 +893,9 @@ static void dss_unregister_vsync_isr(void) for (i = 0; i < num_mgrs; ++i) mask |= dispc_mgr_get_framedone_irq(i); + for (i = 0; i < num_wbs; i++) + mask |= dispc_wb_get_framedone_irq(); + r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask); WARN_ON(r); @@ -879,6 +905,7 @@ static void dss_unregister_vsync_isr(void) static void dss_apply_irq_handler(void *data, u32 mask) { const int num_mgrs = dss_feat_get_num_mgrs(); + const int num_wbs = dss_feat_get_num_wbs(); int i; bool extra_updating; @@ -906,6 +933,16 @@ static void dss_apply_irq_handler(void *data, u32 mask) } } + for (i = 0; i < num_wbs; i++) { + struct omap_dss_output *wb = omap_dss_get_writeback(); + struct wb_priv_data *wp = get_wb_priv(wb); + + if (!wp->enabled) + continue; + + wp->updating = dispc_wb_is_enabled(); + } + dss_write_regs(); dss_set_go_bits(); @@ -1685,6 +1722,11 @@ void dss_wb_disable(struct omap_dss_output *wb) if (!wp->enabled) goto out; + if (wp->updating) { + DSSERR("can't disable writeback in the middle of an update\n"); + goto out; + } + spin_lock_irqsave(&data_lock, flags); wp->updating = false; @@ -1694,3 +1736,44 @@ void dss_wb_disable(struct omap_dss_output *wb) out: mutex_unlock(&apply_lock); } + +/* + * When doing a writeback mem to mem update, the updating field for writeback + * private data is true, but for manager private data the updating field is + * false. This is because a manager isn't really 'enabled' in HW, it's the + * writeback pipeline which initiates the transfer. + */ +void dss_wb_start_update(struct omap_dss_output *wb) +{ + struct omap_overlay_manager *mgr = wb->manager; + struct wb_priv_data *wp = get_wb_priv(wb); + unsigned long flags; + int r; + + spin_lock_irqsave(&data_lock, flags); + + WARN_ON(wp->updating); + + /* add some similar check for writeback later */ + + r = dss_check_settings(mgr); + if (r) { + DSSERR("cannot start manual update: illegal configuration\n"); + spin_unlock_irqrestore(&data_lock, flags); + return; + } + + dss_wb_write_regs(wb); + + dss_mgr_write_regs(mgr); + dss_mgr_write_regs_extra(mgr); + + wp->updating = true; + + if (!dss_data.irq_enabled && need_isr()) + dss_register_vsync_isr(); + + dispc_wb_enable(true); + + spin_unlock_irqrestore(&data_lock, flags); +} diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index f9e7074..8c70b08 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -217,6 +217,7 @@ void dss_wb_get_info(struct omap_dss_output *wb, int omap_dss_wb_apply(struct omap_dss_output *wb); int dss_wb_enable(struct omap_dss_output *wb); void dss_wb_disable(struct omap_dss_output *wb); +void dss_wb_start_update(struct omap_dss_output *wb); /* output */ void dss_register_output(struct omap_dss_output *out); diff --git a/drivers/video/omap2/dss/writeback.c b/drivers/video/omap2/dss/writeback.c index 09394fb..7a25e99 100644 --- a/drivers/video/omap2/dss/writeback.c +++ b/drivers/video/omap2/dss/writeback.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include