drm: rcar-du: Restart the DU group when a plane source changes
[deliverable/linux.git] / drivers / gpu / drm / rcar-du / rcar_du_plane.c
CommitLineData
4bf8e196
LP
1/*
2 * rcar_du_plane.c -- R-Car Display Unit Planes
3 *
36d50464 4 * Copyright (C) 2013-2014 Renesas Electronics Corporation
4bf8e196
LP
5 *
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <drm/drmP.h>
3e8da87d 15#include <drm/drm_atomic_helper.h>
4bf8e196
LP
16#include <drm/drm_crtc.h>
17#include <drm/drm_crtc_helper.h>
18#include <drm/drm_fb_cma_helper.h>
19#include <drm/drm_gem_cma_helper.h>
920888a2 20#include <drm/drm_plane_helper.h>
4bf8e196
LP
21
22#include "rcar_du_drv.h"
34a04f2b 23#include "rcar_du_group.h"
4bf8e196
LP
24#include "rcar_du_kms.h"
25#include "rcar_du_plane.h"
26#include "rcar_du_regs.h"
27
28#define RCAR_DU_COLORKEY_NONE (0 << 24)
29#define RCAR_DU_COLORKEY_SOURCE (1 << 24)
30#define RCAR_DU_COLORKEY_MASK (1 << 24)
31
cb2025d2 32static void rcar_du_plane_write(struct rcar_du_group *rgrp,
4bf8e196
LP
33 unsigned int index, u32 reg, u32 data)
34{
cb2025d2
LP
35 rcar_du_write(rgrp->dev, rgrp->mmio_offset + index * PLANE_OFF + reg,
36 data);
4bf8e196
LP
37}
38
34a04f2b
LP
39static void rcar_du_plane_setup_scanout(struct rcar_du_group *rgrp,
40 const struct rcar_du_plane_state *state)
4bf8e196 41{
5bfcbce0
LP
42 unsigned int src_x = state->state.src_x >> 16;
43 unsigned int src_y = state->state.src_y >> 16;
5ee5a81d 44 unsigned int index = state->hwindex;
2f13c529 45 unsigned int pitch;
906eff7f 46 bool interlaced;
2f13c529 47 u32 dma[2];
eb86301f 48
5bfcbce0 49 interlaced = state->state.crtc->state->adjusted_mode.flags
47094194 50 & DRM_MODE_FLAG_INTERLACE;
906eff7f 51
34a04f2b
LP
52 if (state->source == RCAR_DU_PLANE_MEMORY) {
53 struct drm_framebuffer *fb = state->state.fb;
54 struct drm_gem_cma_object *gem;
55 unsigned int i;
56
57 if (state->format->planes == 2)
58 pitch = fb->pitches[0];
59 else
60 pitch = fb->pitches[0] * 8 / state->format->bpp;
eb86301f 61
34a04f2b
LP
62 for (i = 0; i < state->format->planes; ++i) {
63 gem = drm_fb_cma_get_gem_obj(fb, i);
64 dma[i] = gem->paddr + fb->offsets[i];
65 }
66 } else {
67 pitch = state->state.src_w >> 16;
68 dma[0] = 0;
69 dma[1] = 0;
2f13c529 70 }
906eff7f 71
34a04f2b
LP
72 /* Memory pitch (expressed in pixels). Must be doubled for interlaced
73 * operation with 32bpp formats.
74 */
2f13c529
LP
75 rcar_du_plane_write(rgrp, index, PnMWR,
76 (interlaced && state->format->bpp == 32) ?
77 pitch * 2 : pitch);
4bf8e196 78
9e7db06d
LP
79 /* The Y position is expressed in raster line units and must be doubled
80 * for 32bpp formats, according to the R8A7790 datasheet. No mention of
81 * doubling the Y position is found in the R8A7779 datasheet, but the
82 * rule seems to apply there as well.
83 *
906eff7f
LP
84 * Despite not being documented, doubling seem not to be needed when
85 * operating in interlaced mode.
86 *
9e7db06d 87 * Similarly, for the second plane, NV12 and NV21 formats seem to
906eff7f
LP
88 * require a halved Y position value, in both progressive and interlaced
89 * modes.
4bf8e196 90 */
287bdf03
LP
91 rcar_du_plane_write(rgrp, index, PnSPXR, src_x);
92 rcar_du_plane_write(rgrp, index, PnSPYR, src_y *
5bfcbce0 93 (!interlaced && state->format->bpp == 32 ? 2 : 1));
f398f344 94
2f13c529 95 rcar_du_plane_write(rgrp, index, PnDSA0R, dma[0]);
4bf8e196 96
5bfcbce0 97 if (state->format->planes == 2) {
4bf8e196
LP
98 index = (index + 1) % 8;
99
2f13c529 100 rcar_du_plane_write(rgrp, index, PnMWR, pitch);
49785e25 101
287bdf03
LP
102 rcar_du_plane_write(rgrp, index, PnSPXR, src_x);
103 rcar_du_plane_write(rgrp, index, PnSPYR, src_y *
5bfcbce0 104 (state->format->bpp == 16 ? 2 : 1) / 2);
eb86301f 105
2f13c529 106 rcar_du_plane_write(rgrp, index, PnDSA0R, dma[1]);
4bf8e196
LP
107 }
108}
109
34a04f2b
LP
110static void rcar_du_plane_setup_mode(struct rcar_du_group *rgrp,
111 unsigned int index,
112 const struct rcar_du_plane_state *state)
4bf8e196 113{
4bf8e196
LP
114 u32 colorkey;
115 u32 pnmr;
116
117 /* The PnALPHAR register controls alpha-blending in 16bpp formats
118 * (ARGB1555 and XRGB1555).
119 *
120 * For ARGB, set the alpha value to 0, and enable alpha-blending when
121 * the A bit is 0. This maps A=0 to alpha=0 and A=1 to alpha=255.
122 *
123 * For XRGB, set the alpha value to the plane-wide alpha value and
124 * enable alpha-blending regardless of the X bit value.
125 */
5bfcbce0 126 if (state->format->fourcc != DRM_FORMAT_XRGB1555)
cb2025d2 127 rcar_du_plane_write(rgrp, index, PnALPHAR, PnALPHAR_ABIT_0);
4bf8e196 128 else
cb2025d2 129 rcar_du_plane_write(rgrp, index, PnALPHAR,
4407cc02 130 PnALPHAR_ABIT_X | state->alpha);
4bf8e196 131
5bfcbce0 132 pnmr = PnMR_BM_MD | state->format->pnmr;
4bf8e196
LP
133
134 /* Disable color keying when requested. YUV formats have the
135 * PnMR_SPIM_TP_OFF bit set in their pnmr field, disabling color keying
136 * automatically.
137 */
4407cc02 138 if ((state->colorkey & RCAR_DU_COLORKEY_MASK) == RCAR_DU_COLORKEY_NONE)
4bf8e196
LP
139 pnmr |= PnMR_SPIM_TP_OFF;
140
141 /* For packed YUV formats we need to select the U/V order. */
5bfcbce0 142 if (state->format->fourcc == DRM_FORMAT_YUYV)
4bf8e196
LP
143 pnmr |= PnMR_YCDF_YUYV;
144
cb2025d2 145 rcar_du_plane_write(rgrp, index, PnMR, pnmr);
4bf8e196 146
5bfcbce0 147 switch (state->format->fourcc) {
4bf8e196 148 case DRM_FORMAT_RGB565:
4407cc02
LP
149 colorkey = ((state->colorkey & 0xf80000) >> 8)
150 | ((state->colorkey & 0x00fc00) >> 5)
151 | ((state->colorkey & 0x0000f8) >> 3);
cb2025d2 152 rcar_du_plane_write(rgrp, index, PnTC2R, colorkey);
4bf8e196
LP
153 break;
154
155 case DRM_FORMAT_ARGB1555:
156 case DRM_FORMAT_XRGB1555:
4407cc02
LP
157 colorkey = ((state->colorkey & 0xf80000) >> 9)
158 | ((state->colorkey & 0x00f800) >> 6)
159 | ((state->colorkey & 0x0000f8) >> 3);
cb2025d2 160 rcar_du_plane_write(rgrp, index, PnTC2R, colorkey);
4bf8e196
LP
161 break;
162
163 case DRM_FORMAT_XRGB8888:
164 case DRM_FORMAT_ARGB8888:
cb2025d2 165 rcar_du_plane_write(rgrp, index, PnTC3R,
4407cc02 166 PnTC3R_CODE | (state->colorkey & 0xffffff));
4bf8e196
LP
167 break;
168 }
169}
170
34a04f2b
LP
171static void rcar_du_plane_setup_format(struct rcar_du_group *rgrp,
172 unsigned int index,
173 const struct rcar_du_plane_state *state)
4bf8e196 174{
4bf8e196
LP
175 u32 ddcr2 = PnDDCR2_CODE;
176 u32 ddcr4;
4bf8e196
LP
177
178 /* Data format
179 *
180 * The data format is selected by the DDDF field in PnMR and the EDF
181 * field in DDCR4.
182 */
4bf8e196 183
34a04f2b 184 rcar_du_plane_setup_mode(rgrp, index, state);
4bf8e196 185
5bfcbce0 186 if (state->format->planes == 2) {
5ee5a81d 187 if (state->hwindex != index) {
5bfcbce0
LP
188 if (state->format->fourcc == DRM_FORMAT_NV12 ||
189 state->format->fourcc == DRM_FORMAT_NV21)
4bf8e196
LP
190 ddcr2 |= PnDDCR2_Y420;
191
5bfcbce0 192 if (state->format->fourcc == DRM_FORMAT_NV21)
4bf8e196
LP
193 ddcr2 |= PnDDCR2_NV21;
194
195 ddcr2 |= PnDDCR2_DIVU;
196 } else {
197 ddcr2 |= PnDDCR2_DIVY;
198 }
199 }
200
cb2025d2 201 rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2);
ff967363
LP
202
203 ddcr4 = state->format->edf | PnDDCR4_CODE;
34a04f2b
LP
204 if (state->source != RCAR_DU_PLANE_MEMORY)
205 ddcr4 |= PnDDCR4_VSPS;
ff967363 206
cb2025d2 207 rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4);
4bf8e196 208
4bf8e196 209 /* Destination position and size */
34a04f2b
LP
210 rcar_du_plane_write(rgrp, index, PnDSXR, state->state.crtc_w);
211 rcar_du_plane_write(rgrp, index, PnDSYR, state->state.crtc_h);
212 rcar_du_plane_write(rgrp, index, PnDPXR, state->state.crtc_x);
213 rcar_du_plane_write(rgrp, index, PnDPYR, state->state.crtc_y);
4bf8e196
LP
214
215 /* Wrap-around and blinking, disabled */
cb2025d2
LP
216 rcar_du_plane_write(rgrp, index, PnWASPR, 0);
217 rcar_du_plane_write(rgrp, index, PnWAMWR, 4095);
218 rcar_du_plane_write(rgrp, index, PnBTR, 0);
219 rcar_du_plane_write(rgrp, index, PnMLR, 0);
4bf8e196
LP
220}
221
222void rcar_du_plane_setup(struct rcar_du_plane *plane)
223{
5bfcbce0 224 struct rcar_du_plane_state *state =
ec69a406 225 to_rcar_plane_state(plane->plane.state);
34a04f2b 226 struct rcar_du_group *rgrp = plane->group;
5bfcbce0 227
34a04f2b 228 rcar_du_plane_setup_format(rgrp, state->hwindex, state);
5bfcbce0 229 if (state->format->planes == 2)
34a04f2b
LP
230 rcar_du_plane_setup_format(rgrp, (state->hwindex + 1) % 8,
231 state);
232
233 rcar_du_plane_setup_scanout(rgrp, state);
4bf8e196 234
34a04f2b
LP
235 if (state->source == RCAR_DU_PLANE_VSPD1) {
236 unsigned int vspd1_sink = rgrp->index ? 2 : 0;
237 struct rcar_du_device *rcdu = rgrp->dev;
238
239 if (rcdu->vspd1_sink != vspd1_sink) {
240 rcdu->vspd1_sink = vspd1_sink;
241 rcar_du_set_dpad0_vsp1_routing(rcdu);
242 }
243 }
4bf8e196
LP
244}
245
920888a2
LP
246static int rcar_du_plane_atomic_check(struct drm_plane *plane,
247 struct drm_plane_state *state)
4bf8e196 248{
ec69a406 249 struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
4bf8e196 250 struct rcar_du_plane *rplane = to_rcar_plane(plane);
cb2025d2 251 struct rcar_du_device *rcdu = rplane->group->dev;
4bf8e196 252
5ee5a81d
LP
253 if (!state->fb || !state->crtc) {
254 rstate->format = NULL;
920888a2 255 return 0;
5ee5a81d 256 }
917de180 257
920888a2
LP
258 if (state->src_w >> 16 != state->crtc_w ||
259 state->src_h >> 16 != state->crtc_h) {
260 dev_dbg(rcdu->dev, "%s: scaling not supported\n", __func__);
4bf8e196
LP
261 return -EINVAL;
262 }
263
5ee5a81d
LP
264 rstate->format = rcar_du_format_info(state->fb->pixel_format);
265 if (rstate->format == NULL) {
920888a2
LP
266 dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__,
267 state->fb->pixel_format);
4bf8e196
LP
268 return -EINVAL;
269 }
270
4bf8e196
LP
271 return 0;
272}
273
920888a2
LP
274static void rcar_du_plane_atomic_update(struct drm_plane *plane,
275 struct drm_plane_state *old_state)
276{
277 struct rcar_du_plane *rplane = to_rcar_plane(plane);
2af03944
LP
278 struct rcar_du_plane_state *old_rstate;
279 struct rcar_du_plane_state *new_rstate;
5bfcbce0 280
2af03944
LP
281 if (!plane->state->crtc)
282 return;
283
284 rcar_du_plane_setup(rplane);
285
286 /* Check whether the source has changed from memory to live source or
287 * from live source to memory. The source has been configured by the
288 * VSPS bit in the PnDDCR4 register. Although the datasheet states that
289 * the bit is updated during vertical blanking, it seems that updates
290 * only occur when the DU group is held in reset through the DSYSR.DRES
291 * bit. We thus need to restart the group if the source changes.
292 */
293 old_rstate = to_rcar_plane_state(old_state);
294 new_rstate = to_rcar_plane_state(plane->state);
295
296 if ((old_rstate->source == RCAR_DU_PLANE_MEMORY) !=
297 (new_rstate->source == RCAR_DU_PLANE_MEMORY))
298 rplane->group->need_restart = true;
4bf8e196
LP
299}
300
920888a2
LP
301static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = {
302 .atomic_check = rcar_du_plane_atomic_check,
303 .atomic_update = rcar_du_plane_atomic_update,
304};
305
4407cc02
LP
306static struct drm_plane_state *
307rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
4bf8e196 308{
4407cc02
LP
309 struct rcar_du_plane_state *state;
310 struct rcar_du_plane_state *copy;
4bf8e196 311
263b39fe
LP
312 if (WARN_ON(!plane->state))
313 return NULL;
314
ec69a406 315 state = to_rcar_plane_state(plane->state);
4407cc02
LP
316 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
317 if (copy == NULL)
318 return NULL;
319
263b39fe 320 __drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
4bf8e196 321
4407cc02 322 return &copy->state;
4bf8e196
LP
323}
324
4407cc02
LP
325static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane,
326 struct drm_plane_state *state)
4bf8e196 327{
263b39fe 328 __drm_atomic_helper_plane_destroy_state(plane, state);
ec69a406 329 kfree(to_rcar_plane_state(state));
4407cc02 330}
4bf8e196 331
a32a3c80
LP
332static void rcar_du_plane_reset(struct drm_plane *plane)
333{
334 struct rcar_du_plane_state *state;
335
336 if (plane->state) {
337 rcar_du_plane_atomic_destroy_state(plane, plane->state);
338 plane->state = NULL;
339 }
340
341 state = kzalloc(sizeof(*state), GFP_KERNEL);
342 if (state == NULL)
343 return;
344
345 state->hwindex = -1;
af8ad962 346 state->source = RCAR_DU_PLANE_MEMORY;
a32a3c80
LP
347 state->alpha = 255;
348 state->colorkey = RCAR_DU_COLORKEY_NONE;
349 state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
350
351 plane->state = &state->state;
352 plane->state->plane = plane;
353}
354
4407cc02
LP
355static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
356 struct drm_plane_state *state,
357 struct drm_property *property,
358 uint64_t val)
359{
ec69a406 360 struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
9f6aee95 361 struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
4bf8e196 362
9f6aee95 363 if (property == rcdu->props.alpha)
4407cc02 364 rstate->alpha = val;
9f6aee95 365 else if (property == rcdu->props.colorkey)
4407cc02 366 rstate->colorkey = val;
9f6aee95 367 else if (property == rcdu->props.zpos)
4407cc02
LP
368 rstate->zpos = val;
369 else
370 return -EINVAL;
4bf8e196 371
4407cc02 372 return 0;
4bf8e196
LP
373}
374
4407cc02
LP
375static int rcar_du_plane_atomic_get_property(struct drm_plane *plane,
376 const struct drm_plane_state *state, struct drm_property *property,
377 uint64_t *val)
4bf8e196 378{
4407cc02
LP
379 const struct rcar_du_plane_state *rstate =
380 container_of(state, const struct rcar_du_plane_state, state);
9f6aee95 381 struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
4bf8e196 382
9f6aee95 383 if (property == rcdu->props.alpha)
4407cc02 384 *val = rstate->alpha;
9f6aee95 385 else if (property == rcdu->props.colorkey)
4407cc02 386 *val = rstate->colorkey;
9f6aee95 387 else if (property == rcdu->props.zpos)
4407cc02 388 *val = rstate->zpos;
4bf8e196
LP
389 else
390 return -EINVAL;
391
392 return 0;
393}
394
395static const struct drm_plane_funcs rcar_du_plane_funcs = {
336d04a1
LP
396 .update_plane = drm_atomic_helper_update_plane,
397 .disable_plane = drm_atomic_helper_disable_plane,
4407cc02
LP
398 .reset = rcar_du_plane_reset,
399 .set_property = drm_atomic_helper_plane_set_property,
4bf8e196 400 .destroy = drm_plane_cleanup,
4407cc02
LP
401 .atomic_duplicate_state = rcar_du_plane_atomic_duplicate_state,
402 .atomic_destroy_state = rcar_du_plane_atomic_destroy_state,
403 .atomic_set_property = rcar_du_plane_atomic_set_property,
404 .atomic_get_property = rcar_du_plane_atomic_get_property,
4bf8e196
LP
405};
406
407static const uint32_t formats[] = {
408 DRM_FORMAT_RGB565,
409 DRM_FORMAT_ARGB1555,
410 DRM_FORMAT_XRGB1555,
411 DRM_FORMAT_XRGB8888,
412 DRM_FORMAT_ARGB8888,
413 DRM_FORMAT_UYVY,
414 DRM_FORMAT_YUYV,
415 DRM_FORMAT_NV12,
416 DRM_FORMAT_NV21,
417 DRM_FORMAT_NV16,
418};
419
cb2025d2 420int rcar_du_planes_init(struct rcar_du_group *rgrp)
4bf8e196 421{
cb2025d2 422 struct rcar_du_device *rcdu = rgrp->dev;
917de180 423 unsigned int crtcs;
4bf8e196 424 unsigned int i;
917de180 425 int ret;
4bf8e196 426
9f6aee95 427 /* Create one primary plane per CRTC in this group and seven overlay
917de180
LP
428 * planes.
429 */
d6aed574 430 rgrp->num_planes = rgrp->num_crtcs + 7;
917de180
LP
431
432 crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index));
433
d6aed574 434 for (i = 0; i < rgrp->num_planes; ++i) {
fe6fbe9a 435 enum drm_plane_type type = i < rgrp->num_crtcs
917de180
LP
436 ? DRM_PLANE_TYPE_PRIMARY
437 : DRM_PLANE_TYPE_OVERLAY;
99caede1 438 struct rcar_du_plane *plane = &rgrp->planes[i];
4bf8e196 439
cb2025d2 440 plane->group = rgrp;
4bf8e196 441
917de180
LP
442 ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs,
443 &rcar_du_plane_funcs, formats,
b0b3b795
VS
444 ARRAY_SIZE(formats), type,
445 NULL);
4bf8e196
LP
446 if (ret < 0)
447 return ret;
448
920888a2
LP
449 drm_plane_helper_add(&plane->plane,
450 &rcar_du_plane_helper_funcs);
451
917de180
LP
452 if (type == DRM_PLANE_TYPE_PRIMARY)
453 continue;
454
4bf8e196 455 drm_object_attach_property(&plane->plane.base,
9f6aee95 456 rcdu->props.alpha, 255);
4bf8e196 457 drm_object_attach_property(&plane->plane.base,
9f6aee95 458 rcdu->props.colorkey,
4bf8e196
LP
459 RCAR_DU_COLORKEY_NONE);
460 drm_object_attach_property(&plane->plane.base,
9f6aee95 461 rcdu->props.zpos, 1);
4bf8e196
LP
462 }
463
464 return 0;
465}
This page took 0.17707 seconds and 5 git commands to generate.