diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2015-07-27 08:34:18 -0400 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2016-02-19 19:58:56 -0500 |
commit | ab334e137c31440e3a826e0d3c2753425f18641b (patch) | |
tree | 77671692d81686641543738a96d91c377bd1dd02 /drivers/gpu | |
parent | 2af0394409faec95e80d6061a8a9fe95565be358 (diff) |
drm: rcar-du: Move plane allocator to rcar_du_plane.c
The plane allocator is specific to DU planes and won't be used for
VSP-based planes, move it with the rest of the DU planes code where it
belongs.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_kms.c | 276 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_plane.c | 286 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_plane.h | 3 |
3 files changed, 290 insertions, 275 deletions
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index a69d6075ceae..f5c00c0cd026 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c | |||
@@ -192,290 +192,16 @@ static void rcar_du_output_poll_changed(struct drm_device *dev) | |||
192 | * Atomic Check and Update | 192 | * Atomic Check and Update |
193 | */ | 193 | */ |
194 | 194 | ||
195 | /* | ||
196 | * Atomic hardware plane allocator | ||
197 | * | ||
198 | * The hardware plane allocator is solely based on the atomic plane states | ||
199 | * without keeping any external state to avoid races between .atomic_check() | ||
200 | * and .atomic_commit(). | ||
201 | * | ||
202 | * The core idea is to avoid using a free planes bitmask that would need to be | ||
203 | * shared between check and commit handlers with a collective knowledge based on | ||
204 | * the allocated hardware plane(s) for each KMS plane. The allocator then loops | ||
205 | * over all plane states to compute the free planes bitmask, allocates hardware | ||
206 | * planes based on that bitmask, and stores the result back in the plane states. | ||
207 | * | ||
208 | * For this to work we need to access the current state of planes not touched by | ||
209 | * the atomic update. To ensure that it won't be modified, we need to lock all | ||
210 | * planes using drm_atomic_get_plane_state(). This effectively serializes atomic | ||
211 | * updates from .atomic_check() up to completion (when swapping the states if | ||
212 | * the check step has succeeded) or rollback (when freeing the states if the | ||
213 | * check step has failed). | ||
214 | * | ||
215 | * Allocation is performed in the .atomic_check() handler and applied | ||
216 | * automatically when the core swaps the old and new states. | ||
217 | */ | ||
218 | |||
219 | static bool rcar_du_plane_needs_realloc(struct rcar_du_plane *plane, | ||
220 | struct rcar_du_plane_state *new_state) | ||
221 | { | ||
222 | struct rcar_du_plane_state *cur_state; | ||
223 | |||
224 | cur_state = to_rcar_plane_state(plane->plane.state); | ||
225 | |||
226 | /* Lowering the number of planes doesn't strictly require reallocation | ||
227 | * as the extra hardware plane will be freed when committing, but doing | ||
228 | * so could lead to more fragmentation. | ||
229 | */ | ||
230 | if (!cur_state->format || | ||
231 | cur_state->format->planes != new_state->format->planes) | ||
232 | return true; | ||
233 | |||
234 | /* Reallocate hardware planes if the source has changed. */ | ||
235 | if (cur_state->source != new_state->source) | ||
236 | return true; | ||
237 | |||
238 | return false; | ||
239 | } | ||
240 | |||
241 | static unsigned int rcar_du_plane_hwmask(struct rcar_du_plane_state *state) | ||
242 | { | ||
243 | unsigned int mask; | ||
244 | |||
245 | if (state->hwindex == -1) | ||
246 | return 0; | ||
247 | |||
248 | mask = 1 << state->hwindex; | ||
249 | if (state->format->planes == 2) | ||
250 | mask |= 1 << ((state->hwindex + 1) % 8); | ||
251 | |||
252 | return mask; | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * The R8A7790 DU can source frames directly from the VSP1 devices VSPD0 and | ||
257 | * VSPD1. VSPD0 feeds DU0/1 plane 0, and VSPD1 feeds either DU2 plane 0 or | ||
258 | * DU0/1 plane 1. | ||
259 | * | ||
260 | * Allocate the correct fixed plane when sourcing frames from VSPD0 or VSPD1, | ||
261 | * and allocate planes in reverse index order otherwise to ensure maximum | ||
262 | * availability of planes 0 and 1. | ||
263 | * | ||
264 | * The caller is responsible for ensuring that the requested source is | ||
265 | * compatible with the DU revision. | ||
266 | */ | ||
267 | static int rcar_du_plane_hwalloc(struct rcar_du_plane *plane, | ||
268 | struct rcar_du_plane_state *state, | ||
269 | unsigned int free) | ||
270 | { | ||
271 | unsigned int num_planes = state->format->planes; | ||
272 | int fixed = -1; | ||
273 | int i; | ||
274 | |||
275 | if (state->source == RCAR_DU_PLANE_VSPD0) { | ||
276 | /* VSPD0 feeds plane 0 on DU0/1. */ | ||
277 | if (plane->group->index != 0) | ||
278 | return -EINVAL; | ||
279 | |||
280 | fixed = 0; | ||
281 | } else if (state->source == RCAR_DU_PLANE_VSPD1) { | ||
282 | /* VSPD1 feeds plane 1 on DU0/1 or plane 0 on DU2. */ | ||
283 | fixed = plane->group->index == 0 ? 1 : 0; | ||
284 | } | ||
285 | |||
286 | if (fixed >= 0) | ||
287 | return free & (1 << fixed) ? fixed : -EBUSY; | ||
288 | |||
289 | for (i = RCAR_DU_NUM_HW_PLANES - 1; i >= 0; --i) { | ||
290 | if (!(free & (1 << i))) | ||
291 | continue; | ||
292 | |||
293 | if (num_planes == 1 || free & (1 << ((i + 1) % 8))) | ||
294 | break; | ||
295 | } | ||
296 | |||
297 | return i < 0 ? -EBUSY : i; | ||
298 | } | ||
299 | |||
300 | static int rcar_du_atomic_check(struct drm_device *dev, | 195 | static int rcar_du_atomic_check(struct drm_device *dev, |
301 | struct drm_atomic_state *state) | 196 | struct drm_atomic_state *state) |
302 | { | 197 | { |
303 | struct rcar_du_device *rcdu = dev->dev_private; | ||
304 | unsigned int group_freed_planes[RCAR_DU_MAX_GROUPS] = { 0, }; | ||
305 | unsigned int group_free_planes[RCAR_DU_MAX_GROUPS] = { 0, }; | ||
306 | bool needs_realloc = false; | ||
307 | unsigned int groups = 0; | ||
308 | unsigned int i; | ||
309 | int ret; | 198 | int ret; |
310 | 199 | ||
311 | ret = drm_atomic_helper_check(dev, state); | 200 | ret = drm_atomic_helper_check(dev, state); |
312 | if (ret < 0) | 201 | if (ret < 0) |
313 | return ret; | 202 | return ret; |
314 | 203 | ||
315 | /* Check if hardware planes need to be reallocated. */ | 204 | return rcar_du_atomic_check_planes(dev, state); |
316 | for (i = 0; i < dev->mode_config.num_total_plane; ++i) { | ||
317 | struct rcar_du_plane_state *plane_state; | ||
318 | struct rcar_du_plane *plane; | ||
319 | unsigned int index; | ||
320 | |||
321 | if (!state->planes[i]) | ||
322 | continue; | ||
323 | |||
324 | plane = to_rcar_plane(state->planes[i]); | ||
325 | plane_state = to_rcar_plane_state(state->plane_states[i]); | ||
326 | |||
327 | dev_dbg(rcdu->dev, "%s: checking plane (%u,%u)\n", __func__, | ||
328 | plane->group->index, plane - plane->group->planes); | ||
329 | |||
330 | /* If the plane is being disabled we don't need to go through | ||
331 | * the full reallocation procedure. Just mark the hardware | ||
332 | * plane(s) as freed. | ||
333 | */ | ||
334 | if (!plane_state->format) { | ||
335 | dev_dbg(rcdu->dev, "%s: plane is being disabled\n", | ||
336 | __func__); | ||
337 | index = plane - plane->group->planes; | ||
338 | group_freed_planes[plane->group->index] |= 1 << index; | ||
339 | plane_state->hwindex = -1; | ||
340 | continue; | ||
341 | } | ||
342 | |||
343 | /* If the plane needs to be reallocated mark it as such, and | ||
344 | * mark the hardware plane(s) as free. | ||
345 | */ | ||
346 | if (rcar_du_plane_needs_realloc(plane, plane_state)) { | ||
347 | dev_dbg(rcdu->dev, "%s: plane needs reallocation\n", | ||
348 | __func__); | ||
349 | groups |= 1 << plane->group->index; | ||
350 | needs_realloc = true; | ||
351 | |||
352 | index = plane - plane->group->planes; | ||
353 | group_freed_planes[plane->group->index] |= 1 << index; | ||
354 | plane_state->hwindex = -1; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | if (!needs_realloc) | ||
359 | return 0; | ||
360 | |||
361 | /* Grab all plane states for the groups that need reallocation to ensure | ||
362 | * locking and avoid racy updates. This serializes the update operation, | ||
363 | * but there's not much we can do about it as that's the hardware | ||
364 | * design. | ||
365 | * | ||
366 | * Compute the used planes mask for each group at the same time to avoid | ||
367 | * looping over the planes separately later. | ||
368 | */ | ||
369 | while (groups) { | ||
370 | unsigned int index = ffs(groups) - 1; | ||
371 | struct rcar_du_group *group = &rcdu->groups[index]; | ||
372 | unsigned int used_planes = 0; | ||
373 | |||
374 | dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n", | ||
375 | __func__, index); | ||
376 | |||
377 | for (i = 0; i < group->num_planes; ++i) { | ||
378 | struct rcar_du_plane *plane = &group->planes[i]; | ||
379 | struct rcar_du_plane_state *plane_state; | ||
380 | struct drm_plane_state *s; | ||
381 | |||
382 | s = drm_atomic_get_plane_state(state, &plane->plane); | ||
383 | if (IS_ERR(s)) | ||
384 | return PTR_ERR(s); | ||
385 | |||
386 | /* If the plane has been freed in the above loop its | ||
387 | * hardware planes must not be added to the used planes | ||
388 | * bitmask. However, the current state doesn't reflect | ||
389 | * the free state yet, as we've modified the new state | ||
390 | * above. Use the local freed planes list to check for | ||
391 | * that condition instead. | ||
392 | */ | ||
393 | if (group_freed_planes[index] & (1 << i)) { | ||
394 | dev_dbg(rcdu->dev, | ||
395 | "%s: plane (%u,%u) has been freed, skipping\n", | ||
396 | __func__, plane->group->index, | ||
397 | plane - plane->group->planes); | ||
398 | continue; | ||
399 | } | ||
400 | |||
401 | plane_state = to_rcar_plane_state(plane->plane.state); | ||
402 | used_planes |= rcar_du_plane_hwmask(plane_state); | ||
403 | |||
404 | dev_dbg(rcdu->dev, | ||
405 | "%s: plane (%u,%u) uses %u hwplanes (index %d)\n", | ||
406 | __func__, plane->group->index, | ||
407 | plane - plane->group->planes, | ||
408 | plane_state->format ? | ||
409 | plane_state->format->planes : 0, | ||
410 | plane_state->hwindex); | ||
411 | } | ||
412 | |||
413 | group_free_planes[index] = 0xff & ~used_planes; | ||
414 | groups &= ~(1 << index); | ||
415 | |||
416 | dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n", | ||
417 | __func__, index, group_free_planes[index]); | ||
418 | } | ||
419 | |||
420 | /* Reallocate hardware planes for each plane that needs it. */ | ||
421 | for (i = 0; i < dev->mode_config.num_total_plane; ++i) { | ||
422 | struct rcar_du_plane_state *plane_state; | ||
423 | struct rcar_du_plane *plane; | ||
424 | unsigned int crtc_planes; | ||
425 | unsigned int free; | ||
426 | int idx; | ||
427 | |||
428 | if (!state->planes[i]) | ||
429 | continue; | ||
430 | |||
431 | plane = to_rcar_plane(state->planes[i]); | ||
432 | plane_state = to_rcar_plane_state(state->plane_states[i]); | ||
433 | |||
434 | dev_dbg(rcdu->dev, "%s: allocating plane (%u,%u)\n", __func__, | ||
435 | plane->group->index, plane - plane->group->planes); | ||
436 | |||
437 | /* Skip planes that are being disabled or don't need to be | ||
438 | * reallocated. | ||
439 | */ | ||
440 | if (!plane_state->format || | ||
441 | !rcar_du_plane_needs_realloc(plane, plane_state)) | ||
442 | continue; | ||
443 | |||
444 | /* Try to allocate the plane from the free planes currently | ||
445 | * associated with the target CRTC to avoid restarting the CRTC | ||
446 | * group and thus minimize flicker. If it fails fall back to | ||
447 | * allocating from all free planes. | ||
448 | */ | ||
449 | crtc_planes = to_rcar_crtc(plane_state->state.crtc)->index % 2 | ||
450 | ? plane->group->dptsr_planes | ||
451 | : ~plane->group->dptsr_planes; | ||
452 | free = group_free_planes[plane->group->index]; | ||
453 | |||
454 | idx = rcar_du_plane_hwalloc(plane, plane_state, | ||
455 | free & crtc_planes); | ||
456 | if (idx < 0) | ||
457 | idx = rcar_du_plane_hwalloc(plane, plane_state, | ||
458 | free); | ||
459 | if (idx < 0) { | ||
460 | dev_dbg(rcdu->dev, "%s: no available hardware plane\n", | ||
461 | __func__); | ||
462 | return idx; | ||
463 | } | ||
464 | |||
465 | dev_dbg(rcdu->dev, "%s: allocated %u hwplanes (index %u)\n", | ||
466 | __func__, plane_state->format->planes, idx); | ||
467 | |||
468 | plane_state->hwindex = idx; | ||
469 | |||
470 | group_free_planes[plane->group->index] &= | ||
471 | ~rcar_du_plane_hwmask(plane_state); | ||
472 | |||
473 | dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n", | ||
474 | __func__, plane->group->index, | ||
475 | group_free_planes[plane->group->index]); | ||
476 | } | ||
477 | |||
478 | return 0; | ||
479 | } | 205 | } |
480 | 206 | ||
481 | struct rcar_du_commit { | 207 | struct rcar_du_commit { |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 2fa5745fca37..64450ce13526 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c | |||
@@ -12,6 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <drm/drmP.h> | 14 | #include <drm/drmP.h> |
15 | #include <drm/drm_atomic.h> | ||
15 | #include <drm/drm_atomic_helper.h> | 16 | #include <drm/drm_atomic_helper.h> |
16 | #include <drm/drm_crtc.h> | 17 | #include <drm/drm_crtc.h> |
17 | #include <drm/drm_crtc_helper.h> | 18 | #include <drm/drm_crtc_helper.h> |
@@ -25,6 +26,291 @@ | |||
25 | #include "rcar_du_plane.h" | 26 | #include "rcar_du_plane.h" |
26 | #include "rcar_du_regs.h" | 27 | #include "rcar_du_regs.h" |
27 | 28 | ||
29 | /* ----------------------------------------------------------------------------- | ||
30 | * Atomic hardware plane allocator | ||
31 | * | ||
32 | * The hardware plane allocator is solely based on the atomic plane states | ||
33 | * without keeping any external state to avoid races between .atomic_check() | ||
34 | * and .atomic_commit(). | ||
35 | * | ||
36 | * The core idea is to avoid using a free planes bitmask that would need to be | ||
37 | * shared between check and commit handlers with a collective knowledge based on | ||
38 | * the allocated hardware plane(s) for each KMS plane. The allocator then loops | ||
39 | * over all plane states to compute the free planes bitmask, allocates hardware | ||
40 | * planes based on that bitmask, and stores the result back in the plane states. | ||
41 | * | ||
42 | * For this to work we need to access the current state of planes not touched by | ||
43 | * the atomic update. To ensure that it won't be modified, we need to lock all | ||
44 | * planes using drm_atomic_get_plane_state(). This effectively serializes atomic | ||
45 | * updates from .atomic_check() up to completion (when swapping the states if | ||
46 | * the check step has succeeded) or rollback (when freeing the states if the | ||
47 | * check step has failed). | ||
48 | * | ||
49 | * Allocation is performed in the .atomic_check() handler and applied | ||
50 | * automatically when the core swaps the old and new states. | ||
51 | */ | ||
52 | |||
53 | static bool rcar_du_plane_needs_realloc(struct rcar_du_plane *plane, | ||
54 | struct rcar_du_plane_state *new_state) | ||
55 | { | ||
56 | struct rcar_du_plane_state *cur_state; | ||
57 | |||
58 | cur_state = to_rcar_plane_state(plane->plane.state); | ||
59 | |||
60 | /* Lowering the number of planes doesn't strictly require reallocation | ||
61 | * as the extra hardware plane will be freed when committing, but doing | ||
62 | * so could lead to more fragmentation. | ||
63 | */ | ||
64 | if (!cur_state->format || | ||
65 | cur_state->format->planes != new_state->format->planes) | ||
66 | return true; | ||
67 | |||
68 | /* Reallocate hardware planes if the source has changed. */ | ||
69 | if (cur_state->source != new_state->source) | ||
70 | return true; | ||
71 | |||
72 | return false; | ||
73 | } | ||
74 | |||
75 | static unsigned int rcar_du_plane_hwmask(struct rcar_du_plane_state *state) | ||
76 | { | ||
77 | unsigned int mask; | ||
78 | |||
79 | if (state->hwindex == -1) | ||
80 | return 0; | ||
81 | |||
82 | mask = 1 << state->hwindex; | ||
83 | if (state->format->planes == 2) | ||
84 | mask |= 1 << ((state->hwindex + 1) % 8); | ||
85 | |||
86 | return mask; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * The R8A7790 DU can source frames directly from the VSP1 devices VSPD0 and | ||
91 | * VSPD1. VSPD0 feeds DU0/1 plane 0, and VSPD1 feeds either DU2 plane 0 or | ||
92 | * DU0/1 plane 1. | ||
93 | * | ||
94 | * Allocate the correct fixed plane when sourcing frames from VSPD0 or VSPD1, | ||
95 | * and allocate planes in reverse index order otherwise to ensure maximum | ||
96 | * availability of planes 0 and 1. | ||
97 | * | ||
98 | * The caller is responsible for ensuring that the requested source is | ||
99 | * compatible with the DU revision. | ||
100 | */ | ||
101 | static int rcar_du_plane_hwalloc(struct rcar_du_plane *plane, | ||
102 | struct rcar_du_plane_state *state, | ||
103 | unsigned int free) | ||
104 | { | ||
105 | unsigned int num_planes = state->format->planes; | ||
106 | int fixed = -1; | ||
107 | int i; | ||
108 | |||
109 | if (state->source == RCAR_DU_PLANE_VSPD0) { | ||
110 | /* VSPD0 feeds plane 0 on DU0/1. */ | ||
111 | if (plane->group->index != 0) | ||
112 | return -EINVAL; | ||
113 | |||
114 | fixed = 0; | ||
115 | } else if (state->source == RCAR_DU_PLANE_VSPD1) { | ||
116 | /* VSPD1 feeds plane 1 on DU0/1 or plane 0 on DU2. */ | ||
117 | fixed = plane->group->index == 0 ? 1 : 0; | ||
118 | } | ||
119 | |||
120 | if (fixed >= 0) | ||
121 | return free & (1 << fixed) ? fixed : -EBUSY; | ||
122 | |||
123 | for (i = RCAR_DU_NUM_HW_PLANES - 1; i >= 0; --i) { | ||
124 | if (!(free & (1 << i))) | ||
125 | continue; | ||
126 | |||
127 | if (num_planes == 1 || free & (1 << ((i + 1) % 8))) | ||
128 | break; | ||
129 | } | ||
130 | |||
131 | return i < 0 ? -EBUSY : i; | ||
132 | } | ||
133 | |||
134 | int rcar_du_atomic_check_planes(struct drm_device *dev, | ||
135 | struct drm_atomic_state *state) | ||
136 | { | ||
137 | struct rcar_du_device *rcdu = dev->dev_private; | ||
138 | unsigned int group_freed_planes[RCAR_DU_MAX_GROUPS] = { 0, }; | ||
139 | unsigned int group_free_planes[RCAR_DU_MAX_GROUPS] = { 0, }; | ||
140 | bool needs_realloc = false; | ||
141 | unsigned int groups = 0; | ||
142 | unsigned int i; | ||
143 | |||
144 | /* Check if hardware planes need to be reallocated. */ | ||
145 | for (i = 0; i < dev->mode_config.num_total_plane; ++i) { | ||
146 | struct rcar_du_plane_state *plane_state; | ||
147 | struct rcar_du_plane *plane; | ||
148 | unsigned int index; | ||
149 | |||
150 | if (!state->planes[i]) | ||
151 | continue; | ||
152 | |||
153 | plane = to_rcar_plane(state->planes[i]); | ||
154 | plane_state = to_rcar_plane_state(state->plane_states[i]); | ||
155 | |||
156 | dev_dbg(rcdu->dev, "%s: checking plane (%u,%u)\n", __func__, | ||
157 | plane->group->index, plane - plane->group->planes); | ||
158 | |||
159 | /* If the plane is being disabled we don't need to go through | ||
160 | * the full reallocation procedure. Just mark the hardware | ||
161 | * plane(s) as freed. | ||
162 | */ | ||
163 | if (!plane_state->format) { | ||
164 | dev_dbg(rcdu->dev, "%s: plane is being disabled\n", | ||
165 | __func__); | ||
166 | index = plane - plane->group->planes; | ||
167 | group_freed_planes[plane->group->index] |= 1 << index; | ||
168 | plane_state->hwindex = -1; | ||
169 | continue; | ||
170 | } | ||
171 | |||
172 | /* If the plane needs to be reallocated mark it as such, and | ||
173 | * mark the hardware plane(s) as free. | ||
174 | */ | ||
175 | if (rcar_du_plane_needs_realloc(plane, plane_state)) { | ||
176 | dev_dbg(rcdu->dev, "%s: plane needs reallocation\n", | ||
177 | __func__); | ||
178 | groups |= 1 << plane->group->index; | ||
179 | needs_realloc = true; | ||
180 | |||
181 | index = plane - plane->group->planes; | ||
182 | group_freed_planes[plane->group->index] |= 1 << index; | ||
183 | plane_state->hwindex = -1; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | if (!needs_realloc) | ||
188 | return 0; | ||
189 | |||
190 | /* Grab all plane states for the groups that need reallocation to ensure | ||
191 | * locking and avoid racy updates. This serializes the update operation, | ||
192 | * but there's not much we can do about it as that's the hardware | ||
193 | * design. | ||
194 | * | ||
195 | * Compute the used planes mask for each group at the same time to avoid | ||
196 | * looping over the planes separately later. | ||
197 | */ | ||
198 | while (groups) { | ||
199 | unsigned int index = ffs(groups) - 1; | ||
200 | struct rcar_du_group *group = &rcdu->groups[index]; | ||
201 | unsigned int used_planes = 0; | ||
202 | |||
203 | dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n", | ||
204 | __func__, index); | ||
205 | |||
206 | for (i = 0; i < group->num_planes; ++i) { | ||
207 | struct rcar_du_plane *plane = &group->planes[i]; | ||
208 | struct rcar_du_plane_state *plane_state; | ||
209 | struct drm_plane_state *s; | ||
210 | |||
211 | s = drm_atomic_get_plane_state(state, &plane->plane); | ||
212 | if (IS_ERR(s)) | ||
213 | return PTR_ERR(s); | ||
214 | |||
215 | /* If the plane has been freed in the above loop its | ||
216 | * hardware planes must not be added to the used planes | ||
217 | * bitmask. However, the current state doesn't reflect | ||
218 | * the free state yet, as we've modified the new state | ||
219 | * above. Use the local freed planes list to check for | ||
220 | * that condition instead. | ||
221 | */ | ||
222 | if (group_freed_planes[index] & (1 << i)) { | ||
223 | dev_dbg(rcdu->dev, | ||
224 | "%s: plane (%u,%u) has been freed, skipping\n", | ||
225 | __func__, plane->group->index, | ||
226 | plane - plane->group->planes); | ||
227 | continue; | ||
228 | } | ||
229 | |||
230 | plane_state = to_rcar_plane_state(plane->plane.state); | ||
231 | used_planes |= rcar_du_plane_hwmask(plane_state); | ||
232 | |||
233 | dev_dbg(rcdu->dev, | ||
234 | "%s: plane (%u,%u) uses %u hwplanes (index %d)\n", | ||
235 | __func__, plane->group->index, | ||
236 | plane - plane->group->planes, | ||
237 | plane_state->format ? | ||
238 | plane_state->format->planes : 0, | ||
239 | plane_state->hwindex); | ||
240 | } | ||
241 | |||
242 | group_free_planes[index] = 0xff & ~used_planes; | ||
243 | groups &= ~(1 << index); | ||
244 | |||
245 | dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n", | ||
246 | __func__, index, group_free_planes[index]); | ||
247 | } | ||
248 | |||
249 | /* Reallocate hardware planes for each plane that needs it. */ | ||
250 | for (i = 0; i < dev->mode_config.num_total_plane; ++i) { | ||
251 | struct rcar_du_plane_state *plane_state; | ||
252 | struct rcar_du_plane *plane; | ||
253 | unsigned int crtc_planes; | ||
254 | unsigned int free; | ||
255 | int idx; | ||
256 | |||
257 | if (!state->planes[i]) | ||
258 | continue; | ||
259 | |||
260 | plane = to_rcar_plane(state->planes[i]); | ||
261 | plane_state = to_rcar_plane_state(state->plane_states[i]); | ||
262 | |||
263 | dev_dbg(rcdu->dev, "%s: allocating plane (%u,%u)\n", __func__, | ||
264 | plane->group->index, plane - plane->group->planes); | ||
265 | |||
266 | /* Skip planes that are being disabled or don't need to be | ||
267 | * reallocated. | ||
268 | */ | ||
269 | if (!plane_state->format || | ||
270 | !rcar_du_plane_needs_realloc(plane, plane_state)) | ||
271 | continue; | ||
272 | |||
273 | /* Try to allocate the plane from the free planes currently | ||
274 | * associated with the target CRTC to avoid restarting the CRTC | ||
275 | * group and thus minimize flicker. If it fails fall back to | ||
276 | * allocating from all free planes. | ||
277 | */ | ||
278 | crtc_planes = to_rcar_crtc(plane_state->state.crtc)->index % 2 | ||
279 | ? plane->group->dptsr_planes | ||
280 | : ~plane->group->dptsr_planes; | ||
281 | free = group_free_planes[plane->group->index]; | ||
282 | |||
283 | idx = rcar_du_plane_hwalloc(plane, plane_state, | ||
284 | free & crtc_planes); | ||
285 | if (idx < 0) | ||
286 | idx = rcar_du_plane_hwalloc(plane, plane_state, | ||
287 | free); | ||
288 | if (idx < 0) { | ||
289 | dev_dbg(rcdu->dev, "%s: no available hardware plane\n", | ||
290 | __func__); | ||
291 | return idx; | ||
292 | } | ||
293 | |||
294 | dev_dbg(rcdu->dev, "%s: allocated %u hwplanes (index %u)\n", | ||
295 | __func__, plane_state->format->planes, idx); | ||
296 | |||
297 | plane_state->hwindex = idx; | ||
298 | |||
299 | group_free_planes[plane->group->index] &= | ||
300 | ~rcar_du_plane_hwmask(plane_state); | ||
301 | |||
302 | dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n", | ||
303 | __func__, plane->group->index, | ||
304 | group_free_planes[plane->group->index]); | ||
305 | } | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | /* ----------------------------------------------------------------------------- | ||
311 | * Plane Setup | ||
312 | */ | ||
313 | |||
28 | #define RCAR_DU_COLORKEY_NONE (0 << 24) | 314 | #define RCAR_DU_COLORKEY_NONE (0 << 24) |
29 | #define RCAR_DU_COLORKEY_SOURCE (1 << 24) | 315 | #define RCAR_DU_COLORKEY_SOURCE (1 << 24) |
30 | #define RCAR_DU_COLORKEY_MASK (1 << 24) | 316 | #define RCAR_DU_COLORKEY_MASK (1 << 24) |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/rcar-du/rcar_du_plane.h index e24e45828d6a..6a6460dffae4 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h | |||
@@ -71,6 +71,9 @@ to_rcar_plane_state(struct drm_plane_state *state) | |||
71 | return container_of(state, struct rcar_du_plane_state, state); | 71 | return container_of(state, struct rcar_du_plane_state, state); |
72 | } | 72 | } |
73 | 73 | ||
74 | int rcar_du_atomic_check_planes(struct drm_device *dev, | ||
75 | struct drm_atomic_state *state); | ||
76 | |||
74 | int rcar_du_planes_init(struct rcar_du_group *rgrp); | 77 | int rcar_du_planes_init(struct rcar_du_group *rgrp); |
75 | 78 | ||
76 | void rcar_du_plane_setup(struct rcar_du_plane *plane); | 79 | void rcar_du_plane_setup(struct rcar_du_plane *plane); |