On Friday 16 November 2012 05:30 AM, Rob Clark wrote: > This patch changes the omapdrm KMS to bypass the omapdss "compat" > layer and use the core omapdss API directly. This solves some layering > issues that would cause unpin confusion vs GO bit status, because we > would not know whether a particular pageflip or overlay update has hit > the screen or not. Now instead we explicitly manage the GO bits in > dispc and handle the vblank/framedone interrupts ourself so that we > always know which buffers are being scanned out at any given time, and > so on. > > As an added bonus, we no longer leave the last overlay buffer pinned > when the display is disabled, and have been able to add the previously > missing vblank event handling. > > Signed-off-by: Rob Clark <robdclark at gmail.com> > --- > Note: this patch applies on top of staging-next plus the "OMAPDSS: > create compat layer" patch series: > > http://comments.gmane.org/gmane.linux.ports.arm.omap/89435 > > drivers/staging/omapdrm/Makefile | 1 + > drivers/staging/omapdrm/TODO | 3 - > drivers/staging/omapdrm/omap_connector.c | 111 +------- > drivers/staging/omapdrm/omap_crtc.c | 472 > +++++++++++++++++++++++++++++-- > drivers/staging/omapdrm/omap_drv.c | 439 +++++----------------------- > drivers/staging/omapdrm/omap_drv.h | 140 +++++++-- > drivers/staging/omapdrm/omap_encoder.c | 132 ++++----- > drivers/staging/omapdrm/omap_irq.c | 322 +++++++++++++++++++++ > drivers/staging/omapdrm/omap_plane.c | 452 +++++++++++------------------ > 9 files changed, 1207 insertions(+), 865 deletions(-) > create mode 100644 drivers/staging/omapdrm/omap_irq.c > > 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 3e2c736..e3496e5 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);
Maybe you should move this dispc write also to omap_crtc_pre_apply, the same way it's done for timings. We'll also be confident about having the clocks required if this is called in pre_apply. > +} > + > +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) > @@ -123,7 +261,7 @@ static void vblank_cb(void *arg) > > /* wakeup userspace */ > if (omap_crtc->event) > - drm_send_vblank_event(dev, -1, omap_crtc->event); > + drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event); > > omap_crtc->event = NULL; > omap_crtc->old_fb = NULL; > @@ -131,25 +269,37 @@ static void vblank_cb(void *arg) > 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_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) > @@ -158,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->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; > > @@ -213,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 if (!dispc_mgr_go_busy(channel)) { I'm not clear about this. Why would GO be set in the first place if the manager isn't enabled? This could be replaced with a simple '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) { If I get it right, full_update refers to manager properties that previously used to propogate downstream from the output driver to dispc, i.e, things like timings and so on. and the ones which aren't full_update are upstream properties like transparency keys, default_color and so on? > + 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; > +} > + >< snip > > -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_display_type supported_displays = > + > dss_feat_get_supported_displays(pipe2chan(id)); We could use the newer version here: dss_feat_get_supported_outputs(), this will tell what all outputs a manager can connect to. > + if (supported_displays & dssdev->type) > + 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; > - } > - How can omapdss_compat_init/ininit already exist in the driver, and removed in this patch? <snip> Archit