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