Fixes for omapdrm, some of which were already present in 3.14, and some which
appeared in 3.15-rc1: - fixes for primary-plane handling which caused crashes - fix all kinds of uninit issues which prevented from unloading the omapdrm module. - fixes for HDMI enable/disable issues -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABAgAGBQJTTkM7AAoJEPo9qoy8lh71JaQP/2NvUIr64vCXd39FqzrpwJ2n iRwHFt0M5sHld6NCNVyaThQtmRAN7u7fkInwcUWPU1yv0HIkHB2CRAzTx3H1Ca73 S+eaqda6Rog2oGh/Q6xmpAjaxZX0td9QhhGfKm9MlNJQ/a50H/7ovq5XZu2etfj2 m1nW6L1U+43aZYDLjM6T6IOydqWZGZ0jv6sNOAa4vwWWIJ85y+MybL2AL6SOQXpR LLbe/wI6eMBguJQOiLfZivFtlF7HzvT9I/VRhrtL+aanBOqVeqEFEcxJhutIl8/g NOZo+XfeRJqGJ5FDbgwFqP/+sDQEKQBHL+9/XfUVdJmKI3ihyhF5o4jCPpkHqYTP S3hyxQOkPZ/wgP8ucG0BvzhQRZoatSyIUbDE/98etmZ2pqLXk6d+tRs2uAev/0ec WLDc8/JEbTOE9cG/VAqVZTPsucuoWZ8Ow70v65ZlloqiaD/6QAWigavcQA1EZO+F cHBuwNXXAu8b2VV1cQcQVbihhga7lt1RFIzr7hQpniERK7tqeVqgapLWruxEJ5HZ 9HTRR+JIUydbXjsr0RtY3KIAKhKyfUiEAn7YIZBPpR7jSlUiexbX2ZrBN4Ea+sst Kjs/I71KN6j7lI3hh3R+HKOeYw9wqXuoqtojCafx2JRMEMhiSpOrAZuOjsW0fWSD AJhzTX8ZiFGFOB/oGdwp =03GJ -----END PGP SIGNATURE----- Merge tag 'omapdrm-fixes-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux into drm-next Fixes for omapdrm, some of which were already present in 3.14, and some which appeared in 3.15-rc1: - fixes for primary-plane handling which caused crashes - fix all kinds of uninit issues which prevented from unloading the omapdrm module. - fixes for HDMI enable/disable issues * tag 'omapdrm-fixes-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: drm/omap: fix the handling of fb ref counts drm/omap: protect omap_crtc's event with event_lock spinlock drm/omap: Use old_fb to synchronize between successive page flips drm/omap: Fix crash when using LCD3 overlay manager drm/omap: gem sync: wait on correct events drm/omap: Fix memory leak in omap_gem_op_async drm/omap: remove warn from debugfs drm/omap: remove extra plane->destroy from crtc destroy drm/omap: print warning when rotating non-TILER fb drm/omap: fix missing unref to fb's buf object drm/omap: fix plane rotation drm/omap: fix enabling/disabling of video pipeline drm/omap: fix missing disable for unused encoder drm/omap: fix race issue when unloading omapdrm drm/omap: fix DMM driver (un)registration drm/omap: fix uninit order in pdev_remove() drm/omap: fix output enable/disable sequence
This commit is contained in:
commit
d62c3e7a73
|
@ -33,6 +33,7 @@ struct omap_crtc {
|
|||
int pipe;
|
||||
enum omap_channel channel;
|
||||
struct omap_overlay_manager_info info;
|
||||
struct drm_encoder *current_encoder;
|
||||
|
||||
/*
|
||||
* Temporary: eventually this will go away, but it is needed
|
||||
|
@ -120,13 +121,25 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
|
|||
{
|
||||
}
|
||||
|
||||
static void set_enabled(struct drm_crtc *crtc, bool enable);
|
||||
|
||||
static int omap_crtc_enable(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
|
||||
|
@ -184,7 +197,6 @@ static void omap_crtc_destroy(struct drm_crtc *crtc)
|
|||
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);
|
||||
|
@ -338,17 +350,23 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
|
|||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||
struct drm_plane *primary = crtc->primary;
|
||||
struct drm_gem_object *bo;
|
||||
unsigned long flags;
|
||||
|
||||
DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1,
|
||||
fb->base.id, event);
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
|
||||
if (omap_crtc->old_fb) {
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
dev_err(dev->dev, "already a pending flip\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
omap_crtc->event = event;
|
||||
primary->fb = fb;
|
||||
omap_crtc->old_fb = primary->fb = fb;
|
||||
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
/*
|
||||
* Hold a reference temporarily until the crtc is updated
|
||||
|
@ -528,38 +546,46 @@ 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;
|
||||
struct omap_irq_wait *wait;
|
||||
u32 framedone_irq, vsync_irq;
|
||||
int ret;
|
||||
|
||||
if (dispc_mgr_is_enabled(channel) == enable)
|
||||
return;
|
||||
|
||||
/* ignore sync-lost irqs during enable/disable */
|
||||
/*
|
||||
* 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);
|
||||
|
||||
if (dispc_mgr_get_framedone_irq(channel)) {
|
||||
if (!enable) {
|
||||
wait = omap_irq_wait_init(dev,
|
||||
dispc_mgr_get_framedone_irq(channel), 1);
|
||||
}
|
||||
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 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
|
||||
* 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.
|
||||
*/
|
||||
wait = omap_irq_wait_init(dev,
|
||||
dispc_mgr_get_vsync_irq(channel), 2);
|
||||
|
||||
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);
|
||||
|
||||
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");
|
||||
}
|
||||
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);
|
||||
|
@ -586,8 +612,12 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
set_enabled(&omap_crtc->base, false);
|
||||
if (encoder)
|
||||
omap_encoder_set_enabled(encoder, false);
|
||||
} else {
|
||||
|
@ -596,13 +626,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
|
|||
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;
|
||||
|
@ -613,10 +637,30 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
};
|
||||
|
||||
void omap_crtc_pre_init(void)
|
||||
|
|
|
@ -513,12 +513,18 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
|
|||
static int dev_unload(struct drm_device *dev)
|
||||
{
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
int i;
|
||||
|
||||
DBG("unload: dev=%p", dev);
|
||||
|
||||
drm_kms_helper_poll_fini(dev);
|
||||
|
||||
omap_fbdev_free(dev);
|
||||
|
||||
/* flush crtcs so the fbs get released */
|
||||
for (i = 0; i < priv->num_crtcs; i++)
|
||||
omap_crtc_flush(priv->crtcs[i]);
|
||||
|
||||
omap_modeset_free(dev);
|
||||
omap_gem_deinit(dev);
|
||||
|
||||
|
@ -696,10 +702,11 @@ static int pdev_remove(struct platform_device *device)
|
|||
{
|
||||
DBG("");
|
||||
|
||||
drm_put_dev(platform_get_drvdata(device));
|
||||
|
||||
omap_disconnect_dssdevs();
|
||||
omap_crtc_pre_uninit();
|
||||
|
||||
drm_put_dev(platform_get_drvdata(device));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -726,18 +733,33 @@ static struct platform_driver pdev = {
|
|||
|
||||
static int __init omap_drm_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DBG("init");
|
||||
if (platform_driver_register(&omap_dmm_driver)) {
|
||||
/* we can continue on without DMM.. so not fatal */
|
||||
dev_err(NULL, "DMM registration failed\n");
|
||||
|
||||
r = platform_driver_register(&omap_dmm_driver);
|
||||
if (r) {
|
||||
pr_err("DMM driver registration failed\n");
|
||||
return r;
|
||||
}
|
||||
return platform_driver_register(&pdev);
|
||||
|
||||
r = platform_driver_register(&pdev);
|
||||
if (r) {
|
||||
pr_err("omapdrm driver registration failed\n");
|
||||
platform_driver_unregister(&omap_dmm_driver);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit omap_drm_fini(void)
|
||||
{
|
||||
DBG("fini");
|
||||
|
||||
platform_driver_unregister(&pdev);
|
||||
|
||||
platform_driver_unregister(&omap_dmm_driver);
|
||||
}
|
||||
|
||||
/* need late_initcall() so we load after dss_driver's are loaded */
|
||||
|
|
|
@ -163,6 +163,7 @@ void omap_crtc_pre_init(void);
|
|||
void omap_crtc_pre_uninit(void);
|
||||
struct drm_crtc *omap_crtc_init(struct drm_device *dev,
|
||||
struct drm_plane *plane, enum omap_channel channel, int id);
|
||||
void omap_crtc_flush(struct drm_crtc *crtc);
|
||||
|
||||
struct drm_plane *omap_plane_init(struct drm_device *dev,
|
||||
int plane_id, bool private_plane);
|
||||
|
|
|
@ -218,6 +218,20 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
|
|||
info->rotation_type = OMAP_DSS_ROT_TILER;
|
||||
info->screen_width = omap_gem_tiled_stride(plane->bo, orient);
|
||||
} else {
|
||||
switch (win->rotation & 0xf) {
|
||||
case 0:
|
||||
case BIT(DRM_ROTATE_0):
|
||||
/* OK */
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(fb->dev->dev,
|
||||
"rotation '%d' ignored for non-tiled fb\n",
|
||||
win->rotation);
|
||||
win->rotation = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
info->paddr = get_linear_addr(plane, format, 0, x, y);
|
||||
info->rotation_type = OMAP_DSS_ROT_DMA;
|
||||
info->screen_width = plane->pitch;
|
||||
|
|
|
@ -371,6 +371,9 @@ void omap_fbdev_free(struct drm_device *dev)
|
|||
|
||||
fbdev = to_omap_fbdev(priv->fbdev);
|
||||
|
||||
/* release the ref taken in omap_fbdev_create() */
|
||||
omap_gem_put_paddr(fbdev->bo);
|
||||
|
||||
/* this will free the backing object */
|
||||
if (fbdev->fb) {
|
||||
drm_framebuffer_unregister_private(fbdev->fb);
|
||||
|
|
|
@ -980,12 +980,9 @@ int omap_gem_resume(struct device *dev)
|
|||
#ifdef CONFIG_DEBUG_FS
|
||||
void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
|
||||
{
|
||||
struct drm_device *dev = obj->dev;
|
||||
struct omap_gem_object *omap_obj = to_omap_bo(obj);
|
||||
uint64_t off;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
|
||||
|
||||
off = drm_vma_node_start(&obj->vma_node);
|
||||
|
||||
seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d",
|
||||
|
@ -1050,10 +1047,10 @@ static inline bool is_waiting(struct omap_gem_sync_waiter *waiter)
|
|||
{
|
||||
struct omap_gem_object *omap_obj = waiter->omap_obj;
|
||||
if ((waiter->op & OMAP_GEM_READ) &&
|
||||
(omap_obj->sync->read_complete < waiter->read_target))
|
||||
(omap_obj->sync->write_complete < waiter->write_target))
|
||||
return true;
|
||||
if ((waiter->op & OMAP_GEM_WRITE) &&
|
||||
(omap_obj->sync->write_complete < waiter->write_target))
|
||||
(omap_obj->sync->read_complete < waiter->read_target))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -1229,6 +1226,8 @@ int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,
|
|||
}
|
||||
|
||||
spin_unlock(&sync_lock);
|
||||
|
||||
kfree(waiter);
|
||||
}
|
||||
|
||||
/* no waiting.. */
|
||||
|
|
|
@ -225,6 +225,11 @@ int omap_plane_mode_set(struct drm_plane *plane,
|
|||
omap_plane->apply_done_cb.arg = arg;
|
||||
}
|
||||
|
||||
if (plane->fb)
|
||||
drm_framebuffer_unreference(plane->fb);
|
||||
|
||||
drm_framebuffer_reference(fb);
|
||||
|
||||
plane->fb = fb;
|
||||
plane->crtc = crtc;
|
||||
|
||||
|
@ -241,10 +246,13 @@ static int omap_plane_update(struct drm_plane *plane,
|
|||
struct omap_plane *omap_plane = to_omap_plane(plane);
|
||||
omap_plane->enabled = true;
|
||||
|
||||
if (plane->fb)
|
||||
drm_framebuffer_unreference(plane->fb);
|
||||
|
||||
drm_framebuffer_reference(fb);
|
||||
/* omap_plane_mode_set() takes adjusted src */
|
||||
switch (omap_plane->win.rotation & 0xf) {
|
||||
case BIT(DRM_ROTATE_90):
|
||||
case BIT(DRM_ROTATE_270):
|
||||
swap(src_w, src_h);
|
||||
break;
|
||||
}
|
||||
|
||||
return omap_plane_mode_set(plane, crtc, fb,
|
||||
crtc_x, crtc_y, crtc_w, crtc_h,
|
||||
|
|
Loading…
Reference in New Issue