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