Commit 84e35483 authored by Shawn Guo's avatar Shawn Guo Committed by Daniel Vetter

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: default avatarShawn Guo <shawn.guo@linaro.org>
Reviewed-by: default avatarAndrzej Hajda <a.hajda@samsung.com>
Acked-by: default avatarThierry Reding <treding@nvidia.com>
Reviewed-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1486458995-31018-2-git-send-email-shawnguo@kernel.org
parent da7bdda2
...@@ -89,6 +89,21 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe, ...@@ -89,6 +89,21 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
write_sequnlock(&vblank->seqlock); 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 * Reset the stored timestamp for the current vblank count to correspond
* to the last vblank occurred. * to the last vblank occurred.
...@@ -112,9 +127,9 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe ...@@ -112,9 +127,9 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe
* when drm_vblank_enable() applies the diff * when drm_vblank_enable() applies the diff
*/ */
do { 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); 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 * 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, ...@@ -168,9 +183,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
* corresponding vblank timestamp. * corresponding vblank timestamp.
*/ */
do { 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); 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) { if (dev->max_vblank_count != 0) {
/* trust the hw counter when it's around */ /* trust the hw counter when it's around */
...@@ -275,6 +290,20 @@ u32 drm_accurate_vblank_count(struct drm_crtc *crtc) ...@@ -275,6 +290,20 @@ u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
} }
EXPORT_SYMBOL(drm_accurate_vblank_count); 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 * Disable vblank irq's on crtc, make sure that last vblank count
* of hardware and corresponding consistent software vblank counter * 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) ...@@ -298,7 +327,7 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe)
* hardware potentially runtime suspended. * hardware potentially runtime suspended.
*/ */
if (vblank->enabled) { if (vblank->enabled) {
dev->driver->disable_vblank(dev, pipe); __disable_vblank(dev, pipe);
vblank->enabled = false; vblank->enabled = false;
} }
...@@ -1027,6 +1056,18 @@ void drm_crtc_send_vblank_event(struct drm_crtc *crtc, ...@@ -1027,6 +1056,18 @@ void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
} }
EXPORT_SYMBOL(drm_crtc_send_vblank_event); 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 * drm_vblank_enable - enable the vblank interrupt on a CRTC
* @dev: DRM device * @dev: DRM device
...@@ -1052,7 +1093,7 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) ...@@ -1052,7 +1093,7 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe)
* timestamps. Filtercode in drm_handle_vblank() will * timestamps. Filtercode in drm_handle_vblank() will
* prevent double-accounting of same vblank interval. * 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); DRM_DEBUG("enabling vblank on crtc %u, ret: %d\n", pipe, ret);
if (ret) if (ret)
atomic_dec(&vblank->refcount); atomic_dec(&vblank->refcount);
......
...@@ -608,6 +608,50 @@ struct drm_crtc_funcs { ...@@ -608,6 +608,50 @@ struct drm_crtc_funcs {
*/ */
void (*atomic_print_state)(struct drm_printer *p, void (*atomic_print_state)(struct drm_printer *p,
const struct drm_crtc_state *state); 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 { ...@@ -130,6 +130,9 @@ struct drm_driver {
* drm_crtc_vblank_off() and drm_crtc_vblank_on() when disabling or * drm_crtc_vblank_off() and drm_crtc_vblank_on() when disabling or
* enabling a CRTC. * enabling a CRTC.
* *
* This is deprecated and should not be used by new drivers.
* Use &drm_crtc_funcs.get_vblank_counter instead.
*
* Returns: * Returns:
* *
* Raw vblank counter value. * Raw vblank counter value.
...@@ -142,6 +145,9 @@ struct drm_driver { ...@@ -142,6 +145,9 @@ struct drm_driver {
* Enable vblank interrupts for the CRTC specified with the pipe * Enable vblank interrupts for the CRTC specified with the pipe
* argument. * argument.
* *
* This is deprecated and should not be used by new drivers.
* Use &drm_crtc_funcs.enable_vblank instead.
*
* Returns: * Returns:
* *
* Zero on success, appropriate errno if the given @crtc's vblank * Zero on success, appropriate errno if the given @crtc's vblank
...@@ -154,6 +160,9 @@ struct drm_driver { ...@@ -154,6 +160,9 @@ struct drm_driver {
* *
* Disable vblank interrupts for the CRTC specified with the pipe * Disable vblank interrupts for the CRTC specified with the pipe
* argument. * 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); void (*disable_vblank) (struct drm_device *dev, unsigned int pipe);
......
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