drm: atmel-hlcdc: Atomic mode-setting conversion
[deliverable/linux.git] / drivers / gpu / drm / atmel-hlcdc / atmel_hlcdc_plane.c
CommitLineData
1a396789
BB
1/*
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
2389fc13
BB
22/**
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)
40 */
41struct atmel_hlcdc_plane_state {
42 struct drm_plane_state base;
43 int crtc_x;
44 int crtc_y;
45 unsigned int crtc_w;
46 unsigned int crtc_h;
47 uint32_t src_x;
48 uint32_t src_y;
49 uint32_t src_w;
50 uint32_t src_h;
51
52 u8 alpha;
53
54 /* These fields are private and should not be touched */
55 int bpp[ATMEL_HLCDC_MAX_PLANES];
56 unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
57 int xstride[ATMEL_HLCDC_MAX_PLANES];
58 int pstride[ATMEL_HLCDC_MAX_PLANES];
59 int nplanes;
60};
61
62static inline struct atmel_hlcdc_plane_state *
63drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
64{
65 return container_of(s, struct atmel_hlcdc_plane_state, base);
66}
67
1a396789
BB
68#define SUBPIXEL_MASK 0xffff
69
70static uint32_t rgb_formats[] = {
71 DRM_FORMAT_XRGB4444,
72 DRM_FORMAT_ARGB4444,
73 DRM_FORMAT_RGBA4444,
74 DRM_FORMAT_ARGB1555,
75 DRM_FORMAT_RGB565,
76 DRM_FORMAT_RGB888,
77 DRM_FORMAT_XRGB8888,
78 DRM_FORMAT_ARGB8888,
79 DRM_FORMAT_RGBA8888,
80};
81
82struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
83 .formats = rgb_formats,
84 .nformats = ARRAY_SIZE(rgb_formats),
85};
86
87static uint32_t rgb_and_yuv_formats[] = {
88 DRM_FORMAT_XRGB4444,
89 DRM_FORMAT_ARGB4444,
90 DRM_FORMAT_RGBA4444,
91 DRM_FORMAT_ARGB1555,
92 DRM_FORMAT_RGB565,
93 DRM_FORMAT_RGB888,
94 DRM_FORMAT_XRGB8888,
95 DRM_FORMAT_ARGB8888,
96 DRM_FORMAT_RGBA8888,
97 DRM_FORMAT_AYUV,
98 DRM_FORMAT_YUYV,
99 DRM_FORMAT_UYVY,
100 DRM_FORMAT_YVYU,
101 DRM_FORMAT_VYUY,
102 DRM_FORMAT_NV21,
103 DRM_FORMAT_NV61,
104 DRM_FORMAT_YUV422,
105 DRM_FORMAT_YUV420,
106};
107
108struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
109 .formats = rgb_and_yuv_formats,
110 .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
111};
112
113static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
114{
115 switch (format) {
116 case DRM_FORMAT_XRGB4444:
117 *mode = ATMEL_HLCDC_XRGB4444_MODE;
118 break;
119 case DRM_FORMAT_ARGB4444:
120 *mode = ATMEL_HLCDC_ARGB4444_MODE;
121 break;
122 case DRM_FORMAT_RGBA4444:
123 *mode = ATMEL_HLCDC_RGBA4444_MODE;
124 break;
125 case DRM_FORMAT_RGB565:
126 *mode = ATMEL_HLCDC_RGB565_MODE;
127 break;
128 case DRM_FORMAT_RGB888:
129 *mode = ATMEL_HLCDC_RGB888_MODE;
130 break;
131 case DRM_FORMAT_ARGB1555:
132 *mode = ATMEL_HLCDC_ARGB1555_MODE;
133 break;
134 case DRM_FORMAT_XRGB8888:
135 *mode = ATMEL_HLCDC_XRGB8888_MODE;
136 break;
137 case DRM_FORMAT_ARGB8888:
138 *mode = ATMEL_HLCDC_ARGB8888_MODE;
139 break;
140 case DRM_FORMAT_RGBA8888:
141 *mode = ATMEL_HLCDC_RGBA8888_MODE;
142 break;
143 case DRM_FORMAT_AYUV:
144 *mode = ATMEL_HLCDC_AYUV_MODE;
145 break;
146 case DRM_FORMAT_YUYV:
147 *mode = ATMEL_HLCDC_YUYV_MODE;
148 break;
149 case DRM_FORMAT_UYVY:
150 *mode = ATMEL_HLCDC_UYVY_MODE;
151 break;
152 case DRM_FORMAT_YVYU:
153 *mode = ATMEL_HLCDC_YVYU_MODE;
154 break;
155 case DRM_FORMAT_VYUY:
156 *mode = ATMEL_HLCDC_VYUY_MODE;
157 break;
158 case DRM_FORMAT_NV21:
159 *mode = ATMEL_HLCDC_NV21_MODE;
160 break;
161 case DRM_FORMAT_NV61:
162 *mode = ATMEL_HLCDC_NV61_MODE;
163 break;
164 case DRM_FORMAT_YUV420:
165 *mode = ATMEL_HLCDC_YUV420_MODE;
166 break;
167 case DRM_FORMAT_YUV422:
168 *mode = ATMEL_HLCDC_YUV422_MODE;
169 break;
170 default:
171 return -ENOTSUPP;
172 }
173
174 return 0;
175}
176
2389fc13 177static bool atmel_hlcdc_format_embeds_alpha(u32 format)
1a396789
BB
178{
179 int i;
180
181 for (i = 0; i < sizeof(format); i++) {
182 char tmp = (format >> (8 * i)) & 0xff;
183
184 if (tmp == 'A')
185 return true;
186 }
187
188 return false;
189}
190
191static u32 heo_downscaling_xcoef[] = {
192 0x11343311,
193 0x000000f7,
194 0x1635300c,
195 0x000000f9,
196 0x1b362c08,
197 0x000000fb,
198 0x1f372804,
199 0x000000fe,
200 0x24382400,
201 0x00000000,
202 0x28371ffe,
203 0x00000004,
204 0x2c361bfb,
205 0x00000008,
206 0x303516f9,
207 0x0000000c,
208};
209
210static u32 heo_downscaling_ycoef[] = {
211 0x00123737,
212 0x00173732,
213 0x001b382d,
214 0x001f3928,
215 0x00243824,
216 0x0028391f,
217 0x002d381b,
218 0x00323717,
219};
220
221static u32 heo_upscaling_xcoef[] = {
222 0xf74949f7,
223 0x00000000,
224 0xf55f33fb,
225 0x000000fe,
226 0xf5701efe,
227 0x000000ff,
228 0xf87c0dff,
229 0x00000000,
230 0x00800000,
231 0x00000000,
232 0x0d7cf800,
233 0x000000ff,
234 0x1e70f5ff,
235 0x000000fe,
236 0x335ff5fe,
237 0x000000fb,
238};
239
240static u32 heo_upscaling_ycoef[] = {
241 0x00004040,
242 0x00075920,
243 0x00056f0c,
244 0x00027b03,
245 0x00008000,
246 0x00037b02,
247 0x000c6f05,
248 0x00205907,
249};
250
251static void
252atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
2389fc13 253 struct atmel_hlcdc_plane_state *state)
1a396789
BB
254{
255 const struct atmel_hlcdc_layer_cfg_layout *layout =
256 &plane->layer.desc->layout;
257
258 if (layout->size)
259 atmel_hlcdc_layer_update_cfg(&plane->layer,
260 layout->size,
261 0xffffffff,
2389fc13
BB
262 (state->crtc_w - 1) |
263 ((state->crtc_h - 1) << 16));
1a396789
BB
264
265 if (layout->memsize)
266 atmel_hlcdc_layer_update_cfg(&plane->layer,
267 layout->memsize,
268 0xffffffff,
2389fc13
BB
269 (state->src_w - 1) |
270 ((state->src_h - 1) << 16));
1a396789
BB
271
272 if (layout->pos)
273 atmel_hlcdc_layer_update_cfg(&plane->layer,
274 layout->pos,
275 0xffffffff,
2389fc13
BB
276 state->crtc_x |
277 (state->crtc_y << 16));
1a396789
BB
278
279 /* TODO: rework the rescaling part */
2389fc13 280 if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
1a396789
BB
281 u32 factor_reg = 0;
282
2389fc13 283 if (state->crtc_w != state->src_w) {
1a396789
BB
284 int i;
285 u32 factor;
286 u32 *coeff_tab = heo_upscaling_xcoef;
287 u32 max_memsize;
288
2389fc13 289 if (state->crtc_w < state->src_w)
1a396789
BB
290 coeff_tab = heo_downscaling_xcoef;
291 for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
292 atmel_hlcdc_layer_update_cfg(&plane->layer,
293 17 + i,
294 0xffffffff,
295 coeff_tab[i]);
2389fc13
BB
296 factor = ((8 * 256 * state->src_w) - (256 * 4)) /
297 state->crtc_w;
1a396789 298 factor++;
2389fc13 299 max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
1a396789 300 2048;
2389fc13 301 if (max_memsize > state->src_w)
1a396789
BB
302 factor--;
303 factor_reg |= factor | 0x80000000;
304 }
305
2389fc13 306 if (state->crtc_h != state->src_h) {
1a396789
BB
307 int i;
308 u32 factor;
309 u32 *coeff_tab = heo_upscaling_ycoef;
310 u32 max_memsize;
311
2389fc13 312 if (state->crtc_w < state->src_w)
1a396789
BB
313 coeff_tab = heo_downscaling_ycoef;
314 for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
315 atmel_hlcdc_layer_update_cfg(&plane->layer,
316 33 + i,
317 0xffffffff,
318 coeff_tab[i]);
2389fc13
BB
319 factor = ((8 * 256 * state->src_w) - (256 * 4)) /
320 state->crtc_w;
1a396789 321 factor++;
2389fc13 322 max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
1a396789 323 2048;
2389fc13 324 if (max_memsize > state->src_w)
1a396789
BB
325 factor--;
326 factor_reg |= (factor << 16) | 0x80000000;
327 }
328
329 atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
330 factor_reg);
331 }
332}
333
334static void
335atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
2389fc13 336 struct atmel_hlcdc_plane_state *state)
1a396789
BB
337{
338 const struct atmel_hlcdc_layer_cfg_layout *layout =
339 &plane->layer.desc->layout;
340 unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
341
342 if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
343 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
344 ATMEL_HLCDC_LAYER_ITER;
345
2389fc13 346 if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
1a396789
BB
347 cfg |= ATMEL_HLCDC_LAYER_LAEN;
348 else
2389fc13
BB
349 cfg |= ATMEL_HLCDC_LAYER_GAEN |
350 ATMEL_HLCDC_LAYER_GA(state->alpha);
1a396789
BB
351 }
352
353 atmel_hlcdc_layer_update_cfg(&plane->layer,
354 ATMEL_HLCDC_LAYER_DMA_CFG_ID,
355 ATMEL_HLCDC_LAYER_DMA_BLEN_MASK,
356 ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16);
357
358 atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
359 ATMEL_HLCDC_LAYER_ITER2BL |
360 ATMEL_HLCDC_LAYER_ITER |
361 ATMEL_HLCDC_LAYER_GAEN |
2389fc13 362 ATMEL_HLCDC_LAYER_GA_MASK |
1a396789
BB
363 ATMEL_HLCDC_LAYER_LAEN |
364 ATMEL_HLCDC_LAYER_OVR |
365 ATMEL_HLCDC_LAYER_DMA, cfg);
366}
367
368static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
2389fc13 369 struct atmel_hlcdc_plane_state *state)
1a396789
BB
370{
371 u32 cfg;
372 int ret;
373
2389fc13
BB
374 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
375 &cfg);
1a396789
BB
376 if (ret)
377 return;
378
2389fc13
BB
379 if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 ||
380 state->base.fb->pixel_format == DRM_FORMAT_NV61) &&
381 (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
1a396789
BB
382 cfg |= ATMEL_HLCDC_YUV422ROT;
383
384 atmel_hlcdc_layer_update_cfg(&plane->layer,
385 ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
386 0xffffffff,
387 cfg);
388
389 /*
390 * Rotation optimization is not working on RGB888 (rotation is still
391 * working but without any optimization).
392 */
2389fc13 393 if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
1a396789
BB
394 cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
395 else
396 cfg = 0;
397
398 atmel_hlcdc_layer_update_cfg(&plane->layer,
399 ATMEL_HLCDC_LAYER_DMA_CFG_ID,
400 ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
401}
402
403static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
2389fc13 404 struct atmel_hlcdc_plane_state *state)
1a396789
BB
405{
406 struct atmel_hlcdc_layer *layer = &plane->layer;
407 const struct atmel_hlcdc_layer_cfg_layout *layout =
408 &layer->desc->layout;
409 int i;
410
2389fc13
BB
411 atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
412 state->offsets);
1a396789 413
2389fc13 414 for (i = 0; i < state->nplanes; i++) {
1a396789
BB
415 if (layout->xstride[i]) {
416 atmel_hlcdc_layer_update_cfg(&plane->layer,
417 layout->xstride[i],
418 0xffffffff,
2389fc13 419 state->xstride[i]);
1a396789
BB
420 }
421
422 if (layout->pstride[i]) {
423 atmel_hlcdc_layer_update_cfg(&plane->layer,
424 layout->pstride[i],
425 0xffffffff,
2389fc13 426 state->pstride[i]);
1a396789
BB
427 }
428 }
429}
430
2389fc13
BB
431static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
432 struct drm_plane_state *s)
1a396789
BB
433{
434 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
2389fc13
BB
435 struct atmel_hlcdc_plane_state *state =
436 drm_plane_state_to_atmel_hlcdc_plane_state(s);
1a396789
BB
437 const struct atmel_hlcdc_layer_cfg_layout *layout =
438 &plane->layer.desc->layout;
2389fc13
BB
439 struct drm_framebuffer *fb = state->base.fb;
440 const struct drm_display_mode *mode;
441 struct drm_crtc_state *crtc_state;
1a396789
BB
442 unsigned int patched_crtc_w;
443 unsigned int patched_crtc_h;
444 unsigned int patched_src_w;
445 unsigned int patched_src_h;
446 unsigned int tmp;
447 int x_offset = 0;
448 int y_offset = 0;
449 int hsub = 1;
450 int vsub = 1;
451 int i;
452
2389fc13
BB
453 if (!state->base.crtc || !fb)
454 return 0;
455
456 crtc_state = s->state->crtc_states[drm_crtc_index(s->crtc)];
457 mode = &crtc_state->adjusted_mode;
458
459 state->src_x = s->src_x;
460 state->src_y = s->src_y;
461 state->src_h = s->src_h;
462 state->src_w = s->src_w;
463 state->crtc_x = s->crtc_x;
464 state->crtc_y = s->crtc_y;
465 state->crtc_h = s->crtc_h;
466 state->crtc_w = s->crtc_w;
467 if ((state->src_x | state->src_y | state->src_w | state->src_h) &
1a396789
BB
468 SUBPIXEL_MASK)
469 return -EINVAL;
470
2389fc13
BB
471 state->src_x >>= 16;
472 state->src_y >>= 16;
473 state->src_w >>= 16;
474 state->src_h >>= 16;
1a396789 475
2389fc13
BB
476 state->nplanes = drm_format_num_planes(fb->pixel_format);
477 if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
1a396789
BB
478 return -EINVAL;
479
480 /*
481 * Swap width and size in case of 90 or 270 degrees rotation
482 */
2389fc13
BB
483 if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
484 tmp = state->crtc_w;
485 state->crtc_w = state->crtc_h;
486 state->crtc_h = tmp;
487 tmp = state->src_w;
488 state->src_w = state->src_h;
489 state->src_h = tmp;
1a396789
BB
490 }
491
2389fc13
BB
492 if (state->crtc_x + state->crtc_w > mode->hdisplay)
493 patched_crtc_w = mode->hdisplay - state->crtc_x;
1a396789 494 else
2389fc13 495 patched_crtc_w = state->crtc_w;
1a396789 496
2389fc13
BB
497 if (state->crtc_x < 0) {
498 patched_crtc_w += state->crtc_x;
499 x_offset = -state->crtc_x;
500 state->crtc_x = 0;
1a396789
BB
501 }
502
2389fc13
BB
503 if (state->crtc_y + state->crtc_h > mode->vdisplay)
504 patched_crtc_h = mode->vdisplay - state->crtc_y;
1a396789 505 else
2389fc13 506 patched_crtc_h = state->crtc_h;
1a396789 507
2389fc13
BB
508 if (state->crtc_y < 0) {
509 patched_crtc_h += state->crtc_y;
510 y_offset = -state->crtc_y;
511 state->crtc_y = 0;
1a396789
BB
512 }
513
2389fc13
BB
514 patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
515 state->crtc_w);
516 patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
517 state->crtc_h);
1a396789 518
2389fc13
BB
519 hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
520 vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
1a396789 521
2389fc13 522 for (i = 0; i < state->nplanes; i++) {
1a396789
BB
523 unsigned int offset = 0;
524 int xdiv = i ? hsub : 1;
525 int ydiv = i ? vsub : 1;
526
2389fc13
BB
527 state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
528 if (!state->bpp[i])
1a396789
BB
529 return -EINVAL;
530
2389fc13 531 switch (state->base.rotation & 0xf) {
1a396789 532 case BIT(DRM_ROTATE_90):
2389fc13
BB
533 offset = ((y_offset + state->src_y + patched_src_w - 1) /
534 ydiv) * fb->pitches[i];
535 offset += ((x_offset + state->src_x) / xdiv) *
536 state->bpp[i];
537 state->xstride[i] = ((patched_src_w - 1) / ydiv) *
538 fb->pitches[i];
539 state->pstride[i] = -fb->pitches[i] - state->bpp[i];
1a396789
BB
540 break;
541 case BIT(DRM_ROTATE_180):
2389fc13
BB
542 offset = ((y_offset + state->src_y + patched_src_h - 1) /
543 ydiv) * fb->pitches[i];
544 offset += ((x_offset + state->src_x + patched_src_w - 1) /
545 xdiv) * state->bpp[i];
546 state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
547 state->bpp[i]) - fb->pitches[i];
548 state->pstride[i] = -2 * state->bpp[i];
1a396789
BB
549 break;
550 case BIT(DRM_ROTATE_270):
2389fc13
BB
551 offset = ((y_offset + state->src_y) / ydiv) *
552 fb->pitches[i];
553 offset += ((x_offset + state->src_x + patched_src_h - 1) /
554 xdiv) * state->bpp[i];
555 state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
556 fb->pitches[i]) -
557 (2 * state->bpp[i]);
558 state->pstride[i] = fb->pitches[i] - state->bpp[i];
1a396789
BB
559 break;
560 case BIT(DRM_ROTATE_0):
561 default:
2389fc13
BB
562 offset = ((y_offset + state->src_y) / ydiv) *
563 fb->pitches[i];
564 offset += ((x_offset + state->src_x) / xdiv) *
565 state->bpp[i];
566 state->xstride[i] = fb->pitches[i] -
1a396789 567 ((patched_src_w / xdiv) *
2389fc13
BB
568 state->bpp[i]);
569 state->pstride[i] = 0;
1a396789
BB
570 break;
571 }
572
2389fc13 573 state->offsets[i] = offset + fb->offsets[i];
1a396789
BB
574 }
575
2389fc13
BB
576 state->src_w = patched_src_w;
577 state->src_h = patched_src_h;
578 state->crtc_w = patched_crtc_w;
579 state->crtc_h = patched_crtc_h;
1a396789 580
2389fc13
BB
581 if (!layout->size &&
582 (mode->hdisplay != state->crtc_w ||
583 mode->vdisplay != state->crtc_h))
584 return -EINVAL;
1a396789 585
2389fc13
BB
586 if (plane->layer.desc->max_height &&
587 state->crtc_h > plane->layer.desc->max_height)
588 return -EINVAL;
1a396789 589
2389fc13
BB
590 if (plane->layer.desc->max_width &&
591 state->crtc_w > plane->layer.desc->max_width)
592 return -EINVAL;
1a396789 593
2389fc13
BB
594 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
595 (!layout->memsize ||
596 atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
597 return -EINVAL;
1a396789 598
2389fc13
BB
599 if (state->crtc_x < 0 || state->crtc_y < 0)
600 return -EINVAL;
601
602 if (state->crtc_w + state->crtc_x > mode->hdisplay ||
603 state->crtc_h + state->crtc_y > mode->vdisplay)
604 return -EINVAL;
1a396789
BB
605
606 return 0;
607}
608
2389fc13
BB
609static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
610 struct drm_framebuffer *fb)
1a396789
BB
611{
612 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
1a396789 613
2389fc13 614 return atmel_hlcdc_layer_update_start(&plane->layer);
1a396789
BB
615}
616
2389fc13
BB
617static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
618 struct drm_plane_state *old_s)
1a396789 619{
2389fc13
BB
620 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
621 struct atmel_hlcdc_plane_state *state =
622 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
623
624 if (!p->state->crtc || !p->state->fb)
625 return;
626
627 atmel_hlcdc_plane_update_pos_and_size(plane, state);
628 atmel_hlcdc_plane_update_general_settings(plane, state);
629 atmel_hlcdc_plane_update_format(plane, state);
630 atmel_hlcdc_plane_update_buffers(plane, state);
631
632 atmel_hlcdc_layer_update_commit(&plane->layer);
1a396789
BB
633}
634
2389fc13
BB
635static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
636 struct drm_plane_state *old_state)
1a396789
BB
637{
638 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
639
2389fc13 640 atmel_hlcdc_layer_disable(&plane->layer);
1a396789
BB
641}
642
643static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
644{
645 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
646
647 if (plane->base.fb)
648 drm_framebuffer_unreference(plane->base.fb);
649
650 atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
651
652 drm_plane_cleanup(p);
653 devm_kfree(p->dev->dev, plane);
654}
655
2389fc13
BB
656static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
657 struct drm_plane_state *s,
658 struct drm_property *property,
659 uint64_t val)
1a396789 660{
2389fc13
BB
661 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
662 struct atmel_hlcdc_plane_properties *props = plane->properties;
663 struct atmel_hlcdc_plane_state *state =
664 drm_plane_state_to_atmel_hlcdc_plane_state(s);
1a396789 665
2389fc13
BB
666 if (property == props->alpha)
667 state->alpha = val;
668 else
669 return -EINVAL;
1a396789
BB
670
671 return 0;
672}
673
2389fc13
BB
674static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
675 const struct drm_plane_state *s,
676 struct drm_property *property,
677 uint64_t *val)
1a396789
BB
678{
679 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
680 struct atmel_hlcdc_plane_properties *props = plane->properties;
2389fc13
BB
681 const struct atmel_hlcdc_plane_state *state =
682 container_of(s, const struct atmel_hlcdc_plane_state, base);
1a396789
BB
683
684 if (property == props->alpha)
2389fc13 685 *val = state->alpha;
1a396789
BB
686 else
687 return -EINVAL;
688
689 return 0;
690}
691
692static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
693 const struct atmel_hlcdc_layer_desc *desc,
694 struct atmel_hlcdc_plane_properties *props)
695{
696 struct regmap *regmap = plane->layer.hlcdc->regmap;
697
698 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
699 desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
700 drm_object_attach_property(&plane->base.base,
701 props->alpha, 255);
702
703 /* Set default alpha value */
704 regmap_update_bits(regmap,
705 desc->regs_offset +
706 ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
707 ATMEL_HLCDC_LAYER_GA_MASK,
708 ATMEL_HLCDC_LAYER_GA_MASK);
709 }
710
711 if (desc->layout.xstride && desc->layout.pstride)
712 drm_object_attach_property(&plane->base.base,
2389fc13
BB
713 plane->base.dev->mode_config.rotation_property,
714 BIT(DRM_ROTATE_0));
1a396789
BB
715
716 if (desc->layout.csc) {
717 /*
718 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
719 * userspace modify these factors (using a BLOB property ?).
720 */
721 regmap_write(regmap,
722 desc->regs_offset +
723 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
724 0x4c900091);
725 regmap_write(regmap,
726 desc->regs_offset +
727 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
728 0x7a5f5090);
729 regmap_write(regmap,
730 desc->regs_offset +
731 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
732 0x40040890);
733 }
734}
735
2389fc13
BB
736static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
737 .prepare_fb = atmel_hlcdc_plane_prepare_fb,
738 .atomic_check = atmel_hlcdc_plane_atomic_check,
739 .atomic_update = atmel_hlcdc_plane_atomic_update,
740 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
741};
742
743static void atmel_hlcdc_plane_reset(struct drm_plane *p)
744{
745 struct atmel_hlcdc_plane_state *state;
746
747 if (p->state) {
748 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
749
750 if (state->base.fb)
751 drm_framebuffer_unreference(state->base.fb);
752
753 kfree(state);
754 p->state = NULL;
755 }
756
757 state = kzalloc(sizeof(*state), GFP_KERNEL);
758 if (state) {
759 state->alpha = 255;
760 p->state = &state->base;
761 p->state->plane = p;
762 }
763}
764
765static struct drm_plane_state *
766atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
767{
768 struct atmel_hlcdc_plane_state *state =
769 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
770 struct atmel_hlcdc_plane_state *copy;
771
772 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
773 if (!copy)
774 return NULL;
775
776 if (copy->base.fb)
777 drm_framebuffer_reference(copy->base.fb);
778
779 return &copy->base;
780}
781
782static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
783 struct drm_plane_state *s)
784{
785 struct atmel_hlcdc_plane_state *state =
786 drm_plane_state_to_atmel_hlcdc_plane_state(s);
787
788 if (s->fb)
789 drm_framebuffer_unreference(s->fb);
790
791 kfree(state);
792}
793
1a396789 794static struct drm_plane_funcs layer_plane_funcs = {
2389fc13
BB
795 .update_plane = drm_atomic_helper_update_plane,
796 .disable_plane = drm_atomic_helper_disable_plane,
797 .set_property = drm_atomic_helper_plane_set_property,
1a396789 798 .destroy = atmel_hlcdc_plane_destroy,
2389fc13
BB
799 .reset = atmel_hlcdc_plane_reset,
800 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
801 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
802 .atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
803 .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
1a396789
BB
804};
805
806static struct atmel_hlcdc_plane *
807atmel_hlcdc_plane_create(struct drm_device *dev,
808 const struct atmel_hlcdc_layer_desc *desc,
809 struct atmel_hlcdc_plane_properties *props)
810{
811 struct atmel_hlcdc_plane *plane;
812 enum drm_plane_type type;
813 int ret;
814
815 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
816 if (!plane)
817 return ERR_PTR(-ENOMEM);
818
819 ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
820 if (ret)
821 return ERR_PTR(ret);
822
823 if (desc->type == ATMEL_HLCDC_BASE_LAYER)
824 type = DRM_PLANE_TYPE_PRIMARY;
825 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
826 type = DRM_PLANE_TYPE_CURSOR;
827 else
828 type = DRM_PLANE_TYPE_OVERLAY;
829
830 ret = drm_universal_plane_init(dev, &plane->base, 0,
831 &layer_plane_funcs,
832 desc->formats->formats,
833 desc->formats->nformats, type);
834 if (ret)
835 return ERR_PTR(ret);
836
2389fc13
BB
837 drm_plane_helper_add(&plane->base,
838 &atmel_hlcdc_layer_plane_helper_funcs);
839
1a396789
BB
840 /* Set default property values*/
841 atmel_hlcdc_plane_init_properties(plane, desc, props);
842
843 return plane;
844}
845
846static struct atmel_hlcdc_plane_properties *
847atmel_hlcdc_plane_create_properties(struct drm_device *dev)
848{
849 struct atmel_hlcdc_plane_properties *props;
850
851 props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
852 if (!props)
853 return ERR_PTR(-ENOMEM);
854
855 props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
856 if (!props->alpha)
857 return ERR_PTR(-ENOMEM);
858
2389fc13
BB
859 dev->mode_config.rotation_property =
860 drm_mode_create_rotation_property(dev,
861 BIT(DRM_ROTATE_0) |
862 BIT(DRM_ROTATE_90) |
863 BIT(DRM_ROTATE_180) |
864 BIT(DRM_ROTATE_270));
865 if (!dev->mode_config.rotation_property)
1a396789
BB
866 return ERR_PTR(-ENOMEM);
867
868 return props;
869}
870
871struct atmel_hlcdc_planes *
872atmel_hlcdc_create_planes(struct drm_device *dev)
873{
874 struct atmel_hlcdc_dc *dc = dev->dev_private;
875 struct atmel_hlcdc_plane_properties *props;
876 struct atmel_hlcdc_planes *planes;
877 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
878 int nlayers = dc->desc->nlayers;
879 int i;
880
881 planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
882 if (!planes)
883 return ERR_PTR(-ENOMEM);
884
885 for (i = 0; i < nlayers; i++) {
886 if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
887 planes->noverlays++;
888 }
889
890 if (planes->noverlays) {
891 planes->overlays = devm_kzalloc(dev->dev,
892 planes->noverlays *
893 sizeof(*planes->overlays),
894 GFP_KERNEL);
895 if (!planes->overlays)
896 return ERR_PTR(-ENOMEM);
897 }
898
899 props = atmel_hlcdc_plane_create_properties(dev);
900 if (IS_ERR(props))
901 return ERR_CAST(props);
902
903 planes->noverlays = 0;
904 for (i = 0; i < nlayers; i++) {
905 struct atmel_hlcdc_plane *plane;
906
907 if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
908 continue;
909
910 plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
911 if (IS_ERR(plane))
912 return ERR_CAST(plane);
913
914 plane->properties = props;
915
916 switch (descs[i].type) {
917 case ATMEL_HLCDC_BASE_LAYER:
918 if (planes->primary)
919 return ERR_PTR(-EINVAL);
920 planes->primary = plane;
921 break;
922
923 case ATMEL_HLCDC_OVERLAY_LAYER:
924 planes->overlays[planes->noverlays++] = plane;
925 break;
926
927 case ATMEL_HLCDC_CURSOR_LAYER:
928 if (planes->cursor)
929 return ERR_PTR(-EINVAL);
930 planes->cursor = plane;
931 break;
932
933 default:
934 break;
935 }
936 }
937
938 return planes;
939}
This page took 0.081605 seconds and 5 git commands to generate.