1a1b63119SJosé Roberto de Souza // SPDX-License-Identifier: MIT 2a1b63119SJosé Roberto de Souza /* 3a1b63119SJosé Roberto de Souza * Copyright © 2021 Intel Corporation 4a1b63119SJosé Roberto de Souza */ 5a1b63119SJosé Roberto de Souza 6a1b63119SJosé Roberto de Souza #include "i915_drv.h" 7801543b2SJani Nikula #include "i915_reg.h" 8a1b63119SJosé Roberto de Souza #include "intel_atomic.h" 9a1b63119SJosé Roberto de Souza #include "intel_de.h" 10a1b63119SJosé Roberto de Souza #include "intel_display_types.h" 11a1b63119SJosé Roberto de Souza #include "intel_drrs.h" 12a1b63119SJosé Roberto de Souza #include "intel_panel.h" 13a1b63119SJosé Roberto de Souza 14a1b63119SJosé Roberto de Souza /** 15a1b63119SJosé Roberto de Souza * DOC: Display Refresh Rate Switching (DRRS) 16a1b63119SJosé Roberto de Souza * 17a1b63119SJosé Roberto de Souza * Display Refresh Rate Switching (DRRS) is a power conservation feature 18a1b63119SJosé Roberto de Souza * which enables swtching between low and high refresh rates, 19a1b63119SJosé Roberto de Souza * dynamically, based on the usage scenario. This feature is applicable 20a1b63119SJosé Roberto de Souza * for internal panels. 21a1b63119SJosé Roberto de Souza * 22a1b63119SJosé Roberto de Souza * Indication that the panel supports DRRS is given by the panel EDID, which 23a1b63119SJosé Roberto de Souza * would list multiple refresh rates for one resolution. 24a1b63119SJosé Roberto de Souza * 25a1b63119SJosé Roberto de Souza * DRRS is of 2 types - static and seamless. 26a1b63119SJosé Roberto de Souza * Static DRRS involves changing refresh rate (RR) by doing a full modeset 27a1b63119SJosé Roberto de Souza * (may appear as a blink on screen) and is used in dock-undock scenario. 28a1b63119SJosé Roberto de Souza * Seamless DRRS involves changing RR without any visual effect to the user 29a1b63119SJosé Roberto de Souza * and can be used during normal system usage. This is done by programming 30a1b63119SJosé Roberto de Souza * certain registers. 31a1b63119SJosé Roberto de Souza * 32a1b63119SJosé Roberto de Souza * Support for static/seamless DRRS may be indicated in the VBT based on 33a1b63119SJosé Roberto de Souza * inputs from the panel spec. 34a1b63119SJosé Roberto de Souza * 35a1b63119SJosé Roberto de Souza * DRRS saves power by switching to low RR based on usage scenarios. 36a1b63119SJosé Roberto de Souza * 37a1b63119SJosé Roberto de Souza * The implementation is based on frontbuffer tracking implementation. When 38a1b63119SJosé Roberto de Souza * there is a disturbance on the screen triggered by user activity or a periodic 39a1b63119SJosé Roberto de Souza * system activity, DRRS is disabled (RR is changed to high RR). When there is 40a1b63119SJosé Roberto de Souza * no movement on screen, after a timeout of 1 second, a switch to low RR is 41a1b63119SJosé Roberto de Souza * made. 42a1b63119SJosé Roberto de Souza * 433a3dd534SJosé Roberto de Souza * For integration with frontbuffer tracking code, intel_drrs_invalidate() 443a3dd534SJosé Roberto de Souza * and intel_drrs_flush() are called. 45a1b63119SJosé Roberto de Souza * 46a1b63119SJosé Roberto de Souza * DRRS can be further extended to support other internal panels and also 47a1b63119SJosé Roberto de Souza * the scenario of video playback wherein RR is set based on the rate 48a1b63119SJosé Roberto de Souza * requested by userspace. 49a1b63119SJosé Roberto de Souza */ 50a1b63119SJosé Roberto de Souza 51a1b952d4SVille Syrjälä const char *intel_drrs_type_str(enum drrs_type drrs_type) 52a1b952d4SVille Syrjälä { 53a1b952d4SVille Syrjälä static const char * const str[] = { 54a1b952d4SVille Syrjälä [DRRS_TYPE_NONE] = "none", 55a1b952d4SVille Syrjälä [DRRS_TYPE_STATIC] = "static", 56a1b952d4SVille Syrjälä [DRRS_TYPE_SEAMLESS] = "seamless", 57a1b952d4SVille Syrjälä }; 58a1b952d4SVille Syrjälä 59a1b952d4SVille Syrjälä if (drrs_type >= ARRAY_SIZE(str)) 60a1b952d4SVille Syrjälä return "<invalid>"; 61a1b952d4SVille Syrjälä 62a1b952d4SVille Syrjälä return str[drrs_type]; 63a1b952d4SVille Syrjälä } 64a1b952d4SVille Syrjälä 6514683babSVille Syrjälä static void 66851f15feSVille Syrjälä intel_drrs_set_refresh_rate_pipeconf(struct intel_crtc *crtc, 675a220c53SVille Syrjälä enum drrs_refresh_rate refresh_rate) 6814683babSVille Syrjälä { 6914683babSVille Syrjälä struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); 70851f15feSVille Syrjälä enum transcoder cpu_transcoder = crtc->drrs.cpu_transcoder; 71*59ea2887SAndrzej Hajda u32 bit; 7214683babSVille Syrjälä 7314683babSVille Syrjälä if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) 74dd7ae6b3SVille Syrjälä bit = PIPECONF_REFRESH_RATE_ALT_VLV; 7514683babSVille Syrjälä else 76dd7ae6b3SVille Syrjälä bit = PIPECONF_REFRESH_RATE_ALT_ILK; 7714683babSVille Syrjälä 78*59ea2887SAndrzej Hajda intel_de_rmw(dev_priv, PIPECONF(cpu_transcoder), 79*59ea2887SAndrzej Hajda bit, refresh_rate == DRRS_REFRESH_RATE_LOW ? bit : 0); 8014683babSVille Syrjälä } 8114683babSVille Syrjälä 8214683babSVille Syrjälä static void 83851f15feSVille Syrjälä intel_drrs_set_refresh_rate_m_n(struct intel_crtc *crtc, 845a220c53SVille Syrjälä enum drrs_refresh_rate refresh_rate) 8514683babSVille Syrjälä { 86851f15feSVille Syrjälä intel_cpu_transcoder_set_m1_n1(crtc, crtc->drrs.cpu_transcoder, 875a220c53SVille Syrjälä refresh_rate == DRRS_REFRESH_RATE_LOW ? 88851f15feSVille Syrjälä &crtc->drrs.m2_n2 : &crtc->drrs.m_n); 8914683babSVille Syrjälä } 9014683babSVille Syrjälä 9154903c7aSVille Syrjälä bool intel_drrs_is_active(struct intel_crtc *crtc) 92a1b63119SJosé Roberto de Souza { 93851f15feSVille Syrjälä return crtc->drrs.cpu_transcoder != INVALID_TRANSCODER; 94a1b63119SJosé Roberto de Souza } 95a1b63119SJosé Roberto de Souza 96851f15feSVille Syrjälä static void intel_drrs_set_state(struct intel_crtc *crtc, 97851f15feSVille Syrjälä enum drrs_refresh_rate refresh_rate) 98a1b63119SJosé Roberto de Souza { 99ba770ce3SVille Syrjälä struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); 100a1b63119SJosé Roberto de Souza 101851f15feSVille Syrjälä if (refresh_rate == crtc->drrs.refresh_rate) 102851f15feSVille Syrjälä return; 103851f15feSVille Syrjälä 104c2f12155SVille Syrjälä if (intel_cpu_transcoder_has_m2_n2(dev_priv, crtc->drrs.cpu_transcoder)) 105851f15feSVille Syrjälä intel_drrs_set_refresh_rate_pipeconf(crtc, refresh_rate); 106c2f12155SVille Syrjälä else 107c2f12155SVille Syrjälä intel_drrs_set_refresh_rate_m_n(crtc, refresh_rate); 108851f15feSVille Syrjälä 109851f15feSVille Syrjälä crtc->drrs.refresh_rate = refresh_rate; 110a1b63119SJosé Roberto de Souza } 111a1b63119SJosé Roberto de Souza 1121c004047SVille Syrjälä static void intel_drrs_schedule_work(struct intel_crtc *crtc) 1131c004047SVille Syrjälä { 1141c004047SVille Syrjälä mod_delayed_work(system_wq, &crtc->drrs.work, msecs_to_jiffies(1000)); 1151c004047SVille Syrjälä } 1161c004047SVille Syrjälä 11770e10a2bSVille Syrjälä static unsigned int intel_drrs_frontbuffer_bits(const struct intel_crtc_state *crtc_state) 11870e10a2bSVille Syrjälä { 11970e10a2bSVille Syrjälä struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); 120579899c7SVille Syrjälä struct drm_i915_private *i915 = to_i915(crtc->base.dev); 121579899c7SVille Syrjälä unsigned int frontbuffer_bits; 12270e10a2bSVille Syrjälä 123579899c7SVille Syrjälä frontbuffer_bits = INTEL_FRONTBUFFER_ALL_MASK(crtc->pipe); 124579899c7SVille Syrjälä 125579899c7SVille Syrjälä for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, 126579899c7SVille Syrjälä crtc_state->bigjoiner_pipes) 127579899c7SVille Syrjälä frontbuffer_bits |= INTEL_FRONTBUFFER_ALL_MASK(crtc->pipe); 128579899c7SVille Syrjälä 129579899c7SVille Syrjälä return frontbuffer_bits; 13070e10a2bSVille Syrjälä } 13170e10a2bSVille Syrjälä 132a1b63119SJosé Roberto de Souza /** 13354903c7aSVille Syrjälä * intel_drrs_activate - activate DRRS 13454903c7aSVille Syrjälä * @crtc_state: the crtc state 135a1b63119SJosé Roberto de Souza * 13654903c7aSVille Syrjälä * Activates DRRS on the crtc. 137a1b63119SJosé Roberto de Souza */ 13854903c7aSVille Syrjälä void intel_drrs_activate(const struct intel_crtc_state *crtc_state) 139a1b63119SJosé Roberto de Souza { 140ba770ce3SVille Syrjälä struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); 141a1b63119SJosé Roberto de Souza 142a1b63119SJosé Roberto de Souza if (!crtc_state->has_drrs) 143a1b63119SJosé Roberto de Souza return; 144a1b63119SJosé Roberto de Souza 1451b333c67SVille Syrjälä if (!crtc_state->hw.active) 1461b333c67SVille Syrjälä return; 147a1b63119SJosé Roberto de Souza 148579899c7SVille Syrjälä if (intel_crtc_is_bigjoiner_slave(crtc_state)) 149579899c7SVille Syrjälä return; 150579899c7SVille Syrjälä 151851f15feSVille Syrjälä mutex_lock(&crtc->drrs.mutex); 152a1b63119SJosé Roberto de Souza 153851f15feSVille Syrjälä crtc->drrs.cpu_transcoder = crtc_state->cpu_transcoder; 154851f15feSVille Syrjälä crtc->drrs.m_n = crtc_state->dp_m_n; 155851f15feSVille Syrjälä crtc->drrs.m2_n2 = crtc_state->dp_m2_n2; 15670e10a2bSVille Syrjälä crtc->drrs.frontbuffer_bits = intel_drrs_frontbuffer_bits(crtc_state); 157851f15feSVille Syrjälä crtc->drrs.busy_frontbuffer_bits = 0; 158a1b63119SJosé Roberto de Souza 1591c004047SVille Syrjälä intel_drrs_schedule_work(crtc); 1601c004047SVille Syrjälä 161851f15feSVille Syrjälä mutex_unlock(&crtc->drrs.mutex); 162a1b63119SJosé Roberto de Souza } 163a1b63119SJosé Roberto de Souza 164a1b63119SJosé Roberto de Souza /** 16554903c7aSVille Syrjälä * intel_drrs_deactivate - deactivate DRRS 16654903c7aSVille Syrjälä * @old_crtc_state: the old crtc state 16754903c7aSVille Syrjälä * 16854903c7aSVille Syrjälä * Deactivates DRRS on the crtc. 169a1b63119SJosé Roberto de Souza */ 17054903c7aSVille Syrjälä void intel_drrs_deactivate(const struct intel_crtc_state *old_crtc_state) 171a1b63119SJosé Roberto de Souza { 172ba770ce3SVille Syrjälä struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); 173a1b63119SJosé Roberto de Souza 174a1b63119SJosé Roberto de Souza if (!old_crtc_state->has_drrs) 175a1b63119SJosé Roberto de Souza return; 176a1b63119SJosé Roberto de Souza 1771b333c67SVille Syrjälä if (!old_crtc_state->hw.active) 1781b333c67SVille Syrjälä return; 179a1b63119SJosé Roberto de Souza 180579899c7SVille Syrjälä if (intel_crtc_is_bigjoiner_slave(old_crtc_state)) 181579899c7SVille Syrjälä return; 182579899c7SVille Syrjälä 183851f15feSVille Syrjälä mutex_lock(&crtc->drrs.mutex); 184a1b63119SJosé Roberto de Souza 18554903c7aSVille Syrjälä if (intel_drrs_is_active(crtc)) 186851f15feSVille Syrjälä intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_HIGH); 187851f15feSVille Syrjälä 188851f15feSVille Syrjälä crtc->drrs.cpu_transcoder = INVALID_TRANSCODER; 18970e10a2bSVille Syrjälä crtc->drrs.frontbuffer_bits = 0; 190851f15feSVille Syrjälä crtc->drrs.busy_frontbuffer_bits = 0; 191851f15feSVille Syrjälä 192851f15feSVille Syrjälä mutex_unlock(&crtc->drrs.mutex); 193851f15feSVille Syrjälä 194851f15feSVille Syrjälä cancel_delayed_work_sync(&crtc->drrs.work); 195a1b63119SJosé Roberto de Souza } 196a1b63119SJosé Roberto de Souza 1973a3dd534SJosé Roberto de Souza static void intel_drrs_downclock_work(struct work_struct *work) 198a1b63119SJosé Roberto de Souza { 199851f15feSVille Syrjälä struct intel_crtc *crtc = container_of(work, typeof(*crtc), drrs.work.work); 200a1b63119SJosé Roberto de Souza 201851f15feSVille Syrjälä mutex_lock(&crtc->drrs.mutex); 202a1b63119SJosé Roberto de Souza 20354903c7aSVille Syrjälä if (intel_drrs_is_active(crtc) && !crtc->drrs.busy_frontbuffer_bits) 204851f15feSVille Syrjälä intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_LOW); 205a1b63119SJosé Roberto de Souza 206851f15feSVille Syrjälä mutex_unlock(&crtc->drrs.mutex); 207a1b63119SJosé Roberto de Souza } 208a1b63119SJosé Roberto de Souza 2096bd58b70SJosé Roberto de Souza static void intel_drrs_frontbuffer_update(struct drm_i915_private *dev_priv, 21018f23b92SVille Syrjälä unsigned int all_frontbuffer_bits, 2116bd58b70SJosé Roberto de Souza bool invalidate) 212a1b63119SJosé Roberto de Souza { 213ba770ce3SVille Syrjälä struct intel_crtc *crtc; 214a1b63119SJosé Roberto de Souza 215851f15feSVille Syrjälä for_each_intel_crtc(&dev_priv->drm, crtc) { 21618f23b92SVille Syrjälä unsigned int frontbuffer_bits; 21718f23b92SVille Syrjälä 218851f15feSVille Syrjälä mutex_lock(&crtc->drrs.mutex); 219a1b63119SJosé Roberto de Souza 220fb4ae6e6SVille Syrjälä frontbuffer_bits = all_frontbuffer_bits & crtc->drrs.frontbuffer_bits; 221fb4ae6e6SVille Syrjälä if (!frontbuffer_bits) { 222851f15feSVille Syrjälä mutex_unlock(&crtc->drrs.mutex); 223851f15feSVille Syrjälä continue; 224a1b63119SJosé Roberto de Souza } 225a1b63119SJosé Roberto de Souza 2266bd58b70SJosé Roberto de Souza if (invalidate) 227851f15feSVille Syrjälä crtc->drrs.busy_frontbuffer_bits |= frontbuffer_bits; 2286bd58b70SJosé Roberto de Souza else 229851f15feSVille Syrjälä crtc->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; 230a1b63119SJosé Roberto de Souza 2316bd58b70SJosé Roberto de Souza /* flush/invalidate means busy screen hence upclock */ 232851f15feSVille Syrjälä intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_HIGH); 233a1b63119SJosé Roberto de Souza 2346bd58b70SJosé Roberto de Souza /* 2356bd58b70SJosé Roberto de Souza * flush also means no more activity hence schedule downclock, if all 2366bd58b70SJosé Roberto de Souza * other fbs are quiescent too 2376bd58b70SJosé Roberto de Souza */ 238fb4ae6e6SVille Syrjälä if (!crtc->drrs.busy_frontbuffer_bits) 2391c004047SVille Syrjälä intel_drrs_schedule_work(crtc); 240fb4ae6e6SVille Syrjälä else 241fb4ae6e6SVille Syrjälä cancel_delayed_work(&crtc->drrs.work); 242851f15feSVille Syrjälä 243851f15feSVille Syrjälä mutex_unlock(&crtc->drrs.mutex); 244851f15feSVille Syrjälä } 245a1b63119SJosé Roberto de Souza } 246a1b63119SJosé Roberto de Souza 247a1b63119SJosé Roberto de Souza /** 2486bd58b70SJosé Roberto de Souza * intel_drrs_invalidate - Disable Idleness DRRS 2496bd58b70SJosé Roberto de Souza * @dev_priv: i915 device 2506bd58b70SJosé Roberto de Souza * @frontbuffer_bits: frontbuffer plane tracking bits 2516bd58b70SJosé Roberto de Souza * 2526bd58b70SJosé Roberto de Souza * This function gets called everytime rendering on the given planes start. 2536bd58b70SJosé Roberto de Souza * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR). 2546bd58b70SJosé Roberto de Souza * 2556bd58b70SJosé Roberto de Souza * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits. 2566bd58b70SJosé Roberto de Souza */ 2576bd58b70SJosé Roberto de Souza void intel_drrs_invalidate(struct drm_i915_private *dev_priv, 2586bd58b70SJosé Roberto de Souza unsigned int frontbuffer_bits) 2596bd58b70SJosé Roberto de Souza { 2606bd58b70SJosé Roberto de Souza intel_drrs_frontbuffer_update(dev_priv, frontbuffer_bits, true); 2616bd58b70SJosé Roberto de Souza } 2626bd58b70SJosé Roberto de Souza 2636bd58b70SJosé Roberto de Souza /** 2643a3dd534SJosé Roberto de Souza * intel_drrs_flush - Restart Idleness DRRS 265a1b63119SJosé Roberto de Souza * @dev_priv: i915 device 266a1b63119SJosé Roberto de Souza * @frontbuffer_bits: frontbuffer plane tracking bits 267a1b63119SJosé Roberto de Souza * 268a1b63119SJosé Roberto de Souza * This function gets called every time rendering on the given planes has 269a1b63119SJosé Roberto de Souza * completed or flip on a crtc is completed. So DRRS should be upclocked 270a1b63119SJosé Roberto de Souza * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again, 271a1b63119SJosé Roberto de Souza * if no other planes are dirty. 272a1b63119SJosé Roberto de Souza * 273a1b63119SJosé Roberto de Souza * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits. 274a1b63119SJosé Roberto de Souza */ 2753a3dd534SJosé Roberto de Souza void intel_drrs_flush(struct drm_i915_private *dev_priv, 276a1b63119SJosé Roberto de Souza unsigned int frontbuffer_bits) 277a1b63119SJosé Roberto de Souza { 2786bd58b70SJosé Roberto de Souza intel_drrs_frontbuffer_update(dev_priv, frontbuffer_bits, false); 279a1b63119SJosé Roberto de Souza } 280a1b63119SJosé Roberto de Souza 281a1b63119SJosé Roberto de Souza /** 282a2b1d9ecSVille Syrjälä * intel_drrs_crtc_init - Init DRRS for CRTC 283851f15feSVille Syrjälä * @crtc: crtc 284a1b63119SJosé Roberto de Souza * 285a1b63119SJosé Roberto de Souza * This function is called only once at driver load to initialize basic 286a1b63119SJosé Roberto de Souza * DRRS stuff. 287a1b63119SJosé Roberto de Souza * 288851f15feSVille Syrjälä */ 289a2b1d9ecSVille Syrjälä void intel_drrs_crtc_init(struct intel_crtc *crtc) 290851f15feSVille Syrjälä { 291851f15feSVille Syrjälä INIT_DELAYED_WORK(&crtc->drrs.work, intel_drrs_downclock_work); 292851f15feSVille Syrjälä mutex_init(&crtc->drrs.mutex); 293851f15feSVille Syrjälä crtc->drrs.cpu_transcoder = INVALID_TRANSCODER; 294851f15feSVille Syrjälä } 29561564e6cSVille Syrjälä 29661564e6cSVille Syrjälä static int intel_drrs_debugfs_status_show(struct seq_file *m, void *unused) 29761564e6cSVille Syrjälä { 298adc831bfSVille Syrjälä struct intel_crtc *crtc = m->private; 2999519c865SVille Syrjälä const struct intel_crtc_state *crtc_state; 3009519c865SVille Syrjälä int ret; 3019519c865SVille Syrjälä 3029519c865SVille Syrjälä ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex); 3039519c865SVille Syrjälä if (ret) 3049519c865SVille Syrjälä return ret; 3059519c865SVille Syrjälä 3069519c865SVille Syrjälä crtc_state = to_intel_crtc_state(crtc->base.state); 30761564e6cSVille Syrjälä 30861564e6cSVille Syrjälä mutex_lock(&crtc->drrs.mutex); 30961564e6cSVille Syrjälä 310adc831bfSVille Syrjälä seq_printf(m, "DRRS enabled: %s\n", 31161564e6cSVille Syrjälä str_yes_no(crtc_state->has_drrs)); 31261564e6cSVille Syrjälä 313adc831bfSVille Syrjälä seq_printf(m, "DRRS active: %s\n", 31461564e6cSVille Syrjälä str_yes_no(intel_drrs_is_active(crtc))); 31561564e6cSVille Syrjälä 316adc831bfSVille Syrjälä seq_printf(m, "DRRS refresh rate: %s\n", 31761564e6cSVille Syrjälä crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ? 31861564e6cSVille Syrjälä "low" : "high"); 31961564e6cSVille Syrjälä 320adc831bfSVille Syrjälä seq_printf(m, "DRRS busy frontbuffer bits: 0x%x\n", 3212e25c1fbSVille Syrjälä crtc->drrs.busy_frontbuffer_bits); 3222e25c1fbSVille Syrjälä 32361564e6cSVille Syrjälä mutex_unlock(&crtc->drrs.mutex); 32461564e6cSVille Syrjälä 3259519c865SVille Syrjälä drm_modeset_unlock(&crtc->base.mutex); 3269519c865SVille Syrjälä 32761564e6cSVille Syrjälä return 0; 32861564e6cSVille Syrjälä } 32961564e6cSVille Syrjälä 33061564e6cSVille Syrjälä DEFINE_SHOW_ATTRIBUTE(intel_drrs_debugfs_status); 33161564e6cSVille Syrjälä 33261564e6cSVille Syrjälä static int intel_drrs_debugfs_ctl_set(void *data, u64 val) 33361564e6cSVille Syrjälä { 334adc831bfSVille Syrjälä struct intel_crtc *crtc = data; 335adc831bfSVille Syrjälä struct drm_i915_private *i915 = to_i915(crtc->base.dev); 33661564e6cSVille Syrjälä struct intel_crtc_state *crtc_state; 33761564e6cSVille Syrjälä struct drm_crtc_commit *commit; 33861564e6cSVille Syrjälä int ret; 33961564e6cSVille Syrjälä 34061564e6cSVille Syrjälä ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex); 34161564e6cSVille Syrjälä if (ret) 34261564e6cSVille Syrjälä return ret; 34361564e6cSVille Syrjälä 34461564e6cSVille Syrjälä crtc_state = to_intel_crtc_state(crtc->base.state); 34561564e6cSVille Syrjälä 34661564e6cSVille Syrjälä if (!crtc_state->hw.active || 34761564e6cSVille Syrjälä !crtc_state->has_drrs) 34861564e6cSVille Syrjälä goto out; 34961564e6cSVille Syrjälä 35061564e6cSVille Syrjälä commit = crtc_state->uapi.commit; 35161564e6cSVille Syrjälä if (commit) { 35261564e6cSVille Syrjälä ret = wait_for_completion_interruptible(&commit->hw_done); 35361564e6cSVille Syrjälä if (ret) 35461564e6cSVille Syrjälä goto out; 35561564e6cSVille Syrjälä } 35661564e6cSVille Syrjälä 35761564e6cSVille Syrjälä drm_dbg(&i915->drm, 35861564e6cSVille Syrjälä "Manually %sactivating DRRS\n", val ? "" : "de"); 35961564e6cSVille Syrjälä 36061564e6cSVille Syrjälä if (val) 36161564e6cSVille Syrjälä intel_drrs_activate(crtc_state); 36261564e6cSVille Syrjälä else 36361564e6cSVille Syrjälä intel_drrs_deactivate(crtc_state); 36461564e6cSVille Syrjälä 36561564e6cSVille Syrjälä out: 36661564e6cSVille Syrjälä drm_modeset_unlock(&crtc->base.mutex); 36761564e6cSVille Syrjälä 368adc831bfSVille Syrjälä return ret; 36961564e6cSVille Syrjälä } 37061564e6cSVille Syrjälä 37140a7463cSDeepak R Varma DEFINE_DEBUGFS_ATTRIBUTE(intel_drrs_debugfs_ctl_fops, 37261564e6cSVille Syrjälä NULL, intel_drrs_debugfs_ctl_set, "%llu\n"); 37361564e6cSVille Syrjälä 374adc831bfSVille Syrjälä void intel_drrs_crtc_debugfs_add(struct intel_crtc *crtc) 37561564e6cSVille Syrjälä { 376adc831bfSVille Syrjälä debugfs_create_file("i915_drrs_status", 0444, crtc->base.debugfs_entry, 377adc831bfSVille Syrjälä crtc, &intel_drrs_debugfs_status_fops); 37861564e6cSVille Syrjälä 37940a7463cSDeepak R Varma debugfs_create_file_unsafe("i915_drrs_ctl", 0644, crtc->base.debugfs_entry, 380adc831bfSVille Syrjälä crtc, &intel_drrs_debugfs_ctl_fops); 381adc831bfSVille Syrjälä } 38261564e6cSVille Syrjälä 383adc831bfSVille Syrjälä static int intel_drrs_debugfs_type_show(struct seq_file *m, void *unused) 384adc831bfSVille Syrjälä { 385adc831bfSVille Syrjälä struct intel_connector *connector = m->private; 386adc831bfSVille Syrjälä 387adc831bfSVille Syrjälä seq_printf(m, "DRRS type: %s\n", 388adc831bfSVille Syrjälä intel_drrs_type_str(intel_panel_drrs_type(connector))); 389adc831bfSVille Syrjälä 390adc831bfSVille Syrjälä return 0; 391adc831bfSVille Syrjälä } 392adc831bfSVille Syrjälä 393adc831bfSVille Syrjälä DEFINE_SHOW_ATTRIBUTE(intel_drrs_debugfs_type); 394adc831bfSVille Syrjälä 395adc831bfSVille Syrjälä void intel_drrs_connector_debugfs_add(struct intel_connector *connector) 396adc831bfSVille Syrjälä { 397adc831bfSVille Syrjälä if (intel_panel_drrs_type(connector) == DRRS_TYPE_NONE) 398adc831bfSVille Syrjälä return; 399adc831bfSVille Syrjälä 400adc831bfSVille Syrjälä debugfs_create_file("i915_drrs_type", 0444, connector->base.debugfs_entry, 401adc831bfSVille Syrjälä connector, &intel_drrs_debugfs_type_fops); 40261564e6cSVille Syrjälä } 403