1 /* $NetBSD: intel_atomic_plane.c,v 1.3 2021/12/19 11:38:03 riastradh Exp $ */
2
3 /*
4 * Copyright © 2014 Intel Corporation
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26 /**
27 * DOC: atomic plane helpers
28 *
29 * The functions here are used by the atomic plane helper functions to
30 * implement legacy plane updates (i.e., drm_plane->update_plane() and
31 * drm_plane->disable_plane()). This allows plane updates to use the
32 * atomic state infrastructure and perform plane updates as separate
33 * prepare/check/commit/cleanup steps.
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: intel_atomic_plane.c,v 1.3 2021/12/19 11:38:03 riastradh Exp $");
38
39 #include <drm/drm_atomic_helper.h>
40 #include <drm/drm_fourcc.h>
41 #include <drm/drm_plane_helper.h>
42
43 #include "i915_trace.h"
44 #include "intel_atomic_plane.h"
45 #include "intel_display_types.h"
46 #include "intel_pm.h"
47 #include "intel_sprite.h"
48
intel_plane_state_reset(struct intel_plane_state * plane_state,struct intel_plane * plane)49 static void intel_plane_state_reset(struct intel_plane_state *plane_state,
50 struct intel_plane *plane)
51 {
52 memset(plane_state, 0, sizeof(*plane_state));
53
54 __drm_atomic_helper_plane_state_reset(&plane_state->uapi, &plane->base);
55
56 plane_state->scaler_id = -1;
57 }
58
intel_plane_alloc(void)59 struct intel_plane *intel_plane_alloc(void)
60 {
61 struct intel_plane_state *plane_state;
62 struct intel_plane *plane;
63
64 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
65 if (!plane)
66 return ERR_PTR(-ENOMEM);
67
68 plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
69 if (!plane_state) {
70 kfree(plane);
71 return ERR_PTR(-ENOMEM);
72 }
73
74 intel_plane_state_reset(plane_state, plane);
75
76 plane->base.state = &plane_state->uapi;
77
78 return plane;
79 }
80
intel_plane_free(struct intel_plane * plane)81 void intel_plane_free(struct intel_plane *plane)
82 {
83 intel_plane_destroy_state(&plane->base, plane->base.state);
84 kfree(plane);
85 }
86
87 /**
88 * intel_plane_duplicate_state - duplicate plane state
89 * @plane: drm plane
90 *
91 * Allocates and returns a copy of the plane state (both common and
92 * Intel-specific) for the specified plane.
93 *
94 * Returns: The newly allocated plane state, or NULL on failure.
95 */
96 struct drm_plane_state *
intel_plane_duplicate_state(struct drm_plane * plane)97 intel_plane_duplicate_state(struct drm_plane *plane)
98 {
99 struct intel_plane_state *intel_state;
100
101 intel_state = to_intel_plane_state(plane->state);
102 intel_state = kmemdup(intel_state, sizeof(*intel_state), GFP_KERNEL);
103
104 if (!intel_state)
105 return NULL;
106
107 __drm_atomic_helper_plane_duplicate_state(plane, &intel_state->uapi);
108
109 intel_state->vma = NULL;
110 intel_state->flags = 0;
111
112 /* add reference to fb */
113 if (intel_state->hw.fb)
114 drm_framebuffer_get(intel_state->hw.fb);
115
116 return &intel_state->uapi;
117 }
118
119 /**
120 * intel_plane_destroy_state - destroy plane state
121 * @plane: drm plane
122 * @state: state object to destroy
123 *
124 * Destroys the plane state (both common and Intel-specific) for the
125 * specified plane.
126 */
127 void
intel_plane_destroy_state(struct drm_plane * plane,struct drm_plane_state * state)128 intel_plane_destroy_state(struct drm_plane *plane,
129 struct drm_plane_state *state)
130 {
131 struct intel_plane_state *plane_state = to_intel_plane_state(state);
132 WARN_ON(plane_state->vma);
133
134 __drm_atomic_helper_plane_destroy_state(&plane_state->uapi);
135 if (plane_state->hw.fb)
136 drm_framebuffer_put(plane_state->hw.fb);
137 kfree(plane_state);
138 }
139
intel_plane_data_rate(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)140 unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
141 const struct intel_plane_state *plane_state)
142 {
143 const struct drm_framebuffer *fb = plane_state->hw.fb;
144 unsigned int cpp;
145
146 if (!plane_state->uapi.visible)
147 return 0;
148
149 cpp = fb->format->cpp[0];
150
151 /*
152 * Based on HSD#:1408715493
153 * NV12 cpp == 4, P010 cpp == 8
154 *
155 * FIXME what is the logic behind this?
156 */
157 if (fb->format->is_yuv && fb->format->num_planes > 1)
158 cpp *= 4;
159
160 return cpp * crtc_state->pixel_rate;
161 }
162
intel_plane_calc_min_cdclk(struct intel_atomic_state * state,struct intel_plane * plane)163 bool intel_plane_calc_min_cdclk(struct intel_atomic_state *state,
164 struct intel_plane *plane)
165 {
166 struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
167 const struct intel_plane_state *plane_state =
168 intel_atomic_get_new_plane_state(state, plane);
169 struct intel_crtc *crtc = to_intel_crtc(plane_state->hw.crtc);
170 struct intel_crtc_state *crtc_state;
171
172 if (!plane_state->uapi.visible || !plane->min_cdclk)
173 return false;
174
175 crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
176
177 crtc_state->min_cdclk[plane->id] =
178 plane->min_cdclk(crtc_state, plane_state);
179
180 /*
181 * Does the cdclk need to be bumbed up?
182 *
183 * Note: we obviously need to be called before the new
184 * cdclk frequency is calculated so state->cdclk.logical
185 * hasn't been populated yet. Hence we look at the old
186 * cdclk state under dev_priv->cdclk.logical. This is
187 * safe as long we hold at least one crtc mutex (which
188 * must be true since we have crtc_state).
189 */
190 if (crtc_state->min_cdclk[plane->id] > dev_priv->cdclk.logical.cdclk) {
191 DRM_DEBUG_KMS("[PLANE:%d:%s] min_cdclk (%d kHz) > logical cdclk (%d kHz)\n",
192 plane->base.base.id, plane->base.name,
193 crtc_state->min_cdclk[plane->id],
194 dev_priv->cdclk.logical.cdclk);
195 return true;
196 }
197
198 return false;
199 }
200
intel_plane_clear_hw_state(struct intel_plane_state * plane_state)201 static void intel_plane_clear_hw_state(struct intel_plane_state *plane_state)
202 {
203 if (plane_state->hw.fb)
204 drm_framebuffer_put(plane_state->hw.fb);
205
206 memset(&plane_state->hw, 0, sizeof(plane_state->hw));
207 }
208
intel_plane_copy_uapi_to_hw_state(struct intel_plane_state * plane_state,const struct intel_plane_state * from_plane_state)209 void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
210 const struct intel_plane_state *from_plane_state)
211 {
212 intel_plane_clear_hw_state(plane_state);
213
214 plane_state->hw.crtc = from_plane_state->uapi.crtc;
215 plane_state->hw.fb = from_plane_state->uapi.fb;
216 if (plane_state->hw.fb)
217 drm_framebuffer_get(plane_state->hw.fb);
218
219 plane_state->hw.alpha = from_plane_state->uapi.alpha;
220 plane_state->hw.pixel_blend_mode =
221 from_plane_state->uapi.pixel_blend_mode;
222 plane_state->hw.rotation = from_plane_state->uapi.rotation;
223 plane_state->hw.color_encoding = from_plane_state->uapi.color_encoding;
224 plane_state->hw.color_range = from_plane_state->uapi.color_range;
225 }
226
intel_plane_atomic_check_with_state(const struct intel_crtc_state * old_crtc_state,struct intel_crtc_state * new_crtc_state,const struct intel_plane_state * old_plane_state,struct intel_plane_state * new_plane_state)227 int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
228 struct intel_crtc_state *new_crtc_state,
229 const struct intel_plane_state *old_plane_state,
230 struct intel_plane_state *new_plane_state)
231 {
232 struct intel_plane *plane = to_intel_plane(new_plane_state->uapi.plane);
233 const struct drm_framebuffer *fb;
234 int ret;
235
236 intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state);
237 fb = new_plane_state->hw.fb;
238
239 new_crtc_state->active_planes &= ~BIT(plane->id);
240 new_crtc_state->nv12_planes &= ~BIT(plane->id);
241 new_crtc_state->c8_planes &= ~BIT(plane->id);
242 new_crtc_state->data_rate[plane->id] = 0;
243 new_crtc_state->min_cdclk[plane->id] = 0;
244 new_plane_state->uapi.visible = false;
245
246 if (!new_plane_state->hw.crtc && !old_plane_state->hw.crtc)
247 return 0;
248
249 ret = plane->check_plane(new_crtc_state, new_plane_state);
250 if (ret)
251 return ret;
252
253 /* FIXME pre-g4x don't work like this */
254 if (new_plane_state->uapi.visible)
255 new_crtc_state->active_planes |= BIT(plane->id);
256
257 if (new_plane_state->uapi.visible &&
258 intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
259 new_crtc_state->nv12_planes |= BIT(plane->id);
260
261 if (new_plane_state->uapi.visible &&
262 fb->format->format == DRM_FORMAT_C8)
263 new_crtc_state->c8_planes |= BIT(plane->id);
264
265 if (new_plane_state->uapi.visible || old_plane_state->uapi.visible)
266 new_crtc_state->update_planes |= BIT(plane->id);
267
268 new_crtc_state->data_rate[plane->id] =
269 intel_plane_data_rate(new_crtc_state, new_plane_state);
270
271 return intel_plane_atomic_calc_changes(old_crtc_state, new_crtc_state,
272 old_plane_state, new_plane_state);
273 }
274
275 static struct intel_crtc *
get_crtc_from_states(const struct intel_plane_state * old_plane_state,const struct intel_plane_state * new_plane_state)276 get_crtc_from_states(const struct intel_plane_state *old_plane_state,
277 const struct intel_plane_state *new_plane_state)
278 {
279 if (new_plane_state->uapi.crtc)
280 return to_intel_crtc(new_plane_state->uapi.crtc);
281
282 if (old_plane_state->uapi.crtc)
283 return to_intel_crtc(old_plane_state->uapi.crtc);
284
285 return NULL;
286 }
287
intel_plane_atomic_check(struct intel_atomic_state * state,struct intel_plane * plane)288 int intel_plane_atomic_check(struct intel_atomic_state *state,
289 struct intel_plane *plane)
290 {
291 struct intel_plane_state *new_plane_state =
292 intel_atomic_get_new_plane_state(state, plane);
293 const struct intel_plane_state *old_plane_state =
294 intel_atomic_get_old_plane_state(state, plane);
295 struct intel_crtc *crtc =
296 get_crtc_from_states(old_plane_state, new_plane_state);
297 const struct intel_crtc_state *old_crtc_state;
298 struct intel_crtc_state *new_crtc_state;
299
300 new_plane_state->uapi.visible = false;
301 if (!crtc)
302 return 0;
303
304 old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc);
305 new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
306
307 return intel_plane_atomic_check_with_state(old_crtc_state,
308 new_crtc_state,
309 old_plane_state,
310 new_plane_state);
311 }
312
313 static struct intel_plane *
skl_next_plane_to_commit(struct intel_atomic_state * state,struct intel_crtc * crtc,struct skl_ddb_entry entries_y[I915_MAX_PLANES],struct skl_ddb_entry entries_uv[I915_MAX_PLANES],unsigned int * update_mask)314 skl_next_plane_to_commit(struct intel_atomic_state *state,
315 struct intel_crtc *crtc,
316 struct skl_ddb_entry entries_y[I915_MAX_PLANES],
317 struct skl_ddb_entry entries_uv[I915_MAX_PLANES],
318 unsigned int *update_mask)
319 {
320 struct intel_crtc_state *crtc_state =
321 intel_atomic_get_new_crtc_state(state, crtc);
322 struct intel_plane_state *plane_state __unused;
323 struct intel_plane *plane;
324 int i;
325
326 if (*update_mask == 0)
327 return NULL;
328
329 for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
330 enum plane_id plane_id = plane->id;
331
332 if (crtc->pipe != plane->pipe ||
333 !(*update_mask & BIT(plane_id)))
334 continue;
335
336 if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id],
337 entries_y,
338 I915_MAX_PLANES, plane_id) ||
339 skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_uv[plane_id],
340 entries_uv,
341 I915_MAX_PLANES, plane_id))
342 continue;
343
344 *update_mask &= ~BIT(plane_id);
345 entries_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id];
346 entries_uv[plane_id] = crtc_state->wm.skl.plane_ddb_uv[plane_id];
347
348 return plane;
349 }
350
351 /* should never happen */
352 WARN_ON(1);
353
354 return NULL;
355 }
356
intel_update_plane(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)357 void intel_update_plane(struct intel_plane *plane,
358 const struct intel_crtc_state *crtc_state,
359 const struct intel_plane_state *plane_state)
360 {
361 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
362
363 trace_intel_update_plane(&plane->base, crtc);
364 plane->update_plane(plane, crtc_state, plane_state);
365 }
366
intel_disable_plane(struct intel_plane * plane,const struct intel_crtc_state * crtc_state)367 void intel_disable_plane(struct intel_plane *plane,
368 const struct intel_crtc_state *crtc_state)
369 {
370 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
371
372 trace_intel_disable_plane(&plane->base, crtc);
373 plane->disable_plane(plane, crtc_state);
374 }
375
skl_update_planes_on_crtc(struct intel_atomic_state * state,struct intel_crtc * crtc)376 void skl_update_planes_on_crtc(struct intel_atomic_state *state,
377 struct intel_crtc *crtc)
378 {
379 struct intel_crtc_state *old_crtc_state =
380 intel_atomic_get_old_crtc_state(state, crtc);
381 struct intel_crtc_state *new_crtc_state =
382 intel_atomic_get_new_crtc_state(state, crtc);
383 struct skl_ddb_entry entries_y[I915_MAX_PLANES];
384 struct skl_ddb_entry entries_uv[I915_MAX_PLANES];
385 u32 update_mask = new_crtc_state->update_planes;
386 struct intel_plane *plane;
387
388 memcpy(entries_y, old_crtc_state->wm.skl.plane_ddb_y,
389 sizeof(old_crtc_state->wm.skl.plane_ddb_y));
390 memcpy(entries_uv, old_crtc_state->wm.skl.plane_ddb_uv,
391 sizeof(old_crtc_state->wm.skl.plane_ddb_uv));
392
393 while ((plane = skl_next_plane_to_commit(state, crtc,
394 entries_y, entries_uv,
395 &update_mask))) {
396 struct intel_plane_state *new_plane_state =
397 intel_atomic_get_new_plane_state(state, plane);
398
399 if (new_plane_state->uapi.visible ||
400 new_plane_state->planar_slave) {
401 intel_update_plane(plane, new_crtc_state, new_plane_state);
402 } else {
403 intel_disable_plane(plane, new_crtc_state);
404 }
405 }
406 }
407
i9xx_update_planes_on_crtc(struct intel_atomic_state * state,struct intel_crtc * crtc)408 void i9xx_update_planes_on_crtc(struct intel_atomic_state *state,
409 struct intel_crtc *crtc)
410 {
411 struct intel_crtc_state *new_crtc_state =
412 intel_atomic_get_new_crtc_state(state, crtc);
413 u32 update_mask = new_crtc_state->update_planes;
414 struct intel_plane_state *new_plane_state;
415 struct intel_plane *plane;
416 int i;
417
418 for_each_new_intel_plane_in_state(state, plane, new_plane_state, i) {
419 if (crtc->pipe != plane->pipe ||
420 !(update_mask & BIT(plane->id)))
421 continue;
422
423 if (new_plane_state->uapi.visible)
424 intel_update_plane(plane, new_crtc_state, new_plane_state);
425 else
426 intel_disable_plane(plane, new_crtc_state);
427 }
428 }
429
430 const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
431 .prepare_fb = intel_prepare_plane_fb,
432 .cleanup_fb = intel_cleanup_plane_fb,
433 };
434