1 /*
2  * Copyright (C) 2014 Free Electrons
3  * Copyright (C) 2014 Atmel
4  *
5  * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "atmel_hlcdc_dc.h"
21 
22 /**
23  * 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  * @alpha: alpha blending of the plane
35  * @bpp: bytes per pixel deduced from pixel_format
36  * @offsets: offsets to apply to the GEM buffers
37  * @xstride: value to add to the pixel pointer between each line
38  * @pstride: value to add to the pixel pointer between each pixel
39  * @nplanes: number of planes (deduced from pixel_format)
40  * @prepared: plane update has been prepared
41  */
42 struct atmel_hlcdc_plane_state {
43 	struct drm_plane_state base;
44 	int crtc_x;
45 	int crtc_y;
46 	unsigned int crtc_w;
47 	unsigned int crtc_h;
48 	uint32_t src_x;
49 	uint32_t src_y;
50 	uint32_t src_w;
51 	uint32_t src_h;
52 
53 	u8 alpha;
54 
55 	bool disc_updated;
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_MAX_PLANES];
66 	unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
67 	int xstride[ATMEL_HLCDC_MAX_PLANES];
68 	int pstride[ATMEL_HLCDC_MAX_PLANES];
69 	int nplanes;
70 	bool prepared;
71 };
72 
73 static inline struct atmel_hlcdc_plane_state *
74 drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
75 {
76 	return container_of(s, struct atmel_hlcdc_plane_state, base);
77 }
78 
79 #define SUBPIXEL_MASK			0xffff
80 
81 static uint32_t rgb_formats[] = {
82 	DRM_FORMAT_XRGB4444,
83 	DRM_FORMAT_ARGB4444,
84 	DRM_FORMAT_RGBA4444,
85 	DRM_FORMAT_ARGB1555,
86 	DRM_FORMAT_RGB565,
87 	DRM_FORMAT_RGB888,
88 	DRM_FORMAT_XRGB8888,
89 	DRM_FORMAT_ARGB8888,
90 	DRM_FORMAT_RGBA8888,
91 };
92 
93 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
94 	.formats = rgb_formats,
95 	.nformats = ARRAY_SIZE(rgb_formats),
96 };
97 
98 static uint32_t rgb_and_yuv_formats[] = {
99 	DRM_FORMAT_XRGB4444,
100 	DRM_FORMAT_ARGB4444,
101 	DRM_FORMAT_RGBA4444,
102 	DRM_FORMAT_ARGB1555,
103 	DRM_FORMAT_RGB565,
104 	DRM_FORMAT_RGB888,
105 	DRM_FORMAT_XRGB8888,
106 	DRM_FORMAT_ARGB8888,
107 	DRM_FORMAT_RGBA8888,
108 	DRM_FORMAT_AYUV,
109 	DRM_FORMAT_YUYV,
110 	DRM_FORMAT_UYVY,
111 	DRM_FORMAT_YVYU,
112 	DRM_FORMAT_VYUY,
113 	DRM_FORMAT_NV21,
114 	DRM_FORMAT_NV61,
115 	DRM_FORMAT_YUV422,
116 	DRM_FORMAT_YUV420,
117 };
118 
119 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
120 	.formats = rgb_and_yuv_formats,
121 	.nformats = ARRAY_SIZE(rgb_and_yuv_formats),
122 };
123 
124 static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
125 {
126 	switch (format) {
127 	case DRM_FORMAT_XRGB4444:
128 		*mode = ATMEL_HLCDC_XRGB4444_MODE;
129 		break;
130 	case DRM_FORMAT_ARGB4444:
131 		*mode = ATMEL_HLCDC_ARGB4444_MODE;
132 		break;
133 	case DRM_FORMAT_RGBA4444:
134 		*mode = ATMEL_HLCDC_RGBA4444_MODE;
135 		break;
136 	case DRM_FORMAT_RGB565:
137 		*mode = ATMEL_HLCDC_RGB565_MODE;
138 		break;
139 	case DRM_FORMAT_RGB888:
140 		*mode = ATMEL_HLCDC_RGB888_MODE;
141 		break;
142 	case DRM_FORMAT_ARGB1555:
143 		*mode = ATMEL_HLCDC_ARGB1555_MODE;
144 		break;
145 	case DRM_FORMAT_XRGB8888:
146 		*mode = ATMEL_HLCDC_XRGB8888_MODE;
147 		break;
148 	case DRM_FORMAT_ARGB8888:
149 		*mode = ATMEL_HLCDC_ARGB8888_MODE;
150 		break;
151 	case DRM_FORMAT_RGBA8888:
152 		*mode = ATMEL_HLCDC_RGBA8888_MODE;
153 		break;
154 	case DRM_FORMAT_AYUV:
155 		*mode = ATMEL_HLCDC_AYUV_MODE;
156 		break;
157 	case DRM_FORMAT_YUYV:
158 		*mode = ATMEL_HLCDC_YUYV_MODE;
159 		break;
160 	case DRM_FORMAT_UYVY:
161 		*mode = ATMEL_HLCDC_UYVY_MODE;
162 		break;
163 	case DRM_FORMAT_YVYU:
164 		*mode = ATMEL_HLCDC_YVYU_MODE;
165 		break;
166 	case DRM_FORMAT_VYUY:
167 		*mode = ATMEL_HLCDC_VYUY_MODE;
168 		break;
169 	case DRM_FORMAT_NV21:
170 		*mode = ATMEL_HLCDC_NV21_MODE;
171 		break;
172 	case DRM_FORMAT_NV61:
173 		*mode = ATMEL_HLCDC_NV61_MODE;
174 		break;
175 	case DRM_FORMAT_YUV420:
176 		*mode = ATMEL_HLCDC_YUV420_MODE;
177 		break;
178 	case DRM_FORMAT_YUV422:
179 		*mode = ATMEL_HLCDC_YUV422_MODE;
180 		break;
181 	default:
182 		return -ENOTSUPP;
183 	}
184 
185 	return 0;
186 }
187 
188 static bool atmel_hlcdc_format_embeds_alpha(u32 format)
189 {
190 	int i;
191 
192 	for (i = 0; i < sizeof(format); i++) {
193 		char tmp = (format >> (8 * i)) & 0xff;
194 
195 		if (tmp == 'A')
196 			return true;
197 	}
198 
199 	return false;
200 }
201 
202 static u32 heo_downscaling_xcoef[] = {
203 	0x11343311,
204 	0x000000f7,
205 	0x1635300c,
206 	0x000000f9,
207 	0x1b362c08,
208 	0x000000fb,
209 	0x1f372804,
210 	0x000000fe,
211 	0x24382400,
212 	0x00000000,
213 	0x28371ffe,
214 	0x00000004,
215 	0x2c361bfb,
216 	0x00000008,
217 	0x303516f9,
218 	0x0000000c,
219 };
220 
221 static u32 heo_downscaling_ycoef[] = {
222 	0x00123737,
223 	0x00173732,
224 	0x001b382d,
225 	0x001f3928,
226 	0x00243824,
227 	0x0028391f,
228 	0x002d381b,
229 	0x00323717,
230 };
231 
232 static u32 heo_upscaling_xcoef[] = {
233 	0xf74949f7,
234 	0x00000000,
235 	0xf55f33fb,
236 	0x000000fe,
237 	0xf5701efe,
238 	0x000000ff,
239 	0xf87c0dff,
240 	0x00000000,
241 	0x00800000,
242 	0x00000000,
243 	0x0d7cf800,
244 	0x000000ff,
245 	0x1e70f5ff,
246 	0x000000fe,
247 	0x335ff5fe,
248 	0x000000fb,
249 };
250 
251 static u32 heo_upscaling_ycoef[] = {
252 	0x00004040,
253 	0x00075920,
254 	0x00056f0c,
255 	0x00027b03,
256 	0x00008000,
257 	0x00037b02,
258 	0x000c6f05,
259 	0x00205907,
260 };
261 
262 static void
263 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
264 				      struct atmel_hlcdc_plane_state *state)
265 {
266 	const struct atmel_hlcdc_layer_cfg_layout *layout =
267 						&plane->layer.desc->layout;
268 
269 	if (layout->size)
270 		atmel_hlcdc_layer_update_cfg(&plane->layer,
271 					     layout->size,
272 					     0xffffffff,
273 					     (state->crtc_w - 1) |
274 					     ((state->crtc_h - 1) << 16));
275 
276 	if (layout->memsize)
277 		atmel_hlcdc_layer_update_cfg(&plane->layer,
278 					     layout->memsize,
279 					     0xffffffff,
280 					     (state->src_w - 1) |
281 					     ((state->src_h - 1) << 16));
282 
283 	if (layout->pos)
284 		atmel_hlcdc_layer_update_cfg(&plane->layer,
285 					     layout->pos,
286 					     0xffffffff,
287 					     state->crtc_x |
288 					     (state->crtc_y  << 16));
289 
290 	/* TODO: rework the rescaling part */
291 	if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
292 		u32 factor_reg = 0;
293 
294 		if (state->crtc_w != state->src_w) {
295 			int i;
296 			u32 factor;
297 			u32 *coeff_tab = heo_upscaling_xcoef;
298 			u32 max_memsize;
299 
300 			if (state->crtc_w < state->src_w)
301 				coeff_tab = heo_downscaling_xcoef;
302 			for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
303 				atmel_hlcdc_layer_update_cfg(&plane->layer,
304 							     17 + i,
305 							     0xffffffff,
306 							     coeff_tab[i]);
307 			factor = ((8 * 256 * state->src_w) - (256 * 4)) /
308 				 state->crtc_w;
309 			factor++;
310 			max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
311 				      2048;
312 			if (max_memsize > state->src_w)
313 				factor--;
314 			factor_reg |= factor | 0x80000000;
315 		}
316 
317 		if (state->crtc_h != state->src_h) {
318 			int i;
319 			u32 factor;
320 			u32 *coeff_tab = heo_upscaling_ycoef;
321 			u32 max_memsize;
322 
323 			if (state->crtc_w < state->src_w)
324 				coeff_tab = heo_downscaling_ycoef;
325 			for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
326 				atmel_hlcdc_layer_update_cfg(&plane->layer,
327 							     33 + i,
328 							     0xffffffff,
329 							     coeff_tab[i]);
330 			factor = ((8 * 256 * state->src_w) - (256 * 4)) /
331 				 state->crtc_w;
332 			factor++;
333 			max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
334 				      2048;
335 			if (max_memsize > state->src_w)
336 				factor--;
337 			factor_reg |= (factor << 16) | 0x80000000;
338 		}
339 
340 		atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
341 					     factor_reg);
342 	} else {
343 		atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff, 0);
344 	}
345 }
346 
347 static void
348 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
349 					struct atmel_hlcdc_plane_state *state)
350 {
351 	const struct atmel_hlcdc_layer_cfg_layout *layout =
352 						&plane->layer.desc->layout;
353 	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
354 
355 	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
356 		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
357 		       ATMEL_HLCDC_LAYER_ITER;
358 
359 		if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
360 			cfg |= ATMEL_HLCDC_LAYER_LAEN;
361 		else
362 			cfg |= ATMEL_HLCDC_LAYER_GAEN |
363 			       ATMEL_HLCDC_LAYER_GA(state->alpha);
364 	}
365 
366 	atmel_hlcdc_layer_update_cfg(&plane->layer,
367 				     ATMEL_HLCDC_LAYER_DMA_CFG_ID,
368 				     ATMEL_HLCDC_LAYER_DMA_BLEN_MASK |
369 				     ATMEL_HLCDC_LAYER_DMA_SIF,
370 				     ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 |
371 				     state->ahb_id);
372 
373 	atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
374 				     ATMEL_HLCDC_LAYER_ITER2BL |
375 				     ATMEL_HLCDC_LAYER_ITER |
376 				     ATMEL_HLCDC_LAYER_GAEN |
377 				     ATMEL_HLCDC_LAYER_GA_MASK |
378 				     ATMEL_HLCDC_LAYER_LAEN |
379 				     ATMEL_HLCDC_LAYER_OVR |
380 				     ATMEL_HLCDC_LAYER_DMA, cfg);
381 }
382 
383 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
384 					struct atmel_hlcdc_plane_state *state)
385 {
386 	u32 cfg;
387 	int ret;
388 
389 	ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
390 					       &cfg);
391 	if (ret)
392 		return;
393 
394 	if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 ||
395 	     state->base.fb->pixel_format == DRM_FORMAT_NV61) &&
396 	    (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
397 		cfg |= ATMEL_HLCDC_YUV422ROT;
398 
399 	atmel_hlcdc_layer_update_cfg(&plane->layer,
400 				     ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
401 				     0xffffffff,
402 				     cfg);
403 
404 	/*
405 	 * Rotation optimization is not working on RGB888 (rotation is still
406 	 * working but without any optimization).
407 	 */
408 	if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
409 		cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
410 	else
411 		cfg = 0;
412 
413 	atmel_hlcdc_layer_update_cfg(&plane->layer,
414 				     ATMEL_HLCDC_LAYER_DMA_CFG_ID,
415 				     ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
416 }
417 
418 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
419 					struct atmel_hlcdc_plane_state *state)
420 {
421 	struct atmel_hlcdc_layer *layer = &plane->layer;
422 	const struct atmel_hlcdc_layer_cfg_layout *layout =
423 							&layer->desc->layout;
424 	int i;
425 
426 	atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
427 					state->offsets);
428 
429 	for (i = 0; i < state->nplanes; i++) {
430 		if (layout->xstride[i]) {
431 			atmel_hlcdc_layer_update_cfg(&plane->layer,
432 						layout->xstride[i],
433 						0xffffffff,
434 						state->xstride[i]);
435 		}
436 
437 		if (layout->pstride[i]) {
438 			atmel_hlcdc_layer_update_cfg(&plane->layer,
439 						layout->pstride[i],
440 						0xffffffff,
441 						state->pstride[i]);
442 		}
443 	}
444 }
445 
446 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
447 {
448 	unsigned int ahb_load[2] = { };
449 	struct drm_plane *plane;
450 
451 	drm_atomic_crtc_state_for_each_plane(plane, c_state) {
452 		struct atmel_hlcdc_plane_state *plane_state;
453 		struct drm_plane_state *plane_s;
454 		unsigned int pixels, load = 0;
455 		int i;
456 
457 		plane_s = drm_atomic_get_plane_state(c_state->state, plane);
458 		if (IS_ERR(plane_s))
459 			return PTR_ERR(plane_s);
460 
461 		plane_state =
462 			drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
463 
464 		pixels = (plane_state->src_w * plane_state->src_h) -
465 			 (plane_state->disc_w * plane_state->disc_h);
466 
467 		for (i = 0; i < plane_state->nplanes; i++)
468 			load += pixels * plane_state->bpp[i];
469 
470 		if (ahb_load[0] <= ahb_load[1])
471 			plane_state->ahb_id = 0;
472 		else
473 			plane_state->ahb_id = 1;
474 
475 		ahb_load[plane_state->ahb_id] += load;
476 	}
477 
478 	return 0;
479 }
480 
481 int
482 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
483 {
484 	int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
485 	const struct atmel_hlcdc_layer_cfg_layout *layout;
486 	struct atmel_hlcdc_plane_state *primary_state;
487 	struct drm_plane_state *primary_s;
488 	struct atmel_hlcdc_plane *primary;
489 	struct drm_plane *ovl;
490 
491 	primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
492 	layout = &primary->layer.desc->layout;
493 	if (!layout->disc_pos || !layout->disc_size)
494 		return 0;
495 
496 	primary_s = drm_atomic_get_plane_state(c_state->state,
497 					       &primary->base);
498 	if (IS_ERR(primary_s))
499 		return PTR_ERR(primary_s);
500 
501 	primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
502 
503 	drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
504 		struct atmel_hlcdc_plane_state *ovl_state;
505 		struct drm_plane_state *ovl_s;
506 
507 		if (ovl == c_state->crtc->primary)
508 			continue;
509 
510 		ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
511 		if (IS_ERR(ovl_s))
512 			return PTR_ERR(ovl_s);
513 
514 		ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
515 
516 		if (!ovl_s->fb ||
517 		    atmel_hlcdc_format_embeds_alpha(ovl_s->fb->pixel_format) ||
518 		    ovl_state->alpha != 255)
519 			continue;
520 
521 		/* TODO: implement a smarter hidden area detection */
522 		if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
523 			continue;
524 
525 		disc_x = ovl_state->crtc_x;
526 		disc_y = ovl_state->crtc_y;
527 		disc_h = ovl_state->crtc_h;
528 		disc_w = ovl_state->crtc_w;
529 	}
530 
531 	if (disc_x == primary_state->disc_x &&
532 	    disc_y == primary_state->disc_y &&
533 	    disc_w == primary_state->disc_w &&
534 	    disc_h == primary_state->disc_h)
535 		return 0;
536 
537 
538 	primary_state->disc_x = disc_x;
539 	primary_state->disc_y = disc_y;
540 	primary_state->disc_w = disc_w;
541 	primary_state->disc_h = disc_h;
542 	primary_state->disc_updated = true;
543 
544 	return 0;
545 }
546 
547 static void
548 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
549 				   struct atmel_hlcdc_plane_state *state)
550 {
551 	const struct atmel_hlcdc_layer_cfg_layout *layout =
552 						&plane->layer.desc->layout;
553 	int disc_surface = 0;
554 
555 	if (!state->disc_updated)
556 		return;
557 
558 	disc_surface = state->disc_h * state->disc_w;
559 
560 	atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
561 				ATMEL_HLCDC_LAYER_DISCEN,
562 				disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0);
563 
564 	if (!disc_surface)
565 		return;
566 
567 	atmel_hlcdc_layer_update_cfg(&plane->layer,
568 				     layout->disc_pos,
569 				     0xffffffff,
570 				     state->disc_x | (state->disc_y << 16));
571 
572 	atmel_hlcdc_layer_update_cfg(&plane->layer,
573 				     layout->disc_size,
574 				     0xffffffff,
575 				     (state->disc_w - 1) |
576 				     ((state->disc_h - 1) << 16));
577 }
578 
579 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
580 					  struct drm_plane_state *s)
581 {
582 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
583 	struct atmel_hlcdc_plane_state *state =
584 				drm_plane_state_to_atmel_hlcdc_plane_state(s);
585 	const struct atmel_hlcdc_layer_cfg_layout *layout =
586 						&plane->layer.desc->layout;
587 	struct drm_framebuffer *fb = state->base.fb;
588 	const struct drm_display_mode *mode;
589 	struct drm_crtc_state *crtc_state;
590 	unsigned int patched_crtc_w;
591 	unsigned int patched_crtc_h;
592 	unsigned int patched_src_w;
593 	unsigned int patched_src_h;
594 	unsigned int tmp;
595 	int x_offset = 0;
596 	int y_offset = 0;
597 	int hsub = 1;
598 	int vsub = 1;
599 	int i;
600 
601 	if (!state->base.crtc || !fb)
602 		return 0;
603 
604 	crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
605 	mode = &crtc_state->adjusted_mode;
606 
607 	state->src_x = s->src_x;
608 	state->src_y = s->src_y;
609 	state->src_h = s->src_h;
610 	state->src_w = s->src_w;
611 	state->crtc_x = s->crtc_x;
612 	state->crtc_y = s->crtc_y;
613 	state->crtc_h = s->crtc_h;
614 	state->crtc_w = s->crtc_w;
615 	if ((state->src_x | state->src_y | state->src_w | state->src_h) &
616 	    SUBPIXEL_MASK)
617 		return -EINVAL;
618 
619 	state->src_x >>= 16;
620 	state->src_y >>= 16;
621 	state->src_w >>= 16;
622 	state->src_h >>= 16;
623 
624 	state->nplanes = drm_format_num_planes(fb->pixel_format);
625 	if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
626 		return -EINVAL;
627 
628 	/*
629 	 * Swap width and size in case of 90 or 270 degrees rotation
630 	 */
631 	if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
632 		tmp = state->crtc_w;
633 		state->crtc_w = state->crtc_h;
634 		state->crtc_h = tmp;
635 		tmp = state->src_w;
636 		state->src_w = state->src_h;
637 		state->src_h = tmp;
638 	}
639 
640 	if (state->crtc_x + state->crtc_w > mode->hdisplay)
641 		patched_crtc_w = mode->hdisplay - state->crtc_x;
642 	else
643 		patched_crtc_w = state->crtc_w;
644 
645 	if (state->crtc_x < 0) {
646 		patched_crtc_w += state->crtc_x;
647 		x_offset = -state->crtc_x;
648 		state->crtc_x = 0;
649 	}
650 
651 	if (state->crtc_y + state->crtc_h > mode->vdisplay)
652 		patched_crtc_h = mode->vdisplay - state->crtc_y;
653 	else
654 		patched_crtc_h = state->crtc_h;
655 
656 	if (state->crtc_y < 0) {
657 		patched_crtc_h += state->crtc_y;
658 		y_offset = -state->crtc_y;
659 		state->crtc_y = 0;
660 	}
661 
662 	patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
663 					  state->crtc_w);
664 	patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
665 					  state->crtc_h);
666 
667 	hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
668 	vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
669 
670 	for (i = 0; i < state->nplanes; i++) {
671 		unsigned int offset = 0;
672 		int xdiv = i ? hsub : 1;
673 		int ydiv = i ? vsub : 1;
674 
675 		state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
676 		if (!state->bpp[i])
677 			return -EINVAL;
678 
679 		switch (state->base.rotation & DRM_ROTATE_MASK) {
680 		case BIT(DRM_ROTATE_90):
681 			offset = ((y_offset + state->src_y + patched_src_w - 1) /
682 				  ydiv) * fb->pitches[i];
683 			offset += ((x_offset + state->src_x) / xdiv) *
684 				  state->bpp[i];
685 			state->xstride[i] = ((patched_src_w - 1) / ydiv) *
686 					  fb->pitches[i];
687 			state->pstride[i] = -fb->pitches[i] - state->bpp[i];
688 			break;
689 		case BIT(DRM_ROTATE_180):
690 			offset = ((y_offset + state->src_y + patched_src_h - 1) /
691 				  ydiv) * fb->pitches[i];
692 			offset += ((x_offset + state->src_x + patched_src_w - 1) /
693 				   xdiv) * state->bpp[i];
694 			state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
695 					   state->bpp[i]) - fb->pitches[i];
696 			state->pstride[i] = -2 * state->bpp[i];
697 			break;
698 		case BIT(DRM_ROTATE_270):
699 			offset = ((y_offset + state->src_y) / ydiv) *
700 				 fb->pitches[i];
701 			offset += ((x_offset + state->src_x + patched_src_h - 1) /
702 				   xdiv) * state->bpp[i];
703 			state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
704 					    fb->pitches[i]) -
705 					  (2 * state->bpp[i]);
706 			state->pstride[i] = fb->pitches[i] - state->bpp[i];
707 			break;
708 		case BIT(DRM_ROTATE_0):
709 		default:
710 			offset = ((y_offset + state->src_y) / ydiv) *
711 				 fb->pitches[i];
712 			offset += ((x_offset + state->src_x) / xdiv) *
713 				  state->bpp[i];
714 			state->xstride[i] = fb->pitches[i] -
715 					  ((patched_src_w / xdiv) *
716 					   state->bpp[i]);
717 			state->pstride[i] = 0;
718 			break;
719 		}
720 
721 		state->offsets[i] = offset + fb->offsets[i];
722 	}
723 
724 	state->src_w = patched_src_w;
725 	state->src_h = patched_src_h;
726 	state->crtc_w = patched_crtc_w;
727 	state->crtc_h = patched_crtc_h;
728 
729 	if (!layout->size &&
730 	    (mode->hdisplay != state->crtc_w ||
731 	     mode->vdisplay != state->crtc_h))
732 		return -EINVAL;
733 
734 	if (plane->layer.desc->max_height &&
735 	    state->crtc_h > plane->layer.desc->max_height)
736 		return -EINVAL;
737 
738 	if (plane->layer.desc->max_width &&
739 	    state->crtc_w > plane->layer.desc->max_width)
740 		return -EINVAL;
741 
742 	if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
743 	    (!layout->memsize ||
744 	     atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
745 		return -EINVAL;
746 
747 	if (state->crtc_x < 0 || state->crtc_y < 0)
748 		return -EINVAL;
749 
750 	if (state->crtc_w + state->crtc_x > mode->hdisplay ||
751 	    state->crtc_h + state->crtc_y > mode->vdisplay)
752 		return -EINVAL;
753 
754 	return 0;
755 }
756 
757 static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
758 					const struct drm_plane_state *new_state)
759 {
760 	/*
761 	 * FIXME: we should avoid this const -> non-const cast but it's
762 	 * currently the only solution we have to modify the ->prepared
763 	 * state and rollback the update request.
764 	 * Ideally, we should rework the code to attach all the resources
765 	 * to atmel_hlcdc_plane_state (including the DMA desc allocation),
766 	 * but this require a complete rework of the atmel_hlcdc_layer
767 	 * code.
768 	 */
769 	struct drm_plane_state *s = (struct drm_plane_state *)new_state;
770 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
771 	struct atmel_hlcdc_plane_state *state =
772 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
773 	int ret;
774 
775 	ret = atmel_hlcdc_layer_update_start(&plane->layer);
776 	if (!ret)
777 		state->prepared = true;
778 
779 	return ret;
780 }
781 
782 static void atmel_hlcdc_plane_cleanup_fb(struct drm_plane *p,
783 				const struct drm_plane_state *old_state)
784 {
785 	/*
786 	 * FIXME: we should avoid this const -> non-const cast but it's
787 	 * currently the only solution we have to modify the ->prepared
788 	 * state and rollback the update request.
789 	 * Ideally, we should rework the code to attach all the resources
790 	 * to atmel_hlcdc_plane_state (including the DMA desc allocation),
791 	 * but this require a complete rework of the atmel_hlcdc_layer
792 	 * code.
793 	 */
794 	struct drm_plane_state *s = (struct drm_plane_state *)old_state;
795 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
796 	struct atmel_hlcdc_plane_state *state =
797 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
798 
799 	/*
800 	 * The Request has already been applied or cancelled, nothing to do
801 	 * here.
802 	 */
803 	if (!state->prepared)
804 		return;
805 
806 	atmel_hlcdc_layer_update_rollback(&plane->layer);
807 	state->prepared = false;
808 }
809 
810 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
811 					    struct drm_plane_state *old_s)
812 {
813 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
814 	struct atmel_hlcdc_plane_state *state =
815 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
816 
817 	if (!p->state->crtc || !p->state->fb)
818 		return;
819 
820 	atmel_hlcdc_plane_update_pos_and_size(plane, state);
821 	atmel_hlcdc_plane_update_general_settings(plane, state);
822 	atmel_hlcdc_plane_update_format(plane, state);
823 	atmel_hlcdc_plane_update_buffers(plane, state);
824 	atmel_hlcdc_plane_update_disc_area(plane, state);
825 
826 	atmel_hlcdc_layer_update_commit(&plane->layer);
827 }
828 
829 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
830 					     struct drm_plane_state *old_state)
831 {
832 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
833 
834 	atmel_hlcdc_layer_disable(&plane->layer);
835 }
836 
837 static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
838 {
839 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
840 
841 	if (plane->base.fb)
842 		drm_framebuffer_unreference(plane->base.fb);
843 
844 	atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
845 
846 	drm_plane_cleanup(p);
847 	devm_kfree(p->dev->dev, plane);
848 }
849 
850 static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
851 						 struct drm_plane_state *s,
852 						 struct drm_property *property,
853 						 uint64_t val)
854 {
855 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
856 	struct atmel_hlcdc_plane_properties *props = plane->properties;
857 	struct atmel_hlcdc_plane_state *state =
858 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
859 
860 	if (property == props->alpha)
861 		state->alpha = val;
862 	else
863 		return -EINVAL;
864 
865 	return 0;
866 }
867 
868 static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
869 					const struct drm_plane_state *s,
870 					struct drm_property *property,
871 					uint64_t *val)
872 {
873 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
874 	struct atmel_hlcdc_plane_properties *props = plane->properties;
875 	const struct atmel_hlcdc_plane_state *state =
876 		container_of(s, const struct atmel_hlcdc_plane_state, base);
877 
878 	if (property == props->alpha)
879 		*val = state->alpha;
880 	else
881 		return -EINVAL;
882 
883 	return 0;
884 }
885 
886 static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
887 				const struct atmel_hlcdc_layer_desc *desc,
888 				struct atmel_hlcdc_plane_properties *props)
889 {
890 	struct regmap *regmap = plane->layer.hlcdc->regmap;
891 
892 	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
893 	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
894 		drm_object_attach_property(&plane->base.base,
895 					   props->alpha, 255);
896 
897 		/* Set default alpha value */
898 		regmap_update_bits(regmap,
899 				desc->regs_offset +
900 				ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
901 				ATMEL_HLCDC_LAYER_GA_MASK,
902 				ATMEL_HLCDC_LAYER_GA_MASK);
903 	}
904 
905 	if (desc->layout.xstride && desc->layout.pstride)
906 		drm_object_attach_property(&plane->base.base,
907 				plane->base.dev->mode_config.rotation_property,
908 				BIT(DRM_ROTATE_0));
909 
910 	if (desc->layout.csc) {
911 		/*
912 		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
913 		 * userspace modify these factors (using a BLOB property ?).
914 		 */
915 		regmap_write(regmap,
916 			     desc->regs_offset +
917 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
918 			     0x4c900091);
919 		regmap_write(regmap,
920 			     desc->regs_offset +
921 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
922 			     0x7a5f5090);
923 		regmap_write(regmap,
924 			     desc->regs_offset +
925 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
926 			     0x40040890);
927 	}
928 }
929 
930 static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
931 	.prepare_fb = atmel_hlcdc_plane_prepare_fb,
932 	.cleanup_fb = atmel_hlcdc_plane_cleanup_fb,
933 	.atomic_check = atmel_hlcdc_plane_atomic_check,
934 	.atomic_update = atmel_hlcdc_plane_atomic_update,
935 	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
936 };
937 
938 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
939 {
940 	struct atmel_hlcdc_plane_state *state;
941 
942 	if (p->state) {
943 		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
944 
945 		if (state->base.fb)
946 			drm_framebuffer_unreference(state->base.fb);
947 
948 		kfree(state);
949 		p->state = NULL;
950 	}
951 
952 	state = kzalloc(sizeof(*state), GFP_KERNEL);
953 	if (state) {
954 		state->alpha = 255;
955 		p->state = &state->base;
956 		p->state->plane = p;
957 	}
958 }
959 
960 static struct drm_plane_state *
961 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
962 {
963 	struct atmel_hlcdc_plane_state *state =
964 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
965 	struct atmel_hlcdc_plane_state *copy;
966 
967 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
968 	if (!copy)
969 		return NULL;
970 
971 	copy->disc_updated = false;
972 	copy->prepared = false;
973 
974 	if (copy->base.fb)
975 		drm_framebuffer_reference(copy->base.fb);
976 
977 	return &copy->base;
978 }
979 
980 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
981 						   struct drm_plane_state *s)
982 {
983 	struct atmel_hlcdc_plane_state *state =
984 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
985 
986 	if (s->fb)
987 		drm_framebuffer_unreference(s->fb);
988 
989 	kfree(state);
990 }
991 
992 static struct drm_plane_funcs layer_plane_funcs = {
993 	.update_plane = drm_atomic_helper_update_plane,
994 	.disable_plane = drm_atomic_helper_disable_plane,
995 	.set_property = drm_atomic_helper_plane_set_property,
996 	.destroy = atmel_hlcdc_plane_destroy,
997 	.reset = atmel_hlcdc_plane_reset,
998 	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
999 	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
1000 	.atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
1001 	.atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
1002 };
1003 
1004 static struct atmel_hlcdc_plane *
1005 atmel_hlcdc_plane_create(struct drm_device *dev,
1006 			 const struct atmel_hlcdc_layer_desc *desc,
1007 			 struct atmel_hlcdc_plane_properties *props)
1008 {
1009 	struct atmel_hlcdc_plane *plane;
1010 	enum drm_plane_type type;
1011 	int ret;
1012 
1013 	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
1014 	if (!plane)
1015 		return ERR_PTR(-ENOMEM);
1016 
1017 	ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
1018 	if (ret)
1019 		return ERR_PTR(ret);
1020 
1021 	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1022 		type = DRM_PLANE_TYPE_PRIMARY;
1023 	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1024 		type = DRM_PLANE_TYPE_CURSOR;
1025 	else
1026 		type = DRM_PLANE_TYPE_OVERLAY;
1027 
1028 	ret = drm_universal_plane_init(dev, &plane->base, 0,
1029 				       &layer_plane_funcs,
1030 				       desc->formats->formats,
1031 				       desc->formats->nformats, type, NULL);
1032 	if (ret)
1033 		return ERR_PTR(ret);
1034 
1035 	drm_plane_helper_add(&plane->base,
1036 			     &atmel_hlcdc_layer_plane_helper_funcs);
1037 
1038 	/* Set default property values*/
1039 	atmel_hlcdc_plane_init_properties(plane, desc, props);
1040 
1041 	return plane;
1042 }
1043 
1044 static struct atmel_hlcdc_plane_properties *
1045 atmel_hlcdc_plane_create_properties(struct drm_device *dev)
1046 {
1047 	struct atmel_hlcdc_plane_properties *props;
1048 
1049 	props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
1050 	if (!props)
1051 		return ERR_PTR(-ENOMEM);
1052 
1053 	props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
1054 	if (!props->alpha)
1055 		return ERR_PTR(-ENOMEM);
1056 
1057 	dev->mode_config.rotation_property =
1058 			drm_mode_create_rotation_property(dev,
1059 							  BIT(DRM_ROTATE_0) |
1060 							  BIT(DRM_ROTATE_90) |
1061 							  BIT(DRM_ROTATE_180) |
1062 							  BIT(DRM_ROTATE_270));
1063 	if (!dev->mode_config.rotation_property)
1064 		return ERR_PTR(-ENOMEM);
1065 
1066 	return props;
1067 }
1068 
1069 struct atmel_hlcdc_planes *
1070 atmel_hlcdc_create_planes(struct drm_device *dev)
1071 {
1072 	struct atmel_hlcdc_dc *dc = dev->dev_private;
1073 	struct atmel_hlcdc_plane_properties *props;
1074 	struct atmel_hlcdc_planes *planes;
1075 	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1076 	int nlayers = dc->desc->nlayers;
1077 	int i;
1078 
1079 	planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
1080 	if (!planes)
1081 		return ERR_PTR(-ENOMEM);
1082 
1083 	for (i = 0; i < nlayers; i++) {
1084 		if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
1085 			planes->noverlays++;
1086 	}
1087 
1088 	if (planes->noverlays) {
1089 		planes->overlays = devm_kzalloc(dev->dev,
1090 						planes->noverlays *
1091 						sizeof(*planes->overlays),
1092 						GFP_KERNEL);
1093 		if (!planes->overlays)
1094 			return ERR_PTR(-ENOMEM);
1095 	}
1096 
1097 	props = atmel_hlcdc_plane_create_properties(dev);
1098 	if (IS_ERR(props))
1099 		return ERR_CAST(props);
1100 
1101 	planes->noverlays = 0;
1102 	for (i = 0; i < nlayers; i++) {
1103 		struct atmel_hlcdc_plane *plane;
1104 
1105 		if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
1106 			continue;
1107 
1108 		plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
1109 		if (IS_ERR(plane))
1110 			return ERR_CAST(plane);
1111 
1112 		plane->properties = props;
1113 
1114 		switch (descs[i].type) {
1115 		case ATMEL_HLCDC_BASE_LAYER:
1116 			if (planes->primary)
1117 				return ERR_PTR(-EINVAL);
1118 			planes->primary = plane;
1119 			break;
1120 
1121 		case ATMEL_HLCDC_OVERLAY_LAYER:
1122 			planes->overlays[planes->noverlays++] = plane;
1123 			break;
1124 
1125 		case ATMEL_HLCDC_CURSOR_LAYER:
1126 			if (planes->cursor)
1127 				return ERR_PTR(-EINVAL);
1128 			planes->cursor = plane;
1129 			break;
1130 
1131 		default:
1132 			break;
1133 		}
1134 	}
1135 
1136 	return planes;
1137 }
1138