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