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