mirror of https://gitee.com/openkylin/linux.git
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:
parent
da7bdda2af
commit
84e354839b
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue