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