drm: add vblank hooks to struct drm_crtc_funcs

The vblank is mostly CRTC specific and implemented as part of CRTC
driver.  Let's keep the vblank hooks struct drm_driver for legacy
drivers, and add corresponding hooks in struct drm_crtc_funcs.  These
hooks take struct drm_crtc pointer as argument, and will be called by
core vblank handling code for DRIVER_MODESET drivers.

The new hooks get plugged into core by adding wrapper functions for
vblank handling code.  The .get_vblank_counter hook is effectively
optional, as we provide drm_vblank_no_hw_counter() as the default
fallback in the wrapper function.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1486458995-31018-2-git-send-email-shawnguo@kernel.org
This commit is contained in:
Shawn Guo 2017-02-07 17:16:13 +08:00 committed by Daniel Vetter
parent da7bdda2af
commit 84e354839b
3 changed files with 100 additions and 6 deletions

View File

@ -89,6 +89,21 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
write_sequnlock(&vblank->seqlock);
}
static u32 __get_vblank_counter(struct drm_device *dev, unsigned int pipe)
{
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
if (crtc->funcs->get_vblank_counter)
return crtc->funcs->get_vblank_counter(crtc);
}
if (dev->driver->get_vblank_counter)
return dev->driver->get_vblank_counter(dev, pipe);
return drm_vblank_no_hw_counter(dev, pipe);
}
/*
* Reset the stored timestamp for the current vblank count to correspond
* to the last vblank occurred.
@ -112,9 +127,9 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe
* when drm_vblank_enable() applies the diff
*/
do {
cur_vblank = dev->driver->get_vblank_counter(dev, pipe);
cur_vblank = __get_vblank_counter(dev, pipe);
rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, 0);
} while (cur_vblank != dev->driver->get_vblank_counter(dev, pipe) && --count > 0);
} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
/*
* Only reinitialize corresponding vblank timestamp if high-precision query
@ -168,9 +183,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
* corresponding vblank timestamp.
*/
do {
cur_vblank = dev->driver->get_vblank_counter(dev, pipe);
cur_vblank = __get_vblank_counter(dev, pipe);
rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, flags);
} while (cur_vblank != dev->driver->get_vblank_counter(dev, pipe) && --count > 0);
} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
if (dev->max_vblank_count != 0) {
/* trust the hw counter when it's around */
@ -275,6 +290,20 @@ u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
}
EXPORT_SYMBOL(drm_accurate_vblank_count);
static void __disable_vblank(struct drm_device *dev, unsigned int pipe)
{
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
if (crtc->funcs->disable_vblank) {
crtc->funcs->disable_vblank(crtc);
return;
}
}
dev->driver->disable_vblank(dev, pipe);
}
/*
* Disable vblank irq's on crtc, make sure that last vblank count
* of hardware and corresponding consistent software vblank counter
@ -298,7 +327,7 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe)
* hardware potentially runtime suspended.
*/
if (vblank->enabled) {
dev->driver->disable_vblank(dev, pipe);
__disable_vblank(dev, pipe);
vblank->enabled = false;
}
@ -1027,6 +1056,18 @@ void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
}
EXPORT_SYMBOL(drm_crtc_send_vblank_event);
static int __enable_vblank(struct drm_device *dev, unsigned int pipe)
{
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
if (crtc->funcs->enable_vblank)
return crtc->funcs->enable_vblank(crtc);
}
return dev->driver->enable_vblank(dev, pipe);
}
/**
* drm_vblank_enable - enable the vblank interrupt on a CRTC
* @dev: DRM device
@ -1052,7 +1093,7 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe)
* timestamps. Filtercode in drm_handle_vblank() will
* prevent double-accounting of same vblank interval.
*/
ret = dev->driver->enable_vblank(dev, pipe);
ret = __enable_vblank(dev, pipe);
DRM_DEBUG("enabling vblank on crtc %u, ret: %d\n", pipe, ret);
if (ret)
atomic_dec(&vblank->refcount);

View File

@ -608,6 +608,50 @@ struct drm_crtc_funcs {
*/
void (*atomic_print_state)(struct drm_printer *p,
const struct drm_crtc_state *state);
/**
* @get_vblank_counter:
*
* Driver callback for fetching a raw hardware vblank counter for the
* CRTC. It's meant to be used by new drivers as the replacement of
* &drm_driver.get_vblank_counter hook.
*
* This callback is optional. If a device doesn't have a hardware
* counter, the driver can simply leave the hook as NULL. The DRM core
* will account for missed vblank events while interrupts where disabled
* based on system timestamps.
*
* Wraparound handling and loss of events due to modesetting is dealt
* with in the DRM core code, as long as drivers call
* drm_crtc_vblank_off() and drm_crtc_vblank_on() when disabling or
* enabling a CRTC.
*
* Returns:
*
* Raw vblank counter value.
*/
u32 (*get_vblank_counter)(struct drm_crtc *crtc);
/**
* @enable_vblank:
*
* Enable vblank interrupts for the CRTC. It's meant to be used by
* new drivers as the replacement of &drm_driver.enable_vblank hook.
*
* Returns:
*
* Zero on success, appropriate errno if the vblank interrupt cannot
* be enabled.
*/
int (*enable_vblank)(struct drm_crtc *crtc);
/**
* @disable_vblank:
*
* Disable vblank interrupts for the CRTC. It's meant to be used by
* new drivers as the replacement of &drm_driver.disable_vblank hook.
*/
void (*disable_vblank)(struct drm_crtc *crtc);
};
/**

View File

@ -130,6 +130,9 @@ struct drm_driver {
* drm_crtc_vblank_off() and drm_crtc_vblank_on() when disabling or
* enabling a CRTC.
*
* This is deprecated and should not be used by new drivers.
* Use &drm_crtc_funcs.get_vblank_counter instead.
*
* Returns:
*
* Raw vblank counter value.
@ -142,6 +145,9 @@ struct drm_driver {
* Enable vblank interrupts for the CRTC specified with the pipe
* argument.
*
* This is deprecated and should not be used by new drivers.
* Use &drm_crtc_funcs.enable_vblank instead.
*
* Returns:
*
* Zero on success, appropriate errno if the given @crtc's vblank
@ -154,6 +160,9 @@ struct drm_driver {
*
* Disable vblank interrupts for the CRTC specified with the pipe
* argument.
*
* This is deprecated and should not be used by new drivers.
* Use &drm_crtc_funcs.disable_vblank instead.
*/
void (*disable_vblank) (struct drm_device *dev, unsigned int pipe);