1 // SPDX-License-Identifier: MIT 2 3 #include <drm/drm_atomic.h> 4 #include <drm/drm_crtc.h> 5 #include <drm/drm_managed.h> 6 #include <drm/drm_modeset_helper_vtables.h> 7 #include <drm/drm_print.h> 8 #include <drm/drm_vblank.h> 9 #include <drm/drm_vblank_helper.h> 10 11 /** 12 * DOC: overview 13 * 14 * The vblank helper library provides functions for supporting vertical 15 * blanking in DRM drivers. 16 * 17 * For vblank timers, several callback implementations are available. 18 * Drivers enable support for vblank timers by setting the vblank callbacks 19 * in struct &drm_crtc_funcs to the helpers provided by this library. The 20 * initializer macro DRM_CRTC_VBLANK_TIMER_FUNCS does this conveniently. 21 * The driver further has to send the VBLANK event from its atomic_flush 22 * callback and control vblank from the CRTC's atomic_enable and atomic_disable 23 * callbacks. The callbacks are located in struct &drm_crtc_helper_funcs. 24 * The vblank helper library provides implementations of these callbacks 25 * for drivers without further requirements. The initializer macro 26 * DRM_CRTC_HELPER_VBLANK_FUNCS sets them coveniently. 27 * 28 * Once the driver enables vblank support with drm_vblank_init(), each 29 * CRTC's vblank timer fires according to the programmed display mode. By 30 * default, the vblank timer invokes drm_crtc_handle_vblank(). Drivers with 31 * more specific requirements can set their own handler function in 32 * struct &drm_crtc_helper_funcs.handle_vblank_timeout. 33 */ 34 35 /* 36 * VBLANK helpers 37 */ 38 39 /** 40 * drm_crtc_vblank_atomic_flush - 41 * Implements struct &drm_crtc_helper_funcs.atomic_flush 42 * @crtc: The CRTC 43 * @state: The atomic state to apply 44 * 45 * The helper drm_crtc_vblank_atomic_flush() implements atomic_flush of 46 * struct drm_crtc_helper_funcs for CRTCs that only need to send out a 47 * VBLANK event. 48 * 49 * See also struct &drm_crtc_helper_funcs.atomic_flush. 50 */ 51 void drm_crtc_vblank_atomic_flush(struct drm_crtc *crtc, 52 struct drm_atomic_state *state) 53 { 54 struct drm_device *dev = crtc->dev; 55 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 56 struct drm_pending_vblank_event *event; 57 58 spin_lock_irq(&dev->event_lock); 59 60 event = crtc_state->event; 61 crtc_state->event = NULL; 62 63 if (event) { 64 if (drm_crtc_vblank_get(crtc) == 0) 65 drm_crtc_arm_vblank_event(crtc, event); 66 else 67 drm_crtc_send_vblank_event(crtc, event); 68 } 69 70 spin_unlock_irq(&dev->event_lock); 71 } 72 EXPORT_SYMBOL(drm_crtc_vblank_atomic_flush); 73 74 /** 75 * drm_crtc_vblank_atomic_enable - Implements struct &drm_crtc_helper_funcs.atomic_enable 76 * @crtc: The CRTC 77 * @state: The atomic state 78 * 79 * The helper drm_crtc_vblank_atomic_enable() implements atomic_enable 80 * of struct drm_crtc_helper_funcs for CRTCs the only need to enable VBLANKs. 81 * 82 * See also struct &drm_crtc_helper_funcs.atomic_enable. 83 */ 84 void drm_crtc_vblank_atomic_enable(struct drm_crtc *crtc, 85 struct drm_atomic_state *state) 86 { 87 drm_crtc_vblank_on(crtc); 88 } 89 EXPORT_SYMBOL(drm_crtc_vblank_atomic_enable); 90 91 /** 92 * drm_crtc_vblank_atomic_disable - Implements struct &drm_crtc_helper_funcs.atomic_disable 93 * @crtc: The CRTC 94 * @state: The atomic state 95 * 96 * The helper drm_crtc_vblank_atomic_disable() implements atomic_disable 97 * of struct drm_crtc_helper_funcs for CRTCs the only need to disable VBLANKs. 98 * 99 * See also struct &drm_crtc_funcs.atomic_disable. 100 */ 101 void drm_crtc_vblank_atomic_disable(struct drm_crtc *crtc, 102 struct drm_atomic_state *state) 103 { 104 drm_crtc_vblank_off(crtc); 105 } 106 EXPORT_SYMBOL(drm_crtc_vblank_atomic_disable); 107 108 /* 109 * VBLANK timer 110 */ 111 112 /** 113 * drm_crtc_vblank_helper_enable_vblank_timer - Implements struct &drm_crtc_funcs.enable_vblank 114 * @crtc: The CRTC 115 * 116 * The helper drm_crtc_vblank_helper_enable_vblank_timer() implements 117 * enable_vblank of struct drm_crtc_helper_funcs for CRTCs that require 118 * a VBLANK timer. It sets up the timer on the first invocation. The 119 * started timer expires after the current frame duration. See struct 120 * &drm_vblank_crtc.framedur_ns. 121 * 122 * See also struct &drm_crtc_helper_funcs.enable_vblank. 123 * 124 * Returns: 125 * 0 on success, or a negative errno code otherwise. 126 */ 127 int drm_crtc_vblank_helper_enable_vblank_timer(struct drm_crtc *crtc) 128 { 129 return drm_crtc_vblank_start_timer(crtc); 130 } 131 EXPORT_SYMBOL(drm_crtc_vblank_helper_enable_vblank_timer); 132 133 /** 134 * drm_crtc_vblank_helper_disable_vblank_timer - Implements struct &drm_crtc_funcs.disable_vblank 135 * @crtc: The CRTC 136 * 137 * The helper drm_crtc_vblank_helper_disable_vblank_timer() implements 138 * disable_vblank of struct drm_crtc_funcs for CRTCs that require a 139 * VBLANK timer. 140 * 141 * See also struct &drm_crtc_helper_funcs.disable_vblank. 142 */ 143 void drm_crtc_vblank_helper_disable_vblank_timer(struct drm_crtc *crtc) 144 { 145 drm_crtc_vblank_cancel_timer(crtc); 146 } 147 EXPORT_SYMBOL(drm_crtc_vblank_helper_disable_vblank_timer); 148 149 /** 150 * drm_crtc_vblank_helper_get_vblank_timestamp_from_timer - 151 * Implements struct &drm_crtc_funcs.get_vblank_timestamp 152 * @crtc: The CRTC 153 * @max_error: Maximum acceptable error 154 * @vblank_time: Returns the next vblank timestamp 155 * @in_vblank_irq: True is called from drm_crtc_handle_vblank() 156 * 157 * The helper drm_crtc_helper_get_vblank_timestamp_from_timer() implements 158 * get_vblank_timestamp of struct drm_crtc_funcs for CRTCs that require a 159 * VBLANK timer. It returns the timestamp according to the timer's expiry 160 * time. 161 * 162 * See also struct &drm_crtc_funcs.get_vblank_timestamp. 163 * 164 * Returns: 165 * True on success, or false otherwise. 166 */ 167 bool drm_crtc_vblank_helper_get_vblank_timestamp_from_timer(struct drm_crtc *crtc, 168 int *max_error, 169 ktime_t *vblank_time, 170 bool in_vblank_irq) 171 { 172 drm_crtc_vblank_get_vblank_timeout(crtc, vblank_time); 173 174 return true; 175 } 176 EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp_from_timer); 177