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