blob: 2158d7a61c5e5c333b7a28d5d59fdc749001f5df [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 Brezillon2389fc12015-02-05 16:32:33 +010062 /* These fields are private and should not be touched */
63 int bpp[ATMEL_HLCDC_MAX_PLANES];
64 unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
65 int xstride[ATMEL_HLCDC_MAX_PLANES];
66 int pstride[ATMEL_HLCDC_MAX_PLANES];
67 int nplanes;
Boris Brezillon1a7b37c2015-10-10 07:55:39 +020068 bool prepared;
Boris Brezillon2389fc12015-02-05 16:32:33 +010069};
70
71static inline struct atmel_hlcdc_plane_state *
72drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
73{
74 return container_of(s, struct atmel_hlcdc_plane_state, base);
75}
76
Boris Brezillon1a396782015-01-06 11:13:28 +010077#define SUBPIXEL_MASK 0xffff
78
79static uint32_t rgb_formats[] = {
80 DRM_FORMAT_XRGB4444,
81 DRM_FORMAT_ARGB4444,
82 DRM_FORMAT_RGBA4444,
83 DRM_FORMAT_ARGB1555,
84 DRM_FORMAT_RGB565,
85 DRM_FORMAT_RGB888,
86 DRM_FORMAT_XRGB8888,
87 DRM_FORMAT_ARGB8888,
88 DRM_FORMAT_RGBA8888,
89};
90
91struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
92 .formats = rgb_formats,
93 .nformats = ARRAY_SIZE(rgb_formats),
94};
95
96static uint32_t rgb_and_yuv_formats[] = {
97 DRM_FORMAT_XRGB4444,
98 DRM_FORMAT_ARGB4444,
99 DRM_FORMAT_RGBA4444,
100 DRM_FORMAT_ARGB1555,
101 DRM_FORMAT_RGB565,
102 DRM_FORMAT_RGB888,
103 DRM_FORMAT_XRGB8888,
104 DRM_FORMAT_ARGB8888,
105 DRM_FORMAT_RGBA8888,
106 DRM_FORMAT_AYUV,
107 DRM_FORMAT_YUYV,
108 DRM_FORMAT_UYVY,
109 DRM_FORMAT_YVYU,
110 DRM_FORMAT_VYUY,
111 DRM_FORMAT_NV21,
112 DRM_FORMAT_NV61,
113 DRM_FORMAT_YUV422,
114 DRM_FORMAT_YUV420,
115};
116
117struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
118 .formats = rgb_and_yuv_formats,
119 .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
120};
121
122static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
123{
124 switch (format) {
125 case DRM_FORMAT_XRGB4444:
126 *mode = ATMEL_HLCDC_XRGB4444_MODE;
127 break;
128 case DRM_FORMAT_ARGB4444:
129 *mode = ATMEL_HLCDC_ARGB4444_MODE;
130 break;
131 case DRM_FORMAT_RGBA4444:
132 *mode = ATMEL_HLCDC_RGBA4444_MODE;
133 break;
134 case DRM_FORMAT_RGB565:
135 *mode = ATMEL_HLCDC_RGB565_MODE;
136 break;
137 case DRM_FORMAT_RGB888:
138 *mode = ATMEL_HLCDC_RGB888_MODE;
139 break;
140 case DRM_FORMAT_ARGB1555:
141 *mode = ATMEL_HLCDC_ARGB1555_MODE;
142 break;
143 case DRM_FORMAT_XRGB8888:
144 *mode = ATMEL_HLCDC_XRGB8888_MODE;
145 break;
146 case DRM_FORMAT_ARGB8888:
147 *mode = ATMEL_HLCDC_ARGB8888_MODE;
148 break;
149 case DRM_FORMAT_RGBA8888:
150 *mode = ATMEL_HLCDC_RGBA8888_MODE;
151 break;
152 case DRM_FORMAT_AYUV:
153 *mode = ATMEL_HLCDC_AYUV_MODE;
154 break;
155 case DRM_FORMAT_YUYV:
156 *mode = ATMEL_HLCDC_YUYV_MODE;
157 break;
158 case DRM_FORMAT_UYVY:
159 *mode = ATMEL_HLCDC_UYVY_MODE;
160 break;
161 case DRM_FORMAT_YVYU:
162 *mode = ATMEL_HLCDC_YVYU_MODE;
163 break;
164 case DRM_FORMAT_VYUY:
165 *mode = ATMEL_HLCDC_VYUY_MODE;
166 break;
167 case DRM_FORMAT_NV21:
168 *mode = ATMEL_HLCDC_NV21_MODE;
169 break;
170 case DRM_FORMAT_NV61:
171 *mode = ATMEL_HLCDC_NV61_MODE;
172 break;
173 case DRM_FORMAT_YUV420:
174 *mode = ATMEL_HLCDC_YUV420_MODE;
175 break;
176 case DRM_FORMAT_YUV422:
177 *mode = ATMEL_HLCDC_YUV422_MODE;
178 break;
179 default:
180 return -ENOTSUPP;
181 }
182
183 return 0;
184}
185
Boris Brezillon2389fc12015-02-05 16:32:33 +0100186static bool atmel_hlcdc_format_embeds_alpha(u32 format)
Boris Brezillon1a396782015-01-06 11:13:28 +0100187{
188 int i;
189
190 for (i = 0; i < sizeof(format); i++) {
191 char tmp = (format >> (8 * i)) & 0xff;
192
193 if (tmp == 'A')
194 return true;
195 }
196
197 return false;
198}
199
200static u32 heo_downscaling_xcoef[] = {
201 0x11343311,
202 0x000000f7,
203 0x1635300c,
204 0x000000f9,
205 0x1b362c08,
206 0x000000fb,
207 0x1f372804,
208 0x000000fe,
209 0x24382400,
210 0x00000000,
211 0x28371ffe,
212 0x00000004,
213 0x2c361bfb,
214 0x00000008,
215 0x303516f9,
216 0x0000000c,
217};
218
219static u32 heo_downscaling_ycoef[] = {
220 0x00123737,
221 0x00173732,
222 0x001b382d,
223 0x001f3928,
224 0x00243824,
225 0x0028391f,
226 0x002d381b,
227 0x00323717,
228};
229
230static u32 heo_upscaling_xcoef[] = {
231 0xf74949f7,
232 0x00000000,
233 0xf55f33fb,
234 0x000000fe,
235 0xf5701efe,
236 0x000000ff,
237 0xf87c0dff,
238 0x00000000,
239 0x00800000,
240 0x00000000,
241 0x0d7cf800,
242 0x000000ff,
243 0x1e70f5ff,
244 0x000000fe,
245 0x335ff5fe,
246 0x000000fb,
247};
248
249static u32 heo_upscaling_ycoef[] = {
250 0x00004040,
251 0x00075920,
252 0x00056f0c,
253 0x00027b03,
254 0x00008000,
255 0x00037b02,
256 0x000c6f05,
257 0x00205907,
258};
259
260static void
261atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100262 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100263{
264 const struct atmel_hlcdc_layer_cfg_layout *layout =
265 &plane->layer.desc->layout;
266
267 if (layout->size)
268 atmel_hlcdc_layer_update_cfg(&plane->layer,
269 layout->size,
270 0xffffffff,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100271 (state->crtc_w - 1) |
272 ((state->crtc_h - 1) << 16));
Boris Brezillon1a396782015-01-06 11:13:28 +0100273
274 if (layout->memsize)
275 atmel_hlcdc_layer_update_cfg(&plane->layer,
276 layout->memsize,
277 0xffffffff,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100278 (state->src_w - 1) |
279 ((state->src_h - 1) << 16));
Boris Brezillon1a396782015-01-06 11:13:28 +0100280
281 if (layout->pos)
282 atmel_hlcdc_layer_update_cfg(&plane->layer,
283 layout->pos,
284 0xffffffff,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100285 state->crtc_x |
286 (state->crtc_y << 16));
Boris Brezillon1a396782015-01-06 11:13:28 +0100287
288 /* TODO: rework the rescaling part */
Boris Brezillon2389fc12015-02-05 16:32:33 +0100289 if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100290 u32 factor_reg = 0;
291
Boris Brezillon2389fc12015-02-05 16:32:33 +0100292 if (state->crtc_w != state->src_w) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100293 int i;
294 u32 factor;
295 u32 *coeff_tab = heo_upscaling_xcoef;
296 u32 max_memsize;
297
Boris Brezillon2389fc12015-02-05 16:32:33 +0100298 if (state->crtc_w < state->src_w)
Boris Brezillon1a396782015-01-06 11:13:28 +0100299 coeff_tab = heo_downscaling_xcoef;
300 for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
301 atmel_hlcdc_layer_update_cfg(&plane->layer,
302 17 + i,
303 0xffffffff,
304 coeff_tab[i]);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100305 factor = ((8 * 256 * state->src_w) - (256 * 4)) /
306 state->crtc_w;
Boris Brezillon1a396782015-01-06 11:13:28 +0100307 factor++;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100308 max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
Boris Brezillon1a396782015-01-06 11:13:28 +0100309 2048;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100310 if (max_memsize > state->src_w)
Boris Brezillon1a396782015-01-06 11:13:28 +0100311 factor--;
312 factor_reg |= factor | 0x80000000;
313 }
314
Boris Brezillon2389fc12015-02-05 16:32:33 +0100315 if (state->crtc_h != state->src_h) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100316 int i;
317 u32 factor;
318 u32 *coeff_tab = heo_upscaling_ycoef;
319 u32 max_memsize;
320
Boris Brezillon2389fc12015-02-05 16:32:33 +0100321 if (state->crtc_w < state->src_w)
Boris Brezillon1a396782015-01-06 11:13:28 +0100322 coeff_tab = heo_downscaling_ycoef;
323 for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
324 atmel_hlcdc_layer_update_cfg(&plane->layer,
325 33 + i,
326 0xffffffff,
327 coeff_tab[i]);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100328 factor = ((8 * 256 * state->src_w) - (256 * 4)) /
329 state->crtc_w;
Boris Brezillon1a396782015-01-06 11:13:28 +0100330 factor++;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100331 max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
Boris Brezillon1a396782015-01-06 11:13:28 +0100332 2048;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100333 if (max_memsize > state->src_w)
Boris Brezillon1a396782015-01-06 11:13:28 +0100334 factor--;
335 factor_reg |= (factor << 16) | 0x80000000;
336 }
337
338 atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
339 factor_reg);
340 }
341}
342
343static void
344atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100345 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100346{
347 const struct atmel_hlcdc_layer_cfg_layout *layout =
348 &plane->layer.desc->layout;
349 unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
350
351 if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
352 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
353 ATMEL_HLCDC_LAYER_ITER;
354
Boris Brezillon2389fc12015-02-05 16:32:33 +0100355 if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
Boris Brezillon1a396782015-01-06 11:13:28 +0100356 cfg |= ATMEL_HLCDC_LAYER_LAEN;
357 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100358 cfg |= ATMEL_HLCDC_LAYER_GAEN |
359 ATMEL_HLCDC_LAYER_GA(state->alpha);
Boris Brezillon1a396782015-01-06 11:13:28 +0100360 }
361
362 atmel_hlcdc_layer_update_cfg(&plane->layer,
363 ATMEL_HLCDC_LAYER_DMA_CFG_ID,
364 ATMEL_HLCDC_LAYER_DMA_BLEN_MASK,
365 ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16);
366
367 atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
368 ATMEL_HLCDC_LAYER_ITER2BL |
369 ATMEL_HLCDC_LAYER_ITER |
370 ATMEL_HLCDC_LAYER_GAEN |
Boris Brezillon2389fc12015-02-05 16:32:33 +0100371 ATMEL_HLCDC_LAYER_GA_MASK |
Boris Brezillon1a396782015-01-06 11:13:28 +0100372 ATMEL_HLCDC_LAYER_LAEN |
373 ATMEL_HLCDC_LAYER_OVR |
374 ATMEL_HLCDC_LAYER_DMA, cfg);
375}
376
377static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100378 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100379{
380 u32 cfg;
381 int ret;
382
Boris Brezillon2389fc12015-02-05 16:32:33 +0100383 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
384 &cfg);
Boris Brezillon1a396782015-01-06 11:13:28 +0100385 if (ret)
386 return;
387
Boris Brezillon2389fc12015-02-05 16:32:33 +0100388 if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 ||
389 state->base.fb->pixel_format == DRM_FORMAT_NV61) &&
390 (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
Boris Brezillon1a396782015-01-06 11:13:28 +0100391 cfg |= ATMEL_HLCDC_YUV422ROT;
392
393 atmel_hlcdc_layer_update_cfg(&plane->layer,
394 ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
395 0xffffffff,
396 cfg);
397
398 /*
399 * Rotation optimization is not working on RGB888 (rotation is still
400 * working but without any optimization).
401 */
Boris Brezillon2389fc12015-02-05 16:32:33 +0100402 if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
Boris Brezillon1a396782015-01-06 11:13:28 +0100403 cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
404 else
405 cfg = 0;
406
407 atmel_hlcdc_layer_update_cfg(&plane->layer,
408 ATMEL_HLCDC_LAYER_DMA_CFG_ID,
409 ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
410}
411
412static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100413 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100414{
415 struct atmel_hlcdc_layer *layer = &plane->layer;
416 const struct atmel_hlcdc_layer_cfg_layout *layout =
417 &layer->desc->layout;
418 int i;
419
Boris Brezillon2389fc12015-02-05 16:32:33 +0100420 atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
421 state->offsets);
Boris Brezillon1a396782015-01-06 11:13:28 +0100422
Boris Brezillon2389fc12015-02-05 16:32:33 +0100423 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100424 if (layout->xstride[i]) {
425 atmel_hlcdc_layer_update_cfg(&plane->layer,
426 layout->xstride[i],
427 0xffffffff,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100428 state->xstride[i]);
Boris Brezillon1a396782015-01-06 11:13:28 +0100429 }
430
431 if (layout->pstride[i]) {
432 atmel_hlcdc_layer_update_cfg(&plane->layer,
433 layout->pstride[i],
434 0xffffffff,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100435 state->pstride[i]);
Boris Brezillon1a396782015-01-06 11:13:28 +0100436 }
437 }
438}
439
Boris Brezillon59570172015-02-06 16:25:06 +0100440int
441atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
442{
443 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
444 const struct atmel_hlcdc_layer_cfg_layout *layout;
445 struct atmel_hlcdc_plane_state *primary_state;
446 struct drm_plane_state *primary_s;
447 struct atmel_hlcdc_plane *primary;
448 struct drm_plane *ovl;
449
450 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
451 layout = &primary->layer.desc->layout;
452 if (!layout->disc_pos || !layout->disc_size)
453 return 0;
454
455 primary_s = drm_atomic_get_plane_state(c_state->state,
456 &primary->base);
457 if (IS_ERR(primary_s))
458 return PTR_ERR(primary_s);
459
460 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
461
462 drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
463 struct atmel_hlcdc_plane_state *ovl_state;
464 struct drm_plane_state *ovl_s;
465
466 if (ovl == c_state->crtc->primary)
467 continue;
468
469 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
470 if (IS_ERR(ovl_s))
471 return PTR_ERR(ovl_s);
472
473 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
474
475 if (!ovl_s->fb ||
476 atmel_hlcdc_format_embeds_alpha(ovl_s->fb->pixel_format) ||
477 ovl_state->alpha != 255)
478 continue;
479
480 /* TODO: implement a smarter hidden area detection */
481 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
482 continue;
483
484 disc_x = ovl_state->crtc_x;
485 disc_y = ovl_state->crtc_y;
486 disc_h = ovl_state->crtc_h;
487 disc_w = ovl_state->crtc_w;
488 }
489
490 if (disc_x == primary_state->disc_x &&
491 disc_y == primary_state->disc_y &&
492 disc_w == primary_state->disc_w &&
493 disc_h == primary_state->disc_h)
494 return 0;
495
496
497 primary_state->disc_x = disc_x;
498 primary_state->disc_y = disc_y;
499 primary_state->disc_w = disc_w;
500 primary_state->disc_h = disc_h;
501 primary_state->disc_updated = true;
502
503 return 0;
504}
505
506static void
507atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
508 struct atmel_hlcdc_plane_state *state)
509{
510 const struct atmel_hlcdc_layer_cfg_layout *layout =
511 &plane->layer.desc->layout;
512 int disc_surface = 0;
513
514 if (!state->disc_updated)
515 return;
516
517 disc_surface = state->disc_h * state->disc_w;
518
519 atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
520 ATMEL_HLCDC_LAYER_DISCEN,
521 disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0);
522
523 if (!disc_surface)
524 return;
525
526 atmel_hlcdc_layer_update_cfg(&plane->layer,
527 layout->disc_pos,
528 0xffffffff,
529 state->disc_x | (state->disc_y << 16));
530
531 atmel_hlcdc_layer_update_cfg(&plane->layer,
532 layout->disc_size,
533 0xffffffff,
534 (state->disc_w - 1) |
535 ((state->disc_h - 1) << 16));
536}
537
Boris Brezillon2389fc12015-02-05 16:32:33 +0100538static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
539 struct drm_plane_state *s)
Boris Brezillon1a396782015-01-06 11:13:28 +0100540{
541 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100542 struct atmel_hlcdc_plane_state *state =
543 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon1a396782015-01-06 11:13:28 +0100544 const struct atmel_hlcdc_layer_cfg_layout *layout =
545 &plane->layer.desc->layout;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100546 struct drm_framebuffer *fb = state->base.fb;
547 const struct drm_display_mode *mode;
548 struct drm_crtc_state *crtc_state;
Boris Brezillon1a396782015-01-06 11:13:28 +0100549 unsigned int patched_crtc_w;
550 unsigned int patched_crtc_h;
551 unsigned int patched_src_w;
552 unsigned int patched_src_h;
553 unsigned int tmp;
554 int x_offset = 0;
555 int y_offset = 0;
556 int hsub = 1;
557 int vsub = 1;
558 int i;
559
Boris Brezillon2389fc12015-02-05 16:32:33 +0100560 if (!state->base.crtc || !fb)
561 return 0;
562
Andrzej Hajdab47ff7e2016-03-15 13:46:28 +0100563 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100564 mode = &crtc_state->adjusted_mode;
565
566 state->src_x = s->src_x;
567 state->src_y = s->src_y;
568 state->src_h = s->src_h;
569 state->src_w = s->src_w;
570 state->crtc_x = s->crtc_x;
571 state->crtc_y = s->crtc_y;
572 state->crtc_h = s->crtc_h;
573 state->crtc_w = s->crtc_w;
574 if ((state->src_x | state->src_y | state->src_w | state->src_h) &
Boris Brezillon1a396782015-01-06 11:13:28 +0100575 SUBPIXEL_MASK)
576 return -EINVAL;
577
Boris Brezillon2389fc12015-02-05 16:32:33 +0100578 state->src_x >>= 16;
579 state->src_y >>= 16;
580 state->src_w >>= 16;
581 state->src_h >>= 16;
Boris Brezillon1a396782015-01-06 11:13:28 +0100582
Boris Brezillon2389fc12015-02-05 16:32:33 +0100583 state->nplanes = drm_format_num_planes(fb->pixel_format);
584 if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
Boris Brezillon1a396782015-01-06 11:13:28 +0100585 return -EINVAL;
586
587 /*
588 * Swap width and size in case of 90 or 270 degrees rotation
589 */
Boris Brezillon2389fc12015-02-05 16:32:33 +0100590 if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
591 tmp = state->crtc_w;
592 state->crtc_w = state->crtc_h;
593 state->crtc_h = tmp;
594 tmp = state->src_w;
595 state->src_w = state->src_h;
596 state->src_h = tmp;
Boris Brezillon1a396782015-01-06 11:13:28 +0100597 }
598
Boris Brezillon2389fc12015-02-05 16:32:33 +0100599 if (state->crtc_x + state->crtc_w > mode->hdisplay)
600 patched_crtc_w = mode->hdisplay - state->crtc_x;
Boris Brezillon1a396782015-01-06 11:13:28 +0100601 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100602 patched_crtc_w = state->crtc_w;
Boris Brezillon1a396782015-01-06 11:13:28 +0100603
Boris Brezillon2389fc12015-02-05 16:32:33 +0100604 if (state->crtc_x < 0) {
605 patched_crtc_w += state->crtc_x;
606 x_offset = -state->crtc_x;
607 state->crtc_x = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100608 }
609
Boris Brezillon2389fc12015-02-05 16:32:33 +0100610 if (state->crtc_y + state->crtc_h > mode->vdisplay)
611 patched_crtc_h = mode->vdisplay - state->crtc_y;
Boris Brezillon1a396782015-01-06 11:13:28 +0100612 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100613 patched_crtc_h = state->crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100614
Boris Brezillon2389fc12015-02-05 16:32:33 +0100615 if (state->crtc_y < 0) {
616 patched_crtc_h += state->crtc_y;
617 y_offset = -state->crtc_y;
618 state->crtc_y = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100619 }
620
Boris Brezillon2389fc12015-02-05 16:32:33 +0100621 patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
622 state->crtc_w);
623 patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
624 state->crtc_h);
Boris Brezillon1a396782015-01-06 11:13:28 +0100625
Boris Brezillon2389fc12015-02-05 16:32:33 +0100626 hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
627 vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
Boris Brezillon1a396782015-01-06 11:13:28 +0100628
Boris Brezillon2389fc12015-02-05 16:32:33 +0100629 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100630 unsigned int offset = 0;
631 int xdiv = i ? hsub : 1;
632 int ydiv = i ? vsub : 1;
633
Boris Brezillon2389fc12015-02-05 16:32:33 +0100634 state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
635 if (!state->bpp[i])
Boris Brezillon1a396782015-01-06 11:13:28 +0100636 return -EINVAL;
637
Joonas Lahtinen14152c82015-10-01 10:00:58 +0300638 switch (state->base.rotation & DRM_ROTATE_MASK) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100639 case BIT(DRM_ROTATE_90):
Boris Brezillon2389fc12015-02-05 16:32:33 +0100640 offset = ((y_offset + state->src_y + patched_src_w - 1) /
641 ydiv) * fb->pitches[i];
642 offset += ((x_offset + state->src_x) / xdiv) *
643 state->bpp[i];
644 state->xstride[i] = ((patched_src_w - 1) / ydiv) *
645 fb->pitches[i];
646 state->pstride[i] = -fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100647 break;
648 case BIT(DRM_ROTATE_180):
Boris Brezillon2389fc12015-02-05 16:32:33 +0100649 offset = ((y_offset + state->src_y + patched_src_h - 1) /
650 ydiv) * fb->pitches[i];
651 offset += ((x_offset + state->src_x + patched_src_w - 1) /
652 xdiv) * state->bpp[i];
653 state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
654 state->bpp[i]) - fb->pitches[i];
655 state->pstride[i] = -2 * state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100656 break;
657 case BIT(DRM_ROTATE_270):
Boris Brezillon2389fc12015-02-05 16:32:33 +0100658 offset = ((y_offset + state->src_y) / ydiv) *
659 fb->pitches[i];
660 offset += ((x_offset + state->src_x + patched_src_h - 1) /
661 xdiv) * state->bpp[i];
662 state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
663 fb->pitches[i]) -
664 (2 * state->bpp[i]);
665 state->pstride[i] = fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100666 break;
667 case BIT(DRM_ROTATE_0):
668 default:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100669 offset = ((y_offset + state->src_y) / ydiv) *
670 fb->pitches[i];
671 offset += ((x_offset + state->src_x) / xdiv) *
672 state->bpp[i];
673 state->xstride[i] = fb->pitches[i] -
Boris Brezillon1a396782015-01-06 11:13:28 +0100674 ((patched_src_w / xdiv) *
Boris Brezillon2389fc12015-02-05 16:32:33 +0100675 state->bpp[i]);
676 state->pstride[i] = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100677 break;
678 }
679
Boris Brezillon2389fc12015-02-05 16:32:33 +0100680 state->offsets[i] = offset + fb->offsets[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100681 }
682
Boris Brezillon2389fc12015-02-05 16:32:33 +0100683 state->src_w = patched_src_w;
684 state->src_h = patched_src_h;
685 state->crtc_w = patched_crtc_w;
686 state->crtc_h = patched_crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100687
Boris Brezillon2389fc12015-02-05 16:32:33 +0100688 if (!layout->size &&
689 (mode->hdisplay != state->crtc_w ||
690 mode->vdisplay != state->crtc_h))
691 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100692
Boris Brezillon2389fc12015-02-05 16:32:33 +0100693 if (plane->layer.desc->max_height &&
694 state->crtc_h > plane->layer.desc->max_height)
695 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100696
Boris Brezillon2389fc12015-02-05 16:32:33 +0100697 if (plane->layer.desc->max_width &&
698 state->crtc_w > plane->layer.desc->max_width)
699 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100700
Boris Brezillon2389fc12015-02-05 16:32:33 +0100701 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
702 (!layout->memsize ||
703 atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
704 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100705
Boris Brezillon2389fc12015-02-05 16:32:33 +0100706 if (state->crtc_x < 0 || state->crtc_y < 0)
707 return -EINVAL;
708
709 if (state->crtc_w + state->crtc_x > mode->hdisplay ||
710 state->crtc_h + state->crtc_y > mode->vdisplay)
711 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100712
713 return 0;
714}
715
Boris Brezillon2389fc12015-02-05 16:32:33 +0100716static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
Tvrtko Ursulind136dfe2015-03-03 14:22:31 +0000717 const struct drm_plane_state *new_state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100718{
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200719 /*
720 * FIXME: we should avoid this const -> non-const cast but it's
721 * currently the only solution we have to modify the ->prepared
722 * state and rollback the update request.
723 * Ideally, we should rework the code to attach all the resources
724 * to atmel_hlcdc_plane_state (including the DMA desc allocation),
725 * but this require a complete rework of the atmel_hlcdc_layer
726 * code.
727 */
728 struct drm_plane_state *s = (struct drm_plane_state *)new_state;
Boris Brezillon1a396782015-01-06 11:13:28 +0100729 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200730 struct atmel_hlcdc_plane_state *state =
731 drm_plane_state_to_atmel_hlcdc_plane_state(s);
732 int ret;
Boris Brezillon1a396782015-01-06 11:13:28 +0100733
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200734 ret = atmel_hlcdc_layer_update_start(&plane->layer);
735 if (!ret)
736 state->prepared = true;
Maarten Lankhorst844f9112015-09-02 10:42:40 +0200737
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200738 return ret;
739}
740
741static void atmel_hlcdc_plane_cleanup_fb(struct drm_plane *p,
742 const struct drm_plane_state *old_state)
743{
744 /*
745 * FIXME: we should avoid this const -> non-const cast but it's
746 * currently the only solution we have to modify the ->prepared
747 * state and rollback the update request.
748 * Ideally, we should rework the code to attach all the resources
749 * to atmel_hlcdc_plane_state (including the DMA desc allocation),
750 * but this require a complete rework of the atmel_hlcdc_layer
751 * code.
752 */
753 struct drm_plane_state *s = (struct drm_plane_state *)old_state;
754 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
755 struct atmel_hlcdc_plane_state *state =
756 drm_plane_state_to_atmel_hlcdc_plane_state(s);
757
758 /*
759 * The Request has already been applied or cancelled, nothing to do
760 * here.
761 */
762 if (!state->prepared)
763 return;
764
765 atmel_hlcdc_layer_update_rollback(&plane->layer);
766 state->prepared = false;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100767}
768
769static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
770 struct drm_plane_state *old_s)
771{
772 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
773 struct atmel_hlcdc_plane_state *state =
774 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
775
776 if (!p->state->crtc || !p->state->fb)
777 return;
778
779 atmel_hlcdc_plane_update_pos_and_size(plane, state);
780 atmel_hlcdc_plane_update_general_settings(plane, state);
781 atmel_hlcdc_plane_update_format(plane, state);
782 atmel_hlcdc_plane_update_buffers(plane, state);
Boris Brezillon59570172015-02-06 16:25:06 +0100783 atmel_hlcdc_plane_update_disc_area(plane, state);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100784
785 atmel_hlcdc_layer_update_commit(&plane->layer);
786}
787
788static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
789 struct drm_plane_state *old_state)
790{
791 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
792
793 atmel_hlcdc_layer_disable(&plane->layer);
Boris Brezillon1a396782015-01-06 11:13:28 +0100794}
795
796static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
797{
798 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
799
800 if (plane->base.fb)
801 drm_framebuffer_unreference(plane->base.fb);
802
803 atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
804
805 drm_plane_cleanup(p);
806 devm_kfree(p->dev->dev, plane);
807}
808
Boris Brezillon2389fc12015-02-05 16:32:33 +0100809static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
810 struct drm_plane_state *s,
811 struct drm_property *property,
812 uint64_t val)
Boris Brezillon1a396782015-01-06 11:13:28 +0100813{
814 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
815 struct atmel_hlcdc_plane_properties *props = plane->properties;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100816 struct atmel_hlcdc_plane_state *state =
817 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon1a396782015-01-06 11:13:28 +0100818
819 if (property == props->alpha)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100820 state->alpha = val;
821 else
822 return -EINVAL;
823
824 return 0;
825}
826
827static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
828 const struct drm_plane_state *s,
829 struct drm_property *property,
830 uint64_t *val)
831{
832 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
833 struct atmel_hlcdc_plane_properties *props = plane->properties;
834 const struct atmel_hlcdc_plane_state *state =
835 container_of(s, const struct atmel_hlcdc_plane_state, base);
836
837 if (property == props->alpha)
838 *val = state->alpha;
Boris Brezillon1a396782015-01-06 11:13:28 +0100839 else
840 return -EINVAL;
841
842 return 0;
843}
844
845static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
846 const struct atmel_hlcdc_layer_desc *desc,
847 struct atmel_hlcdc_plane_properties *props)
848{
849 struct regmap *regmap = plane->layer.hlcdc->regmap;
850
851 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
852 desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
853 drm_object_attach_property(&plane->base.base,
854 props->alpha, 255);
855
856 /* Set default alpha value */
857 regmap_update_bits(regmap,
858 desc->regs_offset +
859 ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
860 ATMEL_HLCDC_LAYER_GA_MASK,
861 ATMEL_HLCDC_LAYER_GA_MASK);
862 }
863
864 if (desc->layout.xstride && desc->layout.pstride)
865 drm_object_attach_property(&plane->base.base,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100866 plane->base.dev->mode_config.rotation_property,
867 BIT(DRM_ROTATE_0));
Boris Brezillon1a396782015-01-06 11:13:28 +0100868
869 if (desc->layout.csc) {
870 /*
871 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
872 * userspace modify these factors (using a BLOB property ?).
873 */
874 regmap_write(regmap,
875 desc->regs_offset +
876 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
877 0x4c900091);
878 regmap_write(regmap,
879 desc->regs_offset +
880 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
881 0x7a5f5090);
882 regmap_write(regmap,
883 desc->regs_offset +
884 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
885 0x40040890);
886 }
887}
888
Boris Brezillon2389fc12015-02-05 16:32:33 +0100889static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
890 .prepare_fb = atmel_hlcdc_plane_prepare_fb,
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200891 .cleanup_fb = atmel_hlcdc_plane_cleanup_fb,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100892 .atomic_check = atmel_hlcdc_plane_atomic_check,
893 .atomic_update = atmel_hlcdc_plane_atomic_update,
894 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
895};
896
897static void atmel_hlcdc_plane_reset(struct drm_plane *p)
898{
899 struct atmel_hlcdc_plane_state *state;
900
901 if (p->state) {
902 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
903
904 if (state->base.fb)
905 drm_framebuffer_unreference(state->base.fb);
906
907 kfree(state);
908 p->state = NULL;
909 }
910
911 state = kzalloc(sizeof(*state), GFP_KERNEL);
912 if (state) {
913 state->alpha = 255;
914 p->state = &state->base;
915 p->state->plane = p;
916 }
917}
918
919static struct drm_plane_state *
920atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
921{
922 struct atmel_hlcdc_plane_state *state =
923 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
924 struct atmel_hlcdc_plane_state *copy;
925
926 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
927 if (!copy)
928 return NULL;
929
Boris Brezillon59570172015-02-06 16:25:06 +0100930 copy->disc_updated = false;
Boris Brezillon1a7b37c2015-10-10 07:55:39 +0200931 copy->prepared = false;
Boris Brezillon59570172015-02-06 16:25:06 +0100932
Boris Brezillon2389fc12015-02-05 16:32:33 +0100933 if (copy->base.fb)
934 drm_framebuffer_reference(copy->base.fb);
935
936 return &copy->base;
937}
938
939static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
940 struct drm_plane_state *s)
941{
942 struct atmel_hlcdc_plane_state *state =
943 drm_plane_state_to_atmel_hlcdc_plane_state(s);
944
945 if (s->fb)
946 drm_framebuffer_unreference(s->fb);
947
948 kfree(state);
949}
950
Boris Brezillon1a396782015-01-06 11:13:28 +0100951static struct drm_plane_funcs layer_plane_funcs = {
Boris Brezillon2389fc12015-02-05 16:32:33 +0100952 .update_plane = drm_atomic_helper_update_plane,
953 .disable_plane = drm_atomic_helper_disable_plane,
954 .set_property = drm_atomic_helper_plane_set_property,
Boris Brezillon1a396782015-01-06 11:13:28 +0100955 .destroy = atmel_hlcdc_plane_destroy,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100956 .reset = atmel_hlcdc_plane_reset,
957 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
958 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
959 .atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
960 .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
Boris Brezillon1a396782015-01-06 11:13:28 +0100961};
962
963static struct atmel_hlcdc_plane *
964atmel_hlcdc_plane_create(struct drm_device *dev,
965 const struct atmel_hlcdc_layer_desc *desc,
966 struct atmel_hlcdc_plane_properties *props)
967{
968 struct atmel_hlcdc_plane *plane;
969 enum drm_plane_type type;
970 int ret;
971
972 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
973 if (!plane)
974 return ERR_PTR(-ENOMEM);
975
976 ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
977 if (ret)
978 return ERR_PTR(ret);
979
980 if (desc->type == ATMEL_HLCDC_BASE_LAYER)
981 type = DRM_PLANE_TYPE_PRIMARY;
982 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
983 type = DRM_PLANE_TYPE_CURSOR;
984 else
985 type = DRM_PLANE_TYPE_OVERLAY;
986
987 ret = drm_universal_plane_init(dev, &plane->base, 0,
988 &layer_plane_funcs,
989 desc->formats->formats,
Ville Syrjäläb0b3b792015-12-09 16:19:55 +0200990 desc->formats->nformats, type, NULL);
Boris Brezillon1a396782015-01-06 11:13:28 +0100991 if (ret)
992 return ERR_PTR(ret);
993
Boris Brezillon2389fc12015-02-05 16:32:33 +0100994 drm_plane_helper_add(&plane->base,
995 &atmel_hlcdc_layer_plane_helper_funcs);
996
Boris Brezillon1a396782015-01-06 11:13:28 +0100997 /* Set default property values*/
998 atmel_hlcdc_plane_init_properties(plane, desc, props);
999
1000 return plane;
1001}
1002
1003static struct atmel_hlcdc_plane_properties *
1004atmel_hlcdc_plane_create_properties(struct drm_device *dev)
1005{
1006 struct atmel_hlcdc_plane_properties *props;
1007
1008 props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
1009 if (!props)
1010 return ERR_PTR(-ENOMEM);
1011
1012 props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
1013 if (!props->alpha)
1014 return ERR_PTR(-ENOMEM);
1015
Boris Brezillon2389fc12015-02-05 16:32:33 +01001016 dev->mode_config.rotation_property =
1017 drm_mode_create_rotation_property(dev,
1018 BIT(DRM_ROTATE_0) |
1019 BIT(DRM_ROTATE_90) |
1020 BIT(DRM_ROTATE_180) |
1021 BIT(DRM_ROTATE_270));
1022 if (!dev->mode_config.rotation_property)
Boris Brezillon1a396782015-01-06 11:13:28 +01001023 return ERR_PTR(-ENOMEM);
1024
1025 return props;
1026}
1027
1028struct atmel_hlcdc_planes *
1029atmel_hlcdc_create_planes(struct drm_device *dev)
1030{
1031 struct atmel_hlcdc_dc *dc = dev->dev_private;
1032 struct atmel_hlcdc_plane_properties *props;
1033 struct atmel_hlcdc_planes *planes;
1034 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1035 int nlayers = dc->desc->nlayers;
1036 int i;
1037
1038 planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
1039 if (!planes)
1040 return ERR_PTR(-ENOMEM);
1041
1042 for (i = 0; i < nlayers; i++) {
1043 if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
1044 planes->noverlays++;
1045 }
1046
1047 if (planes->noverlays) {
1048 planes->overlays = devm_kzalloc(dev->dev,
1049 planes->noverlays *
1050 sizeof(*planes->overlays),
1051 GFP_KERNEL);
1052 if (!planes->overlays)
1053 return ERR_PTR(-ENOMEM);
1054 }
1055
1056 props = atmel_hlcdc_plane_create_properties(dev);
1057 if (IS_ERR(props))
1058 return ERR_CAST(props);
1059
1060 planes->noverlays = 0;
1061 for (i = 0; i < nlayers; i++) {
1062 struct atmel_hlcdc_plane *plane;
1063
1064 if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
1065 continue;
1066
1067 plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
1068 if (IS_ERR(plane))
1069 return ERR_CAST(plane);
1070
1071 plane->properties = props;
1072
1073 switch (descs[i].type) {
1074 case ATMEL_HLCDC_BASE_LAYER:
1075 if (planes->primary)
1076 return ERR_PTR(-EINVAL);
1077 planes->primary = plane;
1078 break;
1079
1080 case ATMEL_HLCDC_OVERLAY_LAYER:
1081 planes->overlays[planes->noverlays++] = plane;
1082 break;
1083
1084 case ATMEL_HLCDC_CURSOR_LAYER:
1085 if (planes->cursor)
1086 return ERR_PTR(-EINVAL);
1087 planes->cursor = plane;
1088 break;
1089
1090 default:
1091 break;
1092 }
1093 }
1094
1095 return planes;
1096}