Skip to content

Commit

Permalink
drm: add vblank hooks to struct drm_crtc_funcs
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Shawn Guo authored and Daniel Vetter committed Feb 7, 2017
1 parent da7bdda commit 84e3548
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 6 deletions.
53 changes: 47 additions & 6 deletions drivers/gpu/drm/drm_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand All @@ -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;
}

Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
44 changes: 44 additions & 0 deletions include/drm/drm_crtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

/**
Expand Down
9 changes: 9 additions & 0 deletions include/drm/drm_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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);

Expand Down

0 comments on commit 84e3548

Please sign in to comment.