diff --git a/arm-omapdrm-fixinc.patch b/arm-omapdrm-fixinc.patch deleted file mode 100644 index 6892655eb..000000000 --- a/arm-omapdrm-fixinc.patch +++ /dev/null @@ -1,2767 +0,0 @@ ---- linux-3.8.0-0.rc2.git1.1.fc19.x86_64/arch/arm/mach-omap2/drm.c.orig 2013-01-07 12:31:44.014857064 +0000 -+++ linux-3.8.0-0.rc2.git1.1.fc19.x86_64/arch/arm/mach-omap2/drm.c 2013-01-07 12:33:33.570861903 +0000 -@@ -27,6 +27,7 @@ - - #include "omap_device.h" - #include "omap_hwmod.h" -+#include "soc.h" - - #if defined(CONFIG_DRM_OMAP) || (CONFIG_DRM_OMAP_MODULE) - -@@ -56,7 +57,7 @@ - oh->name); - } - -- platform_data.omaprev = GET_OMAP_REVISION(); -+ platform_data.omaprev = GET_OMAP_TYPE; - - return platform_device_register(&omap_drm_device); - -diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile -index 1ca0e00..d85e058 100644 ---- a/drivers/staging/omapdrm/Makefile -+++ b/drivers/staging/omapdrm/Makefile -@@ -5,6 +5,7 @@ - - ccflags-y := -Iinclude/drm -Werror - omapdrm-y := omap_drv.o \ -+ omap_irq.o \ - omap_debugfs.o \ - omap_crtc.o \ - omap_plane.o \ -diff --git a/drivers/staging/omapdrm/TODO b/drivers/staging/omapdrm/TODO -index 938c788..abeeb00 100644 ---- a/drivers/staging/omapdrm/TODO -+++ b/drivers/staging/omapdrm/TODO -@@ -17,9 +17,6 @@ TODO - . Revisit GEM sync object infrastructure.. TTM has some framework for this - already. Possibly this could be refactored out and made more common? - There should be some way to do this with less wheel-reinvention. --. Review DSS vs KMS mismatches. The omap_dss_device is sort of part encoder, -- part connector. Which results in a bit of duct tape to fwd calls from -- encoder to connector. Possibly this could be done a bit better. - . Solve PM sequencing on resume. DMM/TILER must be reloaded before any - access is made from any component in the system. Which means on suspend - CRTC's should be disabled, and on resume the LUT should be reprogrammed -diff --git a/drivers/staging/omapdrm/omap_connector.c b/drivers/staging/omapdrm/omap_connector.c -index 91edb3f..4cc9ee7 100644 ---- a/drivers/staging/omapdrm/omap_connector.c -+++ b/drivers/staging/omapdrm/omap_connector.c -@@ -31,9 +31,10 @@ - struct omap_connector { - struct drm_connector base; - struct omap_dss_device *dssdev; -+ struct drm_encoder *encoder; - }; - --static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode, -+void copy_timings_omap_to_drm(struct drm_display_mode *mode, - struct omap_video_timings *timings) - { - mode->clock = timings->pixel_clock; -@@ -64,7 +65,7 @@ static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode, - mode->flags |= DRM_MODE_FLAG_NVSYNC; - } - --static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, -+void copy_timings_drm_to_omap(struct omap_video_timings *timings, - struct drm_display_mode *mode) - { - timings->pixel_clock = mode->clock; -@@ -96,48 +97,7 @@ static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, - timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; - } - --static void omap_connector_dpms(struct drm_connector *connector, int mode) --{ -- struct omap_connector *omap_connector = to_omap_connector(connector); -- struct omap_dss_device *dssdev = omap_connector->dssdev; -- int old_dpms; -- -- DBG("%s: %d", dssdev->name, mode); -- -- old_dpms = connector->dpms; -- -- /* from off to on, do from crtc to connector */ -- if (mode < old_dpms) -- drm_helper_connector_dpms(connector, mode); -- -- if (mode == DRM_MODE_DPMS_ON) { -- /* store resume info for suspended displays */ -- switch (dssdev->state) { -- case OMAP_DSS_DISPLAY_SUSPENDED: -- dssdev->activate_after_resume = true; -- break; -- case OMAP_DSS_DISPLAY_DISABLED: { -- int ret = dssdev->driver->enable(dssdev); -- if (ret) { -- DBG("%s: failed to enable: %d", -- dssdev->name, ret); -- dssdev->driver->disable(dssdev); -- } -- break; -- } -- default: -- break; -- } -- } else { -- /* TODO */ -- } -- -- /* from on to off, do from connector to crtc */ -- if (mode > old_dpms) -- drm_helper_connector_dpms(connector, mode); --} -- --enum drm_connector_status omap_connector_detect( -+static enum drm_connector_status omap_connector_detect( - struct drm_connector *connector, bool force) - { - struct omap_connector *omap_connector = to_omap_connector(connector); -@@ -164,8 +124,6 @@ static void omap_connector_destroy(struct drm_connector *connector) - struct omap_connector *omap_connector = to_omap_connector(connector); - struct omap_dss_device *dssdev = omap_connector->dssdev; - -- dssdev->driver->disable(dssdev); -- - DBG("%s", omap_connector->dssdev->name); - drm_sysfs_connector_remove(connector); - drm_connector_cleanup(connector); -@@ -261,36 +219,12 @@ static int omap_connector_mode_valid(struct drm_connector *connector, - struct drm_encoder *omap_connector_attached_encoder( - struct drm_connector *connector) - { -- int i; - struct omap_connector *omap_connector = to_omap_connector(connector); -- -- for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { -- struct drm_mode_object *obj; -- -- if (connector->encoder_ids[i] == 0) -- break; -- -- obj = drm_mode_object_find(connector->dev, -- connector->encoder_ids[i], -- DRM_MODE_OBJECT_ENCODER); -- -- if (obj) { -- struct drm_encoder *encoder = obj_to_encoder(obj); -- struct omap_overlay_manager *mgr = -- omap_encoder_get_manager(encoder); -- DBG("%s: found %s", omap_connector->dssdev->name, -- mgr->name); -- return encoder; -- } -- } -- -- DBG("%s: no encoder", omap_connector->dssdev->name); -- -- return NULL; -+ return omap_connector->encoder; - } - - static const struct drm_connector_funcs omap_connector_funcs = { -- .dpms = omap_connector_dpms, -+ .dpms = drm_helper_connector_dpms, - .detect = omap_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = omap_connector_destroy, -@@ -302,34 +236,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = { - .best_encoder = omap_connector_attached_encoder, - }; - --/* called from encoder when mode is set, to propagate settings to the dssdev */ --void omap_connector_mode_set(struct drm_connector *connector, -- struct drm_display_mode *mode) --{ -- struct drm_device *dev = connector->dev; -- struct omap_connector *omap_connector = to_omap_connector(connector); -- struct omap_dss_device *dssdev = omap_connector->dssdev; -- struct omap_dss_driver *dssdrv = dssdev->driver; -- struct omap_video_timings timings = {0}; -- -- copy_timings_drm_to_omap(&timings, mode); -- -- DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", -- omap_connector->dssdev->name, -- mode->base.id, mode->name, mode->vrefresh, mode->clock, -- mode->hdisplay, mode->hsync_start, -- mode->hsync_end, mode->htotal, -- mode->vdisplay, mode->vsync_start, -- mode->vsync_end, mode->vtotal, mode->type, mode->flags); -- -- if (dssdrv->check_timings(dssdev, &timings)) { -- dev_err(dev->dev, "could not set timings\n"); -- return; -- } -- -- dssdrv->set_timings(dssdev, &timings); --} -- - /* flush an area of the framebuffer (in case of manual update display that - * is not automatically flushed) - */ -@@ -344,7 +250,8 @@ void omap_connector_flush(struct drm_connector *connector, - - /* initialize connector */ - struct drm_connector *omap_connector_init(struct drm_device *dev, -- int connector_type, struct omap_dss_device *dssdev) -+ int connector_type, struct omap_dss_device *dssdev, -+ struct drm_encoder *encoder) - { - struct drm_connector *connector = NULL; - struct omap_connector *omap_connector; -@@ -360,6 +267,8 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, - } - - omap_connector->dssdev = dssdev; -+ omap_connector->encoder = encoder; -+ - connector = &omap_connector->base; - - drm_connector_init(dev, connector, &omap_connector_funcs, -diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c -index d87bd84..5c6ed60 100644 ---- a/drivers/staging/omapdrm/omap_crtc.c -+++ b/drivers/staging/omapdrm/omap_crtc.c -@@ -28,19 +28,131 @@ - struct omap_crtc { - struct drm_crtc base; - struct drm_plane *plane; -+ - const char *name; -- int id; -+ int pipe; -+ enum omap_channel channel; -+ struct omap_overlay_manager_info info; -+ -+ /* -+ * Temporary: eventually this will go away, but it is needed -+ * for now to keep the output's happy. (They only need -+ * mgr->id.) Eventually this will be replaced w/ something -+ * more common-panel-framework-y -+ */ -+ struct omap_overlay_manager mgr; -+ -+ struct omap_video_timings timings; -+ bool enabled; -+ bool full_update; -+ -+ struct omap_drm_apply apply; -+ -+ struct omap_drm_irq apply_irq; -+ struct omap_drm_irq error_irq; -+ -+ /* list of in-progress apply's: */ -+ struct list_head pending_applies; -+ -+ /* list of queued apply's: */ -+ struct list_head queued_applies; -+ -+ /* for handling queued and in-progress applies: */ -+ struct work_struct apply_work; - - /* if there is a pending flip, these will be non-null: */ - struct drm_pending_vblank_event *event; - struct drm_framebuffer *old_fb; -+ -+ /* for handling page flips without caring about what -+ * the callback is called from. Possibly we should just -+ * make omap_gem always call the cb from the worker so -+ * we don't have to care about this.. -+ * -+ * XXX maybe fold into apply_work?? -+ */ -+ struct work_struct page_flip_work; -+}; -+ -+/* -+ * Manager-ops, callbacks from output when they need to configure -+ * the upstream part of the video pipe. -+ * -+ * Most of these we can ignore until we add support for command-mode -+ * panels.. for video-mode the crtc-helpers already do an adequate -+ * job of sequencing the setup of the video pipe in the proper order -+ */ -+ -+/* we can probably ignore these until we support command-mode panels: */ -+static void omap_crtc_start_update(struct omap_overlay_manager *mgr) -+{ -+} -+ -+static int omap_crtc_enable(struct omap_overlay_manager *mgr) -+{ -+ return 0; -+} -+ -+static void omap_crtc_disable(struct omap_overlay_manager *mgr) -+{ -+} -+ -+static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, -+ const struct omap_video_timings *timings) -+{ -+ struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); -+ DBG("%s", omap_crtc->name); -+ omap_crtc->timings = *timings; -+ omap_crtc->full_update = true; -+} -+ -+static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr, -+ const struct dss_lcd_mgr_config *config) -+{ -+ struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); -+ DBG("%s", omap_crtc->name); -+ dispc_mgr_set_lcd_config(omap_crtc->channel, config); -+} -+ -+static int omap_crtc_register_framedone_handler( -+ struct omap_overlay_manager *mgr, -+ void (*handler)(void *), void *data) -+{ -+ return 0; -+} -+ -+static void omap_crtc_unregister_framedone_handler( -+ struct omap_overlay_manager *mgr, -+ void (*handler)(void *), void *data) -+{ -+} -+ -+static const struct dss_mgr_ops mgr_ops = { -+ .start_update = omap_crtc_start_update, -+ .enable = omap_crtc_enable, -+ .disable = omap_crtc_disable, -+ .set_timings = omap_crtc_set_timings, -+ .set_lcd_config = omap_crtc_set_lcd_config, -+ .register_framedone_handler = omap_crtc_register_framedone_handler, -+ .unregister_framedone_handler = omap_crtc_unregister_framedone_handler, - }; - -+/* -+ * CRTC funcs: -+ */ -+ - static void omap_crtc_destroy(struct drm_crtc *crtc) - { - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -+ -+ DBG("%s", omap_crtc->name); -+ -+ WARN_ON(omap_crtc->apply_irq.registered); -+ omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); -+ - omap_crtc->plane->funcs->destroy(omap_crtc->plane); - drm_crtc_cleanup(crtc); -+ - kfree(omap_crtc); - } - -@@ -48,14 +160,25 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) - { - struct omap_drm_private *priv = crtc->dev->dev_private; - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -+ bool enabled = (mode == DRM_MODE_DPMS_ON); - int i; - -- WARN_ON(omap_plane_dpms(omap_crtc->plane, mode)); -+ DBG("%s: %d", omap_crtc->name, mode); -+ -+ if (enabled != omap_crtc->enabled) { -+ omap_crtc->enabled = enabled; -+ omap_crtc->full_update = true; -+ omap_crtc_apply(crtc, &omap_crtc->apply); - -- for (i = 0; i < priv->num_planes; i++) { -- struct drm_plane *plane = priv->planes[i]; -- if (plane->crtc == crtc) -- WARN_ON(omap_plane_dpms(plane, mode)); -+ /* also enable our private plane: */ -+ WARN_ON(omap_plane_dpms(omap_crtc->plane, mode)); -+ -+ /* and any attached overlay planes: */ -+ for (i = 0; i < priv->num_planes; i++) { -+ struct drm_plane *plane = priv->planes[i]; -+ if (plane->crtc == crtc) -+ WARN_ON(omap_plane_dpms(plane, mode)); -+ } - } - } - -@@ -73,12 +196,26 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc, - struct drm_framebuffer *old_fb) - { - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -- struct drm_plane *plane = omap_crtc->plane; - -- return omap_plane_mode_set(plane, crtc, crtc->fb, -+ mode = adjusted_mode; -+ -+ DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", -+ omap_crtc->name, mode->base.id, mode->name, -+ mode->vrefresh, mode->clock, -+ mode->hdisplay, mode->hsync_start, -+ mode->hsync_end, mode->htotal, -+ mode->vdisplay, mode->vsync_start, -+ mode->vsync_end, mode->vtotal, -+ mode->type, mode->flags); -+ -+ copy_timings_drm_to_omap(&omap_crtc->timings, mode); -+ omap_crtc->full_update = true; -+ -+ return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, - 0, 0, mode->hdisplay, mode->vdisplay, - x << 16, y << 16, -- mode->hdisplay << 16, mode->vdisplay << 16); -+ mode->hdisplay << 16, mode->vdisplay << 16, -+ NULL, NULL); - } - - static void omap_crtc_prepare(struct drm_crtc *crtc) -@@ -102,10 +239,11 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_plane *plane = omap_crtc->plane; - struct drm_display_mode *mode = &crtc->mode; - -- return plane->funcs->update_plane(plane, crtc, crtc->fb, -+ return omap_plane_mode_set(plane, crtc, crtc->fb, - 0, 0, mode->hdisplay, mode->vdisplay, - x << 16, y << 16, -- mode->hdisplay << 16, mode->vdisplay << 16); -+ mode->hdisplay << 16, mode->vdisplay << 16, -+ NULL, NULL); - } - - static void omap_crtc_load_lut(struct drm_crtc *crtc) -@@ -114,63 +252,54 @@ static void omap_crtc_load_lut(struct drm_crtc *crtc) - - static void vblank_cb(void *arg) - { -- static uint32_t sequence; - struct drm_crtc *crtc = arg; - struct drm_device *dev = crtc->dev; - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -- struct drm_pending_vblank_event *event = omap_crtc->event; - unsigned long flags; -- struct timeval now; - -- WARN_ON(!event); -+ spin_lock_irqsave(&dev->event_lock, flags); -+ -+ /* wakeup userspace */ -+ if (omap_crtc->event) -+ drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event); - - omap_crtc->event = NULL; -+ omap_crtc->old_fb = NULL; - -- /* wakeup userspace */ -- if (event) { -- do_gettimeofday(&now); -- -- spin_lock_irqsave(&dev->event_lock, flags); -- /* TODO: we can't yet use the vblank time accounting, -- * because omapdss lower layer is the one that knows -- * the irq # and registers the handler, which more or -- * less defeats how drm_irq works.. for now just fake -- * the sequence number and use gettimeofday.. -- * -- event->event.sequence = drm_vblank_count_and_time( -- dev, omap_crtc->id, &now); -- */ -- event->event.sequence = sequence++; -- event->event.tv_sec = now.tv_sec; -- event->event.tv_usec = now.tv_usec; -- list_add_tail(&event->base.link, -- &event->base.file_priv->event_list); -- wake_up_interruptible(&event->base.file_priv->event_wait); -- spin_unlock_irqrestore(&dev->event_lock, flags); -- } -+ spin_unlock_irqrestore(&dev->event_lock, flags); - } - --static void page_flip_cb(void *arg) -+static void page_flip_worker(struct work_struct *work) - { -- struct drm_crtc *crtc = arg; -- struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -- struct drm_framebuffer *old_fb = omap_crtc->old_fb; -+ struct omap_crtc *omap_crtc = -+ container_of(work, struct omap_crtc, page_flip_work); -+ struct drm_crtc *crtc = &omap_crtc->base; -+ struct drm_device *dev = crtc->dev; -+ struct drm_display_mode *mode = &crtc->mode; - struct drm_gem_object *bo; - -- omap_crtc->old_fb = NULL; -- -- omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb); -- -- /* really we'd like to setup the callback atomically w/ setting the -- * new scanout buffer to avoid getting stuck waiting an extra vblank -- * cycle.. for now go for correctness and later figure out speed.. -- */ -- omap_plane_on_endwin(omap_crtc->plane, vblank_cb, crtc); -+ mutex_lock(&dev->mode_config.mutex); -+ omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, -+ 0, 0, mode->hdisplay, mode->vdisplay, -+ crtc->x << 16, crtc->y << 16, -+ mode->hdisplay << 16, mode->vdisplay << 16, -+ vblank_cb, crtc); -+ mutex_unlock(&dev->mode_config.mutex); - - bo = omap_framebuffer_bo(crtc->fb, 0); - drm_gem_object_unreference_unlocked(bo); - } - -+static void page_flip_cb(void *arg) -+{ -+ struct drm_crtc *crtc = arg; -+ struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -+ struct omap_drm_private *priv = crtc->dev->dev_private; -+ -+ /* avoid assumptions about what ctxt we are called from: */ -+ queue_work(priv->wq, &omap_crtc->page_flip_work); -+} -+ - static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event) -@@ -179,14 +308,14 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); - struct drm_gem_object *bo; - -- DBG("%d -> %d", crtc->fb ? crtc->fb->base.id : -1, fb->base.id); -+ DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1, -+ fb->base.id, event); - -- if (omap_crtc->event) { -+ if (omap_crtc->old_fb) { - dev_err(dev->dev, "already a pending flip\n"); - return -EINVAL; - } - -- omap_crtc->old_fb = crtc->fb; - omap_crtc->event = event; - crtc->fb = fb; - -@@ -234,14 +363,244 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { - .load_lut = omap_crtc_load_lut, - }; - -+const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc) -+{ -+ struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -+ return &omap_crtc->timings; -+} -+ -+enum omap_channel omap_crtc_channel(struct drm_crtc *crtc) -+{ -+ struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -+ return omap_crtc->channel; -+} -+ -+static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) -+{ -+ struct omap_crtc *omap_crtc = -+ container_of(irq, struct omap_crtc, error_irq); -+ struct drm_crtc *crtc = &omap_crtc->base; -+ DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus); -+ /* avoid getting in a flood, unregister the irq until next vblank */ -+ omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); -+} -+ -+static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus) -+{ -+ struct omap_crtc *omap_crtc = -+ container_of(irq, struct omap_crtc, apply_irq); -+ struct drm_crtc *crtc = &omap_crtc->base; -+ -+ if (!omap_crtc->error_irq.registered) -+ omap_irq_register(crtc->dev, &omap_crtc->error_irq); -+ -+ if (!dispc_mgr_go_busy(omap_crtc->channel)) { -+ struct omap_drm_private *priv = -+ crtc->dev->dev_private; -+ DBG("%s: apply done", omap_crtc->name); -+ omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq); -+ queue_work(priv->wq, &omap_crtc->apply_work); -+ } -+} -+ -+static void apply_worker(struct work_struct *work) -+{ -+ struct omap_crtc *omap_crtc = -+ container_of(work, struct omap_crtc, apply_work); -+ struct drm_crtc *crtc = &omap_crtc->base; -+ struct drm_device *dev = crtc->dev; -+ struct omap_drm_apply *apply, *n; -+ bool need_apply; -+ -+ /* -+ * Synchronize everything on mode_config.mutex, to keep -+ * the callbacks and list modification all serialized -+ * with respect to modesetting ioctls from userspace. -+ */ -+ mutex_lock(&dev->mode_config.mutex); -+ dispc_runtime_get(); -+ -+ /* -+ * If we are still pending a previous update, wait.. when the -+ * pending update completes, we get kicked again. -+ */ -+ if (omap_crtc->apply_irq.registered) -+ goto out; -+ -+ /* finish up previous apply's: */ -+ list_for_each_entry_safe(apply, n, -+ &omap_crtc->pending_applies, pending_node) { -+ apply->post_apply(apply); -+ list_del(&apply->pending_node); -+ } -+ -+ need_apply = !list_empty(&omap_crtc->queued_applies); -+ -+ /* then handle the next round of of queued apply's: */ -+ list_for_each_entry_safe(apply, n, -+ &omap_crtc->queued_applies, queued_node) { -+ apply->pre_apply(apply); -+ list_del(&apply->queued_node); -+ apply->queued = false; -+ list_add_tail(&apply->pending_node, -+ &omap_crtc->pending_applies); -+ } -+ -+ if (need_apply) { -+ enum omap_channel channel = omap_crtc->channel; -+ -+ DBG("%s: GO", omap_crtc->name); -+ -+ if (dispc_mgr_is_enabled(channel)) { -+ omap_irq_register(dev, &omap_crtc->apply_irq); -+ dispc_mgr_go(channel); -+ } else { -+ struct omap_drm_private *priv = dev->dev_private; -+ queue_work(priv->wq, &omap_crtc->apply_work); -+ } -+ } -+ -+out: -+ dispc_runtime_put(); -+ mutex_unlock(&dev->mode_config.mutex); -+} -+ -+int omap_crtc_apply(struct drm_crtc *crtc, -+ struct omap_drm_apply *apply) -+{ -+ struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -+ struct drm_device *dev = crtc->dev; -+ -+ WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); -+ -+ /* no need to queue it again if it is already queued: */ -+ if (apply->queued) -+ return 0; -+ -+ apply->queued = true; -+ list_add_tail(&apply->queued_node, &omap_crtc->queued_applies); -+ -+ /* -+ * If there are no currently pending updates, then go ahead and -+ * kick the worker immediately, otherwise it will run again when -+ * the current update finishes. -+ */ -+ if (list_empty(&omap_crtc->pending_applies)) { -+ struct omap_drm_private *priv = crtc->dev->dev_private; -+ queue_work(priv->wq, &omap_crtc->apply_work); -+ } -+ -+ return 0; -+} -+ -+/* called only from apply */ -+static void set_enabled(struct drm_crtc *crtc, bool enable) -+{ -+ struct drm_device *dev = crtc->dev; -+ struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -+ enum omap_channel channel = omap_crtc->channel; -+ struct omap_irq_wait *wait = NULL; -+ -+ if (dispc_mgr_is_enabled(channel) == enable) -+ return; -+ -+ /* ignore sync-lost irqs during enable/disable */ -+ omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); -+ -+ if (dispc_mgr_get_framedone_irq(channel)) { -+ if (!enable) { -+ wait = omap_irq_wait_init(dev, -+ dispc_mgr_get_framedone_irq(channel), 1); -+ } -+ } else { -+ /* -+ * When we disable digit output, we need to wait until fields -+ * are done. Otherwise the DSS is still working, and turning -+ * off the clocks prevents DSS from going to OFF mode. And when -+ * enabling, we need to wait for the extra sync losts -+ */ -+ wait = omap_irq_wait_init(dev, -+ dispc_mgr_get_vsync_irq(channel), 2); -+ } -+ -+ dispc_mgr_enable(channel, enable); -+ -+ if (wait) { -+ int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); -+ if (ret) { -+ dev_err(dev->dev, "%s: timeout waiting for %s\n", -+ omap_crtc->name, enable ? "enable" : "disable"); -+ } -+ } -+ -+ omap_irq_register(crtc->dev, &omap_crtc->error_irq); -+} -+ -+static void omap_crtc_pre_apply(struct omap_drm_apply *apply) -+{ -+ struct omap_crtc *omap_crtc = -+ container_of(apply, struct omap_crtc, apply); -+ struct drm_crtc *crtc = &omap_crtc->base; -+ struct drm_encoder *encoder = NULL; -+ -+ DBG("%s: enabled=%d, full=%d", omap_crtc->name, -+ omap_crtc->enabled, omap_crtc->full_update); -+ -+ if (omap_crtc->full_update) { -+ struct omap_drm_private *priv = crtc->dev->dev_private; -+ int i; -+ for (i = 0; i < priv->num_encoders; i++) { -+ if (priv->encoders[i]->crtc == crtc) { -+ encoder = priv->encoders[i]; -+ break; -+ } -+ } -+ } -+ -+ if (!omap_crtc->enabled) { -+ set_enabled(&omap_crtc->base, false); -+ if (encoder) -+ omap_encoder_set_enabled(encoder, false); -+ } else { -+ if (encoder) { -+ omap_encoder_set_enabled(encoder, false); -+ omap_encoder_update(encoder, &omap_crtc->mgr, -+ &omap_crtc->timings); -+ omap_encoder_set_enabled(encoder, true); -+ omap_crtc->full_update = false; -+ } -+ -+ dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); -+ dispc_mgr_set_timings(omap_crtc->channel, -+ &omap_crtc->timings); -+ set_enabled(&omap_crtc->base, true); -+ } -+ -+ omap_crtc->full_update = false; -+} -+ -+static void omap_crtc_post_apply(struct omap_drm_apply *apply) -+{ -+ /* nothing needed for post-apply */ -+} -+ -+static const char *channel_names[] = { -+ [OMAP_DSS_CHANNEL_LCD] = "lcd", -+ [OMAP_DSS_CHANNEL_DIGIT] = "tv", -+ [OMAP_DSS_CHANNEL_LCD2] = "lcd2", -+}; -+ - /* initialize crtc */ - struct drm_crtc *omap_crtc_init(struct drm_device *dev, -- struct omap_overlay *ovl, int id) -+ struct drm_plane *plane, enum omap_channel channel, int id) - { - struct drm_crtc *crtc = NULL; -- struct omap_crtc *omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); -+ struct omap_crtc *omap_crtc; -+ struct omap_overlay_manager_info *info; -+ -+ DBG("%s", channel_names[channel]); - -- DBG("%s", ovl->name); -+ omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); - - if (!omap_crtc) { - dev_err(dev->dev, "could not allocate CRTC\n"); -@@ -250,10 +609,40 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, - - crtc = &omap_crtc->base; - -- omap_crtc->plane = omap_plane_init(dev, ovl, (1 << id), true); -+ INIT_WORK(&omap_crtc->page_flip_work, page_flip_worker); -+ INIT_WORK(&omap_crtc->apply_work, apply_worker); -+ -+ INIT_LIST_HEAD(&omap_crtc->pending_applies); -+ INIT_LIST_HEAD(&omap_crtc->queued_applies); -+ -+ omap_crtc->apply.pre_apply = omap_crtc_pre_apply; -+ omap_crtc->apply.post_apply = omap_crtc_post_apply; -+ -+ omap_crtc->apply_irq.irqmask = pipe2vbl(id); -+ omap_crtc->apply_irq.irq = omap_crtc_apply_irq; -+ -+ omap_crtc->error_irq.irqmask = -+ dispc_mgr_get_sync_lost_irq(channel); -+ omap_crtc->error_irq.irq = omap_crtc_error_irq; -+ omap_irq_register(dev, &omap_crtc->error_irq); -+ -+ omap_crtc->channel = channel; -+ omap_crtc->plane = plane; - omap_crtc->plane->crtc = crtc; -- omap_crtc->name = ovl->name; -- omap_crtc->id = id; -+ omap_crtc->name = channel_names[channel]; -+ omap_crtc->pipe = id; -+ -+ /* temporary: */ -+ omap_crtc->mgr.id = channel; -+ -+ dss_install_mgr_ops(&mgr_ops); -+ -+ /* TODO: fix hard-coded setup.. add properties! */ -+ info = &omap_crtc->info; -+ info->default_color = 0x00000000; -+ info->trans_key = 0x00000000; -+ info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; -+ info->trans_enabled = false; - - drm_crtc_init(dev, crtc, &omap_crtc_funcs); - drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); -diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c -index 84943e5..ae5ecc2 100644 ---- a/drivers/staging/omapdrm/omap_drv.c -+++ b/drivers/staging/omapdrm/omap_drv.c -@@ -74,320 +74,99 @@ static int get_connector_type(struct omap_dss_device *dssdev) - } - } - --#if 0 /* enable when dss2 supports hotplug */ --static int omap_drm_notifier(struct notifier_block *nb, -- unsigned long evt, void *arg) --{ -- switch (evt) { -- case OMAP_DSS_SIZE_CHANGE: -- case OMAP_DSS_HOTPLUG_CONNECT: -- case OMAP_DSS_HOTPLUG_DISCONNECT: { -- struct drm_device *dev = drm_device; -- DBG("hotplug event: evt=%d, dev=%p", evt, dev); -- if (dev) -- drm_sysfs_hotplug_event(dev); -- -- return NOTIFY_OK; -- } -- default: /* don't care about other events for now */ -- return NOTIFY_DONE; -- } --} --#endif -- --static void dump_video_chains(void) --{ -- int i; -- -- DBG("dumping video chains: "); -- for (i = 0; i < omap_dss_get_num_overlays(); i++) { -- struct omap_overlay *ovl = omap_dss_get_overlay(i); -- struct omap_overlay_manager *mgr = ovl->manager; -- struct omap_dss_device *dssdev = mgr ? -- mgr->get_device(mgr) : NULL; -- if (dssdev) { -- DBG("%d: %s -> %s -> %s", i, ovl->name, mgr->name, -- dssdev->name); -- } else if (mgr) { -- DBG("%d: %s -> %s", i, ovl->name, mgr->name); -- } else { -- DBG("%d: %s", i, ovl->name); -- } -- } --} -- --/* create encoders for each manager */ --static int create_encoder(struct drm_device *dev, -- struct omap_overlay_manager *mgr) --{ -- struct omap_drm_private *priv = dev->dev_private; -- struct drm_encoder *encoder = omap_encoder_init(dev, mgr); -- -- if (!encoder) { -- dev_err(dev->dev, "could not create encoder: %s\n", -- mgr->name); -- return -ENOMEM; -- } -- -- BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); -- -- priv->encoders[priv->num_encoders++] = encoder; -- -- return 0; --} -- --/* create connectors for each display device */ --static int create_connector(struct drm_device *dev, -- struct omap_dss_device *dssdev) -+static int omap_modeset_init(struct drm_device *dev) - { - struct omap_drm_private *priv = dev->dev_private; -- static struct notifier_block *notifier; -- struct drm_connector *connector; -- int j; -- -- if (!dssdev->driver) { -- dev_warn(dev->dev, "%s has no driver.. skipping it\n", -- dssdev->name); -- return 0; -- } -+ struct omap_dss_device *dssdev = NULL; -+ int num_ovls = dss_feat_get_num_ovls(); -+ int id; - -- if (!(dssdev->driver->get_timings || -- dssdev->driver->read_edid)) { -- dev_warn(dev->dev, "%s driver does not support " -- "get_timings or read_edid.. skipping it!\n", -- dssdev->name); -- return 0; -- } -+ drm_mode_config_init(dev); - -- connector = omap_connector_init(dev, -- get_connector_type(dssdev), dssdev); -+ omap_drm_irq_install(dev); - -- if (!connector) { -- dev_err(dev->dev, "could not create connector: %s\n", -- dssdev->name); -- return -ENOMEM; -- } -- -- BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); -+ /* -+ * Create private planes and CRTCs for the last NUM_CRTCs overlay -+ * plus manager: -+ */ -+ for (id = 0; id < min(num_crtc, num_ovls); id++) { -+ struct drm_plane *plane; -+ struct drm_crtc *crtc; - -- priv->connectors[priv->num_connectors++] = connector; -+ plane = omap_plane_init(dev, id, true); -+ crtc = omap_crtc_init(dev, plane, pipe2chan(id), id); - --#if 0 /* enable when dss2 supports hotplug */ -- notifier = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); -- notifier->notifier_call = omap_drm_notifier; -- omap_dss_add_notify(dssdev, notifier); --#else -- notifier = NULL; --#endif -+ BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); -+ priv->crtcs[id] = crtc; -+ priv->num_crtcs++; - -- for (j = 0; j < priv->num_encoders; j++) { -- struct omap_overlay_manager *mgr = -- omap_encoder_get_manager(priv->encoders[j]); -- if (mgr->get_device(mgr) == dssdev) { -- drm_mode_connector_attach_encoder(connector, -- priv->encoders[j]); -- } -+ priv->planes[id] = plane; -+ priv->num_planes++; - } - -- return 0; --} -- --/* create up to max_overlays CRTCs mapping to overlays.. by default, -- * connect the overlays to different managers/encoders, giving priority -- * to encoders connected to connectors with a detected connection -- */ --static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl, -- int *j, unsigned int connected_connectors) --{ -- struct omap_drm_private *priv = dev->dev_private; -- struct omap_overlay_manager *mgr = NULL; -- struct drm_crtc *crtc; -- -- /* find next best connector, ones with detected connection first -+ /* -+ * Create normal planes for the remaining overlays: - */ -- while (*j < priv->num_connectors && !mgr) { -- if (connected_connectors & (1 << *j)) { -- struct drm_encoder *encoder = -- omap_connector_attached_encoder( -- priv->connectors[*j]); -- if (encoder) -- mgr = omap_encoder_get_manager(encoder); -+ for (; id < num_ovls; id++) { -+ struct drm_plane *plane = omap_plane_init(dev, id, false); - -- } -- (*j)++; -+ BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); -+ priv->planes[priv->num_planes++] = plane; - } - -- /* if we couldn't find another connected connector, lets start -- * looking at the unconnected connectors: -- * -- * note: it might not be immediately apparent, but thanks to -- * the !mgr check in both this loop and the one above, the only -- * way to enter this loop is with *j == priv->num_connectors, -- * so idx can never go negative. -- */ -- while (*j < 2 * priv->num_connectors && !mgr) { -- int idx = *j - priv->num_connectors; -- if (!(connected_connectors & (1 << idx))) { -- struct drm_encoder *encoder = -- omap_connector_attached_encoder( -- priv->connectors[idx]); -- if (encoder) -- mgr = omap_encoder_get_manager(encoder); -+ for_each_dss_dev(dssdev) { -+ struct drm_connector *connector; -+ struct drm_encoder *encoder; - -+ if (!dssdev->driver) { -+ dev_warn(dev->dev, "%s has no driver.. skipping it\n", -+ dssdev->name); -+ return 0; - } -- (*j)++; -- } -- -- crtc = omap_crtc_init(dev, ovl, priv->num_crtcs); -- -- if (!crtc) { -- dev_err(dev->dev, "could not create CRTC: %s\n", -- ovl->name); -- return -ENOMEM; -- } - -- BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); -- -- priv->crtcs[priv->num_crtcs++] = crtc; -- -- return 0; --} -- --static int create_plane(struct drm_device *dev, struct omap_overlay *ovl, -- unsigned int possible_crtcs) --{ -- struct omap_drm_private *priv = dev->dev_private; -- struct drm_plane *plane = -- omap_plane_init(dev, ovl, possible_crtcs, false); -- -- if (!plane) { -- dev_err(dev->dev, "could not create plane: %s\n", -- ovl->name); -- return -ENOMEM; -- } -- -- BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); -- -- priv->planes[priv->num_planes++] = plane; -- -- return 0; --} -- --static int match_dev_name(struct omap_dss_device *dssdev, void *data) --{ -- return !strcmp(dssdev->name, data); --} -- --static unsigned int detect_connectors(struct drm_device *dev) --{ -- struct omap_drm_private *priv = dev->dev_private; -- unsigned int connected_connectors = 0; -- int i; -- -- for (i = 0; i < priv->num_connectors; i++) { -- struct drm_connector *connector = priv->connectors[i]; -- if (omap_connector_detect(connector, true) == -- connector_status_connected) { -- connected_connectors |= (1 << i); -+ if (!(dssdev->driver->get_timings || -+ dssdev->driver->read_edid)) { -+ dev_warn(dev->dev, "%s driver does not support " -+ "get_timings or read_edid.. skipping it!\n", -+ dssdev->name); -+ return 0; - } -- } -- -- return connected_connectors; --} - --static int omap_modeset_init(struct drm_device *dev) --{ -- const struct omap_drm_platform_data *pdata = dev->dev->platform_data; -- struct omap_kms_platform_data *kms_pdata = NULL; -- struct omap_drm_private *priv = dev->dev_private; -- struct omap_dss_device *dssdev = NULL; -- int i, j; -- unsigned int connected_connectors = 0; -+ encoder = omap_encoder_init(dev, dssdev); - -- drm_mode_config_init(dev); -- -- if (pdata && pdata->kms_pdata) { -- kms_pdata = pdata->kms_pdata; -- -- /* if platform data is provided by the board file, use it to -- * control which overlays, managers, and devices we own. -- */ -- for (i = 0; i < kms_pdata->mgr_cnt; i++) { -- struct omap_overlay_manager *mgr = -- omap_dss_get_overlay_manager( -- kms_pdata->mgr_ids[i]); -- create_encoder(dev, mgr); -- } -- -- for (i = 0; i < kms_pdata->dev_cnt; i++) { -- struct omap_dss_device *dssdev = -- omap_dss_find_device( -- (void *)kms_pdata->dev_names[i], -- match_dev_name); -- if (!dssdev) { -- dev_warn(dev->dev, "no such dssdev: %s\n", -- kms_pdata->dev_names[i]); -- continue; -- } -- create_connector(dev, dssdev); -+ if (!encoder) { -+ dev_err(dev->dev, "could not create encoder: %s\n", -+ dssdev->name); -+ return -ENOMEM; - } - -- connected_connectors = detect_connectors(dev); -+ connector = omap_connector_init(dev, -+ get_connector_type(dssdev), dssdev, encoder); - -- j = 0; -- for (i = 0; i < kms_pdata->ovl_cnt; i++) { -- struct omap_overlay *ovl = -- omap_dss_get_overlay(kms_pdata->ovl_ids[i]); -- create_crtc(dev, ovl, &j, connected_connectors); -+ if (!connector) { -+ dev_err(dev->dev, "could not create connector: %s\n", -+ dssdev->name); -+ return -ENOMEM; - } - -- for (i = 0; i < kms_pdata->pln_cnt; i++) { -- struct omap_overlay *ovl = -- omap_dss_get_overlay(kms_pdata->pln_ids[i]); -- create_plane(dev, ovl, (1 << priv->num_crtcs) - 1); -- } -- } else { -- /* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and try -- * to make educated guesses about everything else -- */ -- int max_overlays = min(omap_dss_get_num_overlays(), num_crtc); -+ BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); -+ BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); - -- for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) -- create_encoder(dev, omap_dss_get_overlay_manager(i)); -- -- for_each_dss_dev(dssdev) { -- create_connector(dev, dssdev); -- } -+ priv->encoders[priv->num_encoders++] = encoder; -+ priv->connectors[priv->num_connectors++] = connector; - -- connected_connectors = detect_connectors(dev); -+ drm_mode_connector_attach_encoder(connector, encoder); - -- j = 0; -- for (i = 0; i < max_overlays; i++) { -- create_crtc(dev, omap_dss_get_overlay(i), -- &j, connected_connectors); -- } -- -- /* use any remaining overlays as drm planes */ -- for (; i < omap_dss_get_num_overlays(); i++) { -- struct omap_overlay *ovl = omap_dss_get_overlay(i); -- create_plane(dev, ovl, (1 << priv->num_crtcs) - 1); -+ /* figure out which crtc's we can connect the encoder to: */ -+ encoder->possible_crtcs = 0; -+ for (id = 0; id < priv->num_crtcs; id++) { -+ enum omap_dss_output_id supported_outputs = -+ dss_feat_get_supported_outputs(pipe2chan(id)); -+ if (supported_outputs & dssdev->output->id) -+ encoder->possible_crtcs |= (1 << id); - } - } - -- /* for now keep the mapping of CRTCs and encoders static.. */ -- for (i = 0; i < priv->num_encoders; i++) { -- struct drm_encoder *encoder = priv->encoders[i]; -- struct omap_overlay_manager *mgr = -- omap_encoder_get_manager(encoder); -- -- encoder->possible_crtcs = (1 << priv->num_crtcs) - 1; -- -- DBG("%s: possible_crtcs=%08x", mgr->name, -- encoder->possible_crtcs); -- } -- -- dump_video_chains(); -- - dev->mode_config.min_width = 32; - dev->mode_config.min_height = 32; - -@@ -450,7 +229,7 @@ static int ioctl_gem_new(struct drm_device *dev, void *data, - struct drm_file *file_priv) - { - struct drm_omap_gem_new *args = data; -- DBG("%p:%p: size=0x%08x, flags=%08x", dev, file_priv, -+ VERB("%p:%p: size=0x%08x, flags=%08x", dev, file_priv, - args->size.bytes, args->flags); - return omap_gem_new_handle(dev, file_priv, args->size, - args->flags, &args->handle); -@@ -510,7 +289,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data, - struct drm_gem_object *obj; - int ret = 0; - -- DBG("%p:%p: handle=%d", dev, file_priv, args->handle); -+ VERB("%p:%p: handle=%d", dev, file_priv, args->handle); - - obj = drm_gem_object_lookup(dev, file_priv, args->handle); - if (!obj) -@@ -565,14 +344,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags) - - dev->dev_private = priv; - -- ret = omapdss_compat_init(); -- if (ret) { -- dev_err(dev->dev, "coult not init omapdss\n"); -- dev->dev_private = NULL; -- kfree(priv); -- return ret; -- } -- - priv->wq = alloc_ordered_workqueue("omapdrm", 0); - - INIT_LIST_HEAD(&priv->obj_list); -@@ -584,10 +355,13 @@ static int dev_load(struct drm_device *dev, unsigned long flags) - dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret); - dev->dev_private = NULL; - kfree(priv); -- omapdss_compat_uninit(); - return ret; - } - -+ ret = drm_vblank_init(dev, priv->num_crtcs); -+ if (ret) -+ dev_warn(dev->dev, "could not init vblank\n"); -+ - priv->fbdev = omap_fbdev_init(dev); - if (!priv->fbdev) { - dev_warn(dev->dev, "omap_fbdev_init failed\n"); -@@ -596,10 +370,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags) - - drm_kms_helper_poll_init(dev); - -- ret = drm_vblank_init(dev, priv->num_crtcs); -- if (ret) -- dev_warn(dev->dev, "could not init vblank\n"); -- - return 0; - } - -@@ -609,8 +379,9 @@ static int dev_unload(struct drm_device *dev) - - DBG("unload: dev=%p", dev); - -- drm_vblank_cleanup(dev); - drm_kms_helper_poll_fini(dev); -+ drm_vblank_cleanup(dev); -+ omap_drm_irq_uninstall(dev); - - omap_fbdev_free(dev); - omap_modeset_free(dev); -@@ -619,8 +390,6 @@ static int dev_unload(struct drm_device *dev) - flush_workqueue(priv->wq); - destroy_workqueue(priv->wq); - -- omapdss_compat_uninit(); -- - kfree(dev->dev_private); - dev->dev_private = NULL; - -@@ -680,7 +449,9 @@ static void dev_lastclose(struct drm_device *dev) - } - } - -+ mutex_lock(&dev->mode_config.mutex); - ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev); -+ mutex_unlock(&dev->mode_config.mutex); - if (ret) - DBG("failed to restore crtc mode"); - } -@@ -695,60 +466,6 @@ static void dev_postclose(struct drm_device *dev, struct drm_file *file) - DBG("postclose: dev=%p, file=%p", dev, file); - } - --/** -- * enable_vblank - enable vblank interrupt events -- * @dev: DRM device -- * @crtc: which irq to enable -- * -- * Enable vblank interrupts for @crtc. If the device doesn't have -- * a hardware vblank counter, this routine should be a no-op, since -- * interrupts will have to stay on to keep the count accurate. -- * -- * RETURNS -- * Zero on success, appropriate errno if the given @crtc's vblank -- * interrupt cannot be enabled. -- */ --static int dev_enable_vblank(struct drm_device *dev, int crtc) --{ -- DBG("enable_vblank: dev=%p, crtc=%d", dev, crtc); -- return 0; --} -- --/** -- * disable_vblank - disable vblank interrupt events -- * @dev: DRM device -- * @crtc: which irq to enable -- * -- * Disable vblank interrupts for @crtc. If the device doesn't have -- * a hardware vblank counter, this routine should be a no-op, since -- * interrupts will have to stay on to keep the count accurate. -- */ --static void dev_disable_vblank(struct drm_device *dev, int crtc) --{ -- DBG("disable_vblank: dev=%p, crtc=%d", dev, crtc); --} -- --static irqreturn_t dev_irq_handler(DRM_IRQ_ARGS) --{ -- return IRQ_HANDLED; --} -- --static void dev_irq_preinstall(struct drm_device *dev) --{ -- DBG("irq_preinstall: dev=%p", dev); --} -- --static int dev_irq_postinstall(struct drm_device *dev) --{ -- DBG("irq_postinstall: dev=%p", dev); -- return 0; --} -- --static void dev_irq_uninstall(struct drm_device *dev) --{ -- DBG("irq_uninstall: dev=%p", dev); --} -- - static const struct vm_operations_struct omap_gem_vm_ops = { - .fault = omap_gem_fault, - .open = drm_gem_vm_open, -@@ -778,12 +495,12 @@ static struct drm_driver omap_drm_driver = { - .preclose = dev_preclose, - .postclose = dev_postclose, - .get_vblank_counter = drm_vblank_count, -- .enable_vblank = dev_enable_vblank, -- .disable_vblank = dev_disable_vblank, -- .irq_preinstall = dev_irq_preinstall, -- .irq_postinstall = dev_irq_postinstall, -- .irq_uninstall = dev_irq_uninstall, -- .irq_handler = dev_irq_handler, -+ .enable_vblank = omap_irq_enable_vblank, -+ .disable_vblank = omap_irq_disable_vblank, -+ .irq_preinstall = omap_irq_preinstall, -+ .irq_postinstall = omap_irq_postinstall, -+ .irq_uninstall = omap_irq_uninstall, -+ .irq_handler = omap_irq_handler, - #ifdef CONFIG_DEBUG_FS - .debugfs_init = omap_debugfs_init, - .debugfs_cleanup = omap_debugfs_cleanup, -diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h -index 1d4aea5..cd1f22b 100644 ---- a/drivers/staging/omapdrm/omap_drv.h -+++ b/drivers/staging/omapdrm/omap_drv.h -@@ -28,6 +28,7 @@ - #include - #include "omap_drm.h" - -+ - #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) - #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */ - -@@ -39,6 +40,51 @@ - */ - #define MAX_MAPPERS 2 - -+/* parameters which describe (unrotated) coordinates of scanout within a fb: */ -+struct omap_drm_window { -+ uint32_t rotation; -+ int32_t crtc_x, crtc_y; /* signed because can be offscreen */ -+ uint32_t crtc_w, crtc_h; -+ uint32_t src_x, src_y; -+ uint32_t src_w, src_h; -+}; -+ -+/* Once GO bit is set, we can't make further updates to shadowed registers -+ * until the GO bit is cleared. So various parts in the kms code that need -+ * to update shadowed registers queue up a pair of callbacks, pre_apply -+ * which is called before setting GO bit, and post_apply that is called -+ * after GO bit is cleared. The crtc manages the queuing, and everyone -+ * else goes thru omap_crtc_apply() using these callbacks so that the -+ * code which has to deal w/ GO bit state is centralized. -+ */ -+struct omap_drm_apply { -+ struct list_head pending_node, queued_node; -+ bool queued; -+ void (*pre_apply)(struct omap_drm_apply *apply); -+ void (*post_apply)(struct omap_drm_apply *apply); -+}; -+ -+/* For transiently registering for different DSS irqs that various parts -+ * of the KMS code need during setup/configuration. We these are not -+ * necessarily the same as what drm_vblank_get/put() are requesting, and -+ * the hysteresis in drm_vblank_put() is not necessarily desirable for -+ * internal housekeeping related irq usage. -+ */ -+struct omap_drm_irq { -+ struct list_head node; -+ uint32_t irqmask; -+ bool registered; -+ void (*irq)(struct omap_drm_irq *irq, uint32_t irqstatus); -+}; -+ -+/* For KMS code that needs to wait for a certain # of IRQs: -+ */ -+struct omap_irq_wait; -+struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, -+ uint32_t irqmask, int count); -+int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, -+ unsigned long timeout); -+ - struct omap_drm_private { - uint32_t omaprev; - -@@ -58,6 +104,7 @@ struct omap_drm_private { - - struct workqueue_struct *wq; - -+ /* list of GEM objects: */ - struct list_head obj_list; - - bool has_dmm; -@@ -65,6 +112,11 @@ struct omap_drm_private { - /* properties: */ - struct drm_property *rotation_prop; - struct drm_property *zorder_prop; -+ -+ /* irq handling: */ -+ struct list_head irq_list; /* list of omap_drm_irq */ -+ uint32_t vblank_mask; /* irq bits set for userspace vblank */ -+ struct omap_drm_irq error_handler; - }; - - /* this should probably be in drm-core to standardize amongst drivers */ -@@ -75,15 +127,6 @@ struct omap_drm_private { - #define DRM_REFLECT_X 4 - #define DRM_REFLECT_Y 5 - --/* parameters which describe (unrotated) coordinates of scanout within a fb: */ --struct omap_drm_window { -- uint32_t rotation; -- int32_t crtc_x, crtc_y; /* signed because can be offscreen */ -- uint32_t crtc_w, crtc_h; -- uint32_t src_x, src_y; -- uint32_t src_w, src_h; --}; -- - #ifdef CONFIG_DEBUG_FS - int omap_debugfs_init(struct drm_minor *minor); - void omap_debugfs_cleanup(struct drm_minor *minor); -@@ -92,23 +135,36 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m); - void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); - #endif - -+int omap_irq_enable_vblank(struct drm_device *dev, int crtc); -+void omap_irq_disable_vblank(struct drm_device *dev, int crtc); -+irqreturn_t omap_irq_handler(DRM_IRQ_ARGS); -+void omap_irq_preinstall(struct drm_device *dev); -+int omap_irq_postinstall(struct drm_device *dev); -+void omap_irq_uninstall(struct drm_device *dev); -+void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq); -+void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq); -+int omap_drm_irq_uninstall(struct drm_device *dev); -+int omap_drm_irq_install(struct drm_device *dev); -+ - struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); - void omap_fbdev_free(struct drm_device *dev); - -+const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc); -+enum omap_channel omap_crtc_channel(struct drm_crtc *crtc); -+int omap_crtc_apply(struct drm_crtc *crtc, -+ struct omap_drm_apply *apply); - struct drm_crtc *omap_crtc_init(struct drm_device *dev, -- struct omap_overlay *ovl, int id); -+ struct drm_plane *plane, enum omap_channel channel, int id); - - struct drm_plane *omap_plane_init(struct drm_device *dev, -- struct omap_overlay *ovl, unsigned int possible_crtcs, -- bool priv); -+ int plane_id, bool private_plane); - int omap_plane_dpms(struct drm_plane *plane, int mode); - int omap_plane_mode_set(struct drm_plane *plane, - struct drm_crtc *crtc, struct drm_framebuffer *fb, - int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, -- uint32_t src_w, uint32_t src_h); --void omap_plane_on_endwin(struct drm_plane *plane, -+ uint32_t src_w, uint32_t src_h, - void (*fxn)(void *), void *arg); - void omap_plane_install_properties(struct drm_plane *plane, - struct drm_mode_object *obj); -@@ -116,21 +172,25 @@ int omap_plane_set_property(struct drm_plane *plane, - struct drm_property *property, uint64_t val); - - struct drm_encoder *omap_encoder_init(struct drm_device *dev, -- struct omap_overlay_manager *mgr); --struct omap_overlay_manager *omap_encoder_get_manager( -+ struct omap_dss_device *dssdev); -+int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled); -+int omap_encoder_update(struct drm_encoder *encoder, -+ struct omap_overlay_manager *mgr, -+ struct omap_video_timings *timings); -+ -+struct drm_connector *omap_connector_init(struct drm_device *dev, -+ int connector_type, struct omap_dss_device *dssdev, - struct drm_encoder *encoder); - struct drm_encoder *omap_connector_attached_encoder( - struct drm_connector *connector); --enum drm_connector_status omap_connector_detect( -- struct drm_connector *connector, bool force); -- --struct drm_connector *omap_connector_init(struct drm_device *dev, -- int connector_type, struct omap_dss_device *dssdev); --void omap_connector_mode_set(struct drm_connector *connector, -- struct drm_display_mode *mode); - void omap_connector_flush(struct drm_connector *connector, - int x, int y, int w, int h); - -+void copy_timings_omap_to_drm(struct drm_display_mode *mode, -+ struct omap_video_timings *timings); -+void copy_timings_drm_to_omap(struct omap_video_timings *timings, -+ struct drm_display_mode *mode); -+ - uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats, - uint32_t max_formats, enum omap_color_mode supported_modes); - struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, -@@ -207,6 +267,40 @@ static inline int align_pitch(int pitch, int width, int bpp) - return ALIGN(pitch, 8 * bytespp); - } - -+static inline enum omap_channel pipe2chan(int pipe) -+{ -+ int num_mgrs = dss_feat_get_num_mgrs(); -+ -+ /* -+ * We usually don't want to create a CRTC for each manager, -+ * at least not until we have a way to expose private planes -+ * to userspace. Otherwise there would not be enough video -+ * pipes left for drm planes. The higher #'d managers tend -+ * to have more features so start in reverse order. -+ */ -+ return num_mgrs - pipe - 1; -+} -+ -+/* map crtc to vblank mask */ -+static inline uint32_t pipe2vbl(int crtc) -+{ -+ enum omap_channel channel = pipe2chan(crtc); -+ return dispc_mgr_get_vsync_irq(channel); -+} -+ -+static inline int crtc2pipe(struct drm_device *dev, struct drm_crtc *crtc) -+{ -+ struct omap_drm_private *priv = dev->dev_private; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(priv->crtcs); i++) -+ if (priv->crtcs[i] == crtc) -+ return i; -+ -+ BUG(); /* bogus CRTC ptr */ -+ return -1; -+} -+ - /* should these be made into common util helpers? - */ - -diff --git a/drivers/staging/omapdrm/omap_encoder.c b/drivers/staging/omapdrm/omap_encoder.c -index 5341d5e..e053160 100644 ---- a/drivers/staging/omapdrm/omap_encoder.c -+++ b/drivers/staging/omapdrm/omap_encoder.c -@@ -22,37 +22,56 @@ - #include "drm_crtc.h" - #include "drm_crtc_helper.h" - -+#include -+ -+ - /* - * encoder funcs - */ - - #define to_omap_encoder(x) container_of(x, struct omap_encoder, base) - -+/* The encoder and connector both map to same dssdev.. the encoder -+ * handles the 'active' parts, ie. anything the modifies the state -+ * of the hw, and the connector handles the 'read-only' parts, like -+ * detecting connection and reading edid. -+ */ - struct omap_encoder { - struct drm_encoder base; -- struct omap_overlay_manager *mgr; -+ struct omap_dss_device *dssdev; - }; - - static void omap_encoder_destroy(struct drm_encoder *encoder) - { - struct omap_encoder *omap_encoder = to_omap_encoder(encoder); -- DBG("%s", omap_encoder->mgr->name); - drm_encoder_cleanup(encoder); - kfree(omap_encoder); - } - -+static const struct drm_encoder_funcs omap_encoder_funcs = { -+ .destroy = omap_encoder_destroy, -+}; -+ -+/* -+ * The CRTC drm_crtc_helper_set_mode() doesn't really give us the right -+ * order.. the easiest way to work around this for now is to make all -+ * the encoder-helper's no-op's and have the omap_crtc code take care -+ * of the sequencing and call us in the right points. -+ * -+ * Eventually to handle connecting CRTCs to different encoders properly, -+ * either the CRTC helpers need to change or we need to replace -+ * drm_crtc_helper_set_mode(), but lets wait until atomic-modeset for -+ * that. -+ */ -+ - static void omap_encoder_dpms(struct drm_encoder *encoder, int mode) - { -- struct omap_encoder *omap_encoder = to_omap_encoder(encoder); -- DBG("%s: %d", omap_encoder->mgr->name, mode); - } - - static bool omap_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) - { -- struct omap_encoder *omap_encoder = to_omap_encoder(encoder); -- DBG("%s", omap_encoder->mgr->name); - return true; - } - -@@ -60,47 +79,16 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) - { -- struct omap_encoder *omap_encoder = to_omap_encoder(encoder); -- struct drm_device *dev = encoder->dev; -- struct omap_drm_private *priv = dev->dev_private; -- int i; -- -- mode = adjusted_mode; -- -- DBG("%s: set mode: %dx%d", omap_encoder->mgr->name, -- mode->hdisplay, mode->vdisplay); -- -- for (i = 0; i < priv->num_connectors; i++) { -- struct drm_connector *connector = priv->connectors[i]; -- if (connector->encoder == encoder) -- omap_connector_mode_set(connector, mode); -- -- } - } - - static void omap_encoder_prepare(struct drm_encoder *encoder) - { -- struct omap_encoder *omap_encoder = to_omap_encoder(encoder); -- struct drm_encoder_helper_funcs *encoder_funcs = -- encoder->helper_private; -- DBG("%s", omap_encoder->mgr->name); -- encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); - } - - static void omap_encoder_commit(struct drm_encoder *encoder) - { -- struct omap_encoder *omap_encoder = to_omap_encoder(encoder); -- struct drm_encoder_helper_funcs *encoder_funcs = -- encoder->helper_private; -- DBG("%s", omap_encoder->mgr->name); -- omap_encoder->mgr->apply(omap_encoder->mgr); -- encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); - } - --static const struct drm_encoder_funcs omap_encoder_funcs = { -- .destroy = omap_encoder_destroy, --}; -- - static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { - .dpms = omap_encoder_dpms, - .mode_fixup = omap_encoder_mode_fixup, -@@ -109,23 +97,54 @@ static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { - .commit = omap_encoder_commit, - }; - --struct omap_overlay_manager *omap_encoder_get_manager( -- struct drm_encoder *encoder) -+/* -+ * Instead of relying on the helpers for modeset, the omap_crtc code -+ * calls these functions in the proper sequence. -+ */ -+ -+int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled) - { - struct omap_encoder *omap_encoder = to_omap_encoder(encoder); -- return omap_encoder->mgr; -+ struct omap_dss_device *dssdev = omap_encoder->dssdev; -+ struct omap_dss_driver *dssdrv = dssdev->driver; -+ -+ if (enabled) { -+ return dssdrv->enable(dssdev); -+ } else { -+ dssdrv->disable(dssdev); -+ return 0; -+ } -+} -+ -+int omap_encoder_update(struct drm_encoder *encoder, -+ struct omap_overlay_manager *mgr, -+ struct omap_video_timings *timings) -+{ -+ struct drm_device *dev = encoder->dev; -+ struct omap_encoder *omap_encoder = to_omap_encoder(encoder); -+ struct omap_dss_device *dssdev = omap_encoder->dssdev; -+ struct omap_dss_driver *dssdrv = dssdev->driver; -+ int ret; -+ -+ dssdev->output->manager = mgr; -+ -+ ret = dssdrv->check_timings(dssdev, timings); -+ if (ret) { -+ dev_err(dev->dev, "could not set timings: %d\n", ret); -+ return ret; -+ } -+ -+ dssdrv->set_timings(dssdev, timings); -+ -+ return 0; - } - - /* initialize encoder */ - struct drm_encoder *omap_encoder_init(struct drm_device *dev, -- struct omap_overlay_manager *mgr) -+ struct omap_dss_device *dssdev) - { - struct drm_encoder *encoder = NULL; - struct omap_encoder *omap_encoder; -- struct omap_overlay_manager_info info; -- int ret; -- -- DBG("%s", mgr->name); - - omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL); - if (!omap_encoder) { -@@ -133,33 +152,14 @@ struct drm_encoder *omap_encoder_init(struct drm_device *dev, - goto fail; - } - -- omap_encoder->mgr = mgr; -+ omap_encoder->dssdev = dssdev; -+ - encoder = &omap_encoder->base; - - drm_encoder_init(dev, encoder, &omap_encoder_funcs, - DRM_MODE_ENCODER_TMDS); - drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); - -- mgr->get_manager_info(mgr, &info); -- -- /* TODO: fix hard-coded setup.. */ -- info.default_color = 0x00000000; -- info.trans_key = 0x00000000; -- info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; -- info.trans_enabled = false; -- -- ret = mgr->set_manager_info(mgr, &info); -- if (ret) { -- dev_err(dev->dev, "could not set manager info\n"); -- goto fail; -- } -- -- ret = mgr->apply(mgr); -- if (ret) { -- dev_err(dev->dev, "could not apply\n"); -- goto fail; -- } -- - return encoder; - - fail: -diff --git a/drivers/staging/omapdrm/omap_irq.c b/drivers/staging/omapdrm/omap_irq.c -new file mode 100644 -index 0000000..2629ba7 ---- /dev/null -+++ b/drivers/staging/omapdrm/omap_irq.c -@@ -0,0 +1,322 @@ -+/* -+ * drivers/staging/omapdrm/omap_irq.c -+ * -+ * Copyright (C) 2012 Texas Instruments -+ * Author: Rob Clark -+ * -+ * 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 . -+ */ -+ -+#include "omap_drv.h" -+ -+static DEFINE_SPINLOCK(list_lock); -+ -+static void omap_irq_error_handler(struct omap_drm_irq *irq, -+ uint32_t irqstatus) -+{ -+ DRM_ERROR("errors: %08x\n", irqstatus); -+} -+ -+/* call with list_lock and dispc runtime held */ -+static void omap_irq_update(struct drm_device *dev) -+{ -+ struct omap_drm_private *priv = dev->dev_private; -+ struct omap_drm_irq *irq; -+ uint32_t irqmask = priv->vblank_mask; -+ -+ BUG_ON(!spin_is_locked(&list_lock)); -+ -+ list_for_each_entry(irq, &priv->irq_list, node) -+ irqmask |= irq->irqmask; -+ -+ DBG("irqmask=%08x", irqmask); -+ -+ dispc_write_irqenable(irqmask); -+ dispc_read_irqenable(); /* flush posted write */ -+} -+ -+void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq) -+{ -+ struct omap_drm_private *priv = dev->dev_private; -+ unsigned long flags; -+ -+ dispc_runtime_get(); -+ spin_lock_irqsave(&list_lock, flags); -+ -+ if (!WARN_ON(irq->registered)) { -+ irq->registered = true; -+ list_add(&irq->node, &priv->irq_list); -+ omap_irq_update(dev); -+ } -+ -+ spin_unlock_irqrestore(&list_lock, flags); -+ dispc_runtime_put(); -+} -+ -+void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq) -+{ -+ unsigned long flags; -+ -+ dispc_runtime_get(); -+ spin_lock_irqsave(&list_lock, flags); -+ -+ if (!WARN_ON(!irq->registered)) { -+ irq->registered = false; -+ list_del(&irq->node); -+ omap_irq_update(dev); -+ } -+ -+ spin_unlock_irqrestore(&list_lock, flags); -+ dispc_runtime_put(); -+} -+ -+struct omap_irq_wait { -+ struct omap_drm_irq irq; -+ int count; -+}; -+ -+static DECLARE_WAIT_QUEUE_HEAD(wait_event); -+ -+static void wait_irq(struct omap_drm_irq *irq, uint32_t irqstatus) -+{ -+ struct omap_irq_wait *wait = -+ container_of(irq, struct omap_irq_wait, irq); -+ wait->count--; -+ wake_up_all(&wait_event); -+} -+ -+struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, -+ uint32_t irqmask, int count) -+{ -+ struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL); -+ wait->irq.irq = wait_irq; -+ wait->irq.irqmask = irqmask; -+ wait->count = count; -+ omap_irq_register(dev, &wait->irq); -+ return wait; -+} -+ -+int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, -+ unsigned long timeout) -+{ -+ int ret = wait_event_timeout(wait_event, (wait->count <= 0), timeout); -+ omap_irq_unregister(dev, &wait->irq); -+ kfree(wait); -+ if (ret == 0) -+ return -1; -+ return 0; -+} -+ -+/** -+ * enable_vblank - enable vblank interrupt events -+ * @dev: DRM device -+ * @crtc: which irq to enable -+ * -+ * Enable vblank interrupts for @crtc. If the device doesn't have -+ * a hardware vblank counter, this routine should be a no-op, since -+ * interrupts will have to stay on to keep the count accurate. -+ * -+ * RETURNS -+ * Zero on success, appropriate errno if the given @crtc's vblank -+ * interrupt cannot be enabled. -+ */ -+int omap_irq_enable_vblank(struct drm_device *dev, int crtc) -+{ -+ struct omap_drm_private *priv = dev->dev_private; -+ unsigned long flags; -+ -+ DBG("dev=%p, crtc=%d", dev, crtc); -+ -+ dispc_runtime_get(); -+ spin_lock_irqsave(&list_lock, flags); -+ priv->vblank_mask |= pipe2vbl(crtc); -+ omap_irq_update(dev); -+ spin_unlock_irqrestore(&list_lock, flags); -+ dispc_runtime_put(); -+ -+ return 0; -+} -+ -+/** -+ * disable_vblank - disable vblank interrupt events -+ * @dev: DRM device -+ * @crtc: which irq to enable -+ * -+ * Disable vblank interrupts for @crtc. If the device doesn't have -+ * a hardware vblank counter, this routine should be a no-op, since -+ * interrupts will have to stay on to keep the count accurate. -+ */ -+void omap_irq_disable_vblank(struct drm_device *dev, int crtc) -+{ -+ struct omap_drm_private *priv = dev->dev_private; -+ unsigned long flags; -+ -+ DBG("dev=%p, crtc=%d", dev, crtc); -+ -+ dispc_runtime_get(); -+ spin_lock_irqsave(&list_lock, flags); -+ priv->vblank_mask &= ~pipe2vbl(crtc); -+ omap_irq_update(dev); -+ spin_unlock_irqrestore(&list_lock, flags); -+ dispc_runtime_put(); -+} -+ -+irqreturn_t omap_irq_handler(DRM_IRQ_ARGS) -+{ -+ struct drm_device *dev = (struct drm_device *) arg; -+ struct omap_drm_private *priv = dev->dev_private; -+ struct omap_drm_irq *handler, *n; -+ unsigned long flags; -+ unsigned int id; -+ u32 irqstatus; -+ -+ irqstatus = dispc_read_irqstatus(); -+ dispc_clear_irqstatus(irqstatus); -+ dispc_read_irqstatus(); /* flush posted write */ -+ -+ VERB("irqs: %08x", irqstatus); -+ -+ for (id = 0; id < priv->num_crtcs; id++) -+ if (irqstatus & pipe2vbl(id)) -+ drm_handle_vblank(dev, id); -+ -+ spin_lock_irqsave(&list_lock, flags); -+ list_for_each_entry_safe(handler, n, &priv->irq_list, node) { -+ if (handler->irqmask & irqstatus) { -+ spin_unlock_irqrestore(&list_lock, flags); -+ handler->irq(handler, handler->irqmask & irqstatus); -+ spin_lock_irqsave(&list_lock, flags); -+ } -+ } -+ spin_unlock_irqrestore(&list_lock, flags); -+ -+ return IRQ_HANDLED; -+} -+ -+void omap_irq_preinstall(struct drm_device *dev) -+{ -+ DBG("dev=%p", dev); -+ dispc_runtime_get(); -+ dispc_clear_irqstatus(0xffffffff); -+ dispc_runtime_put(); -+} -+ -+int omap_irq_postinstall(struct drm_device *dev) -+{ -+ struct omap_drm_private *priv = dev->dev_private; -+ struct omap_drm_irq *error_handler = &priv->error_handler; -+ -+ DBG("dev=%p", dev); -+ -+ INIT_LIST_HEAD(&priv->irq_list); -+ -+ error_handler->irq = omap_irq_error_handler; -+ error_handler->irqmask = DISPC_IRQ_OCP_ERR; -+ -+ /* for now ignore DISPC_IRQ_SYNC_LOST_DIGIT.. really I think -+ * we just need to ignore it while enabling tv-out -+ */ -+ error_handler->irqmask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; -+ -+ omap_irq_register(dev, error_handler); -+ -+ return 0; -+} -+ -+void omap_irq_uninstall(struct drm_device *dev) -+{ -+ DBG("dev=%p", dev); -+ // TODO prolly need to call drm_irq_uninstall() somewhere too -+} -+ -+/* -+ * We need a special version, instead of just using drm_irq_install(), -+ * because we need to register the irq via omapdss. Once omapdss and -+ * omapdrm are merged together we can assign the dispc hwmod data to -+ * ourselves and drop these and just use drm_irq_{install,uninstall}() -+ */ -+ -+int omap_drm_irq_install(struct drm_device *dev) -+{ -+ int ret; -+ -+ mutex_lock(&dev->struct_mutex); -+ -+ if (dev->irq_enabled) { -+ mutex_unlock(&dev->struct_mutex); -+ return -EBUSY; -+ } -+ dev->irq_enabled = 1; -+ mutex_unlock(&dev->struct_mutex); -+ -+ /* Before installing handler */ -+ if (dev->driver->irq_preinstall) -+ dev->driver->irq_preinstall(dev); -+ -+ ret = dispc_request_irq(dev->driver->irq_handler, dev); -+ -+ if (ret < 0) { -+ mutex_lock(&dev->struct_mutex); -+ dev->irq_enabled = 0; -+ mutex_unlock(&dev->struct_mutex); -+ return ret; -+ } -+ -+ /* After installing handler */ -+ if (dev->driver->irq_postinstall) -+ ret = dev->driver->irq_postinstall(dev); -+ -+ if (ret < 0) { -+ mutex_lock(&dev->struct_mutex); -+ dev->irq_enabled = 0; -+ mutex_unlock(&dev->struct_mutex); -+ dispc_free_irq(dev); -+ } -+ -+ return ret; -+} -+ -+int omap_drm_irq_uninstall(struct drm_device *dev) -+{ -+ unsigned long irqflags; -+ int irq_enabled, i; -+ -+ mutex_lock(&dev->struct_mutex); -+ irq_enabled = dev->irq_enabled; -+ dev->irq_enabled = 0; -+ mutex_unlock(&dev->struct_mutex); -+ -+ /* -+ * Wake up any waiters so they don't hang. -+ */ -+ if (dev->num_crtcs) { -+ spin_lock_irqsave(&dev->vbl_lock, irqflags); -+ for (i = 0; i < dev->num_crtcs; i++) { -+ DRM_WAKEUP(&dev->vbl_queue[i]); -+ dev->vblank_enabled[i] = 0; -+ dev->last_vblank[i] = -+ dev->driver->get_vblank_counter(dev, i); -+ } -+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags); -+ } -+ -+ if (!irq_enabled) -+ return -EINVAL; -+ -+ if (dev->driver->irq_uninstall) -+ dev->driver->irq_uninstall(dev); -+ -+ dispc_free_irq(dev); -+ -+ return 0; -+} -diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c -index 2a8e5ba..bb989d7 100644 ---- a/drivers/staging/omapdrm/omap_plane.c -+++ b/drivers/staging/omapdrm/omap_plane.c -@@ -41,12 +41,14 @@ struct callback { - - struct omap_plane { - struct drm_plane base; -- struct omap_overlay *ovl; -+ int id; /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */ -+ const char *name; - struct omap_overlay_info info; -+ struct omap_drm_apply apply; - - /* position/orientation of scanout within the fb: */ - struct omap_drm_window win; -- -+ bool enabled; - - /* last fb that we pinned: */ - struct drm_framebuffer *pinned_fb; -@@ -54,189 +56,15 @@ struct omap_plane { - uint32_t nformats; - uint32_t formats[32]; - -- /* for synchronizing access to unpins fifo */ -- struct mutex unpin_mutex; -+ struct omap_drm_irq error_irq; - -- /* set of bo's pending unpin until next END_WIN irq */ -+ /* set of bo's pending unpin until next post_apply() */ - DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *); -- int num_unpins, pending_num_unpins; -- -- /* for deferred unpin when we need to wait for scanout complete irq */ -- struct work_struct work; -- -- /* callback on next endwin irq */ -- struct callback endwin; --}; - --/* map from ovl->id to the irq we are interested in for scanout-done */ --static const uint32_t id2irq[] = { -- [OMAP_DSS_GFX] = DISPC_IRQ_GFX_END_WIN, -- [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_END_WIN, -- [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_END_WIN, -- [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_END_WIN, -+ // XXX maybe get rid of this and handle vblank in crtc too? -+ struct callback apply_done_cb; - }; - --static void dispc_isr(void *arg, uint32_t mask) --{ -- struct drm_plane *plane = arg; -- struct omap_plane *omap_plane = to_omap_plane(plane); -- struct omap_drm_private *priv = plane->dev->dev_private; -- -- omap_dispc_unregister_isr(dispc_isr, plane, -- id2irq[omap_plane->ovl->id]); -- -- queue_work(priv->wq, &omap_plane->work); --} -- --static void unpin_worker(struct work_struct *work) --{ -- struct omap_plane *omap_plane = -- container_of(work, struct omap_plane, work); -- struct callback endwin; -- -- mutex_lock(&omap_plane->unpin_mutex); -- DBG("unpinning %d of %d", omap_plane->num_unpins, -- omap_plane->num_unpins + omap_plane->pending_num_unpins); -- while (omap_plane->num_unpins > 0) { -- struct drm_gem_object *bo = NULL; -- int ret = kfifo_get(&omap_plane->unpin_fifo, &bo); -- WARN_ON(!ret); -- omap_gem_put_paddr(bo); -- drm_gem_object_unreference_unlocked(bo); -- omap_plane->num_unpins--; -- } -- endwin = omap_plane->endwin; -- omap_plane->endwin.fxn = NULL; -- mutex_unlock(&omap_plane->unpin_mutex); -- -- if (endwin.fxn) -- endwin.fxn(endwin.arg); --} -- --static void install_irq(struct drm_plane *plane) --{ -- struct omap_plane *omap_plane = to_omap_plane(plane); -- struct omap_overlay *ovl = omap_plane->ovl; -- int ret; -- -- ret = omap_dispc_register_isr(dispc_isr, plane, id2irq[ovl->id]); -- -- /* -- * omapdss has upper limit on # of registered irq handlers, -- * which we shouldn't hit.. but if we do the limit should -- * be raised or bad things happen: -- */ -- WARN_ON(ret == -EBUSY); --} -- --/* push changes down to dss2 */ --static int commit(struct drm_plane *plane) --{ -- struct drm_device *dev = plane->dev; -- struct omap_plane *omap_plane = to_omap_plane(plane); -- struct omap_overlay *ovl = omap_plane->ovl; -- struct omap_overlay_info *info = &omap_plane->info; -- int ret; -- -- DBG("%s", ovl->name); -- DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width, -- info->out_height, info->screen_width); -- DBG("%d,%d %08x %08x", info->pos_x, info->pos_y, -- info->paddr, info->p_uv_addr); -- -- /* NOTE: do we want to do this at all here, or just wait -- * for dpms(ON) since other CRTC's may not have their mode -- * set yet, so fb dimensions may still change.. -- */ -- ret = ovl->set_overlay_info(ovl, info); -- if (ret) { -- dev_err(dev->dev, "could not set overlay info\n"); -- return ret; -- } -- -- mutex_lock(&omap_plane->unpin_mutex); -- omap_plane->num_unpins += omap_plane->pending_num_unpins; -- omap_plane->pending_num_unpins = 0; -- mutex_unlock(&omap_plane->unpin_mutex); -- -- /* our encoder doesn't necessarily get a commit() after this, in -- * particular in the dpms() and mode_set_base() cases, so force the -- * manager to update: -- * -- * could this be in the encoder somehow? -- */ -- if (ovl->manager) { -- ret = ovl->manager->apply(ovl->manager); -- if (ret) { -- dev_err(dev->dev, "could not apply settings\n"); -- return ret; -- } -- -- /* -- * NOTE: really this should be atomic w/ mgr->apply() but -- * omapdss does not expose such an API -- */ -- if (omap_plane->num_unpins > 0) -- install_irq(plane); -- -- } else { -- struct omap_drm_private *priv = dev->dev_private; -- queue_work(priv->wq, &omap_plane->work); -- } -- -- -- if (ovl->is_enabled(ovl)) { -- omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y, -- info->out_width, info->out_height); -- } -- -- return 0; --} -- --/* when CRTC that we are attached to has potentially changed, this checks -- * if we are attached to proper manager, and if necessary updates. -- */ --static void update_manager(struct drm_plane *plane) --{ -- struct omap_drm_private *priv = plane->dev->dev_private; -- struct omap_plane *omap_plane = to_omap_plane(plane); -- struct omap_overlay *ovl = omap_plane->ovl; -- struct omap_overlay_manager *mgr = NULL; -- int i; -- -- if (plane->crtc) { -- for (i = 0; i < priv->num_encoders; i++) { -- struct drm_encoder *encoder = priv->encoders[i]; -- if (encoder->crtc == plane->crtc) { -- mgr = omap_encoder_get_manager(encoder); -- break; -- } -- } -- } -- -- if (ovl->manager != mgr) { -- bool enabled = ovl->is_enabled(ovl); -- -- /* don't switch things around with enabled overlays: */ -- if (enabled) -- omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); -- -- if (ovl->manager) { -- DBG("disconnecting %s from %s", ovl->name, -- ovl->manager->name); -- ovl->unset_manager(ovl); -- } -- -- if (mgr) { -- DBG("connecting %s to %s", ovl->name, mgr->name); -- ovl->set_manager(ovl, mgr); -- } -- -- if (enabled && mgr) -- omap_plane_dpms(plane, DRM_MODE_DPMS_ON); -- } --} -- - static void unpin(void *arg, struct drm_gem_object *bo) - { - struct drm_plane *plane = arg; -@@ -244,7 +72,6 @@ static void unpin(void *arg, struct drm_gem_object *bo) - - if (kfifo_put(&omap_plane->unpin_fifo, - (const struct drm_gem_object **)&bo)) { -- omap_plane->pending_num_unpins++; - /* also hold a ref so it isn't free'd while pinned */ - drm_gem_object_reference(bo); - } else { -@@ -264,13 +91,19 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) - - DBG("%p -> %p", pinned_fb, fb); - -- mutex_lock(&omap_plane->unpin_mutex); -+ if (fb) -+ drm_framebuffer_reference(fb); -+ - ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin); -- mutex_unlock(&omap_plane->unpin_mutex); -+ -+ if (pinned_fb) -+ drm_framebuffer_unreference(pinned_fb); - - if (ret) { - dev_err(plane->dev->dev, "could not swap %p -> %p\n", - omap_plane->pinned_fb, fb); -+ if (fb) -+ drm_framebuffer_unreference(fb); - omap_plane->pinned_fb = NULL; - return ret; - } -@@ -281,31 +114,90 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) - return 0; - } - --/* update parameters that are dependent on the framebuffer dimensions and -- * position within the fb that this plane scans out from. This is called -- * when framebuffer or x,y base may have changed. -- */ --static void update_scanout(struct drm_plane *plane) -+static void omap_plane_pre_apply(struct omap_drm_apply *apply) - { -- struct omap_plane *omap_plane = to_omap_plane(plane); -- struct omap_overlay_info *info = &omap_plane->info; -+ struct omap_plane *omap_plane = -+ container_of(apply, struct omap_plane, apply); - struct omap_drm_window *win = &omap_plane->win; -+ struct drm_plane *plane = &omap_plane->base; -+ struct drm_device *dev = plane->dev; -+ struct omap_overlay_info *info = &omap_plane->info; -+ struct drm_crtc *crtc = plane->crtc; -+ enum omap_channel channel; -+ bool enabled = omap_plane->enabled && crtc; -+ bool ilace, replication; - int ret; - -- ret = update_pin(plane, plane->fb); -- if (ret) { -- dev_err(plane->dev->dev, -- "could not pin fb: %d\n", ret); -- omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); -+ DBG("%s, enabled=%d", omap_plane->name, enabled); -+ -+ /* if fb has changed, pin new fb: */ -+ update_pin(plane, enabled ? plane->fb : NULL); -+ -+ if (!enabled) { -+ dispc_ovl_enable(omap_plane->id, false); - return; - } - -+ channel = omap_crtc_channel(crtc); -+ -+ /* update scanout: */ - omap_framebuffer_update_scanout(plane->fb, win, info); - -- DBG("%s: %d,%d: %08x %08x (%d)", omap_plane->ovl->name, -- win->src_x, win->src_y, -- (u32)info->paddr, (u32)info->p_uv_addr, -+ DBG("%dx%d -> %dx%d (%d)", info->width, info->height, -+ info->out_width, info->out_height, - info->screen_width); -+ DBG("%d,%d %08x %08x", info->pos_x, info->pos_y, -+ info->paddr, info->p_uv_addr); -+ -+ /* TODO: */ -+ ilace = false; -+ replication = false; -+ -+ /* and finally, update omapdss: */ -+ ret = dispc_ovl_setup(omap_plane->id, info, -+ replication, omap_crtc_timings(crtc), false); -+ if (ret) { -+ dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret); -+ return; -+ } -+ -+ dispc_ovl_enable(omap_plane->id, true); -+ dispc_ovl_set_channel_out(omap_plane->id, channel); -+} -+ -+static void omap_plane_post_apply(struct omap_drm_apply *apply) -+{ -+ struct omap_plane *omap_plane = -+ container_of(apply, struct omap_plane, apply); -+ struct drm_plane *plane = &omap_plane->base; -+ struct omap_overlay_info *info = &omap_plane->info; -+ struct drm_gem_object *bo = NULL; -+ struct callback cb; -+ -+ cb = omap_plane->apply_done_cb; -+ omap_plane->apply_done_cb.fxn = NULL; -+ -+ while (kfifo_get(&omap_plane->unpin_fifo, &bo)) { -+ omap_gem_put_paddr(bo); -+ drm_gem_object_unreference_unlocked(bo); -+ } -+ -+ if (cb.fxn) -+ cb.fxn(cb.arg); -+ -+ if (omap_plane->enabled) { -+ omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y, -+ info->out_width, info->out_height); -+ } -+} -+ -+static int apply(struct drm_plane *plane) -+{ -+ if (plane->crtc) { -+ struct omap_plane *omap_plane = to_omap_plane(plane); -+ return omap_crtc_apply(plane->crtc, &omap_plane->apply); -+ } -+ return 0; - } - - int omap_plane_mode_set(struct drm_plane *plane, -@@ -313,7 +205,8 @@ int omap_plane_mode_set(struct drm_plane *plane, - int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, -- uint32_t src_w, uint32_t src_h) -+ uint32_t src_w, uint32_t src_h, -+ void (*fxn)(void *), void *arg) - { - struct omap_plane *omap_plane = to_omap_plane(plane); - struct omap_drm_window *win = &omap_plane->win; -@@ -329,17 +222,20 @@ int omap_plane_mode_set(struct drm_plane *plane, - win->src_w = src_w >> 16; - win->src_h = src_h >> 16; - -- /* note: this is done after this fxn returns.. but if we need -- * to do a commit/update_scanout, etc before this returns we -- * need the current value. -- */ -+ if (fxn) { -+ /* omap_crtc should ensure that a new page flip -+ * isn't permitted while there is one pending: -+ */ -+ BUG_ON(omap_plane->apply_done_cb.fxn); -+ -+ omap_plane->apply_done_cb.fxn = fxn; -+ omap_plane->apply_done_cb.arg = arg; -+ } -+ - plane->fb = fb; - plane->crtc = crtc; - -- update_scanout(plane); -- update_manager(plane); -- -- return 0; -+ return apply(plane); - } - - static int omap_plane_update(struct drm_plane *plane, -@@ -349,9 +245,12 @@ static int omap_plane_update(struct drm_plane *plane, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) - { -- omap_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, -- src_x, src_y, src_w, src_h); -- return omap_plane_dpms(plane, DRM_MODE_DPMS_ON); -+ struct omap_plane *omap_plane = to_omap_plane(plane); -+ omap_plane->enabled = true; -+ return omap_plane_mode_set(plane, crtc, fb, -+ crtc_x, crtc_y, crtc_w, crtc_h, -+ src_x, src_y, src_w, src_h, -+ NULL, NULL); - } - - static int omap_plane_disable(struct drm_plane *plane) -@@ -364,48 +263,32 @@ static int omap_plane_disable(struct drm_plane *plane) - static void omap_plane_destroy(struct drm_plane *plane) - { - struct omap_plane *omap_plane = to_omap_plane(plane); -- DBG("%s", omap_plane->ovl->name); -+ -+ DBG("%s", omap_plane->name); -+ -+ omap_irq_unregister(plane->dev, &omap_plane->error_irq); -+ - omap_plane_disable(plane); - drm_plane_cleanup(plane); -- WARN_ON(omap_plane->pending_num_unpins + omap_plane->num_unpins > 0); -+ -+ WARN_ON(!kfifo_is_empty(&omap_plane->unpin_fifo)); - kfifo_free(&omap_plane->unpin_fifo); -+ - kfree(omap_plane); - } - - int omap_plane_dpms(struct drm_plane *plane, int mode) - { - struct omap_plane *omap_plane = to_omap_plane(plane); -- struct omap_overlay *ovl = omap_plane->ovl; -- int r; -+ bool enabled = (mode == DRM_MODE_DPMS_ON); -+ int ret = 0; - -- DBG("%s: %d", omap_plane->ovl->name, mode); -- -- if (mode == DRM_MODE_DPMS_ON) { -- update_scanout(plane); -- r = commit(plane); -- if (!r) -- r = ovl->enable(ovl); -- } else { -- struct omap_drm_private *priv = plane->dev->dev_private; -- r = ovl->disable(ovl); -- update_pin(plane, NULL); -- queue_work(priv->wq, &omap_plane->work); -+ if (enabled != omap_plane->enabled) { -+ omap_plane->enabled = enabled; -+ ret = apply(plane); - } - -- return r; --} -- --void omap_plane_on_endwin(struct drm_plane *plane, -- void (*fxn)(void *), void *arg) --{ -- struct omap_plane *omap_plane = to_omap_plane(plane); -- -- mutex_lock(&omap_plane->unpin_mutex); -- omap_plane->endwin.fxn = fxn; -- omap_plane->endwin.arg = arg; -- mutex_unlock(&omap_plane->unpin_mutex); -- -- install_irq(plane); -+ return ret; - } - - /* helper to install properties which are common to planes and crtcs */ -@@ -454,25 +337,13 @@ int omap_plane_set_property(struct drm_plane *plane, - int ret = -EINVAL; - - if (property == priv->rotation_prop) { -- struct omap_overlay *ovl = omap_plane->ovl; -- -- DBG("%s: rotation: %02x", ovl->name, (uint32_t)val); -+ DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val); - omap_plane->win.rotation = val; -- -- if (ovl->is_enabled(ovl)) -- ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON); -- else -- ret = 0; -+ ret = apply(plane); - } else if (property == priv->zorder_prop) { -- struct omap_overlay *ovl = omap_plane->ovl; -- -- DBG("%s: zorder: %d", ovl->name, (uint32_t)val); -+ DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val); - omap_plane->info.zorder = val; -- -- if (ovl->is_enabled(ovl)) -- ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON); -- else -- ret = 0; -+ ret = apply(plane); - } - - return ret; -@@ -485,20 +356,38 @@ static const struct drm_plane_funcs omap_plane_funcs = { - .set_property = omap_plane_set_property, - }; - -+static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) -+{ -+ struct omap_plane *omap_plane = -+ container_of(irq, struct omap_plane, error_irq); -+ DRM_ERROR("%s: errors: %08x\n", omap_plane->name, irqstatus); -+} -+ -+static const char *plane_names[] = { -+ [OMAP_DSS_GFX] = "gfx", -+ [OMAP_DSS_VIDEO1] = "vid1", -+ [OMAP_DSS_VIDEO2] = "vid2", -+ [OMAP_DSS_VIDEO3] = "vid3", -+}; -+ -+static const uint32_t error_irqs[] = { -+ [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW, -+ [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW, -+ [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW, -+ [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW, -+}; -+ - /* initialize plane */ - struct drm_plane *omap_plane_init(struct drm_device *dev, -- struct omap_overlay *ovl, unsigned int possible_crtcs, -- bool priv) -+ int id, bool private_plane) - { -+ struct omap_drm_private *priv = dev->dev_private; - struct drm_plane *plane = NULL; - struct omap_plane *omap_plane; -+ struct omap_overlay_info *info; - int ret; - -- DBG("%s: possible_crtcs=%08x, priv=%d", ovl->name, -- possible_crtcs, priv); -- -- /* friendly reminder to update table for future hw: */ -- WARN_ON(ovl->id >= ARRAY_SIZE(id2irq)); -+ DBG("%s: priv=%d", plane_names[id], private_plane); - - omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); - if (!omap_plane) { -@@ -506,47 +395,50 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, - goto fail; - } - -- mutex_init(&omap_plane->unpin_mutex); -- - ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL); - if (ret) { - dev_err(dev->dev, "could not allocate unpin FIFO\n"); - goto fail; - } - -- INIT_WORK(&omap_plane->work, unpin_worker); -- - omap_plane->nformats = omap_framebuffer_get_formats( - omap_plane->formats, ARRAY_SIZE(omap_plane->formats), -- ovl->supported_modes); -- omap_plane->ovl = ovl; -+ dss_feat_get_supported_color_modes(id)); -+ omap_plane->id = id; -+ omap_plane->name = plane_names[id]; -+ - plane = &omap_plane->base; - -- drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs, -- omap_plane->formats, omap_plane->nformats, priv); -+ omap_plane->apply.pre_apply = omap_plane_pre_apply; -+ omap_plane->apply.post_apply = omap_plane_post_apply; -+ -+ omap_plane->error_irq.irqmask = error_irqs[id]; -+ omap_plane->error_irq.irq = omap_plane_error_irq; -+ omap_irq_register(dev, &omap_plane->error_irq); -+ -+ drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs, -+ omap_plane->formats, omap_plane->nformats, private_plane); - - omap_plane_install_properties(plane, &plane->base); - - /* get our starting configuration, set defaults for parameters - * we don't currently use, etc: - */ -- ovl->get_overlay_info(ovl, &omap_plane->info); -- omap_plane->info.rotation_type = OMAP_DSS_ROT_DMA; -- omap_plane->info.rotation = OMAP_DSS_ROT_0; -- omap_plane->info.global_alpha = 0xff; -- omap_plane->info.mirror = 0; -+ info = &omap_plane->info; -+ info->rotation_type = OMAP_DSS_ROT_DMA; -+ info->rotation = OMAP_DSS_ROT_0; -+ info->global_alpha = 0xff; -+ info->mirror = 0; - - /* Set defaults depending on whether we are a CRTC or overlay - * layer. - * TODO add ioctl to give userspace an API to change this.. this - * will come in a subsequent patch. - */ -- if (priv) -+ if (private_plane) - omap_plane->info.zorder = 0; - else -- omap_plane->info.zorder = ovl->id; -- -- update_manager(plane); -+ omap_plane->info.zorder = id; - - return plane; - diff --git a/config-generic b/config-generic index b5d964155..ca7e7fb6e 100644 --- a/config-generic +++ b/config-generic @@ -1518,6 +1518,8 @@ CONFIG_ATH9K_HTC=m CONFIG_ATH9K_BTCOEX_SUPPORT=y # CONFIG_ATH9K_HTC_DEBUGFS is not set CONFIG_ATH9K_RATE_CONTROL=y +CONFIG_WIL6210=m +CONFIG_WIL6210_ISR_COR=y CONFIG_CARL9170=m CONFIG_CARL9170_LEDS=y # CONFIG_CARL9170_HWRNG is not set diff --git a/kernel.spec b/kernel.spec index 6c479b7c1..426e8c629 100644 --- a/kernel.spec +++ b/kernel.spec @@ -62,7 +62,7 @@ Summary: The Linux kernel # For non-released -rc kernels, this will be appended after the rcX and # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" # -%global baserelease 2 +%global baserelease 1 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -95,7 +95,7 @@ Summary: The Linux kernel # The rc snapshot level %define rcrev 3 # The git snapshot level -%define gitrev 1 +%define gitrev 2 # Set rpm version accordingly %define rpmversion 3.%{upstream_sublevel}.0 %endif @@ -717,7 +717,6 @@ Patch21001: arm-allnoconfig-error-__LINUX_ARM_ARCH__-undeclared.patch # OMAP # https://patchwork.kernel.org/patch/1721241/ # https://patchwork.kernel.org/patch/1839401/ -Patch21003: arm-omapdrm-fixinc.patch # ARM tegra Patch21004: arm-tegra-nvec-kconfig.patch @@ -737,10 +736,6 @@ Patch22070: irqnr-build.patch #rhbz 859485 Patch21226: vt-Drop-K_OFF-for-VC_MUTE.patch -#rhbz 883414 -Patch21236: mac80211-fix-ibss-scanning.patch - - # END OF PATCH DEFINITIONS %endif @@ -1301,7 +1296,6 @@ ApplyPatch vmbugon-warnon.patch # ApplyPatch arm-export-read_current_timer.patch ApplyPatch arm-allnoconfig-error-__LINUX_ARM_ARCH__-undeclared.patch -ApplyPatch arm-omapdrm-fixinc.patch # ApplyPatch arm-tegra-nvec-kconfig.patch ApplyPatch arm-tegra-usb-no-reset-linux33.patch @@ -1424,10 +1418,6 @@ ApplyPatch irqnr-build.patch #rhbz 859485 ApplyPatch vt-Drop-K_OFF-for-VC_MUTE.patch -#rhbz 883414 -ApplyPatch mac80211-fix-ibss-scanning.patch - - # END OF PATCH APPLICATIONS %endif @@ -2296,6 +2286,9 @@ fi # ||----w | # || || %changelog +* Tue Jan 15 2013 Justin M. Forbes - 3.8.0-0.rc3.git2.1 +- Linux v3.8-rc3-293-g406089d + * Tue Jan 15 2013 Josh Boyer - Enable CONFIG_DVB_USB_V2 (rhbz 895460) diff --git a/mac80211-fix-ibss-scanning.patch b/mac80211-fix-ibss-scanning.patch deleted file mode 100644 index c2bc698a0..000000000 --- a/mac80211-fix-ibss-scanning.patch +++ /dev/null @@ -1,132 +0,0 @@ -Do not scan on no-IBSS and disabled channels in IBSS mode. Doing this -can trigger Microcode errors on iwlwifi and iwlegacy drivers. - -Also rename ieee80211_request_internal_scan() function since it is only -used in IBSS mode and simplify calling it from ieee80211_sta_find_ibss(). - -This patch should address: -https://bugzilla.redhat.com/show_bug.cgi?id=883414 -https://bugzilla.kernel.org/show_bug.cgi?id=49411 - -Reported-by: Jesse Kahtava -Reported-by: Mikko Rapeli -Cc: stable@vger.kernel.org -Signed-off-by: Stanislaw Gruszka ---- - net/mac80211/ibss.c | 9 ++++----- - net/mac80211/ieee80211_i.h | 6 +++--- - net/mac80211/scan.c | 34 ++++++++++++++++++++++++---------- - 3 files changed, 31 insertions(+), 18 deletions(-) - -diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c -index c21e33d..d9df6b8 100644 ---- a/net/mac80211/ibss.c -+++ b/net/mac80211/ibss.c -@@ -678,8 +678,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) - sdata_info(sdata, - "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n"); - -- ieee80211_request_internal_scan(sdata, -- ifibss->ssid, ifibss->ssid_len, NULL); -+ ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, -+ NULL); - } - - static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) -@@ -777,9 +777,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) - IEEE80211_SCAN_INTERVAL)) { - sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); - -- ieee80211_request_internal_scan(sdata, -- ifibss->ssid, ifibss->ssid_len, -- ifibss->fixed_channel ? ifibss->channel : NULL); -+ ieee80211_request_ibss_scan(sdata, ifibss->ssid, -+ ifibss->ssid_len, chan); - } else { - int interval = IEEE80211_SCAN_INTERVAL; - -diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h -index 156e583..bc48d4d 100644 ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -1247,9 +1247,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, - - /* scan/BSS handling */ - void ieee80211_scan_work(struct work_struct *work); --int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, -- const u8 *ssid, u8 ssid_len, -- struct ieee80211_channel *chan); -+int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, -+ const u8 *ssid, u8 ssid_len, -+ struct ieee80211_channel *chan); - int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, - struct cfg80211_scan_request *req); - void ieee80211_scan_cancel(struct ieee80211_local *local); -diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c -index 43e60b5..fab706f 100644 ---- a/net/mac80211/scan.c -+++ b/net/mac80211/scan.c -@@ -819,9 +819,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, - return res; - } - --int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, -- const u8 *ssid, u8 ssid_len, -- struct ieee80211_channel *chan) -+int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, -+ const u8 *ssid, u8 ssid_len, -+ struct ieee80211_channel *chan) - { - struct ieee80211_local *local = sdata->local; - int ret = -EBUSY; -@@ -835,22 +835,36 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, - - /* fill internal scan request */ - if (!chan) { -- int i, nchan = 0; -+ int i, max_n; -+ int n_ch = 0; - - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - if (!local->hw.wiphy->bands[band]) - continue; -- for (i = 0; -- i < local->hw.wiphy->bands[band]->n_channels; -- i++) { -- local->int_scan_req->channels[nchan] = -+ -+ max_n = local->hw.wiphy->bands[band]->n_channels; -+ for (i = 0; i < max_n; i++) { -+ struct ieee80211_channel *tmp_ch = - &local->hw.wiphy->bands[band]->channels[i]; -- nchan++; -+ -+ if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS | -+ IEEE80211_CHAN_DISABLED)) -+ continue; -+ -+ local->int_scan_req->channels[n_ch] = tmp_ch; -+ n_ch++; - } - } - -- local->int_scan_req->n_channels = nchan; -+ if (WARN_ON_ONCE(n_ch == 0)) -+ goto unlock; -+ -+ local->int_scan_req->n_channels = n_ch; - } else { -+ if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS | -+ IEEE80211_CHAN_DISABLED))) -+ goto unlock; -+ - local->int_scan_req->channels[0] = chan; - local->int_scan_req->n_channels = 1; - } --- -1.7.1 - --- -To unsubscribe from this list: send the line "unsubscribe linux-wireless" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html \ No newline at end of file diff --git a/sources b/sources index 779b7d50f..626fd256d 100644 --- a/sources +++ b/sources @@ -1,3 +1,3 @@ 21223369d682bcf44bcdfe1521095983 linux-3.7.tar.xz f2b76b61390ce8f3e1303d9a6a645498 patch-3.8-rc3.xz -394345a07cea1f27afeb74a780597072 patch-3.8-rc3-git1.xz +fca85aec6adc6f3047d9b32e84560e5f patch-3.8-rc3-git2.xz