blob: b380179d4013c3f596ef80fce54682375d11535c [file] [log] [blame]
Boris Brezillon1a396782015-01-06 11:13:28 +01001/*
2 * Copyright (C) 2014 Free Electrons
3 * Copyright (C) 2014 Atmel
4 *
5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "atmel_hlcdc_dc.h"
21
Boris Brezillon2389fc12015-02-05 16:32:33 +010022/**
23 * Atmel HLCDC Plane state structure.
24 *
25 * @base: DRM plane state
26 * @crtc_x: x position of the plane relative to the CRTC
27 * @crtc_y: y position of the plane relative to the CRTC
28 * @crtc_w: visible width of the plane
29 * @crtc_h: visible height of the plane
30 * @src_x: x buffer position
31 * @src_y: y buffer position
32 * @src_w: buffer width
33 * @src_h: buffer height
34 * @alpha: alpha blending of the plane
35 * @bpp: bytes per pixel deduced from pixel_format
36 * @offsets: offsets to apply to the GEM buffers
37 * @xstride: value to add to the pixel pointer between each line
38 * @pstride: value to add to the pixel pointer between each pixel
39 * @nplanes: number of planes (deduced from pixel_format)
Boris Brezillon1a7b37c2015-10-10 07:55:39 +020040 * @prepared: plane update has been prepared
Boris Brezillon2389fc12015-02-05 16:32:33 +010041 */
42struct atmel_hlcdc_plane_state {
43 struct drm_plane_state base;
44 int crtc_x;
45 int crtc_y;
46 unsigned int crtc_w;
47 unsigned int crtc_h;
48 uint32_t src_x;
49 uint32_t src_y;
50 uint32_t src_w;
51 uint32_t src_h;
52
53 u8 alpha;
54
Boris Brezillon59570172015-02-06 16:25:06 +010055 bool disc_updated;
56
57 int disc_x;
58 int disc_y;
59 int disc_w;
60 int disc_h;
61
Boris Brezillonebab87a2016-03-15 18:01:08 +010062 int ahb_id;
63
Boris Brezillon2389fc12015-02-05 16:32:33 +010064 /* These fields are private and should not be touched */
65 int bpp[ATMEL_HLCDC_MAX_PLANES];
66 unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
67 int xstride[ATMEL_HLCDC_MAX_PLANES];
68 int pstride[ATMEL_HLCDC_MAX_PLANES];
69 int nplanes;
Boris Brezillon1a7b37c2015-10-10 07:55:39 +020070 bool prepared;
Boris Brezillon2389fc12015-02-05 16:32:33 +010071};
72
73static inline struct atmel_hlcdc_plane_state *
74drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
75{
76 return container_of(s, struct atmel_hlcdc_plane_state, base);
77}
78
Boris Brezillon1a396782015-01-06 11:13:28 +010079#define SUBPIXEL_MASK 0xffff
80
81static uint32_t rgb_formats[] = {
82 DRM_FORMAT_XRGB4444,
83 DRM_FORMAT_ARGB4444,
84 DRM_FORMAT_RGBA4444,
85 DRM_FORMAT_ARGB1555,
86 DRM_FORMAT_RGB565,
87 DRM_FORMAT_RGB888,
88 DRM_FORMAT_XRGB8888,
89 DRM_FORMAT_ARGB8888,
90 DRM_FORMAT_RGBA8888,
91};
92
93struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
94 .formats = rgb_formats,
95 .nformats = ARRAY_SIZE(rgb_formats),
96};
97
98static uint32_t rgb_and_yuv_formats[] = {
99 DRM_FORMAT_XRGB4444,
100 DRM_FORMAT_ARGB4444,
101 DRM_FORMAT_RGBA4444,
102 DRM_FORMAT_ARGB1555,
103 DRM_FORMAT_RGB565,
104 DRM_FORMAT_RGB888,
105 DRM_FORMAT_XRGB8888,
106 DRM_FORMAT_ARGB8888,
107 DRM_FORMAT_RGBA8888,
108 DRM_FORMAT_AYUV,
109 DRM_FORMAT_YUYV,
110 DRM_FORMAT_UYVY,
111 DRM_FORMAT_YVYU,
112 DRM_FORMAT_VYUY,
113 DRM_FORMAT_NV21,
114 DRM_FORMAT_NV61,
115 DRM_FORMAT_YUV422,
116 DRM_FORMAT_YUV420,
117};
118
119struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
120 .formats = rgb_and_yuv_formats,
121 .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
122};
123
124static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
125{
126 switch (format) {
127 case DRM_FORMAT_XRGB4444:
128 *mode = ATMEL_HLCDC_XRGB4444_MODE;
129 break;
130 case DRM_FORMAT_ARGB4444:
131 *mode = ATMEL_HLCDC_ARGB4444_MODE;
132 break;
133 case DRM_FORMAT_RGBA4444:
134 *mode = ATMEL_HLCDC_RGBA4444_MODE;
135 break;
136 case DRM_FORMAT_RGB565:
137 *mode = ATMEL_HLCDC_RGB565_MODE;
138 break;
139 case DRM_FORMAT_RGB888:
140 *mode = ATMEL_HLCDC_RGB888_MODE;
141 break;
142 case DRM_FORMAT_ARGB1555:
143 *mode = ATMEL_HLCDC_ARGB1555_MODE;
144 break;
145 case DRM_FORMAT_XRGB8888:
146 *mode = ATMEL_HLCDC_XRGB8888_MODE;
147 break;
148 case DRM_FORMAT_ARGB8888:
149 *mode = ATMEL_HLCDC_ARGB8888_MODE;
150 break;
151 case DRM_FORMAT_RGBA8888:
152 *mode = ATMEL_HLCDC_RGBA8888_MODE;
153 break;
154 case DRM_FORMAT_AYUV:
155 *mode = ATMEL_HLCDC_AYUV_MODE;
156 break;
157 case DRM_FORMAT_YUYV:
158 *mode = ATMEL_HLCDC_YUYV_MODE;
159 break;
160 case DRM_FORMAT_UYVY:
161 *mode = ATMEL_HLCDC_UYVY_MODE;
162 break;
163 case DRM_FORMAT_YVYU:
164 *mode = ATMEL_HLCDC_YVYU_MODE;
165 break;
166 case DRM_FORMAT_VYUY:
167 *mode = ATMEL_HLCDC_VYUY_MODE;
168 break;
169 case DRM_FORMAT_NV21:
170 *mode = ATMEL_HLCDC_NV21_MODE;
171 break;
172 case DRM_FORMAT_NV61:
173 *mode = ATMEL_HLCDC_NV61_MODE;
174 break;
175 case DRM_FORMAT_YUV420:
176 *mode = ATMEL_HLCDC_YUV420_MODE;
177 break;
178 case DRM_FORMAT_YUV422:
179 *mode = ATMEL_HLCDC_YUV422_MODE;
180 break;
181 default:
182 return -ENOTSUPP;
183 }
184
185 return 0;
186}
187
Boris Brezillon2389fc12015-02-05 16:32:33 +0100188static bool atmel_hlcdc_format_embeds_alpha(u32 format)
Boris Brezillon1a396782015-01-06 11:13:28 +0100189{
190 int i;
191
192 for (i = 0; i < sizeof(format); i++) {
193 char tmp = (format >> (8 * i)) & 0xff;
194
195 if (tmp == 'A')
196 return true;
197 }
198
199 return false;
200}
201
202static u32 heo_downscaling_xcoef[] = {
203 0x11343311,
204 0x000000f7,
205 0x1635300c,
206 0x000000f9,
207 0x1b362c08,
208 0x000000fb,
209 0x1f372804,
210 0x000000fe,
211 0x24382400,
212 0x00000000,
213 0x28371ffe,
214 0x00000004,
215 0x2c361bfb,
216 0x00000008,
217 0x303516f9,
218 0x0000000c,
219};
220
221static u32 heo_downscaling_ycoef[] = {
222 0x00123737,
223 0x00173732,
224 0x001b382d,
225 0x001f3928,
226 0x00243824,
227 0x0028391f,
228 0x002d381b,
229 0x00323717,
230};
231
232static u32 heo_upscaling_xcoef[] = {
233 0xf74949f7,
234 0x00000000,
235 0xf55f33fb,
236 0x000000fe,
237 0xf5701efe,
238 0x000000ff,
239 0xf87c0dff,
240 0x00000000,
241 0x00800000,
242 0x00000000,
243 0x0d7cf800,
244 0x000000ff,
245 0x1e70f5ff,
246 0x000000fe,
247 0x335ff5fe,
248 0x000000fb,
249};
250
251static u32 heo_upscaling_ycoef[] = {
252 0x00004040,
253 0x00075920,
254 0x00056f0c,
255 0x00027b03,
256 0x00008000,
257 0x00037b02,
258 0x000c6f05,
259 0x00205907,
260};
261
262static void
263atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100264 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100265{
266 const struct atmel_hlcdc_layer_cfg_layout *layout =
267 &plane->layer.desc->layout;
268
269 if (layout->size)
270 atmel_hlcdc_layer_update_cfg(&plane->layer,
271 layout->size,
272 0xffffffff,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100273 (state->crtc_w - 1) |
274 ((state->crtc_h - 1) << 16));
Boris Brezillon1a396782015-01-06 11:13:28 +0100275
276 if (layout->memsize)
277 atmel_hlcdc_layer_update_cfg(&plane->layer,
278 layout->memsize,
279 0xffffffff,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100280 (state->src_w - 1) |
281 ((state->src_h - 1) << 16));
Boris Brezillon1a396782015-01-06 11:13:28 +0100282
283 if (layout->pos)
284 atmel_hlcdc_layer_update_cfg(&plane->layer,
285 layout->pos,
286 0xffffffff,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100287 state->crtc_x |
288 (state->crtc_y << 16));
Boris Brezillon1a396782015-01-06 11:13:28 +0100289
290 /* TODO: rework the rescaling part */
Boris Brezillon2389fc12015-02-05 16:32:33 +0100291 if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100292 u32 factor_reg = 0;
293
Boris Brezillon2389fc12015-02-05 16:32:33 +0100294 if (state->crtc_w != state->src_w) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100295 int i;
296 u32 factor;
297 u32 *coeff_tab = heo_upscaling_xcoef;
298 u32 max_memsize;
299
Boris Brezillon2389fc12015-02-05 16:32:33 +0100300 if (state->crtc_w < state->src_w)
Boris Brezillon1a396782015-01-06 11:13:28 +0100301 coeff_tab = heo_downscaling_xcoef;
302 for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
303 atmel_hlcdc_layer_update_cfg(&plane->layer,
304 17 + i,
305 0xffffffff,
306 coeff_tab[i]);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100307 factor = ((8 * 256 * state->src_w) - (256 * 4)) /
308 state->crtc_w;
Boris Brezillon1a396782015-01-06 11:13:28 +0100309 factor++;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100310 max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
Boris Brezillon1a396782015-01-06 11:13:28 +0100311 2048;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100312 if (max_memsize > state->src_w)
Boris Brezillon1a396782015-01-06 11:13:28 +0100313 factor--;
314 factor_reg |= factor | 0x80000000;
315 }
316
Boris Brezillon2389fc12015-02-05 16:32:33 +0100317 if (state->crtc_h != state->src_h) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100318 int i;
319 u32 factor;
320 u32 *coeff_tab = heo_upscaling_ycoef;
321 u32 max_memsize;
322
Jan Leupoldd31ed3f2016-07-06 13:22:35 +0200323 if (state->crtc_h < state->src_h)
Boris Brezillon1a396782015-01-06 11:13:28 +0100324 coeff_tab = heo_downscaling_ycoef;
325 for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
326 atmel_hlcdc_layer_update_cfg(&plane->layer,
327 33 + i,
328 0xffffffff,
329 coeff_tab[i]);
Jan Leupoldd31ed3f2016-07-06 13:22:35 +0200330 factor = ((8 * 256 * state->src_h) - (256 * 4)) /
331 state->crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100332 factor++;
Jan Leupoldd31ed3f2016-07-06 13:22:35 +0200333 max_memsize = ((factor * state->crtc_h) + (256 * 4)) /
Boris Brezillon1a396782015-01-06 11:13:28 +0100334 2048;
Jan Leupoldd31ed3f2016-07-06 13:22:35 +0200335 if (max_memsize > state->src_h)
Boris Brezillon1a396782015-01-06 11:13:28 +0100336 factor--;
337 factor_reg |= (factor << 16) | 0x80000000;
338 }
339
340 atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
341 factor_reg);
Boris Brezillon1b7e38b2016-05-27 16:09:25 +0200342 } else {
343 atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff, 0);
Boris Brezillon1a396782015-01-06 11:13:28 +0100344 }
345}
346
347static void
348atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100349 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100350{
351 const struct atmel_hlcdc_layer_cfg_layout *layout =
352 &plane->layer.desc->layout;
353 unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
354
355 if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
356 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
357 ATMEL_HLCDC_LAYER_ITER;
358
Boris Brezillon2389fc12015-02-05 16:32:33 +0100359 if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
Boris Brezillon1a396782015-01-06 11:13:28 +0100360 cfg |= ATMEL_HLCDC_LAYER_LAEN;
361 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100362 cfg |= ATMEL_HLCDC_LAYER_GAEN |
363 ATMEL_HLCDC_LAYER_GA(state->alpha);
Boris Brezillon1a396782015-01-06 11:13:28 +0100364 }
365
366 atmel_hlcdc_layer_update_cfg(&plane->layer,
367 ATMEL_HLCDC_LAYER_DMA_CFG_ID,
Boris Brezillonebab87a2016-03-15 18:01:08 +0100368 ATMEL_HLCDC_LAYER_DMA_BLEN_MASK |
369 ATMEL_HLCDC_LAYER_DMA_SIF,
370 ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 |
371 state->ahb_id);
Boris Brezillon1a396782015-01-06 11:13:28 +0100372
373 atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
374 ATMEL_HLCDC_LAYER_ITER2BL |
375 ATMEL_HLCDC_LAYER_ITER |
376 ATMEL_HLCDC_LAYER_GAEN |
Boris Brezillon2389fc12015-02-05 16:32:33 +0100377 ATMEL_HLCDC_LAYER_GA_MASK |
Boris Brezillon1a396782015-01-06 11:13:28 +0100378 ATMEL_HLCDC_LAYER_LAEN |
379 ATMEL_HLCDC_LAYER_OVR |
380 ATMEL_HLCDC_LAYER_DMA, cfg);
381}
382
383static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100384 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100385{
386 u32 cfg;
387 int ret;
388
Boris Brezillon2389fc12015-02-05 16:32:33 +0100389 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
390 &cfg);
Boris Brezillon1a396782015-01-06 11:13:28 +0100391 if (ret)
392 return;
393
Boris Brezillon2389fc12015-02-05 16:32:33 +0100394 if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 ||
395 state->base.fb->pixel_format == DRM_FORMAT_NV61) &&
Ville Syrjäläbd2ef252016-09-26 19:30:46 +0300396 drm_rotation_90_or_270(state->base.rotation))
Boris Brezillon1a396782015-01-06 11:13:28 +0100397 cfg |= ATMEL_HLCDC_YUV422ROT;
398
399 atmel_hlcdc_layer_update_cfg(&plane->layer,
400 ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
401 0xffffffff,
402 cfg);
403
404 /*
405 * Rotation optimization is not working on RGB888 (rotation is still
406 * working but without any optimization).
407 */
Boris Brezillon2389fc12015-02-05 16:32:33 +0100408 if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
Boris Brezillon1a396782015-01-06 11:13:28 +0100409 cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
410 else
411 cfg = 0;
412
413 atmel_hlcdc_layer_update_cfg(&plane->layer,
414 ATMEL_HLCDC_LAYER_DMA_CFG_ID,
415 ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
416}
417
418static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100419 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100420{
421 struct atmel_hlcdc_layer *layer = &plane->layer;
422 const struct atmel_hlcdc_layer_cfg_layout *layout =
423 &layer->desc->layout;
424 int i;
425
Boris Brezillon2389fc12015-02-05 16:32:33 +0100426 atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
427 state->offsets);
Boris Brezillon1a396782015-01-06 11:13:28 +0100428
Boris Brezillon2389fc12015-02-05 16:32:33 +0100429 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100430 if (layout->xstride[i]) {
431 atmel_hlcdc_layer_update_cfg(&plane->layer,
432 layout->xstride[i],
433 0xffffffff,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100434 state->xstride[i]);
Boris Brezillon1a396782015-01-06 11:13:28 +0100435 }
436
437 if (layout->pstride[i]) {
438 atmel_hlcdc_layer_update_cfg(&plane->layer,
439 layout->pstride[i],
440 0xffffffff,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100441 state->pstride[i]);
Boris Brezillon1a396782015-01-06 11:13:28 +0100442 }
443 }
444}
445
Boris Brezillonebab87a2016-03-15 18:01:08 +0100446int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
447{
448 unsigned int ahb_load[2] = { };
449 struct drm_plane *plane;
450
451 drm_atomic_crtc_state_for_each_plane(plane, c_state) {
452 struct atmel_hlcdc_plane_state *plane_state;
453 struct drm_plane_state *plane_s;
454 unsigned int pixels, load = 0;
455 int i;
456
457 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
458 if (IS_ERR(plane_s))
459 return PTR_ERR(plane_s);
460
461 plane_state =
462 drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
463
464 pixels = (plane_state->src_w * plane_state->src_h) -
465 (plane_state->disc_w * plane_state->disc_h);
466
467 for (i = 0; i < plane_state->nplanes; i++)
468 load += pixels * plane_state->bpp[i];
469
470 if (ahb_load[0] <= ahb_load[1])
471 plane_state->ahb_id = 0;
472 else
473 plane_state->ahb_id = 1;
474
475 ahb_load[plane_state->ahb_id] += load;
476 }
477
478 return 0;
479}
480
Boris Brezillon59570172015-02-06 16:25:06 +0100481int
482atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
483{
484 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
485 const struct atmel_hlcdc_layer_cfg_layout *layout;
486 struct atmel_hlcdc_plane_state *primary_state;
487 struct drm_plane_state *primary_s;
488 struct atmel_hlcdc_plane *primary;
489 struct drm_plane *ovl;
490
491 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
492 layout = &primary->layer.desc->layout;
493 if (!layout->disc_pos || !layout->disc_size)
494 return 0;
495
496 primary_s = drm_atomic_get_plane_state(c_state->state,
497 &primary->base);
498 if (IS_ERR(primary_s))
499 return PTR_ERR(primary_s);
500
501 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
502
503 drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
504 struct atmel_hlcdc_plane_state *ovl_state;
505 struct drm_plane_state *ovl_s;
506
507 if (ovl == c_state->crtc->primary)
508 continue;
509
510 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
511 if (IS_ERR(ovl_s))
512 return PTR_ERR(ovl_s);
513
514 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
515
516 if (!ovl_s->fb ||
517 atmel_hlcdc_format_embeds_alpha(ovl_s->fb->pixel_format) ||
518 ovl_state->alpha != 255)
519 continue;
520
521 /* TODO: implement a smarter hidden area detection */
522 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
523 continue;
524
525 disc_x = ovl_state->crtc_x;
526 disc_y = ovl_state->crtc_y;
527 disc_h = ovl_state->crtc_h;
528 disc_w = ovl_state->crtc_w;
529 }
530
531 if (disc_x == primary_state->disc_x &&
532 disc_y == primary_state->disc_y &&
533 disc_w == primary_state->disc_w &&
534 disc_h == primary_state->disc_h)
535 return 0;
536
537
538 primary_state->disc_x = disc_x;
539 primary_state->disc_y = disc_y;
540 primary_state->disc_w = disc_w;
541 primary_state->disc_h = disc_h;
542 primary_state->disc_updated = true;
543
544 return 0;
545}
546
547static void
548atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
549 struct atmel_hlcdc_plane_state *state)
550{
551 const struct atmel_hlcdc_layer_cfg_layout *layout =
552 &plane->layer.desc->layout;
553 int disc_surface = 0;
554
555 if (!state->disc_updated)
556 return;
557
558 disc_surface = state->disc_h * state->disc_w;
559
560 atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
561 ATMEL_HLCDC_LAYER_DISCEN,
562 disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0);
563
564 if (!disc_surface)
565 return;
566
567 atmel_hlcdc_layer_update_cfg(&plane->layer,
568 layout->disc_pos,
569 0xffffffff,
570 state->disc_x | (state->disc_y << 16));
571
572 atmel_hlcdc_layer_update_cfg(&plane->layer,
573 layout->disc_size,
574 0xffffffff,
575 (state->disc_w - 1) |
576 ((state->disc_h - 1) << 16));
577}
578
Boris Brezillon2389fc12015-02-05 16:32:33 +0100579static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
580 struct drm_plane_state *s)
Boris Brezillon1a396782015-01-06 11:13:28 +0100581{
582 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100583 struct atmel_hlcdc_plane_state *state =
584 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon1a396782015-01-06 11:13:28 +0100585 const struct atmel_hlcdc_layer_cfg_layout *layout =
586 &plane->layer.desc->layout;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100587 struct drm_framebuffer *fb = state->base.fb;
588 const struct drm_display_mode *mode;
589 struct drm_crtc_state *crtc_state;
Boris Brezillon1a396782015-01-06 11:13:28 +0100590 unsigned int patched_crtc_w;
591 unsigned int patched_crtc_h;
592 unsigned int patched_src_w;
593 unsigned int patched_src_h;
594 unsigned int tmp;
595 int x_offset = 0;
596 int y_offset = 0;
597 int hsub = 1;
598 int vsub = 1;
599 int i;
600
Boris Brezillon2389fc12015-02-05 16:32:33 +0100601 if (!state->base.crtc || !fb)
602 return 0;
603
Andrzej Hajdab47ff7e2016-03-15 13:46:28 +0100604 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100605 mode = &crtc_state->adjusted_mode;
606
607 state->src_x = s->src_x;
608 state->src_y = s->src_y;
609 state->src_h = s->src_h;
610 state->src_w = s->src_w;
611 state->crtc_x = s->crtc_x;
612 state->crtc_y = s->crtc_y;
613 state->crtc_h = s->crtc_h;
614 state->crtc_w = s->crtc_w;
615 if ((state->src_x | state->src_y | state->src_w | state->src_h) &
Boris Brezillon1a396782015-01-06 11:13:28 +0100616 SUBPIXEL_MASK)
617 return -EINVAL;
618
Boris Brezillon2389fc12015-02-05 16:32:33 +0100619 state->src_x >>= 16;
620 state->src_y >>= 16;
621 state->src_w >>= 16;
622 state->src_h >>= 16;
Boris Brezillon1a396782015-01-06 11:13:28 +0100623
Boris Brezillon2389fc12015-02-05 16:32:33 +0100624 state->nplanes = drm_format_num_planes(fb->pixel_format);
625 if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
Boris Brezillon1a396782015-01-06 11:13:28 +0100626 return -EINVAL;
627
628 /*
629 * Swap width and size in case of 90 or 270 degrees rotation
630 */
Ville Syrjäläbd2ef252016-09-26 19:30:46 +0300631 if (drm_rotation_90_or_270(state->base.rotation)) {
Boris Brezillon2389fc12015-02-05 16:32:33 +0100632 tmp = state->crtc_w;
633 state->crtc_w = state->crtc_h;
634 state->crtc_h = tmp;
635 tmp = state->src_w;
636 state->src_w = state->src_h;
637 state->src_h = tmp;
Boris Brezillon1a396782015-01-06 11:13:28 +0100638 }
639
Boris Brezillon2389fc12015-02-05 16:32:33 +0100640 if (state->crtc_x + state->crtc_w > mode->hdisplay)
641 patched_crtc_w = mode->hdisplay - state->crtc_x;
Boris Brezillon1a396782015-01-06 11:13:28 +0100642 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100643 patched_crtc_w = state->crtc_w;
Boris Brezillon1a396782015-01-06 11:13:28 +0100644
Boris Brezillon2389fc12015-02-05 16:32:33 +0100645 if (state->crtc_x < 0) {
646 patched_crtc_w += state->crtc_x;
647 x_offset = -state->crtc_x;
648 state->crtc_x = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100649 }
650
Boris Brezillon2389fc12015-02-05 16:32:33 +0100651 if (state->crtc_y + state->crtc_h > mode->vdisplay)
652 patched_crtc_h = mode->vdisplay - state->crtc_y;
Boris Brezillon1a396782015-01-06 11:13:28 +0100653 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100654 patched_crtc_h = state->crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100655
Boris Brezillon2389fc12015-02-05 16:32:33 +0100656 if (state->crtc_y < 0) {
657 patched_crtc_h += state->crtc_y;
658 y_offset = -state->crtc_y;
659 state->crtc_y = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100660 }
661
Boris Brezillon2389fc12015-02-05 16:32:33 +0100662 patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
663 state->crtc_w);
664 patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
665 state->crtc_h);
Boris Brezillon1a396782015-01-06 11:13:28 +0100666
Boris Brezillon2389fc12015-02-05 16:32:33 +0100667 hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
668 vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
Boris Brezillon1a396782015-01-06 11:13:28 +0100669
Boris Brezillon2389fc12015-02-05 16:32:33 +0100670 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100671 unsigned int offset = 0;
672 int xdiv = i ? hsub : 1;
673 int ydiv = i ? vsub : 1;
674
Boris Brezillon2389fc12015-02-05 16:32:33 +0100675 state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
676 if (!state->bpp[i])
Boris Brezillon1a396782015-01-06 11:13:28 +0100677 return -EINVAL;
678
Joonas Lahtinen14152c82015-10-01 10:00:58 +0300679 switch (state->base.rotation & DRM_ROTATE_MASK) {
Joonas Lahtinen31ad61e2016-07-29 08:50:05 +0300680 case DRM_ROTATE_90:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100681 offset = ((y_offset + state->src_y + patched_src_w - 1) /
682 ydiv) * fb->pitches[i];
683 offset += ((x_offset + state->src_x) / xdiv) *
684 state->bpp[i];
685 state->xstride[i] = ((patched_src_w - 1) / ydiv) *
686 fb->pitches[i];
687 state->pstride[i] = -fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100688 break;
Joonas Lahtinen31ad61e2016-07-29 08:50:05 +0300689 case DRM_ROTATE_180:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100690 offset = ((y_offset + state->src_y + patched_src_h - 1) /
691 ydiv) * fb->pitches[i];
692 offset += ((x_offset + state->src_x + patched_src_w - 1) /
693 xdiv) * state->bpp[i];
694 state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
695 state->bpp[i]) - fb->pitches[i];
696 state->pstride[i] = -2 * state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100697 break;
Joonas Lahtinen31ad61e2016-07-29 08:50:05 +0300698 case DRM_ROTATE_270:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100699 offset = ((y_offset + state->src_y) / ydiv) *
700 fb->pitches[i];
701 offset += ((x_offset + state->src_x + patched_src_h - 1) /
702 xdiv) * state->bpp[i];
703 state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
704 fb->pitches[i]) -
705 (2 * state->bpp[i]);
706 state->pstride[i] = fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100707 break;
Joonas Lahtinen31ad61e2016-07-29 08:50:05 +0300708 case DRM_ROTATE_0:
Boris Brezillon1a396782015-01-06 11:13:28 +0100709 default:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100710 offset = ((y_offset + state->src_y) / ydiv) *
711 fb->pitches[i];
712 offset += ((x_offset + state->src_x) / xdiv) *
713 state->bpp[i];
714 state->xstride[i] = fb->pitches[i] -
Boris Brezillon1a396782015-01-06 11:13:28 +0100715 ((patched_src_w / xdiv) *
Boris Brezillon2389fc12015-02-05 16:32:33 +0100716 state->bpp[i]);
717 state->pstride[i] = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100718 break;
719 }
720
Boris Brezillon2389fc12015-02-05 16:32:33 +0100721 state->offsets[i] = offset + fb->offsets[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100722 }
723
Boris Brezillon2389fc12015-02-05 16:32:33 +0100724 state->src_w = patched_src_w;
725 state->src_h = patched_src_h;
726 state->crtc_w = patched_crtc_w;
727 state->crtc_h = patched_crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100728
Boris Brezillon2389fc12015-02-05 16:32:33 +0100729 if (!layout->size &&
730 (mode->hdisplay != state->crtc_w ||
731 mode->vdisplay != state->crtc_h))
732 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100733
Boris Brezillon2389fc12015-02-05 16:32:33 +0100734 if (plane->layer.desc->max_height &&
735 state->crtc_h > plane->layer.desc->max_height)
736 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100737
Boris Brezillon2389fc12015-02-05 16:32:33 +0100738 if (plane->layer.desc->max_width &&
739 state->crtc_w > plane->layer.desc->max_width)
740 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100741
Boris Brezillon2389fc12015-02-05 16:32:33 +0100742 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
743 (!layout->memsize ||
744 atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
745 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100746
Boris Brezillon2389fc12015-02-05 16:32:33 +0100747 if (state->crtc_x < 0 || state->crtc_y < 0)
748 return -EINVAL;
749
750 if (state->crtc_w + state->crtc_x > mode->hdisplay ||
751 state->crtc_h + state->crtc_y > mode->vdisplay)
752 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100753
754 return 0;
755}
756
Boris Brezillon2389fc12015-02-05 16:32:33 +0100757static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
Chris Wilson18320402016-08-18 19:00:16 +0100758 struct drm_plane_state *new_state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100759{
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200760 /*
761 * FIXME: we should avoid this const -> non-const cast but it's
762 * currently the only solution we have to modify the ->prepared
763 * state and rollback the update request.
764 * Ideally, we should rework the code to attach all the resources
765 * to atmel_hlcdc_plane_state (including the DMA desc allocation),
766 * but this require a complete rework of the atmel_hlcdc_layer
767 * code.
768 */
769 struct drm_plane_state *s = (struct drm_plane_state *)new_state;
Boris Brezillon1a396782015-01-06 11:13:28 +0100770 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200771 struct atmel_hlcdc_plane_state *state =
772 drm_plane_state_to_atmel_hlcdc_plane_state(s);
773 int ret;
Boris Brezillon1a396782015-01-06 11:13:28 +0100774
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200775 ret = atmel_hlcdc_layer_update_start(&plane->layer);
776 if (!ret)
777 state->prepared = true;
Maarten Lankhorst844f9112015-09-02 10:42:40 +0200778
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200779 return ret;
780}
781
782static void atmel_hlcdc_plane_cleanup_fb(struct drm_plane *p,
Chris Wilson18320402016-08-18 19:00:16 +0100783 struct drm_plane_state *old_state)
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200784{
785 /*
786 * FIXME: we should avoid this const -> non-const cast but it's
787 * currently the only solution we have to modify the ->prepared
788 * state and rollback the update request.
789 * Ideally, we should rework the code to attach all the resources
790 * to atmel_hlcdc_plane_state (including the DMA desc allocation),
791 * but this require a complete rework of the atmel_hlcdc_layer
792 * code.
793 */
794 struct drm_plane_state *s = (struct drm_plane_state *)old_state;
795 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
796 struct atmel_hlcdc_plane_state *state =
797 drm_plane_state_to_atmel_hlcdc_plane_state(s);
798
799 /*
800 * The Request has already been applied or cancelled, nothing to do
801 * here.
802 */
803 if (!state->prepared)
804 return;
805
806 atmel_hlcdc_layer_update_rollback(&plane->layer);
807 state->prepared = false;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100808}
809
810static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
811 struct drm_plane_state *old_s)
812{
813 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
814 struct atmel_hlcdc_plane_state *state =
815 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
816
817 if (!p->state->crtc || !p->state->fb)
818 return;
819
820 atmel_hlcdc_plane_update_pos_and_size(plane, state);
821 atmel_hlcdc_plane_update_general_settings(plane, state);
822 atmel_hlcdc_plane_update_format(plane, state);
823 atmel_hlcdc_plane_update_buffers(plane, state);
Boris Brezillon59570172015-02-06 16:25:06 +0100824 atmel_hlcdc_plane_update_disc_area(plane, state);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100825
826 atmel_hlcdc_layer_update_commit(&plane->layer);
827}
828
829static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
830 struct drm_plane_state *old_state)
831{
832 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
833
834 atmel_hlcdc_layer_disable(&plane->layer);
Boris Brezillon1a396782015-01-06 11:13:28 +0100835}
836
837static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
838{
839 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
840
841 if (plane->base.fb)
842 drm_framebuffer_unreference(plane->base.fb);
843
844 atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
845
846 drm_plane_cleanup(p);
847 devm_kfree(p->dev->dev, plane);
848}
849
Boris Brezillon2389fc12015-02-05 16:32:33 +0100850static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
851 struct drm_plane_state *s,
852 struct drm_property *property,
853 uint64_t val)
Boris Brezillon1a396782015-01-06 11:13:28 +0100854{
855 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
856 struct atmel_hlcdc_plane_properties *props = plane->properties;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100857 struct atmel_hlcdc_plane_state *state =
858 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon1a396782015-01-06 11:13:28 +0100859
860 if (property == props->alpha)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100861 state->alpha = val;
862 else
863 return -EINVAL;
864
865 return 0;
866}
867
868static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
869 const struct drm_plane_state *s,
870 struct drm_property *property,
871 uint64_t *val)
872{
873 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
874 struct atmel_hlcdc_plane_properties *props = plane->properties;
875 const struct atmel_hlcdc_plane_state *state =
876 container_of(s, const struct atmel_hlcdc_plane_state, base);
877
878 if (property == props->alpha)
879 *val = state->alpha;
Boris Brezillon1a396782015-01-06 11:13:28 +0100880 else
881 return -EINVAL;
882
883 return 0;
884}
885
886static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
887 const struct atmel_hlcdc_layer_desc *desc,
888 struct atmel_hlcdc_plane_properties *props)
889{
890 struct regmap *regmap = plane->layer.hlcdc->regmap;
891
892 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
893 desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
894 drm_object_attach_property(&plane->base.base,
895 props->alpha, 255);
896
897 /* Set default alpha value */
898 regmap_update_bits(regmap,
899 desc->regs_offset +
900 ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
901 ATMEL_HLCDC_LAYER_GA_MASK,
902 ATMEL_HLCDC_LAYER_GA_MASK);
903 }
904
905 if (desc->layout.xstride && desc->layout.pstride)
906 drm_object_attach_property(&plane->base.base,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100907 plane->base.dev->mode_config.rotation_property,
Joonas Lahtinen31ad61e2016-07-29 08:50:05 +0300908 DRM_ROTATE_0);
Boris Brezillon1a396782015-01-06 11:13:28 +0100909
910 if (desc->layout.csc) {
911 /*
912 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
913 * userspace modify these factors (using a BLOB property ?).
914 */
915 regmap_write(regmap,
916 desc->regs_offset +
917 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
918 0x4c900091);
919 regmap_write(regmap,
920 desc->regs_offset +
921 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
922 0x7a5f5090);
923 regmap_write(regmap,
924 desc->regs_offset +
925 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
926 0x40040890);
927 }
928}
929
Boris Brezillon2389fc12015-02-05 16:32:33 +0100930static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
931 .prepare_fb = atmel_hlcdc_plane_prepare_fb,
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200932 .cleanup_fb = atmel_hlcdc_plane_cleanup_fb,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100933 .atomic_check = atmel_hlcdc_plane_atomic_check,
934 .atomic_update = atmel_hlcdc_plane_atomic_update,
935 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
936};
937
938static void atmel_hlcdc_plane_reset(struct drm_plane *p)
939{
940 struct atmel_hlcdc_plane_state *state;
941
942 if (p->state) {
943 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
944
945 if (state->base.fb)
946 drm_framebuffer_unreference(state->base.fb);
947
948 kfree(state);
949 p->state = NULL;
950 }
951
952 state = kzalloc(sizeof(*state), GFP_KERNEL);
953 if (state) {
954 state->alpha = 255;
955 p->state = &state->base;
956 p->state->plane = p;
957 }
958}
959
960static struct drm_plane_state *
961atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
962{
963 struct atmel_hlcdc_plane_state *state =
964 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
965 struct atmel_hlcdc_plane_state *copy;
966
967 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
968 if (!copy)
969 return NULL;
970
Boris Brezillon59570172015-02-06 16:25:06 +0100971 copy->disc_updated = false;
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200972 copy->prepared = false;
Boris Brezillon59570172015-02-06 16:25:06 +0100973
Boris Brezillon2389fc12015-02-05 16:32:33 +0100974 if (copy->base.fb)
975 drm_framebuffer_reference(copy->base.fb);
976
977 return &copy->base;
978}
979
980static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
981 struct drm_plane_state *s)
982{
983 struct atmel_hlcdc_plane_state *state =
984 drm_plane_state_to_atmel_hlcdc_plane_state(s);
985
986 if (s->fb)
987 drm_framebuffer_unreference(s->fb);
988
989 kfree(state);
990}
991
Boris Brezillon1a396782015-01-06 11:13:28 +0100992static struct drm_plane_funcs layer_plane_funcs = {
Boris Brezillon2389fc12015-02-05 16:32:33 +0100993 .update_plane = drm_atomic_helper_update_plane,
994 .disable_plane = drm_atomic_helper_disable_plane,
995 .set_property = drm_atomic_helper_plane_set_property,
Boris Brezillon1a396782015-01-06 11:13:28 +0100996 .destroy = atmel_hlcdc_plane_destroy,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100997 .reset = atmel_hlcdc_plane_reset,
998 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
999 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
1000 .atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
1001 .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
Boris Brezillon1a396782015-01-06 11:13:28 +01001002};
1003
1004static struct atmel_hlcdc_plane *
1005atmel_hlcdc_plane_create(struct drm_device *dev,
1006 const struct atmel_hlcdc_layer_desc *desc,
1007 struct atmel_hlcdc_plane_properties *props)
1008{
1009 struct atmel_hlcdc_plane *plane;
1010 enum drm_plane_type type;
1011 int ret;
1012
1013 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
1014 if (!plane)
1015 return ERR_PTR(-ENOMEM);
1016
1017 ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
1018 if (ret)
1019 return ERR_PTR(ret);
1020
1021 if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1022 type = DRM_PLANE_TYPE_PRIMARY;
1023 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1024 type = DRM_PLANE_TYPE_CURSOR;
1025 else
1026 type = DRM_PLANE_TYPE_OVERLAY;
1027
1028 ret = drm_universal_plane_init(dev, &plane->base, 0,
1029 &layer_plane_funcs,
1030 desc->formats->formats,
Ville Syrjäläb0b3b792015-12-09 16:19:55 +02001031 desc->formats->nformats, type, NULL);
Boris Brezillon1a396782015-01-06 11:13:28 +01001032 if (ret)
1033 return ERR_PTR(ret);
1034
Boris Brezillon2389fc12015-02-05 16:32:33 +01001035 drm_plane_helper_add(&plane->base,
1036 &atmel_hlcdc_layer_plane_helper_funcs);
1037
Boris Brezillon1a396782015-01-06 11:13:28 +01001038 /* Set default property values*/
1039 atmel_hlcdc_plane_init_properties(plane, desc, props);
1040
1041 return plane;
1042}
1043
1044static struct atmel_hlcdc_plane_properties *
1045atmel_hlcdc_plane_create_properties(struct drm_device *dev)
1046{
1047 struct atmel_hlcdc_plane_properties *props;
1048
1049 props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
1050 if (!props)
1051 return ERR_PTR(-ENOMEM);
1052
1053 props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
1054 if (!props->alpha)
1055 return ERR_PTR(-ENOMEM);
1056
Boris Brezillon2389fc12015-02-05 16:32:33 +01001057 dev->mode_config.rotation_property =
1058 drm_mode_create_rotation_property(dev,
Joonas Lahtinen31ad61e2016-07-29 08:50:05 +03001059 DRM_ROTATE_0 |
1060 DRM_ROTATE_90 |
1061 DRM_ROTATE_180 |
1062 DRM_ROTATE_270);
Boris Brezillon2389fc12015-02-05 16:32:33 +01001063 if (!dev->mode_config.rotation_property)
Boris Brezillon1a396782015-01-06 11:13:28 +01001064 return ERR_PTR(-ENOMEM);
1065
1066 return props;
1067}
1068
1069struct atmel_hlcdc_planes *
1070atmel_hlcdc_create_planes(struct drm_device *dev)
1071{
1072 struct atmel_hlcdc_dc *dc = dev->dev_private;
1073 struct atmel_hlcdc_plane_properties *props;
1074 struct atmel_hlcdc_planes *planes;
1075 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1076 int nlayers = dc->desc->nlayers;
1077 int i;
1078
1079 planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
1080 if (!planes)
1081 return ERR_PTR(-ENOMEM);
1082
1083 for (i = 0; i < nlayers; i++) {
1084 if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
1085 planes->noverlays++;
1086 }
1087
1088 if (planes->noverlays) {
1089 planes->overlays = devm_kzalloc(dev->dev,
1090 planes->noverlays *
1091 sizeof(*planes->overlays),
1092 GFP_KERNEL);
1093 if (!planes->overlays)
1094 return ERR_PTR(-ENOMEM);
1095 }
1096
1097 props = atmel_hlcdc_plane_create_properties(dev);
1098 if (IS_ERR(props))
1099 return ERR_CAST(props);
1100
1101 planes->noverlays = 0;
1102 for (i = 0; i < nlayers; i++) {
1103 struct atmel_hlcdc_plane *plane;
1104
1105 if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
1106 continue;
1107
1108 plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
1109 if (IS_ERR(plane))
1110 return ERR_CAST(plane);
1111
1112 plane->properties = props;
1113
1114 switch (descs[i].type) {
1115 case ATMEL_HLCDC_BASE_LAYER:
1116 if (planes->primary)
1117 return ERR_PTR(-EINVAL);
1118 planes->primary = plane;
1119 break;
1120
1121 case ATMEL_HLCDC_OVERLAY_LAYER:
1122 planes->overlays[planes->noverlays++] = plane;
1123 break;
1124
1125 case ATMEL_HLCDC_CURSOR_LAYER:
1126 if (planes->cursor)
1127 return ERR_PTR(-EINVAL);
1128 planes->cursor = plane;
1129 break;
1130
1131 default:
1132 break;
1133 }
1134 }
1135
1136 return planes;
1137}