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