| // SPDX-License-Identifier: MIT |
| |
| #include <drm/drm_atomic.h> |
| #include <drm/drm_crtc.h> |
| #include <drm/drm_managed.h> |
| #include <drm/drm_modeset_helper_vtables.h> |
| #include <drm/drm_print.h> |
| #include <drm/drm_vblank.h> |
| #include <drm/drm_vblank_helper.h> |
| |
| /** |
| * DOC: overview |
| * |
| * The vblank helper library provides functions for supporting vertical |
| * blanking in DRM drivers. |
| * |
| * For vblank timers, several callback implementations are available. |
| * Drivers enable support for vblank timers by setting the vblank callbacks |
| * in struct &drm_crtc_funcs to the helpers provided by this library. The |
| * initializer macro DRM_CRTC_VBLANK_TIMER_FUNCS does this conveniently. |
| * The driver further has to send the VBLANK event from its atomic_flush |
| * callback and control vblank from the CRTC's atomic_enable and atomic_disable |
| * callbacks. The callbacks are located in struct &drm_crtc_helper_funcs. |
| * The vblank helper library provides implementations of these callbacks |
| * for drivers without further requirements. The initializer macro |
| * DRM_CRTC_HELPER_VBLANK_FUNCS sets them coveniently. |
| * |
| * Once the driver enables vblank support with drm_vblank_init(), each |
| * CRTC's vblank timer fires according to the programmed display mode. By |
| * default, the vblank timer invokes drm_crtc_handle_vblank(). Drivers with |
| * more specific requirements can set their own handler function in |
| * struct &drm_crtc_helper_funcs.handle_vblank_timeout. |
| */ |
| |
| /* |
| * VBLANK helpers |
| */ |
| |
| /** |
| * drm_crtc_vblank_atomic_flush - |
| * Implements struct &drm_crtc_helper_funcs.atomic_flush |
| * @crtc: The CRTC |
| * @state: The atomic state to apply |
| * |
| * The helper drm_crtc_vblank_atomic_flush() implements atomic_flush of |
| * struct drm_crtc_helper_funcs for CRTCs that only need to send out a |
| * VBLANK event. |
| * |
| * See also struct &drm_crtc_helper_funcs.atomic_flush. |
| */ |
| void drm_crtc_vblank_atomic_flush(struct drm_crtc *crtc, |
| struct drm_atomic_state *state) |
| { |
| struct drm_device *dev = crtc->dev; |
| struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); |
| struct drm_pending_vblank_event *event; |
| |
| spin_lock_irq(&dev->event_lock); |
| |
| event = crtc_state->event; |
| crtc_state->event = NULL; |
| |
| if (event) { |
| if (drm_crtc_vblank_get(crtc) == 0) |
| drm_crtc_arm_vblank_event(crtc, event); |
| else |
| drm_crtc_send_vblank_event(crtc, event); |
| } |
| |
| spin_unlock_irq(&dev->event_lock); |
| } |
| EXPORT_SYMBOL(drm_crtc_vblank_atomic_flush); |
| |
| /** |
| * drm_crtc_vblank_atomic_enable - Implements struct &drm_crtc_helper_funcs.atomic_enable |
| * @crtc: The CRTC |
| * @state: The atomic state |
| * |
| * The helper drm_crtc_vblank_atomic_enable() implements atomic_enable |
| * of struct drm_crtc_helper_funcs for CRTCs the only need to enable VBLANKs. |
| * |
| * See also struct &drm_crtc_helper_funcs.atomic_enable. |
| */ |
| void drm_crtc_vblank_atomic_enable(struct drm_crtc *crtc, |
| struct drm_atomic_state *state) |
| { |
| drm_crtc_vblank_on(crtc); |
| } |
| EXPORT_SYMBOL(drm_crtc_vblank_atomic_enable); |
| |
| /** |
| * drm_crtc_vblank_atomic_disable - Implements struct &drm_crtc_helper_funcs.atomic_disable |
| * @crtc: The CRTC |
| * @state: The atomic state |
| * |
| * The helper drm_crtc_vblank_atomic_disable() implements atomic_disable |
| * of struct drm_crtc_helper_funcs for CRTCs the only need to disable VBLANKs. |
| * |
| * See also struct &drm_crtc_funcs.atomic_disable. |
| */ |
| void drm_crtc_vblank_atomic_disable(struct drm_crtc *crtc, |
| struct drm_atomic_state *state) |
| { |
| drm_crtc_vblank_off(crtc); |
| } |
| EXPORT_SYMBOL(drm_crtc_vblank_atomic_disable); |
| |
| /* |
| * VBLANK timer |
| */ |
| |
| /** |
| * drm_crtc_vblank_helper_enable_vblank_timer - Implements struct &drm_crtc_funcs.enable_vblank |
| * @crtc: The CRTC |
| * |
| * The helper drm_crtc_vblank_helper_enable_vblank_timer() implements |
| * enable_vblank of struct drm_crtc_helper_funcs for CRTCs that require |
| * a VBLANK timer. It sets up the timer on the first invocation. The |
| * started timer expires after the current frame duration. See struct |
| * &drm_vblank_crtc.framedur_ns. |
| * |
| * See also struct &drm_crtc_helper_funcs.enable_vblank. |
| * |
| * Returns: |
| * 0 on success, or a negative errno code otherwise. |
| */ |
| int drm_crtc_vblank_helper_enable_vblank_timer(struct drm_crtc *crtc) |
| { |
| return drm_crtc_vblank_start_timer(crtc); |
| } |
| EXPORT_SYMBOL(drm_crtc_vblank_helper_enable_vblank_timer); |
| |
| /** |
| * drm_crtc_vblank_helper_disable_vblank_timer - Implements struct &drm_crtc_funcs.disable_vblank |
| * @crtc: The CRTC |
| * |
| * The helper drm_crtc_vblank_helper_disable_vblank_timer() implements |
| * disable_vblank of struct drm_crtc_funcs for CRTCs that require a |
| * VBLANK timer. |
| * |
| * See also struct &drm_crtc_helper_funcs.disable_vblank. |
| */ |
| void drm_crtc_vblank_helper_disable_vblank_timer(struct drm_crtc *crtc) |
| { |
| drm_crtc_vblank_cancel_timer(crtc); |
| } |
| EXPORT_SYMBOL(drm_crtc_vblank_helper_disable_vblank_timer); |
| |
| /** |
| * drm_crtc_vblank_helper_get_vblank_timestamp_from_timer - |
| * Implements struct &drm_crtc_funcs.get_vblank_timestamp |
| * @crtc: The CRTC |
| * @max_error: Maximum acceptable error |
| * @vblank_time: Returns the next vblank timestamp |
| * @in_vblank_irq: True is called from drm_crtc_handle_vblank() |
| * |
| * The helper drm_crtc_helper_get_vblank_timestamp_from_timer() implements |
| * get_vblank_timestamp of struct drm_crtc_funcs for CRTCs that require a |
| * VBLANK timer. It returns the timestamp according to the timer's expiry |
| * time. |
| * |
| * See also struct &drm_crtc_funcs.get_vblank_timestamp. |
| * |
| * Returns: |
| * True on success, or false otherwise. |
| */ |
| bool drm_crtc_vblank_helper_get_vblank_timestamp_from_timer(struct drm_crtc *crtc, |
| int *max_error, |
| ktime_t *vblank_time, |
| bool in_vblank_irq) |
| { |
| drm_crtc_vblank_get_vblank_timeout(crtc, vblank_time); |
| |
| return true; |
| } |
| EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp_from_timer); |