1 | // SPDX-License-Identifier: MIT |
2 | /* |
3 | * Copyright © 2022 Intel Corporation |
4 | */ |
5 | |
6 | #include "hsw_ips.h" |
7 | #include "i915_drv.h" |
8 | #include "i915_reg.h" |
9 | #include "intel_color_regs.h" |
10 | #include "intel_de.h" |
11 | #include "intel_display_types.h" |
12 | #include "intel_pcode.h" |
13 | |
14 | static void hsw_ips_enable(const struct intel_crtc_state *crtc_state) |
15 | { |
16 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
17 | struct drm_i915_private *i915 = to_i915(dev: crtc->base.dev); |
18 | u32 val; |
19 | |
20 | if (!crtc_state->ips_enabled) |
21 | return; |
22 | |
23 | /* |
24 | * We can only enable IPS after we enable a plane and wait for a vblank |
25 | * This function is called from post_plane_update, which is run after |
26 | * a vblank wait. |
27 | */ |
28 | drm_WARN_ON(&i915->drm, |
29 | !(crtc_state->active_planes & ~BIT(PLANE_CURSOR))); |
30 | |
31 | val = IPS_ENABLE; |
32 | |
33 | if (i915->display.ips.false_color) |
34 | val |= IPS_FALSE_COLOR; |
35 | |
36 | if (IS_BROADWELL(i915)) { |
37 | drm_WARN_ON(&i915->drm, |
38 | snb_pcode_write(&i915->uncore, DISPLAY_IPS_CONTROL, |
39 | val | IPS_PCODE_CONTROL)); |
40 | /* |
41 | * Quoting Art Runyan: "its not safe to expect any particular |
42 | * value in IPS_CTL bit 31 after enabling IPS through the |
43 | * mailbox." Moreover, the mailbox may return a bogus state, |
44 | * so we need to just enable it and continue on. |
45 | */ |
46 | } else { |
47 | intel_de_write(i915, IPS_CTL, val); |
48 | /* |
49 | * The bit only becomes 1 in the next vblank, so this wait here |
50 | * is essentially intel_wait_for_vblank. If we don't have this |
51 | * and don't wait for vblanks until the end of crtc_enable, then |
52 | * the HW state readout code will complain that the expected |
53 | * IPS_CTL value is not the one we read. |
54 | */ |
55 | if (intel_de_wait_for_set(i915, IPS_CTL, IPS_ENABLE, timeout: 50)) |
56 | drm_err(&i915->drm, |
57 | "Timed out waiting for IPS enable\n" ); |
58 | } |
59 | } |
60 | |
61 | bool hsw_ips_disable(const struct intel_crtc_state *crtc_state) |
62 | { |
63 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
64 | struct drm_i915_private *i915 = to_i915(dev: crtc->base.dev); |
65 | bool need_vblank_wait = false; |
66 | |
67 | if (!crtc_state->ips_enabled) |
68 | return need_vblank_wait; |
69 | |
70 | if (IS_BROADWELL(i915)) { |
71 | drm_WARN_ON(&i915->drm, |
72 | snb_pcode_write(&i915->uncore, DISPLAY_IPS_CONTROL, 0)); |
73 | /* |
74 | * Wait for PCODE to finish disabling IPS. The BSpec specified |
75 | * 42ms timeout value leads to occasional timeouts so use 100ms |
76 | * instead. |
77 | */ |
78 | if (intel_de_wait_for_clear(i915, IPS_CTL, IPS_ENABLE, timeout: 100)) |
79 | drm_err(&i915->drm, |
80 | "Timed out waiting for IPS disable\n" ); |
81 | } else { |
82 | intel_de_write(i915, IPS_CTL, val: 0); |
83 | intel_de_posting_read(i915, IPS_CTL); |
84 | } |
85 | |
86 | /* We need to wait for a vblank before we can disable the plane. */ |
87 | need_vblank_wait = true; |
88 | |
89 | return need_vblank_wait; |
90 | } |
91 | |
92 | static bool hsw_ips_need_disable(struct intel_atomic_state *state, |
93 | struct intel_crtc *crtc) |
94 | { |
95 | struct drm_i915_private *i915 = to_i915(dev: state->base.dev); |
96 | const struct intel_crtc_state *old_crtc_state = |
97 | intel_atomic_get_old_crtc_state(state, crtc); |
98 | const struct intel_crtc_state *new_crtc_state = |
99 | intel_atomic_get_new_crtc_state(state, crtc); |
100 | |
101 | if (!old_crtc_state->ips_enabled) |
102 | return false; |
103 | |
104 | if (intel_crtc_needs_modeset(crtc_state: new_crtc_state)) |
105 | return true; |
106 | |
107 | /* |
108 | * Workaround : Do not read or write the pipe palette/gamma data while |
109 | * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled. |
110 | * |
111 | * Disable IPS before we program the LUT. |
112 | */ |
113 | if (IS_HASWELL(i915) && |
114 | intel_crtc_needs_color_update(crtc_state: new_crtc_state) && |
115 | new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) |
116 | return true; |
117 | |
118 | return !new_crtc_state->ips_enabled; |
119 | } |
120 | |
121 | bool hsw_ips_pre_update(struct intel_atomic_state *state, |
122 | struct intel_crtc *crtc) |
123 | { |
124 | const struct intel_crtc_state *old_crtc_state = |
125 | intel_atomic_get_old_crtc_state(state, crtc); |
126 | |
127 | if (!hsw_ips_need_disable(state, crtc)) |
128 | return false; |
129 | |
130 | return hsw_ips_disable(crtc_state: old_crtc_state); |
131 | } |
132 | |
133 | static bool hsw_ips_need_enable(struct intel_atomic_state *state, |
134 | struct intel_crtc *crtc) |
135 | { |
136 | struct drm_i915_private *i915 = to_i915(dev: state->base.dev); |
137 | const struct intel_crtc_state *old_crtc_state = |
138 | intel_atomic_get_old_crtc_state(state, crtc); |
139 | const struct intel_crtc_state *new_crtc_state = |
140 | intel_atomic_get_new_crtc_state(state, crtc); |
141 | |
142 | if (!new_crtc_state->ips_enabled) |
143 | return false; |
144 | |
145 | if (intel_crtc_needs_modeset(crtc_state: new_crtc_state)) |
146 | return true; |
147 | |
148 | /* |
149 | * Workaround : Do not read or write the pipe palette/gamma data while |
150 | * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled. |
151 | * |
152 | * Re-enable IPS after the LUT has been programmed. |
153 | */ |
154 | if (IS_HASWELL(i915) && |
155 | intel_crtc_needs_color_update(crtc_state: new_crtc_state) && |
156 | new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) |
157 | return true; |
158 | |
159 | /* |
160 | * We can't read out IPS on broadwell, assume the worst and |
161 | * forcibly enable IPS on the first fastset. |
162 | */ |
163 | if (intel_crtc_needs_fastset(crtc_state: new_crtc_state) && old_crtc_state->inherited) |
164 | return true; |
165 | |
166 | return !old_crtc_state->ips_enabled; |
167 | } |
168 | |
169 | void hsw_ips_post_update(struct intel_atomic_state *state, |
170 | struct intel_crtc *crtc) |
171 | { |
172 | const struct intel_crtc_state *new_crtc_state = |
173 | intel_atomic_get_new_crtc_state(state, crtc); |
174 | |
175 | if (!hsw_ips_need_enable(state, crtc)) |
176 | return; |
177 | |
178 | hsw_ips_enable(crtc_state: new_crtc_state); |
179 | } |
180 | |
181 | /* IPS only exists on ULT machines and is tied to pipe A. */ |
182 | bool hsw_crtc_supports_ips(struct intel_crtc *crtc) |
183 | { |
184 | return HAS_IPS(to_i915(crtc->base.dev)) && crtc->pipe == PIPE_A; |
185 | } |
186 | |
187 | bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state) |
188 | { |
189 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
190 | struct drm_i915_private *i915 = to_i915(dev: crtc->base.dev); |
191 | |
192 | /* IPS only exists on ULT machines and is tied to pipe A. */ |
193 | if (!hsw_crtc_supports_ips(crtc)) |
194 | return false; |
195 | |
196 | if (!i915->display.params.enable_ips) |
197 | return false; |
198 | |
199 | if (crtc_state->pipe_bpp > 24) |
200 | return false; |
201 | |
202 | /* |
203 | * We compare against max which means we must take |
204 | * the increased cdclk requirement into account when |
205 | * calculating the new cdclk. |
206 | * |
207 | * Should measure whether using a lower cdclk w/o IPS |
208 | */ |
209 | if (IS_BROADWELL(i915) && |
210 | crtc_state->pixel_rate > i915->display.cdclk.max_cdclk_freq * 95 / 100) |
211 | return false; |
212 | |
213 | return true; |
214 | } |
215 | |
216 | int hsw_ips_compute_config(struct intel_atomic_state *state, |
217 | struct intel_crtc *crtc) |
218 | { |
219 | struct drm_i915_private *i915 = to_i915(dev: state->base.dev); |
220 | struct intel_crtc_state *crtc_state = |
221 | intel_atomic_get_new_crtc_state(state, crtc); |
222 | |
223 | crtc_state->ips_enabled = false; |
224 | |
225 | if (!hsw_crtc_state_ips_capable(crtc_state)) |
226 | return 0; |
227 | |
228 | /* |
229 | * When IPS gets enabled, the pipe CRC changes. Since IPS gets |
230 | * enabled and disabled dynamically based on package C states, |
231 | * user space can't make reliable use of the CRCs, so let's just |
232 | * completely disable it. |
233 | */ |
234 | if (crtc_state->crc_enabled) |
235 | return 0; |
236 | |
237 | /* IPS should be fine as long as at least one plane is enabled. */ |
238 | if (!(crtc_state->active_planes & ~BIT(PLANE_CURSOR))) |
239 | return 0; |
240 | |
241 | if (IS_BROADWELL(i915)) { |
242 | const struct intel_cdclk_state *cdclk_state; |
243 | |
244 | cdclk_state = intel_atomic_get_cdclk_state(state); |
245 | if (IS_ERR(ptr: cdclk_state)) |
246 | return PTR_ERR(ptr: cdclk_state); |
247 | |
248 | /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ |
249 | if (crtc_state->pixel_rate > cdclk_state->logical.cdclk * 95 / 100) |
250 | return 0; |
251 | } |
252 | |
253 | crtc_state->ips_enabled = true; |
254 | |
255 | return 0; |
256 | } |
257 | |
258 | void hsw_ips_get_config(struct intel_crtc_state *crtc_state) |
259 | { |
260 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
261 | struct drm_i915_private *i915 = to_i915(dev: crtc->base.dev); |
262 | |
263 | if (!hsw_crtc_supports_ips(crtc)) |
264 | return; |
265 | |
266 | if (IS_HASWELL(i915)) { |
267 | crtc_state->ips_enabled = intel_de_read(i915, IPS_CTL) & IPS_ENABLE; |
268 | } else { |
269 | /* |
270 | * We cannot readout IPS state on broadwell, set to |
271 | * true so we can set it to a defined state on first |
272 | * commit. |
273 | */ |
274 | crtc_state->ips_enabled = true; |
275 | } |
276 | } |
277 | |
278 | static int hsw_ips_debugfs_false_color_get(void *data, u64 *val) |
279 | { |
280 | struct intel_crtc *crtc = data; |
281 | struct drm_i915_private *i915 = to_i915(dev: crtc->base.dev); |
282 | |
283 | *val = i915->display.ips.false_color; |
284 | |
285 | return 0; |
286 | } |
287 | |
288 | static int hsw_ips_debugfs_false_color_set(void *data, u64 val) |
289 | { |
290 | struct intel_crtc *crtc = data; |
291 | struct drm_i915_private *i915 = to_i915(dev: crtc->base.dev); |
292 | struct intel_crtc_state *crtc_state; |
293 | int ret; |
294 | |
295 | ret = drm_modeset_lock(lock: &crtc->base.mutex, NULL); |
296 | if (ret) |
297 | return ret; |
298 | |
299 | i915->display.ips.false_color = val; |
300 | |
301 | crtc_state = to_intel_crtc_state(crtc->base.state); |
302 | |
303 | if (!crtc_state->hw.active) |
304 | goto unlock; |
305 | |
306 | if (crtc_state->uapi.commit && |
307 | !try_wait_for_completion(x: &crtc_state->uapi.commit->hw_done)) |
308 | goto unlock; |
309 | |
310 | hsw_ips_enable(crtc_state); |
311 | |
312 | unlock: |
313 | drm_modeset_unlock(lock: &crtc->base.mutex); |
314 | |
315 | return ret; |
316 | } |
317 | |
318 | DEFINE_DEBUGFS_ATTRIBUTE(hsw_ips_debugfs_false_color_fops, |
319 | hsw_ips_debugfs_false_color_get, |
320 | hsw_ips_debugfs_false_color_set, |
321 | "%llu\n" ); |
322 | |
323 | static int hsw_ips_debugfs_status_show(struct seq_file *m, void *unused) |
324 | { |
325 | struct intel_crtc *crtc = m->private; |
326 | struct drm_i915_private *i915 = to_i915(dev: crtc->base.dev); |
327 | intel_wakeref_t wakeref; |
328 | |
329 | wakeref = intel_runtime_pm_get(rpm: &i915->runtime_pm); |
330 | |
331 | seq_printf(m, fmt: "Enabled by kernel parameter: %s\n" , |
332 | str_yes_no(v: i915->display.params.enable_ips)); |
333 | |
334 | if (DISPLAY_VER(i915) >= 8) { |
335 | seq_puts(m, s: "Currently: unknown\n" ); |
336 | } else { |
337 | if (intel_de_read(i915, IPS_CTL) & IPS_ENABLE) |
338 | seq_puts(m, s: "Currently: enabled\n" ); |
339 | else |
340 | seq_puts(m, s: "Currently: disabled\n" ); |
341 | } |
342 | |
343 | intel_runtime_pm_put(rpm: &i915->runtime_pm, wref: wakeref); |
344 | |
345 | return 0; |
346 | } |
347 | |
348 | DEFINE_SHOW_ATTRIBUTE(hsw_ips_debugfs_status); |
349 | |
350 | void hsw_ips_crtc_debugfs_add(struct intel_crtc *crtc) |
351 | { |
352 | if (!hsw_crtc_supports_ips(crtc)) |
353 | return; |
354 | |
355 | debugfs_create_file(name: "i915_ips_false_color" , mode: 0644, parent: crtc->base.debugfs_entry, |
356 | data: crtc, fops: &hsw_ips_debugfs_false_color_fops); |
357 | |
358 | debugfs_create_file(name: "i915_ips_status" , mode: 0444, parent: crtc->base.debugfs_entry, |
359 | data: crtc, fops: &hsw_ips_debugfs_status_fops); |
360 | } |
361 | |