aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorSebastian Reichel <sebastian.reichel@collabora.com>2019-05-23 16:07:56 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2019-06-10 10:04:15 -0400
commit1bb418bffdd6f95a41e8e59be63933bc84fde13c (patch)
tree64b10a440e9fe72c3ed85274ba217a0fcda0a8af /drivers/gpu
parent47103a80f55a6b7f5a51f1e9a4886e532cdfa4e2 (diff)
drm/omap: add support for manually updated displays
This adds the required infrastructure for manually updated displays, such as DSI command mode panels. While those panels often support partial updates we currently always do a full refresh. The display will be refreshed when something calls the dirty callback, such as libdrm's drmModeDirtyFB(). This is currently being done at least by the kernel console and Xorg (with modesetting driver) in their default configuration. Weston does not implement this and the fbdev backend does not work (display will not update). Weston's DRM backend uses double buffering and the page flip will also trigger a display refresh. Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c114
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.h1
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fb.c19
3 files changed, 129 insertions, 5 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 5b6a18a62bbb..d61215494617 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -32,6 +32,7 @@ struct omap_crtc_state {
32 /* Shadow values for legacy userspace support. */ 32 /* Shadow values for legacy userspace support. */
33 unsigned int rotation; 33 unsigned int rotation;
34 unsigned int zpos; 34 unsigned int zpos;
35 bool manually_updated;
35}; 36};
36 37
37#define to_omap_crtc(x) container_of(x, struct omap_crtc, base) 38#define to_omap_crtc(x) container_of(x, struct omap_crtc, base)
@@ -51,6 +52,7 @@ struct omap_crtc {
51 bool pending; 52 bool pending;
52 wait_queue_head_t pending_wait; 53 wait_queue_head_t pending_wait;
53 struct drm_pending_vblank_event *event; 54 struct drm_pending_vblank_event *event;
55 struct delayed_work update_work;
54 56
55 void (*framedone_handler)(void *); 57 void (*framedone_handler)(void *);
56 void *framedone_handler_data; 58 void *framedone_handler_data;
@@ -105,21 +107,18 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc)
105/* 107/*
106 * Manager-ops, callbacks from output when they need to configure 108 * Manager-ops, callbacks from output when they need to configure
107 * the upstream part of the video pipe. 109 * the upstream part of the video pipe.
108 *
109 * Most of these we can ignore until we add support for command-mode
110 * panels.. for video-mode the crtc-helpers already do an adequate
111 * job of sequencing the setup of the video pipe in the proper order
112 */ 110 */
113 111
114/* we can probably ignore these until we support command-mode panels: */
115static void omap_crtc_dss_start_update(struct omap_drm_private *priv, 112static void omap_crtc_dss_start_update(struct omap_drm_private *priv,
116 enum omap_channel channel) 113 enum omap_channel channel)
117{ 114{
115 priv->dispc_ops->mgr_enable(priv->dispc, channel, true);
118} 116}
119 117
120/* Called only from the encoder enable/disable and suspend/resume handlers. */ 118/* Called only from the encoder enable/disable and suspend/resume handlers. */
121static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) 119static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
122{ 120{
121 struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state);
123 struct drm_device *dev = crtc->dev; 122 struct drm_device *dev = crtc->dev;
124 struct omap_drm_private *priv = dev->dev_private; 123 struct omap_drm_private *priv = dev->dev_private;
125 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 124 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@@ -131,6 +130,12 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
131 if (WARN_ON(omap_crtc->enabled == enable)) 130 if (WARN_ON(omap_crtc->enabled == enable))
132 return; 131 return;
133 132
133 if (omap_state->manually_updated) {
134 omap_irq_enable_framedone(crtc, enable);
135 omap_crtc->enabled = enable;
136 return;
137 }
138
134 if (omap_crtc->pipe->output->type == OMAP_DISPLAY_TYPE_HDMI) { 139 if (omap_crtc->pipe->output->type == OMAP_DISPLAY_TYPE_HDMI) {
135 priv->dispc_ops->mgr_enable(priv->dispc, channel, enable); 140 priv->dispc_ops->mgr_enable(priv->dispc, channel, enable);
136 omap_crtc->enabled = enable; 141 omap_crtc->enabled = enable;
@@ -350,6 +355,51 @@ void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus)
350 wake_up(&omap_crtc->pending_wait); 355 wake_up(&omap_crtc->pending_wait);
351} 356}
352 357
358void omap_crtc_flush(struct drm_crtc *crtc)
359{
360 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
361 struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state);
362
363 if (!omap_state->manually_updated)
364 return;
365
366 if (!delayed_work_pending(&omap_crtc->update_work))
367 schedule_delayed_work(&omap_crtc->update_work, 0);
368}
369
370static void omap_crtc_manual_display_update(struct work_struct *data)
371{
372 struct omap_crtc *omap_crtc =
373 container_of(data, struct omap_crtc, update_work.work);
374 struct drm_display_mode *mode = &omap_crtc->pipe->crtc->mode;
375 struct omap_dss_device *dssdev = omap_crtc->pipe->output->next;
376 struct drm_device *dev = omap_crtc->base.dev;
377 const struct omap_dss_driver *dssdrv;
378 int ret;
379
380 if (!dssdev) {
381 dev_err_once(dev->dev, "missing display dssdev!");
382 return;
383 }
384
385 dssdrv = dssdev->driver;
386 if (!dssdrv || !dssdrv->update) {
387 dev_err_once(dev->dev, "missing or incorrect dssdrv!");
388 return;
389 }
390
391 if (dssdrv->sync)
392 dssdrv->sync(dssdev);
393
394 ret = dssdrv->update(dssdev, 0, 0, mode->hdisplay, mode->vdisplay);
395 if (ret < 0) {
396 spin_lock_irq(&dev->event_lock);
397 omap_crtc->pending = false;
398 spin_unlock_irq(&dev->event_lock);
399 wake_up(&omap_crtc->pending_wait);
400 }
401}
402
353static void omap_crtc_write_crtc_properties(struct drm_crtc *crtc) 403static void omap_crtc_write_crtc_properties(struct drm_crtc *crtc)
354{ 404{
355 struct omap_drm_private *priv = crtc->dev->dev_private; 405 struct omap_drm_private *priv = crtc->dev->dev_private;
@@ -399,12 +449,17 @@ static void omap_crtc_atomic_enable(struct drm_crtc *crtc,
399{ 449{
400 struct omap_drm_private *priv = crtc->dev->dev_private; 450 struct omap_drm_private *priv = crtc->dev->dev_private;
401 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 451 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
452 struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state);
402 int ret; 453 int ret;
403 454
404 DBG("%s", omap_crtc->name); 455 DBG("%s", omap_crtc->name);
405 456
406 priv->dispc_ops->runtime_get(priv->dispc); 457 priv->dispc_ops->runtime_get(priv->dispc);
407 458
459 /* manual updated display will not trigger vsync irq */
460 if (omap_state->manually_updated)
461 return;
462
408 spin_lock_irq(&crtc->dev->event_lock); 463 spin_lock_irq(&crtc->dev->event_lock);
409 drm_crtc_vblank_on(crtc); 464 drm_crtc_vblank_on(crtc);
410 ret = drm_crtc_vblank_get(crtc); 465 ret = drm_crtc_vblank_get(crtc);
@@ -419,6 +474,7 @@ static void omap_crtc_atomic_disable(struct drm_crtc *crtc,
419{ 474{
420 struct omap_drm_private *priv = crtc->dev->dev_private; 475 struct omap_drm_private *priv = crtc->dev->dev_private;
421 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 476 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
477 struct drm_device *dev = crtc->dev;
422 478
423 DBG("%s", omap_crtc->name); 479 DBG("%s", omap_crtc->name);
424 480
@@ -429,6 +485,11 @@ static void omap_crtc_atomic_disable(struct drm_crtc *crtc,
429 } 485 }
430 spin_unlock_irq(&crtc->dev->event_lock); 486 spin_unlock_irq(&crtc->dev->event_lock);
431 487
488 cancel_delayed_work(&omap_crtc->update_work);
489
490 if (!omap_crtc_wait_pending(crtc))
491 dev_warn(dev->dev, "manual display update did not finish!");
492
432 drm_crtc_vblank_off(crtc); 493 drm_crtc_vblank_off(crtc);
433 494
434 priv->dispc_ops->runtime_put(priv->dispc); 495 priv->dispc_ops->runtime_put(priv->dispc);
@@ -499,6 +560,22 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
499 drm_display_mode_to_videomode(mode, &omap_crtc->vm); 560 drm_display_mode_to_videomode(mode, &omap_crtc->vm);
500} 561}
501 562
563static bool omap_crtc_is_manually_updated(struct drm_crtc *crtc)
564{
565 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
566 struct omap_dss_device *display = omap_crtc->pipe->output->next;
567
568 if (!display)
569 return false;
570
571 if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
572 DBG("detected manually updated display!");
573 return true;
574 }
575
576 return false;
577}
578
502static int omap_crtc_atomic_check(struct drm_crtc *crtc, 579static int omap_crtc_atomic_check(struct drm_crtc *crtc,
503 struct drm_crtc_state *state) 580 struct drm_crtc_state *state)
504{ 581{
@@ -520,6 +597,9 @@ static int omap_crtc_atomic_check(struct drm_crtc *crtc,
520 /* Mirror new values for zpos and rotation in omap_crtc_state */ 597 /* Mirror new values for zpos and rotation in omap_crtc_state */
521 omap_crtc_state->zpos = pri_state->zpos; 598 omap_crtc_state->zpos = pri_state->zpos;
522 omap_crtc_state->rotation = pri_state->rotation; 599 omap_crtc_state->rotation = pri_state->rotation;
600
601 /* Check if this CRTC is for a manually updated display */
602 omap_crtc_state->manually_updated = omap_crtc_is_manually_updated(crtc);
523 } 603 }
524 604
525 return 0; 605 return 0;
@@ -535,6 +615,7 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
535{ 615{
536 struct omap_drm_private *priv = crtc->dev->dev_private; 616 struct omap_drm_private *priv = crtc->dev->dev_private;
537 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 617 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
618 struct omap_crtc_state *omap_crtc_state = to_omap_crtc_state(crtc->state);
538 int ret; 619 int ret;
539 620
540 if (crtc->state->color_mgmt_changed) { 621 if (crtc->state->color_mgmt_changed) {
@@ -559,6 +640,15 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
559 640
560 DBG("%s: GO", omap_crtc->name); 641 DBG("%s: GO", omap_crtc->name);
561 642
643 if (omap_crtc_state->manually_updated) {
644 /* send new image for page flips and modeset changes */
645 spin_lock_irq(&crtc->dev->event_lock);
646 omap_crtc_flush(crtc);
647 omap_crtc_arm_event(crtc);
648 spin_unlock_irq(&crtc->dev->event_lock);
649 return;
650 }
651
562 ret = drm_crtc_vblank_get(crtc); 652 ret = drm_crtc_vblank_get(crtc);
563 WARN_ON(ret != 0); 653 WARN_ON(ret != 0);
564 654
@@ -644,6 +734,7 @@ omap_crtc_duplicate_state(struct drm_crtc *crtc)
644 734
645 state->zpos = current_state->zpos; 735 state->zpos = current_state->zpos;
646 state->rotation = current_state->rotation; 736 state->rotation = current_state->rotation;
737 state->manually_updated = current_state->manually_updated;
647 738
648 return &state->base; 739 return &state->base;
649} 740}
@@ -720,6 +811,19 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
720 omap_crtc->channel = channel; 811 omap_crtc->channel = channel;
721 omap_crtc->name = channel_names[channel]; 812 omap_crtc->name = channel_names[channel];
722 813
814 /*
815 * We want to refresh manually updated displays from dirty callback,
816 * which is called quite often (e.g. for each drawn line). This will
817 * be used to do the display update asynchronously to avoid blocking
818 * the rendering process and merges multiple dirty calls into one
819 * update if they arrive very fast. We also call this function for
820 * atomic display updates (e.g. for page flips), which means we do
821 * not need extra locking. Atomic updates should be synchronous, but
822 * need to wait for the framedone interrupt anyways.
823 */
824 INIT_DELAYED_WORK(&omap_crtc->update_work,
825 omap_crtc_manual_display_update);
826
723 ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, 827 ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
724 &omap_crtc_funcs, NULL); 828 &omap_crtc_funcs, NULL);
725 if (ret < 0) { 829 if (ret < 0) {
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.h b/drivers/gpu/drm/omapdrm/omap_crtc.h
index d33bbb7a4f90..2b518c74203e 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.h
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.h
@@ -42,5 +42,6 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc);
42void omap_crtc_error_irq(struct drm_crtc *crtc, u32 irqstatus); 42void omap_crtc_error_irq(struct drm_crtc *crtc, u32 irqstatus);
43void omap_crtc_vblank_irq(struct drm_crtc *crtc); 43void omap_crtc_vblank_irq(struct drm_crtc *crtc);
44void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus); 44void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus);
45void omap_crtc_flush(struct drm_crtc *crtc);
45 46
46#endif /* __OMAPDRM_CRTC_H__ */ 47#endif /* __OMAPDRM_CRTC_H__ */
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
index 6557b2d6e16e..06d5c5081e41 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.c
+++ b/drivers/gpu/drm/omapdrm/omap_fb.c
@@ -66,8 +66,27 @@ struct omap_framebuffer {
66 struct mutex lock; 66 struct mutex lock;
67}; 67};
68 68
69static int omap_framebuffer_dirty(struct drm_framebuffer *fb,
70 struct drm_file *file_priv,
71 unsigned flags, unsigned color,
72 struct drm_clip_rect *clips,
73 unsigned num_clips)
74{
75 struct drm_crtc *crtc;
76
77 drm_modeset_lock_all(fb->dev);
78
79 drm_for_each_crtc(crtc, fb->dev)
80 omap_crtc_flush(crtc);
81
82 drm_modeset_unlock_all(fb->dev);
83
84 return 0;
85}
86
69static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { 87static const struct drm_framebuffer_funcs omap_framebuffer_funcs = {
70 .create_handle = drm_gem_fb_create_handle, 88 .create_handle = drm_gem_fb_create_handle,
89 .dirty = omap_framebuffer_dirty,
71 .destroy = drm_gem_fb_destroy, 90 .destroy = drm_gem_fb_destroy,
72}; 91};
73 92