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 & DRM_ROTATE_MASK) {
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 					const struct drm_plane_state *new_state)
716 {
717 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
718 
719 	if (!new_state->fb)
720 		return 0;
721 
722 	return atmel_hlcdc_layer_update_start(&plane->layer);
723 }
724 
725 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
726 					    struct drm_plane_state *old_s)
727 {
728 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
729 	struct atmel_hlcdc_plane_state *state =
730 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
731 
732 	if (!p->state->crtc || !p->state->fb)
733 		return;
734 
735 	atmel_hlcdc_plane_update_pos_and_size(plane, state);
736 	atmel_hlcdc_plane_update_general_settings(plane, state);
737 	atmel_hlcdc_plane_update_format(plane, state);
738 	atmel_hlcdc_plane_update_buffers(plane, state);
739 	atmel_hlcdc_plane_update_disc_area(plane, state);
740 
741 	atmel_hlcdc_layer_update_commit(&plane->layer);
742 }
743 
744 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
745 					     struct drm_plane_state *old_state)
746 {
747 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
748 
749 	atmel_hlcdc_layer_disable(&plane->layer);
750 }
751 
752 static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
753 {
754 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
755 
756 	if (plane->base.fb)
757 		drm_framebuffer_unreference(plane->base.fb);
758 
759 	atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
760 
761 	drm_plane_cleanup(p);
762 	devm_kfree(p->dev->dev, plane);
763 }
764 
765 static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
766 						 struct drm_plane_state *s,
767 						 struct drm_property *property,
768 						 uint64_t val)
769 {
770 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
771 	struct atmel_hlcdc_plane_properties *props = plane->properties;
772 	struct atmel_hlcdc_plane_state *state =
773 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
774 
775 	if (property == props->alpha)
776 		state->alpha = val;
777 	else
778 		return -EINVAL;
779 
780 	return 0;
781 }
782 
783 static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
784 					const struct drm_plane_state *s,
785 					struct drm_property *property,
786 					uint64_t *val)
787 {
788 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
789 	struct atmel_hlcdc_plane_properties *props = plane->properties;
790 	const struct atmel_hlcdc_plane_state *state =
791 		container_of(s, const struct atmel_hlcdc_plane_state, base);
792 
793 	if (property == props->alpha)
794 		*val = state->alpha;
795 	else
796 		return -EINVAL;
797 
798 	return 0;
799 }
800 
801 static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
802 				const struct atmel_hlcdc_layer_desc *desc,
803 				struct atmel_hlcdc_plane_properties *props)
804 {
805 	struct regmap *regmap = plane->layer.hlcdc->regmap;
806 
807 	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
808 	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
809 		drm_object_attach_property(&plane->base.base,
810 					   props->alpha, 255);
811 
812 		/* Set default alpha value */
813 		regmap_update_bits(regmap,
814 				desc->regs_offset +
815 				ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
816 				ATMEL_HLCDC_LAYER_GA_MASK,
817 				ATMEL_HLCDC_LAYER_GA_MASK);
818 	}
819 
820 	if (desc->layout.xstride && desc->layout.pstride)
821 		drm_object_attach_property(&plane->base.base,
822 				plane->base.dev->mode_config.rotation_property,
823 				BIT(DRM_ROTATE_0));
824 
825 	if (desc->layout.csc) {
826 		/*
827 		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
828 		 * userspace modify these factors (using a BLOB property ?).
829 		 */
830 		regmap_write(regmap,
831 			     desc->regs_offset +
832 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
833 			     0x4c900091);
834 		regmap_write(regmap,
835 			     desc->regs_offset +
836 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
837 			     0x7a5f5090);
838 		regmap_write(regmap,
839 			     desc->regs_offset +
840 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
841 			     0x40040890);
842 	}
843 }
844 
845 static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
846 	.prepare_fb = atmel_hlcdc_plane_prepare_fb,
847 	.atomic_check = atmel_hlcdc_plane_atomic_check,
848 	.atomic_update = atmel_hlcdc_plane_atomic_update,
849 	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
850 };
851 
852 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
853 {
854 	struct atmel_hlcdc_plane_state *state;
855 
856 	if (p->state) {
857 		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
858 
859 		if (state->base.fb)
860 			drm_framebuffer_unreference(state->base.fb);
861 
862 		kfree(state);
863 		p->state = NULL;
864 	}
865 
866 	state = kzalloc(sizeof(*state), GFP_KERNEL);
867 	if (state) {
868 		state->alpha = 255;
869 		p->state = &state->base;
870 		p->state->plane = p;
871 	}
872 }
873 
874 static struct drm_plane_state *
875 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
876 {
877 	struct atmel_hlcdc_plane_state *state =
878 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
879 	struct atmel_hlcdc_plane_state *copy;
880 
881 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
882 	if (!copy)
883 		return NULL;
884 
885 	copy->disc_updated = false;
886 
887 	if (copy->base.fb)
888 		drm_framebuffer_reference(copy->base.fb);
889 
890 	return &copy->base;
891 }
892 
893 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
894 						   struct drm_plane_state *s)
895 {
896 	struct atmel_hlcdc_plane_state *state =
897 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
898 
899 	if (s->fb)
900 		drm_framebuffer_unreference(s->fb);
901 
902 	kfree(state);
903 }
904 
905 static struct drm_plane_funcs layer_plane_funcs = {
906 	.update_plane = drm_atomic_helper_update_plane,
907 	.disable_plane = drm_atomic_helper_disable_plane,
908 	.set_property = drm_atomic_helper_plane_set_property,
909 	.destroy = atmel_hlcdc_plane_destroy,
910 	.reset = atmel_hlcdc_plane_reset,
911 	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
912 	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
913 	.atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
914 	.atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
915 };
916 
917 static struct atmel_hlcdc_plane *
918 atmel_hlcdc_plane_create(struct drm_device *dev,
919 			 const struct atmel_hlcdc_layer_desc *desc,
920 			 struct atmel_hlcdc_plane_properties *props)
921 {
922 	struct atmel_hlcdc_plane *plane;
923 	enum drm_plane_type type;
924 	int ret;
925 
926 	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
927 	if (!plane)
928 		return ERR_PTR(-ENOMEM);
929 
930 	ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
931 	if (ret)
932 		return ERR_PTR(ret);
933 
934 	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
935 		type = DRM_PLANE_TYPE_PRIMARY;
936 	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
937 		type = DRM_PLANE_TYPE_CURSOR;
938 	else
939 		type = DRM_PLANE_TYPE_OVERLAY;
940 
941 	ret = drm_universal_plane_init(dev, &plane->base, 0,
942 				       &layer_plane_funcs,
943 				       desc->formats->formats,
944 				       desc->formats->nformats, type);
945 	if (ret)
946 		return ERR_PTR(ret);
947 
948 	drm_plane_helper_add(&plane->base,
949 			     &atmel_hlcdc_layer_plane_helper_funcs);
950 
951 	/* Set default property values*/
952 	atmel_hlcdc_plane_init_properties(plane, desc, props);
953 
954 	return plane;
955 }
956 
957 static struct atmel_hlcdc_plane_properties *
958 atmel_hlcdc_plane_create_properties(struct drm_device *dev)
959 {
960 	struct atmel_hlcdc_plane_properties *props;
961 
962 	props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
963 	if (!props)
964 		return ERR_PTR(-ENOMEM);
965 
966 	props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
967 	if (!props->alpha)
968 		return ERR_PTR(-ENOMEM);
969 
970 	dev->mode_config.rotation_property =
971 			drm_mode_create_rotation_property(dev,
972 							  BIT(DRM_ROTATE_0) |
973 							  BIT(DRM_ROTATE_90) |
974 							  BIT(DRM_ROTATE_180) |
975 							  BIT(DRM_ROTATE_270));
976 	if (!dev->mode_config.rotation_property)
977 		return ERR_PTR(-ENOMEM);
978 
979 	return props;
980 }
981 
982 struct atmel_hlcdc_planes *
983 atmel_hlcdc_create_planes(struct drm_device *dev)
984 {
985 	struct atmel_hlcdc_dc *dc = dev->dev_private;
986 	struct atmel_hlcdc_plane_properties *props;
987 	struct atmel_hlcdc_planes *planes;
988 	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
989 	int nlayers = dc->desc->nlayers;
990 	int i;
991 
992 	planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
993 	if (!planes)
994 		return ERR_PTR(-ENOMEM);
995 
996 	for (i = 0; i < nlayers; i++) {
997 		if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
998 			planes->noverlays++;
999 	}
1000 
1001 	if (planes->noverlays) {
1002 		planes->overlays = devm_kzalloc(dev->dev,
1003 						planes->noverlays *
1004 						sizeof(*planes->overlays),
1005 						GFP_KERNEL);
1006 		if (!planes->overlays)
1007 			return ERR_PTR(-ENOMEM);
1008 	}
1009 
1010 	props = atmel_hlcdc_plane_create_properties(dev);
1011 	if (IS_ERR(props))
1012 		return ERR_CAST(props);
1013 
1014 	planes->noverlays = 0;
1015 	for (i = 0; i < nlayers; i++) {
1016 		struct atmel_hlcdc_plane *plane;
1017 
1018 		if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
1019 			continue;
1020 
1021 		plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
1022 		if (IS_ERR(plane))
1023 			return ERR_CAST(plane);
1024 
1025 		plane->properties = props;
1026 
1027 		switch (descs[i].type) {
1028 		case ATMEL_HLCDC_BASE_LAYER:
1029 			if (planes->primary)
1030 				return ERR_PTR(-EINVAL);
1031 			planes->primary = plane;
1032 			break;
1033 
1034 		case ATMEL_HLCDC_OVERLAY_LAYER:
1035 			planes->overlays[planes->noverlays++] = plane;
1036 			break;
1037 
1038 		case ATMEL_HLCDC_CURSOR_LAYER:
1039 			if (planes->cursor)
1040 				return ERR_PTR(-EINVAL);
1041 			planes->cursor = plane;
1042 			break;
1043 
1044 		default:
1045 			break;
1046 		}
1047 	}
1048 
1049 	return planes;
1050 }
1051