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