Search
SailfishOS Open Build Service
>
Projects
>
home:dcthang:branches:nemo:devel:hw:ti:omap3:n900
>
kernel-adaptation-n900
> linux-2.6-DSS2-patches.patch
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File linux-2.6-DSS2-patches.patch of Package kernel-adaptation-n900
From 6e09be6ecac390787aca38493db21cf1b9df756e Mon Sep 17 00:00:00 2001 From: Ilkka Koskinen <ilkka.koskinen@nokia.com> Date: Thu, 27 Jan 2011 14:57:27 +0200 Subject: [PATCH 37/42] DSS2 patches Consists of the following patches: 75b41a20b0afeb4dd8fee3a43dbe11d5fbe34d38 OMAP: DSS2: Fix notifiers when swapping managers ab01d99f8c1a13cee8f5ec190510be0fb8891937 OMAP: DSS2: Rename pending_notify to requested_events 14f79f34246c0550c4827f29f5879a51e613d320 OMAP: DSS2: Implement update notify for manual update display 4b59f2b284da06ec47d1b65ae08c18c00b3eca0f OMAP: DSS2: Implement support for more notification types. e0ae3eb3aaa8ff6abc664a45e29814e8b8db1d3d OMAP: DSS2: use atomic notifiers 6308d1897ca03d511b0175c57333fed352e4284c OMAP: DSS2: return error values down to caller 7cad62ff19fda5289b5693c8a2296bb944f01006 OMAP: DSS2: Rename notify_go to notify 4a037a2c0d3f04a4af9e418eeeacf497ec2421b9 OMAP: DSS2: Use GO notifiers for wait_for_go() b628480b180796ffa4f1a9d942e762d880d1e4d5 OMAP: DSS2: Add GO notifiers 82040c1e1f6747c3bf2bd228febc28cec44f6532 OMAP: DSS2: in_use flag for dss_cache 3bc782b2ed39f21fb406e38fdd31fd0e86e21718 OMAP: DSS2: Keep track whether overlay managers are enabled 7dbff8d6800f1af3bdd277c0cf4b398f993a20c2 OMAP: DSS2: Use spin_lock_irqsave/unlock_irqrestore in apply irq handler --- arch/arm/plat-omap/include/plat/display.h | 55 +++ drivers/video/omap2/dss/dss.h | 2 + drivers/video/omap2/dss/manager.c | 531 ++++++++++++++++++++++------- drivers/video/omap2/dss/overlay.c | 7 + 4 files changed, 470 insertions(+), 125 deletions(-) diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index c915a66..488890e 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h @@ -23,6 +23,7 @@ #include <linux/list.h> #include <linux/kobject.h> #include <linux/device.h> +#include <linux/notifier.h> #include <asm/atomic.h> #define DISPC_IRQ_FRAMEDONE (1 << 0) @@ -166,6 +167,48 @@ enum omap_overlay_manager_caps { OMAP_DSS_OVL_MGR_CAP_DISPC = 1 << 0, }; +/** + * Go event is triggered when all dss caches are clean (including shadow + * registers). + * + * This is used in xserver xv implementation to block writing to overlay until + * dss has completed reading same memory area. + * + * Example use in xv: + * If there is manual update triggered by gfx overlay first wait_for_go() + * doesn't block but wait_gfx() would block. + ** Frame 5 to first "buffer" + * wait_for_go() + * fill frame + * pan to first "buffer" + * update_window() for frame 1 + * request update notify + ** Frame 6 to second "buffer" (wait_gfx() would block here) + * wait_for_go() + * fill frame + * pan to second "buffer" + ** Frame 7 to first "buffer" + * wait_for_go() blocking + * First update completes + * wait_for_go() returns + * update notify arrives + * update_window() for frame 2 + * fill frame + * pan to third frame + * + * Update event is sent when manual update completes. Update event is not + * available for automatic update displays (returns -EINVAL). + */ +enum omap_dss_notify_event { + OMAP_DSS_NOTIFY_NONE = 0 << 0, + OMAP_DSS_NOTIFY_GO_MGR = 1 << 0, + OMAP_DSS_NOTIFY_UPDATE_MGR = 2 << 0, + OMAP_DSS_NOTIFY_MASK_MGR = 3 << 0, + OMAP_DSS_NOTIFY_GO_OVL = 1 << 2, + OMAP_DSS_NOTIFY_UPDATE_OVL = 2 << 2, + OMAP_DSS_NOTIFY_MASK_OVL = 3 << 2, +}; + /* RFBI */ struct rfbi_timings { @@ -297,6 +340,8 @@ struct omap_overlay { struct omap_overlay_info *info); int (*wait_for_go)(struct omap_overlay *ovl); + int (*notify)(struct omap_overlay *ovl, + enum omap_dss_notify_event events); }; struct omap_overlay_manager_info { @@ -340,6 +385,8 @@ struct omap_overlay_manager { int (*apply)(struct omap_overlay_manager *mgr); int (*wait_for_go)(struct omap_overlay_manager *mgr); + int (*notify)(struct omap_overlay_manager *mgr, + enum omap_dss_notify_event events); int (*wait_for_vsync)(struct omap_overlay_manager *mgr); int (*enable)(struct omap_overlay_manager *mgr); @@ -510,10 +557,18 @@ struct omap_overlay_manager *omap_dss_get_overlay_manager(int num); int omap_dss_get_num_overlays(void); struct omap_overlay *omap_dss_get_overlay(int num); +void omap_dss_lock_cache(void); +void omap_dss_unlock_cache(void); + void omapdss_default_get_resolution(struct omap_dss_device *dssdev, u16 *xres, u16 *yres); int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev); +int omap_dss_register_notifier(struct notifier_block *nb); +int omap_dss_unregister_notifier(struct notifier_block *nb); + +int omap_dss_request_notify(enum omap_dss_notify_event event, long value); + typedef void (*omap_dispc_isr_t) (void *arg, u32 mask); int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask); int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 5c7940d..8d14d94 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -198,6 +198,8 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane, int dss_init_overlay_managers(struct platform_device *pdev); void dss_uninit_overlay_managers(struct platform_device *pdev); int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); +int dss_mgr_notify_ovl(struct omap_overlay *ovl, + enum omap_dss_notify_event events); void dss_setup_partial_planes(struct omap_dss_device *dssdev, u16 *x, u16 *y, u16 *w, u16 *h, bool enlarge_update_area); diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 545e9b9..a66579c 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -25,6 +25,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/notifier.h> #include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/jiffies.h> @@ -416,6 +417,8 @@ struct overlay_cache_data { u32 fifo_high; bool manual_update; + + enum omap_dss_notify_event requested_events; }; struct manager_cache_data { @@ -427,6 +430,8 @@ struct manager_cache_data { * VSYNC/EVSYNC */ bool shadow_dirty; + bool enabled; + u32 default_color; enum omap_dss_trans_key_type trans_key_type; @@ -445,8 +450,13 @@ struct manager_cache_data { /* enlarge the update area if the update area contains scaled * overlays */ bool enlarge_update_area; + bool in_use; + + enum omap_dss_notify_event requested_events; }; +static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr); + static struct { spinlock_t lock; struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS]; @@ -455,7 +465,156 @@ static struct { bool irq_enabled; } dss_cache; +static ATOMIC_NOTIFIER_HEAD(dss_notifier_list); +static int dss_notifier_call_chain(unsigned long val, void *v) +{ + return atomic_notifier_call_chain(&dss_notifier_list, val, v); +} + +/** + * Check from events which should be fired now. + * + * @return: list of events that should fire now. + */ +static enum omap_dss_notify_event dss_mgr_notify_check( + struct omap_overlay_manager *mgr, + struct manager_cache_data *mc, + enum omap_dss_notify_event events) +{ + if (mc->manual_update) { + if (mc->enabled && mc->in_use && mgr->info_dirty) + events &= ~OMAP_DSS_NOTIFY_GO_MGR; + + if (mc->enabled && mc->in_use) + events &= ~OMAP_DSS_NOTIFY_UPDATE_MGR; + } else { + if (mc->enabled && (mc->dirty || mc->shadow_dirty)) + events = OMAP_DSS_NOTIFY_NONE; + } + + return events; +} + +static enum omap_dss_notify_event dss_mgr_notify_check_ovl( + struct omap_overlay *ovl, + struct overlay_cache_data *oc, + struct manager_cache_data *mc, + enum omap_dss_notify_event events) +{ + if (mc->manual_update) { + if (mc->enabled && oc->enabled + && mc->in_use && ovl->info_dirty) + events &= ~OMAP_DSS_NOTIFY_GO_OVL; + + if (mc->enabled && oc->enabled && mc->in_use) + events &= ~OMAP_DSS_NOTIFY_UPDATE_OVL; + } else { + if (mc->enabled && oc->enabled + && (oc->dirty || oc->shadow_dirty)) + events = OMAP_DSS_NOTIFY_NONE; + } + + return events; +} + +static enum omap_dss_notify_event check_mgr_notify( + struct omap_overlay_manager *mgr) +{ + struct manager_cache_data *mc; + + if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC)) + return OMAP_DSS_NOTIFY_NONE; + + mc = &dss_cache.manager_cache[mgr->id]; + + if (mc->requested_events == OMAP_DSS_NOTIFY_NONE) + return OMAP_DSS_NOTIFY_NONE; + + return dss_mgr_notify_check(mgr, mc, mc->requested_events); +} + +static enum omap_dss_notify_event check_ovl_notify( + struct omap_overlay *ovl) +{ + struct overlay_cache_data *oc; + struct manager_cache_data *mc; + + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) + return OMAP_DSS_NOTIFY_NONE; + + oc = &dss_cache.overlay_cache[ovl->id]; + + if (!ovl->manager) + return oc->requested_events; + + mc = &dss_cache.manager_cache[ovl->manager->id]; + + if (oc->requested_events == OMAP_DSS_NOTIFY_NONE) + return OMAP_DSS_NOTIFY_NONE; + + return dss_mgr_notify_check_ovl(ovl, oc, mc, oc->requested_events); +} + +static void dss_run_notifiers(void) +{ + struct overlay_cache_data *oc; + struct manager_cache_data *mc; + int i; + struct omap_overlay_manager *mgr; + struct omap_overlay *ovl; + enum omap_dss_notify_event events; + + list_for_each_entry(mgr, &manager_list, list) { + events = check_mgr_notify(mgr); + if (events == OMAP_DSS_NOTIFY_NONE) + continue; + + mc = &dss_cache.manager_cache[mgr->id]; + + mc->requested_events &= ~events; + + dss_notifier_call_chain(events, + (void *)(long)mgr->id); + } + + for (i = 0; i < omap_dss_get_num_overlays(); ++i) { + ovl = omap_dss_get_overlay(i); + + events = check_ovl_notify(ovl); + if (events == OMAP_DSS_NOTIFY_NONE) + continue; + + oc = &dss_cache.overlay_cache[ovl->id]; + + oc->requested_events &= ~events; + + dss_notifier_call_chain(events, + (void *)(long)ovl->id); + } +} + +void omap_dss_lock_cache(void) +{ + unsigned long flags; + spin_lock_irqsave(&dss_cache.lock, flags); + BUG_ON(dss_cache.manager_cache[0].in_use); + dss_cache.manager_cache[0].in_use = true; + spin_unlock_irqrestore(&dss_cache.lock, flags); +} +EXPORT_SYMBOL(omap_dss_lock_cache); + +void omap_dss_unlock_cache(void) +{ + unsigned long flags; + spin_lock_irqsave(&dss_cache.lock, flags); + BUG_ON(!dss_cache.manager_cache[0].in_use); + dss_cache.manager_cache[0].in_use = false; + dss_run_notifiers(); + spin_unlock_irqrestore(&dss_cache.lock, flags); + omap_dss_mgr_apply(omap_dss_get_overlay_manager(0)); +} +EXPORT_SYMBOL(omap_dss_unlock_cache); static int omap_dss_set_device(struct omap_overlay_manager *mgr, struct omap_dss_device *dssdev) @@ -520,149 +679,89 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); } -static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) -{ - unsigned long timeout = msecs_to_jiffies(500); - struct manager_cache_data *mc; - enum omap_channel channel; - u32 irq; - int r; - int i; - struct omap_dss_device *dssdev = mgr->device; - - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return 0; - - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { - irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - channel = OMAP_DSS_CHANNEL_DIGIT; - } else { - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { - enum omap_dss_update_mode mode; - mode = dssdev->driver->get_update_mode(dssdev); - if (mode != OMAP_DSS_UPDATE_AUTO) - return 0; - - irq = DISPC_IRQ_FRAMEDONE; - } else { - irq = DISPC_IRQ_VSYNC; - } - channel = OMAP_DSS_CHANNEL_LCD; - } +struct dss_wait_notify_event { + enum omap_dss_notify_event event; + int id; + struct completion compl; + struct list_head list; +}; - mc = &dss_cache.manager_cache[mgr->id]; - i = 0; - while (1) { - unsigned long flags; - bool shadow_dirty, dirty; - - spin_lock_irqsave(&dss_cache.lock, flags); - dirty = mc->dirty; - shadow_dirty = mc->shadow_dirty; - spin_unlock_irqrestore(&dss_cache.lock, flags); - - if (!dirty && !shadow_dirty) { - r = 0; - break; - } +static struct { + struct notifier_block nb; + spinlock_t lock; + struct list_head list; +} dss_wait_notify; - /* 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; - } +static int dss_wait_notify_callback(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct dss_wait_notify_event *e; + unsigned long flags; - r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); - if (r == -ERESTARTSYS) - break; + spin_lock_irqsave(&dss_wait_notify.lock, flags); - if (r) { - DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); - break; - } + list_for_each_entry(e, &dss_wait_notify.list, list) { + if (!(event & e->event)) + continue; + if ((long)data != e->id) + continue; + complete(&e->compl); } - return r; + spin_unlock_irqrestore(&dss_wait_notify.lock, flags); + + return 0; } -int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) +static int dss_wait_notify_event(enum omap_dss_notify_event event, + int id) { unsigned long timeout = msecs_to_jiffies(500); - enum omap_channel channel; - struct overlay_cache_data *oc; - struct omap_dss_device *dssdev; - u32 irq; + struct dss_wait_notify_event e = { + .event = event, + .id = id, + }; + unsigned long flags; int r; - int i; - if (!ovl->manager) - return 0; + init_completion(&e.compl); - dssdev = ovl->manager->device; + spin_lock_irqsave(&dss_wait_notify.lock, flags); + list_add_tail(&e.list, &dss_wait_notify.list); + spin_unlock_irqrestore(&dss_wait_notify.lock, flags); - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return 0; + r = omap_dss_request_notify(event, id); + if (r) + goto list_remove; - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { - irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - channel = OMAP_DSS_CHANNEL_DIGIT; - } else { - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { - enum omap_dss_update_mode mode; - mode = dssdev->driver->get_update_mode(dssdev); - if (mode != OMAP_DSS_UPDATE_AUTO) - return 0; + r = wait_for_completion_interruptible_timeout(&e.compl, timeout); + if (!r) + r = -ETIMEDOUT; - irq = DISPC_IRQ_FRAMEDONE; - } else { - irq = DISPC_IRQ_VSYNC; - } - channel = OMAP_DSS_CHANNEL_LCD; - } + list_remove: + spin_lock_irqsave(&dss_wait_notify.lock, flags); + list_del(&e.list); + spin_unlock_irqrestore(&dss_wait_notify.lock, flags); - oc = &dss_cache.overlay_cache[ovl->id]; - i = 0; - while (1) { - unsigned long flags; - bool shadow_dirty, dirty; - - spin_lock_irqsave(&dss_cache.lock, flags); - dirty = oc->dirty; - shadow_dirty = oc->shadow_dirty; - spin_unlock_irqrestore(&dss_cache.lock, flags); - - if (!dirty && !shadow_dirty) { - r = 0; - break; - } + return r < 0 ? r : 0; +} - /* 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; - } +static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) +{ + int r = dss_wait_notify_event(OMAP_DSS_NOTIFY_GO_MGR, mgr->id); - r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); - if (r == -ERESTARTSYS) - break; + if (r == -ETIMEDOUT) + DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); - if (r) { - DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); - break; - } - } + return r; +} + +int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) +{ + int r = dss_wait_notify_event(OMAP_DSS_NOTIFY_GO_OVL, ovl->id); + + if (r == -ETIMEDOUT) + DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); return r; } @@ -983,6 +1082,146 @@ static void make_even(u16 *x, u16 *w) *w = x2 - x1; } +static int dss_mgr_notify(struct omap_overlay_manager *mgr, + enum omap_dss_notify_event events) +{ + struct manager_cache_data *mc; + const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache); + unsigned long flags; + enum omap_dss_notify_event fire_events = OMAP_DSS_NOTIFY_NONE; + struct omap_dss_device *dssdev = mgr->device; + int r = 0; + + if (mgr->id >= num_mgrs) + return -EINVAL; + + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { + dss_notifier_call_chain(events, + (void *)(long)mgr->id); + return 0; + } + + spin_lock_irqsave(&dss_cache.lock, flags); + + mc = &dss_cache.manager_cache[mgr->id]; + + if (!mc->manual_update && (events & OMAP_DSS_NOTIFY_UPDATE_MGR)) { + r = -EINVAL; + goto err_out; + } + + fire_events = dss_mgr_notify_check(mgr, mc, events); + + mc->requested_events |= events & ~fire_events; + +err_out: + spin_unlock_irqrestore(&dss_cache.lock, flags); + + if (fire_events != OMAP_DSS_NOTIFY_NONE) + dss_notifier_call_chain(fire_events, + (void *)(long)mgr->id); + + return r; +} + +int dss_mgr_notify_ovl(struct omap_overlay *ovl, + enum omap_dss_notify_event events) +{ + struct overlay_cache_data *oc; + struct manager_cache_data *mc; + const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache); + unsigned long flags; + enum omap_dss_notify_event fire_events = OMAP_DSS_NOTIFY_NONE; + struct omap_dss_device *dssdev; + int r = 0; + + if (ovl->id >= num_ovls) + return -EINVAL; + + if (!ovl->manager) { + dss_notifier_call_chain(events, + (void *)(long)ovl->id); + return 0; + } + + dssdev = ovl->manager->device; + + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { + dss_notifier_call_chain(events, + (void *)(long)ovl->id); + return 0; + } + + spin_lock_irqsave(&dss_cache.lock, flags); + + oc = &dss_cache.overlay_cache[ovl->id]; + mc = &dss_cache.manager_cache[ovl->manager->id]; + + if (!mc->manual_update && (events & OMAP_DSS_NOTIFY_UPDATE_OVL)) { + r = -EINVAL; + goto err_out; + } + + fire_events = dss_mgr_notify_check_ovl(ovl, oc, mc, events); + + oc->requested_events |= events & ~fire_events; + +err_out: + spin_unlock_irqrestore(&dss_cache.lock, flags); + + if (fire_events != OMAP_DSS_NOTIFY_NONE) + dss_notifier_call_chain(fire_events, + (void *)(long)ovl->id); + + return r; +} + +int omap_dss_request_notify(enum omap_dss_notify_event events, + long value) +{ + int r; + struct omap_overlay_manager *mgr; + struct omap_overlay *ovl; + + if (events & ~(OMAP_DSS_NOTIFY_MASK_MGR | OMAP_DSS_NOTIFY_MASK_OVL)) + return -EINVAL; + + if (events & OMAP_DSS_NOTIFY_MASK_MGR) { + mgr = omap_dss_get_overlay_manager(value); + if (!mgr) + return -EINVAL; + if (!mgr->notify) + return -ENOSYS; + r = mgr->notify(mgr, events & OMAP_DSS_NOTIFY_MASK_MGR); + if (r) + return r; + } + if (events & OMAP_DSS_NOTIFY_MASK_OVL) { + ovl = omap_dss_get_overlay(value); + if (!ovl) + return -EINVAL; + if (!ovl->notify) + return -ENOSYS; + r = ovl->notify(ovl, events & OMAP_DSS_NOTIFY_MASK_OVL); + if (r) + return r; + } + return 0; +} +EXPORT_SYMBOL(omap_dss_request_notify); + +int omap_dss_register_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&dss_notifier_list, nb); +} +EXPORT_SYMBOL(omap_dss_register_notifier); + +int omap_dss_unregister_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&dss_notifier_list, nb); +} +EXPORT_SYMBOL(omap_dss_unregister_notifier); + /* Configure dispc for partial update. Return possibly modified update * area */ void dss_setup_partial_planes(struct omap_dss_device *dssdev, @@ -1156,11 +1395,12 @@ static void dss_apply_irq_handler(void *data, u32 mask) const int num_mgrs = dss_feat_get_num_mgrs(); int i, r; bool mgr_busy[MAX_DSS_MANAGERS]; + unsigned long flags; mgr_busy[0] = dispc_go_busy(0); mgr_busy[1] = dispc_go_busy(1); - spin_lock(&dss_cache.lock); + spin_lock_irqsave(&dss_cache.lock, flags); for (i = 0; i < num_ovls; ++i) { oc = &dss_cache.overlay_cache[i]; @@ -1195,7 +1435,8 @@ static void dss_apply_irq_handler(void *data, u32 mask) dss_cache.irq_enabled = false; end: - spin_unlock(&dss_cache.lock); + dss_run_notifiers(); + spin_unlock_irqrestore(&dss_cache.lock, flags); } static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) @@ -1223,6 +1464,12 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) continue; oc = &dss_cache.overlay_cache[ovl->id]; + if (ovl->manager) { + mc = &dss_cache.manager_cache[ovl->manager->id]; + + if (mc->in_use) + continue; + } if (!overlay_enabled(ovl)) { if (oc->enabled) { @@ -1292,6 +1539,9 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) mc = &dss_cache.manager_cache[mgr->id]; + if (mc->in_use) + continue; + if (mgr->device_changed) { mgr->device_changed = false; mgr->info_dirty = true; @@ -1350,6 +1600,13 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) oc = &dss_cache.overlay_cache[ovl->id]; + if (ovl->manager) { + mc = &dss_cache.manager_cache[ovl->manager->id]; + + if (mc->in_use) + continue; + } + if (!oc->enabled) continue; @@ -1436,13 +1693,29 @@ static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr, static int dss_mgr_enable(struct omap_overlay_manager *mgr) { + struct manager_cache_data *mc = &dss_cache.manager_cache[mgr->id]; + unsigned long flags; + + spin_lock_irqsave(&dss_cache.lock, flags); + mc->enabled = true; + spin_unlock_irqrestore(&dss_cache.lock, flags); + dispc_enable_channel(mgr->id, 1); return 0; } static int dss_mgr_disable(struct omap_overlay_manager *mgr) { + struct manager_cache_data *mc = &dss_cache.manager_cache[mgr->id]; + unsigned long flags; + dispc_enable_channel(mgr->id, 0); + + spin_lock_irqsave(&dss_cache.lock, flags); + mc->enabled = false; + dss_run_notifiers(); + spin_unlock_irqrestore(&dss_cache.lock, flags); + return 0; } @@ -1458,6 +1731,11 @@ int dss_init_overlay_managers(struct platform_device *pdev) spin_lock_init(&dss_cache.lock); + spin_lock_init(&dss_wait_notify.lock); + INIT_LIST_HEAD(&dss_wait_notify.list); + dss_wait_notify.nb.notifier_call = dss_wait_notify_callback; + omap_dss_register_notifier(&dss_wait_notify.nb); + INIT_LIST_HEAD(&manager_list); num_managers = 0; @@ -1485,6 +1763,7 @@ int dss_init_overlay_managers(struct platform_device *pdev) mgr->set_manager_info = &omap_dss_mgr_set_info; mgr->get_manager_info = &omap_dss_mgr_get_info; mgr->wait_for_go = &dss_mgr_wait_for_go; + mgr->notify = &dss_mgr_notify; mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; mgr->enable = &dss_mgr_enable; @@ -1559,6 +1838,8 @@ void dss_uninit_overlay_managers(struct platform_device *pdev) kfree(mgr); } + omap_dss_unregister_notifier(&dss_wait_notify.nb); + num_managers = 0; } diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 75642c2..aa1dc56 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -430,6 +430,12 @@ static int dss_ovl_wait_for_go(struct omap_overlay *ovl) return dss_mgr_wait_for_go_ovl(ovl); } +static int dss_ovl_notify(struct omap_overlay *ovl, + enum omap_dss_notify_event events) +{ + return dss_mgr_notify_ovl(ovl, events); +} + static int omap_dss_set_manager(struct omap_overlay *ovl, struct omap_overlay_manager *mgr) { @@ -571,6 +577,7 @@ void dss_init_overlays(struct platform_device *pdev) ovl->set_overlay_info = &dss_ovl_set_overlay_info; ovl->get_overlay_info = &dss_ovl_get_overlay_info; ovl->wait_for_go = &dss_ovl_wait_for_go; + ovl->notify = &dss_ovl_notify; ovl->supported_modes = dss_feat_get_supported_color_modes(ovl->id); -- 1.7.0.4