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