xref: /linux/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c (revision 0883c2c06fb5bcf5b9e008270827e63c09a88c1e)
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 	}
343 }
344 
345 static void
346 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
347 					struct atmel_hlcdc_plane_state *state)
348 {
349 	const struct atmel_hlcdc_layer_cfg_layout *layout =
350 						&plane->layer.desc->layout;
351 	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
352 
353 	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
354 		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
355 		       ATMEL_HLCDC_LAYER_ITER;
356 
357 		if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
358 			cfg |= ATMEL_HLCDC_LAYER_LAEN;
359 		else
360 			cfg |= ATMEL_HLCDC_LAYER_GAEN |
361 			       ATMEL_HLCDC_LAYER_GA(state->alpha);
362 	}
363 
364 	atmel_hlcdc_layer_update_cfg(&plane->layer,
365 				     ATMEL_HLCDC_LAYER_DMA_CFG_ID,
366 				     ATMEL_HLCDC_LAYER_DMA_BLEN_MASK |
367 				     ATMEL_HLCDC_LAYER_DMA_SIF,
368 				     ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 |
369 				     state->ahb_id);
370 
371 	atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
372 				     ATMEL_HLCDC_LAYER_ITER2BL |
373 				     ATMEL_HLCDC_LAYER_ITER |
374 				     ATMEL_HLCDC_LAYER_GAEN |
375 				     ATMEL_HLCDC_LAYER_GA_MASK |
376 				     ATMEL_HLCDC_LAYER_LAEN |
377 				     ATMEL_HLCDC_LAYER_OVR |
378 				     ATMEL_HLCDC_LAYER_DMA, cfg);
379 }
380 
381 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
382 					struct atmel_hlcdc_plane_state *state)
383 {
384 	u32 cfg;
385 	int ret;
386 
387 	ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
388 					       &cfg);
389 	if (ret)
390 		return;
391 
392 	if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 ||
393 	     state->base.fb->pixel_format == DRM_FORMAT_NV61) &&
394 	    (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
395 		cfg |= ATMEL_HLCDC_YUV422ROT;
396 
397 	atmel_hlcdc_layer_update_cfg(&plane->layer,
398 				     ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
399 				     0xffffffff,
400 				     cfg);
401 
402 	/*
403 	 * Rotation optimization is not working on RGB888 (rotation is still
404 	 * working but without any optimization).
405 	 */
406 	if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
407 		cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
408 	else
409 		cfg = 0;
410 
411 	atmel_hlcdc_layer_update_cfg(&plane->layer,
412 				     ATMEL_HLCDC_LAYER_DMA_CFG_ID,
413 				     ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
414 }
415 
416 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
417 					struct atmel_hlcdc_plane_state *state)
418 {
419 	struct atmel_hlcdc_layer *layer = &plane->layer;
420 	const struct atmel_hlcdc_layer_cfg_layout *layout =
421 							&layer->desc->layout;
422 	int i;
423 
424 	atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
425 					state->offsets);
426 
427 	for (i = 0; i < state->nplanes; i++) {
428 		if (layout->xstride[i]) {
429 			atmel_hlcdc_layer_update_cfg(&plane->layer,
430 						layout->xstride[i],
431 						0xffffffff,
432 						state->xstride[i]);
433 		}
434 
435 		if (layout->pstride[i]) {
436 			atmel_hlcdc_layer_update_cfg(&plane->layer,
437 						layout->pstride[i],
438 						0xffffffff,
439 						state->pstride[i]);
440 		}
441 	}
442 }
443 
444 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
445 {
446 	unsigned int ahb_load[2] = { };
447 	struct drm_plane *plane;
448 
449 	drm_atomic_crtc_state_for_each_plane(plane, c_state) {
450 		struct atmel_hlcdc_plane_state *plane_state;
451 		struct drm_plane_state *plane_s;
452 		unsigned int pixels, load = 0;
453 		int i;
454 
455 		plane_s = drm_atomic_get_plane_state(c_state->state, plane);
456 		if (IS_ERR(plane_s))
457 			return PTR_ERR(plane_s);
458 
459 		plane_state =
460 			drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
461 
462 		pixels = (plane_state->src_w * plane_state->src_h) -
463 			 (plane_state->disc_w * plane_state->disc_h);
464 
465 		for (i = 0; i < plane_state->nplanes; i++)
466 			load += pixels * plane_state->bpp[i];
467 
468 		if (ahb_load[0] <= ahb_load[1])
469 			plane_state->ahb_id = 0;
470 		else
471 			plane_state->ahb_id = 1;
472 
473 		ahb_load[plane_state->ahb_id] += load;
474 	}
475 
476 	return 0;
477 }
478 
479 int
480 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
481 {
482 	int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
483 	const struct atmel_hlcdc_layer_cfg_layout *layout;
484 	struct atmel_hlcdc_plane_state *primary_state;
485 	struct drm_plane_state *primary_s;
486 	struct atmel_hlcdc_plane *primary;
487 	struct drm_plane *ovl;
488 
489 	primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
490 	layout = &primary->layer.desc->layout;
491 	if (!layout->disc_pos || !layout->disc_size)
492 		return 0;
493 
494 	primary_s = drm_atomic_get_plane_state(c_state->state,
495 					       &primary->base);
496 	if (IS_ERR(primary_s))
497 		return PTR_ERR(primary_s);
498 
499 	primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
500 
501 	drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
502 		struct atmel_hlcdc_plane_state *ovl_state;
503 		struct drm_plane_state *ovl_s;
504 
505 		if (ovl == c_state->crtc->primary)
506 			continue;
507 
508 		ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
509 		if (IS_ERR(ovl_s))
510 			return PTR_ERR(ovl_s);
511 
512 		ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
513 
514 		if (!ovl_s->fb ||
515 		    atmel_hlcdc_format_embeds_alpha(ovl_s->fb->pixel_format) ||
516 		    ovl_state->alpha != 255)
517 			continue;
518 
519 		/* TODO: implement a smarter hidden area detection */
520 		if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
521 			continue;
522 
523 		disc_x = ovl_state->crtc_x;
524 		disc_y = ovl_state->crtc_y;
525 		disc_h = ovl_state->crtc_h;
526 		disc_w = ovl_state->crtc_w;
527 	}
528 
529 	if (disc_x == primary_state->disc_x &&
530 	    disc_y == primary_state->disc_y &&
531 	    disc_w == primary_state->disc_w &&
532 	    disc_h == primary_state->disc_h)
533 		return 0;
534 
535 
536 	primary_state->disc_x = disc_x;
537 	primary_state->disc_y = disc_y;
538 	primary_state->disc_w = disc_w;
539 	primary_state->disc_h = disc_h;
540 	primary_state->disc_updated = true;
541 
542 	return 0;
543 }
544 
545 static void
546 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
547 				   struct atmel_hlcdc_plane_state *state)
548 {
549 	const struct atmel_hlcdc_layer_cfg_layout *layout =
550 						&plane->layer.desc->layout;
551 	int disc_surface = 0;
552 
553 	if (!state->disc_updated)
554 		return;
555 
556 	disc_surface = state->disc_h * state->disc_w;
557 
558 	atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
559 				ATMEL_HLCDC_LAYER_DISCEN,
560 				disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0);
561 
562 	if (!disc_surface)
563 		return;
564 
565 	atmel_hlcdc_layer_update_cfg(&plane->layer,
566 				     layout->disc_pos,
567 				     0xffffffff,
568 				     state->disc_x | (state->disc_y << 16));
569 
570 	atmel_hlcdc_layer_update_cfg(&plane->layer,
571 				     layout->disc_size,
572 				     0xffffffff,
573 				     (state->disc_w - 1) |
574 				     ((state->disc_h - 1) << 16));
575 }
576 
577 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
578 					  struct drm_plane_state *s)
579 {
580 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
581 	struct atmel_hlcdc_plane_state *state =
582 				drm_plane_state_to_atmel_hlcdc_plane_state(s);
583 	const struct atmel_hlcdc_layer_cfg_layout *layout =
584 						&plane->layer.desc->layout;
585 	struct drm_framebuffer *fb = state->base.fb;
586 	const struct drm_display_mode *mode;
587 	struct drm_crtc_state *crtc_state;
588 	unsigned int patched_crtc_w;
589 	unsigned int patched_crtc_h;
590 	unsigned int patched_src_w;
591 	unsigned int patched_src_h;
592 	unsigned int tmp;
593 	int x_offset = 0;
594 	int y_offset = 0;
595 	int hsub = 1;
596 	int vsub = 1;
597 	int i;
598 
599 	if (!state->base.crtc || !fb)
600 		return 0;
601 
602 	crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
603 	mode = &crtc_state->adjusted_mode;
604 
605 	state->src_x = s->src_x;
606 	state->src_y = s->src_y;
607 	state->src_h = s->src_h;
608 	state->src_w = s->src_w;
609 	state->crtc_x = s->crtc_x;
610 	state->crtc_y = s->crtc_y;
611 	state->crtc_h = s->crtc_h;
612 	state->crtc_w = s->crtc_w;
613 	if ((state->src_x | state->src_y | state->src_w | state->src_h) &
614 	    SUBPIXEL_MASK)
615 		return -EINVAL;
616 
617 	state->src_x >>= 16;
618 	state->src_y >>= 16;
619 	state->src_w >>= 16;
620 	state->src_h >>= 16;
621 
622 	state->nplanes = drm_format_num_planes(fb->pixel_format);
623 	if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
624 		return -EINVAL;
625 
626 	/*
627 	 * Swap width and size in case of 90 or 270 degrees rotation
628 	 */
629 	if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
630 		tmp = state->crtc_w;
631 		state->crtc_w = state->crtc_h;
632 		state->crtc_h = tmp;
633 		tmp = state->src_w;
634 		state->src_w = state->src_h;
635 		state->src_h = tmp;
636 	}
637 
638 	if (state->crtc_x + state->crtc_w > mode->hdisplay)
639 		patched_crtc_w = mode->hdisplay - state->crtc_x;
640 	else
641 		patched_crtc_w = state->crtc_w;
642 
643 	if (state->crtc_x < 0) {
644 		patched_crtc_w += state->crtc_x;
645 		x_offset = -state->crtc_x;
646 		state->crtc_x = 0;
647 	}
648 
649 	if (state->crtc_y + state->crtc_h > mode->vdisplay)
650 		patched_crtc_h = mode->vdisplay - state->crtc_y;
651 	else
652 		patched_crtc_h = state->crtc_h;
653 
654 	if (state->crtc_y < 0) {
655 		patched_crtc_h += state->crtc_y;
656 		y_offset = -state->crtc_y;
657 		state->crtc_y = 0;
658 	}
659 
660 	patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
661 					  state->crtc_w);
662 	patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
663 					  state->crtc_h);
664 
665 	hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
666 	vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
667 
668 	for (i = 0; i < state->nplanes; i++) {
669 		unsigned int offset = 0;
670 		int xdiv = i ? hsub : 1;
671 		int ydiv = i ? vsub : 1;
672 
673 		state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
674 		if (!state->bpp[i])
675 			return -EINVAL;
676 
677 		switch (state->base.rotation & DRM_ROTATE_MASK) {
678 		case BIT(DRM_ROTATE_90):
679 			offset = ((y_offset + state->src_y + patched_src_w - 1) /
680 				  ydiv) * fb->pitches[i];
681 			offset += ((x_offset + state->src_x) / xdiv) *
682 				  state->bpp[i];
683 			state->xstride[i] = ((patched_src_w - 1) / ydiv) *
684 					  fb->pitches[i];
685 			state->pstride[i] = -fb->pitches[i] - state->bpp[i];
686 			break;
687 		case BIT(DRM_ROTATE_180):
688 			offset = ((y_offset + state->src_y + patched_src_h - 1) /
689 				  ydiv) * fb->pitches[i];
690 			offset += ((x_offset + state->src_x + patched_src_w - 1) /
691 				   xdiv) * state->bpp[i];
692 			state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
693 					   state->bpp[i]) - fb->pitches[i];
694 			state->pstride[i] = -2 * state->bpp[i];
695 			break;
696 		case BIT(DRM_ROTATE_270):
697 			offset = ((y_offset + state->src_y) / ydiv) *
698 				 fb->pitches[i];
699 			offset += ((x_offset + state->src_x + patched_src_h - 1) /
700 				   xdiv) * state->bpp[i];
701 			state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
702 					    fb->pitches[i]) -
703 					  (2 * state->bpp[i]);
704 			state->pstride[i] = fb->pitches[i] - state->bpp[i];
705 			break;
706 		case BIT(DRM_ROTATE_0):
707 		default:
708 			offset = ((y_offset + state->src_y) / ydiv) *
709 				 fb->pitches[i];
710 			offset += ((x_offset + state->src_x) / xdiv) *
711 				  state->bpp[i];
712 			state->xstride[i] = fb->pitches[i] -
713 					  ((patched_src_w / xdiv) *
714 					   state->bpp[i]);
715 			state->pstride[i] = 0;
716 			break;
717 		}
718 
719 		state->offsets[i] = offset + fb->offsets[i];
720 	}
721 
722 	state->src_w = patched_src_w;
723 	state->src_h = patched_src_h;
724 	state->crtc_w = patched_crtc_w;
725 	state->crtc_h = patched_crtc_h;
726 
727 	if (!layout->size &&
728 	    (mode->hdisplay != state->crtc_w ||
729 	     mode->vdisplay != state->crtc_h))
730 		return -EINVAL;
731 
732 	if (plane->layer.desc->max_height &&
733 	    state->crtc_h > plane->layer.desc->max_height)
734 		return -EINVAL;
735 
736 	if (plane->layer.desc->max_width &&
737 	    state->crtc_w > plane->layer.desc->max_width)
738 		return -EINVAL;
739 
740 	if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
741 	    (!layout->memsize ||
742 	     atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
743 		return -EINVAL;
744 
745 	if (state->crtc_x < 0 || state->crtc_y < 0)
746 		return -EINVAL;
747 
748 	if (state->crtc_w + state->crtc_x > mode->hdisplay ||
749 	    state->crtc_h + state->crtc_y > mode->vdisplay)
750 		return -EINVAL;
751 
752 	return 0;
753 }
754 
755 static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
756 					const struct drm_plane_state *new_state)
757 {
758 	/*
759 	 * FIXME: we should avoid this const -> non-const cast but it's
760 	 * currently the only solution we have to modify the ->prepared
761 	 * state and rollback the update request.
762 	 * Ideally, we should rework the code to attach all the resources
763 	 * to atmel_hlcdc_plane_state (including the DMA desc allocation),
764 	 * but this require a complete rework of the atmel_hlcdc_layer
765 	 * code.
766 	 */
767 	struct drm_plane_state *s = (struct drm_plane_state *)new_state;
768 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
769 	struct atmel_hlcdc_plane_state *state =
770 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
771 	int ret;
772 
773 	ret = atmel_hlcdc_layer_update_start(&plane->layer);
774 	if (!ret)
775 		state->prepared = true;
776 
777 	return ret;
778 }
779 
780 static void atmel_hlcdc_plane_cleanup_fb(struct drm_plane *p,
781 				const struct drm_plane_state *old_state)
782 {
783 	/*
784 	 * FIXME: we should avoid this const -> non-const cast but it's
785 	 * currently the only solution we have to modify the ->prepared
786 	 * state and rollback the update request.
787 	 * Ideally, we should rework the code to attach all the resources
788 	 * to atmel_hlcdc_plane_state (including the DMA desc allocation),
789 	 * but this require a complete rework of the atmel_hlcdc_layer
790 	 * code.
791 	 */
792 	struct drm_plane_state *s = (struct drm_plane_state *)old_state;
793 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
794 	struct atmel_hlcdc_plane_state *state =
795 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
796 
797 	/*
798 	 * The Request has already been applied or cancelled, nothing to do
799 	 * here.
800 	 */
801 	if (!state->prepared)
802 		return;
803 
804 	atmel_hlcdc_layer_update_rollback(&plane->layer);
805 	state->prepared = false;
806 }
807 
808 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
809 					    struct drm_plane_state *old_s)
810 {
811 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
812 	struct atmel_hlcdc_plane_state *state =
813 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
814 
815 	if (!p->state->crtc || !p->state->fb)
816 		return;
817 
818 	atmel_hlcdc_plane_update_pos_and_size(plane, state);
819 	atmel_hlcdc_plane_update_general_settings(plane, state);
820 	atmel_hlcdc_plane_update_format(plane, state);
821 	atmel_hlcdc_plane_update_buffers(plane, state);
822 	atmel_hlcdc_plane_update_disc_area(plane, state);
823 
824 	atmel_hlcdc_layer_update_commit(&plane->layer);
825 }
826 
827 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
828 					     struct drm_plane_state *old_state)
829 {
830 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
831 
832 	atmel_hlcdc_layer_disable(&plane->layer);
833 }
834 
835 static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
836 {
837 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
838 
839 	if (plane->base.fb)
840 		drm_framebuffer_unreference(plane->base.fb);
841 
842 	atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
843 
844 	drm_plane_cleanup(p);
845 	devm_kfree(p->dev->dev, plane);
846 }
847 
848 static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
849 						 struct drm_plane_state *s,
850 						 struct drm_property *property,
851 						 uint64_t val)
852 {
853 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
854 	struct atmel_hlcdc_plane_properties *props = plane->properties;
855 	struct atmel_hlcdc_plane_state *state =
856 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
857 
858 	if (property == props->alpha)
859 		state->alpha = val;
860 	else
861 		return -EINVAL;
862 
863 	return 0;
864 }
865 
866 static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
867 					const struct drm_plane_state *s,
868 					struct drm_property *property,
869 					uint64_t *val)
870 {
871 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
872 	struct atmel_hlcdc_plane_properties *props = plane->properties;
873 	const struct atmel_hlcdc_plane_state *state =
874 		container_of(s, const struct atmel_hlcdc_plane_state, base);
875 
876 	if (property == props->alpha)
877 		*val = state->alpha;
878 	else
879 		return -EINVAL;
880 
881 	return 0;
882 }
883 
884 static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
885 				const struct atmel_hlcdc_layer_desc *desc,
886 				struct atmel_hlcdc_plane_properties *props)
887 {
888 	struct regmap *regmap = plane->layer.hlcdc->regmap;
889 
890 	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
891 	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
892 		drm_object_attach_property(&plane->base.base,
893 					   props->alpha, 255);
894 
895 		/* Set default alpha value */
896 		regmap_update_bits(regmap,
897 				desc->regs_offset +
898 				ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
899 				ATMEL_HLCDC_LAYER_GA_MASK,
900 				ATMEL_HLCDC_LAYER_GA_MASK);
901 	}
902 
903 	if (desc->layout.xstride && desc->layout.pstride)
904 		drm_object_attach_property(&plane->base.base,
905 				plane->base.dev->mode_config.rotation_property,
906 				BIT(DRM_ROTATE_0));
907 
908 	if (desc->layout.csc) {
909 		/*
910 		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
911 		 * userspace modify these factors (using a BLOB property ?).
912 		 */
913 		regmap_write(regmap,
914 			     desc->regs_offset +
915 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
916 			     0x4c900091);
917 		regmap_write(regmap,
918 			     desc->regs_offset +
919 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
920 			     0x7a5f5090);
921 		regmap_write(regmap,
922 			     desc->regs_offset +
923 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
924 			     0x40040890);
925 	}
926 }
927 
928 static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
929 	.prepare_fb = atmel_hlcdc_plane_prepare_fb,
930 	.cleanup_fb = atmel_hlcdc_plane_cleanup_fb,
931 	.atomic_check = atmel_hlcdc_plane_atomic_check,
932 	.atomic_update = atmel_hlcdc_plane_atomic_update,
933 	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
934 };
935 
936 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
937 {
938 	struct atmel_hlcdc_plane_state *state;
939 
940 	if (p->state) {
941 		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
942 
943 		if (state->base.fb)
944 			drm_framebuffer_unreference(state->base.fb);
945 
946 		kfree(state);
947 		p->state = NULL;
948 	}
949 
950 	state = kzalloc(sizeof(*state), GFP_KERNEL);
951 	if (state) {
952 		state->alpha = 255;
953 		p->state = &state->base;
954 		p->state->plane = p;
955 	}
956 }
957 
958 static struct drm_plane_state *
959 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
960 {
961 	struct atmel_hlcdc_plane_state *state =
962 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
963 	struct atmel_hlcdc_plane_state *copy;
964 
965 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
966 	if (!copy)
967 		return NULL;
968 
969 	copy->disc_updated = false;
970 	copy->prepared = false;
971 
972 	if (copy->base.fb)
973 		drm_framebuffer_reference(copy->base.fb);
974 
975 	return &copy->base;
976 }
977 
978 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
979 						   struct drm_plane_state *s)
980 {
981 	struct atmel_hlcdc_plane_state *state =
982 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
983 
984 	if (s->fb)
985 		drm_framebuffer_unreference(s->fb);
986 
987 	kfree(state);
988 }
989 
990 static struct drm_plane_funcs layer_plane_funcs = {
991 	.update_plane = drm_atomic_helper_update_plane,
992 	.disable_plane = drm_atomic_helper_disable_plane,
993 	.set_property = drm_atomic_helper_plane_set_property,
994 	.destroy = atmel_hlcdc_plane_destroy,
995 	.reset = atmel_hlcdc_plane_reset,
996 	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
997 	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
998 	.atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
999 	.atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
1000 };
1001 
1002 static struct atmel_hlcdc_plane *
1003 atmel_hlcdc_plane_create(struct drm_device *dev,
1004 			 const struct atmel_hlcdc_layer_desc *desc,
1005 			 struct atmel_hlcdc_plane_properties *props)
1006 {
1007 	struct atmel_hlcdc_plane *plane;
1008 	enum drm_plane_type type;
1009 	int ret;
1010 
1011 	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
1012 	if (!plane)
1013 		return ERR_PTR(-ENOMEM);
1014 
1015 	ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
1016 	if (ret)
1017 		return ERR_PTR(ret);
1018 
1019 	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1020 		type = DRM_PLANE_TYPE_PRIMARY;
1021 	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1022 		type = DRM_PLANE_TYPE_CURSOR;
1023 	else
1024 		type = DRM_PLANE_TYPE_OVERLAY;
1025 
1026 	ret = drm_universal_plane_init(dev, &plane->base, 0,
1027 				       &layer_plane_funcs,
1028 				       desc->formats->formats,
1029 				       desc->formats->nformats, type, NULL);
1030 	if (ret)
1031 		return ERR_PTR(ret);
1032 
1033 	drm_plane_helper_add(&plane->base,
1034 			     &atmel_hlcdc_layer_plane_helper_funcs);
1035 
1036 	/* Set default property values*/
1037 	atmel_hlcdc_plane_init_properties(plane, desc, props);
1038 
1039 	return plane;
1040 }
1041 
1042 static struct atmel_hlcdc_plane_properties *
1043 atmel_hlcdc_plane_create_properties(struct drm_device *dev)
1044 {
1045 	struct atmel_hlcdc_plane_properties *props;
1046 
1047 	props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
1048 	if (!props)
1049 		return ERR_PTR(-ENOMEM);
1050 
1051 	props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
1052 	if (!props->alpha)
1053 		return ERR_PTR(-ENOMEM);
1054 
1055 	dev->mode_config.rotation_property =
1056 			drm_mode_create_rotation_property(dev,
1057 							  BIT(DRM_ROTATE_0) |
1058 							  BIT(DRM_ROTATE_90) |
1059 							  BIT(DRM_ROTATE_180) |
1060 							  BIT(DRM_ROTATE_270));
1061 	if (!dev->mode_config.rotation_property)
1062 		return ERR_PTR(-ENOMEM);
1063 
1064 	return props;
1065 }
1066 
1067 struct atmel_hlcdc_planes *
1068 atmel_hlcdc_create_planes(struct drm_device *dev)
1069 {
1070 	struct atmel_hlcdc_dc *dc = dev->dev_private;
1071 	struct atmel_hlcdc_plane_properties *props;
1072 	struct atmel_hlcdc_planes *planes;
1073 	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1074 	int nlayers = dc->desc->nlayers;
1075 	int i;
1076 
1077 	planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
1078 	if (!planes)
1079 		return ERR_PTR(-ENOMEM);
1080 
1081 	for (i = 0; i < nlayers; i++) {
1082 		if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
1083 			planes->noverlays++;
1084 	}
1085 
1086 	if (planes->noverlays) {
1087 		planes->overlays = devm_kzalloc(dev->dev,
1088 						planes->noverlays *
1089 						sizeof(*planes->overlays),
1090 						GFP_KERNEL);
1091 		if (!planes->overlays)
1092 			return ERR_PTR(-ENOMEM);
1093 	}
1094 
1095 	props = atmel_hlcdc_plane_create_properties(dev);
1096 	if (IS_ERR(props))
1097 		return ERR_CAST(props);
1098 
1099 	planes->noverlays = 0;
1100 	for (i = 0; i < nlayers; i++) {
1101 		struct atmel_hlcdc_plane *plane;
1102 
1103 		if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
1104 			continue;
1105 
1106 		plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
1107 		if (IS_ERR(plane))
1108 			return ERR_CAST(plane);
1109 
1110 		plane->properties = props;
1111 
1112 		switch (descs[i].type) {
1113 		case ATMEL_HLCDC_BASE_LAYER:
1114 			if (planes->primary)
1115 				return ERR_PTR(-EINVAL);
1116 			planes->primary = plane;
1117 			break;
1118 
1119 		case ATMEL_HLCDC_OVERLAY_LAYER:
1120 			planes->overlays[planes->noverlays++] = plane;
1121 			break;
1122 
1123 		case ATMEL_HLCDC_CURSOR_LAYER:
1124 			if (planes->cursor)
1125 				return ERR_PTR(-EINVAL);
1126 			planes->cursor = plane;
1127 			break;
1128 
1129 		default:
1130 			break;
1131 		}
1132 	}
1133 
1134 	return planes;
1135 }
1136