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_crtc.h>
16 #include <drm/drm_crtc_helper.h>
17 #include <drm/drm_fb_cma_helper.h>
18 #include <drm/drm_gem_cma_helper.h>
20 #include "rcar_du_drv.h"
21 #include "rcar_du_kms.h"
22 #include "rcar_du_plane.h"
23 #include "rcar_du_regs.h"
25 #define RCAR_DU_COLORKEY_NONE (0 << 24)
26 #define RCAR_DU_COLORKEY_SOURCE (1 << 24)
27 #define RCAR_DU_COLORKEY_MASK (1 << 24)
29 struct rcar_du_kms_plane
{
30 struct drm_plane plane
;
31 struct rcar_du_plane
*hwplane
;
34 static inline struct rcar_du_plane
*to_rcar_plane(struct drm_plane
*plane
)
36 return container_of(plane
, struct rcar_du_kms_plane
, plane
)->hwplane
;
39 static u32
rcar_du_plane_read(struct rcar_du_group
*rgrp
,
40 unsigned int index
, u32 reg
)
42 return rcar_du_read(rgrp
->dev
,
43 rgrp
->mmio_offset
+ index
* PLANE_OFF
+ reg
);
46 static void rcar_du_plane_write(struct rcar_du_group
*rgrp
,
47 unsigned int index
, u32 reg
, u32 data
)
49 rcar_du_write(rgrp
->dev
, rgrp
->mmio_offset
+ index
* PLANE_OFF
+ reg
,
53 int rcar_du_plane_reserve(struct rcar_du_plane
*plane
,
54 const struct rcar_du_format_info
*format
)
56 struct rcar_du_group
*rgrp
= plane
->group
;
60 mutex_lock(&rgrp
->planes
.lock
);
62 for (i
= 0; i
< ARRAY_SIZE(rgrp
->planes
.planes
); ++i
) {
63 if (!(rgrp
->planes
.free
& (1 << i
)))
66 if (format
->planes
== 1 ||
67 rgrp
->planes
.free
& (1 << ((i
+ 1) % 8)))
71 if (i
== ARRAY_SIZE(rgrp
->planes
.planes
))
74 rgrp
->planes
.free
&= ~(1 << i
);
75 if (format
->planes
== 2)
76 rgrp
->planes
.free
&= ~(1 << ((i
+ 1) % 8));
83 mutex_unlock(&rgrp
->planes
.lock
);
87 void rcar_du_plane_release(struct rcar_du_plane
*plane
)
89 struct rcar_du_group
*rgrp
= plane
->group
;
91 if (plane
->hwindex
== -1)
94 mutex_lock(&rgrp
->planes
.lock
);
95 rgrp
->planes
.free
|= 1 << plane
->hwindex
;
96 if (plane
->format
->planes
== 2)
97 rgrp
->planes
.free
|= 1 << ((plane
->hwindex
+ 1) % 8);
98 mutex_unlock(&rgrp
->planes
.lock
);
103 void rcar_du_plane_update_base(struct rcar_du_plane
*plane
)
105 struct rcar_du_group
*rgrp
= plane
->group
;
106 unsigned int index
= plane
->hwindex
;
110 interlaced
= plane
->crtc
->mode
.flags
& DRM_MODE_FLAG_INTERLACE
;
112 /* Memory pitch (expressed in pixels). Must be doubled for interlaced
113 * operation with 32bpp formats.
115 if (plane
->format
->planes
== 2)
118 mwr
= plane
->pitch
* 8 / plane
->format
->bpp
;
120 if (interlaced
&& plane
->format
->bpp
== 32)
123 rcar_du_plane_write(rgrp
, index
, PnMWR
, mwr
);
125 /* The Y position is expressed in raster line units and must be doubled
126 * for 32bpp formats, according to the R8A7790 datasheet. No mention of
127 * doubling the Y position is found in the R8A7779 datasheet, but the
128 * rule seems to apply there as well.
130 * Despite not being documented, doubling seem not to be needed when
131 * operating in interlaced mode.
133 * Similarly, for the second plane, NV12 and NV21 formats seem to
134 * require a halved Y position value, in both progressive and interlaced
137 rcar_du_plane_write(rgrp
, index
, PnSPXR
, plane
->src_x
);
138 rcar_du_plane_write(rgrp
, index
, PnSPYR
, plane
->src_y
*
139 (!interlaced
&& plane
->format
->bpp
== 32 ? 2 : 1));
140 rcar_du_plane_write(rgrp
, index
, PnDSA0R
, plane
->dma
[0]);
142 if (plane
->format
->planes
== 2) {
143 index
= (index
+ 1) % 8;
145 rcar_du_plane_write(rgrp
, index
, PnMWR
, plane
->pitch
);
147 rcar_du_plane_write(rgrp
, index
, PnSPXR
, plane
->src_x
);
148 rcar_du_plane_write(rgrp
, index
, PnSPYR
, plane
->src_y
*
149 (plane
->format
->bpp
== 16 ? 2 : 1) / 2);
150 rcar_du_plane_write(rgrp
, index
, PnDSA0R
, plane
->dma
[1]);
154 void rcar_du_plane_compute_base(struct rcar_du_plane
*plane
,
155 struct drm_framebuffer
*fb
)
157 struct drm_gem_cma_object
*gem
;
159 plane
->pitch
= fb
->pitches
[0];
161 gem
= drm_fb_cma_get_gem_obj(fb
, 0);
162 plane
->dma
[0] = gem
->paddr
+ fb
->offsets
[0];
164 if (plane
->format
->planes
== 2) {
165 gem
= drm_fb_cma_get_gem_obj(fb
, 1);
166 plane
->dma
[1] = gem
->paddr
+ fb
->offsets
[1];
170 static void rcar_du_plane_setup_mode(struct rcar_du_plane
*plane
,
173 struct rcar_du_group
*rgrp
= plane
->group
;
177 /* The PnALPHAR register controls alpha-blending in 16bpp formats
178 * (ARGB1555 and XRGB1555).
180 * For ARGB, set the alpha value to 0, and enable alpha-blending when
181 * the A bit is 0. This maps A=0 to alpha=0 and A=1 to alpha=255.
183 * For XRGB, set the alpha value to the plane-wide alpha value and
184 * enable alpha-blending regardless of the X bit value.
186 if (plane
->format
->fourcc
!= DRM_FORMAT_XRGB1555
)
187 rcar_du_plane_write(rgrp
, index
, PnALPHAR
, PnALPHAR_ABIT_0
);
189 rcar_du_plane_write(rgrp
, index
, PnALPHAR
,
190 PnALPHAR_ABIT_X
| plane
->alpha
);
192 pnmr
= PnMR_BM_MD
| plane
->format
->pnmr
;
194 /* Disable color keying when requested. YUV formats have the
195 * PnMR_SPIM_TP_OFF bit set in their pnmr field, disabling color keying
198 if ((plane
->colorkey
& RCAR_DU_COLORKEY_MASK
) == RCAR_DU_COLORKEY_NONE
)
199 pnmr
|= PnMR_SPIM_TP_OFF
;
201 /* For packed YUV formats we need to select the U/V order. */
202 if (plane
->format
->fourcc
== DRM_FORMAT_YUYV
)
203 pnmr
|= PnMR_YCDF_YUYV
;
205 rcar_du_plane_write(rgrp
, index
, PnMR
, pnmr
);
207 switch (plane
->format
->fourcc
) {
208 case DRM_FORMAT_RGB565
:
209 colorkey
= ((plane
->colorkey
& 0xf80000) >> 8)
210 | ((plane
->colorkey
& 0x00fc00) >> 5)
211 | ((plane
->colorkey
& 0x0000f8) >> 3);
212 rcar_du_plane_write(rgrp
, index
, PnTC2R
, colorkey
);
215 case DRM_FORMAT_ARGB1555
:
216 case DRM_FORMAT_XRGB1555
:
217 colorkey
= ((plane
->colorkey
& 0xf80000) >> 9)
218 | ((plane
->colorkey
& 0x00f800) >> 6)
219 | ((plane
->colorkey
& 0x0000f8) >> 3);
220 rcar_du_plane_write(rgrp
, index
, PnTC2R
, colorkey
);
223 case DRM_FORMAT_XRGB8888
:
224 case DRM_FORMAT_ARGB8888
:
225 rcar_du_plane_write(rgrp
, index
, PnTC3R
,
226 PnTC3R_CODE
| (plane
->colorkey
& 0xffffff));
231 static void __rcar_du_plane_setup(struct rcar_du_plane
*plane
,
234 struct rcar_du_group
*rgrp
= plane
->group
;
235 u32 ddcr2
= PnDDCR2_CODE
;
240 * The data format is selected by the DDDF field in PnMR and the EDF
243 ddcr4
= rcar_du_plane_read(rgrp
, index
, PnDDCR4
);
244 ddcr4
&= ~PnDDCR4_EDF_MASK
;
245 ddcr4
|= plane
->format
->edf
| PnDDCR4_CODE
;
247 rcar_du_plane_setup_mode(plane
, index
);
249 if (plane
->format
->planes
== 2) {
250 if (plane
->hwindex
!= index
) {
251 if (plane
->format
->fourcc
== DRM_FORMAT_NV12
||
252 plane
->format
->fourcc
== DRM_FORMAT_NV21
)
253 ddcr2
|= PnDDCR2_Y420
;
255 if (plane
->format
->fourcc
== DRM_FORMAT_NV21
)
256 ddcr2
|= PnDDCR2_NV21
;
258 ddcr2
|= PnDDCR2_DIVU
;
260 ddcr2
|= PnDDCR2_DIVY
;
264 rcar_du_plane_write(rgrp
, index
, PnDDCR2
, ddcr2
);
265 rcar_du_plane_write(rgrp
, index
, PnDDCR4
, ddcr4
);
267 /* Destination position and size */
268 rcar_du_plane_write(rgrp
, index
, PnDSXR
, plane
->width
);
269 rcar_du_plane_write(rgrp
, index
, PnDSYR
, plane
->height
);
270 rcar_du_plane_write(rgrp
, index
, PnDPXR
, plane
->dst_x
);
271 rcar_du_plane_write(rgrp
, index
, PnDPYR
, plane
->dst_y
);
273 /* Wrap-around and blinking, disabled */
274 rcar_du_plane_write(rgrp
, index
, PnWASPR
, 0);
275 rcar_du_plane_write(rgrp
, index
, PnWAMWR
, 4095);
276 rcar_du_plane_write(rgrp
, index
, PnBTR
, 0);
277 rcar_du_plane_write(rgrp
, index
, PnMLR
, 0);
280 void rcar_du_plane_setup(struct rcar_du_plane
*plane
)
282 __rcar_du_plane_setup(plane
, plane
->hwindex
);
283 if (plane
->format
->planes
== 2)
284 __rcar_du_plane_setup(plane
, (plane
->hwindex
+ 1) % 8);
286 rcar_du_plane_update_base(plane
);
290 rcar_du_plane_update(struct drm_plane
*plane
, struct drm_crtc
*crtc
,
291 struct drm_framebuffer
*fb
, int crtc_x
, int crtc_y
,
292 unsigned int crtc_w
, unsigned int crtc_h
,
293 uint32_t src_x
, uint32_t src_y
,
294 uint32_t src_w
, uint32_t src_h
)
296 struct rcar_du_plane
*rplane
= to_rcar_plane(plane
);
297 struct rcar_du_device
*rcdu
= rplane
->group
->dev
;
298 const struct rcar_du_format_info
*format
;
299 unsigned int nplanes
;
302 format
= rcar_du_format_info(fb
->pixel_format
);
303 if (format
== NULL
) {
304 dev_dbg(rcdu
->dev
, "%s: unsupported format %08x\n", __func__
,
309 if (src_w
>> 16 != crtc_w
|| src_h
>> 16 != crtc_h
) {
310 dev_dbg(rcdu
->dev
, "%s: scaling not supported\n", __func__
);
314 nplanes
= rplane
->format
? rplane
->format
->planes
: 0;
316 /* Reallocate hardware planes if the number of required planes has
319 if (format
->planes
!= nplanes
) {
320 rcar_du_plane_release(rplane
);
321 ret
= rcar_du_plane_reserve(rplane
, format
);
327 rplane
->format
= format
;
329 rplane
->src_x
= src_x
>> 16;
330 rplane
->src_y
= src_y
>> 16;
331 rplane
->dst_x
= crtc_x
;
332 rplane
->dst_y
= crtc_y
;
333 rplane
->width
= crtc_w
;
334 rplane
->height
= crtc_h
;
336 rcar_du_plane_compute_base(rplane
, fb
);
337 rcar_du_plane_setup(rplane
);
339 mutex_lock(&rplane
->group
->planes
.lock
);
340 rplane
->enabled
= true;
341 rcar_du_crtc_update_planes(rplane
->crtc
);
342 mutex_unlock(&rplane
->group
->planes
.lock
);
347 static int rcar_du_plane_disable(struct drm_plane
*plane
)
349 struct rcar_du_plane
*rplane
= to_rcar_plane(plane
);
351 if (!rplane
->enabled
)
354 mutex_lock(&rplane
->group
->planes
.lock
);
355 rplane
->enabled
= false;
356 rcar_du_crtc_update_planes(rplane
->crtc
);
357 mutex_unlock(&rplane
->group
->planes
.lock
);
359 rcar_du_plane_release(rplane
);
362 rplane
->format
= NULL
;
367 /* Both the .set_property and the .update_plane operations are called with the
368 * mode_config lock held. There is this no need to explicitly protect access to
369 * the alpha and colorkey fields and the mode register.
371 static void rcar_du_plane_set_alpha(struct rcar_du_plane
*plane
, u32 alpha
)
373 if (plane
->alpha
== alpha
)
376 plane
->alpha
= alpha
;
377 if (!plane
->enabled
|| plane
->format
->fourcc
!= DRM_FORMAT_XRGB1555
)
380 rcar_du_plane_setup_mode(plane
, plane
->hwindex
);
383 static void rcar_du_plane_set_colorkey(struct rcar_du_plane
*plane
,
386 if (plane
->colorkey
== colorkey
)
389 plane
->colorkey
= colorkey
;
393 rcar_du_plane_setup_mode(plane
, plane
->hwindex
);
396 static void rcar_du_plane_set_zpos(struct rcar_du_plane
*plane
,
399 mutex_lock(&plane
->group
->planes
.lock
);
400 if (plane
->zpos
== zpos
)
407 rcar_du_crtc_update_planes(plane
->crtc
);
410 mutex_unlock(&plane
->group
->planes
.lock
);
413 static int rcar_du_plane_set_property(struct drm_plane
*plane
,
414 struct drm_property
*property
,
417 struct rcar_du_plane
*rplane
= to_rcar_plane(plane
);
418 struct rcar_du_group
*rgrp
= rplane
->group
;
420 if (property
== rgrp
->planes
.alpha
)
421 rcar_du_plane_set_alpha(rplane
, value
);
422 else if (property
== rgrp
->planes
.colorkey
)
423 rcar_du_plane_set_colorkey(rplane
, value
);
424 else if (property
== rgrp
->planes
.zpos
)
425 rcar_du_plane_set_zpos(rplane
, value
);
432 static const struct drm_plane_funcs rcar_du_plane_funcs
= {
433 .update_plane
= rcar_du_plane_update
,
434 .disable_plane
= rcar_du_plane_disable
,
435 .set_property
= rcar_du_plane_set_property
,
436 .destroy
= drm_plane_cleanup
,
439 static const uint32_t formats
[] = {
452 int rcar_du_planes_init(struct rcar_du_group
*rgrp
)
454 struct rcar_du_planes
*planes
= &rgrp
->planes
;
455 struct rcar_du_device
*rcdu
= rgrp
->dev
;
458 mutex_init(&planes
->lock
);
462 drm_property_create_range(rcdu
->ddev
, 0, "alpha", 0, 255);
463 if (planes
->alpha
== NULL
)
466 /* The color key is expressed as an RGB888 triplet stored in a 32-bit
467 * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0)
468 * or enable source color keying (1).
471 drm_property_create_range(rcdu
->ddev
, 0, "colorkey",
473 if (planes
->colorkey
== NULL
)
477 drm_property_create_range(rcdu
->ddev
, 0, "zpos", 1, 7);
478 if (planes
->zpos
== NULL
)
481 for (i
= 0; i
< ARRAY_SIZE(planes
->planes
); ++i
) {
482 struct rcar_du_plane
*plane
= &planes
->planes
[i
];
487 plane
->colorkey
= RCAR_DU_COLORKEY_NONE
;
494 int rcar_du_planes_register(struct rcar_du_group
*rgrp
)
496 struct rcar_du_planes
*planes
= &rgrp
->planes
;
497 struct rcar_du_device
*rcdu
= rgrp
->dev
;
502 crtcs
= ((1 << rcdu
->num_crtcs
) - 1) & (3 << (2 * rgrp
->index
));
504 for (i
= 0; i
< RCAR_DU_NUM_KMS_PLANES
; ++i
) {
505 struct rcar_du_kms_plane
*plane
;
507 plane
= devm_kzalloc(rcdu
->dev
, sizeof(*plane
), GFP_KERNEL
);
511 plane
->hwplane
= &planes
->planes
[i
+ 2];
512 plane
->hwplane
->zpos
= 1;
514 ret
= drm_plane_init(rcdu
->ddev
, &plane
->plane
, crtcs
,
515 &rcar_du_plane_funcs
, formats
,
516 ARRAY_SIZE(formats
), false);
520 drm_object_attach_property(&plane
->plane
.base
,
522 drm_object_attach_property(&plane
->plane
.base
,
524 RCAR_DU_COLORKEY_NONE
);
525 drm_object_attach_property(&plane
->plane
.base
,