drm/i915: Rename intel_context[engine].ringbuf
[deliverable/linux.git] / drivers / gpu / drm / atmel-hlcdc / atmel_hlcdc_plane.c
... / ...
CommitLineData
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
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 * @prepared: plane update has been prepared
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
55 bool disc_updated;
56
57 int disc_x;
58 int disc_y;
59 int disc_w;
60 int disc_h;
61
62 int ahb_id;
63
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;
70 bool prepared;
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
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
188static bool atmel_hlcdc_format_embeds_alpha(u32 format)
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,
264 struct atmel_hlcdc_plane_state *state)
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,
273 (state->crtc_w - 1) |
274 ((state->crtc_h - 1) << 16));
275
276 if (layout->memsize)
277 atmel_hlcdc_layer_update_cfg(&plane->layer,
278 layout->memsize,
279 0xffffffff,
280 (state->src_w - 1) |
281 ((state->src_h - 1) << 16));
282
283 if (layout->pos)
284 atmel_hlcdc_layer_update_cfg(&plane->layer,
285 layout->pos,
286 0xffffffff,
287 state->crtc_x |
288 (state->crtc_y << 16));
289
290 /* TODO: rework the rescaling part */
291 if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
292 u32 factor_reg = 0;
293
294 if (state->crtc_w != state->src_w) {
295 int i;
296 u32 factor;
297 u32 *coeff_tab = heo_upscaling_xcoef;
298 u32 max_memsize;
299
300 if (state->crtc_w < state->src_w)
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]);
307 factor = ((8 * 256 * state->src_w) - (256 * 4)) /
308 state->crtc_w;
309 factor++;
310 max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
311 2048;
312 if (max_memsize > state->src_w)
313 factor--;
314 factor_reg |= factor | 0x80000000;
315 }
316
317 if (state->crtc_h != state->src_h) {
318 int i;
319 u32 factor;
320 u32 *coeff_tab = heo_upscaling_ycoef;
321 u32 max_memsize;
322
323 if (state->crtc_w < state->src_w)
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]);
330 factor = ((8 * 256 * state->src_w) - (256 * 4)) /
331 state->crtc_w;
332 factor++;
333 max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
334 2048;
335 if (max_memsize > state->src_w)
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,
347 struct atmel_hlcdc_plane_state *state)
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
357 if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
358 cfg |= ATMEL_HLCDC_LAYER_LAEN;
359 else
360 cfg |= ATMEL_HLCDC_LAYER_GAEN |
361 ATMEL_HLCDC_LAYER_GA(state->alpha);
362 }
363
364 atmel_hlcdc_layer_update_cfg(&plane->layer,
365 ATMEL_HLCDC_LAYER_DMA_CFG_ID,
366 ATMEL_HLCDC_LAYER_DMA_BLEN_MASK |
367 ATMEL_HLCDC_LAYER_DMA_SIF,
368 ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 |
369 state->ahb_id);
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 |
375 ATMEL_HLCDC_LAYER_GA_MASK |
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,
382 struct atmel_hlcdc_plane_state *state)
383{
384 u32 cfg;
385 int ret;
386
387 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
388 &cfg);
389 if (ret)
390 return;
391
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))))
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 */
406 if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
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,
417 struct atmel_hlcdc_plane_state *state)
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
424 atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
425 state->offsets);
426
427 for (i = 0; i < state->nplanes; i++) {
428 if (layout->xstride[i]) {
429 atmel_hlcdc_layer_update_cfg(&plane->layer,
430 layout->xstride[i],
431 0xffffffff,
432 state->xstride[i]);
433 }
434
435 if (layout->pstride[i]) {
436 atmel_hlcdc_layer_update_cfg(&plane->layer,
437 layout->pstride[i],
438 0xffffffff,
439 state->pstride[i]);
440 }
441 }
442}
443
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
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
577static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
578 struct drm_plane_state *s)
579{
580 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
581 struct atmel_hlcdc_plane_state *state =
582 drm_plane_state_to_atmel_hlcdc_plane_state(s);
583 const struct atmel_hlcdc_layer_cfg_layout *layout =
584 &plane->layer.desc->layout;
585 struct drm_framebuffer *fb = state->base.fb;
586 const struct drm_display_mode *mode;
587 struct drm_crtc_state *crtc_state;
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
599 if (!state->base.crtc || !fb)
600 return 0;
601
602 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
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) &
614 SUBPIXEL_MASK)
615 return -EINVAL;
616
617 state->src_x >>= 16;
618 state->src_y >>= 16;
619 state->src_w >>= 16;
620 state->src_h >>= 16;
621
622 state->nplanes = drm_format_num_planes(fb->pixel_format);
623 if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
624 return -EINVAL;
625
626 /*
627 * Swap width and size in case of 90 or 270 degrees rotation
628 */
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;
636 }
637
638 if (state->crtc_x + state->crtc_w > mode->hdisplay)
639 patched_crtc_w = mode->hdisplay - state->crtc_x;
640 else
641 patched_crtc_w = state->crtc_w;
642
643 if (state->crtc_x < 0) {
644 patched_crtc_w += state->crtc_x;
645 x_offset = -state->crtc_x;
646 state->crtc_x = 0;
647 }
648
649 if (state->crtc_y + state->crtc_h > mode->vdisplay)
650 patched_crtc_h = mode->vdisplay - state->crtc_y;
651 else
652 patched_crtc_h = state->crtc_h;
653
654 if (state->crtc_y < 0) {
655 patched_crtc_h += state->crtc_y;
656 y_offset = -state->crtc_y;
657 state->crtc_y = 0;
658 }
659
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);
664
665 hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
666 vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
667
668 for (i = 0; i < state->nplanes; i++) {
669 unsigned int offset = 0;
670 int xdiv = i ? hsub : 1;
671 int ydiv = i ? vsub : 1;
672
673 state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
674 if (!state->bpp[i])
675 return -EINVAL;
676
677 switch (state->base.rotation & DRM_ROTATE_MASK) {
678 case BIT(DRM_ROTATE_90):
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];
686 break;
687 case BIT(DRM_ROTATE_180):
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];
695 break;
696 case BIT(DRM_ROTATE_270):
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];
705 break;
706 case BIT(DRM_ROTATE_0):
707 default:
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] -
713 ((patched_src_w / xdiv) *
714 state->bpp[i]);
715 state->pstride[i] = 0;
716 break;
717 }
718
719 state->offsets[i] = offset + fb->offsets[i];
720 }
721
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;
726
727 if (!layout->size &&
728 (mode->hdisplay != state->crtc_w ||
729 mode->vdisplay != state->crtc_h))
730 return -EINVAL;
731
732 if (plane->layer.desc->max_height &&
733 state->crtc_h > plane->layer.desc->max_height)
734 return -EINVAL;
735
736 if (plane->layer.desc->max_width &&
737 state->crtc_w > plane->layer.desc->max_width)
738 return -EINVAL;
739
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;
744
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;
751
752 return 0;
753}
754
755static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
756 const struct drm_plane_state *new_state)
757{
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;
768 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
769 struct atmel_hlcdc_plane_state *state =
770 drm_plane_state_to_atmel_hlcdc_plane_state(s);
771 int ret;
772
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;
803
804 atmel_hlcdc_layer_update_rollback(&plane->layer);
805 state->prepared = false;
806}
807
808static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
809 struct drm_plane_state *old_s)
810{
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);
822 atmel_hlcdc_plane_update_disc_area(plane, state);
823
824 atmel_hlcdc_layer_update_commit(&plane->layer);
825}
826
827static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
828 struct drm_plane_state *old_state)
829{
830 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
831
832 atmel_hlcdc_layer_disable(&plane->layer);
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
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)
852{
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);
857
858 if (property == props->alpha)
859 state->alpha = val;
860 else
861 return -EINVAL;
862
863 return 0;
864}
865
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)
870{
871 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
872 struct atmel_hlcdc_plane_properties *props = plane->properties;
873 const struct atmel_hlcdc_plane_state *state =
874 container_of(s, const struct atmel_hlcdc_plane_state, base);
875
876 if (property == props->alpha)
877 *val = state->alpha;
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,
905 plane->base.dev->mode_config.rotation_property,
906 BIT(DRM_ROTATE_0));
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
928static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
929 .prepare_fb = atmel_hlcdc_plane_prepare_fb,
930 .cleanup_fb = atmel_hlcdc_plane_cleanup_fb,
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
969 copy->disc_updated = false;
970 copy->prepared = false;
971
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
990static struct drm_plane_funcs layer_plane_funcs = {
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,
994 .destroy = atmel_hlcdc_plane_destroy,
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,
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,
1029 desc->formats->nformats, type, NULL);
1030 if (ret)
1031 return ERR_PTR(ret);
1032
1033 drm_plane_helper_add(&plane->base,
1034 &atmel_hlcdc_layer_plane_helper_funcs);
1035
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
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)
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.036288 seconds and 5 git commands to generate.