xref: /linux/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c (revision 6dfafbd0299a60bfb5d5e277fdf100037c7ded07)
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 #include <drm/drm_print.h>
20 
21 #include "atmel_hlcdc_dc.h"
22 
23 /**
24  * struct atmel_hlcdc_plane_state - Atmel HLCDC Plane state structure.
25  *
26  * @base: DRM plane state
27  * @crtc_x: x position of the plane relative to the CRTC
28  * @crtc_y: y position of the plane relative to the CRTC
29  * @crtc_w: visible width of the plane
30  * @crtc_h: visible height of the plane
31  * @src_x: x buffer position
32  * @src_y: y buffer position
33  * @src_w: buffer width
34  * @src_h: buffer height
35  * @disc_x: x discard position
36  * @disc_y: y discard position
37  * @disc_w: discard width
38  * @disc_h: discard height
39  * @ahb_id: AHB identification number
40  * @bpp: bytes per pixel deduced from pixel_format
41  * @offsets: offsets to apply to the GEM buffers
42  * @xstride: value to add to the pixel pointer between each line
43  * @pstride: value to add to the pixel pointer between each pixel
44  * @nplanes: number of planes (deduced from pixel_format)
45  * @dscrs: DMA descriptors
46  */
47 struct atmel_hlcdc_plane_state {
48 	struct drm_plane_state base;
49 	int crtc_x;
50 	int crtc_y;
51 	unsigned int crtc_w;
52 	unsigned int crtc_h;
53 	uint32_t src_x;
54 	uint32_t src_y;
55 	uint32_t src_w;
56 	uint32_t src_h;
57 
58 	int disc_x;
59 	int disc_y;
60 	int disc_w;
61 	int disc_h;
62 
63 	int ahb_id;
64 
65 	/* These fields are private and should not be touched */
66 	int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
67 	unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
68 	int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
69 	int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
70 	int nplanes;
71 
72 	/* DMA descriptors. */
73 	struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
74 };
75 
76 static inline struct atmel_hlcdc_plane_state *
77 drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
78 {
79 	return container_of(s, struct atmel_hlcdc_plane_state, base);
80 }
81 
82 #define SUBPIXEL_MASK			0xffff
83 
84 static uint32_t rgb_formats[] = {
85 	DRM_FORMAT_C8,
86 	DRM_FORMAT_XRGB4444,
87 	DRM_FORMAT_ARGB4444,
88 	DRM_FORMAT_RGBA4444,
89 	DRM_FORMAT_ARGB1555,
90 	DRM_FORMAT_RGB565,
91 	DRM_FORMAT_RGB888,
92 	DRM_FORMAT_XRGB8888,
93 	DRM_FORMAT_ARGB8888,
94 	DRM_FORMAT_RGBA8888,
95 };
96 
97 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
98 	.formats = rgb_formats,
99 	.nformats = ARRAY_SIZE(rgb_formats),
100 };
101 
102 static uint32_t rgb_and_yuv_formats[] = {
103 	DRM_FORMAT_C8,
104 	DRM_FORMAT_XRGB4444,
105 	DRM_FORMAT_ARGB4444,
106 	DRM_FORMAT_RGBA4444,
107 	DRM_FORMAT_ARGB1555,
108 	DRM_FORMAT_RGB565,
109 	DRM_FORMAT_RGB888,
110 	DRM_FORMAT_XRGB8888,
111 	DRM_FORMAT_ARGB8888,
112 	DRM_FORMAT_RGBA8888,
113 	DRM_FORMAT_AYUV,
114 	DRM_FORMAT_YUYV,
115 	DRM_FORMAT_UYVY,
116 	DRM_FORMAT_YVYU,
117 	DRM_FORMAT_VYUY,
118 	DRM_FORMAT_NV21,
119 	DRM_FORMAT_NV61,
120 	DRM_FORMAT_YUV422,
121 	DRM_FORMAT_YUV420,
122 };
123 
124 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
125 	.formats = rgb_and_yuv_formats,
126 	.nformats = ARRAY_SIZE(rgb_and_yuv_formats),
127 };
128 
129 static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
130 {
131 	switch (format) {
132 	case DRM_FORMAT_C8:
133 		*mode = ATMEL_HLCDC_C8_MODE;
134 		break;
135 	case DRM_FORMAT_XRGB4444:
136 		*mode = ATMEL_HLCDC_XRGB4444_MODE;
137 		break;
138 	case DRM_FORMAT_ARGB4444:
139 		*mode = ATMEL_HLCDC_ARGB4444_MODE;
140 		break;
141 	case DRM_FORMAT_RGBA4444:
142 		*mode = ATMEL_HLCDC_RGBA4444_MODE;
143 		break;
144 	case DRM_FORMAT_RGB565:
145 		*mode = ATMEL_HLCDC_RGB565_MODE;
146 		break;
147 	case DRM_FORMAT_RGB888:
148 		*mode = ATMEL_HLCDC_RGB888_MODE;
149 		break;
150 	case DRM_FORMAT_ARGB1555:
151 		*mode = ATMEL_HLCDC_ARGB1555_MODE;
152 		break;
153 	case DRM_FORMAT_XRGB8888:
154 		*mode = ATMEL_HLCDC_XRGB8888_MODE;
155 		break;
156 	case DRM_FORMAT_ARGB8888:
157 		*mode = ATMEL_HLCDC_ARGB8888_MODE;
158 		break;
159 	case DRM_FORMAT_RGBA8888:
160 		*mode = ATMEL_HLCDC_RGBA8888_MODE;
161 		break;
162 	case DRM_FORMAT_AYUV:
163 		*mode = ATMEL_HLCDC_AYUV_MODE;
164 		break;
165 	case DRM_FORMAT_YUYV:
166 		*mode = ATMEL_HLCDC_YUYV_MODE;
167 		break;
168 	case DRM_FORMAT_UYVY:
169 		*mode = ATMEL_HLCDC_UYVY_MODE;
170 		break;
171 	case DRM_FORMAT_YVYU:
172 		*mode = ATMEL_HLCDC_YVYU_MODE;
173 		break;
174 	case DRM_FORMAT_VYUY:
175 		*mode = ATMEL_HLCDC_VYUY_MODE;
176 		break;
177 	case DRM_FORMAT_NV21:
178 		*mode = ATMEL_HLCDC_NV21_MODE;
179 		break;
180 	case DRM_FORMAT_NV61:
181 		*mode = ATMEL_HLCDC_NV61_MODE;
182 		break;
183 	case DRM_FORMAT_YUV420:
184 		*mode = ATMEL_HLCDC_YUV420_MODE;
185 		break;
186 	case DRM_FORMAT_YUV422:
187 		*mode = ATMEL_HLCDC_YUV422_MODE;
188 		break;
189 	default:
190 		return -ENOTSUPP;
191 	}
192 
193 	return 0;
194 }
195 
196 static u32 heo_downscaling_xcoef[] = {
197 	0x11343311,
198 	0x000000f7,
199 	0x1635300c,
200 	0x000000f9,
201 	0x1b362c08,
202 	0x000000fb,
203 	0x1f372804,
204 	0x000000fe,
205 	0x24382400,
206 	0x00000000,
207 	0x28371ffe,
208 	0x00000004,
209 	0x2c361bfb,
210 	0x00000008,
211 	0x303516f9,
212 	0x0000000c,
213 };
214 
215 static u32 heo_downscaling_ycoef[] = {
216 	0x00123737,
217 	0x00173732,
218 	0x001b382d,
219 	0x001f3928,
220 	0x00243824,
221 	0x0028391f,
222 	0x002d381b,
223 	0x00323717,
224 };
225 
226 static u32 heo_upscaling_xcoef[] = {
227 	0xf74949f7,
228 	0x00000000,
229 	0xf55f33fb,
230 	0x000000fe,
231 	0xf5701efe,
232 	0x000000ff,
233 	0xf87c0dff,
234 	0x00000000,
235 	0x00800000,
236 	0x00000000,
237 	0x0d7cf800,
238 	0x000000ff,
239 	0x1e70f5ff,
240 	0x000000fe,
241 	0x335ff5fe,
242 	0x000000fb,
243 };
244 
245 static u32 heo_upscaling_ycoef[] = {
246 	0x00004040,
247 	0x00075920,
248 	0x00056f0c,
249 	0x00027b03,
250 	0x00008000,
251 	0x00037b02,
252 	0x000c6f05,
253 	0x00205907,
254 };
255 
256 #define ATMEL_HLCDC_XPHIDEF	4
257 #define ATMEL_HLCDC_YPHIDEF	4
258 
259 static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
260 						  u32 dstsize,
261 						  u32 phidef)
262 {
263 	u32 factor, max_memsize;
264 
265 	factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
266 	max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
267 
268 	if (max_memsize > srcsize - 1)
269 		factor--;
270 
271 	return factor;
272 }
273 
274 static void
275 atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
276 				      const u32 *coeff_tab, int size,
277 				      unsigned int cfg_offs)
278 {
279 	int i;
280 
281 	for (i = 0; i < size; i++)
282 		atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
283 					    coeff_tab[i]);
284 }
285 
286 static
287 void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
288 				    struct atmel_hlcdc_plane_state *state)
289 {
290 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
291 	u32 xfactor, yfactor;
292 
293 	if (!desc->layout.scaler_config)
294 		return;
295 
296 	if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
297 		atmel_hlcdc_layer_write_cfg(&plane->layer,
298 					    desc->layout.scaler_config, 0);
299 		return;
300 	}
301 
302 	if (desc->layout.phicoeffs.x) {
303 		xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
304 							state->crtc_w,
305 							ATMEL_HLCDC_XPHIDEF);
306 
307 		yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
308 							state->crtc_h,
309 							ATMEL_HLCDC_YPHIDEF);
310 
311 		atmel_hlcdc_plane_scaler_set_phicoeff(plane,
312 				state->crtc_w < state->src_w ?
313 				heo_downscaling_xcoef :
314 				heo_upscaling_xcoef,
315 				ARRAY_SIZE(heo_upscaling_xcoef),
316 				desc->layout.phicoeffs.x);
317 
318 		atmel_hlcdc_plane_scaler_set_phicoeff(plane,
319 				state->crtc_h < state->src_h ?
320 				heo_downscaling_ycoef :
321 				heo_upscaling_ycoef,
322 				ARRAY_SIZE(heo_upscaling_ycoef),
323 				desc->layout.phicoeffs.y);
324 	} else {
325 		xfactor = (1024 * state->src_w) / state->crtc_w;
326 		yfactor = (1024 * state->src_h) / state->crtc_h;
327 	}
328 
329 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
330 				    ATMEL_HLCDC_LAYER_SCALER_ENABLE |
331 				    ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
332 								     yfactor));
333 }
334 
335 static
336 void atmel_xlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
337 				    struct atmel_hlcdc_plane_state *state)
338 {
339 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
340 	u32 xfactor, yfactor;
341 
342 	if (!desc->layout.scaler_config)
343 		return;
344 
345 	if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
346 		atmel_hlcdc_layer_write_cfg(&plane->layer,
347 					    desc->layout.scaler_config, 0);
348 		return;
349 	}
350 
351 	/* xfactor = round[(2^20 * XMEMSIZE)/XSIZE)] */
352 	xfactor = (u32)(((1 << 20) * state->src_w) / state->crtc_w);
353 
354 	/* yfactor = round[(2^20 * YMEMSIZE)/YSIZE)] */
355 	yfactor = (u32)(((1 << 20) * state->src_h) / state->crtc_h);
356 
357 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
358 				    ATMEL_XLCDC_LAYER_VSCALER_LUMA_ENABLE |
359 				    ATMEL_XLCDC_LAYER_VSCALER_CHROMA_ENABLE |
360 				    ATMEL_XLCDC_LAYER_HSCALER_LUMA_ENABLE |
361 				    ATMEL_XLCDC_LAYER_HSCALER_CHROMA_ENABLE);
362 
363 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 1,
364 				    yfactor);
365 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 3,
366 				    xfactor);
367 
368 	/*
369 	 * With YCbCr 4:2:0 window resampling, configuration register
370 	 * LCDC_HEOCFG25.VXSCFACT and LCDC_HEOCFG27.HXSCFACT values are half
371 	 * the value of yfactor and xfactor.
372 	 *
373 	 * On the other hand, with YCbCr 4:2:2 window resampling, only the
374 	 * configuration register LCDC_HEOCFG27.HXSCFACT value is half the value
375 	 * of the xfactor; the value of LCDC_HEOCFG25.VXSCFACT is yfactor (no
376 	 * division by 2).
377 	 */
378 	switch (state->base.fb->format->format) {
379 	/* YCbCr 4:2:2 */
380 	case DRM_FORMAT_YUYV:
381 	case DRM_FORMAT_UYVY:
382 	case DRM_FORMAT_YVYU:
383 	case DRM_FORMAT_VYUY:
384 	case DRM_FORMAT_YUV422:
385 	case DRM_FORMAT_NV61:
386 		xfactor /= 2;
387 		break;
388 
389 	/* YCbCr 4:2:0 */
390 	case DRM_FORMAT_YUV420:
391 	case DRM_FORMAT_NV21:
392 		yfactor /= 2;
393 		xfactor /= 2;
394 		break;
395 	default:
396 		break;
397 	}
398 
399 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 2,
400 				    yfactor);
401 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 4,
402 				    xfactor);
403 }
404 
405 static void
406 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
407 				      struct atmel_hlcdc_plane_state *state)
408 {
409 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
410 	struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
411 
412 	if (desc->layout.size)
413 		atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
414 					ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
415 							       state->crtc_h));
416 
417 	if (desc->layout.memsize)
418 		atmel_hlcdc_layer_write_cfg(&plane->layer,
419 					desc->layout.memsize,
420 					ATMEL_HLCDC_LAYER_SIZE(state->src_w,
421 							       state->src_h));
422 
423 	if (desc->layout.pos)
424 		atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
425 					ATMEL_HLCDC_LAYER_POS(state->crtc_x,
426 							      state->crtc_y));
427 
428 	dc->desc->ops->plane_setup_scaler(plane, state);
429 }
430 
431 static
432 void atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
433 					       struct atmel_hlcdc_plane_state *state)
434 {
435 	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
436 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
437 	const struct drm_format_info *format = state->base.fb->format;
438 
439 	/*
440 	 * Rotation optimization is not working on RGB888 (rotation is still
441 	 * working but without any optimization).
442 	 */
443 	if (format->format == DRM_FORMAT_RGB888)
444 		cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
445 
446 	atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
447 				    cfg);
448 
449 	cfg = ATMEL_HLCDC_LAYER_DMA | ATMEL_HLCDC_LAYER_REP;
450 
451 	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
452 		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
453 		       ATMEL_HLCDC_LAYER_ITER;
454 
455 		if (format->has_alpha)
456 			cfg |= ATMEL_HLCDC_LAYER_LAEN;
457 		else
458 			cfg |= ATMEL_HLCDC_LAYER_GAEN |
459 			       ATMEL_HLCDC_LAYER_GA(state->base.alpha);
460 	}
461 
462 	if (state->disc_h && state->disc_w)
463 		cfg |= ATMEL_HLCDC_LAYER_DISCEN;
464 
465 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
466 				    cfg);
467 }
468 
469 static
470 void atmel_xlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
471 					       struct atmel_hlcdc_plane_state *state)
472 {
473 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
474 	const struct drm_format_info *format = state->base.fb->format;
475 	unsigned int cfg;
476 
477 	atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_XLCDC_LAYER_DMA_CFG,
478 				    ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id);
479 
480 	cfg = ATMEL_XLCDC_LAYER_DMA | ATMEL_XLCDC_LAYER_REP;
481 
482 	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
483 		/*
484 		 * Alpha Blending bits specific to SAM9X7 SoC
485 		 */
486 		cfg |= ATMEL_XLCDC_LAYER_SFACTC_A0_MULT_AS |
487 		       ATMEL_XLCDC_LAYER_SFACTA_ONE |
488 		       ATMEL_XLCDC_LAYER_DFACTC_M_A0_MULT_AS |
489 		       ATMEL_XLCDC_LAYER_DFACTA_ONE;
490 		if (format->has_alpha)
491 			cfg |= ATMEL_XLCDC_LAYER_A0(0xff);
492 		else
493 			cfg |= ATMEL_XLCDC_LAYER_A0(state->base.alpha);
494 	}
495 
496 	if (state->disc_h && state->disc_w)
497 		cfg |= ATMEL_XLCDC_LAYER_DISCEN;
498 
499 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
500 				    cfg);
501 }
502 
503 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
504 					struct atmel_hlcdc_plane_state *state)
505 {
506 	u32 cfg;
507 	int ret;
508 
509 	ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
510 					       &cfg);
511 	if (ret)
512 		return;
513 
514 	if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
515 	     state->base.fb->format->format == DRM_FORMAT_NV61) &&
516 	    drm_rotation_90_or_270(state->base.rotation))
517 		cfg |= ATMEL_HLCDC_YUV422ROT;
518 
519 	atmel_hlcdc_layer_write_cfg(&plane->layer,
520 				    ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
521 }
522 
523 static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane,
524 					  struct atmel_hlcdc_plane_state *state)
525 {
526 	struct drm_crtc *crtc = state->base.crtc;
527 	struct drm_color_lut *lut;
528 	int idx;
529 
530 	if (!crtc || !crtc->state)
531 		return;
532 
533 	if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
534 		return;
535 
536 	lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
537 
538 	for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
539 		u32 val = ((lut->red << 8) & 0xff0000) |
540 			(lut->green & 0xff00) |
541 			(lut->blue >> 8);
542 
543 		atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
544 	}
545 }
546 
547 static void atmel_hlcdc_update_buffers(struct atmel_hlcdc_plane *plane,
548 				       struct atmel_hlcdc_plane_state *state,
549 				       u32 sr, int i)
550 {
551 	atmel_hlcdc_layer_write_reg(&plane->layer,
552 				    ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
553 				    state->dscrs[i]->self);
554 
555 	if (sr & ATMEL_HLCDC_LAYER_EN)
556 		return;
557 
558 	atmel_hlcdc_layer_write_reg(&plane->layer,
559 				    ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
560 				    state->dscrs[i]->addr);
561 	atmel_hlcdc_layer_write_reg(&plane->layer,
562 				    ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
563 				    state->dscrs[i]->ctrl);
564 	atmel_hlcdc_layer_write_reg(&plane->layer,
565 				    ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
566 				    state->dscrs[i]->self);
567 }
568 
569 static void atmel_xlcdc_update_buffers(struct atmel_hlcdc_plane *plane,
570 				       struct atmel_hlcdc_plane_state *state,
571 				       u32 sr, int i)
572 {
573 	atmel_hlcdc_layer_write_reg(&plane->layer,
574 				    ATMEL_XLCDC_LAYER_PLANE_ADDR(i),
575 				    state->dscrs[i]->addr);
576 }
577 
578 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
579 					     struct atmel_hlcdc_plane_state *state)
580 {
581 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
582 	struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
583 	struct drm_framebuffer *fb = state->base.fb;
584 	u32 sr;
585 	int i;
586 
587 	if (!dc->desc->is_xlcdc)
588 		sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
589 
590 	for (i = 0; i < state->nplanes; i++) {
591 		struct drm_gem_dma_object *gem = drm_fb_dma_get_gem_obj(fb, i);
592 
593 		state->dscrs[i]->addr = gem->dma_addr + state->offsets[i];
594 
595 		dc->desc->ops->lcdc_update_buffers(plane, state, sr, i);
596 
597 		if (desc->layout.xstride[i])
598 			atmel_hlcdc_layer_write_cfg(&plane->layer,
599 						    desc->layout.xstride[i],
600 						    state->xstride[i]);
601 
602 		if (desc->layout.pstride[i])
603 			atmel_hlcdc_layer_write_cfg(&plane->layer,
604 						    desc->layout.pstride[i],
605 						    state->pstride[i]);
606 	}
607 }
608 
609 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
610 {
611 	unsigned int ahb_load[2] = { };
612 	struct drm_plane *plane;
613 
614 	drm_atomic_crtc_state_for_each_plane(plane, c_state) {
615 		struct atmel_hlcdc_plane_state *plane_state;
616 		struct drm_plane_state *plane_s;
617 		unsigned int pixels, load = 0;
618 		int i;
619 
620 		plane_s = drm_atomic_get_plane_state(c_state->state, plane);
621 		if (IS_ERR(plane_s))
622 			return PTR_ERR(plane_s);
623 
624 		plane_state =
625 			drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
626 
627 		pixels = (plane_state->src_w * plane_state->src_h) -
628 			 (plane_state->disc_w * plane_state->disc_h);
629 
630 		for (i = 0; i < plane_state->nplanes; i++)
631 			load += pixels * plane_state->bpp[i];
632 
633 		if (ahb_load[0] <= ahb_load[1])
634 			plane_state->ahb_id = 0;
635 		else
636 			plane_state->ahb_id = 1;
637 
638 		ahb_load[plane_state->ahb_id] += load;
639 	}
640 
641 	return 0;
642 }
643 
644 int
645 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
646 {
647 	int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
648 	const struct atmel_hlcdc_layer_cfg_layout *layout;
649 	struct atmel_hlcdc_plane_state *primary_state;
650 	struct drm_plane_state *primary_s;
651 	struct atmel_hlcdc_plane *primary;
652 	struct drm_plane *ovl;
653 
654 	primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
655 	layout = &primary->layer.desc->layout;
656 	if (!layout->disc_pos || !layout->disc_size)
657 		return 0;
658 
659 	primary_s = drm_atomic_get_plane_state(c_state->state,
660 					       &primary->base);
661 	if (IS_ERR(primary_s))
662 		return PTR_ERR(primary_s);
663 
664 	primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
665 
666 	drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
667 		struct atmel_hlcdc_plane_state *ovl_state;
668 		struct drm_plane_state *ovl_s;
669 
670 		if (ovl == c_state->crtc->primary)
671 			continue;
672 
673 		ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
674 		if (IS_ERR(ovl_s))
675 			return PTR_ERR(ovl_s);
676 
677 		ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
678 
679 		if (!ovl_s->visible ||
680 		    !ovl_s->fb ||
681 		    ovl_s->fb->format->has_alpha ||
682 		    ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
683 			continue;
684 
685 		/* TODO: implement a smarter hidden area detection */
686 		if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
687 			continue;
688 
689 		disc_x = ovl_state->crtc_x;
690 		disc_y = ovl_state->crtc_y;
691 		disc_h = ovl_state->crtc_h;
692 		disc_w = ovl_state->crtc_w;
693 	}
694 
695 	primary_state->disc_x = disc_x;
696 	primary_state->disc_y = disc_y;
697 	primary_state->disc_w = disc_w;
698 	primary_state->disc_h = disc_h;
699 
700 	return 0;
701 }
702 
703 static void
704 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
705 				   struct atmel_hlcdc_plane_state *state)
706 {
707 	const struct atmel_hlcdc_layer_cfg_layout *layout;
708 
709 	layout = &plane->layer.desc->layout;
710 	if (!layout->disc_pos || !layout->disc_size)
711 		return;
712 
713 	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
714 				ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
715 							   state->disc_y));
716 
717 	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
718 				ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
719 							    state->disc_h));
720 }
721 
722 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
723 					  struct drm_atomic_state *state)
724 {
725 	struct drm_plane_state *s = drm_atomic_get_new_plane_state(state, p);
726 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
727 	struct atmel_hlcdc_plane_state *hstate =
728 				drm_plane_state_to_atmel_hlcdc_plane_state(s);
729 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
730 	struct drm_framebuffer *fb = hstate->base.fb;
731 	const struct drm_display_mode *mode;
732 	struct drm_crtc_state *crtc_state;
733 	int ret;
734 	int i;
735 
736 	if (!hstate->base.crtc || WARN_ON(!fb))
737 		return 0;
738 
739 	crtc_state = drm_atomic_get_new_crtc_state(state, s->crtc);
740 	mode = &crtc_state->adjusted_mode;
741 
742 	ret = drm_atomic_helper_check_plane_state(s, crtc_state,
743 						  (1 << 16) / 2048,
744 						  INT_MAX, true, true);
745 	if (ret || !s->visible)
746 		return ret;
747 
748 	hstate->src_x = s->src.x1;
749 	hstate->src_y = s->src.y1;
750 	hstate->src_w = drm_rect_width(&s->src);
751 	hstate->src_h = drm_rect_height(&s->src);
752 	hstate->crtc_x = s->dst.x1;
753 	hstate->crtc_y = s->dst.y1;
754 	hstate->crtc_w = drm_rect_width(&s->dst);
755 	hstate->crtc_h = drm_rect_height(&s->dst);
756 
757 	if ((hstate->src_x | hstate->src_y | hstate->src_w | hstate->src_h) &
758 	    SUBPIXEL_MASK)
759 		return -EINVAL;
760 
761 	hstate->src_x >>= 16;
762 	hstate->src_y >>= 16;
763 	hstate->src_w >>= 16;
764 	hstate->src_h >>= 16;
765 
766 	hstate->nplanes = fb->format->num_planes;
767 	if (hstate->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
768 		return -EINVAL;
769 
770 	for (i = 0; i < hstate->nplanes; i++) {
771 		unsigned int offset = 0;
772 		int xdiv = i ? fb->format->hsub : 1;
773 		int ydiv = i ? fb->format->vsub : 1;
774 
775 		hstate->bpp[i] = fb->format->cpp[i];
776 		if (!hstate->bpp[i])
777 			return -EINVAL;
778 
779 		switch (hstate->base.rotation & DRM_MODE_ROTATE_MASK) {
780 		case DRM_MODE_ROTATE_90:
781 			offset = (hstate->src_y / ydiv) *
782 				 fb->pitches[i];
783 			offset += ((hstate->src_x + hstate->src_w - 1) /
784 				   xdiv) * hstate->bpp[i];
785 			hstate->xstride[i] = -(((hstate->src_h - 1) / ydiv) *
786 					    fb->pitches[i]) -
787 					  (2 * hstate->bpp[i]);
788 			hstate->pstride[i] = fb->pitches[i] - hstate->bpp[i];
789 			break;
790 		case DRM_MODE_ROTATE_180:
791 			offset = ((hstate->src_y + hstate->src_h - 1) /
792 				  ydiv) * fb->pitches[i];
793 			offset += ((hstate->src_x + hstate->src_w - 1) /
794 				   xdiv) * hstate->bpp[i];
795 			hstate->xstride[i] = ((((hstate->src_w - 1) / xdiv) - 1) *
796 					   hstate->bpp[i]) - fb->pitches[i];
797 			hstate->pstride[i] = -2 * hstate->bpp[i];
798 			break;
799 		case DRM_MODE_ROTATE_270:
800 			offset = ((hstate->src_y + hstate->src_h - 1) /
801 				  ydiv) * fb->pitches[i];
802 			offset += (hstate->src_x / xdiv) * hstate->bpp[i];
803 			hstate->xstride[i] = ((hstate->src_h - 1) / ydiv) *
804 					  fb->pitches[i];
805 			hstate->pstride[i] = -fb->pitches[i] - hstate->bpp[i];
806 			break;
807 		case DRM_MODE_ROTATE_0:
808 		default:
809 			offset = (hstate->src_y / ydiv) * fb->pitches[i];
810 			offset += (hstate->src_x / xdiv) * hstate->bpp[i];
811 			hstate->xstride[i] = fb->pitches[i] -
812 					  ((hstate->src_w / xdiv) *
813 					   hstate->bpp[i]);
814 			hstate->pstride[i] = 0;
815 			break;
816 		}
817 
818 		hstate->offsets[i] = offset + fb->offsets[i];
819 	}
820 
821 	/*
822 	 * Swap width and size in case of 90 or 270 degrees rotation
823 	 */
824 	if (drm_rotation_90_or_270(hstate->base.rotation)) {
825 		swap(hstate->src_w, hstate->src_h);
826 	}
827 
828 	if (!desc->layout.size &&
829 	    (mode->hdisplay != hstate->crtc_w ||
830 	     mode->vdisplay != hstate->crtc_h))
831 		return -EINVAL;
832 
833 	if ((hstate->crtc_h != hstate->src_h || hstate->crtc_w != hstate->src_w) &&
834 	    (!desc->layout.memsize ||
835 	     hstate->base.fb->format->has_alpha))
836 		return -EINVAL;
837 
838 	return 0;
839 }
840 
841 static void atmel_hlcdc_atomic_disable(struct atmel_hlcdc_plane *plane,
842 				       struct atmel_hlcdc_dc *dc)
843 {
844 	/* Disable interrupts */
845 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
846 				    0xffffffff);
847 
848 	/* Disable the layer */
849 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
850 				    ATMEL_HLCDC_LAYER_RST |
851 				    ATMEL_HLCDC_LAYER_A2Q |
852 				    ATMEL_HLCDC_LAYER_UPDATE);
853 
854 	/* Clear all pending interrupts */
855 	atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
856 }
857 
858 static void atmel_xlcdc_atomic_disable(struct atmel_hlcdc_plane *plane,
859 				       struct atmel_hlcdc_dc *dc)
860 {
861 	/* Disable interrupts */
862 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_IDR,
863 				    0xffffffff);
864 
865 	/* Disable the layer */
866 	atmel_hlcdc_layer_write_reg(&plane->layer,
867 				    ATMEL_XLCDC_LAYER_ENR, 0);
868 
869 	/*
870 	 * Updating XLCDC_xxxCFGx, XLCDC_xxxFBA and XLCDC_xxxEN,
871 	 * (where xxx indicates each layer) requires writing one to the
872 	 * Update Attribute field for each layer in LCDC_ATTRE register for SAM9X7.
873 	 */
874 	regmap_write(dc->hlcdc->regmap, ATMEL_XLCDC_ATTRE, ATMEL_XLCDC_BASE_UPDATE |
875 		     ATMEL_XLCDC_OVR1_UPDATE | ATMEL_XLCDC_OVR3_UPDATE |
876 		     ATMEL_XLCDC_HEO_UPDATE);
877 
878 	/* Clear all pending interrupts */
879 	atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_XLCDC_LAYER_ISR);
880 }
881 
882 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
883 					     struct drm_atomic_state *state)
884 {
885 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
886 	struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
887 
888 	dc->desc->ops->lcdc_atomic_disable(plane, dc);
889 }
890 
891 static void atmel_hlcdc_atomic_update(struct atmel_hlcdc_plane *plane,
892 				      struct atmel_hlcdc_dc *dc)
893 {
894 	u32 sr;
895 
896 	/* Enable the overrun interrupts. */
897 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
898 				    ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
899 				    ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
900 				    ATMEL_HLCDC_LAYER_OVR_IRQ(2));
901 
902 	/* Apply the new config at the next SOF event. */
903 	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
904 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
905 				    ATMEL_HLCDC_LAYER_UPDATE |
906 				    (sr & ATMEL_HLCDC_LAYER_EN ?
907 				    ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
908 }
909 
910 static void atmel_xlcdc_atomic_update(struct atmel_hlcdc_plane *plane,
911 				      struct atmel_hlcdc_dc *dc)
912 {
913 	/* Enable the overrun interrupts. */
914 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_IER,
915 				    ATMEL_XLCDC_LAYER_OVR_IRQ(0) |
916 				    ATMEL_XLCDC_LAYER_OVR_IRQ(1) |
917 				    ATMEL_XLCDC_LAYER_OVR_IRQ(2));
918 
919 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_ENR,
920 				    ATMEL_XLCDC_LAYER_EN);
921 
922 	/*
923 	 * Updating XLCDC_xxxCFGx, XLCDC_xxxFBA and XLCDC_xxxEN,
924 	 * (where xxx indicates each layer) requires writing one to the
925 	 * Update Attribute field for each layer in LCDC_ATTRE register for SAM9X7.
926 	 */
927 	regmap_write(dc->hlcdc->regmap, ATMEL_XLCDC_ATTRE, ATMEL_XLCDC_BASE_UPDATE |
928 		     ATMEL_XLCDC_OVR1_UPDATE | ATMEL_XLCDC_OVR3_UPDATE |
929 		     ATMEL_XLCDC_HEO_UPDATE);
930 }
931 
932 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
933 					    struct drm_atomic_state *state)
934 {
935 	struct drm_plane_state *new_s = drm_atomic_get_new_plane_state(state,
936 								       p);
937 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
938 	struct atmel_hlcdc_plane_state *hstate =
939 			drm_plane_state_to_atmel_hlcdc_plane_state(new_s);
940 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
941 
942 	if (!new_s->crtc || !new_s->fb)
943 		return;
944 
945 	if (!hstate->base.visible) {
946 		atmel_hlcdc_plane_atomic_disable(p, state);
947 		return;
948 	}
949 
950 	atmel_hlcdc_plane_update_pos_and_size(plane, hstate);
951 	dc->desc->ops->lcdc_update_general_settings(plane, hstate);
952 	atmel_hlcdc_plane_update_format(plane, hstate);
953 	atmel_hlcdc_plane_update_clut(plane, hstate);
954 	atmel_hlcdc_plane_update_buffers(plane, hstate);
955 	atmel_hlcdc_plane_update_disc_area(plane, hstate);
956 
957 	dc->desc->ops->lcdc_atomic_update(plane, dc);
958 }
959 
960 static void atmel_hlcdc_csc_init(struct atmel_hlcdc_plane *plane,
961 				 const struct atmel_hlcdc_layer_desc *desc)
962 {
963 	/*
964 	 * TODO: declare a "yuv-to-rgb-conv-factors" property to let
965 	 * userspace modify these factors (using a BLOB property ?).
966 	 */
967 	static const u32 hlcdc_csc_coeffs[] = {
968 		0x4c900091,
969 		0x7a5f5090,
970 		0x40040890
971 	};
972 
973 	for (int i = 0; i < ARRAY_SIZE(hlcdc_csc_coeffs); i++) {
974 		atmel_hlcdc_layer_write_cfg(&plane->layer,
975 					    desc->layout.csc + i,
976 					    hlcdc_csc_coeffs[i]);
977 	}
978 }
979 
980 static void atmel_xlcdc_csc_init(struct atmel_hlcdc_plane *plane,
981 				 const struct atmel_hlcdc_layer_desc *desc)
982 {
983 	/*
984 	 * yuv-to-rgb-conv-factors are now defined from LCDC_HEOCFG16 to
985 	 * LCDC_HEOCFG21 registers in SAM9X7.
986 	 */
987 	static const u32 xlcdc_csc_coeffs[] = {
988 		0x00000488,
989 		0x00000648,
990 		0x1EA00480,
991 		0x00001D28,
992 		0x08100480,
993 		0x00000000,
994 		0x00000007
995 	};
996 
997 	for (int i = 0; i < ARRAY_SIZE(xlcdc_csc_coeffs); i++) {
998 		atmel_hlcdc_layer_write_cfg(&plane->layer,
999 					    desc->layout.csc + i,
1000 					    xlcdc_csc_coeffs[i]);
1001 	}
1002 
1003 	if (desc->layout.vxs_config && desc->layout.hxs_config) {
1004 		/*
1005 		 * Updating vxs.config and hxs.config fixes the
1006 		 * Green Color Issue in SAM9X7 EGT Video Player App
1007 		 */
1008 		atmel_hlcdc_layer_write_cfg(&plane->layer,
1009 					    desc->layout.vxs_config,
1010 					    ATMEL_XLCDC_LAYER_VXSYCFG_ONE |
1011 					    ATMEL_XLCDC_LAYER_VXSYTAP2_ENABLE |
1012 					    ATMEL_XLCDC_LAYER_VXSCCFG_ONE |
1013 					    ATMEL_XLCDC_LAYER_VXSCTAP2_ENABLE);
1014 
1015 		atmel_hlcdc_layer_write_cfg(&plane->layer,
1016 					    desc->layout.hxs_config,
1017 					    ATMEL_XLCDC_LAYER_HXSYCFG_ONE |
1018 					    ATMEL_XLCDC_LAYER_HXSYTAP2_ENABLE |
1019 					    ATMEL_XLCDC_LAYER_HXSCCFG_ONE |
1020 					    ATMEL_XLCDC_LAYER_HXSCTAP2_ENABLE);
1021 	}
1022 }
1023 
1024 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
1025 {
1026 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
1027 	struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
1028 
1029 	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
1030 	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
1031 		int ret;
1032 
1033 		ret = drm_plane_create_alpha_property(&plane->base);
1034 		if (ret)
1035 			return ret;
1036 	}
1037 
1038 	if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
1039 		int ret;
1040 
1041 		ret = drm_plane_create_rotation_property(&plane->base,
1042 							 DRM_MODE_ROTATE_0,
1043 							 DRM_MODE_ROTATE_0 |
1044 							 DRM_MODE_ROTATE_90 |
1045 							 DRM_MODE_ROTATE_180 |
1046 							 DRM_MODE_ROTATE_270);
1047 		if (ret)
1048 			return ret;
1049 	}
1050 
1051 	if (desc->layout.csc)
1052 		dc->desc->ops->lcdc_csc_init(plane, desc);
1053 
1054 	return 0;
1055 }
1056 
1057 static void atmel_hlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
1058 				const struct atmel_hlcdc_layer_desc *desc)
1059 {
1060 	u32 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
1061 
1062 	/*
1063 	 * There's not much we can do in case of overrun except informing
1064 	 * the user. However, we are in interrupt context here, hence the
1065 	 * use of dev_dbg().
1066 	 */
1067 	if (isr &
1068 	    (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
1069 	     ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
1070 		drm_dbg(plane->base.dev, "overrun on plane %s\n",
1071 			desc->name);
1072 }
1073 
1074 static void atmel_xlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
1075 				const struct atmel_hlcdc_layer_desc *desc)
1076 {
1077 	u32 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_XLCDC_LAYER_ISR);
1078 
1079 	/*
1080 	 * There's not much we can do in case of overrun except informing
1081 	 * the user. However, we are in interrupt context here, hence the
1082 	 * use of dev_dbg().
1083 	 */
1084 	if (isr &
1085 	    (ATMEL_XLCDC_LAYER_OVR_IRQ(0) | ATMEL_XLCDC_LAYER_OVR_IRQ(1) |
1086 	     ATMEL_XLCDC_LAYER_OVR_IRQ(2)))
1087 		drm_dbg(plane->base.dev, "overrun on plane %s\n",
1088 			desc->name);
1089 }
1090 
1091 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
1092 {
1093 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
1094 	struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
1095 
1096 	dc->desc->ops->lcdc_irq_dbg(plane, desc);
1097 }
1098 
1099 const struct atmel_lcdc_dc_ops atmel_hlcdc_ops = {
1100 	.plane_setup_scaler = atmel_hlcdc_plane_setup_scaler,
1101 	.lcdc_update_buffers = atmel_hlcdc_update_buffers,
1102 	.lcdc_atomic_disable = atmel_hlcdc_atomic_disable,
1103 	.lcdc_update_general_settings = atmel_hlcdc_plane_update_general_settings,
1104 	.lcdc_atomic_update = atmel_hlcdc_atomic_update,
1105 	.lcdc_csc_init = atmel_hlcdc_csc_init,
1106 	.lcdc_irq_dbg = atmel_hlcdc_irq_dbg,
1107 };
1108 
1109 const struct atmel_lcdc_dc_ops atmel_xlcdc_ops = {
1110 	.plane_setup_scaler = atmel_xlcdc_plane_setup_scaler,
1111 	.lcdc_update_buffers = atmel_xlcdc_update_buffers,
1112 	.lcdc_atomic_disable = atmel_xlcdc_atomic_disable,
1113 	.lcdc_update_general_settings = atmel_xlcdc_plane_update_general_settings,
1114 	.lcdc_atomic_update = atmel_xlcdc_atomic_update,
1115 	.lcdc_csc_init = atmel_xlcdc_csc_init,
1116 	.lcdc_irq_dbg = atmel_xlcdc_irq_dbg,
1117 };
1118 
1119 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
1120 	.atomic_check = atmel_hlcdc_plane_atomic_check,
1121 	.atomic_update = atmel_hlcdc_plane_atomic_update,
1122 	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
1123 };
1124 
1125 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
1126 					 struct atmel_hlcdc_plane_state *state)
1127 {
1128 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
1129 	int i;
1130 
1131 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
1132 		struct atmel_hlcdc_dma_channel_dscr *dscr;
1133 		dma_addr_t dscr_dma;
1134 
1135 		dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
1136 		if (!dscr)
1137 			goto err;
1138 
1139 		dscr->addr = 0;
1140 		dscr->next = dscr_dma;
1141 		dscr->self = dscr_dma;
1142 		dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
1143 
1144 		state->dscrs[i] = dscr;
1145 	}
1146 
1147 	return 0;
1148 
1149 err:
1150 	for (i--; i >= 0; i--) {
1151 		dma_pool_free(dc->dscrpool, state->dscrs[i],
1152 			      state->dscrs[i]->self);
1153 	}
1154 
1155 	return -ENOMEM;
1156 }
1157 
1158 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
1159 {
1160 	struct atmel_hlcdc_plane_state *state;
1161 
1162 	if (p->state) {
1163 		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
1164 
1165 		if (state->base.fb)
1166 			drm_framebuffer_put(state->base.fb);
1167 
1168 		kfree(state);
1169 		p->state = NULL;
1170 	}
1171 
1172 	state = kzalloc(sizeof(*state), GFP_KERNEL);
1173 	if (state) {
1174 		if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
1175 			kfree(state);
1176 			drm_err(p->dev,
1177 				"Failed to allocate initial plane state\n");
1178 			return;
1179 		}
1180 		__drm_atomic_helper_plane_reset(p, &state->base);
1181 	}
1182 }
1183 
1184 static struct drm_plane_state *
1185 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
1186 {
1187 	struct atmel_hlcdc_plane_state *state =
1188 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
1189 	struct atmel_hlcdc_plane_state *copy;
1190 
1191 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
1192 	if (!copy)
1193 		return NULL;
1194 
1195 	if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
1196 		kfree(copy);
1197 		return NULL;
1198 	}
1199 
1200 	if (copy->base.fb)
1201 		drm_framebuffer_get(copy->base.fb);
1202 
1203 	return &copy->base;
1204 }
1205 
1206 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
1207 						   struct drm_plane_state *s)
1208 {
1209 	struct atmel_hlcdc_plane_state *state =
1210 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
1211 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
1212 	int i;
1213 
1214 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
1215 		dma_pool_free(dc->dscrpool, state->dscrs[i],
1216 			      state->dscrs[i]->self);
1217 	}
1218 
1219 	if (s->fb)
1220 		drm_framebuffer_put(s->fb);
1221 
1222 	kfree(state);
1223 }
1224 
1225 static const struct drm_plane_funcs layer_plane_funcs = {
1226 	.update_plane = drm_atomic_helper_update_plane,
1227 	.disable_plane = drm_atomic_helper_disable_plane,
1228 	.destroy = drm_plane_cleanup,
1229 	.reset = atmel_hlcdc_plane_reset,
1230 	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
1231 	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
1232 };
1233 
1234 static int atmel_hlcdc_plane_create(struct drm_device *dev,
1235 				    const struct atmel_hlcdc_layer_desc *desc)
1236 {
1237 	struct atmel_hlcdc_dc *dc = dev->dev_private;
1238 	struct atmel_hlcdc_plane *plane;
1239 	enum drm_plane_type type;
1240 	int ret;
1241 
1242 	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
1243 	if (!plane)
1244 		return -ENOMEM;
1245 
1246 	atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
1247 
1248 	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1249 		type = DRM_PLANE_TYPE_PRIMARY;
1250 	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1251 		type = DRM_PLANE_TYPE_CURSOR;
1252 	else
1253 		type = DRM_PLANE_TYPE_OVERLAY;
1254 
1255 	ret = drm_universal_plane_init(dev, &plane->base, 0,
1256 				       &layer_plane_funcs,
1257 				       desc->formats->formats,
1258 				       desc->formats->nformats,
1259 				       NULL, type, NULL);
1260 	if (ret)
1261 		return ret;
1262 
1263 	drm_plane_helper_add(&plane->base,
1264 			     &atmel_hlcdc_layer_plane_helper_funcs);
1265 
1266 	/* Set default property values*/
1267 	ret = atmel_hlcdc_plane_init_properties(plane);
1268 	if (ret)
1269 		return ret;
1270 
1271 	dc->layers[desc->id] = &plane->layer;
1272 
1273 	return 0;
1274 }
1275 
1276 int atmel_hlcdc_create_planes(struct drm_device *dev)
1277 {
1278 	struct atmel_hlcdc_dc *dc = dev->dev_private;
1279 	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1280 	int nlayers = dc->desc->nlayers;
1281 	int i, ret;
1282 
1283 	dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1284 				sizeof(struct atmel_hlcdc_dma_channel_dscr),
1285 				sizeof(u64), 0);
1286 	if (!dc->dscrpool)
1287 		return -ENOMEM;
1288 
1289 	for (i = 0; i < nlayers; i++) {
1290 		if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1291 		    descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1292 		    descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1293 			continue;
1294 
1295 		ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1296 		if (ret)
1297 			return ret;
1298 	}
1299 
1300 	return 0;
1301 }
1302