summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustin M. Forbes <jforbes@redhat.com>2013-01-15 17:02:15 -0600
committerJustin M. Forbes <jforbes@redhat.com>2013-01-15 17:02:15 -0600
commit45aa9a25561570fc0feb8d355edaf7f763b4743e (patch)
tree944fa93e771016e9f7e769f6ad7df99b2a50cdad
parentaef2a4b3e0119151b8cf7b01689478c5664bc64c (diff)
downloadkernel-45aa9a25561570fc0feb8d355edaf7f763b4743e.tar.gz
kernel-45aa9a25561570fc0feb8d355edaf7f763b4743e.tar.xz
kernel-45aa9a25561570fc0feb8d355edaf7f763b4743e.zip
Linux v3.8-rc3-293-g406089d
-rw-r--r--arm-omapdrm-fixinc.patch2767
-rw-r--r--config-generic2
-rw-r--r--kernel.spec17
-rw-r--r--mac80211-fix-ibss-scanning.patch132
-rw-r--r--sources2
5 files changed, 8 insertions, 2912 deletions
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 <linux/platform_data/omap_drm.h>
- #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 <linux/list.h>
-+
-+
- /*
- * 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 <rob.clark@linaro.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 as published by
-+ * the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-+ * more details.
-+ *
-+ * You should have received a copy of the GNU General Public License along with
-+ * this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#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 <jforbes@redhat.com> - 3.8.0-0.rc3.git2.1
+- Linux v3.8-rc3-293-g406089d
+
* Tue Jan 15 2013 Josh Boyer <jwboyer@redhat.com>
- 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 <jesse_kahtava@f-m.fm>
-Reported-by: Mikko Rapeli <mikko.rapeli@iki.fi>
-Cc: stable@vger.kernel.org
-Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
----
- 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