drm/rcar-du: Rename rcar_du_plane_(init|register) to rcar_du_planes_*
[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 *
4 * Copyright (C) 2013 Renesas Corporation
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>
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>
19
20#include "rcar_du_drv.h"
21#include "rcar_du_kms.h"
22#include "rcar_du_plane.h"
23#include "rcar_du_regs.h"
24
25#define RCAR_DU_COLORKEY_NONE (0 << 24)
26#define RCAR_DU_COLORKEY_SOURCE (1 << 24)
27#define RCAR_DU_COLORKEY_MASK (1 << 24)
28
29struct rcar_du_kms_plane {
30 struct drm_plane plane;
31 struct rcar_du_plane *hwplane;
32};
33
34static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane)
35{
36 return container_of(plane, struct rcar_du_kms_plane, plane)->hwplane;
37}
38
39static u32 rcar_du_plane_read(struct rcar_du_device *rcdu,
40 unsigned int index, u32 reg)
41{
42 return rcar_du_read(rcdu, index * PLANE_OFF + reg);
43}
44
45static void rcar_du_plane_write(struct rcar_du_device *rcdu,
46 unsigned int index, u32 reg, u32 data)
47{
48 rcar_du_write(rcdu, index * PLANE_OFF + reg, data);
49}
50
51int rcar_du_plane_reserve(struct rcar_du_plane *plane,
52 const struct rcar_du_format_info *format)
53{
54 struct rcar_du_device *rcdu = plane->dev;
55 unsigned int i;
56 int ret = -EBUSY;
57
58 mutex_lock(&rcdu->planes.lock);
59
60 for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
61 if (!(rcdu->planes.free & (1 << i)))
62 continue;
63
64 if (format->planes == 1 ||
65 rcdu->planes.free & (1 << ((i + 1) % 8)))
66 break;
67 }
68
69 if (i == ARRAY_SIZE(rcdu->planes.planes))
70 goto done;
71
72 rcdu->planes.free &= ~(1 << i);
73 if (format->planes == 2)
74 rcdu->planes.free &= ~(1 << ((i + 1) % 8));
75
76 plane->hwindex = i;
77
78 ret = 0;
79
80done:
81 mutex_unlock(&rcdu->planes.lock);
82 return ret;
83}
84
85void rcar_du_plane_release(struct rcar_du_plane *plane)
86{
87 struct rcar_du_device *rcdu = plane->dev;
88
89 if (plane->hwindex == -1)
90 return;
91
92 mutex_lock(&rcdu->planes.lock);
93 rcdu->planes.free |= 1 << plane->hwindex;
94 if (plane->format->planes == 2)
95 rcdu->planes.free |= 1 << ((plane->hwindex + 1) % 8);
96 mutex_unlock(&rcdu->planes.lock);
97
98 plane->hwindex = -1;
99}
100
101void rcar_du_plane_update_base(struct rcar_du_plane *plane)
102{
103 struct rcar_du_device *rcdu = plane->dev;
104 unsigned int index = plane->hwindex;
105
9e7db06d
LP
106 /* The Y position is expressed in raster line units and must be doubled
107 * for 32bpp formats, according to the R8A7790 datasheet. No mention of
108 * doubling the Y position is found in the R8A7779 datasheet, but the
109 * rule seems to apply there as well.
110 *
111 * Similarly, for the second plane, NV12 and NV21 formats seem to
4bf8e196
LP
112 * require a halved Y position value.
113 */
114 rcar_du_plane_write(rcdu, index, PnSPXR, plane->src_x);
115 rcar_du_plane_write(rcdu, index, PnSPYR, plane->src_y *
116 (plane->format->bpp == 32 ? 2 : 1));
117 rcar_du_plane_write(rcdu, index, PnDSA0R, plane->dma[0]);
118
119 if (plane->format->planes == 2) {
120 index = (index + 1) % 8;
121
122 rcar_du_plane_write(rcdu, index, PnSPXR, plane->src_x);
123 rcar_du_plane_write(rcdu, index, PnSPYR, plane->src_y *
124 (plane->format->bpp == 16 ? 2 : 1) / 2);
125 rcar_du_plane_write(rcdu, index, PnDSA0R, plane->dma[1]);
126 }
127}
128
129void rcar_du_plane_compute_base(struct rcar_du_plane *plane,
130 struct drm_framebuffer *fb)
131{
132 struct drm_gem_cma_object *gem;
133
134 gem = drm_fb_cma_get_gem_obj(fb, 0);
135 plane->dma[0] = gem->paddr + fb->offsets[0];
136
137 if (plane->format->planes == 2) {
138 gem = drm_fb_cma_get_gem_obj(fb, 1);
139 plane->dma[1] = gem->paddr + fb->offsets[1];
140 }
141}
142
143static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
144 unsigned int index)
145{
146 struct rcar_du_device *rcdu = plane->dev;
147 u32 colorkey;
148 u32 pnmr;
149
150 /* The PnALPHAR register controls alpha-blending in 16bpp formats
151 * (ARGB1555 and XRGB1555).
152 *
153 * For ARGB, set the alpha value to 0, and enable alpha-blending when
154 * the A bit is 0. This maps A=0 to alpha=0 and A=1 to alpha=255.
155 *
156 * For XRGB, set the alpha value to the plane-wide alpha value and
157 * enable alpha-blending regardless of the X bit value.
158 */
159 if (plane->format->fourcc != DRM_FORMAT_XRGB1555)
160 rcar_du_plane_write(rcdu, index, PnALPHAR, PnALPHAR_ABIT_0);
161 else
162 rcar_du_plane_write(rcdu, index, PnALPHAR,
163 PnALPHAR_ABIT_X | plane->alpha);
164
165 pnmr = PnMR_BM_MD | plane->format->pnmr;
166
167 /* Disable color keying when requested. YUV formats have the
168 * PnMR_SPIM_TP_OFF bit set in their pnmr field, disabling color keying
169 * automatically.
170 */
171 if ((plane->colorkey & RCAR_DU_COLORKEY_MASK) == RCAR_DU_COLORKEY_NONE)
172 pnmr |= PnMR_SPIM_TP_OFF;
173
174 /* For packed YUV formats we need to select the U/V order. */
175 if (plane->format->fourcc == DRM_FORMAT_YUYV)
176 pnmr |= PnMR_YCDF_YUYV;
177
178 rcar_du_plane_write(rcdu, index, PnMR, pnmr);
179
180 switch (plane->format->fourcc) {
181 case DRM_FORMAT_RGB565:
182 colorkey = ((plane->colorkey & 0xf80000) >> 8)
183 | ((plane->colorkey & 0x00fc00) >> 5)
184 | ((plane->colorkey & 0x0000f8) >> 3);
185 rcar_du_plane_write(rcdu, index, PnTC2R, colorkey);
186 break;
187
188 case DRM_FORMAT_ARGB1555:
189 case DRM_FORMAT_XRGB1555:
190 colorkey = ((plane->colorkey & 0xf80000) >> 9)
191 | ((plane->colorkey & 0x00f800) >> 6)
192 | ((plane->colorkey & 0x0000f8) >> 3);
193 rcar_du_plane_write(rcdu, index, PnTC2R, colorkey);
194 break;
195
196 case DRM_FORMAT_XRGB8888:
197 case DRM_FORMAT_ARGB8888:
198 rcar_du_plane_write(rcdu, index, PnTC3R,
199 PnTC3R_CODE | (plane->colorkey & 0xffffff));
200 break;
201 }
202}
203
204static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
205 unsigned int index)
206{
207 struct rcar_du_device *rcdu = plane->dev;
208 u32 ddcr2 = PnDDCR2_CODE;
209 u32 ddcr4;
210 u32 mwr;
211
212 /* Data format
213 *
214 * The data format is selected by the DDDF field in PnMR and the EDF
215 * field in DDCR4.
216 */
217 ddcr4 = rcar_du_plane_read(rcdu, index, PnDDCR4);
218 ddcr4 &= ~PnDDCR4_EDF_MASK;
219 ddcr4 |= plane->format->edf | PnDDCR4_CODE;
220
221 rcar_du_plane_setup_mode(plane, index);
222
223 if (plane->format->planes == 2) {
224 if (plane->hwindex != index) {
225 if (plane->format->fourcc == DRM_FORMAT_NV12 ||
226 plane->format->fourcc == DRM_FORMAT_NV21)
227 ddcr2 |= PnDDCR2_Y420;
228
229 if (plane->format->fourcc == DRM_FORMAT_NV21)
230 ddcr2 |= PnDDCR2_NV21;
231
232 ddcr2 |= PnDDCR2_DIVU;
233 } else {
234 ddcr2 |= PnDDCR2_DIVY;
235 }
236 }
237
238 rcar_du_plane_write(rcdu, index, PnDDCR2, ddcr2);
239 rcar_du_plane_write(rcdu, index, PnDDCR4, ddcr4);
240
241 /* Memory pitch (expressed in pixels) */
242 if (plane->format->planes == 2)
243 mwr = plane->pitch;
244 else
245 mwr = plane->pitch * 8 / plane->format->bpp;
246
247 rcar_du_plane_write(rcdu, index, PnMWR, mwr);
248
249 /* Destination position and size */
250 rcar_du_plane_write(rcdu, index, PnDSXR, plane->width);
251 rcar_du_plane_write(rcdu, index, PnDSYR, plane->height);
252 rcar_du_plane_write(rcdu, index, PnDPXR, plane->dst_x);
253 rcar_du_plane_write(rcdu, index, PnDPYR, plane->dst_y);
254
255 /* Wrap-around and blinking, disabled */
256 rcar_du_plane_write(rcdu, index, PnWASPR, 0);
257 rcar_du_plane_write(rcdu, index, PnWAMWR, 4095);
258 rcar_du_plane_write(rcdu, index, PnBTR, 0);
259 rcar_du_plane_write(rcdu, index, PnMLR, 0);
260}
261
262void rcar_du_plane_setup(struct rcar_du_plane *plane)
263{
264 __rcar_du_plane_setup(plane, plane->hwindex);
265 if (plane->format->planes == 2)
266 __rcar_du_plane_setup(plane, (plane->hwindex + 1) % 8);
267
268 rcar_du_plane_update_base(plane);
269}
270
271static int
272rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
273 struct drm_framebuffer *fb, int crtc_x, int crtc_y,
274 unsigned int crtc_w, unsigned int crtc_h,
275 uint32_t src_x, uint32_t src_y,
276 uint32_t src_w, uint32_t src_h)
277{
278 struct rcar_du_plane *rplane = to_rcar_plane(plane);
279 struct rcar_du_device *rcdu = plane->dev->dev_private;
280 const struct rcar_du_format_info *format;
281 unsigned int nplanes;
282 int ret;
283
284 format = rcar_du_format_info(fb->pixel_format);
285 if (format == NULL) {
286 dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__,
287 fb->pixel_format);
288 return -EINVAL;
289 }
290
291 if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) {
292 dev_dbg(rcdu->dev, "%s: scaling not supported\n", __func__);
293 return -EINVAL;
294 }
295
296 nplanes = rplane->format ? rplane->format->planes : 0;
297
298 /* Reallocate hardware planes if the number of required planes has
299 * changed.
300 */
301 if (format->planes != nplanes) {
302 rcar_du_plane_release(rplane);
303 ret = rcar_du_plane_reserve(rplane, format);
304 if (ret < 0)
305 return ret;
306 }
307
308 rplane->crtc = crtc;
309 rplane->format = format;
310 rplane->pitch = fb->pitches[0];
311
312 rplane->src_x = src_x >> 16;
313 rplane->src_y = src_y >> 16;
314 rplane->dst_x = crtc_x;
315 rplane->dst_y = crtc_y;
316 rplane->width = crtc_w;
317 rplane->height = crtc_h;
318
319 rcar_du_plane_compute_base(rplane, fb);
320 rcar_du_plane_setup(rplane);
321
322 mutex_lock(&rcdu->planes.lock);
323 rplane->enabled = true;
324 rcar_du_crtc_update_planes(rplane->crtc);
325 mutex_unlock(&rcdu->planes.lock);
326
327 return 0;
328}
329
330static int rcar_du_plane_disable(struct drm_plane *plane)
331{
332 struct rcar_du_device *rcdu = plane->dev->dev_private;
333 struct rcar_du_plane *rplane = to_rcar_plane(plane);
334
335 if (!rplane->enabled)
336 return 0;
337
338 mutex_lock(&rcdu->planes.lock);
339 rplane->enabled = false;
340 rcar_du_crtc_update_planes(rplane->crtc);
341 mutex_unlock(&rcdu->planes.lock);
342
343 rcar_du_plane_release(rplane);
344
345 rplane->crtc = NULL;
346 rplane->format = NULL;
347
348 return 0;
349}
350
351/* Both the .set_property and the .update_plane operations are called with the
352 * mode_config lock held. There is this no need to explicitly protect access to
353 * the alpha and colorkey fields and the mode register.
354 */
355static void rcar_du_plane_set_alpha(struct rcar_du_plane *plane, u32 alpha)
356{
357 if (plane->alpha == alpha)
358 return;
359
360 plane->alpha = alpha;
361 if (!plane->enabled || plane->format->fourcc != DRM_FORMAT_XRGB1555)
362 return;
363
364 rcar_du_plane_setup_mode(plane, plane->hwindex);
365}
366
367static void rcar_du_plane_set_colorkey(struct rcar_du_plane *plane,
368 u32 colorkey)
369{
370 if (plane->colorkey == colorkey)
371 return;
372
373 plane->colorkey = colorkey;
374 if (!plane->enabled)
375 return;
376
377 rcar_du_plane_setup_mode(plane, plane->hwindex);
378}
379
380static void rcar_du_plane_set_zpos(struct rcar_du_plane *plane,
381 unsigned int zpos)
382{
383 struct rcar_du_device *rcdu = plane->dev;
384
385 mutex_lock(&rcdu->planes.lock);
386 if (plane->zpos == zpos)
387 goto done;
388
389 plane->zpos = zpos;
390 if (!plane->enabled)
391 goto done;
392
393 rcar_du_crtc_update_planes(plane->crtc);
394
395done:
396 mutex_unlock(&rcdu->planes.lock);
397}
398
399static int rcar_du_plane_set_property(struct drm_plane *plane,
400 struct drm_property *property,
401 uint64_t value)
402{
403 struct rcar_du_device *rcdu = plane->dev->dev_private;
404 struct rcar_du_plane *rplane = to_rcar_plane(plane);
405
406 if (property == rcdu->planes.alpha)
407 rcar_du_plane_set_alpha(rplane, value);
408 else if (property == rcdu->planes.colorkey)
409 rcar_du_plane_set_colorkey(rplane, value);
410 else if (property == rcdu->planes.zpos)
411 rcar_du_plane_set_zpos(rplane, value);
412 else
413 return -EINVAL;
414
415 return 0;
416}
417
418static const struct drm_plane_funcs rcar_du_plane_funcs = {
419 .update_plane = rcar_du_plane_update,
420 .disable_plane = rcar_du_plane_disable,
421 .set_property = rcar_du_plane_set_property,
422 .destroy = drm_plane_cleanup,
423};
424
425static const uint32_t formats[] = {
426 DRM_FORMAT_RGB565,
427 DRM_FORMAT_ARGB1555,
428 DRM_FORMAT_XRGB1555,
429 DRM_FORMAT_XRGB8888,
430 DRM_FORMAT_ARGB8888,
431 DRM_FORMAT_UYVY,
432 DRM_FORMAT_YUYV,
433 DRM_FORMAT_NV12,
434 DRM_FORMAT_NV21,
435 DRM_FORMAT_NV16,
436};
437
7fe99fda 438int rcar_du_planes_init(struct rcar_du_device *rcdu)
4bf8e196
LP
439{
440 unsigned int i;
441
442 mutex_init(&rcdu->planes.lock);
443 rcdu->planes.free = 0xff;
444
445 rcdu->planes.alpha =
446 drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255);
447 if (rcdu->planes.alpha == NULL)
448 return -ENOMEM;
449
450 /* The color key is expressed as an RGB888 triplet stored in a 32-bit
451 * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0)
452 * or enable source color keying (1).
453 */
454 rcdu->planes.colorkey =
455 drm_property_create_range(rcdu->ddev, 0, "colorkey",
456 0, 0x01ffffff);
457 if (rcdu->planes.colorkey == NULL)
458 return -ENOMEM;
459
460 rcdu->planes.zpos =
461 drm_property_create_range(rcdu->ddev, 0, "zpos", 1, 7);
462 if (rcdu->planes.zpos == NULL)
463 return -ENOMEM;
464
465 for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
466 struct rcar_du_plane *plane = &rcdu->planes.planes[i];
467
468 plane->dev = rcdu;
469 plane->hwindex = -1;
470 plane->alpha = 255;
471 plane->colorkey = RCAR_DU_COLORKEY_NONE;
472 plane->zpos = 0;
473 }
474
475 return 0;
476}
477
7fe99fda 478int rcar_du_planes_register(struct rcar_du_device *rcdu)
4bf8e196
LP
479{
480 unsigned int i;
481 int ret;
482
483 for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
484 struct rcar_du_kms_plane *plane;
485
486 plane = devm_kzalloc(rcdu->dev, sizeof(*plane), GFP_KERNEL);
487 if (plane == NULL)
488 return -ENOMEM;
489
490 plane->hwplane = &rcdu->planes.planes[i + 2];
491 plane->hwplane->zpos = 1;
492
493 ret = drm_plane_init(rcdu->ddev, &plane->plane,
494 (1 << rcdu->num_crtcs) - 1,
495 &rcar_du_plane_funcs, formats,
496 ARRAY_SIZE(formats), false);
497 if (ret < 0)
498 return ret;
499
500 drm_object_attach_property(&plane->plane.base,
501 rcdu->planes.alpha, 255);
502 drm_object_attach_property(&plane->plane.base,
503 rcdu->planes.colorkey,
504 RCAR_DU_COLORKEY_NONE);
505 drm_object_attach_property(&plane->plane.base,
506 rcdu->planes.zpos, 1);
507 }
508
509 return 0;
510}
This page took 0.056246 seconds and 5 git commands to generate.