Commit 378db830 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'for-next' of ssh://people.freedesktop.org/~seanpaul/dogwood into drm-next

I've included some improvements to PSR from myself, as well as a great
series from Tomasz to clean up and tighten up vblank/flip handling.

The last patch is one from Tomeu that has been floating around for a
while, and since rockchip is one of the beneficiaries, I figured this
would be a good place to pick it up.

* 'for-next' of ssh://people.freedesktop.org/~seanpaul/dogwood:
  drm/rockchip: Balance irq refcount on failure
  drm/rockchip: Kill vop_plane_state
  drm/rockchip: Always signal event in next vblank after cfg_done
  drm/rockchip: Do not enable vblank without event
  drm/rockchip: Replace custom wait_for_vblanks with helper
  drm/rockchip: Unreference framebuffers from flip work
  drm/rockchip: Avoid race with vblank count increment
  drm/rockchip: Get rid of some unnecessary code
  drm/rockchip: Clear interrupt status bits before enabling
  drm/rockchip: Fix up bug in psr state machine
  drm/bridge: analogix_dp: Remove duplicated code
  drm/rockchip: Reduce psr flush time to 100ms
  drm/rockchip: Don't key off vblank for psr
parents 662d5c95 8c763c9b
...@@ -39,7 +39,6 @@ struct drm_connector; ...@@ -39,7 +39,6 @@ struct drm_connector;
struct rockchip_crtc_funcs { struct rockchip_crtc_funcs {
int (*enable_vblank)(struct drm_crtc *crtc); int (*enable_vblank)(struct drm_crtc *crtc);
void (*disable_vblank)(struct drm_crtc *crtc); void (*disable_vblank)(struct drm_crtc *crtc);
void (*wait_for_update)(struct drm_crtc *crtc);
}; };
struct rockchip_crtc_state { struct rockchip_crtc_state {
......
...@@ -70,7 +70,7 @@ static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb, ...@@ -70,7 +70,7 @@ static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb,
struct drm_clip_rect *clips, struct drm_clip_rect *clips,
unsigned int num_clips) unsigned int num_clips)
{ {
rockchip_drm_psr_flush(fb->dev); rockchip_drm_psr_flush_all(fb->dev);
return 0; return 0;
} }
...@@ -174,68 +174,6 @@ static void rockchip_drm_output_poll_changed(struct drm_device *dev) ...@@ -174,68 +174,6 @@ static void rockchip_drm_output_poll_changed(struct drm_device *dev)
drm_fb_helper_hotplug_event(fb_helper); drm_fb_helper_hotplug_event(fb_helper);
} }
static void rockchip_crtc_wait_for_update(struct drm_crtc *crtc)
{
struct rockchip_drm_private *priv = crtc->dev->dev_private;
int pipe = drm_crtc_index(crtc);
const struct rockchip_crtc_funcs *crtc_funcs = priv->crtc_funcs[pipe];
if (crtc_funcs && crtc_funcs->wait_for_update)
crtc_funcs->wait_for_update(crtc);
}
/*
* We can't use drm_atomic_helper_wait_for_vblanks() because rk3288 and rk3066
* have hardware counters for neither vblanks nor scanlines, which results in
* a race where:
* | <-- HW vsync irq and reg take effect
* plane_commit --> |
* get_vblank and wait --> |
* | <-- handle_vblank, vblank->count + 1
* cleanup_fb --> |
* iommu crash --> |
* | <-- HW vsync irq and reg take effect
*
* This function is equivalent but uses rockchip_crtc_wait_for_update() instead
* of waiting for vblank_count to change.
*/
static void
rockchip_atomic_wait_for_complete(struct drm_device *dev, struct drm_atomic_state *old_state)
{
struct drm_crtc_state *old_crtc_state;
struct drm_crtc *crtc;
int i, ret;
for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
/* No one cares about the old state, so abuse it for tracking
* and store whether we hold a vblank reference (and should do a
* vblank wait) in the ->enable boolean.
*/
old_crtc_state->enable = false;
if (!crtc->state->active)
continue;
if (!drm_atomic_helper_framebuffer_changed(dev,
old_state, crtc))
continue;
ret = drm_crtc_vblank_get(crtc);
if (ret != 0)
continue;
old_crtc_state->enable = true;
}
for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
if (!old_crtc_state->enable)
continue;
rockchip_crtc_wait_for_update(crtc);
drm_crtc_vblank_put(crtc);
}
}
static void static void
rockchip_atomic_commit_tail(struct drm_atomic_state *state) rockchip_atomic_commit_tail(struct drm_atomic_state *state)
{ {
...@@ -250,7 +188,7 @@ rockchip_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -250,7 +188,7 @@ rockchip_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_helper_commit_hw_done(state); drm_atomic_helper_commit_hw_done(state);
rockchip_atomic_wait_for_complete(dev, state); drm_atomic_helper_wait_for_vblanks(dev, state);
drm_atomic_helper_cleanup_planes(dev, state); drm_atomic_helper_cleanup_planes(dev, state);
} }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include "rockchip_drm_drv.h" #include "rockchip_drm_drv.h"
#include "rockchip_drm_psr.h" #include "rockchip_drm_psr.h"
#define PSR_FLUSH_TIMEOUT msecs_to_jiffies(3000) /* 3 seconds */ #define PSR_FLUSH_TIMEOUT msecs_to_jiffies(100)
enum psr_state { enum psr_state {
PSR_FLUSH, PSR_FLUSH,
...@@ -31,6 +31,7 @@ struct psr_drv { ...@@ -31,6 +31,7 @@ struct psr_drv {
struct drm_encoder *encoder; struct drm_encoder *encoder;
spinlock_t lock; spinlock_t lock;
bool active;
enum psr_state state; enum psr_state state;
struct timer_list flush_timer; struct timer_list flush_timer;
...@@ -67,19 +68,17 @@ static void psr_set_state_locked(struct psr_drv *psr, enum psr_state state) ...@@ -67,19 +68,17 @@ static void psr_set_state_locked(struct psr_drv *psr, enum psr_state state)
* v | | * v | |
* PSR_DISABLE < - - - - - - - - - * PSR_DISABLE < - - - - - - - - -
*/ */
if (state == psr->state) if (state == psr->state || !psr->active)
return; return;
/* Requesting a flush when disabled is a noop */ /* Already disabled in flush, change the state, but not the hardware */
if (state == PSR_FLUSH && psr->state == PSR_DISABLE) if (state == PSR_DISABLE && psr->state == PSR_FLUSH) {
psr->state = state;
return; return;
}
psr->state = state; psr->state = state;
/* Already disabled in flush, change the state, but not the hardware */
if (state == PSR_DISABLE && psr->state == PSR_FLUSH)
return;
/* Actually commit the state change to hardware */ /* Actually commit the state change to hardware */
switch (psr->state) { switch (psr->state) {
case PSR_ENABLE: case PSR_ENABLE:
...@@ -115,45 +114,79 @@ static void psr_flush_handler(unsigned long data) ...@@ -115,45 +114,79 @@ static void psr_flush_handler(unsigned long data)
} }
/** /**
* rockchip_drm_psr_enable - enable the encoder PSR which bind to given CRTC * rockchip_drm_psr_activate - activate PSR on the given pipe
* @crtc: CRTC to obtain the PSR encoder * @crtc: CRTC to obtain the PSR encoder
* *
* Returns: * Returns:
* Zero on success, negative errno on failure. * Zero on success, negative errno on failure.
*/ */
int rockchip_drm_psr_enable(struct drm_crtc *crtc) int rockchip_drm_psr_activate(struct drm_crtc *crtc)
{ {
struct psr_drv *psr = find_psr_by_crtc(crtc); struct psr_drv *psr = find_psr_by_crtc(crtc);
unsigned long flags;
if (IS_ERR(psr)) if (IS_ERR(psr))
return PTR_ERR(psr); return PTR_ERR(psr);
psr_set_state(psr, PSR_ENABLE); spin_lock_irqsave(&psr->lock, flags);
psr->active = true;
spin_unlock_irqrestore(&psr->lock, flags);
return 0; return 0;
} }
EXPORT_SYMBOL(rockchip_drm_psr_enable); EXPORT_SYMBOL(rockchip_drm_psr_activate);
/** /**
* rockchip_drm_psr_disable - disable the encoder PSR which bind to given CRTC * rockchip_drm_psr_deactivate - deactivate PSR on the given pipe
* @crtc: CRTC to obtain the PSR encoder * @crtc: CRTC to obtain the PSR encoder
* *
* Returns: * Returns:
* Zero on success, negative errno on failure. * Zero on success, negative errno on failure.
*/ */
int rockchip_drm_psr_disable(struct drm_crtc *crtc) int rockchip_drm_psr_deactivate(struct drm_crtc *crtc)
{ {
struct psr_drv *psr = find_psr_by_crtc(crtc); struct psr_drv *psr = find_psr_by_crtc(crtc);
unsigned long flags;
if (IS_ERR(psr))
return PTR_ERR(psr);
spin_lock_irqsave(&psr->lock, flags);
psr->active = false;
spin_unlock_irqrestore(&psr->lock, flags);
del_timer_sync(&psr->flush_timer);
return 0;
}
EXPORT_SYMBOL(rockchip_drm_psr_deactivate);
static void rockchip_drm_do_flush(struct psr_drv *psr)
{
mod_timer(&psr->flush_timer,
round_jiffies_up(jiffies + PSR_FLUSH_TIMEOUT));
psr_set_state(psr, PSR_FLUSH);
}
/**
* rockchip_drm_psr_flush - flush a single pipe
* @crtc: CRTC of the pipe to flush
*
* Returns:
* 0 on success, -errno on fail
*/
int rockchip_drm_psr_flush(struct drm_crtc *crtc)
{
struct psr_drv *psr = find_psr_by_crtc(crtc);
if (IS_ERR(psr)) if (IS_ERR(psr))
return PTR_ERR(psr); return PTR_ERR(psr);
psr_set_state(psr, PSR_DISABLE); rockchip_drm_do_flush(psr);
return 0; return 0;
} }
EXPORT_SYMBOL(rockchip_drm_psr_disable); EXPORT_SYMBOL(rockchip_drm_psr_flush);
/** /**
* rockchip_drm_psr_flush - force to flush all registered PSR encoders * rockchip_drm_psr_flush_all - force to flush all registered PSR encoders
* @dev: drm device * @dev: drm device
* *
* Disable the PSR function for all registered encoders, and then enable the * Disable the PSR function for all registered encoders, and then enable the
...@@ -164,22 +197,18 @@ EXPORT_SYMBOL(rockchip_drm_psr_disable); ...@@ -164,22 +197,18 @@ EXPORT_SYMBOL(rockchip_drm_psr_disable);
* Returns: * Returns:
* Zero on success, negative errno on failure. * Zero on success, negative errno on failure.
*/ */
void rockchip_drm_psr_flush(struct drm_device *dev) void rockchip_drm_psr_flush_all(struct drm_device *dev)
{ {
struct rockchip_drm_private *drm_drv = dev->dev_private; struct rockchip_drm_private *drm_drv = dev->dev_private;
struct psr_drv *psr; struct psr_drv *psr;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&drm_drv->psr_list_lock, flags); spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
list_for_each_entry(psr, &drm_drv->psr_list, list) { list_for_each_entry(psr, &drm_drv->psr_list, list)
mod_timer(&psr->flush_timer, rockchip_drm_do_flush(psr);
round_jiffies_up(jiffies + PSR_FLUSH_TIMEOUT));
psr_set_state(psr, PSR_FLUSH);
}
spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags); spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
} }
EXPORT_SYMBOL(rockchip_drm_psr_flush); EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
/** /**
* rockchip_drm_psr_register - register encoder to psr driver * rockchip_drm_psr_register - register encoder to psr driver
...@@ -206,6 +235,7 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder, ...@@ -206,6 +235,7 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder,
setup_timer(&psr->flush_timer, psr_flush_handler, (unsigned long)psr); setup_timer(&psr->flush_timer, psr_flush_handler, (unsigned long)psr);
spin_lock_init(&psr->lock); spin_lock_init(&psr->lock);
psr->active = true;
psr->state = PSR_DISABLE; psr->state = PSR_DISABLE;
psr->encoder = encoder; psr->encoder = encoder;
psr->set = psr_set; psr->set = psr_set;
......
...@@ -15,9 +15,11 @@ ...@@ -15,9 +15,11 @@
#ifndef __ROCKCHIP_DRM_PSR___ #ifndef __ROCKCHIP_DRM_PSR___
#define __ROCKCHIP_DRM_PSR___ #define __ROCKCHIP_DRM_PSR___
void rockchip_drm_psr_flush(struct drm_device *dev); void rockchip_drm_psr_flush_all(struct drm_device *dev);
int rockchip_drm_psr_enable(struct drm_crtc *crtc); int rockchip_drm_psr_flush(struct drm_crtc *crtc);
int rockchip_drm_psr_disable(struct drm_crtc *crtc);
int rockchip_drm_psr_activate(struct drm_crtc *crtc);
int rockchip_drm_psr_deactivate(struct drm_crtc *crtc);
int rockchip_drm_psr_register(struct drm_encoder *encoder, int rockchip_drm_psr_register(struct drm_encoder *encoder,
void (*psr_set)(struct drm_encoder *, bool enable)); void (*psr_set)(struct drm_encoder *, bool enable));
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment