1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright 2026 Intel Corporation 4 */ 5 6 #include <drm/intel/intel_gmd_misc_regs.h> 7 8 #include "intel_de.h" 9 #include "i9xx_plane_regs.h" 10 #include "intel_display.h" 11 #include "intel_display_clock_gating.h" 12 #include "intel_display_core.h" 13 #include "intel_display_regs.h" 14 15 static void intel_display_gen9_init_clock_gating(struct intel_display *display) 16 { 17 /* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,bxt,kbl,cfl */ 18 intel_de_rmw(display, CHICKEN_PAR1_1, 0, SKL_EDP_PSR_FIX_RDWRAP); 19 20 /* WaEnableChickenDCPR:skl,bxt,kbl,glk,cfl */ 21 intel_de_rmw(display, GEN8_CHICKEN_DCPR_1, 0, MASK_WAKEMEM); 22 23 /* 24 * WaFbcWakeMemOn:skl,bxt,kbl,glk,cfl 25 * Display WA #0859: skl,bxt,kbl,glk,cfl 26 */ 27 intel_de_rmw(display, DISP_ARB_CTL, 0, DISP_FBC_MEMORY_WAKE); 28 } 29 30 void intel_display_skl_init_clock_gating(struct intel_display *display) 31 { 32 /* 33 * WaCompressedResourceDisplayNewHashMode:skl,kbl 34 * Display WA #0390: skl,kbl 35 * 36 * Must match Sampler, Pixel Back End, and Media. See 37 * WaCompressedResourceSamplerPbeMediaNewHashMode. 38 */ 39 intel_de_rmw(display, CHICKEN_PAR1_1, 0, SKL_DE_COMPRESSED_HASH_MODE); 40 41 intel_display_gen9_init_clock_gating(display); 42 43 /* 44 * WaFbcTurnOffFbcWatermark:skl 45 * Display WA #0562: skl 46 */ 47 intel_de_rmw(display, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS); 48 } 49 50 void intel_display_kbl_init_clock_gating(struct intel_display *display) 51 { 52 /* 53 * WaCompressedResourceDisplayNewHashMode:skl,kbl 54 * Display WA #0390: skl,kbl 55 * 56 * Must match Sampler, Pixel Back End, and Media. See 57 * WaCompressedResourceSamplerPbeMediaNewHashMode. 58 */ 59 intel_de_rmw(display, CHICKEN_PAR1_1, 0, SKL_DE_COMPRESSED_HASH_MODE); 60 61 intel_display_gen9_init_clock_gating(display); 62 63 /* 64 * WaFbcTurnOffFbcWatermark:kbl 65 * Display WA #0562: kbl 66 */ 67 intel_de_rmw(display, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS); 68 } 69 70 void intel_display_cfl_init_clock_gating(struct intel_display *display) 71 { 72 /* 73 * WaCompressedResourceDisplayNewHashMode:skl,kbl (and cfl, cml) 74 * Display WA #0390: skl,kbl (and cfl, cml) 75 * 76 * Must match Sampler, Pixel Back End, and Media. See 77 * WaCompressedResourceSamplerPbeMediaNewHashMode. 78 * 79 * NOTE: this is the same workaround used for skl and kbl, 80 * because the original implementation was checking HAS_LLC(), 81 * which cfl/cml have, even though the comment for the 82 * workaround doesn't mention it. 83 * 84 */ 85 intel_de_rmw(display, CHICKEN_PAR1_1, 0, SKL_DE_COMPRESSED_HASH_MODE); 86 87 intel_display_gen9_init_clock_gating(display); 88 89 /* 90 * WaFbcTurnOffFbcWatermark:cfl 91 * Display WA #0562: cfl 92 */ 93 intel_de_rmw(display, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS); 94 } 95 96 void intel_display_bxt_init_clock_gating(struct intel_display *display) 97 { 98 intel_display_gen9_init_clock_gating(display); 99 100 /* 101 * Wa: Backlight PWM may stop in the asserted state, causing backlight 102 * to stay fully on. 103 */ 104 intel_de_write(display, GEN9_CLKGATE_DIS_0, 105 intel_de_read(display, GEN9_CLKGATE_DIS_0) | 106 PWM1_GATING_DIS | PWM2_GATING_DIS); 107 108 /* 109 * Lower the display internal timeout. 110 * This is needed to avoid any hard hangs when DSI port PLL 111 * is off and a MMIO access is attempted by any privilege 112 * application, using batch buffers or any other means. 113 */ 114 intel_de_write(display, RM_TIMEOUT, MMIO_TIMEOUT_US(950)); 115 116 /* 117 * WaFbcTurnOffFbcWatermark:bxt 118 * Display WA #0562: bxt 119 */ 120 intel_de_rmw(display, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS); 121 } 122 123 void intel_display_glk_init_clock_gating(struct intel_display *display) 124 { 125 intel_display_gen9_init_clock_gating(display); 126 127 /* 128 * WaDisablePWMClockGating:glk 129 * Backlight PWM may stop in the asserted state, causing backlight 130 * to stay fully on. 131 */ 132 intel_de_write(display, GEN9_CLKGATE_DIS_0, 133 intel_de_read(display, GEN9_CLKGATE_DIS_0) | 134 PWM1_GATING_DIS | PWM2_GATING_DIS); 135 } 136 137 void intel_display_bdw_clock_gating_disable_fbcq(struct intel_display *display) 138 { 139 /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ 140 intel_de_rmw(display, CHICKEN_PIPESL_1(PIPE_A), 0, HSW_FBCQ_DIS); 141 } 142 143 void intel_display_bdw_clock_gating_vblank_in_srd(struct intel_display *display) 144 { 145 enum pipe pipe; 146 147 /* WaPsrDPAMaskVBlankInSRD:hsw */ 148 intel_de_rmw(display, CHICKEN_PAR1_1, 0, HSW_MASK_VBL_TO_PIPE_IN_SRD); 149 150 for_each_pipe(display, pipe) { 151 /* WaPsrDPRSUnmaskVBlankInSRD:hsw,bdw */ 152 intel_de_rmw(display, CHICKEN_PIPESL_1(pipe), 0, 153 BDW_UNMASK_VBL_TO_REGS_IN_SRD); 154 } 155 } 156 157 void intel_display_bdw_clock_gating_kvm_notif(struct intel_display *display) 158 { 159 /* WaKVMNotificationOnConfigChange:bdw */ 160 intel_de_rmw(display, CHICKEN_PAR2_1, 0, 161 KVM_CONFIG_CHANGE_NOTIFICATION_SELECT); 162 } 163 164 void intel_display_hsw_init_clock_gating(struct intel_display *display) 165 { 166 enum pipe pipe; 167 168 /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ 169 intel_de_rmw(display, CHICKEN_PIPESL_1(PIPE_A), 0, HSW_FBCQ_DIS); 170 171 /* WaPsrDPAMaskVBlankInSRD:hsw */ 172 intel_de_rmw(display, CHICKEN_PAR1_1, 0, HSW_MASK_VBL_TO_PIPE_IN_SRD); 173 174 for_each_pipe(display, pipe) { 175 /* WaPsrDPRSUnmaskVBlankInSRD:hsw,bdw */ 176 intel_de_rmw(display, CHICKEN_PIPESL_1(pipe), 0, 177 HSW_UNMASK_VBL_TO_REGS_IN_SRD); 178 } 179 } 180 181 void intel_display_disable_trickle_feed(struct intel_display *display) 182 { 183 enum pipe pipe; 184 185 for_each_pipe(display, pipe) { 186 intel_de_rmw(display, DSPCNTR(display, pipe), 0, 187 DISP_TRICKLE_FEED_DISABLE); 188 189 intel_de_rmw(display, DSPSURF(display, pipe), 0, 0); 190 intel_de_posting_read(display, DSPSURF(display, pipe)); 191 } 192 } 193 194 void intel_display_ilk_init_clock_gating(struct intel_display *display) 195 { 196 u32 dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE; 197 198 /* 199 * Required for FBC 200 * WaFbcDisableDpfcClockGating:ilk 201 */ 202 dspclk_gate |= ILK_DPFCRUNIT_CLOCK_GATE_DISABLE | 203 ILK_DPFCUNIT_CLOCK_GATE_DISABLE | 204 ILK_DPFDUNIT_CLOCK_GATE_ENABLE; 205 206 intel_de_write(display, ILK_DISPLAY_CHICKEN2, 207 intel_de_read(display, ILK_DISPLAY_CHICKEN2) | 208 ILK_DPARB_GATE | ILK_VSDPFD_FULL); 209 dspclk_gate |= ILK_DPARBUNIT_CLOCK_GATE_ENABLE; 210 intel_de_write(display, DISP_ARB_CTL, 211 intel_de_read(display, DISP_ARB_CTL) | 212 DISP_FBC_WM_DIS); 213 214 if (display->platform.ironlake && display->platform.mobile) { 215 /* WaFbcAsynchFlipDisableFbcQueue:ilk */ 216 intel_de_rmw(display, ILK_DISPLAY_CHICKEN1, 0, ILK_FBCQ_DIS); 217 intel_de_rmw(display, ILK_DISPLAY_CHICKEN2, 0, ILK_DPARB_GATE); 218 } 219 220 intel_de_write(display, ILK_DSPCLK_GATE_D, dspclk_gate); 221 intel_de_rmw(display, ILK_DISPLAY_CHICKEN2, 0, ILK_ELPIN_409_SELECT); 222 223 intel_display_disable_trickle_feed(display); 224 } 225 226 void intel_display_gen6_init_clock_gating(struct intel_display *display) 227 { 228 u32 dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE; 229 230 intel_de_write(display, ILK_DSPCLK_GATE_D, dspclk_gate); 231 intel_de_rmw(display, ILK_DISPLAY_CHICKEN2, 0, ILK_ELPIN_409_SELECT); 232 233 intel_de_write(display, ILK_DISPLAY_CHICKEN1, 234 intel_de_read(display, ILK_DISPLAY_CHICKEN1) | 235 ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS); 236 intel_de_write(display, ILK_DISPLAY_CHICKEN2, 237 intel_de_read(display, ILK_DISPLAY_CHICKEN2) | 238 ILK_DPARB_GATE | ILK_VSDPFD_FULL); 239 intel_de_write(display, ILK_DSPCLK_GATE_D, 240 intel_de_read(display, ILK_DSPCLK_GATE_D) | 241 ILK_DPARBUNIT_CLOCK_GATE_ENABLE | 242 ILK_DPFDUNIT_CLOCK_GATE_ENABLE); 243 244 intel_display_disable_trickle_feed(display); 245 } 246 247 void intel_display_ivb_init_clock_gating(struct intel_display *display) 248 { 249 intel_de_write(display, ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); 250 intel_de_rmw(display, ILK_DISPLAY_CHICKEN1, 0, ILK_FBCQ_DIS); 251 } 252 253 void intel_display_g4x_init_clock_gating(struct intel_display *display) 254 { 255 u32 dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE | 256 OVRUNIT_CLOCK_GATE_DISABLE | 257 OVCUNIT_CLOCK_GATE_DISABLE; 258 259 if (display->platform.gm45) 260 dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE; 261 262 intel_de_write(display, DSPCLK_GATE_D, dspclk_gate); 263 264 intel_display_disable_trickle_feed(display); 265 } 266 267 void intel_display_i965gm_init_clock_gating(struct intel_display *display) 268 { 269 intel_de_write(display, DSPCLK_GATE_D, 0); 270 } 271