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->visible ||
553 		    !ovl_s->fb ||
554 		    ovl_s->fb->format->has_alpha ||
555 		    ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
556 			continue;
557 
558 		/* TODO: implement a smarter hidden area detection */
559 		if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
560 			continue;
561 
562 		disc_x = ovl_state->crtc_x;
563 		disc_y = ovl_state->crtc_y;
564 		disc_h = ovl_state->crtc_h;
565 		disc_w = ovl_state->crtc_w;
566 	}
567 
568 	primary_state->disc_x = disc_x;
569 	primary_state->disc_y = disc_y;
570 	primary_state->disc_w = disc_w;
571 	primary_state->disc_h = disc_h;
572 
573 	return 0;
574 }
575 
576 static void
577 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
578 				   struct atmel_hlcdc_plane_state *state)
579 {
580 	const struct atmel_hlcdc_layer_cfg_layout *layout;
581 
582 	layout = &plane->layer.desc->layout;
583 	if (!layout->disc_pos || !layout->disc_size)
584 		return;
585 
586 	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
587 				ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
588 							   state->disc_y));
589 
590 	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
591 				ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
592 							    state->disc_h));
593 }
594 
595 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
596 					  struct drm_plane_state *s)
597 {
598 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
599 	struct atmel_hlcdc_plane_state *state =
600 				drm_plane_state_to_atmel_hlcdc_plane_state(s);
601 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
602 	struct drm_framebuffer *fb = state->base.fb;
603 	const struct drm_display_mode *mode;
604 	struct drm_crtc_state *crtc_state;
605 	unsigned int tmp;
606 	int hsub = 1;
607 	int vsub = 1;
608 	int ret;
609 	int i;
610 
611 	if (!state->base.crtc || !fb)
612 		return 0;
613 
614 	crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
615 	mode = &crtc_state->adjusted_mode;
616 
617 	ret = drm_atomic_helper_check_plane_state(s, crtc_state,
618 						  (1 << 16) / 2048,
619 						  INT_MAX, true, true);
620 	if (ret || !s->visible)
621 		return ret;
622 
623 	state->src_x = s->src.x1;
624 	state->src_y = s->src.y1;
625 	state->src_w = drm_rect_width(&s->src);
626 	state->src_h = drm_rect_height(&s->src);
627 	state->crtc_x = s->dst.x1;
628 	state->crtc_y = s->dst.y1;
629 	state->crtc_w = drm_rect_width(&s->dst);
630 	state->crtc_h = drm_rect_height(&s->dst);
631 
632 	if ((state->src_x | state->src_y | state->src_w | state->src_h) &
633 	    SUBPIXEL_MASK)
634 		return -EINVAL;
635 
636 	state->src_x >>= 16;
637 	state->src_y >>= 16;
638 	state->src_w >>= 16;
639 	state->src_h >>= 16;
640 
641 	state->nplanes = fb->format->num_planes;
642 	if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
643 		return -EINVAL;
644 
645 	hsub = drm_format_horz_chroma_subsampling(fb->format->format);
646 	vsub = drm_format_vert_chroma_subsampling(fb->format->format);
647 
648 	for (i = 0; i < state->nplanes; i++) {
649 		unsigned int offset = 0;
650 		int xdiv = i ? hsub : 1;
651 		int ydiv = i ? vsub : 1;
652 
653 		state->bpp[i] = fb->format->cpp[i];
654 		if (!state->bpp[i])
655 			return -EINVAL;
656 
657 		switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
658 		case DRM_MODE_ROTATE_90:
659 			offset = (state->src_y / ydiv) *
660 				 fb->pitches[i];
661 			offset += ((state->src_x + state->src_w - 1) /
662 				   xdiv) * state->bpp[i];
663 			state->xstride[i] = -(((state->src_h - 1) / ydiv) *
664 					    fb->pitches[i]) -
665 					  (2 * state->bpp[i]);
666 			state->pstride[i] = fb->pitches[i] - state->bpp[i];
667 			break;
668 		case DRM_MODE_ROTATE_180:
669 			offset = ((state->src_y + state->src_h - 1) /
670 				  ydiv) * fb->pitches[i];
671 			offset += ((state->src_x + state->src_w - 1) /
672 				   xdiv) * state->bpp[i];
673 			state->xstride[i] = ((((state->src_w - 1) / xdiv) - 1) *
674 					   state->bpp[i]) - fb->pitches[i];
675 			state->pstride[i] = -2 * state->bpp[i];
676 			break;
677 		case DRM_MODE_ROTATE_270:
678 			offset = ((state->src_y + state->src_h - 1) /
679 				  ydiv) * fb->pitches[i];
680 			offset += (state->src_x / xdiv) * state->bpp[i];
681 			state->xstride[i] = ((state->src_h - 1) / ydiv) *
682 					  fb->pitches[i];
683 			state->pstride[i] = -fb->pitches[i] - state->bpp[i];
684 			break;
685 		case DRM_MODE_ROTATE_0:
686 		default:
687 			offset = (state->src_y / ydiv) * fb->pitches[i];
688 			offset += (state->src_x / xdiv) * state->bpp[i];
689 			state->xstride[i] = fb->pitches[i] -
690 					  ((state->src_w / xdiv) *
691 					   state->bpp[i]);
692 			state->pstride[i] = 0;
693 			break;
694 		}
695 
696 		state->offsets[i] = offset + fb->offsets[i];
697 	}
698 
699 	/*
700 	 * Swap width and size in case of 90 or 270 degrees rotation
701 	 */
702 	if (drm_rotation_90_or_270(state->base.rotation)) {
703 		tmp = state->src_w;
704 		state->src_w = state->src_h;
705 		state->src_h = tmp;
706 	}
707 
708 	if (!desc->layout.size &&
709 	    (mode->hdisplay != state->crtc_w ||
710 	     mode->vdisplay != state->crtc_h))
711 		return -EINVAL;
712 
713 	if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
714 	    (!desc->layout.memsize ||
715 	     state->base.fb->format->has_alpha))
716 		return -EINVAL;
717 
718 	return 0;
719 }
720 
721 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
722 					     struct drm_plane_state *old_state)
723 {
724 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
725 
726 	/* Disable interrupts */
727 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
728 				    0xffffffff);
729 
730 	/* Disable the layer */
731 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
732 				    ATMEL_HLCDC_LAYER_RST |
733 				    ATMEL_HLCDC_LAYER_A2Q |
734 				    ATMEL_HLCDC_LAYER_UPDATE);
735 
736 	/* Clear all pending interrupts */
737 	atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
738 }
739 
740 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
741 					    struct drm_plane_state *old_s)
742 {
743 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
744 	struct atmel_hlcdc_plane_state *state =
745 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
746 	u32 sr;
747 
748 	if (!p->state->crtc || !p->state->fb)
749 		return;
750 
751 	if (!state->base.visible) {
752 		atmel_hlcdc_plane_atomic_disable(p, old_s);
753 		return;
754 	}
755 
756 	atmel_hlcdc_plane_update_pos_and_size(plane, state);
757 	atmel_hlcdc_plane_update_general_settings(plane, state);
758 	atmel_hlcdc_plane_update_format(plane, state);
759 	atmel_hlcdc_plane_update_clut(plane, state);
760 	atmel_hlcdc_plane_update_buffers(plane, state);
761 	atmel_hlcdc_plane_update_disc_area(plane, state);
762 
763 	/* Enable the overrun interrupts. */
764 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
765 				    ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
766 				    ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
767 				    ATMEL_HLCDC_LAYER_OVR_IRQ(2));
768 
769 	/* Apply the new config at the next SOF event. */
770 	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
771 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
772 			ATMEL_HLCDC_LAYER_UPDATE |
773 			(sr & ATMEL_HLCDC_LAYER_EN ?
774 			 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
775 }
776 
777 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
778 {
779 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
780 
781 	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
782 	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
783 		int ret;
784 
785 		ret = drm_plane_create_alpha_property(&plane->base);
786 		if (ret)
787 			return ret;
788 	}
789 
790 	if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
791 		int ret;
792 
793 		ret = drm_plane_create_rotation_property(&plane->base,
794 							 DRM_MODE_ROTATE_0,
795 							 DRM_MODE_ROTATE_0 |
796 							 DRM_MODE_ROTATE_90 |
797 							 DRM_MODE_ROTATE_180 |
798 							 DRM_MODE_ROTATE_270);
799 		if (ret)
800 			return ret;
801 	}
802 
803 	if (desc->layout.csc) {
804 		/*
805 		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
806 		 * userspace modify these factors (using a BLOB property ?).
807 		 */
808 		atmel_hlcdc_layer_write_cfg(&plane->layer,
809 					    desc->layout.csc,
810 					    0x4c900091);
811 		atmel_hlcdc_layer_write_cfg(&plane->layer,
812 					    desc->layout.csc + 1,
813 					    0x7a5f5090);
814 		atmel_hlcdc_layer_write_cfg(&plane->layer,
815 					    desc->layout.csc + 2,
816 					    0x40040890);
817 	}
818 
819 	return 0;
820 }
821 
822 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
823 {
824 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
825 	u32 isr;
826 
827 	isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
828 
829 	/*
830 	 * There's not much we can do in case of overrun except informing
831 	 * the user. However, we are in interrupt context here, hence the
832 	 * use of dev_dbg().
833 	 */
834 	if (isr &
835 	    (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
836 	     ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
837 		dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
838 			desc->name);
839 }
840 
841 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
842 	.atomic_check = atmel_hlcdc_plane_atomic_check,
843 	.atomic_update = atmel_hlcdc_plane_atomic_update,
844 	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
845 };
846 
847 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
848 					 struct atmel_hlcdc_plane_state *state)
849 {
850 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
851 	int i;
852 
853 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
854 		struct atmel_hlcdc_dma_channel_dscr *dscr;
855 		dma_addr_t dscr_dma;
856 
857 		dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
858 		if (!dscr)
859 			goto err;
860 
861 		dscr->addr = 0;
862 		dscr->next = dscr_dma;
863 		dscr->self = dscr_dma;
864 		dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
865 
866 		state->dscrs[i] = dscr;
867 	}
868 
869 	return 0;
870 
871 err:
872 	for (i--; i >= 0; i--) {
873 		dma_pool_free(dc->dscrpool, state->dscrs[i],
874 			      state->dscrs[i]->self);
875 	}
876 
877 	return -ENOMEM;
878 }
879 
880 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
881 {
882 	struct atmel_hlcdc_plane_state *state;
883 
884 	if (p->state) {
885 		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
886 
887 		if (state->base.fb)
888 			drm_framebuffer_put(state->base.fb);
889 
890 		kfree(state);
891 		p->state = NULL;
892 	}
893 
894 	state = kzalloc(sizeof(*state), GFP_KERNEL);
895 	if (state) {
896 		if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
897 			kfree(state);
898 			dev_err(p->dev->dev,
899 				"Failed to allocate initial plane state\n");
900 			return;
901 		}
902 		__drm_atomic_helper_plane_reset(p, &state->base);
903 	}
904 }
905 
906 static struct drm_plane_state *
907 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
908 {
909 	struct atmel_hlcdc_plane_state *state =
910 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
911 	struct atmel_hlcdc_plane_state *copy;
912 
913 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
914 	if (!copy)
915 		return NULL;
916 
917 	if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
918 		kfree(copy);
919 		return NULL;
920 	}
921 
922 	if (copy->base.fb)
923 		drm_framebuffer_get(copy->base.fb);
924 
925 	return &copy->base;
926 }
927 
928 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
929 						   struct drm_plane_state *s)
930 {
931 	struct atmel_hlcdc_plane_state *state =
932 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
933 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
934 	int i;
935 
936 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
937 		dma_pool_free(dc->dscrpool, state->dscrs[i],
938 			      state->dscrs[i]->self);
939 	}
940 
941 	if (s->fb)
942 		drm_framebuffer_put(s->fb);
943 
944 	kfree(state);
945 }
946 
947 static const struct drm_plane_funcs layer_plane_funcs = {
948 	.update_plane = drm_atomic_helper_update_plane,
949 	.disable_plane = drm_atomic_helper_disable_plane,
950 	.destroy = drm_plane_cleanup,
951 	.reset = atmel_hlcdc_plane_reset,
952 	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
953 	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
954 };
955 
956 static int atmel_hlcdc_plane_create(struct drm_device *dev,
957 				    const struct atmel_hlcdc_layer_desc *desc)
958 {
959 	struct atmel_hlcdc_dc *dc = dev->dev_private;
960 	struct atmel_hlcdc_plane *plane;
961 	enum drm_plane_type type;
962 	int ret;
963 
964 	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
965 	if (!plane)
966 		return -ENOMEM;
967 
968 	atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
969 
970 	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
971 		type = DRM_PLANE_TYPE_PRIMARY;
972 	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
973 		type = DRM_PLANE_TYPE_CURSOR;
974 	else
975 		type = DRM_PLANE_TYPE_OVERLAY;
976 
977 	ret = drm_universal_plane_init(dev, &plane->base, 0,
978 				       &layer_plane_funcs,
979 				       desc->formats->formats,
980 				       desc->formats->nformats,
981 				       NULL, type, NULL);
982 	if (ret)
983 		return ret;
984 
985 	drm_plane_helper_add(&plane->base,
986 			     &atmel_hlcdc_layer_plane_helper_funcs);
987 
988 	/* Set default property values*/
989 	ret = atmel_hlcdc_plane_init_properties(plane);
990 	if (ret)
991 		return ret;
992 
993 	dc->layers[desc->id] = &plane->layer;
994 
995 	return 0;
996 }
997 
998 int atmel_hlcdc_create_planes(struct drm_device *dev)
999 {
1000 	struct atmel_hlcdc_dc *dc = dev->dev_private;
1001 	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1002 	int nlayers = dc->desc->nlayers;
1003 	int i, ret;
1004 
1005 	dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1006 				sizeof(struct atmel_hlcdc_dma_channel_dscr),
1007 				sizeof(u64), 0);
1008 	if (!dc->dscrpool)
1009 		return -ENOMEM;
1010 
1011 	for (i = 0; i < nlayers; i++) {
1012 		if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1013 		    descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1014 		    descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1015 			continue;
1016 
1017 		ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1018 		if (ret)
1019 			return ret;
1020 	}
1021 
1022 	return 0;
1023 }
1024