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 	int ret;
605 	int i;
606 
607 	if (!state->base.crtc || !fb)
608 		return 0;
609 
610 	crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
611 	mode = &crtc_state->adjusted_mode;
612 
613 	ret = drm_atomic_helper_check_plane_state(s, crtc_state,
614 						  (1 << 16) / 2048,
615 						  INT_MAX, true, true);
616 	if (ret || !s->visible)
617 		return ret;
618 
619 	state->src_x = s->src.x1;
620 	state->src_y = s->src.y1;
621 	state->src_w = drm_rect_width(&s->src);
622 	state->src_h = drm_rect_height(&s->src);
623 	state->crtc_x = s->dst.x1;
624 	state->crtc_y = s->dst.y1;
625 	state->crtc_w = drm_rect_width(&s->dst);
626 	state->crtc_h = drm_rect_height(&s->dst);
627 
628 	if ((state->src_x | state->src_y | state->src_w | state->src_h) &
629 	    SUBPIXEL_MASK)
630 		return -EINVAL;
631 
632 	state->src_x >>= 16;
633 	state->src_y >>= 16;
634 	state->src_w >>= 16;
635 	state->src_h >>= 16;
636 
637 	state->nplanes = fb->format->num_planes;
638 	if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
639 		return -EINVAL;
640 
641 	for (i = 0; i < state->nplanes; i++) {
642 		unsigned int offset = 0;
643 		int xdiv = i ? fb->format->hsub : 1;
644 		int ydiv = i ? fb->format->vsub : 1;
645 
646 		state->bpp[i] = fb->format->cpp[i];
647 		if (!state->bpp[i])
648 			return -EINVAL;
649 
650 		switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
651 		case DRM_MODE_ROTATE_90:
652 			offset = (state->src_y / ydiv) *
653 				 fb->pitches[i];
654 			offset += ((state->src_x + state->src_w - 1) /
655 				   xdiv) * state->bpp[i];
656 			state->xstride[i] = -(((state->src_h - 1) / ydiv) *
657 					    fb->pitches[i]) -
658 					  (2 * state->bpp[i]);
659 			state->pstride[i] = fb->pitches[i] - state->bpp[i];
660 			break;
661 		case DRM_MODE_ROTATE_180:
662 			offset = ((state->src_y + state->src_h - 1) /
663 				  ydiv) * fb->pitches[i];
664 			offset += ((state->src_x + state->src_w - 1) /
665 				   xdiv) * state->bpp[i];
666 			state->xstride[i] = ((((state->src_w - 1) / xdiv) - 1) *
667 					   state->bpp[i]) - fb->pitches[i];
668 			state->pstride[i] = -2 * state->bpp[i];
669 			break;
670 		case DRM_MODE_ROTATE_270:
671 			offset = ((state->src_y + state->src_h - 1) /
672 				  ydiv) * fb->pitches[i];
673 			offset += (state->src_x / xdiv) * state->bpp[i];
674 			state->xstride[i] = ((state->src_h - 1) / ydiv) *
675 					  fb->pitches[i];
676 			state->pstride[i] = -fb->pitches[i] - state->bpp[i];
677 			break;
678 		case DRM_MODE_ROTATE_0:
679 		default:
680 			offset = (state->src_y / ydiv) * fb->pitches[i];
681 			offset += (state->src_x / xdiv) * state->bpp[i];
682 			state->xstride[i] = fb->pitches[i] -
683 					  ((state->src_w / xdiv) *
684 					   state->bpp[i]);
685 			state->pstride[i] = 0;
686 			break;
687 		}
688 
689 		state->offsets[i] = offset + fb->offsets[i];
690 	}
691 
692 	/*
693 	 * Swap width and size in case of 90 or 270 degrees rotation
694 	 */
695 	if (drm_rotation_90_or_270(state->base.rotation)) {
696 		swap(state->src_w, state->src_h);
697 	}
698 
699 	if (!desc->layout.size &&
700 	    (mode->hdisplay != state->crtc_w ||
701 	     mode->vdisplay != state->crtc_h))
702 		return -EINVAL;
703 
704 	if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
705 	    (!desc->layout.memsize ||
706 	     state->base.fb->format->has_alpha))
707 		return -EINVAL;
708 
709 	return 0;
710 }
711 
712 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
713 					     struct drm_plane_state *old_state)
714 {
715 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
716 
717 	/* Disable interrupts */
718 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
719 				    0xffffffff);
720 
721 	/* Disable the layer */
722 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
723 				    ATMEL_HLCDC_LAYER_RST |
724 				    ATMEL_HLCDC_LAYER_A2Q |
725 				    ATMEL_HLCDC_LAYER_UPDATE);
726 
727 	/* Clear all pending interrupts */
728 	atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
729 }
730 
731 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
732 					    struct drm_plane_state *old_s)
733 {
734 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
735 	struct atmel_hlcdc_plane_state *state =
736 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
737 	u32 sr;
738 
739 	if (!p->state->crtc || !p->state->fb)
740 		return;
741 
742 	if (!state->base.visible) {
743 		atmel_hlcdc_plane_atomic_disable(p, old_s);
744 		return;
745 	}
746 
747 	atmel_hlcdc_plane_update_pos_and_size(plane, state);
748 	atmel_hlcdc_plane_update_general_settings(plane, state);
749 	atmel_hlcdc_plane_update_format(plane, state);
750 	atmel_hlcdc_plane_update_clut(plane, state);
751 	atmel_hlcdc_plane_update_buffers(plane, state);
752 	atmel_hlcdc_plane_update_disc_area(plane, state);
753 
754 	/* Enable the overrun interrupts. */
755 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
756 				    ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
757 				    ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
758 				    ATMEL_HLCDC_LAYER_OVR_IRQ(2));
759 
760 	/* Apply the new config at the next SOF event. */
761 	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
762 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
763 			ATMEL_HLCDC_LAYER_UPDATE |
764 			(sr & ATMEL_HLCDC_LAYER_EN ?
765 			 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
766 }
767 
768 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
769 {
770 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
771 
772 	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
773 	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
774 		int ret;
775 
776 		ret = drm_plane_create_alpha_property(&plane->base);
777 		if (ret)
778 			return ret;
779 	}
780 
781 	if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
782 		int ret;
783 
784 		ret = drm_plane_create_rotation_property(&plane->base,
785 							 DRM_MODE_ROTATE_0,
786 							 DRM_MODE_ROTATE_0 |
787 							 DRM_MODE_ROTATE_90 |
788 							 DRM_MODE_ROTATE_180 |
789 							 DRM_MODE_ROTATE_270);
790 		if (ret)
791 			return ret;
792 	}
793 
794 	if (desc->layout.csc) {
795 		/*
796 		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
797 		 * userspace modify these factors (using a BLOB property ?).
798 		 */
799 		atmel_hlcdc_layer_write_cfg(&plane->layer,
800 					    desc->layout.csc,
801 					    0x4c900091);
802 		atmel_hlcdc_layer_write_cfg(&plane->layer,
803 					    desc->layout.csc + 1,
804 					    0x7a5f5090);
805 		atmel_hlcdc_layer_write_cfg(&plane->layer,
806 					    desc->layout.csc + 2,
807 					    0x40040890);
808 	}
809 
810 	return 0;
811 }
812 
813 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
814 {
815 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
816 	u32 isr;
817 
818 	isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
819 
820 	/*
821 	 * There's not much we can do in case of overrun except informing
822 	 * the user. However, we are in interrupt context here, hence the
823 	 * use of dev_dbg().
824 	 */
825 	if (isr &
826 	    (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
827 	     ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
828 		dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
829 			desc->name);
830 }
831 
832 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
833 	.atomic_check = atmel_hlcdc_plane_atomic_check,
834 	.atomic_update = atmel_hlcdc_plane_atomic_update,
835 	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
836 };
837 
838 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
839 					 struct atmel_hlcdc_plane_state *state)
840 {
841 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
842 	int i;
843 
844 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
845 		struct atmel_hlcdc_dma_channel_dscr *dscr;
846 		dma_addr_t dscr_dma;
847 
848 		dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
849 		if (!dscr)
850 			goto err;
851 
852 		dscr->addr = 0;
853 		dscr->next = dscr_dma;
854 		dscr->self = dscr_dma;
855 		dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
856 
857 		state->dscrs[i] = dscr;
858 	}
859 
860 	return 0;
861 
862 err:
863 	for (i--; i >= 0; i--) {
864 		dma_pool_free(dc->dscrpool, state->dscrs[i],
865 			      state->dscrs[i]->self);
866 	}
867 
868 	return -ENOMEM;
869 }
870 
871 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
872 {
873 	struct atmel_hlcdc_plane_state *state;
874 
875 	if (p->state) {
876 		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
877 
878 		if (state->base.fb)
879 			drm_framebuffer_put(state->base.fb);
880 
881 		kfree(state);
882 		p->state = NULL;
883 	}
884 
885 	state = kzalloc(sizeof(*state), GFP_KERNEL);
886 	if (state) {
887 		if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
888 			kfree(state);
889 			dev_err(p->dev->dev,
890 				"Failed to allocate initial plane state\n");
891 			return;
892 		}
893 		__drm_atomic_helper_plane_reset(p, &state->base);
894 	}
895 }
896 
897 static struct drm_plane_state *
898 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
899 {
900 	struct atmel_hlcdc_plane_state *state =
901 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
902 	struct atmel_hlcdc_plane_state *copy;
903 
904 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
905 	if (!copy)
906 		return NULL;
907 
908 	if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
909 		kfree(copy);
910 		return NULL;
911 	}
912 
913 	if (copy->base.fb)
914 		drm_framebuffer_get(copy->base.fb);
915 
916 	return &copy->base;
917 }
918 
919 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
920 						   struct drm_plane_state *s)
921 {
922 	struct atmel_hlcdc_plane_state *state =
923 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
924 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
925 	int i;
926 
927 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
928 		dma_pool_free(dc->dscrpool, state->dscrs[i],
929 			      state->dscrs[i]->self);
930 	}
931 
932 	if (s->fb)
933 		drm_framebuffer_put(s->fb);
934 
935 	kfree(state);
936 }
937 
938 static const struct drm_plane_funcs layer_plane_funcs = {
939 	.update_plane = drm_atomic_helper_update_plane,
940 	.disable_plane = drm_atomic_helper_disable_plane,
941 	.destroy = drm_plane_cleanup,
942 	.reset = atmel_hlcdc_plane_reset,
943 	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
944 	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
945 };
946 
947 static int atmel_hlcdc_plane_create(struct drm_device *dev,
948 				    const struct atmel_hlcdc_layer_desc *desc)
949 {
950 	struct atmel_hlcdc_dc *dc = dev->dev_private;
951 	struct atmel_hlcdc_plane *plane;
952 	enum drm_plane_type type;
953 	int ret;
954 
955 	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
956 	if (!plane)
957 		return -ENOMEM;
958 
959 	atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
960 
961 	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
962 		type = DRM_PLANE_TYPE_PRIMARY;
963 	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
964 		type = DRM_PLANE_TYPE_CURSOR;
965 	else
966 		type = DRM_PLANE_TYPE_OVERLAY;
967 
968 	ret = drm_universal_plane_init(dev, &plane->base, 0,
969 				       &layer_plane_funcs,
970 				       desc->formats->formats,
971 				       desc->formats->nformats,
972 				       NULL, type, NULL);
973 	if (ret)
974 		return ret;
975 
976 	drm_plane_helper_add(&plane->base,
977 			     &atmel_hlcdc_layer_plane_helper_funcs);
978 
979 	/* Set default property values*/
980 	ret = atmel_hlcdc_plane_init_properties(plane);
981 	if (ret)
982 		return ret;
983 
984 	dc->layers[desc->id] = &plane->layer;
985 
986 	return 0;
987 }
988 
989 int atmel_hlcdc_create_planes(struct drm_device *dev)
990 {
991 	struct atmel_hlcdc_dc *dc = dev->dev_private;
992 	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
993 	int nlayers = dc->desc->nlayers;
994 	int i, ret;
995 
996 	dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
997 				sizeof(struct atmel_hlcdc_dma_channel_dscr),
998 				sizeof(u64), 0);
999 	if (!dc->dscrpool)
1000 		return -ENOMEM;
1001 
1002 	for (i = 0; i < nlayers; i++) {
1003 		if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1004 		    descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1005 		    descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1006 			continue;
1007 
1008 		ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1009 		if (ret)
1010 			return ret;
1011 	}
1012 
1013 	return 0;
1014 }
1015