提交 5f741b39 编写于 作者: T Tomi Valkeinen 提交者: Laurent Pinchart

drm: omapdrm: new vblank and event handling

Rework the crtc event/flip_wait system as follows:

- If we enable a crtc (full modeset), we set omap_crtc->pending and
  register vblank irq.

- If we need to set GO bit (page flip), we do the same but also set the
  GO bit.

- On vblank we unregister the irq, clear the 'pending' flag, send vblank
  event to userspace if crtc->state->event != NULL, and wake up
  'pending_wait' wq.

- In omap_atomic_complete() we wait for the 'pending' flag to get reset
  for all enabled crtcs  using 'pending_wait' wq.

The above ensures that we send the events to userspace in vblank, and
that after the wait in omap_atomic_complete() everything for the
affected crtcs has been completed.
Signed-off-by: NTomi Valkeinen <tomi.valkeinen@ti.com>
Signed-off-by: NLaurent Pinchart <laurent.pinchart@ideasonboard.com>
上级 6646dfd0
...@@ -17,8 +17,6 @@ ...@@ -17,8 +17,6 @@
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <linux/completion.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
...@@ -49,13 +47,10 @@ struct omap_crtc { ...@@ -49,13 +47,10 @@ struct omap_crtc {
struct omap_drm_irq vblank_irq; struct omap_drm_irq vblank_irq;
struct omap_drm_irq error_irq; struct omap_drm_irq error_irq;
/* pending event */
struct drm_pending_vblank_event *event;
wait_queue_head_t flip_wait;
struct completion completion;
bool ignore_digit_sync_lost; bool ignore_digit_sync_lost;
bool pending;
wait_queue_head_t pending_wait;
}; };
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
...@@ -81,6 +76,15 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc) ...@@ -81,6 +76,15 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
return omap_crtc->channel; return omap_crtc->channel;
} }
int omap_crtc_wait_pending(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
return wait_event_timeout(omap_crtc->pending_wait,
!omap_crtc->pending,
msecs_to_jiffies(50));
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* DSS Manager Functions * DSS Manager Functions
*/ */
...@@ -255,17 +259,17 @@ static const struct dss_mgr_ops mgr_ops = { ...@@ -255,17 +259,17 @@ static const struct dss_mgr_ops mgr_ops = {
static void omap_crtc_complete_page_flip(struct drm_crtc *crtc) static void omap_crtc_complete_page_flip(struct drm_crtc *crtc)
{ {
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_pending_vblank_event *event; struct drm_pending_vblank_event *event;
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags); event = crtc->state->event;
event = omap_crtc->event; if (!event)
omap_crtc->event = NULL; return;
spin_lock_irqsave(&dev->event_lock, flags);
if (event) {
list_del(&event->base.link); list_del(&event->base.link);
/* /*
...@@ -277,41 +281,9 @@ static void omap_crtc_complete_page_flip(struct drm_crtc *crtc) ...@@ -277,41 +281,9 @@ static void omap_crtc_complete_page_flip(struct drm_crtc *crtc)
else else
event->base.destroy(&event->base); event->base.destroy(&event->base);
wake_up(&omap_crtc->flip_wait);
drm_crtc_vblank_put(crtc);
}
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
} }
static bool omap_crtc_page_flip_pending(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_device *dev = crtc->dev;
unsigned long flags;
bool pending;
spin_lock_irqsave(&dev->event_lock, flags);
pending = omap_crtc->event != NULL;
spin_unlock_irqrestore(&dev->event_lock, flags);
return pending;
}
static void omap_crtc_wait_page_flip(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
if (wait_event_timeout(omap_crtc->flip_wait,
!omap_crtc_page_flip_pending(crtc),
msecs_to_jiffies(50)))
return;
dev_warn(crtc->dev->dev, "page flip timeout!\n");
omap_crtc_complete_page_flip(crtc);
}
static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
{ {
struct omap_crtc *omap_crtc = struct omap_crtc *omap_crtc =
...@@ -336,12 +308,19 @@ static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus) ...@@ -336,12 +308,19 @@ static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
return; return;
DBG("%s: apply done", omap_crtc->name); DBG("%s: apply done", omap_crtc->name);
__omap_irq_unregister(dev, &omap_crtc->vblank_irq); __omap_irq_unregister(dev, &omap_crtc->vblank_irq);
/* wakeup userspace */ rmb();
WARN_ON(!omap_crtc->pending);
omap_crtc->pending = false;
wmb();
/* wake up userspace */
omap_crtc_complete_page_flip(&omap_crtc->base); omap_crtc_complete_page_flip(&omap_crtc->base);
complete(&omap_crtc->completion); /* wake up omap_atomic_complete */
wake_up(&omap_crtc->pending_wait);
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
...@@ -375,6 +354,13 @@ static void omap_crtc_enable(struct drm_crtc *crtc) ...@@ -375,6 +354,13 @@ static void omap_crtc_enable(struct drm_crtc *crtc)
DBG("%s", omap_crtc->name); DBG("%s", omap_crtc->name);
rmb();
WARN_ON(omap_crtc->pending);
omap_crtc->pending = true;
wmb();
omap_irq_register(crtc->dev, &omap_crtc->vblank_irq);
drm_crtc_vblank_on(crtc); drm_crtc_vblank_on(crtc);
} }
...@@ -384,7 +370,6 @@ static void omap_crtc_disable(struct drm_crtc *crtc) ...@@ -384,7 +370,6 @@ static void omap_crtc_disable(struct drm_crtc *crtc)
DBG("%s", omap_crtc->name); DBG("%s", omap_crtc->name);
omap_crtc_wait_page_flip(crtc);
drm_crtc_vblank_off(crtc); drm_crtc_vblank_off(crtc);
} }
...@@ -405,19 +390,6 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc) ...@@ -405,19 +390,6 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
static void omap_crtc_atomic_begin(struct drm_crtc *crtc) static void omap_crtc_atomic_begin(struct drm_crtc *crtc)
{ {
struct drm_pending_vblank_event *event = crtc->state->event;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_device *dev = crtc->dev;
unsigned long flags;
if (event) {
WARN_ON(omap_crtc->event);
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
spin_lock_irqsave(&dev->event_lock, flags);
omap_crtc->event = event;
spin_unlock_irqrestore(&dev->event_lock, flags);
}
} }
static void omap_crtc_atomic_flush(struct drm_crtc *crtc) static void omap_crtc_atomic_flush(struct drm_crtc *crtc)
...@@ -427,14 +399,16 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc) ...@@ -427,14 +399,16 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc)
WARN_ON(omap_crtc->vblank_irq.registered); WARN_ON(omap_crtc->vblank_irq.registered);
if (dispc_mgr_is_enabled(omap_crtc->channel)) { if (dispc_mgr_is_enabled(omap_crtc->channel)) {
DBG("%s: GO", omap_crtc->name); DBG("%s: GO", omap_crtc->name);
rmb();
WARN_ON(omap_crtc->pending);
omap_crtc->pending = true;
wmb();
dispc_mgr_go(omap_crtc->channel); dispc_mgr_go(omap_crtc->channel);
omap_irq_register(crtc->dev, &omap_crtc->vblank_irq); omap_irq_register(crtc->dev, &omap_crtc->vblank_irq);
WARN_ON(!wait_for_completion_timeout(&omap_crtc->completion,
msecs_to_jiffies(100)));
reinit_completion(&omap_crtc->completion);
} }
crtc->invert_dimensions = !!(crtc->primary->state->rotation & crtc->invert_dimensions = !!(crtc->primary->state->rotation &
...@@ -534,8 +508,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, ...@@ -534,8 +508,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
crtc = &omap_crtc->base; crtc = &omap_crtc->base;
init_waitqueue_head(&omap_crtc->flip_wait); init_waitqueue_head(&omap_crtc->pending_wait);
init_completion(&omap_crtc->completion);
omap_crtc->channel = channel; omap_crtc->channel = channel;
omap_crtc->name = channel_names[channel]; omap_crtc->name = channel_names[channel];
......
...@@ -66,6 +66,26 @@ struct omap_atomic_state_commit { ...@@ -66,6 +66,26 @@ struct omap_atomic_state_commit {
u32 crtcs; u32 crtcs;
}; };
static void omap_atomic_wait_for_completion(struct drm_device *dev,
struct drm_atomic_state *old_state)
{
struct drm_crtc_state *old_crtc_state;
struct drm_crtc *crtc;
unsigned int i;
int ret;
for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
if (!crtc->state->enable)
continue;
ret = omap_crtc_wait_pending(crtc);
if (!ret)
dev_warn(dev->dev,
"atomic complete timeout (pipe %u)!\n", i);
}
}
static void omap_atomic_complete(struct omap_atomic_state_commit *commit) static void omap_atomic_complete(struct omap_atomic_state_commit *commit)
{ {
struct drm_device *dev = commit->dev; struct drm_device *dev = commit->dev;
...@@ -79,7 +99,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit) ...@@ -79,7 +99,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit)
drm_atomic_helper_commit_planes(dev, old_state); drm_atomic_helper_commit_planes(dev, old_state);
drm_atomic_helper_commit_modeset_enables(dev, old_state); drm_atomic_helper_commit_modeset_enables(dev, old_state);
drm_atomic_helper_wait_for_vblanks(dev, old_state); omap_atomic_wait_for_completion(dev, old_state);
drm_atomic_helper_cleanup_planes(dev, old_state); drm_atomic_helper_cleanup_planes(dev, old_state);
......
...@@ -147,6 +147,7 @@ void omap_crtc_pre_init(void); ...@@ -147,6 +147,7 @@ void omap_crtc_pre_init(void);
void omap_crtc_pre_uninit(void); void omap_crtc_pre_uninit(void);
struct drm_crtc *omap_crtc_init(struct drm_device *dev, struct drm_crtc *omap_crtc_init(struct drm_device *dev,
struct drm_plane *plane, enum omap_channel channel, int id); struct drm_plane *plane, enum omap_channel channel, int id);
int omap_crtc_wait_pending(struct drm_crtc *crtc);
struct drm_plane *omap_plane_init(struct drm_device *dev, struct drm_plane *omap_plane_init(struct drm_device *dev,
int id, enum drm_plane_type type); int id, enum drm_plane_type type);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册