Skip to content

Commit

Permalink
drm: omapdrm: new vblank and event handling
Browse files Browse the repository at this point in the history
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: Tomi Valkeinen <tomi.valkeinen@ti.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  • Loading branch information
Tomi Valkeinen authored and Laurent Pinchart committed Jun 12, 2015
1 parent 6646dfd commit 5f741b3
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 76 deletions.
123 changes: 48 additions & 75 deletions drivers/gpu/drm/omapdrm/omap_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <linux/completion.h>

#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
Expand Down Expand Up @@ -49,13 +47,10 @@ struct omap_crtc {
struct omap_drm_irq vblank_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 pending;
wait_queue_head_t pending_wait;
};

/* -----------------------------------------------------------------------------
Expand All @@ -81,6 +76,15 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
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
*/
Expand Down Expand Up @@ -255,61 +259,29 @@ static const struct dss_mgr_ops mgr_ops = {

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_device *dev = crtc->dev;
unsigned long flags;

spin_lock_irqsave(&dev->event_lock, flags);

event = omap_crtc->event;
omap_crtc->event = NULL;
event = crtc->state->event;

if (event) {
list_del(&event->base.link);

/*
* Queue the event for delivery if it's still linked to a file
* handle, otherwise just destroy it.
*/
if (event->base.file_priv)
drm_crtc_send_vblank_event(crtc, event);
else
event->base.destroy(&event->base);

wake_up(&omap_crtc->flip_wait);
drm_crtc_vblank_put(crtc);
}

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;
if (!event)
return;

spin_lock_irqsave(&dev->event_lock, flags);
pending = omap_crtc->event != NULL;
spin_unlock_irqrestore(&dev->event_lock, flags);

return pending;
}
list_del(&event->base.link);

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");
/*
* Queue the event for delivery if it's still linked to a file
* handle, otherwise just destroy it.
*/
if (event->base.file_priv)
drm_crtc_send_vblank_event(crtc, event);
else
event->base.destroy(&event->base);

omap_crtc_complete_page_flip(crtc);
spin_unlock_irqrestore(&dev->event_lock, flags);
}

static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
Expand All @@ -336,12 +308,19 @@ static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
return;

DBG("%s: apply done", omap_crtc->name);

__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);

complete(&omap_crtc->completion);
/* wake up omap_atomic_complete */
wake_up(&omap_crtc->pending_wait);
}

/* -----------------------------------------------------------------------------
Expand Down Expand Up @@ -375,6 +354,13 @@ static void omap_crtc_enable(struct drm_crtc *crtc)

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);
}

Expand All @@ -384,7 +370,6 @@ static void omap_crtc_disable(struct drm_crtc *crtc)

DBG("%s", omap_crtc->name);

omap_crtc_wait_page_flip(crtc);
drm_crtc_vblank_off(crtc);
}

Expand All @@ -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)
{
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)
Expand All @@ -427,14 +399,16 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc)
WARN_ON(omap_crtc->vblank_irq.registered);

if (dispc_mgr_is_enabled(omap_crtc->channel)) {

DBG("%s: GO", omap_crtc->name);

rmb();
WARN_ON(omap_crtc->pending);
omap_crtc->pending = true;
wmb();

dispc_mgr_go(omap_crtc->channel);
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 &
Expand Down Expand Up @@ -534,8 +508,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,

crtc = &omap_crtc->base;

init_waitqueue_head(&omap_crtc->flip_wait);
init_completion(&omap_crtc->completion);
init_waitqueue_head(&omap_crtc->pending_wait);

omap_crtc->channel = channel;
omap_crtc->name = channel_names[channel];
Expand Down
22 changes: 21 additions & 1 deletion drivers/gpu/drm/omapdrm/omap_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,26 @@ struct omap_atomic_state_commit {
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)
{
struct drm_device *dev = commit->dev;
Expand All @@ -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_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);

Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/omapdrm/omap_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,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);
int omap_crtc_wait_pending(struct drm_crtc *crtc);

struct drm_plane *omap_plane_init(struct drm_device *dev,
int id, enum drm_plane_type type);
Expand Down

0 comments on commit 5f741b3

Please sign in to comment.