Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/vblank: Add CRTC helpers for simple use cases

Implement atomic_flush, atomic_enable and atomic_disable of struct
drm_crtc_helper_funcs for vblank handling. Driver with no further
requirements can use these functions instead of adding their own.
Also simplifies the use of vblank timers.

The code has been adopted from vkms, which added the funtionality
in commit 3a0709928b17 ("drm/vkms: Add vblank events simulated by
hrtimers").

v3:
- mention vkms (Javier)
v2:
- fix docs

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Tested-by: Michael Kelley <mhklinux@outlook.com>
Link: https://lore.kernel.org/r/20250916083816.30275-3-tzimmermann@suse.de

+103
+80
drivers/gpu/drm/drm_vblank_helper.c
··· 1 1 // SPDX-License-Identifier: MIT 2 2 3 + #include <drm/drm_atomic.h> 3 4 #include <drm/drm_crtc.h> 4 5 #include <drm/drm_managed.h> 5 6 #include <drm/drm_modeset_helper_vtables.h> ··· 18 17 * Drivers enable support for vblank timers by setting the vblank callbacks 19 18 * in struct &drm_crtc_funcs to the helpers provided by this library. The 20 19 * initializer macro DRM_CRTC_VBLANK_TIMER_FUNCS does this conveniently. 20 + * The driver further has to send the VBLANK event from its atomic_flush 21 + * callback and control vblank from the CRTC's atomic_enable and atomic_disable 22 + * callbacks. The callbacks are located in struct &drm_crtc_helper_funcs. 23 + * The vblank helper library provides implementations of these callbacks 24 + * for drivers without further requirements. The initializer macro 25 + * DRM_CRTC_HELPER_VBLANK_FUNCS sets them coveniently. 21 26 * 22 27 * Once the driver enables vblank support with drm_vblank_init(), each 23 28 * CRTC's vblank timer fires according to the programmed display mode. By ··· 31 24 * more specific requirements can set their own handler function in 32 25 * struct &drm_crtc_helper_funcs.handle_vblank_timeout. 33 26 */ 27 + 28 + /* 29 + * VBLANK helpers 30 + */ 31 + 32 + /** 33 + * drm_crtc_vblank_atomic_flush - 34 + * Implements struct &drm_crtc_helper_funcs.atomic_flush 35 + * @crtc: The CRTC 36 + * @state: The atomic state to apply 37 + * 38 + * The helper drm_crtc_vblank_atomic_flush() implements atomic_flush of 39 + * struct drm_crtc_helper_funcs for CRTCs that only need to send out a 40 + * VBLANK event. 41 + * 42 + * See also struct &drm_crtc_helper_funcs.atomic_flush. 43 + */ 44 + void drm_crtc_vblank_atomic_flush(struct drm_crtc *crtc, 45 + struct drm_atomic_state *state) 46 + { 47 + struct drm_device *dev = crtc->dev; 48 + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 49 + struct drm_pending_vblank_event *event; 50 + 51 + spin_lock_irq(&dev->event_lock); 52 + 53 + event = crtc_state->event; 54 + crtc_state->event = NULL; 55 + 56 + if (event) { 57 + if (drm_crtc_vblank_get(crtc) == 0) 58 + drm_crtc_arm_vblank_event(crtc, event); 59 + else 60 + drm_crtc_send_vblank_event(crtc, event); 61 + } 62 + 63 + spin_unlock_irq(&dev->event_lock); 64 + } 65 + EXPORT_SYMBOL(drm_crtc_vblank_atomic_flush); 66 + 67 + /** 68 + * drm_crtc_vblank_atomic_enable - Implements struct &drm_crtc_helper_funcs.atomic_enable 69 + * @crtc: The CRTC 70 + * @state: The atomic state 71 + * 72 + * The helper drm_crtc_vblank_atomic_enable() implements atomic_enable 73 + * of struct drm_crtc_helper_funcs for CRTCs the only need to enable VBLANKs. 74 + * 75 + * See also struct &drm_crtc_helper_funcs.atomic_enable. 76 + */ 77 + void drm_crtc_vblank_atomic_enable(struct drm_crtc *crtc, 78 + struct drm_atomic_state *state) 79 + { 80 + drm_crtc_vblank_on(crtc); 81 + } 82 + EXPORT_SYMBOL(drm_crtc_vblank_atomic_enable); 83 + 84 + /** 85 + * drm_crtc_vblank_atomic_disable - Implements struct &drm_crtc_helper_funcs.atomic_disable 86 + * @crtc: The CRTC 87 + * @state: The atomic state 88 + * 89 + * The helper drm_crtc_vblank_atomic_disable() implements atomic_disable 90 + * of struct drm_crtc_helper_funcs for CRTCs the only need to disable VBLANKs. 91 + * 92 + * See also struct &drm_crtc_funcs.atomic_disable. 93 + */ 94 + void drm_crtc_vblank_atomic_disable(struct drm_crtc *crtc, 95 + struct drm_atomic_state *state) 96 + { 97 + drm_crtc_vblank_off(crtc); 98 + } 99 + EXPORT_SYMBOL(drm_crtc_vblank_atomic_disable); 34 100 35 101 /* 36 102 * VBLANK timer
+23
include/drm/drm_vblank_helper.h
··· 6 6 #include <linux/hrtimer_types.h> 7 7 #include <linux/types.h> 8 8 9 + struct drm_atomic_state; 9 10 struct drm_crtc; 11 + 12 + /* 13 + * VBLANK helpers 14 + */ 15 + 16 + void drm_crtc_vblank_atomic_flush(struct drm_crtc *crtc, 17 + struct drm_atomic_state *state); 18 + void drm_crtc_vblank_atomic_enable(struct drm_crtc *crtc, 19 + struct drm_atomic_state *state); 20 + void drm_crtc_vblank_atomic_disable(struct drm_crtc *crtc, 21 + struct drm_atomic_state *crtc_state); 22 + 23 + /** 24 + * DRM_CRTC_HELPER_VBLANK_FUNCS - Default implementation for VBLANK helpers 25 + * 26 + * This macro initializes struct &drm_crtc_helper_funcs to default helpers 27 + * for VBLANK handling. 28 + */ 29 + #define DRM_CRTC_HELPER_VBLANK_FUNCS \ 30 + .atomic_flush = drm_crtc_vblank_atomic_flush, \ 31 + .atomic_enable = drm_crtc_vblank_atomic_enable, \ 32 + .atomic_disable = drm_crtc_vblank_atomic_disable 10 33 11 34 /* 12 35 * VBLANK timer