aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/rcar-du/rcar_du_kms.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2015-07-27 08:34:18 -0400
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2016-02-19 19:58:56 -0500
commitab334e137c31440e3a826e0d3c2753425f18641b (patch)
tree77671692d81686641543738a96d91c377bd1dd02 /drivers/gpu/drm/rcar-du/rcar_du_kms.c
parent2af0394409faec95e80d6061a8a9fe95565be358 (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/drm/rcar-du/rcar_du_kms.c')
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c276
1 files changed, 1 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
219static 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
241static 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 */
267static 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
300static int rcar_du_atomic_check(struct drm_device *dev, 195static 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
481struct rcar_du_commit { 207struct rcar_du_commit {