diff options
Diffstat (limited to 'drivers/video/omap2')
28 files changed, 2760 insertions, 2058 deletions
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 8d8e1fe1901..74d29b55290 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -41,7 +41,7 @@ config PANEL_NEC_NL8048HL11_01B config PANEL_PICODLP tristate "TI PICO DLP mini-projector" - depends on OMAP2_DSS && I2C + depends on OMAP2_DSS_DPI && I2C help A mini-projector used in TI's SDP4430 and EVM boards For more info please visit http://www.dlp.com/projector/ diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 519c47d2057..28b9a6d61b0 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -297,6 +297,72 @@ static struct panel_config generic_dpi_panels[] = { .name = "apollon", }, + /* FocalTech ETM070003DH6 */ + { + { + .x_res = 800, + .y_res = 480, + + .pixel_clock = 28000, + + .hsw = 48, + .hfp = 40, + .hbp = 40, + + .vsw = 3, + .vfp = 13, + .vbp = 29, + }, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS, + .name = "focaltech_etm070003dh6", + }, + + /* Microtips Technologies - UMSH-8173MD */ + { + { + .x_res = 800, + .y_res = 480, + + .pixel_clock = 34560, + + .hsw = 13, + .hfp = 101, + .hbp = 101, + + .vsw = 23, + .vfp = 1, + .vbp = 1, + }, + .acbi = 0x0, + .acb = 0x0, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC, + .power_on_delay = 0, + .power_off_delay = 0, + .name = "microtips_umsh_8173md", + }, + + /* OrtusTech COM43H4M10XTC */ + { + { + .x_res = 480, + .y_res = 272, + + .pixel_clock = 8000, + + .hsw = 41, + .hfp = 8, + .hbp = 4, + + .vsw = 10, + .vfp = 4, + .vbp = 2, + }, + .config = OMAP_DSS_LCD_TFT, + + .name = "ortustech_com43h4m10xtc", + }, }; struct panel_drv_data { diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index 8365e77e09f..0eb31caddca 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c @@ -163,50 +163,93 @@ static void nec_8048_panel_remove(struct omap_dss_device *dssdev) kfree(necd); } -static int nec_8048_panel_enable(struct omap_dss_device *dssdev) +static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) { - int r = 0; + int r; struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); struct backlight_device *bl = necd->bl; + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + r = omapdss_dpi_display_enable(dssdev); + if (r) + goto err0; + if (dssdev->platform_enable) { r = dssdev->platform_enable(dssdev); if (r) - return r; + goto err1; } r = nec_8048_bl_update_status(bl); if (r < 0) dev_err(&dssdev->dev, "failed to set lcd brightness\n"); - r = omapdss_dpi_display_enable(dssdev); - + return 0; +err1: + omapdss_dpi_display_disable(dssdev); +err0: return r; } -static void nec_8048_panel_disable(struct omap_dss_device *dssdev) +static void nec_8048_panel_power_off(struct omap_dss_device *dssdev) { struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); struct backlight_device *bl = necd->bl; - omapdss_dpi_display_disable(dssdev); + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return; bl->props.brightness = 0; nec_8048_bl_update_status(bl); if (dssdev->platform_disable) dssdev->platform_disable(dssdev); + + omapdss_dpi_display_disable(dssdev); +} + +static int nec_8048_panel_enable(struct omap_dss_device *dssdev) +{ + int r; + + r = nec_8048_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + return 0; +} + +static void nec_8048_panel_disable(struct omap_dss_device *dssdev) +{ + nec_8048_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; } static int nec_8048_panel_suspend(struct omap_dss_device *dssdev) { - nec_8048_panel_disable(dssdev); + nec_8048_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + return 0; } static int nec_8048_panel_resume(struct omap_dss_device *dssdev) { - return nec_8048_panel_enable(dssdev); + int r; + + r = nec_8048_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + return 0; } static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 80c3f6ab1a9..00c5c615585 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -198,12 +198,6 @@ struct taal_data { bool te_enabled; atomic_t do_update; - struct { - u16 x; - u16 y; - u16 w; - u16 h; - } update_region; int channel; struct delayed_work te_timeout_work; @@ -1188,6 +1182,10 @@ static int taal_power_on(struct omap_dss_device *dssdev) if (r) goto err; + r = dsi_enable_video_output(dssdev, td->channel); + if (r) + goto err; + td->enabled = 1; if (!td->intro_printed) { @@ -1217,6 +1215,8 @@ static void taal_power_off(struct omap_dss_device *dssdev) struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; + dsi_disable_video_output(dssdev, td->channel); + r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF); if (!r) r = taal_sleep_in(td); @@ -1394,12 +1394,8 @@ static irqreturn_t taal_te_isr(int irq, void *data) if (old) { cancel_delayed_work(&td->te_timeout_work); - r = omap_dsi_update(dssdev, td->channel, - td->update_region.x, - td->update_region.y, - td->update_region.w, - td->update_region.h, - taal_framedone_cb, dssdev); + r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, + dssdev); if (r) goto err; } @@ -1444,26 +1440,20 @@ static int taal_update(struct omap_dss_device *dssdev, goto err; } - r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true); - if (r) - goto err; - - r = taal_set_update_window(td, x, y, w, h); + /* XXX no need to send this every frame, but dsi break if not done */ + r = taal_set_update_window(td, 0, 0, + td->panel_config->timings.x_res, + td->panel_config->timings.y_res); if (r) goto err; if (td->te_enabled && panel_data->use_ext_te) { - td->update_region.x = x; - td->update_region.y = y; - td->update_region.w = w; - td->update_region.h = h; - barrier(); schedule_delayed_work(&td->te_timeout_work, msecs_to_jiffies(250)); atomic_set(&td->do_update, 1); } else { - r = omap_dsi_update(dssdev, td->channel, x, y, w, h, - taal_framedone_cb, dssdev); + r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, + dssdev); if (r) goto err; } diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index bd34ac5b202..5c450b0f94d 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o -omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o +omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ + manager.o overlay.o apply.o omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c new file mode 100644 index 00000000000..052dc874cd3 --- /dev/null +++ b/drivers/video/omap2/dss/apply.c @@ -0,0 +1,1324 @@ +/* + * Copyright (C) 2011 Texas Instruments + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define DSS_SUBSYS_NAME "APPLY" + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/jiffies.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" + +/* + * We have 4 levels of cache for the dispc settings. First two are in SW and + * the latter two in HW. + * + * set_info() + * v + * +--------------------+ + * | user_info | + * +--------------------+ + * v + * apply() + * v + * +--------------------+ + * | info | + * +--------------------+ + * v + * write_regs() + * v + * +--------------------+ + * | shadow registers | + * +--------------------+ + * v + * VFP or lcd/digit_enable + * v + * +--------------------+ + * | registers | + * +--------------------+ + */ + +struct ovl_priv_data { + + bool user_info_dirty; + struct omap_overlay_info user_info; + + bool info_dirty; + struct omap_overlay_info info; + + bool shadow_info_dirty; + + bool extra_info_dirty; + bool shadow_extra_info_dirty; + + bool enabled; + enum omap_channel channel; + u32 fifo_low, fifo_high; + + /* + * True if overlay is to be enabled. Used to check and calculate configs + * for the overlay before it is enabled in the HW. + */ + bool enabling; +}; + +struct mgr_priv_data { + + bool user_info_dirty; + struct omap_overlay_manager_info user_info; + + bool info_dirty; + struct omap_overlay_manager_info info; + + bool shadow_info_dirty; + + /* If true, GO bit is up and shadow registers cannot be written. + * Never true for manual update displays */ + bool busy; + + /* If true, dispc output is enabled */ + bool updating; + + /* If true, a display is enabled using this manager */ + bool enabled; +}; + +static struct { + struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; + struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; + + bool irq_enabled; +} dss_data; + +/* protects dss_data */ +static spinlock_t data_lock; +/* lock for blocking functions */ +static DEFINE_MUTEX(apply_lock); +static DECLARE_COMPLETION(extra_updated_completion); + +static void dss_register_vsync_isr(void); + +static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl) +{ + return &dss_data.ovl_priv_data_array[ovl->id]; +} + +static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr) +{ + return &dss_data.mgr_priv_data_array[mgr->id]; +} + +void dss_apply_init(void) +{ + const int num_ovls = dss_feat_get_num_ovls(); + int i; + + spin_lock_init(&data_lock); + + for (i = 0; i < num_ovls; ++i) { + struct ovl_priv_data *op; + + op = &dss_data.ovl_priv_data_array[i]; + + op->info.global_alpha = 255; + + switch (i) { + case 0: + op->info.zorder = 0; + break; + case 1: + op->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; + break; + case 2: + op->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; + break; + case 3: + op->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; + break; + } + + op->user_info = op->info; + } +} + +static bool ovl_manual_update(struct omap_overlay *ovl) +{ + return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; +} + +static bool mgr_manual_update(struct omap_overlay_manager *mgr) +{ + return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; +} + +static int dss_check_settings_low(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev, bool applying) +{ + struct omap_overlay_info *oi; + struct omap_overlay_manager_info *mi; + struct omap_overlay *ovl; + struct omap_overlay_info *ois[MAX_DSS_OVERLAYS]; + struct ovl_priv_data *op; + struct mgr_priv_data *mp; + + mp = get_mgr_priv(mgr); + + if (applying && mp->user_info_dirty) + mi = &mp->user_info; + else + mi = &mp->info; + + /* collect the infos to be tested into the array */ + list_for_each_entry(ovl, &mgr->overlays, list) { + op = get_ovl_priv(ovl); + + if (!op->enabled && !op->enabling) + oi = NULL; + else if (applying && op->user_info_dirty) + oi = &op->user_info; + else + oi = &op->info; + + ois[ovl->id] = oi; + } + + return dss_mgr_check(mgr, dssdev, mi, ois); +} + +/* + * check manager and overlay settings using overlay_info from data->info + */ +static int dss_check_settings(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev) +{ + return dss_check_settings_low(mgr, dssdev, false); +} + +/* + * check manager and overlay settings using overlay_info from ovl->info if + * dirty and from data->info otherwise + */ +static int dss_check_settings_apply(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev) +{ + return dss_check_settings_low(mgr, dssdev, true); +} + +static bool need_isr(void) +{ + const int num_mgrs = dss_feat_get_num_mgrs(); + int i; + + for (i = 0; i < num_mgrs; ++i) { + struct omap_overlay_manager *mgr; + struct mgr_priv_data *mp; + struct omap_overlay *ovl; + + mgr = omap_dss_get_overlay_manager(i); + mp = get_mgr_priv(mgr); + + if (!mp->enabled) + continue; + + if (mgr_manual_update(mgr)) { + /* to catch FRAMEDONE */ + if (mp->updating) + return true; + } else { + /* to catch GO bit going down */ + if (mp->busy) + return true; + + /* to write new values to registers */ + if (mp->info_dirty) + return true; + + /* to set GO bit */ + if (mp->shadow_info_dirty) + return true; + + list_for_each_entry(ovl, &mgr->overlays, list) { + struct ovl_priv_data *op; + + op = get_ovl_priv(ovl); + + /* + * NOTE: we check extra_info flags even for + * disabled overlays, as extra_infos need to be + * always written. + */ + + /* to write new values to registers */ + if (op->extra_info_dirty) + return true; + + /* to set GO bit */ + if (op->shadow_extra_info_dirty) + return true; + + if (!op->enabled) + continue; + + /* to write new values to registers */ + if (op->info_dirty) + return true; + + /* to set GO bit */ + if (op->shadow_info_dirty) + return true; + } + } + } + + return false; +} + +static bool need_go(struct omap_overlay_manager *mgr) +{ + struct omap_overlay *ovl; + struct mgr_priv_data *mp; + struct ovl_priv_data *op; + + mp = get_mgr_priv(mgr); + + if (mp->shadow_info_dirty) + return true; + + list_for_each_entry(ovl, &mgr->overlays, list) { + op = get_ovl_priv(ovl); + if (op->shadow_info_dirty || op->shadow_extra_info_dirty) + return true; + } + + return false; +} + +/* returns true if an extra_info field is currently being updated */ +static bool extra_info_update_ongoing(void) +{ + const int num_ovls = omap_dss_get_num_overlays(); + struct ovl_priv_data *op; + struct omap_overlay *ovl; + struct mgr_priv_data *mp; + int i; + + for (i = 0; i < num_ovls; ++i) { + ovl = omap_dss_get_overlay(i); + op = get_ovl_priv(ovl); + + if (!ovl->manager) + continue; + + mp = get_mgr_priv(ovl->manager); + + if (!mp->enabled) + continue; + + if (!mp->updating) + continue; + + if (op->extra_info_dirty || op->shadow_extra_info_dirty) + return true; + } + + return false; +} + +/* wait until no extra_info updates are pending */ +static void wait_pending_extra_info_updates(void) +{ + bool updating; + unsigned long flags; + unsigned long t; + + spin_lock_irqsave(&data_lock, flags); + + updating = extra_info_update_ongoing(); + + if (!updating) { + spin_unlock_irqrestore(&data_lock, flags); + return; + } + + init_completion(&extra_updated_completion); + + spin_unlock_irqrestore(&data_lock, flags); + + t = msecs_to_jiffies(500); + wait_for_completion_timeout(&extra_updated_completion, t); + + updating = extra_info_update_ongoing(); + + WARN_ON(updating); +} + +int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) +{ + unsigned long timeout = msecs_to_jiffies(500); + struct mgr_priv_data *mp; + u32 irq; + int r; + int i; + struct omap_dss_device *dssdev = mgr->device; + + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + if (mgr_manual_update(mgr)) + return 0; + + irq = dispc_mgr_get_vsync_irq(mgr->id); + + mp = get_mgr_priv(mgr); + i = 0; + while (1) { + unsigned long flags; + bool shadow_dirty, dirty; + + spin_lock_irqsave(&data_lock, flags); + dirty = mp->info_dirty; + shadow_dirty = mp->shadow_info_dirty; + spin_unlock_irqrestore(&data_lock, flags); + + if (!dirty && !shadow_dirty) { + r = 0; + break; + } + + /* 4 iterations is the worst case: + * 1 - initial iteration, dirty = true (between VFP and VSYNC) + * 2 - first VSYNC, dirty = true + * 3 - dirty = false, shadow_dirty = true + * 4 - shadow_dirty = false */ + if (i++ == 3) { + DSSERR("mgr(%d)->wait_for_go() not finishing\n", + mgr->id); + r = 0; + break; + } + + r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); + if (r == -ERESTARTSYS) + break; + + if (r) { + DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); + break; + } + } + + return r; +} + +int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) +{ + unsigned long timeout = msecs_to_jiffies(500); + struct ovl_priv_data *op; + struct omap_dss_device *dssdev; + u32 irq; + int r; + int i; + + if (!ovl->manager) + return 0; + + dssdev = ovl->manager->device; + + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + if (ovl_manual_update(ovl)) + return 0; + + irq = dispc_mgr_get_vsync_irq(ovl->manager->id); + + op = get_ovl_priv(ovl); + i = 0; + while (1) { + unsigned long flags; + bool shadow_dirty, dirty; + + spin_lock_irqsave(&data_lock, flags); + dirty = op->info_dirty; + shadow_dirty = op->shadow_info_dirty; + spin_unlock_irqrestore(&data_lock, flags); + + if (!dirty && !shadow_dirty) { + r = 0; + break; + } + + /* 4 iterations is the worst case: + * 1 - initial iteration, dirty = true (between VFP and VSYNC) + * 2 - first VSYNC, dirty = true + * 3 - dirty = false, shadow_dirty = true + * 4 - shadow_dirty = false */ + if (i++ == 3) { + DSSERR("ovl(%d)->wait_for_go() not finishing\n", + ovl->id); + r = 0; + break; + } + + r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); + if (r == -ERESTARTSYS) + break; + + if (r) { + DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); + break; + } + } + + return r; +} + +static void dss_ovl_write_regs(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + struct omap_overlay_info *oi; + bool ilace, replication; + struct mgr_priv_data *mp; + int r; + + DSSDBGF("%d", ovl->id); + + if (!op->enabled || !op->info_dirty) + return; + + oi = &op->info; + + replication = dss_use_replication(ovl->manager->device, oi->color_mode); + + ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC; + + r = dispc_ovl_setup(ovl->id, oi, ilace, replication); + if (r) { + /* + * We can't do much here, as this function can be called from + * vsync interrupt. + */ + DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id); + + /* This will leave fifo configurations in a nonoptimal state */ + op->enabled = false; + dispc_ovl_enable(ovl->id, false); + return; + } + + mp = get_mgr_priv(ovl->manager); + + op->info_dirty = false; + if (mp->updating) + op->shadow_info_dirty = true; +} + +static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + struct mgr_priv_data *mp; + + DSSDBGF("%d", ovl->id); + + if (!op->extra_info_dirty) + return; + + /* note: write also when op->enabled == false, so that the ovl gets + * disabled */ + + dispc_ovl_enable(ovl->id, op->enabled); + dispc_ovl_set_channel_out(ovl->id, op->channel); + dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); + + mp = get_mgr_priv(ovl->manager); + + op->extra_info_dirty = false; + if (mp->updating) + op->shadow_extra_info_dirty = true; +} + +static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + struct omap_overlay *ovl; + + DSSDBGF("%d", mgr->id); + + if (!mp->enabled) + return; + + WARN_ON(mp->busy); + + /* Commit overlay settings */ + list_for_each_entry(ovl, &mgr->overlays, list) { + dss_ovl_write_regs(ovl); + dss_ovl_write_regs_extra(ovl); + } + + if (mp->info_dirty) { + dispc_mgr_setup(mgr->id, &mp->info); + + mp->info_dirty = false; + if (mp->updating) + mp->shadow_info_dirty = true; + } +} + +static void dss_write_regs(void) +{ + const int num_mgrs = omap_dss_get_num_overlay_managers(); + int i; + + for (i = 0; i < num_mgrs; ++i) { + struct omap_overlay_manager *mgr; + struct mgr_priv_data *mp; + int r; + + mgr = omap_dss_get_overlay_manager(i); + mp = get_mgr_priv(mgr); + + if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) + continue; + + r = dss_check_settings(mgr, mgr->device); + if (r) { + DSSERR("cannot write registers for manager %s: " + "illegal configuration\n", mgr->name); + continue; + } + + dss_mgr_write_regs(mgr); + } +} + +static void dss_set_go_bits(void) +{ + const int num_mgrs = omap_dss_get_num_overlay_managers(); + int i; + + for (i = 0; i < num_mgrs; ++i) { + struct omap_overlay_manager *mgr; + struct mgr_priv_data *mp; + + mgr = omap_dss_get_overlay_manager(i); + mp = get_mgr_priv(mgr); + + if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) + continue; + + if (!need_go(mgr)) + continue; + + mp->busy = true; + + if (!dss_data.irq_enabled && need_isr()) + dss_register_vsync_isr(); + + dispc_mgr_go(mgr->id); + } + +} + +void dss_mgr_start_update(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; + int r; + + spin_lock_irqsave(&data_lock, flags); + + WARN_ON(mp->updating); + + r = dss_check_settings(mgr, mgr->device); + if (r) { + DSSERR("cannot start manual update: illegal configuration\n"); + spin_unlock_irqrestore(&data_lock, flags); + return; + } + + dss_mgr_write_regs(mgr); + + mp->updating = true; + + if (!dss_data.irq_enabled && need_isr()) + dss_register_vsync_isr(); + + dispc_mgr_enable(mgr->id, true); + + spin_unlock_irqrestore(&data_lock, flags); +} + +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(); + u32 mask; + int r, i; + + mask = 0; + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_vsync_irq(i); + + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_framedone_irq(i); + + r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); + WARN_ON(r); + + dss_data.irq_enabled = true; +} + +static void dss_unregister_vsync_isr(void) +{ + const int num_mgrs = dss_feat_get_num_mgrs(); + u32 mask; + int r, i; + + mask = 0; + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_vsync_irq(i); + + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_framedone_irq(i); + + r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask); + WARN_ON(r); + + dss_data.irq_enabled = false; +} + +static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) +{ + struct omap_overlay *ovl; + struct mgr_priv_data *mp; + struct ovl_priv_data *op; + + mp = get_mgr_priv(mgr); + mp->shadow_info_dirty = false; + + list_for_each_entry(ovl, &mgr->overlays, list) { + op = get_ovl_priv(ovl); + op->shadow_info_dirty = false; + op->shadow_extra_info_dirty = false; + } +} + +static void dss_apply_irq_handler(void *data, u32 mask) +{ + const int num_mgrs = dss_feat_get_num_mg |