1/*
2 * Copyright (C) 2014 Free Electrons
3 * Copyright (C) 2014 Atmel
4 *
5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "atmel_hlcdc_dc.h"
21
22/**
23 * Atmel HLCDC Plane state structure.
24 *
25 * @base: DRM plane state
26 * @crtc_x: x position of the plane relative to the CRTC
27 * @crtc_y: y position of the plane relative to the CRTC
28 * @crtc_w: visible width of the plane
29 * @crtc_h: visible height of the plane
30 * @src_x: x buffer position
31 * @src_y: y buffer position
32 * @src_w: buffer width
33 * @src_h: buffer height
34 * @alpha: alpha blending of the plane
35 * @bpp: bytes per pixel deduced from pixel_format
36 * @offsets: offsets to apply to the GEM buffers
37 * @xstride: value to add to the pixel pointer between each line
38 * @pstride: value to add to the pixel pointer between each pixel
39 * @nplanes: number of planes (deduced from pixel_format)
40 */
41struct atmel_hlcdc_plane_state {
42	struct drm_plane_state base;
43	int crtc_x;
44	int crtc_y;
45	unsigned int crtc_w;
46	unsigned int crtc_h;
47	uint32_t src_x;
48	uint32_t src_y;
49	uint32_t src_w;
50	uint32_t src_h;
51
52	u8 alpha;
53
54	bool disc_updated;
55
56	int disc_x;
57	int disc_y;
58	int disc_w;
59	int disc_h;
60
61	/* These fields are private and should not be touched */
62	int bpp[ATMEL_HLCDC_MAX_PLANES];
63	unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
64	int xstride[ATMEL_HLCDC_MAX_PLANES];
65	int pstride[ATMEL_HLCDC_MAX_PLANES];
66	int nplanes;
67};
68
69static inline struct atmel_hlcdc_plane_state *
70drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
71{
72	return container_of(s, struct atmel_hlcdc_plane_state, base);
73}
74
75#define SUBPIXEL_MASK			0xffff
76
77static uint32_t rgb_formats[] = {
78	DRM_FORMAT_XRGB4444,
79	DRM_FORMAT_ARGB4444,
80	DRM_FORMAT_RGBA4444,
81	DRM_FORMAT_ARGB1555,
82	DRM_FORMAT_RGB565,
83	DRM_FORMAT_RGB888,
84	DRM_FORMAT_XRGB8888,
85	DRM_FORMAT_ARGB8888,
86	DRM_FORMAT_RGBA8888,
87};
88
89struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
90	.formats = rgb_formats,
91	.nformats = ARRAY_SIZE(rgb_formats),
92};
93
94static uint32_t rgb_and_yuv_formats[] = {
95	DRM_FORMAT_XRGB4444,
96	DRM_FORMAT_ARGB4444,
97	DRM_FORMAT_RGBA4444,
98	DRM_FORMAT_ARGB1555,
99	DRM_FORMAT_RGB565,
100	DRM_FORMAT_RGB888,
101	DRM_FORMAT_XRGB8888,
102	DRM_FORMAT_ARGB8888,
103	DRM_FORMAT_RGBA8888,
104	DRM_FORMAT_AYUV,
105	DRM_FORMAT_YUYV,
106	DRM_FORMAT_UYVY,
107	DRM_FORMAT_YVYU,
108	DRM_FORMAT_VYUY,
109	DRM_FORMAT_NV21,
110	DRM_FORMAT_NV61,
111	DRM_FORMAT_YUV422,
112	DRM_FORMAT_YUV420,
113};
114
115struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
116	.formats = rgb_and_yuv_formats,
117	.nformats = ARRAY_SIZE(rgb_and_yuv_formats),
118};
119
120static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
121{
122	switch (format) {
123	case DRM_FORMAT_XRGB4444:
124		*mode = ATMEL_HLCDC_XRGB4444_MODE;
125		break;
126	case DRM_FORMAT_ARGB4444:
127		*mode = ATMEL_HLCDC_ARGB4444_MODE;
128		break;
129	case DRM_FORMAT_RGBA4444:
130		*mode = ATMEL_HLCDC_RGBA4444_MODE;
131		break;
132	case DRM_FORMAT_RGB565:
133		*mode = ATMEL_HLCDC_RGB565_MODE;
134		break;
135	case DRM_FORMAT_RGB888:
136		*mode = ATMEL_HLCDC_RGB888_MODE;
137		break;
138	case DRM_FORMAT_ARGB1555:
139		*mode = ATMEL_HLCDC_ARGB1555_MODE;
140		break;
141	case DRM_FORMAT_XRGB8888:
142		*mode = ATMEL_HLCDC_XRGB8888_MODE;
143		break;
144	case DRM_FORMAT_ARGB8888:
145		*mode = ATMEL_HLCDC_ARGB8888_MODE;
146		break;
147	case DRM_FORMAT_RGBA8888:
148		*mode = ATMEL_HLCDC_RGBA8888_MODE;
149		break;
150	case DRM_FORMAT_AYUV:
151		*mode = ATMEL_HLCDC_AYUV_MODE;
152		break;
153	case DRM_FORMAT_YUYV:
154		*mode = ATMEL_HLCDC_YUYV_MODE;
155		break;
156	case DRM_FORMAT_UYVY:
157		*mode = ATMEL_HLCDC_UYVY_MODE;
158		break;
159	case DRM_FORMAT_YVYU:
160		*mode = ATMEL_HLCDC_YVYU_MODE;
161		break;
162	case DRM_FORMAT_VYUY:
163		*mode = ATMEL_HLCDC_VYUY_MODE;
164		break;
165	case DRM_FORMAT_NV21:
166		*mode = ATMEL_HLCDC_NV21_MODE;
167		break;
168	case DRM_FORMAT_NV61:
169		*mode = ATMEL_HLCDC_NV61_MODE;
170		break;
171	case DRM_FORMAT_YUV420:
172		*mode = ATMEL_HLCDC_YUV420_MODE;
173		break;
174	case DRM_FORMAT_YUV422:
175		*mode = ATMEL_HLCDC_YUV422_MODE;
176		break;
177	default:
178		return -ENOTSUPP;
179	}
180
181	return 0;
182}
183
184static bool atmel_hlcdc_format_embeds_alpha(u32 format)
185{
186	int i;
187
188	for (i = 0; i < sizeof(format); i++) {
189		char tmp = (format >> (8 * i)) & 0xff;
190
191		if (tmp == 'A')
192			return true;
193	}
194
195	return false;
196}
197
198static u32 heo_downscaling_xcoef[] = {
199	0x11343311,
200	0x000000f7,
201	0x1635300c,
202	0x000000f9,
203	0x1b362c08,
204	0x000000fb,
205	0x1f372804,
206	0x000000fe,
207	0x24382400,
208	0x00000000,
209	0x28371ffe,
210	0x00000004,
211	0x2c361bfb,
212	0x00000008,
213	0x303516f9,
214	0x0000000c,
215};
216
217static u32 heo_downscaling_ycoef[] = {
218	0x00123737,
219	0x00173732,
220	0x001b382d,
221	0x001f3928,
222	0x00243824,
223	0x0028391f,
224	0x002d381b,
225	0x00323717,
226};
227
228static u32 heo_upscaling_xcoef[] = {
229	0xf74949f7,
230	0x00000000,
231	0xf55f33fb,
232	0x000000fe,
233	0xf5701efe,
234	0x000000ff,
235	0xf87c0dff,
236	0x00000000,
237	0x00800000,
238	0x00000000,
239	0x0d7cf800,
240	0x000000ff,
241	0x1e70f5ff,
242	0x000000fe,
243	0x335ff5fe,
244	0x000000fb,
245};
246
247static u32 heo_upscaling_ycoef[] = {
248	0x00004040,
249	0x00075920,
250	0x00056f0c,
251	0x00027b03,
252	0x00008000,
253	0x00037b02,
254	0x000c6f05,
255	0x00205907,
256};
257
258static void
259atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
260				      struct atmel_hlcdc_plane_state *state)
261{
262	const struct atmel_hlcdc_layer_cfg_layout *layout =
263						&plane->layer.desc->layout;
264
265	if (layout->size)
266		atmel_hlcdc_layer_update_cfg(&plane->layer,
267					     layout->size,
268					     0xffffffff,
269					     (state->crtc_w - 1) |
270					     ((state->crtc_h - 1) << 16));
271
272	if (layout->memsize)
273		atmel_hlcdc_layer_update_cfg(&plane->layer,
274					     layout->memsize,
275					     0xffffffff,
276					     (state->src_w - 1) |
277					     ((state->src_h - 1) << 16));
278
279	if (layout->pos)
280		atmel_hlcdc_layer_update_cfg(&plane->layer,
281					     layout->pos,
282					     0xffffffff,
283					     state->crtc_x |
284					     (state->crtc_y  << 16));
285
286	/* TODO: rework the rescaling part */
287	if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
288		u32 factor_reg = 0;
289
290		if (state->crtc_w != state->src_w) {
291			int i;
292			u32 factor;
293			u32 *coeff_tab = heo_upscaling_xcoef;
294			u32 max_memsize;
295
296			if (state->crtc_w < state->src_w)
297				coeff_tab = heo_downscaling_xcoef;
298			for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
299				atmel_hlcdc_layer_update_cfg(&plane->layer,
300							     17 + i,
301							     0xffffffff,
302							     coeff_tab[i]);
303			factor = ((8 * 256 * state->src_w) - (256 * 4)) /
304				 state->crtc_w;
305			factor++;
306			max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
307				      2048;
308			if (max_memsize > state->src_w)
309				factor--;
310			factor_reg |= factor | 0x80000000;
311		}
312
313		if (state->crtc_h != state->src_h) {
314			int i;
315			u32 factor;
316			u32 *coeff_tab = heo_upscaling_ycoef;
317			u32 max_memsize;
318
319			if (state->crtc_w < state->src_w)
320				coeff_tab = heo_downscaling_ycoef;
321			for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
322				atmel_hlcdc_layer_update_cfg(&plane->layer,
323							     33 + i,
324							     0xffffffff,
325							     coeff_tab[i]);
326			factor = ((8 * 256 * state->src_w) - (256 * 4)) /
327				 state->crtc_w;
328			factor++;
329			max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
330				      2048;
331			if (max_memsize > state->src_w)
332				factor--;
333			factor_reg |= (factor << 16) | 0x80000000;
334		}
335
336		atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
337					     factor_reg);
338	}
339}
340
341static void
342atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
343					struct atmel_hlcdc_plane_state *state)
344{
345	const struct atmel_hlcdc_layer_cfg_layout *layout =
346						&plane->layer.desc->layout;
347	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
348
349	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
350		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
351		       ATMEL_HLCDC_LAYER_ITER;
352
353		if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
354			cfg |= ATMEL_HLCDC_LAYER_LAEN;
355		else
356			cfg |= ATMEL_HLCDC_LAYER_GAEN |
357			       ATMEL_HLCDC_LAYER_GA(state->alpha);
358	}
359
360	atmel_hlcdc_layer_update_cfg(&plane->layer,
361				     ATMEL_HLCDC_LAYER_DMA_CFG_ID,
362				     ATMEL_HLCDC_LAYER_DMA_BLEN_MASK,
363				     ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16);
364
365	atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
366				     ATMEL_HLCDC_LAYER_ITER2BL |
367				     ATMEL_HLCDC_LAYER_ITER |
368				     ATMEL_HLCDC_LAYER_GAEN |
369				     ATMEL_HLCDC_LAYER_GA_MASK |
370				     ATMEL_HLCDC_LAYER_LAEN |
371				     ATMEL_HLCDC_LAYER_OVR |
372				     ATMEL_HLCDC_LAYER_DMA, cfg);
373}
374
375static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
376					struct atmel_hlcdc_plane_state *state)
377{
378	u32 cfg;
379	int ret;
380
381	ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
382					       &cfg);
383	if (ret)
384		return;
385
386	if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 ||
387	     state->base.fb->pixel_format == DRM_FORMAT_NV61) &&
388	    (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
389		cfg |= ATMEL_HLCDC_YUV422ROT;
390
391	atmel_hlcdc_layer_update_cfg(&plane->layer,
392				     ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
393				     0xffffffff,
394				     cfg);
395
396	/*
397	 * Rotation optimization is not working on RGB888 (rotation is still
398	 * working but without any optimization).
399	 */
400	if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
401		cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
402	else
403		cfg = 0;
404
405	atmel_hlcdc_layer_update_cfg(&plane->layer,
406				     ATMEL_HLCDC_LAYER_DMA_CFG_ID,
407				     ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
408}
409
410static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
411					struct atmel_hlcdc_plane_state *state)
412{
413	struct atmel_hlcdc_layer *layer = &plane->layer;
414	const struct atmel_hlcdc_layer_cfg_layout *layout =
415							&layer->desc->layout;
416	int i;
417
418	atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
419					state->offsets);
420
421	for (i = 0; i < state->nplanes; i++) {
422		if (layout->xstride[i]) {
423			atmel_hlcdc_layer_update_cfg(&plane->layer,
424						layout->xstride[i],
425						0xffffffff,
426						state->xstride[i]);
427		}
428
429		if (layout->pstride[i]) {
430			atmel_hlcdc_layer_update_cfg(&plane->layer,
431						layout->pstride[i],
432						0xffffffff,
433						state->pstride[i]);
434		}
435	}
436}
437
438int
439atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
440{
441	int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
442	const struct atmel_hlcdc_layer_cfg_layout *layout;
443	struct atmel_hlcdc_plane_state *primary_state;
444	struct drm_plane_state *primary_s;
445	struct atmel_hlcdc_plane *primary;
446	struct drm_plane *ovl;
447
448	primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
449	layout = &primary->layer.desc->layout;
450	if (!layout->disc_pos || !layout->disc_size)
451		return 0;
452
453	primary_s = drm_atomic_get_plane_state(c_state->state,
454					       &primary->base);
455	if (IS_ERR(primary_s))
456		return PTR_ERR(primary_s);
457
458	primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
459
460	drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
461		struct atmel_hlcdc_plane_state *ovl_state;
462		struct drm_plane_state *ovl_s;
463
464		if (ovl == c_state->crtc->primary)
465			continue;
466
467		ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
468		if (IS_ERR(ovl_s))
469			return PTR_ERR(ovl_s);
470
471		ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
472
473		if (!ovl_s->fb ||
474		    atmel_hlcdc_format_embeds_alpha(ovl_s->fb->pixel_format) ||
475		    ovl_state->alpha != 255)
476			continue;
477
478		/* TODO: implement a smarter hidden area detection */
479		if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
480			continue;
481
482		disc_x = ovl_state->crtc_x;
483		disc_y = ovl_state->crtc_y;
484		disc_h = ovl_state->crtc_h;
485		disc_w = ovl_state->crtc_w;
486	}
487
488	if (disc_x == primary_state->disc_x &&
489	    disc_y == primary_state->disc_y &&
490	    disc_w == primary_state->disc_w &&
491	    disc_h == primary_state->disc_h)
492		return 0;
493
494
495	primary_state->disc_x = disc_x;
496	primary_state->disc_y = disc_y;
497	primary_state->disc_w = disc_w;
498	primary_state->disc_h = disc_h;
499	primary_state->disc_updated = true;
500
501	return 0;
502}
503
504static void
505atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
506				   struct atmel_hlcdc_plane_state *state)
507{
508	const struct atmel_hlcdc_layer_cfg_layout *layout =
509						&plane->layer.desc->layout;
510	int disc_surface = 0;
511
512	if (!state->disc_updated)
513		return;
514
515	disc_surface = state->disc_h * state->disc_w;
516
517	atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
518				ATMEL_HLCDC_LAYER_DISCEN,
519				disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0);
520
521	if (!disc_surface)
522		return;
523
524	atmel_hlcdc_layer_update_cfg(&plane->layer,
525				     layout->disc_pos,
526				     0xffffffff,
527				     state->disc_x | (state->disc_y << 16));
528
529	atmel_hlcdc_layer_update_cfg(&plane->layer,
530				     layout->disc_size,
531				     0xffffffff,
532				     (state->disc_w - 1) |
533				     ((state->disc_h - 1) << 16));
534}
535
536static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
537					  struct drm_plane_state *s)
538{
539	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
540	struct atmel_hlcdc_plane_state *state =
541				drm_plane_state_to_atmel_hlcdc_plane_state(s);
542	const struct atmel_hlcdc_layer_cfg_layout *layout =
543						&plane->layer.desc->layout;
544	struct drm_framebuffer *fb = state->base.fb;
545	const struct drm_display_mode *mode;
546	struct drm_crtc_state *crtc_state;
547	unsigned int patched_crtc_w;
548	unsigned int patched_crtc_h;
549	unsigned int patched_src_w;
550	unsigned int patched_src_h;
551	unsigned int tmp;
552	int x_offset = 0;
553	int y_offset = 0;
554	int hsub = 1;
555	int vsub = 1;
556	int i;
557
558	if (!state->base.crtc || !fb)
559		return 0;
560
561	crtc_state = s->state->crtc_states[drm_crtc_index(s->crtc)];
562	mode = &crtc_state->adjusted_mode;
563
564	state->src_x = s->src_x;
565	state->src_y = s->src_y;
566	state->src_h = s->src_h;
567	state->src_w = s->src_w;
568	state->crtc_x = s->crtc_x;
569	state->crtc_y = s->crtc_y;
570	state->crtc_h = s->crtc_h;
571	state->crtc_w = s->crtc_w;
572	if ((state->src_x | state->src_y | state->src_w | state->src_h) &
573	    SUBPIXEL_MASK)
574		return -EINVAL;
575
576	state->src_x >>= 16;
577	state->src_y >>= 16;
578	state->src_w >>= 16;
579	state->src_h >>= 16;
580
581	state->nplanes = drm_format_num_planes(fb->pixel_format);
582	if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
583		return -EINVAL;
584
585	/*
586	 * Swap width and size in case of 90 or 270 degrees rotation
587	 */
588	if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
589		tmp = state->crtc_w;
590		state->crtc_w = state->crtc_h;
591		state->crtc_h = tmp;
592		tmp = state->src_w;
593		state->src_w = state->src_h;
594		state->src_h = tmp;
595	}
596
597	if (state->crtc_x + state->crtc_w > mode->hdisplay)
598		patched_crtc_w = mode->hdisplay - state->crtc_x;
599	else
600		patched_crtc_w = state->crtc_w;
601
602	if (state->crtc_x < 0) {
603		patched_crtc_w += state->crtc_x;
604		x_offset = -state->crtc_x;
605		state->crtc_x = 0;
606	}
607
608	if (state->crtc_y + state->crtc_h > mode->vdisplay)
609		patched_crtc_h = mode->vdisplay - state->crtc_y;
610	else
611		patched_crtc_h = state->crtc_h;
612
613	if (state->crtc_y < 0) {
614		patched_crtc_h += state->crtc_y;
615		y_offset = -state->crtc_y;
616		state->crtc_y = 0;
617	}
618
619	patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
620					  state->crtc_w);
621	patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
622					  state->crtc_h);
623
624	hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
625	vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
626
627	for (i = 0; i < state->nplanes; i++) {
628		unsigned int offset = 0;
629		int xdiv = i ? hsub : 1;
630		int ydiv = i ? vsub : 1;
631
632		state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
633		if (!state->bpp[i])
634			return -EINVAL;
635
636		switch (state->base.rotation & 0xf) {
637		case BIT(DRM_ROTATE_90):
638			offset = ((y_offset + state->src_y + patched_src_w - 1) /
639				  ydiv) * fb->pitches[i];
640			offset += ((x_offset + state->src_x) / xdiv) *
641				  state->bpp[i];
642			state->xstride[i] = ((patched_src_w - 1) / ydiv) *
643					  fb->pitches[i];
644			state->pstride[i] = -fb->pitches[i] - state->bpp[i];
645			break;
646		case BIT(DRM_ROTATE_180):
647			offset = ((y_offset + state->src_y + patched_src_h - 1) /
648				  ydiv) * fb->pitches[i];
649			offset += ((x_offset + state->src_x + patched_src_w - 1) /
650				   xdiv) * state->bpp[i];
651			state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
652					   state->bpp[i]) - fb->pitches[i];
653			state->pstride[i] = -2 * state->bpp[i];
654			break;
655		case BIT(DRM_ROTATE_270):
656			offset = ((y_offset + state->src_y) / ydiv) *
657				 fb->pitches[i];
658			offset += ((x_offset + state->src_x + patched_src_h - 1) /
659				   xdiv) * state->bpp[i];
660			state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
661					    fb->pitches[i]) -
662					  (2 * state->bpp[i]);
663			state->pstride[i] = fb->pitches[i] - state->bpp[i];
664			break;
665		case BIT(DRM_ROTATE_0):
666		default:
667			offset = ((y_offset + state->src_y) / ydiv) *
668				 fb->pitches[i];
669			offset += ((x_offset + state->src_x) / xdiv) *
670				  state->bpp[i];
671			state->xstride[i] = fb->pitches[i] -
672					  ((patched_src_w / xdiv) *
673					   state->bpp[i]);
674			state->pstride[i] = 0;
675			break;
676		}
677
678		state->offsets[i] = offset + fb->offsets[i];
679	}
680
681	state->src_w = patched_src_w;
682	state->src_h = patched_src_h;
683	state->crtc_w = patched_crtc_w;
684	state->crtc_h = patched_crtc_h;
685
686	if (!layout->size &&
687	    (mode->hdisplay != state->crtc_w ||
688	     mode->vdisplay != state->crtc_h))
689		return -EINVAL;
690
691	if (plane->layer.desc->max_height &&
692	    state->crtc_h > plane->layer.desc->max_height)
693		return -EINVAL;
694
695	if (plane->layer.desc->max_width &&
696	    state->crtc_w > plane->layer.desc->max_width)
697		return -EINVAL;
698
699	if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
700	    (!layout->memsize ||
701	     atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
702		return -EINVAL;
703
704	if (state->crtc_x < 0 || state->crtc_y < 0)
705		return -EINVAL;
706
707	if (state->crtc_w + state->crtc_x > mode->hdisplay ||
708	    state->crtc_h + state->crtc_y > mode->vdisplay)
709		return -EINVAL;
710
711	return 0;
712}
713
714static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
715					struct drm_framebuffer *fb,
716					const struct drm_plane_state *new_state)
717{
718	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
719
720	return atmel_hlcdc_layer_update_start(&plane->layer);
721}
722
723static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
724					    struct drm_plane_state *old_s)
725{
726	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
727	struct atmel_hlcdc_plane_state *state =
728			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
729
730	if (!p->state->crtc || !p->state->fb)
731		return;
732
733	atmel_hlcdc_plane_update_pos_and_size(plane, state);
734	atmel_hlcdc_plane_update_general_settings(plane, state);
735	atmel_hlcdc_plane_update_format(plane, state);
736	atmel_hlcdc_plane_update_buffers(plane, state);
737	atmel_hlcdc_plane_update_disc_area(plane, state);
738
739	atmel_hlcdc_layer_update_commit(&plane->layer);
740}
741
742static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
743					     struct drm_plane_state *old_state)
744{
745	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
746
747	atmel_hlcdc_layer_disable(&plane->layer);
748}
749
750static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
751{
752	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
753
754	if (plane->base.fb)
755		drm_framebuffer_unreference(plane->base.fb);
756
757	atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
758
759	drm_plane_cleanup(p);
760	devm_kfree(p->dev->dev, plane);
761}
762
763static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
764						 struct drm_plane_state *s,
765						 struct drm_property *property,
766						 uint64_t val)
767{
768	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
769	struct atmel_hlcdc_plane_properties *props = plane->properties;
770	struct atmel_hlcdc_plane_state *state =
771			drm_plane_state_to_atmel_hlcdc_plane_state(s);
772
773	if (property == props->alpha)
774		state->alpha = val;
775	else
776		return -EINVAL;
777
778	return 0;
779}
780
781static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
782					const struct drm_plane_state *s,
783					struct drm_property *property,
784					uint64_t *val)
785{
786	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
787	struct atmel_hlcdc_plane_properties *props = plane->properties;
788	const struct atmel_hlcdc_plane_state *state =
789		container_of(s, const struct atmel_hlcdc_plane_state, base);
790
791	if (property == props->alpha)
792		*val = state->alpha;
793	else
794		return -EINVAL;
795
796	return 0;
797}
798
799static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
800				const struct atmel_hlcdc_layer_desc *desc,
801				struct atmel_hlcdc_plane_properties *props)
802{
803	struct regmap *regmap = plane->layer.hlcdc->regmap;
804
805	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
806	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
807		drm_object_attach_property(&plane->base.base,
808					   props->alpha, 255);
809
810		/* Set default alpha value */
811		regmap_update_bits(regmap,
812				desc->regs_offset +
813				ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
814				ATMEL_HLCDC_LAYER_GA_MASK,
815				ATMEL_HLCDC_LAYER_GA_MASK);
816	}
817
818	if (desc->layout.xstride && desc->layout.pstride)
819		drm_object_attach_property(&plane->base.base,
820				plane->base.dev->mode_config.rotation_property,
821				BIT(DRM_ROTATE_0));
822
823	if (desc->layout.csc) {
824		/*
825		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
826		 * userspace modify these factors (using a BLOB property ?).
827		 */
828		regmap_write(regmap,
829			     desc->regs_offset +
830			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
831			     0x4c900091);
832		regmap_write(regmap,
833			     desc->regs_offset +
834			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
835			     0x7a5f5090);
836		regmap_write(regmap,
837			     desc->regs_offset +
838			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
839			     0x40040890);
840	}
841}
842
843static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
844	.prepare_fb = atmel_hlcdc_plane_prepare_fb,
845	.atomic_check = atmel_hlcdc_plane_atomic_check,
846	.atomic_update = atmel_hlcdc_plane_atomic_update,
847	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
848};
849
850static void atmel_hlcdc_plane_reset(struct drm_plane *p)
851{
852	struct atmel_hlcdc_plane_state *state;
853
854	if (p->state) {
855		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
856
857		if (state->base.fb)
858			drm_framebuffer_unreference(state->base.fb);
859
860		kfree(state);
861		p->state = NULL;
862	}
863
864	state = kzalloc(sizeof(*state), GFP_KERNEL);
865	if (state) {
866		state->alpha = 255;
867		p->state = &state->base;
868		p->state->plane = p;
869	}
870}
871
872static struct drm_plane_state *
873atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
874{
875	struct atmel_hlcdc_plane_state *state =
876			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
877	struct atmel_hlcdc_plane_state *copy;
878
879	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
880	if (!copy)
881		return NULL;
882
883	copy->disc_updated = false;
884
885	if (copy->base.fb)
886		drm_framebuffer_reference(copy->base.fb);
887
888	return &copy->base;
889}
890
891static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
892						   struct drm_plane_state *s)
893{
894	struct atmel_hlcdc_plane_state *state =
895			drm_plane_state_to_atmel_hlcdc_plane_state(s);
896
897	if (s->fb)
898		drm_framebuffer_unreference(s->fb);
899
900	kfree(state);
901}
902
903static struct drm_plane_funcs layer_plane_funcs = {
904	.update_plane = drm_atomic_helper_update_plane,
905	.disable_plane = drm_atomic_helper_disable_plane,
906	.set_property = drm_atomic_helper_plane_set_property,
907	.destroy = atmel_hlcdc_plane_destroy,
908	.reset = atmel_hlcdc_plane_reset,
909	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
910	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
911	.atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
912	.atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
913};
914
915static struct atmel_hlcdc_plane *
916atmel_hlcdc_plane_create(struct drm_device *dev,
917			 const struct atmel_hlcdc_layer_desc *desc,
918			 struct atmel_hlcdc_plane_properties *props)
919{
920	struct atmel_hlcdc_plane *plane;
921	enum drm_plane_type type;
922	int ret;
923
924	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
925	if (!plane)
926		return ERR_PTR(-ENOMEM);
927
928	ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
929	if (ret)
930		return ERR_PTR(ret);
931
932	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
933		type = DRM_PLANE_TYPE_PRIMARY;
934	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
935		type = DRM_PLANE_TYPE_CURSOR;
936	else
937		type = DRM_PLANE_TYPE_OVERLAY;
938
939	ret = drm_universal_plane_init(dev, &plane->base, 0,
940				       &layer_plane_funcs,
941				       desc->formats->formats,
942				       desc->formats->nformats, type);
943	if (ret)
944		return ERR_PTR(ret);
945
946	drm_plane_helper_add(&plane->base,
947			     &atmel_hlcdc_layer_plane_helper_funcs);
948
949	/* Set default property values*/
950	atmel_hlcdc_plane_init_properties(plane, desc, props);
951
952	return plane;
953}
954
955static struct atmel_hlcdc_plane_properties *
956atmel_hlcdc_plane_create_properties(struct drm_device *dev)
957{
958	struct atmel_hlcdc_plane_properties *props;
959
960	props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
961	if (!props)
962		return ERR_PTR(-ENOMEM);
963
964	props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
965	if (!props->alpha)
966		return ERR_PTR(-ENOMEM);
967
968	dev->mode_config.rotation_property =
969			drm_mode_create_rotation_property(dev,
970							  BIT(DRM_ROTATE_0) |
971							  BIT(DRM_ROTATE_90) |
972							  BIT(DRM_ROTATE_180) |
973							  BIT(DRM_ROTATE_270));
974	if (!dev->mode_config.rotation_property)
975		return ERR_PTR(-ENOMEM);
976
977	return props;
978}
979
980struct atmel_hlcdc_planes *
981atmel_hlcdc_create_planes(struct drm_device *dev)
982{
983	struct atmel_hlcdc_dc *dc = dev->dev_private;
984	struct atmel_hlcdc_plane_properties *props;
985	struct atmel_hlcdc_planes *planes;
986	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
987	int nlayers = dc->desc->nlayers;
988	int i;
989
990	planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
991	if (!planes)
992		return ERR_PTR(-ENOMEM);
993
994	for (i = 0; i < nlayers; i++) {
995		if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
996			planes->noverlays++;
997	}
998
999	if (planes->noverlays) {
1000		planes->overlays = devm_kzalloc(dev->dev,
1001						planes->noverlays *
1002						sizeof(*planes->overlays),
1003						GFP_KERNEL);
1004		if (!planes->overlays)
1005			return ERR_PTR(-ENOMEM);
1006	}
1007
1008	props = atmel_hlcdc_plane_create_properties(dev);
1009	if (IS_ERR(props))
1010		return ERR_CAST(props);
1011
1012	planes->noverlays = 0;
1013	for (i = 0; i < nlayers; i++) {
1014		struct atmel_hlcdc_plane *plane;
1015
1016		if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
1017			continue;
1018
1019		plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
1020		if (IS_ERR(plane))
1021			return ERR_CAST(plane);
1022
1023		plane->properties = props;
1024
1025		switch (descs[i].type) {
1026		case ATMEL_HLCDC_BASE_LAYER:
1027			if (planes->primary)
1028				return ERR_PTR(-EINVAL);
1029			planes->primary = plane;
1030			break;
1031
1032		case ATMEL_HLCDC_OVERLAY_LAYER:
1033			planes->overlays[planes->noverlays++] = plane;
1034			break;
1035
1036		case ATMEL_HLCDC_CURSOR_LAYER:
1037			if (planes->cursor)
1038				return ERR_PTR(-EINVAL);
1039			planes->cursor = plane;
1040			break;
1041
1042		default:
1043			break;
1044		}
1045	}
1046
1047	return planes;
1048}
1049