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