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