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