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