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