11a396789SBoris Brezillon /*
21a396789SBoris Brezillon  * Copyright (C) 2014 Free Electrons
31a396789SBoris Brezillon  * Copyright (C) 2014 Atmel
41a396789SBoris Brezillon  *
51a396789SBoris Brezillon  * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
61a396789SBoris Brezillon  *
71a396789SBoris Brezillon  * This program is free software; you can redistribute it and/or modify it
81a396789SBoris Brezillon  * under the terms of the GNU General Public License version 2 as published by
91a396789SBoris Brezillon  * the Free Software Foundation.
101a396789SBoris Brezillon  *
111a396789SBoris Brezillon  * This program is distributed in the hope that it will be useful, but WITHOUT
121a396789SBoris Brezillon  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131a396789SBoris Brezillon  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
141a396789SBoris Brezillon  * more details.
151a396789SBoris Brezillon  *
161a396789SBoris Brezillon  * You should have received a copy of the GNU General Public License along with
171a396789SBoris Brezillon  * this program.  If not, see <http://www.gnu.org/licenses/>.
181a396789SBoris Brezillon  */
191a396789SBoris Brezillon 
201a396789SBoris Brezillon #include "atmel_hlcdc_dc.h"
211a396789SBoris Brezillon 
222389fc13SBoris Brezillon /**
232389fc13SBoris Brezillon  * Atmel HLCDC Plane state structure.
242389fc13SBoris Brezillon  *
252389fc13SBoris Brezillon  * @base: DRM plane state
262389fc13SBoris Brezillon  * @crtc_x: x position of the plane relative to the CRTC
272389fc13SBoris Brezillon  * @crtc_y: y position of the plane relative to the CRTC
282389fc13SBoris Brezillon  * @crtc_w: visible width of the plane
292389fc13SBoris Brezillon  * @crtc_h: visible height of the plane
302389fc13SBoris Brezillon  * @src_x: x buffer position
312389fc13SBoris Brezillon  * @src_y: y buffer position
322389fc13SBoris Brezillon  * @src_w: buffer width
332389fc13SBoris Brezillon  * @src_h: buffer height
342389fc13SBoris Brezillon  * @alpha: alpha blending of the plane
359a45d33cSBoris Brezillon  * @disc_x: x discard position
369a45d33cSBoris Brezillon  * @disc_y: y discard position
379a45d33cSBoris Brezillon  * @disc_w: discard width
389a45d33cSBoris Brezillon  * @disc_h: discard height
392389fc13SBoris Brezillon  * @bpp: bytes per pixel deduced from pixel_format
402389fc13SBoris Brezillon  * @offsets: offsets to apply to the GEM buffers
412389fc13SBoris Brezillon  * @xstride: value to add to the pixel pointer between each line
422389fc13SBoris Brezillon  * @pstride: value to add to the pixel pointer between each pixel
432389fc13SBoris Brezillon  * @nplanes: number of planes (deduced from pixel_format)
449a45d33cSBoris Brezillon  * @dscrs: DMA descriptors
452389fc13SBoris Brezillon  */
462389fc13SBoris Brezillon struct atmel_hlcdc_plane_state {
472389fc13SBoris Brezillon 	struct drm_plane_state base;
482389fc13SBoris Brezillon 	int crtc_x;
492389fc13SBoris Brezillon 	int crtc_y;
502389fc13SBoris Brezillon 	unsigned int crtc_w;
512389fc13SBoris Brezillon 	unsigned int crtc_h;
522389fc13SBoris Brezillon 	uint32_t src_x;
532389fc13SBoris Brezillon 	uint32_t src_y;
542389fc13SBoris Brezillon 	uint32_t src_w;
552389fc13SBoris Brezillon 	uint32_t src_h;
562389fc13SBoris Brezillon 
572389fc13SBoris Brezillon 	u8 alpha;
582389fc13SBoris Brezillon 
595957017dSBoris Brezillon 	int disc_x;
605957017dSBoris Brezillon 	int disc_y;
615957017dSBoris Brezillon 	int disc_w;
625957017dSBoris Brezillon 	int disc_h;
635957017dSBoris Brezillon 
64ebab87abSBoris Brezillon 	int ahb_id;
65ebab87abSBoris Brezillon 
662389fc13SBoris Brezillon 	/* These fields are private and should not be touched */
679a45d33cSBoris Brezillon 	int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
689a45d33cSBoris Brezillon 	unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
699a45d33cSBoris Brezillon 	int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
709a45d33cSBoris Brezillon 	int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
712389fc13SBoris Brezillon 	int nplanes;
729a45d33cSBoris Brezillon 
739a45d33cSBoris Brezillon 	/* DMA descriptors. */
749a45d33cSBoris Brezillon 	struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
752389fc13SBoris Brezillon };
762389fc13SBoris Brezillon 
772389fc13SBoris Brezillon static inline struct atmel_hlcdc_plane_state *
782389fc13SBoris Brezillon drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
792389fc13SBoris Brezillon {
802389fc13SBoris Brezillon 	return container_of(s, struct atmel_hlcdc_plane_state, base);
812389fc13SBoris Brezillon }
822389fc13SBoris Brezillon 
831a396789SBoris Brezillon #define SUBPIXEL_MASK			0xffff
841a396789SBoris Brezillon 
851a396789SBoris Brezillon static uint32_t rgb_formats[] = {
861a396789SBoris Brezillon 	DRM_FORMAT_XRGB4444,
871a396789SBoris Brezillon 	DRM_FORMAT_ARGB4444,
881a396789SBoris Brezillon 	DRM_FORMAT_RGBA4444,
891a396789SBoris Brezillon 	DRM_FORMAT_ARGB1555,
901a396789SBoris Brezillon 	DRM_FORMAT_RGB565,
911a396789SBoris Brezillon 	DRM_FORMAT_RGB888,
921a396789SBoris Brezillon 	DRM_FORMAT_XRGB8888,
931a396789SBoris Brezillon 	DRM_FORMAT_ARGB8888,
941a396789SBoris Brezillon 	DRM_FORMAT_RGBA8888,
951a396789SBoris Brezillon };
961a396789SBoris Brezillon 
971a396789SBoris Brezillon struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
981a396789SBoris Brezillon 	.formats = rgb_formats,
991a396789SBoris Brezillon 	.nformats = ARRAY_SIZE(rgb_formats),
1001a396789SBoris Brezillon };
1011a396789SBoris Brezillon 
1021a396789SBoris Brezillon static uint32_t rgb_and_yuv_formats[] = {
1031a396789SBoris Brezillon 	DRM_FORMAT_XRGB4444,
1041a396789SBoris Brezillon 	DRM_FORMAT_ARGB4444,
1051a396789SBoris Brezillon 	DRM_FORMAT_RGBA4444,
1061a396789SBoris Brezillon 	DRM_FORMAT_ARGB1555,
1071a396789SBoris Brezillon 	DRM_FORMAT_RGB565,
1081a396789SBoris Brezillon 	DRM_FORMAT_RGB888,
1091a396789SBoris Brezillon 	DRM_FORMAT_XRGB8888,
1101a396789SBoris Brezillon 	DRM_FORMAT_ARGB8888,
1111a396789SBoris Brezillon 	DRM_FORMAT_RGBA8888,
1121a396789SBoris Brezillon 	DRM_FORMAT_AYUV,
1131a396789SBoris Brezillon 	DRM_FORMAT_YUYV,
1141a396789SBoris Brezillon 	DRM_FORMAT_UYVY,
1151a396789SBoris Brezillon 	DRM_FORMAT_YVYU,
1161a396789SBoris Brezillon 	DRM_FORMAT_VYUY,
1171a396789SBoris Brezillon 	DRM_FORMAT_NV21,
1181a396789SBoris Brezillon 	DRM_FORMAT_NV61,
1191a396789SBoris Brezillon 	DRM_FORMAT_YUV422,
1201a396789SBoris Brezillon 	DRM_FORMAT_YUV420,
1211a396789SBoris Brezillon };
1221a396789SBoris Brezillon 
1231a396789SBoris Brezillon struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
1241a396789SBoris Brezillon 	.formats = rgb_and_yuv_formats,
1251a396789SBoris Brezillon 	.nformats = ARRAY_SIZE(rgb_and_yuv_formats),
1261a396789SBoris Brezillon };
1271a396789SBoris Brezillon 
1281a396789SBoris Brezillon static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
1291a396789SBoris Brezillon {
1301a396789SBoris Brezillon 	switch (format) {
1311a396789SBoris Brezillon 	case DRM_FORMAT_XRGB4444:
1321a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_XRGB4444_MODE;
1331a396789SBoris Brezillon 		break;
1341a396789SBoris Brezillon 	case DRM_FORMAT_ARGB4444:
1351a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_ARGB4444_MODE;
1361a396789SBoris Brezillon 		break;
1371a396789SBoris Brezillon 	case DRM_FORMAT_RGBA4444:
1381a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGBA4444_MODE;
1391a396789SBoris Brezillon 		break;
1401a396789SBoris Brezillon 	case DRM_FORMAT_RGB565:
1411a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGB565_MODE;
1421a396789SBoris Brezillon 		break;
1431a396789SBoris Brezillon 	case DRM_FORMAT_RGB888:
1441a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGB888_MODE;
1451a396789SBoris Brezillon 		break;
1461a396789SBoris Brezillon 	case DRM_FORMAT_ARGB1555:
1471a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_ARGB1555_MODE;
1481a396789SBoris Brezillon 		break;
1491a396789SBoris Brezillon 	case DRM_FORMAT_XRGB8888:
1501a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_XRGB8888_MODE;
1511a396789SBoris Brezillon 		break;
1521a396789SBoris Brezillon 	case DRM_FORMAT_ARGB8888:
1531a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_ARGB8888_MODE;
1541a396789SBoris Brezillon 		break;
1551a396789SBoris Brezillon 	case DRM_FORMAT_RGBA8888:
1561a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGBA8888_MODE;
1571a396789SBoris Brezillon 		break;
1581a396789SBoris Brezillon 	case DRM_FORMAT_AYUV:
1591a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_AYUV_MODE;
1601a396789SBoris Brezillon 		break;
1611a396789SBoris Brezillon 	case DRM_FORMAT_YUYV:
1621a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YUYV_MODE;
1631a396789SBoris Brezillon 		break;
1641a396789SBoris Brezillon 	case DRM_FORMAT_UYVY:
1651a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_UYVY_MODE;
1661a396789SBoris Brezillon 		break;
1671a396789SBoris Brezillon 	case DRM_FORMAT_YVYU:
1681a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YVYU_MODE;
1691a396789SBoris Brezillon 		break;
1701a396789SBoris Brezillon 	case DRM_FORMAT_VYUY:
1711a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_VYUY_MODE;
1721a396789SBoris Brezillon 		break;
1731a396789SBoris Brezillon 	case DRM_FORMAT_NV21:
1741a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_NV21_MODE;
1751a396789SBoris Brezillon 		break;
1761a396789SBoris Brezillon 	case DRM_FORMAT_NV61:
1771a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_NV61_MODE;
1781a396789SBoris Brezillon 		break;
1791a396789SBoris Brezillon 	case DRM_FORMAT_YUV420:
1801a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YUV420_MODE;
1811a396789SBoris Brezillon 		break;
1821a396789SBoris Brezillon 	case DRM_FORMAT_YUV422:
1831a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YUV422_MODE;
1841a396789SBoris Brezillon 		break;
1851a396789SBoris Brezillon 	default:
1861a396789SBoris Brezillon 		return -ENOTSUPP;
1871a396789SBoris Brezillon 	}
1881a396789SBoris Brezillon 
1891a396789SBoris Brezillon 	return 0;
1901a396789SBoris Brezillon }
1911a396789SBoris Brezillon 
1922389fc13SBoris Brezillon static bool atmel_hlcdc_format_embeds_alpha(u32 format)
1931a396789SBoris Brezillon {
1941a396789SBoris Brezillon 	int i;
1951a396789SBoris Brezillon 
1961a396789SBoris Brezillon 	for (i = 0; i < sizeof(format); i++) {
1971a396789SBoris Brezillon 		char tmp = (format >> (8 * i)) & 0xff;
1981a396789SBoris Brezillon 
1991a396789SBoris Brezillon 		if (tmp == 'A')
2001a396789SBoris Brezillon 			return true;
2011a396789SBoris Brezillon 	}
2021a396789SBoris Brezillon 
2031a396789SBoris Brezillon 	return false;
2041a396789SBoris Brezillon }
2051a396789SBoris Brezillon 
2061a396789SBoris Brezillon static u32 heo_downscaling_xcoef[] = {
2071a396789SBoris Brezillon 	0x11343311,
2081a396789SBoris Brezillon 	0x000000f7,
2091a396789SBoris Brezillon 	0x1635300c,
2101a396789SBoris Brezillon 	0x000000f9,
2111a396789SBoris Brezillon 	0x1b362c08,
2121a396789SBoris Brezillon 	0x000000fb,
2131a396789SBoris Brezillon 	0x1f372804,
2141a396789SBoris Brezillon 	0x000000fe,
2151a396789SBoris Brezillon 	0x24382400,
2161a396789SBoris Brezillon 	0x00000000,
2171a396789SBoris Brezillon 	0x28371ffe,
2181a396789SBoris Brezillon 	0x00000004,
2191a396789SBoris Brezillon 	0x2c361bfb,
2201a396789SBoris Brezillon 	0x00000008,
2211a396789SBoris Brezillon 	0x303516f9,
2221a396789SBoris Brezillon 	0x0000000c,
2231a396789SBoris Brezillon };
2241a396789SBoris Brezillon 
2251a396789SBoris Brezillon static u32 heo_downscaling_ycoef[] = {
2261a396789SBoris Brezillon 	0x00123737,
2271a396789SBoris Brezillon 	0x00173732,
2281a396789SBoris Brezillon 	0x001b382d,
2291a396789SBoris Brezillon 	0x001f3928,
2301a396789SBoris Brezillon 	0x00243824,
2311a396789SBoris Brezillon 	0x0028391f,
2321a396789SBoris Brezillon 	0x002d381b,
2331a396789SBoris Brezillon 	0x00323717,
2341a396789SBoris Brezillon };
2351a396789SBoris Brezillon 
2361a396789SBoris Brezillon static u32 heo_upscaling_xcoef[] = {
2371a396789SBoris Brezillon 	0xf74949f7,
2381a396789SBoris Brezillon 	0x00000000,
2391a396789SBoris Brezillon 	0xf55f33fb,
2401a396789SBoris Brezillon 	0x000000fe,
2411a396789SBoris Brezillon 	0xf5701efe,
2421a396789SBoris Brezillon 	0x000000ff,
2431a396789SBoris Brezillon 	0xf87c0dff,
2441a396789SBoris Brezillon 	0x00000000,
2451a396789SBoris Brezillon 	0x00800000,
2461a396789SBoris Brezillon 	0x00000000,
2471a396789SBoris Brezillon 	0x0d7cf800,
2481a396789SBoris Brezillon 	0x000000ff,
2491a396789SBoris Brezillon 	0x1e70f5ff,
2501a396789SBoris Brezillon 	0x000000fe,
2511a396789SBoris Brezillon 	0x335ff5fe,
2521a396789SBoris Brezillon 	0x000000fb,
2531a396789SBoris Brezillon };
2541a396789SBoris Brezillon 
2551a396789SBoris Brezillon static u32 heo_upscaling_ycoef[] = {
2561a396789SBoris Brezillon 	0x00004040,
2571a396789SBoris Brezillon 	0x00075920,
2581a396789SBoris Brezillon 	0x00056f0c,
2591a396789SBoris Brezillon 	0x00027b03,
2601a396789SBoris Brezillon 	0x00008000,
2611a396789SBoris Brezillon 	0x00037b02,
2621a396789SBoris Brezillon 	0x000c6f05,
2631a396789SBoris Brezillon 	0x00205907,
2641a396789SBoris Brezillon };
2651a396789SBoris Brezillon 
2669a45d33cSBoris Brezillon #define ATMEL_HLCDC_XPHIDEF	4
2679a45d33cSBoris Brezillon #define ATMEL_HLCDC_YPHIDEF	4
2689a45d33cSBoris Brezillon 
2699a45d33cSBoris Brezillon static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
2709a45d33cSBoris Brezillon 						  u32 dstsize,
2719a45d33cSBoris Brezillon 						  u32 phidef)
2729a45d33cSBoris Brezillon {
2739a45d33cSBoris Brezillon 	u32 factor, max_memsize;
2749a45d33cSBoris Brezillon 
2759a45d33cSBoris Brezillon 	factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
2769a45d33cSBoris Brezillon 	max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
2779a45d33cSBoris Brezillon 
2789a45d33cSBoris Brezillon 	if (max_memsize > srcsize - 1)
2799a45d33cSBoris Brezillon 		factor--;
2809a45d33cSBoris Brezillon 
2819a45d33cSBoris Brezillon 	return factor;
2829a45d33cSBoris Brezillon }
2839a45d33cSBoris Brezillon 
2849a45d33cSBoris Brezillon static void
2859a45d33cSBoris Brezillon atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
2869a45d33cSBoris Brezillon 				      const u32 *coeff_tab, int size,
2879a45d33cSBoris Brezillon 				      unsigned int cfg_offs)
2889a45d33cSBoris Brezillon {
2899a45d33cSBoris Brezillon 	int i;
2909a45d33cSBoris Brezillon 
2919a45d33cSBoris Brezillon 	for (i = 0; i < size; i++)
2929a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
2939a45d33cSBoris Brezillon 					    coeff_tab[i]);
2949a45d33cSBoris Brezillon }
2959a45d33cSBoris Brezillon 
2969a45d33cSBoris Brezillon void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
2979a45d33cSBoris Brezillon 				    struct atmel_hlcdc_plane_state *state)
2989a45d33cSBoris Brezillon {
2999a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
3009a45d33cSBoris Brezillon 	u32 xfactor, yfactor;
3019a45d33cSBoris Brezillon 
3029a45d33cSBoris Brezillon 	if (!desc->layout.scaler_config)
3039a45d33cSBoris Brezillon 		return;
3049a45d33cSBoris Brezillon 
3059a45d33cSBoris Brezillon 	if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
3069a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer,
3079a45d33cSBoris Brezillon 					    desc->layout.scaler_config, 0);
3089a45d33cSBoris Brezillon 		return;
3099a45d33cSBoris Brezillon 	}
3109a45d33cSBoris Brezillon 
3119a45d33cSBoris Brezillon 	if (desc->layout.phicoeffs.x) {
3129a45d33cSBoris Brezillon 		xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
3139a45d33cSBoris Brezillon 							state->crtc_w,
3149a45d33cSBoris Brezillon 							ATMEL_HLCDC_XPHIDEF);
3159a45d33cSBoris Brezillon 
3169a45d33cSBoris Brezillon 		yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
3179a45d33cSBoris Brezillon 							state->crtc_h,
3189a45d33cSBoris Brezillon 							ATMEL_HLCDC_YPHIDEF);
3199a45d33cSBoris Brezillon 
3209a45d33cSBoris Brezillon 		atmel_hlcdc_plane_scaler_set_phicoeff(plane,
3219a45d33cSBoris Brezillon 				state->crtc_w < state->src_w ?
3229a45d33cSBoris Brezillon 				heo_downscaling_xcoef :
3239a45d33cSBoris Brezillon 				heo_upscaling_xcoef,
3249a45d33cSBoris Brezillon 				ARRAY_SIZE(heo_upscaling_xcoef),
3259a45d33cSBoris Brezillon 				desc->layout.phicoeffs.x);
3269a45d33cSBoris Brezillon 
3279a45d33cSBoris Brezillon 		atmel_hlcdc_plane_scaler_set_phicoeff(plane,
3289a45d33cSBoris Brezillon 				state->crtc_h < state->src_h ?
3299a45d33cSBoris Brezillon 				heo_downscaling_ycoef :
3309a45d33cSBoris Brezillon 				heo_upscaling_ycoef,
3319a45d33cSBoris Brezillon 				ARRAY_SIZE(heo_upscaling_ycoef),
3329a45d33cSBoris Brezillon 				desc->layout.phicoeffs.y);
3339a45d33cSBoris Brezillon 	} else {
3349a45d33cSBoris Brezillon 		xfactor = (1024 * state->src_w) / state->crtc_w;
3359a45d33cSBoris Brezillon 		yfactor = (1024 * state->src_h) / state->crtc_h;
3369a45d33cSBoris Brezillon 	}
3379a45d33cSBoris Brezillon 
3389a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
3399a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_SCALER_ENABLE |
3409a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
3419a45d33cSBoris Brezillon 								     yfactor));
3429a45d33cSBoris Brezillon }
3439a45d33cSBoris Brezillon 
3441a396789SBoris Brezillon static void
3451a396789SBoris Brezillon atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
3462389fc13SBoris Brezillon 				      struct atmel_hlcdc_plane_state *state)
3471a396789SBoris Brezillon {
3489a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
3491a396789SBoris Brezillon 
3509a45d33cSBoris Brezillon 	if (desc->layout.size)
3519a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
3529a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
3539a45d33cSBoris Brezillon 							       state->crtc_h));
3541a396789SBoris Brezillon 
3559a45d33cSBoris Brezillon 	if (desc->layout.memsize)
3569a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer,
3579a45d33cSBoris Brezillon 					desc->layout.memsize,
3589a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_SIZE(state->src_w,
3599a45d33cSBoris Brezillon 							       state->src_h));
3601a396789SBoris Brezillon 
3619a45d33cSBoris Brezillon 	if (desc->layout.pos)
3629a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
3639a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_POS(state->crtc_x,
3649a45d33cSBoris Brezillon 							      state->crtc_y));
3651a396789SBoris Brezillon 
3669a45d33cSBoris Brezillon 	atmel_hlcdc_plane_setup_scaler(plane, state);
3671a396789SBoris Brezillon }
3681a396789SBoris Brezillon 
3691a396789SBoris Brezillon static void
3701a396789SBoris Brezillon atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
3712389fc13SBoris Brezillon 					struct atmel_hlcdc_plane_state *state)
3721a396789SBoris Brezillon {
3739a45d33cSBoris Brezillon 	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
3749a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
3759a45d33cSBoris Brezillon 	u32 format = state->base.fb->format->format;
3769a45d33cSBoris Brezillon 
3779a45d33cSBoris Brezillon 	/*
3789a45d33cSBoris Brezillon 	 * Rotation optimization is not working on RGB888 (rotation is still
3799a45d33cSBoris Brezillon 	 * working but without any optimization).
3809a45d33cSBoris Brezillon 	 */
3819a45d33cSBoris Brezillon 	if (format == DRM_FORMAT_RGB888)
3829a45d33cSBoris Brezillon 		cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
3839a45d33cSBoris Brezillon 
3849a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
3859a45d33cSBoris Brezillon 				    cfg);
3869a45d33cSBoris Brezillon 
3879a45d33cSBoris Brezillon 	cfg = ATMEL_HLCDC_LAYER_DMA;
3881a396789SBoris Brezillon 
3891a396789SBoris Brezillon 	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
3901a396789SBoris Brezillon 		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
3911a396789SBoris Brezillon 		       ATMEL_HLCDC_LAYER_ITER;
3921a396789SBoris Brezillon 
3939a45d33cSBoris Brezillon 		if (atmel_hlcdc_format_embeds_alpha(format))
3941a396789SBoris Brezillon 			cfg |= ATMEL_HLCDC_LAYER_LAEN;
3951a396789SBoris Brezillon 		else
3962389fc13SBoris Brezillon 			cfg |= ATMEL_HLCDC_LAYER_GAEN |
3972389fc13SBoris Brezillon 			       ATMEL_HLCDC_LAYER_GA(state->alpha);
3981a396789SBoris Brezillon 	}
3991a396789SBoris Brezillon 
4009a45d33cSBoris Brezillon 	if (state->disc_h && state->disc_w)
4019a45d33cSBoris Brezillon 		cfg |= ATMEL_HLCDC_LAYER_DISCEN;
4021a396789SBoris Brezillon 
4039a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
4049a45d33cSBoris Brezillon 				    cfg);
4051a396789SBoris Brezillon }
4061a396789SBoris Brezillon 
4071a396789SBoris Brezillon static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
4082389fc13SBoris Brezillon 					struct atmel_hlcdc_plane_state *state)
4091a396789SBoris Brezillon {
4101a396789SBoris Brezillon 	u32 cfg;
4111a396789SBoris Brezillon 	int ret;
4121a396789SBoris Brezillon 
413438b74a5SVille Syrjälä 	ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
4142389fc13SBoris Brezillon 					       &cfg);
4151a396789SBoris Brezillon 	if (ret)
4161a396789SBoris Brezillon 		return;
4171a396789SBoris Brezillon 
418438b74a5SVille Syrjälä 	if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
419438b74a5SVille Syrjälä 	     state->base.fb->format->format == DRM_FORMAT_NV61) &&
420bd2ef25dSVille Syrjälä 	    drm_rotation_90_or_270(state->base.rotation))
4211a396789SBoris Brezillon 		cfg |= ATMEL_HLCDC_YUV422ROT;
4221a396789SBoris Brezillon 
4239a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer,
4249a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
4251a396789SBoris Brezillon }
4261a396789SBoris Brezillon 
4271a396789SBoris Brezillon static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
4282389fc13SBoris Brezillon 					struct atmel_hlcdc_plane_state *state)
4291a396789SBoris Brezillon {
4309a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
4319a45d33cSBoris Brezillon 	struct drm_framebuffer *fb = state->base.fb;
4329a45d33cSBoris Brezillon 	u32 sr;
4331a396789SBoris Brezillon 	int i;
4341a396789SBoris Brezillon 
4359a45d33cSBoris Brezillon 	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
4361a396789SBoris Brezillon 
4372389fc13SBoris Brezillon 	for (i = 0; i < state->nplanes; i++) {
4389a45d33cSBoris Brezillon 		struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
4399a45d33cSBoris Brezillon 
4409a45d33cSBoris Brezillon 		state->dscrs[i]->addr = gem->paddr + state->offsets[i];
4419a45d33cSBoris Brezillon 
4429a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_reg(&plane->layer,
4439a45d33cSBoris Brezillon 					    ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
4449a45d33cSBoris Brezillon 					    state->dscrs[i]->self);
4459a45d33cSBoris Brezillon 
4469a45d33cSBoris Brezillon 		if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
4479a45d33cSBoris Brezillon 			atmel_hlcdc_layer_write_reg(&plane->layer,
4489a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
4499a45d33cSBoris Brezillon 					state->dscrs[i]->addr);
4509a45d33cSBoris Brezillon 			atmel_hlcdc_layer_write_reg(&plane->layer,
4519a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
4529a45d33cSBoris Brezillon 					state->dscrs[i]->ctrl);
4539a45d33cSBoris Brezillon 			atmel_hlcdc_layer_write_reg(&plane->layer,
4549a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
4559a45d33cSBoris Brezillon 					state->dscrs[i]->self);
4561a396789SBoris Brezillon 		}
4571a396789SBoris Brezillon 
4589a45d33cSBoris Brezillon 		if (desc->layout.xstride[i])
4599a45d33cSBoris Brezillon 			atmel_hlcdc_layer_write_cfg(&plane->layer,
4609a45d33cSBoris Brezillon 						    desc->layout.xstride[i],
4619a45d33cSBoris Brezillon 						    state->xstride[i]);
4629a45d33cSBoris Brezillon 
4639a45d33cSBoris Brezillon 		if (desc->layout.pstride[i])
4649a45d33cSBoris Brezillon 			atmel_hlcdc_layer_write_cfg(&plane->layer,
4659a45d33cSBoris Brezillon 						    desc->layout.pstride[i],
4662389fc13SBoris Brezillon 						    state->pstride[i]);
4671a396789SBoris Brezillon 	}
4681a396789SBoris Brezillon }
4691a396789SBoris Brezillon 
470ebab87abSBoris Brezillon int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
471ebab87abSBoris Brezillon {
472ebab87abSBoris Brezillon 	unsigned int ahb_load[2] = { };
473ebab87abSBoris Brezillon 	struct drm_plane *plane;
474ebab87abSBoris Brezillon 
475ebab87abSBoris Brezillon 	drm_atomic_crtc_state_for_each_plane(plane, c_state) {
476ebab87abSBoris Brezillon 		struct atmel_hlcdc_plane_state *plane_state;
477ebab87abSBoris Brezillon 		struct drm_plane_state *plane_s;
478ebab87abSBoris Brezillon 		unsigned int pixels, load = 0;
479ebab87abSBoris Brezillon 		int i;
480ebab87abSBoris Brezillon 
481ebab87abSBoris Brezillon 		plane_s = drm_atomic_get_plane_state(c_state->state, plane);
482ebab87abSBoris Brezillon 		if (IS_ERR(plane_s))
483ebab87abSBoris Brezillon 			return PTR_ERR(plane_s);
484ebab87abSBoris Brezillon 
485ebab87abSBoris Brezillon 		plane_state =
486ebab87abSBoris Brezillon 			drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
487ebab87abSBoris Brezillon 
488ebab87abSBoris Brezillon 		pixels = (plane_state->src_w * plane_state->src_h) -
489ebab87abSBoris Brezillon 			 (plane_state->disc_w * plane_state->disc_h);
490ebab87abSBoris Brezillon 
491ebab87abSBoris Brezillon 		for (i = 0; i < plane_state->nplanes; i++)
492ebab87abSBoris Brezillon 			load += pixels * plane_state->bpp[i];
493ebab87abSBoris Brezillon 
494ebab87abSBoris Brezillon 		if (ahb_load[0] <= ahb_load[1])
495ebab87abSBoris Brezillon 			plane_state->ahb_id = 0;
496ebab87abSBoris Brezillon 		else
497ebab87abSBoris Brezillon 			plane_state->ahb_id = 1;
498ebab87abSBoris Brezillon 
499ebab87abSBoris Brezillon 		ahb_load[plane_state->ahb_id] += load;
500ebab87abSBoris Brezillon 	}
501ebab87abSBoris Brezillon 
502ebab87abSBoris Brezillon 	return 0;
503ebab87abSBoris Brezillon }
504ebab87abSBoris Brezillon 
5055957017dSBoris Brezillon int
5065957017dSBoris Brezillon atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
5075957017dSBoris Brezillon {
5085957017dSBoris Brezillon 	int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
5095957017dSBoris Brezillon 	const struct atmel_hlcdc_layer_cfg_layout *layout;
5105957017dSBoris Brezillon 	struct atmel_hlcdc_plane_state *primary_state;
5115957017dSBoris Brezillon 	struct drm_plane_state *primary_s;
5125957017dSBoris Brezillon 	struct atmel_hlcdc_plane *primary;
5135957017dSBoris Brezillon 	struct drm_plane *ovl;
5145957017dSBoris Brezillon 
5155957017dSBoris Brezillon 	primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
5165957017dSBoris Brezillon 	layout = &primary->layer.desc->layout;
5175957017dSBoris Brezillon 	if (!layout->disc_pos || !layout->disc_size)
5185957017dSBoris Brezillon 		return 0;
5195957017dSBoris Brezillon 
5205957017dSBoris Brezillon 	primary_s = drm_atomic_get_plane_state(c_state->state,
5215957017dSBoris Brezillon 					       &primary->base);
5225957017dSBoris Brezillon 	if (IS_ERR(primary_s))
5235957017dSBoris Brezillon 		return PTR_ERR(primary_s);
5245957017dSBoris Brezillon 
5255957017dSBoris Brezillon 	primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
5265957017dSBoris Brezillon 
5275957017dSBoris Brezillon 	drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
5285957017dSBoris Brezillon 		struct atmel_hlcdc_plane_state *ovl_state;
5295957017dSBoris Brezillon 		struct drm_plane_state *ovl_s;
5305957017dSBoris Brezillon 
5315957017dSBoris Brezillon 		if (ovl == c_state->crtc->primary)
5325957017dSBoris Brezillon 			continue;
5335957017dSBoris Brezillon 
5345957017dSBoris Brezillon 		ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
5355957017dSBoris Brezillon 		if (IS_ERR(ovl_s))
5365957017dSBoris Brezillon 			return PTR_ERR(ovl_s);
5375957017dSBoris Brezillon 
5385957017dSBoris Brezillon 		ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
5395957017dSBoris Brezillon 
5405957017dSBoris Brezillon 		if (!ovl_s->fb ||
541438b74a5SVille Syrjälä 		    atmel_hlcdc_format_embeds_alpha(ovl_s->fb->format->format) ||
5425957017dSBoris Brezillon 		    ovl_state->alpha != 255)
5435957017dSBoris Brezillon 			continue;
5445957017dSBoris Brezillon 
5455957017dSBoris Brezillon 		/* TODO: implement a smarter hidden area detection */
5465957017dSBoris Brezillon 		if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
5475957017dSBoris Brezillon 			continue;
5485957017dSBoris Brezillon 
5495957017dSBoris Brezillon 		disc_x = ovl_state->crtc_x;
5505957017dSBoris Brezillon 		disc_y = ovl_state->crtc_y;
5515957017dSBoris Brezillon 		disc_h = ovl_state->crtc_h;
5525957017dSBoris Brezillon 		disc_w = ovl_state->crtc_w;
5535957017dSBoris Brezillon 	}
5545957017dSBoris Brezillon 
5555957017dSBoris Brezillon 	primary_state->disc_x = disc_x;
5565957017dSBoris Brezillon 	primary_state->disc_y = disc_y;
5575957017dSBoris Brezillon 	primary_state->disc_w = disc_w;
5585957017dSBoris Brezillon 	primary_state->disc_h = disc_h;
5595957017dSBoris Brezillon 
5605957017dSBoris Brezillon 	return 0;
5615957017dSBoris Brezillon }
5625957017dSBoris Brezillon 
5635957017dSBoris Brezillon static void
5645957017dSBoris Brezillon atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
5655957017dSBoris Brezillon 				   struct atmel_hlcdc_plane_state *state)
5665957017dSBoris Brezillon {
5679a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_cfg_layout *layout;
5685957017dSBoris Brezillon 
5699a45d33cSBoris Brezillon 	layout = &plane->layer.desc->layout;
5709a45d33cSBoris Brezillon 	if (!layout->disc_pos || !layout->disc_size)
5715957017dSBoris Brezillon 		return;
5725957017dSBoris Brezillon 
5739a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
5749a45d33cSBoris Brezillon 				ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
5759a45d33cSBoris Brezillon 							   state->disc_y));
5765957017dSBoris Brezillon 
5779a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
5789a45d33cSBoris Brezillon 				ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
5799a45d33cSBoris Brezillon 							    state->disc_h));
5805957017dSBoris Brezillon }
5815957017dSBoris Brezillon 
5822389fc13SBoris Brezillon static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
5832389fc13SBoris Brezillon 					  struct drm_plane_state *s)
5841a396789SBoris Brezillon {
5851a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
5862389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_state *state =
5872389fc13SBoris Brezillon 				drm_plane_state_to_atmel_hlcdc_plane_state(s);
5889a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
5892389fc13SBoris Brezillon 	struct drm_framebuffer *fb = state->base.fb;
5902389fc13SBoris Brezillon 	const struct drm_display_mode *mode;
5912389fc13SBoris Brezillon 	struct drm_crtc_state *crtc_state;
5921a396789SBoris Brezillon 	unsigned int patched_crtc_w;
5931a396789SBoris Brezillon 	unsigned int patched_crtc_h;
5941a396789SBoris Brezillon 	unsigned int patched_src_w;
5951a396789SBoris Brezillon 	unsigned int patched_src_h;
5961a396789SBoris Brezillon 	unsigned int tmp;
5971a396789SBoris Brezillon 	int x_offset = 0;
5981a396789SBoris Brezillon 	int y_offset = 0;
5991a396789SBoris Brezillon 	int hsub = 1;
6001a396789SBoris Brezillon 	int vsub = 1;
6011a396789SBoris Brezillon 	int i;
6021a396789SBoris Brezillon 
6032389fc13SBoris Brezillon 	if (!state->base.crtc || !fb)
6042389fc13SBoris Brezillon 		return 0;
6052389fc13SBoris Brezillon 
606b47ff7e6SAndrzej Hajda 	crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
6072389fc13SBoris Brezillon 	mode = &crtc_state->adjusted_mode;
6082389fc13SBoris Brezillon 
6092389fc13SBoris Brezillon 	state->src_x = s->src_x;
6102389fc13SBoris Brezillon 	state->src_y = s->src_y;
6112389fc13SBoris Brezillon 	state->src_h = s->src_h;
6122389fc13SBoris Brezillon 	state->src_w = s->src_w;
6132389fc13SBoris Brezillon 	state->crtc_x = s->crtc_x;
6142389fc13SBoris Brezillon 	state->crtc_y = s->crtc_y;
6152389fc13SBoris Brezillon 	state->crtc_h = s->crtc_h;
6162389fc13SBoris Brezillon 	state->crtc_w = s->crtc_w;
6172389fc13SBoris Brezillon 	if ((state->src_x | state->src_y | state->src_w | state->src_h) &
6181a396789SBoris Brezillon 	    SUBPIXEL_MASK)
6191a396789SBoris Brezillon 		return -EINVAL;
6201a396789SBoris Brezillon 
6212389fc13SBoris Brezillon 	state->src_x >>= 16;
6222389fc13SBoris Brezillon 	state->src_y >>= 16;
6232389fc13SBoris Brezillon 	state->src_w >>= 16;
6242389fc13SBoris Brezillon 	state->src_h >>= 16;
6251a396789SBoris Brezillon 
626bcb0b461SVille Syrjälä 	state->nplanes = fb->format->num_planes;
6279a45d33cSBoris Brezillon 	if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
6281a396789SBoris Brezillon 		return -EINVAL;
6291a396789SBoris Brezillon 
6301a396789SBoris Brezillon 	/*
6311a396789SBoris Brezillon 	 * Swap width and size in case of 90 or 270 degrees rotation
6321a396789SBoris Brezillon 	 */
633bd2ef25dSVille Syrjälä 	if (drm_rotation_90_or_270(state->base.rotation)) {
6342389fc13SBoris Brezillon 		tmp = state->crtc_w;
6352389fc13SBoris Brezillon 		state->crtc_w = state->crtc_h;
6362389fc13SBoris Brezillon 		state->crtc_h = tmp;
6372389fc13SBoris Brezillon 		tmp = state->src_w;
6382389fc13SBoris Brezillon 		state->src_w = state->src_h;
6392389fc13SBoris Brezillon 		state->src_h = tmp;
6401a396789SBoris Brezillon 	}
6411a396789SBoris Brezillon 
6422389fc13SBoris Brezillon 	if (state->crtc_x + state->crtc_w > mode->hdisplay)
6432389fc13SBoris Brezillon 		patched_crtc_w = mode->hdisplay - state->crtc_x;
6441a396789SBoris Brezillon 	else
6452389fc13SBoris Brezillon 		patched_crtc_w = state->crtc_w;
6461a396789SBoris Brezillon 
6472389fc13SBoris Brezillon 	if (state->crtc_x < 0) {
6482389fc13SBoris Brezillon 		patched_crtc_w += state->crtc_x;
6492389fc13SBoris Brezillon 		x_offset = -state->crtc_x;
6502389fc13SBoris Brezillon 		state->crtc_x = 0;
6511a396789SBoris Brezillon 	}
6521a396789SBoris Brezillon 
6532389fc13SBoris Brezillon 	if (state->crtc_y + state->crtc_h > mode->vdisplay)
6542389fc13SBoris Brezillon 		patched_crtc_h = mode->vdisplay - state->crtc_y;
6551a396789SBoris Brezillon 	else
6562389fc13SBoris Brezillon 		patched_crtc_h = state->crtc_h;
6571a396789SBoris Brezillon 
6582389fc13SBoris Brezillon 	if (state->crtc_y < 0) {
6592389fc13SBoris Brezillon 		patched_crtc_h += state->crtc_y;
6602389fc13SBoris Brezillon 		y_offset = -state->crtc_y;
6612389fc13SBoris Brezillon 		state->crtc_y = 0;
6621a396789SBoris Brezillon 	}
6631a396789SBoris Brezillon 
6642389fc13SBoris Brezillon 	patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
6652389fc13SBoris Brezillon 					  state->crtc_w);
6662389fc13SBoris Brezillon 	patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
6672389fc13SBoris Brezillon 					  state->crtc_h);
6681a396789SBoris Brezillon 
669438b74a5SVille Syrjälä 	hsub = drm_format_horz_chroma_subsampling(fb->format->format);
670438b74a5SVille Syrjälä 	vsub = drm_format_vert_chroma_subsampling(fb->format->format);
6711a396789SBoris Brezillon 
6722389fc13SBoris Brezillon 	for (i = 0; i < state->nplanes; i++) {
6731a396789SBoris Brezillon 		unsigned int offset = 0;
6741a396789SBoris Brezillon 		int xdiv = i ? hsub : 1;
6751a396789SBoris Brezillon 		int ydiv = i ? vsub : 1;
6761a396789SBoris Brezillon 
677353c8598SVille Syrjälä 		state->bpp[i] = fb->format->cpp[i];
6782389fc13SBoris Brezillon 		if (!state->bpp[i])
6791a396789SBoris Brezillon 			return -EINVAL;
6801a396789SBoris Brezillon 
68114152c8dSJoonas Lahtinen 		switch (state->base.rotation & DRM_ROTATE_MASK) {
68231ad61e4SJoonas Lahtinen 		case DRM_ROTATE_90:
6832389fc13SBoris Brezillon 			offset = ((y_offset + state->src_y + patched_src_w - 1) /
6842389fc13SBoris Brezillon 				  ydiv) * fb->pitches[i];
6852389fc13SBoris Brezillon 			offset += ((x_offset + state->src_x) / xdiv) *
6862389fc13SBoris Brezillon 				  state->bpp[i];
6872389fc13SBoris Brezillon 			state->xstride[i] = ((patched_src_w - 1) / ydiv) *
6882389fc13SBoris Brezillon 					  fb->pitches[i];
6892389fc13SBoris Brezillon 			state->pstride[i] = -fb->pitches[i] - state->bpp[i];
6901a396789SBoris Brezillon 			break;
69131ad61e4SJoonas Lahtinen 		case DRM_ROTATE_180:
6922389fc13SBoris Brezillon 			offset = ((y_offset + state->src_y + patched_src_h - 1) /
6932389fc13SBoris Brezillon 				  ydiv) * fb->pitches[i];
6942389fc13SBoris Brezillon 			offset += ((x_offset + state->src_x + patched_src_w - 1) /
6952389fc13SBoris Brezillon 				   xdiv) * state->bpp[i];
6962389fc13SBoris Brezillon 			state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
6972389fc13SBoris Brezillon 					   state->bpp[i]) - fb->pitches[i];
6982389fc13SBoris Brezillon 			state->pstride[i] = -2 * state->bpp[i];
6991a396789SBoris Brezillon 			break;
70031ad61e4SJoonas Lahtinen 		case DRM_ROTATE_270:
7012389fc13SBoris Brezillon 			offset = ((y_offset + state->src_y) / ydiv) *
7022389fc13SBoris Brezillon 				 fb->pitches[i];
7032389fc13SBoris Brezillon 			offset += ((x_offset + state->src_x + patched_src_h - 1) /
7042389fc13SBoris Brezillon 				   xdiv) * state->bpp[i];
7052389fc13SBoris Brezillon 			state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
7062389fc13SBoris Brezillon 					    fb->pitches[i]) -
7072389fc13SBoris Brezillon 					  (2 * state->bpp[i]);
7082389fc13SBoris Brezillon 			state->pstride[i] = fb->pitches[i] - state->bpp[i];
7091a396789SBoris Brezillon 			break;
71031ad61e4SJoonas Lahtinen 		case DRM_ROTATE_0:
7111a396789SBoris Brezillon 		default:
7122389fc13SBoris Brezillon 			offset = ((y_offset + state->src_y) / ydiv) *
7132389fc13SBoris Brezillon 				 fb->pitches[i];
7142389fc13SBoris Brezillon 			offset += ((x_offset + state->src_x) / xdiv) *
7152389fc13SBoris Brezillon 				  state->bpp[i];
7162389fc13SBoris Brezillon 			state->xstride[i] = fb->pitches[i] -
7171a396789SBoris Brezillon 					  ((patched_src_w / xdiv) *
7182389fc13SBoris Brezillon 					   state->bpp[i]);
7192389fc13SBoris Brezillon 			state->pstride[i] = 0;
7201a396789SBoris Brezillon 			break;
7211a396789SBoris Brezillon 		}
7221a396789SBoris Brezillon 
7232389fc13SBoris Brezillon 		state->offsets[i] = offset + fb->offsets[i];
7241a396789SBoris Brezillon 	}
7251a396789SBoris Brezillon 
7262389fc13SBoris Brezillon 	state->src_w = patched_src_w;
7272389fc13SBoris Brezillon 	state->src_h = patched_src_h;
7282389fc13SBoris Brezillon 	state->crtc_w = patched_crtc_w;
7292389fc13SBoris Brezillon 	state->crtc_h = patched_crtc_h;
7301a396789SBoris Brezillon 
7319a45d33cSBoris Brezillon 	if (!desc->layout.size &&
7322389fc13SBoris Brezillon 	    (mode->hdisplay != state->crtc_w ||
7332389fc13SBoris Brezillon 	     mode->vdisplay != state->crtc_h))
7342389fc13SBoris Brezillon 		return -EINVAL;
7351a396789SBoris Brezillon 
7369a45d33cSBoris Brezillon 	if (desc->max_height && state->crtc_h > desc->max_height)
7372389fc13SBoris Brezillon 		return -EINVAL;
7381a396789SBoris Brezillon 
7399a45d33cSBoris Brezillon 	if (desc->max_width && state->crtc_w > desc->max_width)
7402389fc13SBoris Brezillon 		return -EINVAL;
7411a396789SBoris Brezillon 
7422389fc13SBoris Brezillon 	if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
7439a45d33cSBoris Brezillon 	    (!desc->layout.memsize ||
744438b74a5SVille Syrjälä 	     atmel_hlcdc_format_embeds_alpha(state->base.fb->format->format)))
7452389fc13SBoris Brezillon 		return -EINVAL;
7461a396789SBoris Brezillon 
7472389fc13SBoris Brezillon 	if (state->crtc_x < 0 || state->crtc_y < 0)
7482389fc13SBoris Brezillon 		return -EINVAL;
7492389fc13SBoris Brezillon 
7502389fc13SBoris Brezillon 	if (state->crtc_w + state->crtc_x > mode->hdisplay ||
7512389fc13SBoris Brezillon 	    state->crtc_h + state->crtc_y > mode->vdisplay)
7522389fc13SBoris Brezillon 		return -EINVAL;
7531a396789SBoris Brezillon 
7541a396789SBoris Brezillon 	return 0;
7551a396789SBoris Brezillon }
7561a396789SBoris Brezillon 
7572389fc13SBoris Brezillon static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
7582389fc13SBoris Brezillon 					    struct drm_plane_state *old_s)
7592389fc13SBoris Brezillon {
7602389fc13SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
7612389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_state *state =
7622389fc13SBoris Brezillon 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
7639a45d33cSBoris Brezillon 	u32 sr;
7642389fc13SBoris Brezillon 
7652389fc13SBoris Brezillon 	if (!p->state->crtc || !p->state->fb)
7662389fc13SBoris Brezillon 		return;
7672389fc13SBoris Brezillon 
7682389fc13SBoris Brezillon 	atmel_hlcdc_plane_update_pos_and_size(plane, state);
7692389fc13SBoris Brezillon 	atmel_hlcdc_plane_update_general_settings(plane, state);
7702389fc13SBoris Brezillon 	atmel_hlcdc_plane_update_format(plane, state);
7712389fc13SBoris Brezillon 	atmel_hlcdc_plane_update_buffers(plane, state);
7725957017dSBoris Brezillon 	atmel_hlcdc_plane_update_disc_area(plane, state);
7732389fc13SBoris Brezillon 
7749a45d33cSBoris Brezillon 	/* Enable the overrun interrupts. */
7759a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
7769a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
7779a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
7789a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_OVR_IRQ(2));
7799a45d33cSBoris Brezillon 
7809a45d33cSBoris Brezillon 	/* Apply the new config at the next SOF event. */
7819a45d33cSBoris Brezillon 	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
7829a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
7839a45d33cSBoris Brezillon 			ATMEL_HLCDC_LAYER_UPDATE |
7849a45d33cSBoris Brezillon 			(sr & ATMEL_HLCDC_LAYER_EN ?
7859a45d33cSBoris Brezillon 			 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
7862389fc13SBoris Brezillon }
7872389fc13SBoris Brezillon 
7882389fc13SBoris Brezillon static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
7892389fc13SBoris Brezillon 					     struct drm_plane_state *old_state)
7902389fc13SBoris Brezillon {
7912389fc13SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
7922389fc13SBoris Brezillon 
7939a45d33cSBoris Brezillon 	/* Disable interrupts */
7949a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
7959a45d33cSBoris Brezillon 				    0xffffffff);
7969a45d33cSBoris Brezillon 
7979a45d33cSBoris Brezillon 	/* Disable the layer */
7989a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
7999a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_RST |
8009a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_A2Q |
8019a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_UPDATE);
8029a45d33cSBoris Brezillon 
8039a45d33cSBoris Brezillon 	/* Clear all pending interrupts */
8049a45d33cSBoris Brezillon 	atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
8051a396789SBoris Brezillon }
8061a396789SBoris Brezillon 
8071a396789SBoris Brezillon static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
8081a396789SBoris Brezillon {
8091a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
8101a396789SBoris Brezillon 
8111a396789SBoris Brezillon 	if (plane->base.fb)
8121a396789SBoris Brezillon 		drm_framebuffer_unreference(plane->base.fb);
8131a396789SBoris Brezillon 
8141a396789SBoris Brezillon 	drm_plane_cleanup(p);
8151a396789SBoris Brezillon }
8161a396789SBoris Brezillon 
8172389fc13SBoris Brezillon static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
8182389fc13SBoris Brezillon 						 struct drm_plane_state *s,
8191a396789SBoris Brezillon 						 struct drm_property *property,
8202389fc13SBoris Brezillon 						 uint64_t val)
8211a396789SBoris Brezillon {
8221a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
8231a396789SBoris Brezillon 	struct atmel_hlcdc_plane_properties *props = plane->properties;
8242389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_state *state =
8252389fc13SBoris Brezillon 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
8261a396789SBoris Brezillon 
8271a396789SBoris Brezillon 	if (property == props->alpha)
8282389fc13SBoris Brezillon 		state->alpha = val;
8292389fc13SBoris Brezillon 	else
8302389fc13SBoris Brezillon 		return -EINVAL;
8312389fc13SBoris Brezillon 
8322389fc13SBoris Brezillon 	return 0;
8332389fc13SBoris Brezillon }
8342389fc13SBoris Brezillon 
8352389fc13SBoris Brezillon static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
8362389fc13SBoris Brezillon 					const struct drm_plane_state *s,
8372389fc13SBoris Brezillon 					struct drm_property *property,
8382389fc13SBoris Brezillon 					uint64_t *val)
8392389fc13SBoris Brezillon {
8402389fc13SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
8412389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_properties *props = plane->properties;
8422389fc13SBoris Brezillon 	const struct atmel_hlcdc_plane_state *state =
8432389fc13SBoris Brezillon 		container_of(s, const struct atmel_hlcdc_plane_state, base);
8442389fc13SBoris Brezillon 
8452389fc13SBoris Brezillon 	if (property == props->alpha)
8462389fc13SBoris Brezillon 		*val = state->alpha;
8471a396789SBoris Brezillon 	else
8481a396789SBoris Brezillon 		return -EINVAL;
8491a396789SBoris Brezillon 
8501a396789SBoris Brezillon 	return 0;
8511a396789SBoris Brezillon }
8521a396789SBoris Brezillon 
8539fe58f01SVille Syrjälä static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
8541a396789SBoris Brezillon 				struct atmel_hlcdc_plane_properties *props)
8551a396789SBoris Brezillon {
8569a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
8571a396789SBoris Brezillon 
8581a396789SBoris Brezillon 	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
8599a45d33cSBoris Brezillon 	    desc->type == ATMEL_HLCDC_CURSOR_LAYER)
8601a396789SBoris Brezillon 		drm_object_attach_property(&plane->base.base,
8611a396789SBoris Brezillon 					   props->alpha, 255);
8621a396789SBoris Brezillon 
8639fe58f01SVille Syrjälä 	if (desc->layout.xstride && desc->layout.pstride) {
8649fe58f01SVille Syrjälä 		int ret;
8659fe58f01SVille Syrjälä 
8669fe58f01SVille Syrjälä 		ret = drm_plane_create_rotation_property(&plane->base,
8679fe58f01SVille Syrjälä 							 DRM_ROTATE_0,
8689fe58f01SVille Syrjälä 							 DRM_ROTATE_0 |
8699fe58f01SVille Syrjälä 							 DRM_ROTATE_90 |
8709fe58f01SVille Syrjälä 							 DRM_ROTATE_180 |
8719fe58f01SVille Syrjälä 							 DRM_ROTATE_270);
8729fe58f01SVille Syrjälä 		if (ret)
8739fe58f01SVille Syrjälä 			return ret;
8749fe58f01SVille Syrjälä 	}
8751a396789SBoris Brezillon 
8761a396789SBoris Brezillon 	if (desc->layout.csc) {
8771a396789SBoris Brezillon 		/*
8781a396789SBoris Brezillon 		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
8791a396789SBoris Brezillon 		 * userspace modify these factors (using a BLOB property ?).
8801a396789SBoris Brezillon 		 */
8819a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer,
8829a45d33cSBoris Brezillon 					    desc->layout.csc,
8831a396789SBoris Brezillon 					    0x4c900091);
8849a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer,
8859a45d33cSBoris Brezillon 					    desc->layout.csc + 1,
8861a396789SBoris Brezillon 					    0x7a5f5090);
8879a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer,
8889a45d33cSBoris Brezillon 					    desc->layout.csc + 2,
8891a396789SBoris Brezillon 					    0x40040890);
8901a396789SBoris Brezillon 	}
8919fe58f01SVille Syrjälä 
8929fe58f01SVille Syrjälä 	return 0;
8931a396789SBoris Brezillon }
8941a396789SBoris Brezillon 
8959a45d33cSBoris Brezillon void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
8969a45d33cSBoris Brezillon {
8979a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
8989a45d33cSBoris Brezillon 	u32 isr;
8999a45d33cSBoris Brezillon 
9009a45d33cSBoris Brezillon 	isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
9019a45d33cSBoris Brezillon 
9029a45d33cSBoris Brezillon 	/*
9039a45d33cSBoris Brezillon 	 * There's not much we can do in case of overrun except informing
9049a45d33cSBoris Brezillon 	 * the user. However, we are in interrupt context here, hence the
9059a45d33cSBoris Brezillon 	 * use of dev_dbg().
9069a45d33cSBoris Brezillon 	 */
9079a45d33cSBoris Brezillon 	if (isr &
9089a45d33cSBoris Brezillon 	    (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
9099a45d33cSBoris Brezillon 	     ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
9109a45d33cSBoris Brezillon 		dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
9119a45d33cSBoris Brezillon 			desc->name);
9129a45d33cSBoris Brezillon }
9139a45d33cSBoris Brezillon 
9142389fc13SBoris Brezillon static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
9152389fc13SBoris Brezillon 	.atomic_check = atmel_hlcdc_plane_atomic_check,
9162389fc13SBoris Brezillon 	.atomic_update = atmel_hlcdc_plane_atomic_update,
9172389fc13SBoris Brezillon 	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
9182389fc13SBoris Brezillon };
9192389fc13SBoris Brezillon 
9209a45d33cSBoris Brezillon static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
9219a45d33cSBoris Brezillon 					 struct atmel_hlcdc_plane_state *state)
9229a45d33cSBoris Brezillon {
9239a45d33cSBoris Brezillon 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
9249a45d33cSBoris Brezillon 	int i;
9259a45d33cSBoris Brezillon 
9269a45d33cSBoris Brezillon 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
9279a45d33cSBoris Brezillon 		struct atmel_hlcdc_dma_channel_dscr *dscr;
9289a45d33cSBoris Brezillon 		dma_addr_t dscr_dma;
9299a45d33cSBoris Brezillon 
9309a45d33cSBoris Brezillon 		dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
9319a45d33cSBoris Brezillon 		if (!dscr)
9329a45d33cSBoris Brezillon 			goto err;
9339a45d33cSBoris Brezillon 
9349a45d33cSBoris Brezillon 		dscr->addr = 0;
9359a45d33cSBoris Brezillon 		dscr->next = dscr_dma;
9369a45d33cSBoris Brezillon 		dscr->self = dscr_dma;
9379a45d33cSBoris Brezillon 		dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
9389a45d33cSBoris Brezillon 
9399a45d33cSBoris Brezillon 		state->dscrs[i] = dscr;
9409a45d33cSBoris Brezillon 	}
9419a45d33cSBoris Brezillon 
9429a45d33cSBoris Brezillon 	return 0;
9439a45d33cSBoris Brezillon 
9449a45d33cSBoris Brezillon err:
9459a45d33cSBoris Brezillon 	for (i--; i >= 0; i--) {
9469a45d33cSBoris Brezillon 		dma_pool_free(dc->dscrpool, state->dscrs[i],
9479a45d33cSBoris Brezillon 			      state->dscrs[i]->self);
9489a45d33cSBoris Brezillon 	}
9499a45d33cSBoris Brezillon 
9509a45d33cSBoris Brezillon 	return -ENOMEM;
9519a45d33cSBoris Brezillon }
9529a45d33cSBoris Brezillon 
9532389fc13SBoris Brezillon static void atmel_hlcdc_plane_reset(struct drm_plane *p)
9542389fc13SBoris Brezillon {
9552389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_state *state;
9562389fc13SBoris Brezillon 
9572389fc13SBoris Brezillon 	if (p->state) {
9582389fc13SBoris Brezillon 		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
9592389fc13SBoris Brezillon 
9602389fc13SBoris Brezillon 		if (state->base.fb)
9612389fc13SBoris Brezillon 			drm_framebuffer_unreference(state->base.fb);
9622389fc13SBoris Brezillon 
9632389fc13SBoris Brezillon 		kfree(state);
9642389fc13SBoris Brezillon 		p->state = NULL;
9652389fc13SBoris Brezillon 	}
9662389fc13SBoris Brezillon 
9672389fc13SBoris Brezillon 	state = kzalloc(sizeof(*state), GFP_KERNEL);
9682389fc13SBoris Brezillon 	if (state) {
9699a45d33cSBoris Brezillon 		if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
9709a45d33cSBoris Brezillon 			kfree(state);
9719a45d33cSBoris Brezillon 			dev_err(p->dev->dev,
9729a45d33cSBoris Brezillon 				"Failed to allocate initial plane state\n");
9739a45d33cSBoris Brezillon 			return;
9749a45d33cSBoris Brezillon 		}
9759a45d33cSBoris Brezillon 
9762389fc13SBoris Brezillon 		state->alpha = 255;
9772389fc13SBoris Brezillon 		p->state = &state->base;
9782389fc13SBoris Brezillon 		p->state->plane = p;
9792389fc13SBoris Brezillon 	}
9802389fc13SBoris Brezillon }
9812389fc13SBoris Brezillon 
9822389fc13SBoris Brezillon static struct drm_plane_state *
9832389fc13SBoris Brezillon atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
9842389fc13SBoris Brezillon {
9852389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_state *state =
9862389fc13SBoris Brezillon 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
9872389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_state *copy;
9882389fc13SBoris Brezillon 
9892389fc13SBoris Brezillon 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
9902389fc13SBoris Brezillon 	if (!copy)
9912389fc13SBoris Brezillon 		return NULL;
9922389fc13SBoris Brezillon 
9939a45d33cSBoris Brezillon 	if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
9949a45d33cSBoris Brezillon 		kfree(copy);
9959a45d33cSBoris Brezillon 		return NULL;
9969a45d33cSBoris Brezillon 	}
9975957017dSBoris Brezillon 
9982389fc13SBoris Brezillon 	if (copy->base.fb)
9992389fc13SBoris Brezillon 		drm_framebuffer_reference(copy->base.fb);
10002389fc13SBoris Brezillon 
10012389fc13SBoris Brezillon 	return &copy->base;
10022389fc13SBoris Brezillon }
10032389fc13SBoris Brezillon 
10049a45d33cSBoris Brezillon static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
10052389fc13SBoris Brezillon 						   struct drm_plane_state *s)
10062389fc13SBoris Brezillon {
10072389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_state *state =
10082389fc13SBoris Brezillon 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
10099a45d33cSBoris Brezillon 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
10109a45d33cSBoris Brezillon 	int i;
10119a45d33cSBoris Brezillon 
10129a45d33cSBoris Brezillon 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
10139a45d33cSBoris Brezillon 		dma_pool_free(dc->dscrpool, state->dscrs[i],
10149a45d33cSBoris Brezillon 			      state->dscrs[i]->self);
10159a45d33cSBoris Brezillon 	}
10162389fc13SBoris Brezillon 
10172389fc13SBoris Brezillon 	if (s->fb)
10182389fc13SBoris Brezillon 		drm_framebuffer_unreference(s->fb);
10192389fc13SBoris Brezillon 
10202389fc13SBoris Brezillon 	kfree(state);
10212389fc13SBoris Brezillon }
10222389fc13SBoris Brezillon 
10231a396789SBoris Brezillon static struct drm_plane_funcs layer_plane_funcs = {
10242389fc13SBoris Brezillon 	.update_plane = drm_atomic_helper_update_plane,
10252389fc13SBoris Brezillon 	.disable_plane = drm_atomic_helper_disable_plane,
10262389fc13SBoris Brezillon 	.set_property = drm_atomic_helper_plane_set_property,
10271a396789SBoris Brezillon 	.destroy = atmel_hlcdc_plane_destroy,
10282389fc13SBoris Brezillon 	.reset = atmel_hlcdc_plane_reset,
10292389fc13SBoris Brezillon 	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
10302389fc13SBoris Brezillon 	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
10312389fc13SBoris Brezillon 	.atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
10322389fc13SBoris Brezillon 	.atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
10331a396789SBoris Brezillon };
10341a396789SBoris Brezillon 
10359a45d33cSBoris Brezillon static int atmel_hlcdc_plane_create(struct drm_device *dev,
10361a396789SBoris Brezillon 				    const struct atmel_hlcdc_layer_desc *desc,
10371a396789SBoris Brezillon 				    struct atmel_hlcdc_plane_properties *props)
10381a396789SBoris Brezillon {
10399a45d33cSBoris Brezillon 	struct atmel_hlcdc_dc *dc = dev->dev_private;
10401a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane;
10411a396789SBoris Brezillon 	enum drm_plane_type type;
10421a396789SBoris Brezillon 	int ret;
10431a396789SBoris Brezillon 
10441a396789SBoris Brezillon 	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
10451a396789SBoris Brezillon 	if (!plane)
10469a45d33cSBoris Brezillon 		return -ENOMEM;
10471a396789SBoris Brezillon 
10489a45d33cSBoris Brezillon 	atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
10499a45d33cSBoris Brezillon 	plane->properties = props;
10501a396789SBoris Brezillon 
10511a396789SBoris Brezillon 	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
10521a396789SBoris Brezillon 		type = DRM_PLANE_TYPE_PRIMARY;
10531a396789SBoris Brezillon 	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
10541a396789SBoris Brezillon 		type = DRM_PLANE_TYPE_CURSOR;
10551a396789SBoris Brezillon 	else
10561a396789SBoris Brezillon 		type = DRM_PLANE_TYPE_OVERLAY;
10571a396789SBoris Brezillon 
10581a396789SBoris Brezillon 	ret = drm_universal_plane_init(dev, &plane->base, 0,
10591a396789SBoris Brezillon 				       &layer_plane_funcs,
10601a396789SBoris Brezillon 				       desc->formats->formats,
1061b0b3b795SVille Syrjälä 				       desc->formats->nformats, type, NULL);
10621a396789SBoris Brezillon 	if (ret)
10639a45d33cSBoris Brezillon 		return ret;
10641a396789SBoris Brezillon 
10652389fc13SBoris Brezillon 	drm_plane_helper_add(&plane->base,
10662389fc13SBoris Brezillon 			     &atmel_hlcdc_layer_plane_helper_funcs);
10672389fc13SBoris Brezillon 
10681a396789SBoris Brezillon 	/* Set default property values*/
10699a45d33cSBoris Brezillon 	ret = atmel_hlcdc_plane_init_properties(plane, props);
10709fe58f01SVille Syrjälä 	if (ret)
10719a45d33cSBoris Brezillon 		return ret;
10721a396789SBoris Brezillon 
10739a45d33cSBoris Brezillon 	dc->layers[desc->id] = &plane->layer;
10749a45d33cSBoris Brezillon 
10759a45d33cSBoris Brezillon 	return 0;
10761a396789SBoris Brezillon }
10771a396789SBoris Brezillon 
10781a396789SBoris Brezillon static struct atmel_hlcdc_plane_properties *
10791a396789SBoris Brezillon atmel_hlcdc_plane_create_properties(struct drm_device *dev)
10801a396789SBoris Brezillon {
10811a396789SBoris Brezillon 	struct atmel_hlcdc_plane_properties *props;
10821a396789SBoris Brezillon 
10831a396789SBoris Brezillon 	props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
10841a396789SBoris Brezillon 	if (!props)
10851a396789SBoris Brezillon 		return ERR_PTR(-ENOMEM);
10861a396789SBoris Brezillon 
10871a396789SBoris Brezillon 	props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
10881a396789SBoris Brezillon 	if (!props->alpha)
10891a396789SBoris Brezillon 		return ERR_PTR(-ENOMEM);
10901a396789SBoris Brezillon 
10911a396789SBoris Brezillon 	return props;
10921a396789SBoris Brezillon }
10931a396789SBoris Brezillon 
10949a45d33cSBoris Brezillon int atmel_hlcdc_create_planes(struct drm_device *dev)
10951a396789SBoris Brezillon {
10961a396789SBoris Brezillon 	struct atmel_hlcdc_dc *dc = dev->dev_private;
10971a396789SBoris Brezillon 	struct atmel_hlcdc_plane_properties *props;
10981a396789SBoris Brezillon 	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
10991a396789SBoris Brezillon 	int nlayers = dc->desc->nlayers;
11009a45d33cSBoris Brezillon 	int i, ret;
11011a396789SBoris Brezillon 
11021a396789SBoris Brezillon 	props = atmel_hlcdc_plane_create_properties(dev);
11031a396789SBoris Brezillon 	if (IS_ERR(props))
11049a45d33cSBoris Brezillon 		return PTR_ERR(props);
11051a396789SBoris Brezillon 
11069a45d33cSBoris Brezillon 	dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
11079a45d33cSBoris Brezillon 				sizeof(struct atmel_hlcdc_dma_channel_dscr),
11089a45d33cSBoris Brezillon 				sizeof(u64), 0);
11099a45d33cSBoris Brezillon 	if (!dc->dscrpool)
11109a45d33cSBoris Brezillon 		return -ENOMEM;
11119a45d33cSBoris Brezillon 
11121a396789SBoris Brezillon 	for (i = 0; i < nlayers; i++) {
11139a45d33cSBoris Brezillon 		if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
11149a45d33cSBoris Brezillon 		    descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
11159a45d33cSBoris Brezillon 		    descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
11161a396789SBoris Brezillon 			continue;
11171a396789SBoris Brezillon 
11189a45d33cSBoris Brezillon 		ret = atmel_hlcdc_plane_create(dev, &descs[i], props);
11199a45d33cSBoris Brezillon 		if (ret)
11209a45d33cSBoris Brezillon 			return ret;
11211a396789SBoris Brezillon 	}
11221a396789SBoris Brezillon 
11239a45d33cSBoris Brezillon 	return 0;
11241a396789SBoris Brezillon }
1125