From 222025e42d7f77133b8c3a2355d20a6004096c4b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Jan 2015 00:02:07 +0200 Subject: drm: omapdrm: Fix indentation of structure and array initializers Indenting by one tab is enough. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_crtc.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index b0566a1ca28f..b9c3d8f830e8 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -174,15 +174,15 @@ 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, }; /* @@ -658,10 +658,10 @@ void omap_crtc_flush(struct drm_crtc *crtc) } 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) -- cgit From ef6b0e0275387f79e6ad848d61dfcb1a4f962fc7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Jan 2015 00:11:18 +0200 Subject: drm: omapdrm: Switch to the universal plane API Remove the CRTC private planes by switching to the universal plane API. This results in a merge of the CRTC private plane created by the driver (omap_crtc->plane) and the CRTC primary plane created by the DRM core (crtc->primary). Reference counting of the framebuffers in the update plane operation is thus simplified as no reference needs to be stored in the private plane anymore. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_crtc.c | 43 ++++++++++++++++++------------------ drivers/gpu/drm/omapdrm/omap_drv.c | 4 ++-- drivers/gpu/drm/omapdrm/omap_drv.h | 2 +- drivers/gpu/drm/omapdrm/omap_plane.c | 36 ++++++++++++++++++------------ 4 files changed, 46 insertions(+), 39 deletions(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index b9c3d8f830e8..7570db59a9ea 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; @@ -217,10 +216,7 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) 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) @@ -258,7 +254,13 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc, 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, + /* + * 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 << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16, @@ -282,8 +284,7 @@ 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, @@ -321,7 +322,7 @@ 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, + omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, crtc->x << 16, crtc->y << 16, mode->hdisplay << 16, mode->vdisplay << 16, @@ -385,7 +386,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 +393,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 = { @@ -681,12 +681,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 +701,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 +722,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; } diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 021855605a1f..5eab83d7de15 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -135,7 +135,7 @@ static int omap_modeset_create_crtc(struct drm_device *dev, int id, struct drm_plane *plane; struct drm_crtc *crtc; - plane = omap_plane_init(dev, id, true); + plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_PRIMARY); if (IS_ERR(plane)) return PTR_ERR(plane); @@ -277,7 +277,7 @@ static int omap_modeset_init(struct drm_device *dev) for (; id < num_ovls; id++) { struct drm_plane *plane; - plane = omap_plane_init(dev, id, false); + plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_OVERLAY); if (IS_ERR(plane)) return PTR_ERR(plane); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 60e47b33c801..f38ffd14ff06 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -160,7 +160,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, void omap_crtc_flush(struct drm_crtc *crtc); struct drm_plane *omap_plane_init(struct drm_device *dev, - int plane_id, bool private_plane); + int id, enum drm_plane_type type); 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, diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index c17460336fcc..32df3e783128 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -220,14 +220,6 @@ 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; - return apply(plane); } @@ -249,6 +241,13 @@ static int omap_plane_update(struct drm_plane *plane, break; } + /* + * We don't need to take a reference to the framebuffer as the DRM core + * has already done so for the purpose of setting plane->fb. + */ + plane->fb = fb; + plane->crtc = crtc; + return omap_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h, @@ -377,14 +376,15 @@ static const uint32_t error_irqs[] = { /* initialize plane */ struct drm_plane *omap_plane_init(struct drm_device *dev, - int id, bool private_plane) + int id, enum drm_plane_type type) { struct omap_drm_private *priv = dev->dev_private; - struct drm_plane *plane = NULL; + struct drm_plane *plane; struct omap_plane *omap_plane; struct omap_overlay_info *info; + int ret; - DBG("%s: priv=%d", plane_names[id], private_plane); + DBG("%s: type=%d", plane_names[id], type); omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); if (!omap_plane) @@ -408,8 +408,11 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, 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); + ret = drm_universal_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, + &omap_plane_funcs, omap_plane->formats, + omap_plane->nformats, type); + if (ret < 0) + goto error; omap_plane_install_properties(plane, &plane->base); @@ -427,10 +430,15 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, * TODO add ioctl to give userspace an API to change this.. this * will come in a subsequent patch. */ - if (private_plane) + if (type == DRM_PLANE_TYPE_PRIMARY) omap_plane->info.zorder = 0; else omap_plane->info.zorder = id; return plane; + +error: + omap_irq_unregister(plane->dev, &omap_plane->error_irq); + kfree(omap_plane); + return NULL; } -- cgit From 2debab97a515374c01d50068de00c95f9befd260 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 12 Jan 2015 22:38:16 +0200 Subject: drm: omapdrm: Rename omap_plane_dpms() to omap_plane_set_enable() The planes don't care about DPMS states, don't propagate it unnecessarily to the plane functions. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_crtc.c | 2 +- drivers/gpu/drm/omapdrm/omap_drv.h | 2 +- drivers/gpu/drm/omapdrm/omap_plane.c | 16 +++++++--------- 3 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 7570db59a9ea..c7d3e1eec6cb 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -220,7 +220,7 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) 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)); } } } diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index f38ffd14ff06..fa6becc4d1be 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -161,7 +161,7 @@ void omap_crtc_flush(struct drm_crtc *crtc); struct drm_plane *omap_plane_init(struct drm_device *dev, int id, enum drm_plane_type type); -int omap_plane_dpms(struct drm_plane *plane, int mode); +int omap_plane_set_enable(struct drm_plane *plane, bool enable); int omap_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 32df3e783128..34f5cca5a6c5 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -257,8 +257,9 @@ static int omap_plane_update(struct drm_plane *plane, static int omap_plane_disable(struct drm_plane *plane) { struct omap_plane *omap_plane = to_omap_plane(plane); + omap_plane->win.rotation = BIT(DRM_ROTATE_0); - return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); + return omap_plane_set_enable(plane, false); } static void omap_plane_destroy(struct drm_plane *plane) @@ -277,18 +278,15 @@ static void omap_plane_destroy(struct drm_plane *plane) kfree(omap_plane); } -int omap_plane_dpms(struct drm_plane *plane, int mode) +int omap_plane_set_enable(struct drm_plane *plane, bool enable) { struct omap_plane *omap_plane = to_omap_plane(plane); - bool enabled = (mode == DRM_MODE_DPMS_ON); - int ret = 0; - if (enabled != omap_plane->enabled) { - omap_plane->enabled = enabled; - ret = apply(plane); - } + if (enable == omap_plane->enabled) + return 0; - return ret; + omap_plane->enabled = enable; + return apply(plane); } /* helper to install properties which are common to planes and crtcs */ -- cgit From 5dbe44336811a7e8ef4c958c6ac054772ee47637 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Jan 2015 09:14:53 +0200 Subject: drm: omapdrm: Fix race condition between GO and vblank IRQ The vblank interrupt is used by the driver as a completion signal when applying new settings. A race condition exist between enabling the vblank interrupt and applying new settings to the hardware by setting the GO bit. If a vblank interrupt occurs in-between, the driver will incorrectly consider the new settings to be applied. Fix this by enabling the interrupt after setting the GO bit. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index c7d3e1eec6cb..3f811186c891 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -501,8 +501,8 @@ static void apply_worker(struct work_struct *work) DBG("%s: GO", omap_crtc->name); if (dispc_mgr_is_enabled(channel)) { - omap_irq_register(dev, &omap_crtc->apply_irq); 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); -- cgit From 297767b68146f2355dfb10cb57185bef7769dfd9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 15 Jan 2015 00:31:11 +0200 Subject: drm: omapdrm: Remove omap_crtc->full_update field The full_update field is always set to true before calling omap_crtc_appy(), resulting in its value always being true in the single location where it is tested, in omap_crtc_pre_apply(). Remove it. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_crtc.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 3f811186c891..e04782489224 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -45,7 +45,6 @@ struct omap_crtc { struct omap_video_timings timings; bool enabled; - bool full_update; struct omap_drm_apply apply; @@ -148,7 +147,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, @@ -213,7 +211,6 @@ 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); /* Enable/disable all planes associated with the CRTC. */ @@ -252,7 +249,6 @@ 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; /* * The primary plane CRTC can be reset if the plane is disabled directly @@ -597,19 +593,16 @@ 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, full=%d", omap_crtc->name, - omap_crtc->enabled, omap_crtc->full_update); + DBG("%s: enabled=%d", omap_crtc->name, omap_crtc->enabled); - 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; - } + for (i = 0; i < priv->num_encoders; i++) { + if (priv->encoders[i]->crtc == crtc) { + encoder = priv->encoders[i]; + break; } } @@ -629,8 +622,6 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply) omap_encoder_set_enabled(encoder, true); } } - - omap_crtc->full_update = false; } static void omap_crtc_post_apply(struct omap_drm_apply *apply) -- cgit From 8472b5708ebaabf4568fe53672db7567e94c4c65 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 15 Jan 2015 00:45:17 +0200 Subject: drm: omapdrm: Avoid function forward declaration in omap_crtc.c Move the set_enabled function to avoid the forward declaration. While at it prefix it with omap_crtc_ like most other functions in the file, and fix the comment stating in which contexts the function is called. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_crtc.c | 107 ++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 54 deletions(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index e04782489224..1ef3e0146c68 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -120,7 +120,57 @@ 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; + + /* + * 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 int omap_crtc_enable(struct omap_overlay_manager *mgr) { @@ -129,7 +179,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; } @@ -138,7 +188,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, @@ -537,57 +587,6 @@ int omap_crtc_apply(struct drm_crtc *crtc, 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 = -- cgit From a350da8be4d91e733ec8cb225e5edefa8b085167 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 17 Jan 2015 22:31:42 +0200 Subject: drm: omapdrm: Pass integer source coordinates to omap_plane_mode_set() The function will convert the Q16 source coordinates to integers, avoid converting integers to Q16 first and perform the opposite conversion. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_crtc.c | 21 +++++++++------------ drivers/gpu/drm/omapdrm/omap_drv.h | 12 ++++++------ drivers/gpu/drm/omapdrm/omap_plane.c | 24 ++++++++++++------------ 3 files changed, 27 insertions(+), 30 deletions(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 1ef3e0146c68..105eab7cb830 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -307,10 +307,9 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc, crtc->primary->crtc = crtc; return omap_plane_mode_set(crtc->primary, 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 omap_crtc_prepare(struct drm_crtc *crtc) @@ -334,10 +333,9 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 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) @@ -369,10 +367,9 @@ static void page_flip_worker(struct work_struct *work) drm_modeset_lock(&crtc->mutex, NULL); omap_plane_mode_set(crtc->primary, 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); + 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); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 1805edc0107d..57e11c1f589f 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -163,12 +163,12 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, int id, enum drm_plane_type type); int omap_plane_set_enable(struct drm_plane *plane, bool enable); 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 (*fxn)(void *), void *arg); + struct drm_crtc *crtc, struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + unsigned int src_x, unsigned int src_y, + unsigned int src_w, unsigned int src_h, + void (*fxn)(void *), void *arg); void omap_plane_install_properties(struct drm_plane *plane, struct drm_mode_object *obj); int omap_plane_set_property(struct drm_plane *plane, diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 309a2246b6e0..29f4371e9e00 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -184,12 +184,12 @@ static int omap_plane_apply(struct drm_plane *plane) } 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 (*fxn)(void *), void *arg) + struct drm_crtc *crtc, struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + unsigned int src_x, unsigned int src_y, + unsigned int src_w, unsigned int src_h, + void (*fxn)(void *), void *arg) { struct omap_plane *omap_plane = to_omap_plane(plane); struct omap_drm_window *win = &omap_plane->win; @@ -199,11 +199,10 @@ int omap_plane_mode_set(struct drm_plane *plane, win->crtc_w = crtc_w; win->crtc_h = crtc_h; - /* src values are in Q16 fixed point, convert to integer: */ - win->src_x = src_x >> 16; - win->src_y = src_y >> 16; - win->src_w = src_w >> 16; - win->src_h = src_h >> 16; + win->src_x = src_x; + win->src_y = src_y; + win->src_w = src_w; + win->src_h = src_h; if (fxn) { /* omap_crtc should ensure that a new page flip @@ -243,9 +242,10 @@ static int omap_plane_update(struct drm_plane *plane, plane->fb = fb; plane->crtc = crtc; + /* src values are in Q16 fixed point, convert to integer: */ return omap_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h, + src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16, NULL, NULL); } -- cgit From 971fb3e55feeafe5182c283a39f1f39d0d705b99 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 18 Jan 2015 01:12:59 +0200 Subject: drm: omapdrm: Reorder CRTC functions The next commit will need functions to be reordered. Do it separately to help review. This only moves functions without any change to the code. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_crtc.c | 396 +++++++++++++++++++----------------- 1 file changed, 206 insertions(+), 190 deletions(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 105eab7cb830..5cd10cf57985 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -74,6 +74,10 @@ struct omap_crtc { struct work_struct page_flip_work; }; +/* ----------------------------------------------------------------------------- + * Helper Functions + */ + uint32_t pipe2vbl(struct drm_crtc *crtc) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); @@ -81,6 +85,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. @@ -232,8 +252,189 @@ static const struct dss_mgr_ops mgr_ops = { .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); + 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)) { + 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) @@ -455,194 +656,9 @@ 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)) { - 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)); - } -} +/* ----------------------------------------------------------------------------- + * Init and Cleanup + */ static const char *channel_names[] = { [OMAP_DSS_CHANNEL_LCD] = "lcd", -- cgit From 549a75498151370214f86eacc788a5832ac01e59 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 3 Sep 2014 19:25:50 +0000 Subject: drm/omap: page_flip: return -EBUSY if flip pending The DRM documentation says: "If a page flip is already pending, the page_flip operation must return -EBUSY." Currently omapdrm returns -EINVAL instead. Fix omapdrm by returning -EBUSY. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 5cd10cf57985..a4d6f5ec627e 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -606,7 +606,7 @@ 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; -- cgit From 3b143fc80c077be54f8f7859d00f2db79250c884 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 19 Nov 2014 12:50:13 +0200 Subject: drm/omap: use DRM_ERROR_RATELIMITED() for error irqs omapdrm uses normal DRM_ERROR() print when the HW reports an error. As we sometimes may get a flood of errors, let's rather use DRM_ERROR_RATELIMITED(). Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_crtc.c | 2 +- drivers/gpu/drm/omapdrm/omap_plane.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index a4d6f5ec627e..e91687fe41be 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -261,7 +261,7 @@ 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); + DRM_ERROR_RATELIMITED("%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); } diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index d52ff0455673..1c6b63f39474 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -357,7 +357,8 @@ 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); + DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name, + irqstatus); } static const char *plane_names[] = { -- cgit From a36af73f5e825c4c5ae5b11580c24fa7841bd5e2 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 26 Feb 2015 15:20:24 +0200 Subject: drm/omap: fix race with error_irq omapdrm tries to avoid error floods by unregistering the error irq when an error happens, and then registering the error irq again later. However, the code is racy, as it sometimes tries to unregister the error irq when it's already unregistered, leading to WARN(). Also, the code only registers the error irq again when something is done on that particular output, i.e. if only TV is used to flip the buffers, and LCD is showing a same buffer, an error on LCD will cause the LCD error irq to be unregistered and never registered again. To fix this, let's keep the error irqs always enabled and trust the DRM_ERROR_RATELIMITED to limit the flood. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_crtc.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index e91687fe41be..c5c21776131a 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -72,6 +72,8 @@ struct omap_crtc { * XXX maybe fold into apply_work?? */ struct work_struct page_flip_work; + + bool ignore_digit_sync_lost; }; /* ----------------------------------------------------------------------------- @@ -157,7 +159,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) * 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); + omap_crtc->ignore_digit_sync_lost = true; framedone_irq = dispc_mgr_get_framedone_irq(channel); vsync_irq = dispc_mgr_get_vsync_irq(channel); @@ -188,7 +190,9 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) omap_crtc->name, enable ? "enable" : "disable"); } - omap_irq_register(crtc->dev, &omap_crtc->error_irq); + omap_crtc->ignore_digit_sync_lost = false; + /* make sure the irq handler sees the value above */ + mb(); } @@ -260,10 +264,14 @@ 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; + + 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); - /* 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) @@ -272,9 +280,6 @@ static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus) 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; -- cgit From ef4222838846fdecb6f1eae5671d9c462fd34852 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 26 Feb 2015 15:20:25 +0200 Subject: drm/omap: only ignore DIGIT SYNC LOST for TV output We need to ignore DIGIT SYNC LOST error when enabling/disabling TV output. The code does that, but it ignores the DIGI SYNC LOST when enabling any output. Normally this does no harm, but it could make us miss DIGIT SYNC LOST on some rare occasions. Fix the code to only ignore DIGIT SYNC LOST when enabling/disabling TV. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_crtc.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index c5c21776131a..7b93880a4577 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -155,11 +155,13 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) 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_crtc->ignore_digit_sync_lost = true; + 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); @@ -190,9 +192,11 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) omap_crtc->name, enable ? "enable" : "disable"); } - omap_crtc->ignore_digit_sync_lost = false; - /* make sure the irq handler sees the value above */ - mb(); + 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(); + } } -- cgit From 223bfd6911a0129d819b4dadb0eec93da014a9d9 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 10 Feb 2015 14:15:52 +0200 Subject: drm/omap: keep ref to old_fb We store the fb being page-flipped to 'old_fb' field, but we don't increase the ref count of the fb when doing that. While I am not sure if it can cause problem in practice, it's still safer to keep a ref when storing a pointer to a fb. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_crtc.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 7b93880a4577..f456544bf300 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -554,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); @@ -561,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) @@ -620,6 +626,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, 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); -- cgit