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