1 | // SPDX-License-Identifier: MIT |
2 | /* |
3 | * Copyright © 2020 Intel Corporation |
4 | */ |
5 | |
6 | #include "i915_reg.h" |
7 | #include "intel_de.h" |
8 | #include "intel_display_types.h" |
9 | #include "intel_fb.h" |
10 | #include "skl_scaler.h" |
11 | #include "skl_universal_plane.h" |
12 | |
13 | /* |
14 | * The hardware phase 0.0 refers to the center of the pixel. |
15 | * We want to start from the top/left edge which is phase |
16 | * -0.5. That matches how the hardware calculates the scaling |
17 | * factors (from top-left of the first pixel to bottom-right |
18 | * of the last pixel, as opposed to the pixel centers). |
19 | * |
20 | * For 4:2:0 subsampled chroma planes we obviously have to |
21 | * adjust that so that the chroma sample position lands in |
22 | * the right spot. |
23 | * |
24 | * Note that for packed YCbCr 4:2:2 formats there is no way to |
25 | * control chroma siting. The hardware simply replicates the |
26 | * chroma samples for both of the luma samples, and thus we don't |
27 | * actually get the expected MPEG2 chroma siting convention :( |
28 | * The same behaviour is observed on pre-SKL platforms as well. |
29 | * |
30 | * Theory behind the formula (note that we ignore sub-pixel |
31 | * source coordinates): |
32 | * s = source sample position |
33 | * d = destination sample position |
34 | * |
35 | * Downscaling 4:1: |
36 | * -0.5 |
37 | * | 0.0 |
38 | * | | 1.5 (initial phase) |
39 | * | | | |
40 | * v v v |
41 | * | s | s | s | s | |
42 | * | d | |
43 | * |
44 | * Upscaling 1:4: |
45 | * -0.5 |
46 | * | -0.375 (initial phase) |
47 | * | | 0.0 |
48 | * | | | |
49 | * v v v |
50 | * | s | |
51 | * | d | d | d | d | |
52 | */ |
53 | static u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited) |
54 | { |
55 | int phase = -0x8000; |
56 | u16 trip = 0; |
57 | |
58 | if (chroma_cosited) |
59 | phase += (sub - 1) * 0x8000 / sub; |
60 | |
61 | phase += scale / (2 * sub); |
62 | |
63 | /* |
64 | * Hardware initial phase limited to [-0.5:1.5]. |
65 | * Since the max hardware scale factor is 3.0, we |
66 | * should never actually excdeed 1.0 here. |
67 | */ |
68 | WARN_ON(phase < -0x8000 || phase > 0x18000); |
69 | |
70 | if (phase < 0) |
71 | phase = 0x10000 + phase; |
72 | else |
73 | trip = PS_PHASE_TRIP; |
74 | |
75 | return ((phase >> 2) & PS_PHASE_MASK) | trip; |
76 | } |
77 | |
78 | #define SKL_MIN_SRC_W 8 |
79 | #define SKL_MAX_SRC_W 4096 |
80 | #define SKL_MIN_SRC_H 8 |
81 | #define SKL_MAX_SRC_H 4096 |
82 | #define SKL_MIN_DST_W 8 |
83 | #define SKL_MAX_DST_W 4096 |
84 | #define SKL_MIN_DST_H 8 |
85 | #define SKL_MAX_DST_H 4096 |
86 | #define ICL_MAX_SRC_W 5120 |
87 | #define ICL_MAX_SRC_H 4096 |
88 | #define ICL_MAX_DST_W 5120 |
89 | #define ICL_MAX_DST_H 4096 |
90 | #define TGL_MAX_SRC_W 5120 |
91 | #define TGL_MAX_SRC_H 8192 |
92 | #define TGL_MAX_DST_W 8192 |
93 | #define TGL_MAX_DST_H 8192 |
94 | #define MTL_MAX_SRC_W 4096 |
95 | #define MTL_MAX_SRC_H 8192 |
96 | #define MTL_MAX_DST_W 8192 |
97 | #define MTL_MAX_DST_H 8192 |
98 | #define SKL_MIN_YUV_420_SRC_W 16 |
99 | #define SKL_MIN_YUV_420_SRC_H 16 |
100 | |
101 | static int |
102 | skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, |
103 | unsigned int scaler_user, int *scaler_id, |
104 | int src_w, int src_h, int dst_w, int dst_h, |
105 | const struct drm_format_info *format, |
106 | u64 modifier, bool need_scaler) |
107 | { |
108 | struct intel_crtc_scaler_state *scaler_state = |
109 | &crtc_state->scaler_state; |
110 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
111 | struct drm_i915_private *dev_priv = to_i915(dev: crtc->base.dev); |
112 | const struct drm_display_mode *adjusted_mode = |
113 | &crtc_state->hw.adjusted_mode; |
114 | int pipe_src_w = drm_rect_width(r: &crtc_state->pipe_src); |
115 | int pipe_src_h = drm_rect_height(r: &crtc_state->pipe_src); |
116 | int min_src_w, min_src_h, min_dst_w, min_dst_h; |
117 | int max_src_w, max_src_h, max_dst_w, max_dst_h; |
118 | |
119 | /* |
120 | * Src coordinates are already rotated by 270 degrees for |
121 | * the 90/270 degree plane rotation cases (to match the |
122 | * GTT mapping), hence no need to account for rotation here. |
123 | */ |
124 | if (src_w != dst_w || src_h != dst_h) |
125 | need_scaler = true; |
126 | |
127 | /* |
128 | * Scaling/fitting not supported in IF-ID mode in GEN9+ |
129 | * TODO: Interlace fetch mode doesn't support YUV420 planar formats. |
130 | * Once NV12 is enabled, handle it here while allocating scaler |
131 | * for NV12. |
132 | */ |
133 | if (DISPLAY_VER(dev_priv) >= 9 && crtc_state->hw.enable && |
134 | need_scaler && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { |
135 | drm_dbg_kms(&dev_priv->drm, |
136 | "Pipe/Plane scaling not supported with IF-ID mode\n" ); |
137 | return -EINVAL; |
138 | } |
139 | |
140 | /* |
141 | * if plane is being disabled or scaler is no more required or force detach |
142 | * - free scaler binded to this plane/crtc |
143 | * - in order to do this, update crtc->scaler_usage |
144 | * |
145 | * Here scaler state in crtc_state is set free so that |
146 | * scaler can be assigned to other user. Actual register |
147 | * update to free the scaler is done in plane/panel-fit programming. |
148 | * For this purpose crtc/plane_state->scaler_id isn't reset here. |
149 | */ |
150 | if (force_detach || !need_scaler) { |
151 | if (*scaler_id >= 0) { |
152 | scaler_state->scaler_users &= ~(1 << scaler_user); |
153 | scaler_state->scalers[*scaler_id].in_use = 0; |
154 | |
155 | drm_dbg_kms(&dev_priv->drm, |
156 | "scaler_user index %u.%u: " |
157 | "Staged freeing scaler id %d scaler_users = 0x%x\n" , |
158 | crtc->pipe, scaler_user, *scaler_id, |
159 | scaler_state->scaler_users); |
160 | *scaler_id = -1; |
161 | } |
162 | return 0; |
163 | } |
164 | |
165 | if (format && intel_format_info_is_yuv_semiplanar(info: format, modifier) && |
166 | (src_h < SKL_MIN_YUV_420_SRC_H || src_w < SKL_MIN_YUV_420_SRC_W)) { |
167 | drm_dbg_kms(&dev_priv->drm, |
168 | "Planar YUV: src dimensions not met\n" ); |
169 | return -EINVAL; |
170 | } |
171 | |
172 | min_src_w = SKL_MIN_SRC_W; |
173 | min_src_h = SKL_MIN_SRC_H; |
174 | min_dst_w = SKL_MIN_DST_W; |
175 | min_dst_h = SKL_MIN_DST_H; |
176 | |
177 | if (DISPLAY_VER(dev_priv) < 11) { |
178 | max_src_w = SKL_MAX_SRC_W; |
179 | max_src_h = SKL_MAX_SRC_H; |
180 | max_dst_w = SKL_MAX_DST_W; |
181 | max_dst_h = SKL_MAX_DST_H; |
182 | } else if (DISPLAY_VER(dev_priv) < 12) { |
183 | max_src_w = ICL_MAX_SRC_W; |
184 | max_src_h = ICL_MAX_SRC_H; |
185 | max_dst_w = ICL_MAX_DST_W; |
186 | max_dst_h = ICL_MAX_DST_H; |
187 | } else if (DISPLAY_VER(dev_priv) < 14) { |
188 | max_src_w = TGL_MAX_SRC_W; |
189 | max_src_h = TGL_MAX_SRC_H; |
190 | max_dst_w = TGL_MAX_DST_W; |
191 | max_dst_h = TGL_MAX_DST_H; |
192 | } else { |
193 | max_src_w = MTL_MAX_SRC_W; |
194 | max_src_h = MTL_MAX_SRC_H; |
195 | max_dst_w = MTL_MAX_DST_W; |
196 | max_dst_h = MTL_MAX_DST_H; |
197 | } |
198 | |
199 | /* range checks */ |
200 | if (src_w < min_src_w || src_h < min_src_h || |
201 | dst_w < min_dst_w || dst_h < min_dst_h || |
202 | src_w > max_src_w || src_h > max_src_h || |
203 | dst_w > max_dst_w || dst_h > max_dst_h) { |
204 | drm_dbg_kms(&dev_priv->drm, |
205 | "scaler_user index %u.%u: src %ux%u dst %ux%u " |
206 | "size is out of scaler range\n" , |
207 | crtc->pipe, scaler_user, src_w, src_h, |
208 | dst_w, dst_h); |
209 | return -EINVAL; |
210 | } |
211 | |
212 | /* |
213 | * The pipe scaler does not use all the bits of PIPESRC, at least |
214 | * on the earlier platforms. So even when we're scaling a plane |
215 | * the *pipe* source size must not be too large. For simplicity |
216 | * we assume the limits match the scaler source size limits. Might |
217 | * not be 100% accurate on all platforms, but good enough for now. |
218 | */ |
219 | if (pipe_src_w > max_src_w || pipe_src_h > max_src_h) { |
220 | drm_dbg_kms(&dev_priv->drm, |
221 | "scaler_user index %u.%u: pipe src size %ux%u " |
222 | "is out of scaler range\n" , |
223 | crtc->pipe, scaler_user, pipe_src_w, pipe_src_h); |
224 | return -EINVAL; |
225 | } |
226 | |
227 | /* mark this plane as a scaler user in crtc_state */ |
228 | scaler_state->scaler_users |= (1 << scaler_user); |
229 | drm_dbg_kms(&dev_priv->drm, "scaler_user index %u.%u: " |
230 | "staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n" , |
231 | crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h, |
232 | scaler_state->scaler_users); |
233 | |
234 | return 0; |
235 | } |
236 | |
237 | int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state) |
238 | { |
239 | const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; |
240 | int width, height; |
241 | |
242 | if (crtc_state->pch_pfit.enabled) { |
243 | width = drm_rect_width(r: &crtc_state->pch_pfit.dst); |
244 | height = drm_rect_height(r: &crtc_state->pch_pfit.dst); |
245 | } else { |
246 | width = pipe_mode->crtc_hdisplay; |
247 | height = pipe_mode->crtc_vdisplay; |
248 | } |
249 | return skl_update_scaler(crtc_state, force_detach: !crtc_state->hw.active, |
250 | SKL_CRTC_INDEX, |
251 | scaler_id: &crtc_state->scaler_state.scaler_id, |
252 | src_w: drm_rect_width(r: &crtc_state->pipe_src), |
253 | src_h: drm_rect_height(r: &crtc_state->pipe_src), |
254 | dst_w: width, dst_h: height, NULL, modifier: 0, |
255 | need_scaler: crtc_state->pch_pfit.enabled); |
256 | } |
257 | |
258 | /** |
259 | * skl_update_scaler_plane - Stages update to scaler state for a given plane. |
260 | * @crtc_state: crtc's scaler state |
261 | * @plane_state: atomic plane state to update |
262 | * |
263 | * Return |
264 | * 0 - scaler_usage updated successfully |
265 | * error - requested scaling cannot be supported or other error condition |
266 | */ |
267 | int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, |
268 | struct intel_plane_state *plane_state) |
269 | { |
270 | struct intel_plane *intel_plane = |
271 | to_intel_plane(plane_state->uapi.plane); |
272 | struct drm_i915_private *dev_priv = to_i915(dev: intel_plane->base.dev); |
273 | struct drm_framebuffer *fb = plane_state->hw.fb; |
274 | int ret; |
275 | bool force_detach = !fb || !plane_state->uapi.visible; |
276 | bool need_scaler = false; |
277 | |
278 | /* Pre-gen11 and SDR planes always need a scaler for planar formats. */ |
279 | if (!icl_is_hdr_plane(dev_priv, plane_id: intel_plane->id) && |
280 | fb && intel_format_info_is_yuv_semiplanar(info: fb->format, modifier: fb->modifier)) |
281 | need_scaler = true; |
282 | |
283 | ret = skl_update_scaler(crtc_state, force_detach, |
284 | scaler_user: drm_plane_index(plane: &intel_plane->base), |
285 | scaler_id: &plane_state->scaler_id, |
286 | src_w: drm_rect_width(r: &plane_state->uapi.src) >> 16, |
287 | src_h: drm_rect_height(r: &plane_state->uapi.src) >> 16, |
288 | dst_w: drm_rect_width(r: &plane_state->uapi.dst), |
289 | dst_h: drm_rect_height(r: &plane_state->uapi.dst), |
290 | format: fb ? fb->format : NULL, |
291 | modifier: fb ? fb->modifier : 0, |
292 | need_scaler); |
293 | |
294 | if (ret || plane_state->scaler_id < 0) |
295 | return ret; |
296 | |
297 | /* check colorkey */ |
298 | if (plane_state->ckey.flags) { |
299 | drm_dbg_kms(&dev_priv->drm, |
300 | "[PLANE:%d:%s] scaling with color key not allowed" , |
301 | intel_plane->base.base.id, |
302 | intel_plane->base.name); |
303 | return -EINVAL; |
304 | } |
305 | |
306 | /* Check src format */ |
307 | switch (fb->format->format) { |
308 | case DRM_FORMAT_RGB565: |
309 | case DRM_FORMAT_XBGR8888: |
310 | case DRM_FORMAT_XRGB8888: |
311 | case DRM_FORMAT_ABGR8888: |
312 | case DRM_FORMAT_ARGB8888: |
313 | case DRM_FORMAT_XRGB2101010: |
314 | case DRM_FORMAT_XBGR2101010: |
315 | case DRM_FORMAT_ARGB2101010: |
316 | case DRM_FORMAT_ABGR2101010: |
317 | case DRM_FORMAT_YUYV: |
318 | case DRM_FORMAT_YVYU: |
319 | case DRM_FORMAT_UYVY: |
320 | case DRM_FORMAT_VYUY: |
321 | case DRM_FORMAT_NV12: |
322 | case DRM_FORMAT_XYUV8888: |
323 | case DRM_FORMAT_P010: |
324 | case DRM_FORMAT_P012: |
325 | case DRM_FORMAT_P016: |
326 | case DRM_FORMAT_Y210: |
327 | case DRM_FORMAT_Y212: |
328 | case DRM_FORMAT_Y216: |
329 | case DRM_FORMAT_XVYU2101010: |
330 | case DRM_FORMAT_XVYU12_16161616: |
331 | case DRM_FORMAT_XVYU16161616: |
332 | break; |
333 | case DRM_FORMAT_XBGR16161616F: |
334 | case DRM_FORMAT_ABGR16161616F: |
335 | case DRM_FORMAT_XRGB16161616F: |
336 | case DRM_FORMAT_ARGB16161616F: |
337 | if (DISPLAY_VER(dev_priv) >= 11) |
338 | break; |
339 | fallthrough; |
340 | default: |
341 | drm_dbg_kms(&dev_priv->drm, |
342 | "[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n" , |
343 | intel_plane->base.base.id, intel_plane->base.name, |
344 | fb->base.id, fb->format->format); |
345 | return -EINVAL; |
346 | } |
347 | |
348 | return 0; |
349 | } |
350 | |
351 | static int intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_state, |
352 | int num_scalers_need, struct intel_crtc *intel_crtc, |
353 | const char *name, int idx, |
354 | struct intel_plane_state *plane_state, |
355 | int *scaler_id) |
356 | { |
357 | struct drm_i915_private *dev_priv = to_i915(dev: intel_crtc->base.dev); |
358 | int j; |
359 | u32 mode; |
360 | |
361 | if (*scaler_id < 0) { |
362 | /* find a free scaler */ |
363 | for (j = 0; j < intel_crtc->num_scalers; j++) { |
364 | if (scaler_state->scalers[j].in_use) |
365 | continue; |
366 | |
367 | *scaler_id = j; |
368 | scaler_state->scalers[*scaler_id].in_use = 1; |
369 | break; |
370 | } |
371 | } |
372 | |
373 | if (drm_WARN(&dev_priv->drm, *scaler_id < 0, |
374 | "Cannot find scaler for %s:%d\n" , name, idx)) |
375 | return -EINVAL; |
376 | |
377 | /* set scaler mode */ |
378 | if (plane_state && plane_state->hw.fb && |
379 | plane_state->hw.fb->format->is_yuv && |
380 | plane_state->hw.fb->format->num_planes > 1) { |
381 | struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); |
382 | |
383 | if (DISPLAY_VER(dev_priv) == 9) { |
384 | mode = SKL_PS_SCALER_MODE_NV12; |
385 | } else if (icl_is_hdr_plane(dev_priv, plane_id: plane->id)) { |
386 | /* |
387 | * On gen11+'s HDR planes we only use the scaler for |
388 | * scaling. They have a dedicated chroma upsampler, so |
389 | * we don't need the scaler to upsample the UV plane. |
390 | */ |
391 | mode = PS_SCALER_MODE_NORMAL; |
392 | } else { |
393 | struct intel_plane *linked = |
394 | plane_state->planar_linked_plane; |
395 | |
396 | mode = PS_SCALER_MODE_PLANAR; |
397 | |
398 | if (linked) |
399 | mode |= PS_BINDING_Y_PLANE(linked->id); |
400 | } |
401 | } else if (DISPLAY_VER(dev_priv) >= 10) { |
402 | mode = PS_SCALER_MODE_NORMAL; |
403 | } else if (num_scalers_need == 1 && intel_crtc->num_scalers > 1) { |
404 | /* |
405 | * when only 1 scaler is in use on a pipe with 2 scalers |
406 | * scaler 0 operates in high quality (HQ) mode. |
407 | * In this case use scaler 0 to take advantage of HQ mode |
408 | */ |
409 | scaler_state->scalers[*scaler_id].in_use = 0; |
410 | *scaler_id = 0; |
411 | scaler_state->scalers[0].in_use = 1; |
412 | mode = SKL_PS_SCALER_MODE_HQ; |
413 | } else { |
414 | mode = SKL_PS_SCALER_MODE_DYN; |
415 | } |
416 | |
417 | /* |
418 | * FIXME: we should also check the scaler factors for pfit, so |
419 | * this shouldn't be tied directly to planes. |
420 | */ |
421 | if (plane_state && plane_state->hw.fb) { |
422 | const struct drm_framebuffer *fb = plane_state->hw.fb; |
423 | const struct drm_rect *src = &plane_state->uapi.src; |
424 | const struct drm_rect *dst = &plane_state->uapi.dst; |
425 | int hscale, vscale, max_vscale, max_hscale; |
426 | |
427 | /* |
428 | * FIXME: When two scalers are needed, but only one of |
429 | * them needs to downscale, we should make sure that |
430 | * the one that needs downscaling support is assigned |
431 | * as the first scaler, so we don't reject downscaling |
432 | * unnecessarily. |
433 | */ |
434 | |
435 | if (DISPLAY_VER(dev_priv) >= 14) { |
436 | /* |
437 | * On versions 14 and up, only the first |
438 | * scaler supports a vertical scaling factor |
439 | * of more than 1.0, while a horizontal |
440 | * scaling factor of 3.0 is supported. |
441 | */ |
442 | max_hscale = 0x30000 - 1; |
443 | if (*scaler_id == 0) |
444 | max_vscale = 0x30000 - 1; |
445 | else |
446 | max_vscale = 0x10000; |
447 | |
448 | } else if (DISPLAY_VER(dev_priv) >= 10 || |
449 | !intel_format_info_is_yuv_semiplanar(info: fb->format, modifier: fb->modifier)) { |
450 | max_hscale = 0x30000 - 1; |
451 | max_vscale = 0x30000 - 1; |
452 | } else { |
453 | max_hscale = 0x20000 - 1; |
454 | max_vscale = 0x20000 - 1; |
455 | } |
456 | |
457 | /* |
458 | * FIXME: We should change the if-else block above to |
459 | * support HQ vs dynamic scaler properly. |
460 | */ |
461 | |
462 | /* Check if required scaling is within limits */ |
463 | hscale = drm_rect_calc_hscale(src, dst, min_hscale: 1, max_hscale); |
464 | vscale = drm_rect_calc_vscale(src, dst, min_vscale: 1, max_vscale); |
465 | |
466 | if (hscale < 0 || vscale < 0) { |
467 | drm_dbg_kms(&dev_priv->drm, |
468 | "Scaler %d doesn't support required plane scaling\n" , |
469 | *scaler_id); |
470 | drm_rect_debug_print(prefix: "src: " , r: src, fixed_point: true); |
471 | drm_rect_debug_print(prefix: "dst: " , r: dst, fixed_point: false); |
472 | |
473 | return -EINVAL; |
474 | } |
475 | } |
476 | |
477 | drm_dbg_kms(&dev_priv->drm, "Attached scaler id %u.%u to %s:%d\n" , |
478 | intel_crtc->pipe, *scaler_id, name, idx); |
479 | scaler_state->scalers[*scaler_id].mode = mode; |
480 | |
481 | return 0; |
482 | } |
483 | |
484 | /** |
485 | * intel_atomic_setup_scalers() - setup scalers for crtc per staged requests |
486 | * @dev_priv: i915 device |
487 | * @intel_crtc: intel crtc |
488 | * @crtc_state: incoming crtc_state to validate and setup scalers |
489 | * |
490 | * This function sets up scalers based on staged scaling requests for |
491 | * a @crtc and its planes. It is called from crtc level check path. If request |
492 | * is a supportable request, it attaches scalers to requested planes and crtc. |
493 | * |
494 | * This function takes into account the current scaler(s) in use by any planes |
495 | * not being part of this atomic state |
496 | * |
497 | * Returns: |
498 | * 0 - scalers were setup successfully |
499 | * error code - otherwise |
500 | */ |
501 | int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, |
502 | struct intel_crtc *intel_crtc, |
503 | struct intel_crtc_state *crtc_state) |
504 | { |
505 | struct drm_plane *plane = NULL; |
506 | struct intel_plane *intel_plane; |
507 | struct intel_crtc_scaler_state *scaler_state = |
508 | &crtc_state->scaler_state; |
509 | struct drm_atomic_state *drm_state = crtc_state->uapi.state; |
510 | struct intel_atomic_state *intel_state = to_intel_atomic_state(drm_state); |
511 | int num_scalers_need; |
512 | int i; |
513 | |
514 | num_scalers_need = hweight32(scaler_state->scaler_users); |
515 | |
516 | /* |
517 | * High level flow: |
518 | * - staged scaler requests are already in scaler_state->scaler_users |
519 | * - check whether staged scaling requests can be supported |
520 | * - add planes using scalers that aren't in current transaction |
521 | * - assign scalers to requested users |
522 | * - as part of plane commit, scalers will be committed |
523 | * (i.e., either attached or detached) to respective planes in hw |
524 | * - as part of crtc_commit, scaler will be either attached or detached |
525 | * to crtc in hw |
526 | */ |
527 | |
528 | /* fail if required scalers > available scalers */ |
529 | if (num_scalers_need > intel_crtc->num_scalers) { |
530 | drm_dbg_kms(&dev_priv->drm, |
531 | "Too many scaling requests %d > %d\n" , |
532 | num_scalers_need, intel_crtc->num_scalers); |
533 | return -EINVAL; |
534 | } |
535 | |
536 | /* walkthrough scaler_users bits and start assigning scalers */ |
537 | for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) { |
538 | struct intel_plane_state *plane_state = NULL; |
539 | int *scaler_id; |
540 | const char *name; |
541 | int idx, ret; |
542 | |
543 | /* skip if scaler not required */ |
544 | if (!(scaler_state->scaler_users & (1 << i))) |
545 | continue; |
546 | |
547 | if (i == SKL_CRTC_INDEX) { |
548 | name = "CRTC" ; |
549 | idx = intel_crtc->base.base.id; |
550 | |
551 | /* panel fitter case: assign as a crtc scaler */ |
552 | scaler_id = &scaler_state->scaler_id; |
553 | } else { |
554 | name = "PLANE" ; |
555 | |
556 | /* plane scaler case: assign as a plane scaler */ |
557 | /* find the plane that set the bit as scaler_user */ |
558 | plane = drm_state->planes[i].ptr; |
559 | |
560 | /* |
561 | * to enable/disable hq mode, add planes that are using scaler |
562 | * into this transaction |
563 | */ |
564 | if (!plane) { |
565 | struct drm_plane_state *state; |
566 | |
567 | /* |
568 | * GLK+ scalers don't have a HQ mode so it |
569 | * isn't necessary to change between HQ and dyn mode |
570 | * on those platforms. |
571 | */ |
572 | if (DISPLAY_VER(dev_priv) >= 10) |
573 | continue; |
574 | |
575 | plane = drm_plane_from_index(dev: &dev_priv->drm, idx: i); |
576 | state = drm_atomic_get_plane_state(state: drm_state, plane); |
577 | if (IS_ERR(ptr: state)) { |
578 | drm_dbg_kms(&dev_priv->drm, |
579 | "Failed to add [PLANE:%d] to drm_state\n" , |
580 | plane->base.id); |
581 | return PTR_ERR(ptr: state); |
582 | } |
583 | } |
584 | |
585 | intel_plane = to_intel_plane(plane); |
586 | idx = plane->base.id; |
587 | |
588 | /* plane on different crtc cannot be a scaler user of this crtc */ |
589 | if (drm_WARN_ON(&dev_priv->drm, |
590 | intel_plane->pipe != intel_crtc->pipe)) |
591 | continue; |
592 | |
593 | plane_state = intel_atomic_get_new_plane_state(state: intel_state, |
594 | plane: intel_plane); |
595 | scaler_id = &plane_state->scaler_id; |
596 | } |
597 | |
598 | ret = intel_atomic_setup_scaler(scaler_state, num_scalers_need, |
599 | intel_crtc, name, idx, |
600 | plane_state, scaler_id); |
601 | if (ret < 0) |
602 | return ret; |
603 | } |
604 | |
605 | return 0; |
606 | } |
607 | |
608 | static int glk_coef_tap(int i) |
609 | { |
610 | return i % 7; |
611 | } |
612 | |
613 | static u16 glk_nearest_filter_coef(int t) |
614 | { |
615 | return t == 3 ? 0x0800 : 0x3000; |
616 | } |
617 | |
618 | /* |
619 | * Theory behind setting nearest-neighbor integer scaling: |
620 | * |
621 | * 17 phase of 7 taps requires 119 coefficients in 60 dwords per set. |
622 | * The letter represents the filter tap (D is the center tap) and the number |
623 | * represents the coefficient set for a phase (0-16). |
624 | * |
625 | * +------------+------------------------+------------------------+ |
626 | * |Index value | Data value coeffient 1 | Data value coeffient 2 | |
627 | * +------------+------------------------+------------------------+ |
628 | * | 00h | B0 | A0 | |
629 | * +------------+------------------------+------------------------+ |
630 | * | 01h | D0 | C0 | |
631 | * +------------+------------------------+------------------------+ |
632 | * | 02h | F0 | E0 | |
633 | * +------------+------------------------+------------------------+ |
634 | * | 03h | A1 | G0 | |
635 | * +------------+------------------------+------------------------+ |
636 | * | 04h | C1 | B1 | |
637 | * +------------+------------------------+------------------------+ |
638 | * | ... | ... | ... | |
639 | * +------------+------------------------+------------------------+ |
640 | * | 38h | B16 | A16 | |
641 | * +------------+------------------------+------------------------+ |
642 | * | 39h | D16 | C16 | |
643 | * +------------+------------------------+------------------------+ |
644 | * | 3Ah | F16 | C16 | |
645 | * +------------+------------------------+------------------------+ |
646 | * | 3Bh | Reserved | G16 | |
647 | * +------------+------------------------+------------------------+ |
648 | * |
649 | * To enable nearest-neighbor scaling: program scaler coefficents with |
650 | * the center tap (Dxx) values set to 1 and all other values set to 0 as per |
651 | * SCALER_COEFFICIENT_FORMAT |
652 | * |
653 | */ |
654 | |
655 | static void glk_program_nearest_filter_coefs(struct drm_i915_private *dev_priv, |
656 | enum pipe pipe, int id, int set) |
657 | { |
658 | int i; |
659 | |
660 | intel_de_write_fw(i915: dev_priv, GLK_PS_COEF_INDEX_SET(pipe, id, set), |
661 | PS_COEF_INDEX_AUTO_INC); |
662 | |
663 | for (i = 0; i < 17 * 7; i += 2) { |
664 | u32 tmp; |
665 | int t; |
666 | |
667 | t = glk_coef_tap(i); |
668 | tmp = glk_nearest_filter_coef(t); |
669 | |
670 | t = glk_coef_tap(i: i + 1); |
671 | tmp |= glk_nearest_filter_coef(t) << 16; |
672 | |
673 | intel_de_write_fw(i915: dev_priv, GLK_PS_COEF_DATA_SET(pipe, id, set), |
674 | val: tmp); |
675 | } |
676 | |
677 | intel_de_write_fw(i915: dev_priv, GLK_PS_COEF_INDEX_SET(pipe, id, set), val: 0); |
678 | } |
679 | |
680 | static u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set) |
681 | { |
682 | if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) { |
683 | return (PS_FILTER_PROGRAMMED | |
684 | PS_Y_VERT_FILTER_SELECT(set) | |
685 | PS_Y_HORZ_FILTER_SELECT(set) | |
686 | PS_UV_VERT_FILTER_SELECT(set) | |
687 | PS_UV_HORZ_FILTER_SELECT(set)); |
688 | } |
689 | |
690 | return PS_FILTER_MEDIUM; |
691 | } |
692 | |
693 | static void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe, |
694 | int id, int set, enum drm_scaling_filter filter) |
695 | { |
696 | switch (filter) { |
697 | case DRM_SCALING_FILTER_DEFAULT: |
698 | break; |
699 | case DRM_SCALING_FILTER_NEAREST_NEIGHBOR: |
700 | glk_program_nearest_filter_coefs(dev_priv, pipe, id, set); |
701 | break; |
702 | default: |
703 | MISSING_CASE(filter); |
704 | } |
705 | } |
706 | |
707 | void skl_pfit_enable(const struct intel_crtc_state *crtc_state) |
708 | { |
709 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
710 | struct drm_i915_private *dev_priv = to_i915(dev: crtc->base.dev); |
711 | const struct intel_crtc_scaler_state *scaler_state = |
712 | &crtc_state->scaler_state; |
713 | const struct drm_rect *dst = &crtc_state->pch_pfit.dst; |
714 | u16 uv_rgb_hphase, uv_rgb_vphase; |
715 | enum pipe pipe = crtc->pipe; |
716 | int width = drm_rect_width(r: dst); |
717 | int height = drm_rect_height(r: dst); |
718 | int x = dst->x1; |
719 | int y = dst->y1; |
720 | int hscale, vscale; |
721 | struct drm_rect src; |
722 | int id; |
723 | u32 ps_ctrl; |
724 | |
725 | if (!crtc_state->pch_pfit.enabled) |
726 | return; |
727 | |
728 | if (drm_WARN_ON(&dev_priv->drm, |
729 | crtc_state->scaler_state.scaler_id < 0)) |
730 | return; |
731 | |
732 | drm_rect_init(r: &src, x: 0, y: 0, |
733 | width: drm_rect_width(r: &crtc_state->pipe_src) << 16, |
734 | height: drm_rect_height(r: &crtc_state->pipe_src) << 16); |
735 | |
736 | hscale = drm_rect_calc_hscale(src: &src, dst, min_hscale: 0, INT_MAX); |
737 | vscale = drm_rect_calc_vscale(src: &src, dst, min_vscale: 0, INT_MAX); |
738 | |
739 | uv_rgb_hphase = skl_scaler_calc_phase(sub: 1, scale: hscale, chroma_cosited: false); |
740 | uv_rgb_vphase = skl_scaler_calc_phase(sub: 1, scale: vscale, chroma_cosited: false); |
741 | |
742 | id = scaler_state->scaler_id; |
743 | |
744 | ps_ctrl = PS_SCALER_EN | PS_BINDING_PIPE | scaler_state->scalers[id].mode | |
745 | skl_scaler_get_filter_select(filter: crtc_state->hw.scaling_filter, set: 0); |
746 | |
747 | skl_scaler_setup_filter(dev_priv, pipe, id, set: 0, |
748 | filter: crtc_state->hw.scaling_filter); |
749 | |
750 | intel_de_write_fw(i915: dev_priv, SKL_PS_CTRL(pipe, id), val: ps_ctrl); |
751 | |
752 | intel_de_write_fw(i915: dev_priv, SKL_PS_VPHASE(pipe, id), |
753 | PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase)); |
754 | intel_de_write_fw(i915: dev_priv, SKL_PS_HPHASE(pipe, id), |
755 | PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_hphase)); |
756 | intel_de_write_fw(i915: dev_priv, SKL_PS_WIN_POS(pipe, id), |
757 | PS_WIN_XPOS(x) | PS_WIN_YPOS(y)); |
758 | intel_de_write_fw(i915: dev_priv, SKL_PS_WIN_SZ(pipe, id), |
759 | PS_WIN_XSIZE(width) | PS_WIN_YSIZE(height)); |
760 | } |
761 | |
762 | void |
763 | skl_program_plane_scaler(struct intel_plane *plane, |
764 | const struct intel_crtc_state *crtc_state, |
765 | const struct intel_plane_state *plane_state) |
766 | { |
767 | struct drm_i915_private *dev_priv = to_i915(dev: plane->base.dev); |
768 | const struct drm_framebuffer *fb = plane_state->hw.fb; |
769 | enum pipe pipe = plane->pipe; |
770 | int scaler_id = plane_state->scaler_id; |
771 | const struct intel_scaler *scaler = |
772 | &crtc_state->scaler_state.scalers[scaler_id]; |
773 | int crtc_x = plane_state->uapi.dst.x1; |
774 | int crtc_y = plane_state->uapi.dst.y1; |
775 | u32 crtc_w = drm_rect_width(r: &plane_state->uapi.dst); |
776 | u32 crtc_h = drm_rect_height(r: &plane_state->uapi.dst); |
777 | u16 y_hphase, uv_rgb_hphase; |
778 | u16 y_vphase, uv_rgb_vphase; |
779 | int hscale, vscale; |
780 | u32 ps_ctrl; |
781 | |
782 | hscale = drm_rect_calc_hscale(src: &plane_state->uapi.src, |
783 | dst: &plane_state->uapi.dst, |
784 | min_hscale: 0, INT_MAX); |
785 | vscale = drm_rect_calc_vscale(src: &plane_state->uapi.src, |
786 | dst: &plane_state->uapi.dst, |
787 | min_vscale: 0, INT_MAX); |
788 | |
789 | /* TODO: handle sub-pixel coordinates */ |
790 | if (intel_format_info_is_yuv_semiplanar(info: fb->format, modifier: fb->modifier) && |
791 | !icl_is_hdr_plane(dev_priv, plane_id: plane->id)) { |
792 | y_hphase = skl_scaler_calc_phase(sub: 1, scale: hscale, chroma_cosited: false); |
793 | y_vphase = skl_scaler_calc_phase(sub: 1, scale: vscale, chroma_cosited: false); |
794 | |
795 | /* MPEG2 chroma siting convention */ |
796 | uv_rgb_hphase = skl_scaler_calc_phase(sub: 2, scale: hscale, chroma_cosited: true); |
797 | uv_rgb_vphase = skl_scaler_calc_phase(sub: 2, scale: vscale, chroma_cosited: false); |
798 | } else { |
799 | /* not used */ |
800 | y_hphase = 0; |
801 | y_vphase = 0; |
802 | |
803 | uv_rgb_hphase = skl_scaler_calc_phase(sub: 1, scale: hscale, chroma_cosited: false); |
804 | uv_rgb_vphase = skl_scaler_calc_phase(sub: 1, scale: vscale, chroma_cosited: false); |
805 | } |
806 | |
807 | ps_ctrl = PS_SCALER_EN | PS_BINDING_PLANE(plane->id) | scaler->mode | |
808 | skl_scaler_get_filter_select(filter: plane_state->hw.scaling_filter, set: 0); |
809 | |
810 | skl_scaler_setup_filter(dev_priv, pipe, id: scaler_id, set: 0, |
811 | filter: plane_state->hw.scaling_filter); |
812 | |
813 | intel_de_write_fw(i915: dev_priv, SKL_PS_CTRL(pipe, scaler_id), val: ps_ctrl); |
814 | intel_de_write_fw(i915: dev_priv, SKL_PS_VPHASE(pipe, scaler_id), |
815 | PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase)); |
816 | intel_de_write_fw(i915: dev_priv, SKL_PS_HPHASE(pipe, scaler_id), |
817 | PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase)); |
818 | intel_de_write_fw(i915: dev_priv, SKL_PS_WIN_POS(pipe, scaler_id), |
819 | PS_WIN_XPOS(crtc_x) | PS_WIN_YPOS(crtc_y)); |
820 | intel_de_write_fw(i915: dev_priv, SKL_PS_WIN_SZ(pipe, scaler_id), |
821 | PS_WIN_XSIZE(crtc_w) | PS_WIN_YSIZE(crtc_h)); |
822 | } |
823 | |
824 | static void skl_detach_scaler(struct intel_crtc *crtc, int id) |
825 | { |
826 | struct drm_device *dev = crtc->base.dev; |
827 | struct drm_i915_private *dev_priv = to_i915(dev); |
828 | |
829 | intel_de_write_fw(i915: dev_priv, SKL_PS_CTRL(crtc->pipe, id), val: 0); |
830 | intel_de_write_fw(i915: dev_priv, SKL_PS_WIN_POS(crtc->pipe, id), val: 0); |
831 | intel_de_write_fw(i915: dev_priv, SKL_PS_WIN_SZ(crtc->pipe, id), val: 0); |
832 | } |
833 | |
834 | /* |
835 | * This function detaches (aka. unbinds) unused scalers in hardware |
836 | */ |
837 | void skl_detach_scalers(const struct intel_crtc_state *crtc_state) |
838 | { |
839 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
840 | const struct intel_crtc_scaler_state *scaler_state = |
841 | &crtc_state->scaler_state; |
842 | int i; |
843 | |
844 | /* loop through and disable scalers that aren't in use */ |
845 | for (i = 0; i < crtc->num_scalers; i++) { |
846 | if (!scaler_state->scalers[i].in_use) |
847 | skl_detach_scaler(crtc, id: i); |
848 | } |
849 | } |
850 | |
851 | void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state) |
852 | { |
853 | struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); |
854 | int i; |
855 | |
856 | for (i = 0; i < crtc->num_scalers; i++) |
857 | skl_detach_scaler(crtc, id: i); |
858 | } |
859 | |
860 | void skl_scaler_get_config(struct intel_crtc_state *crtc_state) |
861 | { |
862 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
863 | struct drm_i915_private *dev_priv = to_i915(dev: crtc->base.dev); |
864 | struct intel_crtc_scaler_state *scaler_state = &crtc_state->scaler_state; |
865 | int id = -1; |
866 | int i; |
867 | |
868 | /* find scaler attached to this pipe */ |
869 | for (i = 0; i < crtc->num_scalers; i++) { |
870 | u32 ctl, pos, size; |
871 | |
872 | ctl = intel_de_read(i915: dev_priv, SKL_PS_CTRL(crtc->pipe, i)); |
873 | if ((ctl & (PS_SCALER_EN | PS_BINDING_MASK)) != (PS_SCALER_EN | PS_BINDING_PIPE)) |
874 | continue; |
875 | |
876 | id = i; |
877 | crtc_state->pch_pfit.enabled = true; |
878 | |
879 | pos = intel_de_read(i915: dev_priv, SKL_PS_WIN_POS(crtc->pipe, i)); |
880 | size = intel_de_read(i915: dev_priv, SKL_PS_WIN_SZ(crtc->pipe, i)); |
881 | |
882 | drm_rect_init(r: &crtc_state->pch_pfit.dst, |
883 | REG_FIELD_GET(PS_WIN_XPOS_MASK, pos), |
884 | REG_FIELD_GET(PS_WIN_YPOS_MASK, pos), |
885 | REG_FIELD_GET(PS_WIN_XSIZE_MASK, size), |
886 | REG_FIELD_GET(PS_WIN_YSIZE_MASK, size)); |
887 | |
888 | scaler_state->scalers[i].in_use = true; |
889 | break; |
890 | } |
891 | |
892 | scaler_state->scaler_id = id; |
893 | if (id >= 0) |
894 | scaler_state->scaler_users |= (1 << SKL_CRTC_INDEX); |
895 | else |
896 | scaler_state->scaler_users &= ~(1 << SKL_CRTC_INDEX); |
897 | } |
898 | |