diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-27 16:32:45 +0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-27 16:32:45 +0300 |
commit | b3e5ced63e051e8f911b795ac5b06229a5328f7b (patch) | |
tree | e63badb76509839ec948431859255923b6e2a09c /drivers/gpu/drm/omapdrm/omap_crtc.c | |
parent | e183201b9e917daf2530b637b2f34f1d5afb934d (diff) | |
parent | b787f68c36d49bb1d9236f403813641efa74a031 (diff) | |
download | linux-b3e5ced63e051e8f911b795ac5b06229a5328f7b.tar.xz |
Merge tag 'v4.1-rc1' into patchwork
Linux 4.1-rc1
* tag 'v4.1-rc1': (11651 commits)
Linux 4.1-rc1
x86_64, asm: Work around AMD SYSRET SS descriptor attribute issue
v4l: xilinx: fix for include file movement
platform/chrome: chromeos_laptop - instantiate Atmel at primary address
RCU pathwalk breakage when running into a symlink overmounting something
fix I_DIO_WAKEUP definition
direct-io: only inc/dec inode->i_dio_count for file systems
fs/9p: fix readdir()
Btrfs: prevent list corruption during free space cache processing
toshiba_acpi: Do not register vendor backlight when acpi_video bl is available
x86: fix special __probe_kernel_write() tail zeroing case
crypto: img-hash - CRYPTO_DEV_IMGTEC_HASH should depend on HAS_DMA
crypto: x86/sha512_ssse3 - fixup for asm function prototype change
nios2: rework cache
nios2: Add types.h header required for __u32 type
ALSA: hda - fix headset mic detection problem for one more machine
eth: bf609 eth clock: add pclk clock for stmmac driver probe
blackfin: Wire up missing syscalls
Btrfs: fix inode cache writeout
ACPI / scan: Add a scan handler for PRP0001
...
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c')
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_crtc.c | 622 |
1 files changed, 320 insertions, 302 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index b0566a1ca28f..f456544bf300 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -28,7 +28,6 @@ struct omap_crtc { struct drm_crtc base; - struct drm_plane *plane; const char *name; int pipe; @@ -46,7 +45,6 @@ struct omap_crtc { struct omap_video_timings timings; bool enabled; - bool full_update; struct omap_drm_apply apply; @@ -74,8 +72,14 @@ struct omap_crtc { * XXX maybe fold into apply_work?? */ struct work_struct page_flip_work; + + bool ignore_digit_sync_lost; }; +/* ----------------------------------------------------------------------------- + * Helper Functions + */ + uint32_t pipe2vbl(struct drm_crtc *crtc) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); @@ -83,6 +87,22 @@ uint32_t pipe2vbl(struct drm_crtc *crtc) return dispc_mgr_get_vsync_irq(omap_crtc->channel); } +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; +} + +/* ----------------------------------------------------------------------------- + * DSS Manager Functions + */ + /* * Manager-ops, callbacks from output when they need to configure * the upstream part of the video pipe. @@ -122,7 +142,63 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr) { } -static void set_enabled(struct drm_crtc *crtc, bool enable); +/* Called only from CRTC pre_apply and suspend/resume handlers. */ +static void omap_crtc_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; + u32 framedone_irq, vsync_irq; + int ret; + + if (dispc_mgr_is_enabled(channel) == enable) + return; + + if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) { + /* + * Digit output produces some sync lost interrupts during the + * first frame when enabling, so we need to ignore those. + */ + omap_crtc->ignore_digit_sync_lost = true; + } + + framedone_irq = dispc_mgr_get_framedone_irq(channel); + vsync_irq = dispc_mgr_get_vsync_irq(channel); + + if (enable) { + wait = omap_irq_wait_init(dev, vsync_irq, 1); + } else { + /* + * When we disable the digit output, we need to wait for + * FRAMEDONE to know that DISPC has finished with the output. + * + * OMAP2/3 does not have FRAMEDONE irq for digit output, and in + * that case we need to use vsync interrupt, and wait for both + * even and odd frames. + */ + + if (framedone_irq) + wait = omap_irq_wait_init(dev, framedone_irq, 1); + else + wait = omap_irq_wait_init(dev, vsync_irq, 2); + } + + dispc_mgr_enable(channel, enable); + + 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"); + } + + if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) { + omap_crtc->ignore_digit_sync_lost = false; + /* make sure the irq handler sees the value above */ + mb(); + } +} + static int omap_crtc_enable(struct omap_overlay_manager *mgr) { @@ -131,7 +207,7 @@ static int omap_crtc_enable(struct omap_overlay_manager *mgr) 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_set_enabled(&omap_crtc->base, true); return 0; } @@ -140,7 +216,7 @@ static void omap_crtc_disable(struct omap_overlay_manager *mgr) { struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; - set_enabled(&omap_crtc->base, false); + omap_crtc_set_enabled(&omap_crtc->base, false); } static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, @@ -149,7 +225,6 @@ static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; 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, @@ -174,19 +249,201 @@ static void omap_crtc_unregister_framedone_handler( } static const struct dss_mgr_ops mgr_ops = { - .connect = omap_crtc_connect, - .disconnect = omap_crtc_disconnect, - .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, + .connect = omap_crtc_connect, + .disconnect = omap_crtc_disconnect, + .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: +/* ----------------------------------------------------------------------------- + * Apply Logic + */ + +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); + + if (omap_crtc->ignore_digit_sync_lost) { + irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT; + if (!irqstatus) + return; + } + + DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus); +} + +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 (!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. + */ + drm_modeset_lock(&crtc->mutex, NULL); + 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)) { + dispc_mgr_go(channel); + omap_irq_register(dev, &omap_crtc->apply_irq); + } else { + struct omap_drm_private *priv = dev->dev_private; + queue_work(priv->wq, &omap_crtc->apply_work); + } + } + +out: + dispc_runtime_put(); + drm_modeset_unlock(&crtc->mutex); +} + +int omap_crtc_apply(struct drm_crtc *crtc, + struct omap_drm_apply *apply) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + + WARN_ON(!drm_modeset_is_locked(&crtc->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; +} + +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 omap_drm_private *priv = crtc->dev->dev_private; + struct drm_encoder *encoder = NULL; + unsigned int i; + + DBG("%s: enabled=%d", omap_crtc->name, omap_crtc->enabled); + + for (i = 0; i < priv->num_encoders; i++) { + if (priv->encoders[i]->crtc == crtc) { + encoder = priv->encoders[i]; + break; + } + } + + if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder) + omap_encoder_set_enabled(omap_crtc->current_encoder, false); + + omap_crtc->current_encoder = encoder; + + if (!omap_crtc->enabled) { + 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); + } + } +} + +static void omap_crtc_post_apply(struct omap_drm_apply *apply) +{ + /* nothing needed for post-apply */ +} + +void omap_crtc_flush(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + int loops = 0; + + while (!list_empty(&omap_crtc->pending_applies) || + !list_empty(&omap_crtc->queued_applies) || + omap_crtc->event || omap_crtc->old_fb) { + + if (++loops > 10) { + dev_err(crtc->dev->dev, + "omap_crtc_flush() timeout\n"); + break; + } + + schedule_timeout_uninterruptible(msecs_to_jiffies(20)); + } +} + +/* ----------------------------------------------------------------------------- + * CRTC Functions */ static void omap_crtc_destroy(struct drm_crtc *crtc) @@ -214,17 +471,13 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) if (enabled != omap_crtc->enabled) { omap_crtc->enabled = enabled; - omap_crtc->full_update = true; omap_crtc_apply(crtc, &omap_crtc->apply); - /* also enable our private plane: */ - WARN_ON(omap_plane_dpms(omap_crtc->plane, mode)); - - /* and any attached overlay planes: */ + /* Enable/disable all planes associated with the CRTC. */ 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)); + WARN_ON(omap_plane_set_enable(plane, enabled)); } } } @@ -256,13 +509,17 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc, 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->primary->fb, - 0, 0, mode->hdisplay, mode->vdisplay, - x << 16, y << 16, - mode->hdisplay << 16, mode->vdisplay << 16, - NULL, NULL); + /* + * The primary plane CRTC can be reset if the plane is disabled directly + * through the universal plane API. Set it again here. + */ + crtc->primary->crtc = crtc; + + return omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb, + 0, 0, mode->hdisplay, mode->vdisplay, + x, y, mode->hdisplay, mode->vdisplay, + NULL, NULL); } static void omap_crtc_prepare(struct drm_crtc *crtc) @@ -282,15 +539,13 @@ static void omap_crtc_commit(struct drm_crtc *crtc) static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); - struct drm_plane *plane = omap_crtc->plane; + struct drm_plane *plane = crtc->primary; struct drm_display_mode *mode = &crtc->mode; return omap_plane_mode_set(plane, crtc, crtc->primary->fb, - 0, 0, mode->hdisplay, mode->vdisplay, - x << 16, y << 16, - mode->hdisplay << 16, mode->vdisplay << 16, - NULL, NULL); + 0, 0, mode->hdisplay, mode->vdisplay, + x, y, mode->hdisplay, mode->vdisplay, + NULL, NULL); } static void vblank_cb(void *arg) @@ -299,6 +554,7 @@ static void vblank_cb(void *arg) struct drm_device *dev = crtc->dev; struct omap_crtc *omap_crtc = to_omap_crtc(crtc); unsigned long flags; + struct drm_framebuffer *fb; spin_lock_irqsave(&dev->event_lock, flags); @@ -306,10 +562,15 @@ static void vblank_cb(void *arg) if (omap_crtc->event) drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event); + fb = omap_crtc->old_fb; + omap_crtc->event = NULL; omap_crtc->old_fb = NULL; spin_unlock_irqrestore(&dev->event_lock, flags); + + if (fb) + drm_framebuffer_unreference(fb); } static void page_flip_worker(struct work_struct *work) @@ -321,11 +582,10 @@ static void page_flip_worker(struct work_struct *work) struct drm_gem_object *bo; drm_modeset_lock(&crtc->mutex, NULL); - omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb, - 0, 0, mode->hdisplay, mode->vdisplay, - crtc->x << 16, crtc->y << 16, - mode->hdisplay << 16, mode->vdisplay << 16, - vblank_cb, crtc); + omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb, + 0, 0, mode->hdisplay, mode->vdisplay, + crtc->x, crtc->y, mode->hdisplay, mode->vdisplay, + vblank_cb, crtc); drm_modeset_unlock(&crtc->mutex); bo = omap_framebuffer_bo(crtc->primary->fb, 0); @@ -361,11 +621,12 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, if (omap_crtc->old_fb) { spin_unlock_irqrestore(&dev->event_lock, flags); dev_err(dev->dev, "already a pending flip\n"); - return -EINVAL; + return -EBUSY; } omap_crtc->event = event; omap_crtc->old_fb = primary->fb = fb; + drm_framebuffer_reference(omap_crtc->old_fb); spin_unlock_irqrestore(&dev->event_lock, flags); @@ -385,7 +646,6 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, static int omap_crtc_set_property(struct drm_crtc *crtc, struct drm_property *property, uint64_t val) { - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct omap_drm_private *priv = crtc->dev->dev_private; if (property == priv->rotation_prop) { @@ -393,7 +653,7 @@ static int omap_crtc_set_property(struct drm_crtc *crtc, !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270))); } - return omap_plane_set_property(omap_crtc->plane, property, val); + return omap_plane_set_property(crtc->primary, property, val); } static const struct drm_crtc_funcs omap_crtc_funcs = { @@ -412,256 +672,15 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { .mode_set_base = omap_crtc_mode_set_base, }; -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. - */ - drm_modeset_lock(&crtc->mutex, NULL); - 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(); - drm_modeset_unlock(&crtc->mutex); -} - -int omap_crtc_apply(struct drm_crtc *crtc, - struct omap_drm_apply *apply) -{ - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); - - WARN_ON(!drm_modeset_is_locked(&crtc->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; - u32 framedone_irq, vsync_irq; - int ret; - - if (dispc_mgr_is_enabled(channel) == enable) - return; - - /* - * Digit output produces some sync lost interrupts during the first - * frame when enabling, so we need to ignore those. - */ - omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); - - framedone_irq = dispc_mgr_get_framedone_irq(channel); - vsync_irq = dispc_mgr_get_vsync_irq(channel); - - if (enable) { - wait = omap_irq_wait_init(dev, vsync_irq, 1); - } else { - /* - * When we disable the digit output, we need to wait for - * FRAMEDONE to know that DISPC has finished with the output. - * - * OMAP2/3 does not have FRAMEDONE irq for digit output, and in - * that case we need to use vsync interrupt, and wait for both - * even and odd frames. - */ - - if (framedone_irq) - wait = omap_irq_wait_init(dev, framedone_irq, 1); - else - wait = omap_irq_wait_init(dev, vsync_irq, 2); - } - - dispc_mgr_enable(channel, enable); - - 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->current_encoder && encoder != omap_crtc->current_encoder) - omap_encoder_set_enabled(omap_crtc->current_encoder, false); - - omap_crtc->current_encoder = encoder; - - if (!omap_crtc->enabled) { - 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; -} - -static void omap_crtc_post_apply(struct omap_drm_apply *apply) -{ - /* nothing needed for post-apply */ -} - -void omap_crtc_flush(struct drm_crtc *crtc) -{ - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); - int loops = 0; - - while (!list_empty(&omap_crtc->pending_applies) || - !list_empty(&omap_crtc->queued_applies) || - omap_crtc->event || omap_crtc->old_fb) { - - if (++loops > 10) { - dev_err(crtc->dev->dev, - "omap_crtc_flush() timeout\n"); - break; - } - - schedule_timeout_uninterruptible(msecs_to_jiffies(20)); - } -} +/* ----------------------------------------------------------------------------- + * Init and Cleanup + */ static const char *channel_names[] = { - [OMAP_DSS_CHANNEL_LCD] = "lcd", - [OMAP_DSS_CHANNEL_DIGIT] = "tv", - [OMAP_DSS_CHANNEL_LCD2] = "lcd2", - [OMAP_DSS_CHANNEL_LCD3] = "lcd3", + [OMAP_DSS_CHANNEL_LCD] = "lcd", + [OMAP_DSS_CHANNEL_DIGIT] = "tv", + [OMAP_DSS_CHANNEL_LCD2] = "lcd2", + [OMAP_DSS_CHANNEL_LCD3] = "lcd3", }; void omap_crtc_pre_init(void) @@ -681,12 +700,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, struct drm_crtc *crtc = NULL; struct omap_crtc *omap_crtc; struct omap_overlay_manager_info *info; + int ret; DBG("%s", channel_names[channel]); omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); if (!omap_crtc) - goto fail; + return NULL; crtc = &omap_crtc->base; @@ -700,8 +720,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, omap_crtc->apply.post_apply = omap_crtc_post_apply; omap_crtc->channel = channel; - omap_crtc->plane = plane; - omap_crtc->plane->crtc = crtc; omap_crtc->name = channel_names[channel]; omap_crtc->pipe = id; @@ -723,18 +741,18 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; info->trans_enabled = false; - drm_crtc_init(dev, crtc, &omap_crtc_funcs); + ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, + &omap_crtc_funcs); + if (ret < 0) { + kfree(omap_crtc); + return NULL; + } + drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); - omap_plane_install_properties(omap_crtc->plane, &crtc->base); + omap_plane_install_properties(crtc->primary, &crtc->base); omap_crtcs[channel] = omap_crtc; return crtc; - -fail: - if (crtc) - omap_crtc_destroy(crtc); - - return NULL; } |