dt-bindings: mtd: ingenic: Use standard ecc-engine property
[linux/fpc-iii.git] / drivers / gpu / drm / atmel-hlcdc / atmel_hlcdc_plane.c
blobe836e2de35ce8bd240ce7db48ffa6adf13c96f4e
1 /*
2 * Copyright (C) 2014 Free Electrons
3 * Copyright (C) 2014 Atmel
5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
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.
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.
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/>.
20 #include "atmel_hlcdc_dc.h"
22 /**
23 * Atmel HLCDC Plane state structure.
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 * @disc_x: x discard position
35 * @disc_y: y discard position
36 * @disc_w: discard width
37 * @disc_h: discard height
38 * @bpp: bytes per pixel deduced from pixel_format
39 * @offsets: offsets to apply to the GEM buffers
40 * @xstride: value to add to the pixel pointer between each line
41 * @pstride: value to add to the pixel pointer between each pixel
42 * @nplanes: number of planes (deduced from pixel_format)
43 * @dscrs: DMA descriptors
45 struct 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;
56 int disc_x;
57 int disc_y;
58 int disc_w;
59 int disc_h;
61 int ahb_id;
63 /* These fields are private and should not be touched */
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;
70 /* DMA descriptors. */
71 struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
74 static inline struct atmel_hlcdc_plane_state *
75 drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
77 return container_of(s, struct atmel_hlcdc_plane_state, base);
80 #define SUBPIXEL_MASK 0xffff
82 static 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,
95 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
96 .formats = rgb_formats,
97 .nformats = ARRAY_SIZE(rgb_formats),
100 static 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,
122 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
123 .formats = rgb_and_yuv_formats,
124 .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
127 static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
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;
191 return 0;
194 static 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,
213 static u32 heo_downscaling_ycoef[] = {
214 0x00123737,
215 0x00173732,
216 0x001b382d,
217 0x001f3928,
218 0x00243824,
219 0x0028391f,
220 0x002d381b,
221 0x00323717,
224 static 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,
243 static u32 heo_upscaling_ycoef[] = {
244 0x00004040,
245 0x00075920,
246 0x00056f0c,
247 0x00027b03,
248 0x00008000,
249 0x00037b02,
250 0x000c6f05,
251 0x00205907,
254 #define ATMEL_HLCDC_XPHIDEF 4
255 #define ATMEL_HLCDC_YPHIDEF 4
257 static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
258 u32 dstsize,
259 u32 phidef)
261 u32 factor, max_memsize;
263 factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
264 max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
266 if (max_memsize > srcsize - 1)
267 factor--;
269 return factor;
272 static void
273 atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
274 const u32 *coeff_tab, int size,
275 unsigned int cfg_offs)
277 int i;
279 for (i = 0; i < size; i++)
280 atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
281 coeff_tab[i]);
284 void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
285 struct atmel_hlcdc_plane_state *state)
287 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
288 u32 xfactor, yfactor;
290 if (!desc->layout.scaler_config)
291 return;
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;
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);
304 yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
305 state->crtc_h,
306 ATMEL_HLCDC_YPHIDEF);
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);
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;
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));
332 static void
333 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
334 struct atmel_hlcdc_plane_state *state)
336 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
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));
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));
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));
354 atmel_hlcdc_plane_setup_scaler(plane, state);
357 static void
358 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
359 struct atmel_hlcdc_plane_state *state)
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;
366 * Rotation optimization is not working on RGB888 (rotation is still
367 * working but without any optimization).
369 if (format->format == DRM_FORMAT_RGB888)
370 cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
372 atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
373 cfg);
375 cfg = ATMEL_HLCDC_LAYER_DMA;
377 if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
378 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
379 ATMEL_HLCDC_LAYER_ITER;
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);
388 if (state->disc_h && state->disc_w)
389 cfg |= ATMEL_HLCDC_LAYER_DISCEN;
391 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
392 cfg);
395 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
396 struct atmel_hlcdc_plane_state *state)
398 u32 cfg;
399 int ret;
401 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
402 &cfg);
403 if (ret)
404 return;
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;
411 atmel_hlcdc_layer_write_cfg(&plane->layer,
412 ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
415 static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane,
416 struct atmel_hlcdc_plane_state *state)
418 struct drm_crtc *crtc = state->base.crtc;
419 struct drm_color_lut *lut;
420 int idx;
422 if (!crtc || !crtc->state)
423 return;
425 if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
426 return;
428 lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
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);
435 atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
439 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
440 struct atmel_hlcdc_plane_state *state)
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;
447 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
449 for (i = 0; i < state->nplanes; i++) {
450 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
452 state->dscrs[i]->addr = gem->paddr + state->offsets[i];
454 atmel_hlcdc_layer_write_reg(&plane->layer,
455 ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
456 state->dscrs[i]->self);
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);
470 if (desc->layout.xstride[i])
471 atmel_hlcdc_layer_write_cfg(&plane->layer,
472 desc->layout.xstride[i],
473 state->xstride[i]);
475 if (desc->layout.pstride[i])
476 atmel_hlcdc_layer_write_cfg(&plane->layer,
477 desc->layout.pstride[i],
478 state->pstride[i]);
482 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
484 unsigned int ahb_load[2] = { };
485 struct drm_plane *plane;
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;
493 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
494 if (IS_ERR(plane_s))
495 return PTR_ERR(plane_s);
497 plane_state =
498 drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
500 pixels = (plane_state->src_w * plane_state->src_h) -
501 (plane_state->disc_w * plane_state->disc_h);
503 for (i = 0; i < plane_state->nplanes; i++)
504 load += pixels * plane_state->bpp[i];
506 if (ahb_load[0] <= ahb_load[1])
507 plane_state->ahb_id = 0;
508 else
509 plane_state->ahb_id = 1;
511 ahb_load[plane_state->ahb_id] += load;
514 return 0;
518 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
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;
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;
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);
537 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
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;
543 if (ovl == c_state->crtc->primary)
544 continue;
546 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
547 if (IS_ERR(ovl_s))
548 return PTR_ERR(ovl_s);
550 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
552 if (!ovl_s->visible ||
553 !ovl_s->fb ||
554 ovl_s->fb->format->has_alpha ||
555 ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
556 continue;
558 /* TODO: implement a smarter hidden area detection */
559 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
560 continue;
562 disc_x = ovl_state->crtc_x;
563 disc_y = ovl_state->crtc_y;
564 disc_h = ovl_state->crtc_h;
565 disc_w = ovl_state->crtc_w;
568 primary_state->disc_x = disc_x;
569 primary_state->disc_y = disc_y;
570 primary_state->disc_w = disc_w;
571 primary_state->disc_h = disc_h;
573 return 0;
576 static void
577 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
578 struct atmel_hlcdc_plane_state *state)
580 const struct atmel_hlcdc_layer_cfg_layout *layout;
582 layout = &plane->layer.desc->layout;
583 if (!layout->disc_pos || !layout->disc_size)
584 return;
586 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
587 ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
588 state->disc_y));
590 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
591 ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
592 state->disc_h));
595 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
596 struct drm_plane_state *s)
598 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
599 struct atmel_hlcdc_plane_state *state =
600 drm_plane_state_to_atmel_hlcdc_plane_state(s);
601 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
602 struct drm_framebuffer *fb = state->base.fb;
603 const struct drm_display_mode *mode;
604 struct drm_crtc_state *crtc_state;
605 unsigned int tmp;
606 int hsub = 1;
607 int vsub = 1;
608 int ret;
609 int i;
611 if (!state->base.crtc || !fb)
612 return 0;
614 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
615 mode = &crtc_state->adjusted_mode;
617 ret = drm_atomic_helper_check_plane_state(s, crtc_state,
618 (1 << 16) / 2048,
619 INT_MAX, true, true);
620 if (ret || !s->visible)
621 return ret;
623 state->src_x = s->src.x1;
624 state->src_y = s->src.y1;
625 state->src_w = drm_rect_width(&s->src);
626 state->src_h = drm_rect_height(&s->src);
627 state->crtc_x = s->dst.x1;
628 state->crtc_y = s->dst.y1;
629 state->crtc_w = drm_rect_width(&s->dst);
630 state->crtc_h = drm_rect_height(&s->dst);
632 if ((state->src_x | state->src_y | state->src_w | state->src_h) &
633 SUBPIXEL_MASK)
634 return -EINVAL;
636 state->src_x >>= 16;
637 state->src_y >>= 16;
638 state->src_w >>= 16;
639 state->src_h >>= 16;
641 state->nplanes = fb->format->num_planes;
642 if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
643 return -EINVAL;
645 hsub = drm_format_horz_chroma_subsampling(fb->format->format);
646 vsub = drm_format_vert_chroma_subsampling(fb->format->format);
648 for (i = 0; i < state->nplanes; i++) {
649 unsigned int offset = 0;
650 int xdiv = i ? hsub : 1;
651 int ydiv = i ? vsub : 1;
653 state->bpp[i] = fb->format->cpp[i];
654 if (!state->bpp[i])
655 return -EINVAL;
657 switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
658 case DRM_MODE_ROTATE_90:
659 offset = (state->src_y / ydiv) *
660 fb->pitches[i];
661 offset += ((state->src_x + state->src_w - 1) /
662 xdiv) * state->bpp[i];
663 state->xstride[i] = -(((state->src_h - 1) / ydiv) *
664 fb->pitches[i]) -
665 (2 * state->bpp[i]);
666 state->pstride[i] = fb->pitches[i] - state->bpp[i];
667 break;
668 case DRM_MODE_ROTATE_180:
669 offset = ((state->src_y + state->src_h - 1) /
670 ydiv) * fb->pitches[i];
671 offset += ((state->src_x + state->src_w - 1) /
672 xdiv) * state->bpp[i];
673 state->xstride[i] = ((((state->src_w - 1) / xdiv) - 1) *
674 state->bpp[i]) - fb->pitches[i];
675 state->pstride[i] = -2 * state->bpp[i];
676 break;
677 case DRM_MODE_ROTATE_270:
678 offset = ((state->src_y + state->src_h - 1) /
679 ydiv) * fb->pitches[i];
680 offset += (state->src_x / xdiv) * state->bpp[i];
681 state->xstride[i] = ((state->src_h - 1) / ydiv) *
682 fb->pitches[i];
683 state->pstride[i] = -fb->pitches[i] - state->bpp[i];
684 break;
685 case DRM_MODE_ROTATE_0:
686 default:
687 offset = (state->src_y / ydiv) * fb->pitches[i];
688 offset += (state->src_x / xdiv) * state->bpp[i];
689 state->xstride[i] = fb->pitches[i] -
690 ((state->src_w / xdiv) *
691 state->bpp[i]);
692 state->pstride[i] = 0;
693 break;
696 state->offsets[i] = offset + fb->offsets[i];
700 * Swap width and size in case of 90 or 270 degrees rotation
702 if (drm_rotation_90_or_270(state->base.rotation)) {
703 tmp = state->src_w;
704 state->src_w = state->src_h;
705 state->src_h = tmp;
708 if (!desc->layout.size &&
709 (mode->hdisplay != state->crtc_w ||
710 mode->vdisplay != state->crtc_h))
711 return -EINVAL;
713 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
714 (!desc->layout.memsize ||
715 state->base.fb->format->has_alpha))
716 return -EINVAL;
718 return 0;
721 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
722 struct drm_plane_state *old_state)
724 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
726 /* Disable interrupts */
727 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
728 0xffffffff);
730 /* Disable the layer */
731 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
732 ATMEL_HLCDC_LAYER_RST |
733 ATMEL_HLCDC_LAYER_A2Q |
734 ATMEL_HLCDC_LAYER_UPDATE);
736 /* Clear all pending interrupts */
737 atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
740 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
741 struct drm_plane_state *old_s)
743 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
744 struct atmel_hlcdc_plane_state *state =
745 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
746 u32 sr;
748 if (!p->state->crtc || !p->state->fb)
749 return;
751 if (!state->base.visible) {
752 atmel_hlcdc_plane_atomic_disable(p, old_s);
753 return;
756 atmel_hlcdc_plane_update_pos_and_size(plane, state);
757 atmel_hlcdc_plane_update_general_settings(plane, state);
758 atmel_hlcdc_plane_update_format(plane, state);
759 atmel_hlcdc_plane_update_clut(plane, state);
760 atmel_hlcdc_plane_update_buffers(plane, state);
761 atmel_hlcdc_plane_update_disc_area(plane, state);
763 /* Enable the overrun interrupts. */
764 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
765 ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
766 ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
767 ATMEL_HLCDC_LAYER_OVR_IRQ(2));
769 /* Apply the new config at the next SOF event. */
770 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
771 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
772 ATMEL_HLCDC_LAYER_UPDATE |
773 (sr & ATMEL_HLCDC_LAYER_EN ?
774 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
777 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
779 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
781 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
782 desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
783 int ret;
785 ret = drm_plane_create_alpha_property(&plane->base);
786 if (ret)
787 return ret;
790 if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
791 int ret;
793 ret = drm_plane_create_rotation_property(&plane->base,
794 DRM_MODE_ROTATE_0,
795 DRM_MODE_ROTATE_0 |
796 DRM_MODE_ROTATE_90 |
797 DRM_MODE_ROTATE_180 |
798 DRM_MODE_ROTATE_270);
799 if (ret)
800 return ret;
803 if (desc->layout.csc) {
805 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
806 * userspace modify these factors (using a BLOB property ?).
808 atmel_hlcdc_layer_write_cfg(&plane->layer,
809 desc->layout.csc,
810 0x4c900091);
811 atmel_hlcdc_layer_write_cfg(&plane->layer,
812 desc->layout.csc + 1,
813 0x7a5f5090);
814 atmel_hlcdc_layer_write_cfg(&plane->layer,
815 desc->layout.csc + 2,
816 0x40040890);
819 return 0;
822 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
824 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
825 u32 isr;
827 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
830 * There's not much we can do in case of overrun except informing
831 * the user. However, we are in interrupt context here, hence the
832 * use of dev_dbg().
834 if (isr &
835 (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
836 ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
837 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
838 desc->name);
841 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
842 .atomic_check = atmel_hlcdc_plane_atomic_check,
843 .atomic_update = atmel_hlcdc_plane_atomic_update,
844 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
847 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
848 struct atmel_hlcdc_plane_state *state)
850 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
851 int i;
853 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
854 struct atmel_hlcdc_dma_channel_dscr *dscr;
855 dma_addr_t dscr_dma;
857 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
858 if (!dscr)
859 goto err;
861 dscr->addr = 0;
862 dscr->next = dscr_dma;
863 dscr->self = dscr_dma;
864 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
866 state->dscrs[i] = dscr;
869 return 0;
871 err:
872 for (i--; i >= 0; i--) {
873 dma_pool_free(dc->dscrpool, state->dscrs[i],
874 state->dscrs[i]->self);
877 return -ENOMEM;
880 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
882 struct atmel_hlcdc_plane_state *state;
884 if (p->state) {
885 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
887 if (state->base.fb)
888 drm_framebuffer_put(state->base.fb);
890 kfree(state);
891 p->state = NULL;
894 state = kzalloc(sizeof(*state), GFP_KERNEL);
895 if (state) {
896 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
897 kfree(state);
898 dev_err(p->dev->dev,
899 "Failed to allocate initial plane state\n");
900 return;
902 __drm_atomic_helper_plane_reset(p, &state->base);
906 static struct drm_plane_state *
907 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
909 struct atmel_hlcdc_plane_state *state =
910 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
911 struct atmel_hlcdc_plane_state *copy;
913 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
914 if (!copy)
915 return NULL;
917 if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
918 kfree(copy);
919 return NULL;
922 if (copy->base.fb)
923 drm_framebuffer_get(copy->base.fb);
925 return &copy->base;
928 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
929 struct drm_plane_state *s)
931 struct atmel_hlcdc_plane_state *state =
932 drm_plane_state_to_atmel_hlcdc_plane_state(s);
933 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
934 int i;
936 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
937 dma_pool_free(dc->dscrpool, state->dscrs[i],
938 state->dscrs[i]->self);
941 if (s->fb)
942 drm_framebuffer_put(s->fb);
944 kfree(state);
947 static const struct drm_plane_funcs layer_plane_funcs = {
948 .update_plane = drm_atomic_helper_update_plane,
949 .disable_plane = drm_atomic_helper_disable_plane,
950 .destroy = drm_plane_cleanup,
951 .reset = atmel_hlcdc_plane_reset,
952 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
953 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
956 static int atmel_hlcdc_plane_create(struct drm_device *dev,
957 const struct atmel_hlcdc_layer_desc *desc)
959 struct atmel_hlcdc_dc *dc = dev->dev_private;
960 struct atmel_hlcdc_plane *plane;
961 enum drm_plane_type type;
962 int ret;
964 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
965 if (!plane)
966 return -ENOMEM;
968 atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
970 if (desc->type == ATMEL_HLCDC_BASE_LAYER)
971 type = DRM_PLANE_TYPE_PRIMARY;
972 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
973 type = DRM_PLANE_TYPE_CURSOR;
974 else
975 type = DRM_PLANE_TYPE_OVERLAY;
977 ret = drm_universal_plane_init(dev, &plane->base, 0,
978 &layer_plane_funcs,
979 desc->formats->formats,
980 desc->formats->nformats,
981 NULL, type, NULL);
982 if (ret)
983 return ret;
985 drm_plane_helper_add(&plane->base,
986 &atmel_hlcdc_layer_plane_helper_funcs);
988 /* Set default property values*/
989 ret = atmel_hlcdc_plane_init_properties(plane);
990 if (ret)
991 return ret;
993 dc->layers[desc->id] = &plane->layer;
995 return 0;
998 int atmel_hlcdc_create_planes(struct drm_device *dev)
1000 struct atmel_hlcdc_dc *dc = dev->dev_private;
1001 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1002 int nlayers = dc->desc->nlayers;
1003 int i, ret;
1005 dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1006 sizeof(struct atmel_hlcdc_dma_channel_dscr),
1007 sizeof(u64), 0);
1008 if (!dc->dscrpool)
1009 return -ENOMEM;
1011 for (i = 0; i < nlayers; i++) {
1012 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1013 descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1014 descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1015 continue;
1017 ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1018 if (ret)
1019 return ret;
1022 return 0;