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