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 {
417 	struct drm_crtc *crtc = plane->base.crtc;
418 	struct drm_color_lut *lut;
419 	int idx;
420 
421 	if (!crtc || !crtc->state)
422 		return;
423 
424 	if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
425 		return;
426 
427 	lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
428 
429 	for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
430 		u32 val = ((lut->red << 8) & 0xff0000) |
431 			(lut->green & 0xff00) |
432 			(lut->blue >> 8);
433 
434 		atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
435 	}
436 }
437 
438 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
439 					struct atmel_hlcdc_plane_state *state)
440 {
441 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
442 	struct drm_framebuffer *fb = state->base.fb;
443 	u32 sr;
444 	int i;
445 
446 	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
447 
448 	for (i = 0; i < state->nplanes; i++) {
449 		struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
450 
451 		state->dscrs[i]->addr = gem->paddr + state->offsets[i];
452 
453 		atmel_hlcdc_layer_write_reg(&plane->layer,
454 					    ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
455 					    state->dscrs[i]->self);
456 
457 		if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
458 			atmel_hlcdc_layer_write_reg(&plane->layer,
459 					ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
460 					state->dscrs[i]->addr);
461 			atmel_hlcdc_layer_write_reg(&plane->layer,
462 					ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
463 					state->dscrs[i]->ctrl);
464 			atmel_hlcdc_layer_write_reg(&plane->layer,
465 					ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
466 					state->dscrs[i]->self);
467 		}
468 
469 		if (desc->layout.xstride[i])
470 			atmel_hlcdc_layer_write_cfg(&plane->layer,
471 						    desc->layout.xstride[i],
472 						    state->xstride[i]);
473 
474 		if (desc->layout.pstride[i])
475 			atmel_hlcdc_layer_write_cfg(&plane->layer,
476 						    desc->layout.pstride[i],
477 						    state->pstride[i]);
478 	}
479 }
480 
481 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
482 {
483 	unsigned int ahb_load[2] = { };
484 	struct drm_plane *plane;
485 
486 	drm_atomic_crtc_state_for_each_plane(plane, c_state) {
487 		struct atmel_hlcdc_plane_state *plane_state;
488 		struct drm_plane_state *plane_s;
489 		unsigned int pixels, load = 0;
490 		int i;
491 
492 		plane_s = drm_atomic_get_plane_state(c_state->state, plane);
493 		if (IS_ERR(plane_s))
494 			return PTR_ERR(plane_s);
495 
496 		plane_state =
497 			drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
498 
499 		pixels = (plane_state->src_w * plane_state->src_h) -
500 			 (plane_state->disc_w * plane_state->disc_h);
501 
502 		for (i = 0; i < plane_state->nplanes; i++)
503 			load += pixels * plane_state->bpp[i];
504 
505 		if (ahb_load[0] <= ahb_load[1])
506 			plane_state->ahb_id = 0;
507 		else
508 			plane_state->ahb_id = 1;
509 
510 		ahb_load[plane_state->ahb_id] += load;
511 	}
512 
513 	return 0;
514 }
515 
516 int
517 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
518 {
519 	int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
520 	const struct atmel_hlcdc_layer_cfg_layout *layout;
521 	struct atmel_hlcdc_plane_state *primary_state;
522 	struct drm_plane_state *primary_s;
523 	struct atmel_hlcdc_plane *primary;
524 	struct drm_plane *ovl;
525 
526 	primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
527 	layout = &primary->layer.desc->layout;
528 	if (!layout->disc_pos || !layout->disc_size)
529 		return 0;
530 
531 	primary_s = drm_atomic_get_plane_state(c_state->state,
532 					       &primary->base);
533 	if (IS_ERR(primary_s))
534 		return PTR_ERR(primary_s);
535 
536 	primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
537 
538 	drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
539 		struct atmel_hlcdc_plane_state *ovl_state;
540 		struct drm_plane_state *ovl_s;
541 
542 		if (ovl == c_state->crtc->primary)
543 			continue;
544 
545 		ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
546 		if (IS_ERR(ovl_s))
547 			return PTR_ERR(ovl_s);
548 
549 		ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
550 
551 		if (!ovl_s->fb ||
552 		    ovl_s->fb->format->has_alpha ||
553 		    ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
554 			continue;
555 
556 		/* TODO: implement a smarter hidden area detection */
557 		if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
558 			continue;
559 
560 		disc_x = ovl_state->crtc_x;
561 		disc_y = ovl_state->crtc_y;
562 		disc_h = ovl_state->crtc_h;
563 		disc_w = ovl_state->crtc_w;
564 	}
565 
566 	primary_state->disc_x = disc_x;
567 	primary_state->disc_y = disc_y;
568 	primary_state->disc_w = disc_w;
569 	primary_state->disc_h = disc_h;
570 
571 	return 0;
572 }
573 
574 static void
575 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
576 				   struct atmel_hlcdc_plane_state *state)
577 {
578 	const struct atmel_hlcdc_layer_cfg_layout *layout;
579 
580 	layout = &plane->layer.desc->layout;
581 	if (!layout->disc_pos || !layout->disc_size)
582 		return;
583 
584 	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
585 				ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
586 							   state->disc_y));
587 
588 	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
589 				ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
590 							    state->disc_h));
591 }
592 
593 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
594 					  struct drm_plane_state *s)
595 {
596 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
597 	struct atmel_hlcdc_plane_state *state =
598 				drm_plane_state_to_atmel_hlcdc_plane_state(s);
599 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
600 	struct drm_framebuffer *fb = state->base.fb;
601 	const struct drm_display_mode *mode;
602 	struct drm_crtc_state *crtc_state;
603 	unsigned int patched_crtc_w;
604 	unsigned int patched_crtc_h;
605 	unsigned int patched_src_w;
606 	unsigned int patched_src_h;
607 	unsigned int tmp;
608 	int x_offset = 0;
609 	int y_offset = 0;
610 	int hsub = 1;
611 	int vsub = 1;
612 	int i;
613 
614 	if (!state->base.crtc || !fb)
615 		return 0;
616 
617 	crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
618 	mode = &crtc_state->adjusted_mode;
619 
620 	state->src_x = s->src_x;
621 	state->src_y = s->src_y;
622 	state->src_h = s->src_h;
623 	state->src_w = s->src_w;
624 	state->crtc_x = s->crtc_x;
625 	state->crtc_y = s->crtc_y;
626 	state->crtc_h = s->crtc_h;
627 	state->crtc_w = s->crtc_w;
628 	if ((state->src_x | state->src_y | state->src_w | state->src_h) &
629 	    SUBPIXEL_MASK)
630 		return -EINVAL;
631 
632 	state->src_x >>= 16;
633 	state->src_y >>= 16;
634 	state->src_w >>= 16;
635 	state->src_h >>= 16;
636 
637 	state->nplanes = fb->format->num_planes;
638 	if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
639 		return -EINVAL;
640 
641 	/*
642 	 * Swap width and size in case of 90 or 270 degrees rotation
643 	 */
644 	if (drm_rotation_90_or_270(state->base.rotation)) {
645 		tmp = state->crtc_w;
646 		state->crtc_w = state->crtc_h;
647 		state->crtc_h = tmp;
648 		tmp = state->src_w;
649 		state->src_w = state->src_h;
650 		state->src_h = tmp;
651 	}
652 
653 	if (state->crtc_x + state->crtc_w > mode->hdisplay)
654 		patched_crtc_w = mode->hdisplay - state->crtc_x;
655 	else
656 		patched_crtc_w = state->crtc_w;
657 
658 	if (state->crtc_x < 0) {
659 		patched_crtc_w += state->crtc_x;
660 		x_offset = -state->crtc_x;
661 		state->crtc_x = 0;
662 	}
663 
664 	if (state->crtc_y + state->crtc_h > mode->vdisplay)
665 		patched_crtc_h = mode->vdisplay - state->crtc_y;
666 	else
667 		patched_crtc_h = state->crtc_h;
668 
669 	if (state->crtc_y < 0) {
670 		patched_crtc_h += state->crtc_y;
671 		y_offset = -state->crtc_y;
672 		state->crtc_y = 0;
673 	}
674 
675 	patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
676 					  state->crtc_w);
677 	patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
678 					  state->crtc_h);
679 
680 	hsub = drm_format_horz_chroma_subsampling(fb->format->format);
681 	vsub = drm_format_vert_chroma_subsampling(fb->format->format);
682 
683 	for (i = 0; i < state->nplanes; i++) {
684 		unsigned int offset = 0;
685 		int xdiv = i ? hsub : 1;
686 		int ydiv = i ? vsub : 1;
687 
688 		state->bpp[i] = fb->format->cpp[i];
689 		if (!state->bpp[i])
690 			return -EINVAL;
691 
692 		switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
693 		case DRM_MODE_ROTATE_90:
694 			offset = ((y_offset + state->src_y + patched_src_w - 1) /
695 				  ydiv) * fb->pitches[i];
696 			offset += ((x_offset + state->src_x) / xdiv) *
697 				  state->bpp[i];
698 			state->xstride[i] = ((patched_src_w - 1) / ydiv) *
699 					  fb->pitches[i];
700 			state->pstride[i] = -fb->pitches[i] - state->bpp[i];
701 			break;
702 		case DRM_MODE_ROTATE_180:
703 			offset = ((y_offset + state->src_y + patched_src_h - 1) /
704 				  ydiv) * fb->pitches[i];
705 			offset += ((x_offset + state->src_x + patched_src_w - 1) /
706 				   xdiv) * state->bpp[i];
707 			state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
708 					   state->bpp[i]) - fb->pitches[i];
709 			state->pstride[i] = -2 * state->bpp[i];
710 			break;
711 		case DRM_MODE_ROTATE_270:
712 			offset = ((y_offset + state->src_y) / ydiv) *
713 				 fb->pitches[i];
714 			offset += ((x_offset + state->src_x + patched_src_h - 1) /
715 				   xdiv) * state->bpp[i];
716 			state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
717 					    fb->pitches[i]) -
718 					  (2 * state->bpp[i]);
719 			state->pstride[i] = fb->pitches[i] - state->bpp[i];
720 			break;
721 		case DRM_MODE_ROTATE_0:
722 		default:
723 			offset = ((y_offset + state->src_y) / ydiv) *
724 				 fb->pitches[i];
725 			offset += ((x_offset + state->src_x) / xdiv) *
726 				  state->bpp[i];
727 			state->xstride[i] = fb->pitches[i] -
728 					  ((patched_src_w / xdiv) *
729 					   state->bpp[i]);
730 			state->pstride[i] = 0;
731 			break;
732 		}
733 
734 		state->offsets[i] = offset + fb->offsets[i];
735 	}
736 
737 	state->src_w = patched_src_w;
738 	state->src_h = patched_src_h;
739 	state->crtc_w = patched_crtc_w;
740 	state->crtc_h = patched_crtc_h;
741 
742 	if (!desc->layout.size &&
743 	    (mode->hdisplay != state->crtc_w ||
744 	     mode->vdisplay != state->crtc_h))
745 		return -EINVAL;
746 
747 	if (desc->max_height && state->crtc_h > desc->max_height)
748 		return -EINVAL;
749 
750 	if (desc->max_width && state->crtc_w > desc->max_width)
751 		return -EINVAL;
752 
753 	if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
754 	    (!desc->layout.memsize ||
755 	     state->base.fb->format->has_alpha))
756 		return -EINVAL;
757 
758 	if (state->crtc_x < 0 || state->crtc_y < 0)
759 		return -EINVAL;
760 
761 	if (state->crtc_w + state->crtc_x > mode->hdisplay ||
762 	    state->crtc_h + state->crtc_y > mode->vdisplay)
763 		return -EINVAL;
764 
765 	return 0;
766 }
767 
768 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
769 					    struct drm_plane_state *old_s)
770 {
771 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
772 	struct atmel_hlcdc_plane_state *state =
773 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
774 	u32 sr;
775 
776 	if (!p->state->crtc || !p->state->fb)
777 		return;
778 
779 	atmel_hlcdc_plane_update_pos_and_size(plane, state);
780 	atmel_hlcdc_plane_update_general_settings(plane, state);
781 	atmel_hlcdc_plane_update_format(plane, state);
782 	atmel_hlcdc_plane_update_clut(plane);
783 	atmel_hlcdc_plane_update_buffers(plane, state);
784 	atmel_hlcdc_plane_update_disc_area(plane, state);
785 
786 	/* Enable the overrun interrupts. */
787 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
788 				    ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
789 				    ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
790 				    ATMEL_HLCDC_LAYER_OVR_IRQ(2));
791 
792 	/* Apply the new config at the next SOF event. */
793 	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
794 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
795 			ATMEL_HLCDC_LAYER_UPDATE |
796 			(sr & ATMEL_HLCDC_LAYER_EN ?
797 			 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
798 }
799 
800 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
801 					     struct drm_plane_state *old_state)
802 {
803 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
804 
805 	/* Disable interrupts */
806 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
807 				    0xffffffff);
808 
809 	/* Disable the layer */
810 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
811 				    ATMEL_HLCDC_LAYER_RST |
812 				    ATMEL_HLCDC_LAYER_A2Q |
813 				    ATMEL_HLCDC_LAYER_UPDATE);
814 
815 	/* Clear all pending interrupts */
816 	atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
817 }
818 
819 static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
820 {
821 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
822 
823 	if (plane->base.fb)
824 		drm_framebuffer_put(plane->base.fb);
825 
826 	drm_plane_cleanup(p);
827 }
828 
829 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
830 {
831 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
832 
833 	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
834 	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
835 		int ret;
836 
837 		ret = drm_plane_create_alpha_property(&plane->base);
838 		if (ret)
839 			return ret;
840 	}
841 
842 	if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
843 		int ret;
844 
845 		ret = drm_plane_create_rotation_property(&plane->base,
846 							 DRM_MODE_ROTATE_0,
847 							 DRM_MODE_ROTATE_0 |
848 							 DRM_MODE_ROTATE_90 |
849 							 DRM_MODE_ROTATE_180 |
850 							 DRM_MODE_ROTATE_270);
851 		if (ret)
852 			return ret;
853 	}
854 
855 	if (desc->layout.csc) {
856 		/*
857 		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
858 		 * userspace modify these factors (using a BLOB property ?).
859 		 */
860 		atmel_hlcdc_layer_write_cfg(&plane->layer,
861 					    desc->layout.csc,
862 					    0x4c900091);
863 		atmel_hlcdc_layer_write_cfg(&plane->layer,
864 					    desc->layout.csc + 1,
865 					    0x7a5f5090);
866 		atmel_hlcdc_layer_write_cfg(&plane->layer,
867 					    desc->layout.csc + 2,
868 					    0x40040890);
869 	}
870 
871 	return 0;
872 }
873 
874 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
875 {
876 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
877 	u32 isr;
878 
879 	isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
880 
881 	/*
882 	 * There's not much we can do in case of overrun except informing
883 	 * the user. However, we are in interrupt context here, hence the
884 	 * use of dev_dbg().
885 	 */
886 	if (isr &
887 	    (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
888 	     ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
889 		dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
890 			desc->name);
891 }
892 
893 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
894 	.atomic_check = atmel_hlcdc_plane_atomic_check,
895 	.atomic_update = atmel_hlcdc_plane_atomic_update,
896 	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
897 };
898 
899 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
900 					 struct atmel_hlcdc_plane_state *state)
901 {
902 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
903 	int i;
904 
905 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
906 		struct atmel_hlcdc_dma_channel_dscr *dscr;
907 		dma_addr_t dscr_dma;
908 
909 		dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
910 		if (!dscr)
911 			goto err;
912 
913 		dscr->addr = 0;
914 		dscr->next = dscr_dma;
915 		dscr->self = dscr_dma;
916 		dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
917 
918 		state->dscrs[i] = dscr;
919 	}
920 
921 	return 0;
922 
923 err:
924 	for (i--; i >= 0; i--) {
925 		dma_pool_free(dc->dscrpool, state->dscrs[i],
926 			      state->dscrs[i]->self);
927 	}
928 
929 	return -ENOMEM;
930 }
931 
932 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
933 {
934 	struct atmel_hlcdc_plane_state *state;
935 
936 	if (p->state) {
937 		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
938 
939 		if (state->base.fb)
940 			drm_framebuffer_put(state->base.fb);
941 
942 		kfree(state);
943 		p->state = NULL;
944 	}
945 
946 	state = kzalloc(sizeof(*state), GFP_KERNEL);
947 	if (state) {
948 		if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
949 			kfree(state);
950 			dev_err(p->dev->dev,
951 				"Failed to allocate initial plane state\n");
952 			return;
953 		}
954 
955 		p->state = &state->base;
956 		p->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
957 		p->state->plane = p;
958 	}
959 }
960 
961 static struct drm_plane_state *
962 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
963 {
964 	struct atmel_hlcdc_plane_state *state =
965 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
966 	struct atmel_hlcdc_plane_state *copy;
967 
968 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
969 	if (!copy)
970 		return NULL;
971 
972 	if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
973 		kfree(copy);
974 		return NULL;
975 	}
976 
977 	if (copy->base.fb)
978 		drm_framebuffer_get(copy->base.fb);
979 
980 	return &copy->base;
981 }
982 
983 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
984 						   struct drm_plane_state *s)
985 {
986 	struct atmel_hlcdc_plane_state *state =
987 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
988 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
989 	int i;
990 
991 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
992 		dma_pool_free(dc->dscrpool, state->dscrs[i],
993 			      state->dscrs[i]->self);
994 	}
995 
996 	if (s->fb)
997 		drm_framebuffer_put(s->fb);
998 
999 	kfree(state);
1000 }
1001 
1002 static const struct drm_plane_funcs layer_plane_funcs = {
1003 	.update_plane = drm_atomic_helper_update_plane,
1004 	.disable_plane = drm_atomic_helper_disable_plane,
1005 	.destroy = atmel_hlcdc_plane_destroy,
1006 	.reset = atmel_hlcdc_plane_reset,
1007 	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
1008 	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
1009 };
1010 
1011 static int atmel_hlcdc_plane_create(struct drm_device *dev,
1012 				    const struct atmel_hlcdc_layer_desc *desc)
1013 {
1014 	struct atmel_hlcdc_dc *dc = dev->dev_private;
1015 	struct atmel_hlcdc_plane *plane;
1016 	enum drm_plane_type type;
1017 	int ret;
1018 
1019 	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
1020 	if (!plane)
1021 		return -ENOMEM;
1022 
1023 	atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
1024 
1025 	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1026 		type = DRM_PLANE_TYPE_PRIMARY;
1027 	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1028 		type = DRM_PLANE_TYPE_CURSOR;
1029 	else
1030 		type = DRM_PLANE_TYPE_OVERLAY;
1031 
1032 	ret = drm_universal_plane_init(dev, &plane->base, 0,
1033 				       &layer_plane_funcs,
1034 				       desc->formats->formats,
1035 				       desc->formats->nformats,
1036 				       NULL, type, NULL);
1037 	if (ret)
1038 		return ret;
1039 
1040 	drm_plane_helper_add(&plane->base,
1041 			     &atmel_hlcdc_layer_plane_helper_funcs);
1042 
1043 	/* Set default property values*/
1044 	ret = atmel_hlcdc_plane_init_properties(plane);
1045 	if (ret)
1046 		return ret;
1047 
1048 	dc->layers[desc->id] = &plane->layer;
1049 
1050 	return 0;
1051 }
1052 
1053 int atmel_hlcdc_create_planes(struct drm_device *dev)
1054 {
1055 	struct atmel_hlcdc_dc *dc = dev->dev_private;
1056 	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1057 	int nlayers = dc->desc->nlayers;
1058 	int i, ret;
1059 
1060 	dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1061 				sizeof(struct atmel_hlcdc_dma_channel_dscr),
1062 				sizeof(u64), 0);
1063 	if (!dc->dscrpool)
1064 		return -ENOMEM;
1065 
1066 	for (i = 0; i < nlayers; i++) {
1067 		if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1068 		    descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1069 		    descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1070 			continue;
1071 
1072 		ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1073 		if (ret)
1074 			return ret;
1075 	}
1076 
1077 	return 0;
1078 }
1079