2 * rcar_du_plane.c -- R-Car Display Unit Planes
4 * Copyright (C) 2013-2014 Renesas Electronics Corporation
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
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.
15 #include <drm/drm_atomic_helper.h>
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>
20 #include <drm/drm_plane_helper.h>
22 #include "rcar_du_drv.h"
23 #include "rcar_du_kms.h"
24 #include "rcar_du_plane.h"
25 #include "rcar_du_regs.h"
27 #define RCAR_DU_COLORKEY_NONE (0 << 24)
28 #define RCAR_DU_COLORKEY_SOURCE (1 << 24)
29 #define RCAR_DU_COLORKEY_MASK (1 << 24)
31 static inline struct rcar_du_plane
*to_rcar_plane(struct drm_plane
*plane
)
33 return container_of(plane
, struct rcar_du_plane
, plane
);
36 static u32
rcar_du_plane_read(struct rcar_du_group
*rgrp
,
37 unsigned int index
, u32 reg
)
39 return rcar_du_read(rgrp
->dev
,
40 rgrp
->mmio_offset
+ index
* PLANE_OFF
+ reg
);
43 static void rcar_du_plane_write(struct rcar_du_group
*rgrp
,
44 unsigned int index
, u32 reg
, u32 data
)
46 rcar_du_write(rgrp
->dev
, rgrp
->mmio_offset
+ index
* PLANE_OFF
+ reg
,
50 static int rcar_du_plane_reserve_check(struct rcar_du_plane
*plane
,
51 const struct rcar_du_format_info
*format
)
53 struct rcar_du_group
*rgrp
= plane
->group
;
58 mutex_lock(&rgrp
->planes
.lock
);
60 free
= rgrp
->planes
.free
;
62 if (plane
->hwindex
!= -1) {
63 free
|= 1 << plane
->hwindex
;
64 if (plane
->format
->planes
== 2)
65 free
|= 1 << ((plane
->hwindex
+ 1) % 8);
68 for (i
= 0; i
< ARRAY_SIZE(rgrp
->planes
.planes
); ++i
) {
69 if (!(free
& (1 << i
)))
72 if (format
->planes
== 1 || free
& (1 << ((i
+ 1) % 8)))
76 ret
= i
== ARRAY_SIZE(rgrp
->planes
.planes
) ? -EBUSY
: 0;
78 mutex_unlock(&rgrp
->planes
.lock
);
82 static int rcar_du_plane_reserve(struct rcar_du_plane
*plane
,
83 const struct rcar_du_format_info
*format
)
85 struct rcar_du_group
*rgrp
= plane
->group
;
89 mutex_lock(&rgrp
->planes
.lock
);
91 for (i
= 0; i
< RCAR_DU_NUM_HW_PLANES
; ++i
) {
92 if (!(rgrp
->planes
.free
& (1 << i
)))
95 if (format
->planes
== 1 ||
96 rgrp
->planes
.free
& (1 << ((i
+ 1) % 8)))
100 if (i
== RCAR_DU_NUM_HW_PLANES
)
103 rgrp
->planes
.free
&= ~(1 << i
);
104 if (format
->planes
== 2)
105 rgrp
->planes
.free
&= ~(1 << ((i
+ 1) % 8));
112 mutex_unlock(&rgrp
->planes
.lock
);
116 static void rcar_du_plane_release(struct rcar_du_plane
*plane
)
118 struct rcar_du_group
*rgrp
= plane
->group
;
120 if (plane
->hwindex
== -1)
123 mutex_lock(&rgrp
->planes
.lock
);
124 rgrp
->planes
.free
|= 1 << plane
->hwindex
;
125 if (plane
->format
->planes
== 2)
126 rgrp
->planes
.free
|= 1 << ((plane
->hwindex
+ 1) % 8);
127 mutex_unlock(&rgrp
->planes
.lock
);
132 static void rcar_du_plane_setup_fb(struct rcar_du_plane
*plane
)
134 struct drm_framebuffer
*fb
= plane
->plane
.state
->fb
;
135 struct rcar_du_group
*rgrp
= plane
->group
;
136 unsigned int src_x
= plane
->plane
.state
->src_x
>> 16;
137 unsigned int src_y
= plane
->plane
.state
->src_y
>> 16;
138 unsigned int index
= plane
->hwindex
;
139 struct drm_gem_cma_object
*gem
;
143 interlaced
= plane
->crtc
->mode
.flags
& DRM_MODE_FLAG_INTERLACE
;
145 /* Memory pitch (expressed in pixels). Must be doubled for interlaced
146 * operation with 32bpp formats.
148 if (plane
->format
->planes
== 2)
149 mwr
= fb
->pitches
[0];
151 mwr
= fb
->pitches
[0] * 8 / plane
->format
->bpp
;
153 if (interlaced
&& plane
->format
->bpp
== 32)
156 rcar_du_plane_write(rgrp
, index
, PnMWR
, mwr
);
158 /* The Y position is expressed in raster line units and must be doubled
159 * for 32bpp formats, according to the R8A7790 datasheet. No mention of
160 * doubling the Y position is found in the R8A7779 datasheet, but the
161 * rule seems to apply there as well.
163 * Despite not being documented, doubling seem not to be needed when
164 * operating in interlaced mode.
166 * Similarly, for the second plane, NV12 and NV21 formats seem to
167 * require a halved Y position value, in both progressive and interlaced
170 rcar_du_plane_write(rgrp
, index
, PnSPXR
, src_x
);
171 rcar_du_plane_write(rgrp
, index
, PnSPYR
, src_y
*
172 (!interlaced
&& plane
->format
->bpp
== 32 ? 2 : 1));
174 gem
= drm_fb_cma_get_gem_obj(fb
, 0);
175 rcar_du_plane_write(rgrp
, index
, PnDSA0R
, gem
->paddr
+ fb
->offsets
[0]);
177 if (plane
->format
->planes
== 2) {
178 index
= (index
+ 1) % 8;
180 rcar_du_plane_write(rgrp
, index
, PnMWR
, fb
->pitches
[0]);
182 rcar_du_plane_write(rgrp
, index
, PnSPXR
, src_x
);
183 rcar_du_plane_write(rgrp
, index
, PnSPYR
, src_y
*
184 (plane
->format
->bpp
== 16 ? 2 : 1) / 2);
186 gem
= drm_fb_cma_get_gem_obj(fb
, 1);
187 rcar_du_plane_write(rgrp
, index
, PnDSA0R
,
188 gem
->paddr
+ fb
->offsets
[1]);
192 static void rcar_du_plane_setup_mode(struct rcar_du_plane
*plane
,
195 struct rcar_du_plane_state
*state
=
196 to_rcar_du_plane_state(plane
->plane
.state
);
197 struct rcar_du_group
*rgrp
= plane
->group
;
201 /* The PnALPHAR register controls alpha-blending in 16bpp formats
202 * (ARGB1555 and XRGB1555).
204 * For ARGB, set the alpha value to 0, and enable alpha-blending when
205 * the A bit is 0. This maps A=0 to alpha=0 and A=1 to alpha=255.
207 * For XRGB, set the alpha value to the plane-wide alpha value and
208 * enable alpha-blending regardless of the X bit value.
210 if (plane
->format
->fourcc
!= DRM_FORMAT_XRGB1555
)
211 rcar_du_plane_write(rgrp
, index
, PnALPHAR
, PnALPHAR_ABIT_0
);
213 rcar_du_plane_write(rgrp
, index
, PnALPHAR
,
214 PnALPHAR_ABIT_X
| state
->alpha
);
216 pnmr
= PnMR_BM_MD
| plane
->format
->pnmr
;
218 /* Disable color keying when requested. YUV formats have the
219 * PnMR_SPIM_TP_OFF bit set in their pnmr field, disabling color keying
222 if ((state
->colorkey
& RCAR_DU_COLORKEY_MASK
) == RCAR_DU_COLORKEY_NONE
)
223 pnmr
|= PnMR_SPIM_TP_OFF
;
225 /* For packed YUV formats we need to select the U/V order. */
226 if (plane
->format
->fourcc
== DRM_FORMAT_YUYV
)
227 pnmr
|= PnMR_YCDF_YUYV
;
229 rcar_du_plane_write(rgrp
, index
, PnMR
, pnmr
);
231 switch (plane
->format
->fourcc
) {
232 case DRM_FORMAT_RGB565
:
233 colorkey
= ((state
->colorkey
& 0xf80000) >> 8)
234 | ((state
->colorkey
& 0x00fc00) >> 5)
235 | ((state
->colorkey
& 0x0000f8) >> 3);
236 rcar_du_plane_write(rgrp
, index
, PnTC2R
, colorkey
);
239 case DRM_FORMAT_ARGB1555
:
240 case DRM_FORMAT_XRGB1555
:
241 colorkey
= ((state
->colorkey
& 0xf80000) >> 9)
242 | ((state
->colorkey
& 0x00f800) >> 6)
243 | ((state
->colorkey
& 0x0000f8) >> 3);
244 rcar_du_plane_write(rgrp
, index
, PnTC2R
, colorkey
);
247 case DRM_FORMAT_XRGB8888
:
248 case DRM_FORMAT_ARGB8888
:
249 rcar_du_plane_write(rgrp
, index
, PnTC3R
,
250 PnTC3R_CODE
| (state
->colorkey
& 0xffffff));
255 static void __rcar_du_plane_setup(struct rcar_du_plane
*plane
,
258 struct rcar_du_group
*rgrp
= plane
->group
;
259 u32 ddcr2
= PnDDCR2_CODE
;
264 * The data format is selected by the DDDF field in PnMR and the EDF
267 ddcr4
= rcar_du_plane_read(rgrp
, index
, PnDDCR4
);
268 ddcr4
&= ~PnDDCR4_EDF_MASK
;
269 ddcr4
|= plane
->format
->edf
| PnDDCR4_CODE
;
271 rcar_du_plane_setup_mode(plane
, index
);
273 if (plane
->format
->planes
== 2) {
274 if (plane
->hwindex
!= index
) {
275 if (plane
->format
->fourcc
== DRM_FORMAT_NV12
||
276 plane
->format
->fourcc
== DRM_FORMAT_NV21
)
277 ddcr2
|= PnDDCR2_Y420
;
279 if (plane
->format
->fourcc
== DRM_FORMAT_NV21
)
280 ddcr2
|= PnDDCR2_NV21
;
282 ddcr2
|= PnDDCR2_DIVU
;
284 ddcr2
|= PnDDCR2_DIVY
;
288 rcar_du_plane_write(rgrp
, index
, PnDDCR2
, ddcr2
);
289 rcar_du_plane_write(rgrp
, index
, PnDDCR4
, ddcr4
);
291 /* Destination position and size */
292 rcar_du_plane_write(rgrp
, index
, PnDSXR
, plane
->plane
.state
->crtc_w
);
293 rcar_du_plane_write(rgrp
, index
, PnDSYR
, plane
->plane
.state
->crtc_h
);
294 rcar_du_plane_write(rgrp
, index
, PnDPXR
, plane
->plane
.state
->crtc_x
);
295 rcar_du_plane_write(rgrp
, index
, PnDPYR
, plane
->plane
.state
->crtc_y
);
297 /* Wrap-around and blinking, disabled */
298 rcar_du_plane_write(rgrp
, index
, PnWASPR
, 0);
299 rcar_du_plane_write(rgrp
, index
, PnWAMWR
, 4095);
300 rcar_du_plane_write(rgrp
, index
, PnBTR
, 0);
301 rcar_du_plane_write(rgrp
, index
, PnMLR
, 0);
304 void rcar_du_plane_setup(struct rcar_du_plane
*plane
)
306 __rcar_du_plane_setup(plane
, plane
->hwindex
);
307 if (plane
->format
->planes
== 2)
308 __rcar_du_plane_setup(plane
, (plane
->hwindex
+ 1) % 8);
310 rcar_du_plane_setup_fb(plane
);
313 static int rcar_du_plane_atomic_check(struct drm_plane
*plane
,
314 struct drm_plane_state
*state
)
316 struct rcar_du_plane
*rplane
= to_rcar_plane(plane
);
317 struct rcar_du_device
*rcdu
= rplane
->group
->dev
;
318 const struct rcar_du_format_info
*format
;
319 unsigned int nplanes
;
322 if (!state
->fb
|| !state
->crtc
)
325 if (state
->src_w
>> 16 != state
->crtc_w
||
326 state
->src_h
>> 16 != state
->crtc_h
) {
327 dev_dbg(rcdu
->dev
, "%s: scaling not supported\n", __func__
);
331 format
= rcar_du_format_info(state
->fb
->pixel_format
);
332 if (format
== NULL
) {
333 dev_dbg(rcdu
->dev
, "%s: unsupported format %08x\n", __func__
,
334 state
->fb
->pixel_format
);
338 nplanes
= rplane
->format
? rplane
->format
->planes
: 0;
340 /* If the number of required planes has changed we will need to
341 * reallocate hardware planes. Ensure free planes are available.
343 if (format
->planes
!= nplanes
) {
344 ret
= rcar_du_plane_reserve_check(rplane
, format
);
346 dev_dbg(rcdu
->dev
, "%s: no available hardware plane\n",
355 static void rcar_du_plane_disable(struct rcar_du_plane
*rplane
)
357 if (!rplane
->enabled
)
360 mutex_lock(&rplane
->group
->planes
.lock
);
361 rplane
->enabled
= false;
362 mutex_unlock(&rplane
->group
->planes
.lock
);
364 rcar_du_plane_release(rplane
);
367 rplane
->format
= NULL
;
370 static void rcar_du_plane_atomic_update(struct drm_plane
*plane
,
371 struct drm_plane_state
*old_state
)
373 struct rcar_du_plane
*rplane
= to_rcar_plane(plane
);
374 struct drm_plane_state
*state
= plane
->state
;
375 const struct rcar_du_format_info
*format
;
376 unsigned int nplanes
;
379 rcar_du_plane_disable(rplane
);
383 format
= rcar_du_format_info(state
->fb
->pixel_format
);
384 nplanes
= rplane
->format
? rplane
->format
->planes
: 0;
386 /* Reallocate hardware planes if the number of required planes has
389 if (format
->planes
!= nplanes
) {
390 rcar_du_plane_release(rplane
);
391 rcar_du_plane_reserve(rplane
, format
);
394 rplane
->crtc
= state
->crtc
;
395 rplane
->format
= format
;
397 rcar_du_plane_setup(rplane
);
399 mutex_lock(&rplane
->group
->planes
.lock
);
400 rplane
->enabled
= true;
401 mutex_unlock(&rplane
->group
->planes
.lock
);
404 static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs
= {
405 .atomic_check
= rcar_du_plane_atomic_check
,
406 .atomic_update
= rcar_du_plane_atomic_update
,
409 static void rcar_du_plane_reset(struct drm_plane
*plane
)
411 struct rcar_du_plane_state
*state
;
413 if (plane
->state
&& plane
->state
->fb
)
414 drm_framebuffer_unreference(plane
->state
->fb
);
419 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
424 state
->colorkey
= RCAR_DU_COLORKEY_NONE
;
425 state
->zpos
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
? 0 : 1;
427 plane
->state
= &state
->state
;
428 plane
->state
->plane
= plane
;
431 static struct drm_plane_state
*
432 rcar_du_plane_atomic_duplicate_state(struct drm_plane
*plane
)
434 struct rcar_du_plane_state
*state
;
435 struct rcar_du_plane_state
*copy
;
437 state
= to_rcar_du_plane_state(plane
->state
);
438 copy
= kmemdup(state
, sizeof(*state
), GFP_KERNEL
);
443 drm_framebuffer_reference(copy
->state
.fb
);
448 static void rcar_du_plane_atomic_destroy_state(struct drm_plane
*plane
,
449 struct drm_plane_state
*state
)
451 kfree(to_rcar_du_plane_state(state
));
454 static int rcar_du_plane_atomic_set_property(struct drm_plane
*plane
,
455 struct drm_plane_state
*state
,
456 struct drm_property
*property
,
459 struct rcar_du_plane_state
*rstate
= to_rcar_du_plane_state(state
);
460 struct rcar_du_plane
*rplane
= to_rcar_plane(plane
);
461 struct rcar_du_group
*rgrp
= rplane
->group
;
463 if (property
== rgrp
->planes
.alpha
)
465 else if (property
== rgrp
->planes
.colorkey
)
466 rstate
->colorkey
= val
;
467 else if (property
== rgrp
->planes
.zpos
)
475 static int rcar_du_plane_atomic_get_property(struct drm_plane
*plane
,
476 const struct drm_plane_state
*state
, struct drm_property
*property
,
479 const struct rcar_du_plane_state
*rstate
=
480 container_of(state
, const struct rcar_du_plane_state
, state
);
481 struct rcar_du_plane
*rplane
= to_rcar_plane(plane
);
482 struct rcar_du_group
*rgrp
= rplane
->group
;
484 if (property
== rgrp
->planes
.alpha
)
485 *val
= rstate
->alpha
;
486 else if (property
== rgrp
->planes
.colorkey
)
487 *val
= rstate
->colorkey
;
488 else if (property
== rgrp
->planes
.zpos
)
496 static const struct drm_plane_funcs rcar_du_plane_funcs
= {
497 .update_plane
= drm_atomic_helper_update_plane
,
498 .disable_plane
= drm_atomic_helper_disable_plane
,
499 .reset
= rcar_du_plane_reset
,
500 .set_property
= drm_atomic_helper_plane_set_property
,
501 .destroy
= drm_plane_cleanup
,
502 .atomic_duplicate_state
= rcar_du_plane_atomic_duplicate_state
,
503 .atomic_destroy_state
= rcar_du_plane_atomic_destroy_state
,
504 .atomic_set_property
= rcar_du_plane_atomic_set_property
,
505 .atomic_get_property
= rcar_du_plane_atomic_get_property
,
508 static const uint32_t formats
[] = {
521 int rcar_du_planes_init(struct rcar_du_group
*rgrp
)
523 struct rcar_du_planes
*planes
= &rgrp
->planes
;
524 struct rcar_du_device
*rcdu
= rgrp
->dev
;
525 unsigned int num_planes
;
526 unsigned int num_crtcs
;
531 mutex_init(&planes
->lock
);
535 drm_property_create_range(rcdu
->ddev
, 0, "alpha", 0, 255);
536 if (planes
->alpha
== NULL
)
539 /* The color key is expressed as an RGB888 triplet stored in a 32-bit
540 * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0)
541 * or enable source color keying (1).
544 drm_property_create_range(rcdu
->ddev
, 0, "colorkey",
546 if (planes
->colorkey
== NULL
)
550 drm_property_create_range(rcdu
->ddev
, 0, "zpos", 1, 7);
551 if (planes
->zpos
== NULL
)
554 /* Create one primary plane per in this group CRTC and seven overlay
557 num_crtcs
= min(rcdu
->num_crtcs
- 2 * rgrp
->index
, 2U);
558 num_planes
= num_crtcs
+ 7;
560 crtcs
= ((1 << rcdu
->num_crtcs
) - 1) & (3 << (2 * rgrp
->index
));
562 for (i
= 0; i
< num_planes
; ++i
) {
563 enum drm_plane_type type
= i
< num_crtcs
564 ? DRM_PLANE_TYPE_PRIMARY
565 : DRM_PLANE_TYPE_OVERLAY
;
566 struct rcar_du_plane
*plane
= &planes
->planes
[i
];
571 ret
= drm_universal_plane_init(rcdu
->ddev
, &plane
->plane
, crtcs
,
572 &rcar_du_plane_funcs
, formats
,
573 ARRAY_SIZE(formats
), type
);
577 drm_plane_helper_add(&plane
->plane
,
578 &rcar_du_plane_helper_funcs
);
580 if (type
== DRM_PLANE_TYPE_PRIMARY
)
583 drm_object_attach_property(&plane
->plane
.base
,
585 drm_object_attach_property(&plane
->plane
.base
,
587 RCAR_DU_COLORKEY_NONE
);
588 drm_object_attach_property(&plane
->plane
.base
,