drm: atmel-hlcdc: check display mode validity in crtc->mode_fixup()
[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)
1a7b37ca 40 * @prepared: plane update has been prepared
2389fc13
BB
41 */
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
5957017d
BB
55 bool disc_updated;
56
57 int disc_x;
58 int disc_y;
59 int disc_w;
60 int disc_h;
61
2389fc13
BB
62 /* 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;
1a7b37ca 68 bool prepared;
2389fc13
BB
69};
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
1a396789
BB
77#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
2389fc13 186static bool atmel_hlcdc_format_embeds_alpha(u32 format)
1a396789
BB
187{
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,
2389fc13 262 struct atmel_hlcdc_plane_state *state)
1a396789
BB
263{
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,
2389fc13
BB
271 (state->crtc_w - 1) |
272 ((state->crtc_h - 1) << 16));
1a396789
BB
273
274 if (layout->memsize)
275 atmel_hlcdc_layer_update_cfg(&plane->layer,
276 layout->memsize,
277 0xffffffff,
2389fc13
BB
278 (state->src_w - 1) |
279 ((state->src_h - 1) << 16));
1a396789
BB
280
281 if (layout->pos)
282 atmel_hlcdc_layer_update_cfg(&plane->layer,
283 layout->pos,
284 0xffffffff,
2389fc13
BB
285 state->crtc_x |
286 (state->crtc_y << 16));
1a396789
BB
287
288 /* TODO: rework the rescaling part */
2389fc13 289 if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
1a396789
BB
290 u32 factor_reg = 0;
291
2389fc13 292 if (state->crtc_w != state->src_w) {
1a396789
BB
293 int i;
294 u32 factor;
295 u32 *coeff_tab = heo_upscaling_xcoef;
296 u32 max_memsize;
297
2389fc13 298 if (state->crtc_w < state->src_w)
1a396789
BB
299 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]);
2389fc13
BB
305 factor = ((8 * 256 * state->src_w) - (256 * 4)) /
306 state->crtc_w;
1a396789 307 factor++;
2389fc13 308 max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
1a396789 309 2048;
2389fc13 310 if (max_memsize > state->src_w)
1a396789
BB
311 factor--;
312 factor_reg |= factor | 0x80000000;
313 }
314
2389fc13 315 if (state->crtc_h != state->src_h) {
1a396789
BB
316 int i;
317 u32 factor;
318 u32 *coeff_tab = heo_upscaling_ycoef;
319 u32 max_memsize;
320
2389fc13 321 if (state->crtc_w < state->src_w)
1a396789
BB
322 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]);
2389fc13
BB
328 factor = ((8 * 256 * state->src_w) - (256 * 4)) /
329 state->crtc_w;
1a396789 330 factor++;
2389fc13 331 max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
1a396789 332 2048;
2389fc13 333 if (max_memsize > state->src_w)
1a396789
BB
334 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,
2389fc13 345 struct atmel_hlcdc_plane_state *state)
1a396789
BB
346{
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
2389fc13 355 if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
1a396789
BB
356 cfg |= ATMEL_HLCDC_LAYER_LAEN;
357 else
2389fc13
BB
358 cfg |= ATMEL_HLCDC_LAYER_GAEN |
359 ATMEL_HLCDC_LAYER_GA(state->alpha);
1a396789
BB
360 }
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 |
2389fc13 371 ATMEL_HLCDC_LAYER_GA_MASK |
1a396789
BB
372 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,
2389fc13 378 struct atmel_hlcdc_plane_state *state)
1a396789
BB
379{
380 u32 cfg;
381 int ret;
382
2389fc13
BB
383 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
384 &cfg);
1a396789
BB
385 if (ret)
386 return;
387
2389fc13
BB
388 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))))
1a396789
BB
391 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 */
2389fc13 402 if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
1a396789
BB
403 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,
2389fc13 413 struct atmel_hlcdc_plane_state *state)
1a396789
BB
414{
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
2389fc13
BB
420 atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
421 state->offsets);
1a396789 422
2389fc13 423 for (i = 0; i < state->nplanes; i++) {
1a396789
BB
424 if (layout->xstride[i]) {
425 atmel_hlcdc_layer_update_cfg(&plane->layer,
426 layout->xstride[i],
427 0xffffffff,
2389fc13 428 state->xstride[i]);
1a396789
BB
429 }
430
431 if (layout->pstride[i]) {
432 atmel_hlcdc_layer_update_cfg(&plane->layer,
433 layout->pstride[i],
434 0xffffffff,
2389fc13 435 state->pstride[i]);
1a396789
BB
436 }
437 }
438}
439
5957017d
BB
440int
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
2389fc13
BB
538static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
539 struct drm_plane_state *s)
1a396789
BB
540{
541 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
2389fc13
BB
542 struct atmel_hlcdc_plane_state *state =
543 drm_plane_state_to_atmel_hlcdc_plane_state(s);
1a396789
BB
544 const struct atmel_hlcdc_layer_cfg_layout *layout =
545 &plane->layer.desc->layout;
2389fc13
BB
546 struct drm_framebuffer *fb = state->base.fb;
547 const struct drm_display_mode *mode;
548 struct drm_crtc_state *crtc_state;
1a396789
BB
549 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
2389fc13
BB
560 if (!state->base.crtc || !fb)
561 return 0;
562
b47ff7e6 563 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
2389fc13
BB
564 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) &
1a396789
BB
575 SUBPIXEL_MASK)
576 return -EINVAL;
577
2389fc13
BB
578 state->src_x >>= 16;
579 state->src_y >>= 16;
580 state->src_w >>= 16;
581 state->src_h >>= 16;
1a396789 582
2389fc13
BB
583 state->nplanes = drm_format_num_planes(fb->pixel_format);
584 if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
1a396789
BB
585 return -EINVAL;
586
587 /*
588 * Swap width and size in case of 90 or 270 degrees rotation
589 */
2389fc13
BB
590 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;
1a396789
BB
597 }
598
2389fc13
BB
599 if (state->crtc_x + state->crtc_w > mode->hdisplay)
600 patched_crtc_w = mode->hdisplay - state->crtc_x;
1a396789 601 else
2389fc13 602 patched_crtc_w = state->crtc_w;
1a396789 603
2389fc13
BB
604 if (state->crtc_x < 0) {
605 patched_crtc_w += state->crtc_x;
606 x_offset = -state->crtc_x;
607 state->crtc_x = 0;
1a396789
BB
608 }
609
2389fc13
BB
610 if (state->crtc_y + state->crtc_h > mode->vdisplay)
611 patched_crtc_h = mode->vdisplay - state->crtc_y;
1a396789 612 else
2389fc13 613 patched_crtc_h = state->crtc_h;
1a396789 614
2389fc13
BB
615 if (state->crtc_y < 0) {
616 patched_crtc_h += state->crtc_y;
617 y_offset = -state->crtc_y;
618 state->crtc_y = 0;
1a396789
BB
619 }
620
2389fc13
BB
621 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);
1a396789 625
2389fc13
BB
626 hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
627 vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
1a396789 628
2389fc13 629 for (i = 0; i < state->nplanes; i++) {
1a396789
BB
630 unsigned int offset = 0;
631 int xdiv = i ? hsub : 1;
632 int ydiv = i ? vsub : 1;
633
2389fc13
BB
634 state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
635 if (!state->bpp[i])
1a396789
BB
636 return -EINVAL;
637
14152c8d 638 switch (state->base.rotation & DRM_ROTATE_MASK) {
1a396789 639 case BIT(DRM_ROTATE_90):
2389fc13
BB
640 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];
1a396789
BB
647 break;
648 case BIT(DRM_ROTATE_180):
2389fc13
BB
649 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];
1a396789
BB
656 break;
657 case BIT(DRM_ROTATE_270):
2389fc13
BB
658 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];
1a396789
BB
666 break;
667 case BIT(DRM_ROTATE_0):
668 default:
2389fc13
BB
669 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] -
1a396789 674 ((patched_src_w / xdiv) *
2389fc13
BB
675 state->bpp[i]);
676 state->pstride[i] = 0;
1a396789
BB
677 break;
678 }
679
2389fc13 680 state->offsets[i] = offset + fb->offsets[i];
1a396789
BB
681 }
682
2389fc13
BB
683 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;
1a396789 687
2389fc13
BB
688 if (!layout->size &&
689 (mode->hdisplay != state->crtc_w ||
690 mode->vdisplay != state->crtc_h))
691 return -EINVAL;
1a396789 692
2389fc13
BB
693 if (plane->layer.desc->max_height &&
694 state->crtc_h > plane->layer.desc->max_height)
695 return -EINVAL;
1a396789 696
2389fc13
BB
697 if (plane->layer.desc->max_width &&
698 state->crtc_w > plane->layer.desc->max_width)
699 return -EINVAL;
1a396789 700
2389fc13
BB
701 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;
1a396789 705
2389fc13
BB
706 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;
1a396789
BB
712
713 return 0;
714}
715
2389fc13 716static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
d136dfee 717 const struct drm_plane_state *new_state)
1a396789 718{
1a7b37ca
BB
719 /*
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;
1a396789 729 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
1a7b37ca
BB
730 struct atmel_hlcdc_plane_state *state =
731 drm_plane_state_to_atmel_hlcdc_plane_state(s);
732 int ret;
1a396789 733
1a7b37ca
BB
734 ret = atmel_hlcdc_layer_update_start(&plane->layer);
735 if (!ret)
736 state->prepared = true;
737
738 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;
844f9111 764
1a7b37ca
BB
765 atmel_hlcdc_layer_update_rollback(&plane->layer);
766 state->prepared = false;
1a396789
BB
767}
768
2389fc13
BB
769static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
770 struct drm_plane_state *old_s)
1a396789 771{
2389fc13
BB
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);
5957017d 783 atmel_hlcdc_plane_update_disc_area(plane, state);
2389fc13
BB
784
785 atmel_hlcdc_layer_update_commit(&plane->layer);
1a396789
BB
786}
787
2389fc13
BB
788static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
789 struct drm_plane_state *old_state)
1a396789
BB
790{
791 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
792
2389fc13 793 atmel_hlcdc_layer_disable(&plane->layer);
1a396789
BB
794}
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
2389fc13
BB
809static 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)
1a396789 813{
2389fc13
BB
814 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
815 struct atmel_hlcdc_plane_properties *props = plane->properties;
816 struct atmel_hlcdc_plane_state *state =
817 drm_plane_state_to_atmel_hlcdc_plane_state(s);
1a396789 818
2389fc13
BB
819 if (property == props->alpha)
820 state->alpha = val;
821 else
822 return -EINVAL;
1a396789
BB
823
824 return 0;
825}
826
2389fc13
BB
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)
1a396789
BB
831{
832 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
833 struct atmel_hlcdc_plane_properties *props = plane->properties;
2389fc13
BB
834 const struct atmel_hlcdc_plane_state *state =
835 container_of(s, const struct atmel_hlcdc_plane_state, base);
1a396789
BB
836
837 if (property == props->alpha)
2389fc13 838 *val = state->alpha;
1a396789
BB
839 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,
2389fc13
BB
866 plane->base.dev->mode_config.rotation_property,
867 BIT(DRM_ROTATE_0));
1a396789
BB
868
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
2389fc13
BB
889static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
890 .prepare_fb = atmel_hlcdc_plane_prepare_fb,
1a7b37ca 891 .cleanup_fb = atmel_hlcdc_plane_cleanup_fb,
2389fc13
BB
892 .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
5957017d 930 copy->disc_updated = false;
1a7b37ca 931 copy->prepared = false;
5957017d 932
2389fc13
BB
933 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
1a396789 951static struct drm_plane_funcs layer_plane_funcs = {
2389fc13
BB
952 .update_plane = drm_atomic_helper_update_plane,
953 .disable_plane = drm_atomic_helper_disable_plane,
954 .set_property = drm_atomic_helper_plane_set_property,
1a396789 955 .destroy = atmel_hlcdc_plane_destroy,
2389fc13
BB
956 .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,
1a396789
BB
961};
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,
b0b3b795 990 desc->formats->nformats, type, NULL);
1a396789
BB
991 if (ret)
992 return ERR_PTR(ret);
993
2389fc13
BB
994 drm_plane_helper_add(&plane->base,
995 &atmel_hlcdc_layer_plane_helper_funcs);
996
1a396789
BB
997 /* 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
2389fc13
BB
1016 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)
1a396789
BB
1023 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}
This page took 0.11394 seconds and 5 git commands to generate.