1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21a396789SBoris Brezillon /*
31a396789SBoris Brezillon  * Copyright (C) 2014 Free Electrons
41a396789SBoris Brezillon  * Copyright (C) 2014 Atmel
51a396789SBoris Brezillon  *
61a396789SBoris Brezillon  * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
71a396789SBoris Brezillon  */
81a396789SBoris Brezillon 
971866a56SSam Ravnborg #include <linux/dmapool.h>
1071866a56SSam Ravnborg #include <linux/mfd/atmel-hlcdc.h>
1171866a56SSam Ravnborg 
1271866a56SSam Ravnborg #include <drm/drm_atomic.h>
1371866a56SSam Ravnborg #include <drm/drm_atomic_helper.h>
1490bb087fSVille Syrjälä #include <drm/drm_blend.h>
156bcfe8eaSDanilo Krummrich #include <drm/drm_fb_dma_helper.h>
1671866a56SSam Ravnborg #include <drm/drm_fourcc.h>
17720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
18*4a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h>
1971866a56SSam Ravnborg 
201a396789SBoris Brezillon #include "atmel_hlcdc_dc.h"
211a396789SBoris Brezillon 
222389fc13SBoris Brezillon /**
234fe092faSLee Jones  * struct atmel_hlcdc_plane_state - 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
349a45d33cSBoris Brezillon  * @disc_x: x discard position
359a45d33cSBoris Brezillon  * @disc_y: y discard position
369a45d33cSBoris Brezillon  * @disc_w: discard width
379a45d33cSBoris Brezillon  * @disc_h: discard height
384fe092faSLee Jones  * @ahb_id: AHB identification number
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 
575957017dSBoris Brezillon 	int disc_x;
585957017dSBoris Brezillon 	int disc_y;
595957017dSBoris Brezillon 	int disc_w;
605957017dSBoris Brezillon 	int disc_h;
615957017dSBoris Brezillon 
62ebab87abSBoris Brezillon 	int ahb_id;
63ebab87abSBoris Brezillon 
642389fc13SBoris Brezillon 	/* These fields are private and should not be touched */
659a45d33cSBoris Brezillon 	int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
669a45d33cSBoris Brezillon 	unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
679a45d33cSBoris Brezillon 	int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
689a45d33cSBoris Brezillon 	int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
692389fc13SBoris Brezillon 	int nplanes;
709a45d33cSBoris Brezillon 
719a45d33cSBoris Brezillon 	/* DMA descriptors. */
729a45d33cSBoris Brezillon 	struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
732389fc13SBoris Brezillon };
742389fc13SBoris Brezillon 
752389fc13SBoris Brezillon static inline struct atmel_hlcdc_plane_state *
762389fc13SBoris Brezillon drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
772389fc13SBoris Brezillon {
782389fc13SBoris Brezillon 	return container_of(s, struct atmel_hlcdc_plane_state, base);
792389fc13SBoris Brezillon }
802389fc13SBoris Brezillon 
811a396789SBoris Brezillon #define SUBPIXEL_MASK			0xffff
821a396789SBoris Brezillon 
831a396789SBoris Brezillon static uint32_t rgb_formats[] = {
84364a7bf5SPeter Rosin 	DRM_FORMAT_C8,
851a396789SBoris Brezillon 	DRM_FORMAT_XRGB4444,
861a396789SBoris Brezillon 	DRM_FORMAT_ARGB4444,
871a396789SBoris Brezillon 	DRM_FORMAT_RGBA4444,
881a396789SBoris Brezillon 	DRM_FORMAT_ARGB1555,
891a396789SBoris Brezillon 	DRM_FORMAT_RGB565,
901a396789SBoris Brezillon 	DRM_FORMAT_RGB888,
911a396789SBoris Brezillon 	DRM_FORMAT_XRGB8888,
921a396789SBoris Brezillon 	DRM_FORMAT_ARGB8888,
931a396789SBoris Brezillon 	DRM_FORMAT_RGBA8888,
941a396789SBoris Brezillon };
951a396789SBoris Brezillon 
961a396789SBoris Brezillon struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
971a396789SBoris Brezillon 	.formats = rgb_formats,
981a396789SBoris Brezillon 	.nformats = ARRAY_SIZE(rgb_formats),
991a396789SBoris Brezillon };
1001a396789SBoris Brezillon 
1011a396789SBoris Brezillon static uint32_t rgb_and_yuv_formats[] = {
102364a7bf5SPeter Rosin 	DRM_FORMAT_C8,
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) {
131364a7bf5SPeter Rosin 	case DRM_FORMAT_C8:
132364a7bf5SPeter Rosin 		*mode = ATMEL_HLCDC_C8_MODE;
133364a7bf5SPeter Rosin 		break;
1341a396789SBoris Brezillon 	case DRM_FORMAT_XRGB4444:
1351a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_XRGB4444_MODE;
1361a396789SBoris Brezillon 		break;
1371a396789SBoris Brezillon 	case DRM_FORMAT_ARGB4444:
1381a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_ARGB4444_MODE;
1391a396789SBoris Brezillon 		break;
1401a396789SBoris Brezillon 	case DRM_FORMAT_RGBA4444:
1411a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGBA4444_MODE;
1421a396789SBoris Brezillon 		break;
1431a396789SBoris Brezillon 	case DRM_FORMAT_RGB565:
1441a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGB565_MODE;
1451a396789SBoris Brezillon 		break;
1461a396789SBoris Brezillon 	case DRM_FORMAT_RGB888:
1471a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGB888_MODE;
1481a396789SBoris Brezillon 		break;
1491a396789SBoris Brezillon 	case DRM_FORMAT_ARGB1555:
1501a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_ARGB1555_MODE;
1511a396789SBoris Brezillon 		break;
1521a396789SBoris Brezillon 	case DRM_FORMAT_XRGB8888:
1531a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_XRGB8888_MODE;
1541a396789SBoris Brezillon 		break;
1551a396789SBoris Brezillon 	case DRM_FORMAT_ARGB8888:
1561a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_ARGB8888_MODE;
1571a396789SBoris Brezillon 		break;
1581a396789SBoris Brezillon 	case DRM_FORMAT_RGBA8888:
1591a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGBA8888_MODE;
1601a396789SBoris Brezillon 		break;
1611a396789SBoris Brezillon 	case DRM_FORMAT_AYUV:
1621a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_AYUV_MODE;
1631a396789SBoris Brezillon 		break;
1641a396789SBoris Brezillon 	case DRM_FORMAT_YUYV:
1651a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YUYV_MODE;
1661a396789SBoris Brezillon 		break;
1671a396789SBoris Brezillon 	case DRM_FORMAT_UYVY:
1681a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_UYVY_MODE;
1691a396789SBoris Brezillon 		break;
1701a396789SBoris Brezillon 	case DRM_FORMAT_YVYU:
1711a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YVYU_MODE;
1721a396789SBoris Brezillon 		break;
1731a396789SBoris Brezillon 	case DRM_FORMAT_VYUY:
1741a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_VYUY_MODE;
1751a396789SBoris Brezillon 		break;
1761a396789SBoris Brezillon 	case DRM_FORMAT_NV21:
1771a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_NV21_MODE;
1781a396789SBoris Brezillon 		break;
1791a396789SBoris Brezillon 	case DRM_FORMAT_NV61:
1801a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_NV61_MODE;
1811a396789SBoris Brezillon 		break;
1821a396789SBoris Brezillon 	case DRM_FORMAT_YUV420:
1831a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YUV420_MODE;
1841a396789SBoris Brezillon 		break;
1851a396789SBoris Brezillon 	case DRM_FORMAT_YUV422:
1861a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YUV422_MODE;
1871a396789SBoris Brezillon 		break;
1881a396789SBoris Brezillon 	default:
1891a396789SBoris Brezillon 		return -ENOTSUPP;
1901a396789SBoris Brezillon 	}
1911a396789SBoris Brezillon 
1921a396789SBoris Brezillon 	return 0;
1931a396789SBoris Brezillon }
1941a396789SBoris Brezillon 
1951a396789SBoris Brezillon static u32 heo_downscaling_xcoef[] = {
1961a396789SBoris Brezillon 	0x11343311,
1971a396789SBoris Brezillon 	0x000000f7,
1981a396789SBoris Brezillon 	0x1635300c,
1991a396789SBoris Brezillon 	0x000000f9,
2001a396789SBoris Brezillon 	0x1b362c08,
2011a396789SBoris Brezillon 	0x000000fb,
2021a396789SBoris Brezillon 	0x1f372804,
2031a396789SBoris Brezillon 	0x000000fe,
2041a396789SBoris Brezillon 	0x24382400,
2051a396789SBoris Brezillon 	0x00000000,
2061a396789SBoris Brezillon 	0x28371ffe,
2071a396789SBoris Brezillon 	0x00000004,
2081a396789SBoris Brezillon 	0x2c361bfb,
2091a396789SBoris Brezillon 	0x00000008,
2101a396789SBoris Brezillon 	0x303516f9,
2111a396789SBoris Brezillon 	0x0000000c,
2121a396789SBoris Brezillon };
2131a396789SBoris Brezillon 
2141a396789SBoris Brezillon static u32 heo_downscaling_ycoef[] = {
2151a396789SBoris Brezillon 	0x00123737,
2161a396789SBoris Brezillon 	0x00173732,
2171a396789SBoris Brezillon 	0x001b382d,
2181a396789SBoris Brezillon 	0x001f3928,
2191a396789SBoris Brezillon 	0x00243824,
2201a396789SBoris Brezillon 	0x0028391f,
2211a396789SBoris Brezillon 	0x002d381b,
2221a396789SBoris Brezillon 	0x00323717,
2231a396789SBoris Brezillon };
2241a396789SBoris Brezillon 
2251a396789SBoris Brezillon static u32 heo_upscaling_xcoef[] = {
2261a396789SBoris Brezillon 	0xf74949f7,
2271a396789SBoris Brezillon 	0x00000000,
2281a396789SBoris Brezillon 	0xf55f33fb,
2291a396789SBoris Brezillon 	0x000000fe,
2301a396789SBoris Brezillon 	0xf5701efe,
2311a396789SBoris Brezillon 	0x000000ff,
2321a396789SBoris Brezillon 	0xf87c0dff,
2331a396789SBoris Brezillon 	0x00000000,
2341a396789SBoris Brezillon 	0x00800000,
2351a396789SBoris Brezillon 	0x00000000,
2361a396789SBoris Brezillon 	0x0d7cf800,
2371a396789SBoris Brezillon 	0x000000ff,
2381a396789SBoris Brezillon 	0x1e70f5ff,
2391a396789SBoris Brezillon 	0x000000fe,
2401a396789SBoris Brezillon 	0x335ff5fe,
2411a396789SBoris Brezillon 	0x000000fb,
2421a396789SBoris Brezillon };
2431a396789SBoris Brezillon 
2441a396789SBoris Brezillon static u32 heo_upscaling_ycoef[] = {
2451a396789SBoris Brezillon 	0x00004040,
2461a396789SBoris Brezillon 	0x00075920,
2471a396789SBoris Brezillon 	0x00056f0c,
2481a396789SBoris Brezillon 	0x00027b03,
2491a396789SBoris Brezillon 	0x00008000,
2501a396789SBoris Brezillon 	0x00037b02,
2511a396789SBoris Brezillon 	0x000c6f05,
2521a396789SBoris Brezillon 	0x00205907,
2531a396789SBoris Brezillon };
2541a396789SBoris Brezillon 
2559a45d33cSBoris Brezillon #define ATMEL_HLCDC_XPHIDEF	4
2569a45d33cSBoris Brezillon #define ATMEL_HLCDC_YPHIDEF	4
2579a45d33cSBoris Brezillon 
2589a45d33cSBoris Brezillon static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
2599a45d33cSBoris Brezillon 						  u32 dstsize,
2609a45d33cSBoris Brezillon 						  u32 phidef)
2619a45d33cSBoris Brezillon {
2629a45d33cSBoris Brezillon 	u32 factor, max_memsize;
2639a45d33cSBoris Brezillon 
2649a45d33cSBoris Brezillon 	factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
2659a45d33cSBoris Brezillon 	max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
2669a45d33cSBoris Brezillon 
2679a45d33cSBoris Brezillon 	if (max_memsize > srcsize - 1)
2689a45d33cSBoris Brezillon 		factor--;
2699a45d33cSBoris Brezillon 
2709a45d33cSBoris Brezillon 	return factor;
2719a45d33cSBoris Brezillon }
2729a45d33cSBoris Brezillon 
2739a45d33cSBoris Brezillon static void
2749a45d33cSBoris Brezillon atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
2759a45d33cSBoris Brezillon 				      const u32 *coeff_tab, int size,
2769a45d33cSBoris Brezillon 				      unsigned int cfg_offs)
2779a45d33cSBoris Brezillon {
2789a45d33cSBoris Brezillon 	int i;
2799a45d33cSBoris Brezillon 
2809a45d33cSBoris Brezillon 	for (i = 0; i < size; i++)
2819a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
2829a45d33cSBoris Brezillon 					    coeff_tab[i]);
2839a45d33cSBoris Brezillon }
2849a45d33cSBoris Brezillon 
2855f1f1099SLee Jones static void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
2869a45d33cSBoris Brezillon 					   struct atmel_hlcdc_plane_state *state)
2879a45d33cSBoris Brezillon {
2889a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
2899a45d33cSBoris Brezillon 	u32 xfactor, yfactor;
2909a45d33cSBoris Brezillon 
2919a45d33cSBoris Brezillon 	if (!desc->layout.scaler_config)
2929a45d33cSBoris Brezillon 		return;
2939a45d33cSBoris Brezillon 
2949a45d33cSBoris Brezillon 	if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
2959a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer,
2969a45d33cSBoris Brezillon 					    desc->layout.scaler_config, 0);
2979a45d33cSBoris Brezillon 		return;
2989a45d33cSBoris Brezillon 	}
2999a45d33cSBoris Brezillon 
3009a45d33cSBoris Brezillon 	if (desc->layout.phicoeffs.x) {
3019a45d33cSBoris Brezillon 		xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
3029a45d33cSBoris Brezillon 							state->crtc_w,
3039a45d33cSBoris Brezillon 							ATMEL_HLCDC_XPHIDEF);
3049a45d33cSBoris Brezillon 
3059a45d33cSBoris Brezillon 		yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
3069a45d33cSBoris Brezillon 							state->crtc_h,
3079a45d33cSBoris Brezillon 							ATMEL_HLCDC_YPHIDEF);
3089a45d33cSBoris Brezillon 
3099a45d33cSBoris Brezillon 		atmel_hlcdc_plane_scaler_set_phicoeff(plane,
3109a45d33cSBoris Brezillon 				state->crtc_w < state->src_w ?
3119a45d33cSBoris Brezillon 				heo_downscaling_xcoef :
3129a45d33cSBoris Brezillon 				heo_upscaling_xcoef,
3139a45d33cSBoris Brezillon 				ARRAY_SIZE(heo_upscaling_xcoef),
3149a45d33cSBoris Brezillon 				desc->layout.phicoeffs.x);
3159a45d33cSBoris Brezillon 
3169a45d33cSBoris Brezillon 		atmel_hlcdc_plane_scaler_set_phicoeff(plane,
3179a45d33cSBoris Brezillon 				state->crtc_h < state->src_h ?
3189a45d33cSBoris Brezillon 				heo_downscaling_ycoef :
3199a45d33cSBoris Brezillon 				heo_upscaling_ycoef,
3209a45d33cSBoris Brezillon 				ARRAY_SIZE(heo_upscaling_ycoef),
3219a45d33cSBoris Brezillon 				desc->layout.phicoeffs.y);
3229a45d33cSBoris Brezillon 	} else {
3239a45d33cSBoris Brezillon 		xfactor = (1024 * state->src_w) / state->crtc_w;
3249a45d33cSBoris Brezillon 		yfactor = (1024 * state->src_h) / state->crtc_h;
3259a45d33cSBoris Brezillon 	}
3269a45d33cSBoris Brezillon 
3279a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
3289a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_SCALER_ENABLE |
3299a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
3309a45d33cSBoris Brezillon 								     yfactor));
3319a45d33cSBoris Brezillon }
3329a45d33cSBoris Brezillon 
3331a396789SBoris Brezillon static void
3341a396789SBoris Brezillon atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
3352389fc13SBoris Brezillon 				      struct atmel_hlcdc_plane_state *state)
3361a396789SBoris Brezillon {
3379a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
3381a396789SBoris Brezillon 
3399a45d33cSBoris Brezillon 	if (desc->layout.size)
3409a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
3419a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
3429a45d33cSBoris Brezillon 							       state->crtc_h));
3431a396789SBoris Brezillon 
3449a45d33cSBoris Brezillon 	if (desc->layout.memsize)
3459a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer,
3469a45d33cSBoris Brezillon 					desc->layout.memsize,
3479a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_SIZE(state->src_w,
3489a45d33cSBoris Brezillon 							       state->src_h));
3491a396789SBoris Brezillon 
3509a45d33cSBoris Brezillon 	if (desc->layout.pos)
3519a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
3529a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_POS(state->crtc_x,
3539a45d33cSBoris Brezillon 							      state->crtc_y));
3541a396789SBoris Brezillon 
3559a45d33cSBoris Brezillon 	atmel_hlcdc_plane_setup_scaler(plane, state);
3561a396789SBoris Brezillon }
3571a396789SBoris Brezillon 
3581a396789SBoris Brezillon static void
3591a396789SBoris Brezillon atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
3602389fc13SBoris Brezillon 					struct atmel_hlcdc_plane_state *state)
3611a396789SBoris Brezillon {
3629a45d33cSBoris Brezillon 	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
3639a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
364e2e287faSMaxime Ripard 	const struct drm_format_info *format = state->base.fb->format;
3659a45d33cSBoris Brezillon 
3669a45d33cSBoris Brezillon 	/*
3679a45d33cSBoris Brezillon 	 * Rotation optimization is not working on RGB888 (rotation is still
3689a45d33cSBoris Brezillon 	 * working but without any optimization).
3699a45d33cSBoris Brezillon 	 */
370e2e287faSMaxime Ripard 	if (format->format == DRM_FORMAT_RGB888)
3719a45d33cSBoris Brezillon 		cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
3729a45d33cSBoris Brezillon 
3739a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
3749a45d33cSBoris Brezillon 				    cfg);
3759a45d33cSBoris Brezillon 
376e3c91a88SJoshua.Henderson@microchip.com 	cfg = ATMEL_HLCDC_LAYER_DMA | ATMEL_HLCDC_LAYER_REP;
3771a396789SBoris Brezillon 
3781a396789SBoris Brezillon 	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
3791a396789SBoris Brezillon 		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
3801a396789SBoris Brezillon 		       ATMEL_HLCDC_LAYER_ITER;
3811a396789SBoris Brezillon 
382e2e287faSMaxime Ripard 		if (format->has_alpha)
3831a396789SBoris Brezillon 			cfg |= ATMEL_HLCDC_LAYER_LAEN;
3841a396789SBoris Brezillon 		else
3852389fc13SBoris Brezillon 			cfg |= ATMEL_HLCDC_LAYER_GAEN |
386cbb32079SClaudiu Beznea 			       ATMEL_HLCDC_LAYER_GA(state->base.alpha);
3871a396789SBoris Brezillon 	}
3881a396789SBoris Brezillon 
3899a45d33cSBoris Brezillon 	if (state->disc_h && state->disc_w)
3909a45d33cSBoris Brezillon 		cfg |= ATMEL_HLCDC_LAYER_DISCEN;
3911a396789SBoris Brezillon 
3929a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
3939a45d33cSBoris Brezillon 				    cfg);
3941a396789SBoris Brezillon }
3951a396789SBoris Brezillon 
3961a396789SBoris Brezillon static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
3972389fc13SBoris Brezillon 					struct atmel_hlcdc_plane_state *state)
3981a396789SBoris Brezillon {
3991a396789SBoris Brezillon 	u32 cfg;
4001a396789SBoris Brezillon 	int ret;
4011a396789SBoris Brezillon 
402438b74a5SVille Syrjälä 	ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
4032389fc13SBoris Brezillon 					       &cfg);
4041a396789SBoris Brezillon 	if (ret)
4051a396789SBoris Brezillon 		return;
4061a396789SBoris Brezillon 
407438b74a5SVille Syrjälä 	if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
408438b74a5SVille Syrjälä 	     state->base.fb->format->format == DRM_FORMAT_NV61) &&
409bd2ef25dSVille Syrjälä 	    drm_rotation_90_or_270(state->base.rotation))
4101a396789SBoris Brezillon 		cfg |= ATMEL_HLCDC_YUV422ROT;
4111a396789SBoris Brezillon 
4129a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer,
4139a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
4141a396789SBoris Brezillon }
4151a396789SBoris Brezillon 
4160010ac3fSVille Syrjälä static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane,
4170010ac3fSVille Syrjälä 					  struct atmel_hlcdc_plane_state *state)
418364a7bf5SPeter Rosin {
4190010ac3fSVille Syrjälä 	struct drm_crtc *crtc = state->base.crtc;
420364a7bf5SPeter Rosin 	struct drm_color_lut *lut;
421364a7bf5SPeter Rosin 	int idx;
422364a7bf5SPeter Rosin 
423364a7bf5SPeter Rosin 	if (!crtc || !crtc->state)
424364a7bf5SPeter Rosin 		return;
425364a7bf5SPeter Rosin 
426364a7bf5SPeter Rosin 	if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
427364a7bf5SPeter Rosin 		return;
428364a7bf5SPeter Rosin 
429364a7bf5SPeter Rosin 	lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
430364a7bf5SPeter Rosin 
431364a7bf5SPeter Rosin 	for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
432364a7bf5SPeter Rosin 		u32 val = ((lut->red << 8) & 0xff0000) |
433364a7bf5SPeter Rosin 			(lut->green & 0xff00) |
434364a7bf5SPeter Rosin 			(lut->blue >> 8);
435364a7bf5SPeter Rosin 
436364a7bf5SPeter Rosin 		atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
437364a7bf5SPeter Rosin 	}
438364a7bf5SPeter Rosin }
439364a7bf5SPeter Rosin 
4401a396789SBoris Brezillon static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
4412389fc13SBoris Brezillon 					struct atmel_hlcdc_plane_state *state)
4421a396789SBoris Brezillon {
4439a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
4449a45d33cSBoris Brezillon 	struct drm_framebuffer *fb = state->base.fb;
4459a45d33cSBoris Brezillon 	u32 sr;
4461a396789SBoris Brezillon 	int i;
4471a396789SBoris Brezillon 
4489a45d33cSBoris Brezillon 	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
4491a396789SBoris Brezillon 
4502389fc13SBoris Brezillon 	for (i = 0; i < state->nplanes; i++) {
451*4a83c26aSDanilo Krummrich 		struct drm_gem_dma_object *gem = drm_fb_dma_get_gem_obj(fb, i);
4529a45d33cSBoris Brezillon 
4539a45d33cSBoris Brezillon 		state->dscrs[i]->addr = gem->paddr + state->offsets[i];
4549a45d33cSBoris Brezillon 
4559a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_reg(&plane->layer,
4569a45d33cSBoris Brezillon 					    ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
4579a45d33cSBoris Brezillon 					    state->dscrs[i]->self);
4589a45d33cSBoris Brezillon 
4599a45d33cSBoris Brezillon 		if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
4609a45d33cSBoris Brezillon 			atmel_hlcdc_layer_write_reg(&plane->layer,
4619a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
4629a45d33cSBoris Brezillon 					state->dscrs[i]->addr);
4639a45d33cSBoris Brezillon 			atmel_hlcdc_layer_write_reg(&plane->layer,
4649a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
4659a45d33cSBoris Brezillon 					state->dscrs[i]->ctrl);
4669a45d33cSBoris Brezillon 			atmel_hlcdc_layer_write_reg(&plane->layer,
4679a45d33cSBoris Brezillon 					ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
4689a45d33cSBoris Brezillon 					state->dscrs[i]->self);
4691a396789SBoris Brezillon 		}
4701a396789SBoris Brezillon 
4719a45d33cSBoris Brezillon 		if (desc->layout.xstride[i])
4729a45d33cSBoris Brezillon 			atmel_hlcdc_layer_write_cfg(&plane->layer,
4739a45d33cSBoris Brezillon 						    desc->layout.xstride[i],
4749a45d33cSBoris Brezillon 						    state->xstride[i]);
4759a45d33cSBoris Brezillon 
4769a45d33cSBoris Brezillon 		if (desc->layout.pstride[i])
4779a45d33cSBoris Brezillon 			atmel_hlcdc_layer_write_cfg(&plane->layer,
4789a45d33cSBoris Brezillon 						    desc->layout.pstride[i],
4792389fc13SBoris Brezillon 						    state->pstride[i]);
4801a396789SBoris Brezillon 	}
4811a396789SBoris Brezillon }
4821a396789SBoris Brezillon 
483ebab87abSBoris Brezillon int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
484ebab87abSBoris Brezillon {
485ebab87abSBoris Brezillon 	unsigned int ahb_load[2] = { };
486ebab87abSBoris Brezillon 	struct drm_plane *plane;
487ebab87abSBoris Brezillon 
488ebab87abSBoris Brezillon 	drm_atomic_crtc_state_for_each_plane(plane, c_state) {
489ebab87abSBoris Brezillon 		struct atmel_hlcdc_plane_state *plane_state;
490ebab87abSBoris Brezillon 		struct drm_plane_state *plane_s;
491ebab87abSBoris Brezillon 		unsigned int pixels, load = 0;
492ebab87abSBoris Brezillon 		int i;
493ebab87abSBoris Brezillon 
494ebab87abSBoris Brezillon 		plane_s = drm_atomic_get_plane_state(c_state->state, plane);
495ebab87abSBoris Brezillon 		if (IS_ERR(plane_s))
496ebab87abSBoris Brezillon 			return PTR_ERR(plane_s);
497ebab87abSBoris Brezillon 
498ebab87abSBoris Brezillon 		plane_state =
499ebab87abSBoris Brezillon 			drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
500ebab87abSBoris Brezillon 
501ebab87abSBoris Brezillon 		pixels = (plane_state->src_w * plane_state->src_h) -
502ebab87abSBoris Brezillon 			 (plane_state->disc_w * plane_state->disc_h);
503ebab87abSBoris Brezillon 
504ebab87abSBoris Brezillon 		for (i = 0; i < plane_state->nplanes; i++)
505ebab87abSBoris Brezillon 			load += pixels * plane_state->bpp[i];
506ebab87abSBoris Brezillon 
507ebab87abSBoris Brezillon 		if (ahb_load[0] <= ahb_load[1])
508ebab87abSBoris Brezillon 			plane_state->ahb_id = 0;
509ebab87abSBoris Brezillon 		else
510ebab87abSBoris Brezillon 			plane_state->ahb_id = 1;
511ebab87abSBoris Brezillon 
512ebab87abSBoris Brezillon 		ahb_load[plane_state->ahb_id] += load;
513ebab87abSBoris Brezillon 	}
514ebab87abSBoris Brezillon 
515ebab87abSBoris Brezillon 	return 0;
516ebab87abSBoris Brezillon }
517ebab87abSBoris Brezillon 
5185957017dSBoris Brezillon int
5195957017dSBoris Brezillon atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
5205957017dSBoris Brezillon {
5215957017dSBoris Brezillon 	int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
5225957017dSBoris Brezillon 	const struct atmel_hlcdc_layer_cfg_layout *layout;
5235957017dSBoris Brezillon 	struct atmel_hlcdc_plane_state *primary_state;
5245957017dSBoris Brezillon 	struct drm_plane_state *primary_s;
5255957017dSBoris Brezillon 	struct atmel_hlcdc_plane *primary;
5265957017dSBoris Brezillon 	struct drm_plane *ovl;
5275957017dSBoris Brezillon 
5285957017dSBoris Brezillon 	primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
5295957017dSBoris Brezillon 	layout = &primary->layer.desc->layout;
5305957017dSBoris Brezillon 	if (!layout->disc_pos || !layout->disc_size)
5315957017dSBoris Brezillon 		return 0;
5325957017dSBoris Brezillon 
5335957017dSBoris Brezillon 	primary_s = drm_atomic_get_plane_state(c_state->state,
5345957017dSBoris Brezillon 					       &primary->base);
5355957017dSBoris Brezillon 	if (IS_ERR(primary_s))
5365957017dSBoris Brezillon 		return PTR_ERR(primary_s);
5375957017dSBoris Brezillon 
5385957017dSBoris Brezillon 	primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
5395957017dSBoris Brezillon 
5405957017dSBoris Brezillon 	drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
5415957017dSBoris Brezillon 		struct atmel_hlcdc_plane_state *ovl_state;
5425957017dSBoris Brezillon 		struct drm_plane_state *ovl_s;
5435957017dSBoris Brezillon 
5445957017dSBoris Brezillon 		if (ovl == c_state->crtc->primary)
5455957017dSBoris Brezillon 			continue;
5465957017dSBoris Brezillon 
5475957017dSBoris Brezillon 		ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
5485957017dSBoris Brezillon 		if (IS_ERR(ovl_s))
5495957017dSBoris Brezillon 			return PTR_ERR(ovl_s);
5505957017dSBoris Brezillon 
5515957017dSBoris Brezillon 		ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
5525957017dSBoris Brezillon 
553ac109c82SPeter Rosin 		if (!ovl_s->visible ||
554ac109c82SPeter Rosin 		    !ovl_s->fb ||
555e2e287faSMaxime Ripard 		    ovl_s->fb->format->has_alpha ||
5567f73c10bSMaxime Ripard 		    ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
5575957017dSBoris Brezillon 			continue;
5585957017dSBoris Brezillon 
5595957017dSBoris Brezillon 		/* TODO: implement a smarter hidden area detection */
5605957017dSBoris Brezillon 		if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
5615957017dSBoris Brezillon 			continue;
5625957017dSBoris Brezillon 
5635957017dSBoris Brezillon 		disc_x = ovl_state->crtc_x;
5645957017dSBoris Brezillon 		disc_y = ovl_state->crtc_y;
5655957017dSBoris Brezillon 		disc_h = ovl_state->crtc_h;
5665957017dSBoris Brezillon 		disc_w = ovl_state->crtc_w;
5675957017dSBoris Brezillon 	}
5685957017dSBoris Brezillon 
5695957017dSBoris Brezillon 	primary_state->disc_x = disc_x;
5705957017dSBoris Brezillon 	primary_state->disc_y = disc_y;
5715957017dSBoris Brezillon 	primary_state->disc_w = disc_w;
5725957017dSBoris Brezillon 	primary_state->disc_h = disc_h;
5735957017dSBoris Brezillon 
5745957017dSBoris Brezillon 	return 0;
5755957017dSBoris Brezillon }
5765957017dSBoris Brezillon 
5775957017dSBoris Brezillon static void
5785957017dSBoris Brezillon atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
5795957017dSBoris Brezillon 				   struct atmel_hlcdc_plane_state *state)
5805957017dSBoris Brezillon {
5819a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_cfg_layout *layout;
5825957017dSBoris Brezillon 
5839a45d33cSBoris Brezillon 	layout = &plane->layer.desc->layout;
5849a45d33cSBoris Brezillon 	if (!layout->disc_pos || !layout->disc_size)
5855957017dSBoris Brezillon 		return;
5865957017dSBoris Brezillon 
5879a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
5889a45d33cSBoris Brezillon 				ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
5899a45d33cSBoris Brezillon 							   state->disc_y));
5905957017dSBoris Brezillon 
5919a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
5929a45d33cSBoris Brezillon 				ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
5939a45d33cSBoris Brezillon 							    state->disc_h));
5945957017dSBoris Brezillon }
5955957017dSBoris Brezillon 
5962389fc13SBoris Brezillon static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
5977c11b99aSMaxime Ripard 					  struct drm_atomic_state *state)
5981a396789SBoris Brezillon {
5997c11b99aSMaxime Ripard 	struct drm_plane_state *s = drm_atomic_get_new_plane_state(state, p);
6001a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
6016af70eb3SMaxime Ripard 	struct atmel_hlcdc_plane_state *hstate =
6022389fc13SBoris Brezillon 				drm_plane_state_to_atmel_hlcdc_plane_state(s);
6039a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
6046af70eb3SMaxime Ripard 	struct drm_framebuffer *fb = hstate->base.fb;
6052389fc13SBoris Brezillon 	const struct drm_display_mode *mode;
6062389fc13SBoris Brezillon 	struct drm_crtc_state *crtc_state;
607ac109c82SPeter Rosin 	int ret;
6081a396789SBoris Brezillon 	int i;
6091a396789SBoris Brezillon 
6106af70eb3SMaxime Ripard 	if (!hstate->base.crtc || WARN_ON(!fb))
6112389fc13SBoris Brezillon 		return 0;
6122389fc13SBoris Brezillon 
613dec92020SMaxime Ripard 	crtc_state = drm_atomic_get_existing_crtc_state(state, s->crtc);
6142389fc13SBoris Brezillon 	mode = &crtc_state->adjusted_mode;
6152389fc13SBoris Brezillon 
616ac109c82SPeter Rosin 	ret = drm_atomic_helper_check_plane_state(s, crtc_state,
617ac109c82SPeter Rosin 						  (1 << 16) / 2048,
618ac109c82SPeter Rosin 						  INT_MAX, true, true);
619ac109c82SPeter Rosin 	if (ret || !s->visible)
620ac109c82SPeter Rosin 		return ret;
621ac109c82SPeter Rosin 
6226af70eb3SMaxime Ripard 	hstate->src_x = s->src.x1;
6236af70eb3SMaxime Ripard 	hstate->src_y = s->src.y1;
6246af70eb3SMaxime Ripard 	hstate->src_w = drm_rect_width(&s->src);
6256af70eb3SMaxime Ripard 	hstate->src_h = drm_rect_height(&s->src);
6266af70eb3SMaxime Ripard 	hstate->crtc_x = s->dst.x1;
6276af70eb3SMaxime Ripard 	hstate->crtc_y = s->dst.y1;
6286af70eb3SMaxime Ripard 	hstate->crtc_w = drm_rect_width(&s->dst);
6296af70eb3SMaxime Ripard 	hstate->crtc_h = drm_rect_height(&s->dst);
630ac109c82SPeter Rosin 
6316af70eb3SMaxime Ripard 	if ((hstate->src_x | hstate->src_y | hstate->src_w | hstate->src_h) &
6321a396789SBoris Brezillon 	    SUBPIXEL_MASK)
6331a396789SBoris Brezillon 		return -EINVAL;
6341a396789SBoris Brezillon 
6356af70eb3SMaxime Ripard 	hstate->src_x >>= 16;
6366af70eb3SMaxime Ripard 	hstate->src_y >>= 16;
6376af70eb3SMaxime Ripard 	hstate->src_w >>= 16;
6386af70eb3SMaxime Ripard 	hstate->src_h >>= 16;
6391a396789SBoris Brezillon 
6406af70eb3SMaxime Ripard 	hstate->nplanes = fb->format->num_planes;
6416af70eb3SMaxime Ripard 	if (hstate->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
6421a396789SBoris Brezillon 		return -EINVAL;
6431a396789SBoris Brezillon 
6446af70eb3SMaxime Ripard 	for (i = 0; i < hstate->nplanes; i++) {
6451a396789SBoris Brezillon 		unsigned int offset = 0;
646f3e9632cSMaxime Ripard 		int xdiv = i ? fb->format->hsub : 1;
647f3e9632cSMaxime Ripard 		int ydiv = i ? fb->format->vsub : 1;
6481a396789SBoris Brezillon 
6496af70eb3SMaxime Ripard 		hstate->bpp[i] = fb->format->cpp[i];
6506af70eb3SMaxime Ripard 		if (!hstate->bpp[i])
6511a396789SBoris Brezillon 			return -EINVAL;
6521a396789SBoris Brezillon 
6536af70eb3SMaxime Ripard 		switch (hstate->base.rotation & DRM_MODE_ROTATE_MASK) {
654c2c446adSRobert Foss 		case DRM_MODE_ROTATE_90:
6556af70eb3SMaxime Ripard 			offset = (hstate->src_y / ydiv) *
6562389fc13SBoris Brezillon 				 fb->pitches[i];
6576af70eb3SMaxime Ripard 			offset += ((hstate->src_x + hstate->src_w - 1) /
6586af70eb3SMaxime Ripard 				   xdiv) * hstate->bpp[i];
6596af70eb3SMaxime Ripard 			hstate->xstride[i] = -(((hstate->src_h - 1) / ydiv) *
6608cdb00a5SPeter Rosin 					    fb->pitches[i]) -
6616af70eb3SMaxime Ripard 					  (2 * hstate->bpp[i]);
6626af70eb3SMaxime Ripard 			hstate->pstride[i] = fb->pitches[i] - hstate->bpp[i];
6631a396789SBoris Brezillon 			break;
664c2c446adSRobert Foss 		case DRM_MODE_ROTATE_180:
6656af70eb3SMaxime Ripard 			offset = ((hstate->src_y + hstate->src_h - 1) /
6662389fc13SBoris Brezillon 				  ydiv) * fb->pitches[i];
6676af70eb3SMaxime Ripard 			offset += ((hstate->src_x + hstate->src_w - 1) /
6686af70eb3SMaxime Ripard 				   xdiv) * hstate->bpp[i];
6696af70eb3SMaxime Ripard 			hstate->xstride[i] = ((((hstate->src_w - 1) / xdiv) - 1) *
6706af70eb3SMaxime Ripard 					   hstate->bpp[i]) - fb->pitches[i];
6716af70eb3SMaxime Ripard 			hstate->pstride[i] = -2 * hstate->bpp[i];
6721a396789SBoris Brezillon 			break;
673c2c446adSRobert Foss 		case DRM_MODE_ROTATE_270:
6746af70eb3SMaxime Ripard 			offset = ((hstate->src_y + hstate->src_h - 1) /
6758cdb00a5SPeter Rosin 				  ydiv) * fb->pitches[i];
6766af70eb3SMaxime Ripard 			offset += (hstate->src_x / xdiv) * hstate->bpp[i];
6776af70eb3SMaxime Ripard 			hstate->xstride[i] = ((hstate->src_h - 1) / ydiv) *
6782389fc13SBoris Brezillon 					  fb->pitches[i];
6796af70eb3SMaxime Ripard 			hstate->pstride[i] = -fb->pitches[i] - hstate->bpp[i];
6801a396789SBoris Brezillon 			break;
681c2c446adSRobert Foss 		case DRM_MODE_ROTATE_0:
6821a396789SBoris Brezillon 		default:
6836af70eb3SMaxime Ripard 			offset = (hstate->src_y / ydiv) * fb->pitches[i];
6846af70eb3SMaxime Ripard 			offset += (hstate->src_x / xdiv) * hstate->bpp[i];
6856af70eb3SMaxime Ripard 			hstate->xstride[i] = fb->pitches[i] -
6866af70eb3SMaxime Ripard 					  ((hstate->src_w / xdiv) *
6876af70eb3SMaxime Ripard 					   hstate->bpp[i]);
6886af70eb3SMaxime Ripard 			hstate->pstride[i] = 0;
6891a396789SBoris Brezillon 			break;
6901a396789SBoris Brezillon 		}
6911a396789SBoris Brezillon 
6926af70eb3SMaxime Ripard 		hstate->offsets[i] = offset + fb->offsets[i];
6931a396789SBoris Brezillon 	}
6941a396789SBoris Brezillon 
695ac109c82SPeter Rosin 	/*
696ac109c82SPeter Rosin 	 * Swap width and size in case of 90 or 270 degrees rotation
697ac109c82SPeter Rosin 	 */
6986af70eb3SMaxime Ripard 	if (drm_rotation_90_or_270(hstate->base.rotation)) {
6996af70eb3SMaxime Ripard 		swap(hstate->src_w, hstate->src_h);
700ac109c82SPeter Rosin 	}
7011a396789SBoris Brezillon 
7029a45d33cSBoris Brezillon 	if (!desc->layout.size &&
7036af70eb3SMaxime Ripard 	    (mode->hdisplay != hstate->crtc_w ||
7046af70eb3SMaxime Ripard 	     mode->vdisplay != hstate->crtc_h))
7052389fc13SBoris Brezillon 		return -EINVAL;
7061a396789SBoris Brezillon 
7076af70eb3SMaxime Ripard 	if ((hstate->crtc_h != hstate->src_h || hstate->crtc_w != hstate->src_w) &&
7089a45d33cSBoris Brezillon 	    (!desc->layout.memsize ||
7096af70eb3SMaxime Ripard 	     hstate->base.fb->format->has_alpha))
7102389fc13SBoris Brezillon 		return -EINVAL;
7111a396789SBoris Brezillon 
7121a396789SBoris Brezillon 	return 0;
7131a396789SBoris Brezillon }
7141a396789SBoris Brezillon 
715ac109c82SPeter Rosin static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
716977697e2SMaxime Ripard 					     struct drm_atomic_state *state)
717ac109c82SPeter Rosin {
718ac109c82SPeter Rosin 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
719ac109c82SPeter Rosin 
720ac109c82SPeter Rosin 	/* Disable interrupts */
721ac109c82SPeter Rosin 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
722ac109c82SPeter Rosin 				    0xffffffff);
723ac109c82SPeter Rosin 
724ac109c82SPeter Rosin 	/* Disable the layer */
725ac109c82SPeter Rosin 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
726ac109c82SPeter Rosin 				    ATMEL_HLCDC_LAYER_RST |
727ac109c82SPeter Rosin 				    ATMEL_HLCDC_LAYER_A2Q |
728ac109c82SPeter Rosin 				    ATMEL_HLCDC_LAYER_UPDATE);
729ac109c82SPeter Rosin 
730ac109c82SPeter Rosin 	/* Clear all pending interrupts */
731ac109c82SPeter Rosin 	atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
732ac109c82SPeter Rosin }
733ac109c82SPeter Rosin 
7342389fc13SBoris Brezillon static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
735977697e2SMaxime Ripard 					    struct drm_atomic_state *state)
7362389fc13SBoris Brezillon {
73737418bf1SMaxime Ripard 	struct drm_plane_state *new_s = drm_atomic_get_new_plane_state(state,
73837418bf1SMaxime Ripard 								       p);
7392389fc13SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
7406af70eb3SMaxime Ripard 	struct atmel_hlcdc_plane_state *hstate =
741e05162c0SMaxime Ripard 			drm_plane_state_to_atmel_hlcdc_plane_state(new_s);
7429a45d33cSBoris Brezillon 	u32 sr;
7432389fc13SBoris Brezillon 
744e05162c0SMaxime Ripard 	if (!new_s->crtc || !new_s->fb)
7452389fc13SBoris Brezillon 		return;
7462389fc13SBoris Brezillon 
7476af70eb3SMaxime Ripard 	if (!hstate->base.visible) {
748977697e2SMaxime Ripard 		atmel_hlcdc_plane_atomic_disable(p, state);
749ac109c82SPeter Rosin 		return;
750ac109c82SPeter Rosin 	}
751ac109c82SPeter Rosin 
7526af70eb3SMaxime Ripard 	atmel_hlcdc_plane_update_pos_and_size(plane, hstate);
7536af70eb3SMaxime Ripard 	atmel_hlcdc_plane_update_general_settings(plane, hstate);
7546af70eb3SMaxime Ripard 	atmel_hlcdc_plane_update_format(plane, hstate);
7556af70eb3SMaxime Ripard 	atmel_hlcdc_plane_update_clut(plane, hstate);
7566af70eb3SMaxime Ripard 	atmel_hlcdc_plane_update_buffers(plane, hstate);
7576af70eb3SMaxime Ripard 	atmel_hlcdc_plane_update_disc_area(plane, hstate);
7582389fc13SBoris Brezillon 
7599a45d33cSBoris Brezillon 	/* Enable the overrun interrupts. */
7609a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
7619a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
7629a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
7639a45d33cSBoris Brezillon 				    ATMEL_HLCDC_LAYER_OVR_IRQ(2));
7649a45d33cSBoris Brezillon 
7659a45d33cSBoris Brezillon 	/* Apply the new config at the next SOF event. */
7669a45d33cSBoris Brezillon 	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
7679a45d33cSBoris Brezillon 	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
7689a45d33cSBoris Brezillon 			ATMEL_HLCDC_LAYER_UPDATE |
7699a45d33cSBoris Brezillon 			(sr & ATMEL_HLCDC_LAYER_EN ?
7709a45d33cSBoris Brezillon 			 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
7712389fc13SBoris Brezillon }
7722389fc13SBoris Brezillon 
7737f73c10bSMaxime Ripard static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
7741a396789SBoris Brezillon {
7759a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
7761a396789SBoris Brezillon 
7771a396789SBoris Brezillon 	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
7787f73c10bSMaxime Ripard 	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
7797f73c10bSMaxime Ripard 		int ret;
7807f73c10bSMaxime Ripard 
7817f73c10bSMaxime Ripard 		ret = drm_plane_create_alpha_property(&plane->base);
7827f73c10bSMaxime Ripard 		if (ret)
7837f73c10bSMaxime Ripard 			return ret;
7847f73c10bSMaxime Ripard 	}
7851a396789SBoris Brezillon 
7869fcf2b3cSStefan Agner 	if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
7879fe58f01SVille Syrjälä 		int ret;
7889fe58f01SVille Syrjälä 
7899fe58f01SVille Syrjälä 		ret = drm_plane_create_rotation_property(&plane->base,
790c2c446adSRobert Foss 							 DRM_MODE_ROTATE_0,
791c2c446adSRobert Foss 							 DRM_MODE_ROTATE_0 |
792c2c446adSRobert Foss 							 DRM_MODE_ROTATE_90 |
793c2c446adSRobert Foss 							 DRM_MODE_ROTATE_180 |
794c2c446adSRobert Foss 							 DRM_MODE_ROTATE_270);
7959fe58f01SVille Syrjälä 		if (ret)
7969fe58f01SVille Syrjälä 			return ret;
7979fe58f01SVille Syrjälä 	}
7981a396789SBoris Brezillon 
7991a396789SBoris Brezillon 	if (desc->layout.csc) {
8001a396789SBoris Brezillon 		/*
8011a396789SBoris Brezillon 		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
8021a396789SBoris Brezillon 		 * userspace modify these factors (using a BLOB property ?).
8031a396789SBoris Brezillon 		 */
8049a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer,
8059a45d33cSBoris Brezillon 					    desc->layout.csc,
8061a396789SBoris Brezillon 					    0x4c900091);
8079a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer,
8089a45d33cSBoris Brezillon 					    desc->layout.csc + 1,
8091a396789SBoris Brezillon 					    0x7a5f5090);
8109a45d33cSBoris Brezillon 		atmel_hlcdc_layer_write_cfg(&plane->layer,
8119a45d33cSBoris Brezillon 					    desc->layout.csc + 2,
8121a396789SBoris Brezillon 					    0x40040890);
8131a396789SBoris Brezillon 	}
8149fe58f01SVille Syrjälä 
8159fe58f01SVille Syrjälä 	return 0;
8161a396789SBoris Brezillon }
8171a396789SBoris Brezillon 
8189a45d33cSBoris Brezillon void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
8199a45d33cSBoris Brezillon {
8209a45d33cSBoris Brezillon 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
8219a45d33cSBoris Brezillon 	u32 isr;
8229a45d33cSBoris Brezillon 
8239a45d33cSBoris Brezillon 	isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
8249a45d33cSBoris Brezillon 
8259a45d33cSBoris Brezillon 	/*
8269a45d33cSBoris Brezillon 	 * There's not much we can do in case of overrun except informing
8279a45d33cSBoris Brezillon 	 * the user. However, we are in interrupt context here, hence the
8289a45d33cSBoris Brezillon 	 * use of dev_dbg().
8299a45d33cSBoris Brezillon 	 */
8309a45d33cSBoris Brezillon 	if (isr &
8319a45d33cSBoris Brezillon 	    (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
8329a45d33cSBoris Brezillon 	     ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
8339a45d33cSBoris Brezillon 		dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
8349a45d33cSBoris Brezillon 			desc->name);
8359a45d33cSBoris Brezillon }
8369a45d33cSBoris Brezillon 
837d95a8e7bSArvind Yadav static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
8382389fc13SBoris Brezillon 	.atomic_check = atmel_hlcdc_plane_atomic_check,
8392389fc13SBoris Brezillon 	.atomic_update = atmel_hlcdc_plane_atomic_update,
8402389fc13SBoris Brezillon 	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
8412389fc13SBoris Brezillon };
8422389fc13SBoris Brezillon 
8439a45d33cSBoris Brezillon static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
8449a45d33cSBoris Brezillon 					 struct atmel_hlcdc_plane_state *state)
8459a45d33cSBoris Brezillon {
8469a45d33cSBoris Brezillon 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
8479a45d33cSBoris Brezillon 	int i;
8489a45d33cSBoris Brezillon 
8499a45d33cSBoris Brezillon 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
8509a45d33cSBoris Brezillon 		struct atmel_hlcdc_dma_channel_dscr *dscr;
8519a45d33cSBoris Brezillon 		dma_addr_t dscr_dma;
8529a45d33cSBoris Brezillon 
8539a45d33cSBoris Brezillon 		dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
8549a45d33cSBoris Brezillon 		if (!dscr)
8559a45d33cSBoris Brezillon 			goto err;
8569a45d33cSBoris Brezillon 
8579a45d33cSBoris Brezillon 		dscr->addr = 0;
8589a45d33cSBoris Brezillon 		dscr->next = dscr_dma;
8599a45d33cSBoris Brezillon 		dscr->self = dscr_dma;
8609a45d33cSBoris Brezillon 		dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
8619a45d33cSBoris Brezillon 
8629a45d33cSBoris Brezillon 		state->dscrs[i] = dscr;
8639a45d33cSBoris Brezillon 	}
8649a45d33cSBoris Brezillon 
8659a45d33cSBoris Brezillon 	return 0;
8669a45d33cSBoris Brezillon 
8679a45d33cSBoris Brezillon err:
8689a45d33cSBoris Brezillon 	for (i--; i >= 0; i--) {
8699a45d33cSBoris Brezillon 		dma_pool_free(dc->dscrpool, state->dscrs[i],
8709a45d33cSBoris Brezillon 			      state->dscrs[i]->self);
8719a45d33cSBoris Brezillon 	}
8729a45d33cSBoris Brezillon 
8739a45d33cSBoris Brezillon 	return -ENOMEM;
8749a45d33cSBoris Brezillon }
8759a45d33cSBoris Brezillon 
8762389fc13SBoris Brezillon static void atmel_hlcdc_plane_reset(struct drm_plane *p)
8772389fc13SBoris Brezillon {
8782389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_state *state;
8792389fc13SBoris Brezillon 
8802389fc13SBoris Brezillon 	if (p->state) {
8812389fc13SBoris Brezillon 		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
8822389fc13SBoris Brezillon 
8832389fc13SBoris Brezillon 		if (state->base.fb)
884f3a73544SCihangir Akturk 			drm_framebuffer_put(state->base.fb);
8852389fc13SBoris Brezillon 
8862389fc13SBoris Brezillon 		kfree(state);
8872389fc13SBoris Brezillon 		p->state = NULL;
8882389fc13SBoris Brezillon 	}
8892389fc13SBoris Brezillon 
8902389fc13SBoris Brezillon 	state = kzalloc(sizeof(*state), GFP_KERNEL);
8912389fc13SBoris Brezillon 	if (state) {
8929a45d33cSBoris Brezillon 		if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
8939a45d33cSBoris Brezillon 			kfree(state);
8949a45d33cSBoris Brezillon 			dev_err(p->dev->dev,
8959a45d33cSBoris Brezillon 				"Failed to allocate initial plane state\n");
8969a45d33cSBoris Brezillon 			return;
8979a45d33cSBoris Brezillon 		}
898e2512172SAlexandru Gheorghe 		__drm_atomic_helper_plane_reset(p, &state->base);
8992389fc13SBoris Brezillon 	}
9002389fc13SBoris Brezillon }
9012389fc13SBoris Brezillon 
9022389fc13SBoris Brezillon static struct drm_plane_state *
9032389fc13SBoris Brezillon atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
9042389fc13SBoris Brezillon {
9052389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_state *state =
9062389fc13SBoris Brezillon 			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
9072389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_state *copy;
9082389fc13SBoris Brezillon 
9092389fc13SBoris Brezillon 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
9102389fc13SBoris Brezillon 	if (!copy)
9112389fc13SBoris Brezillon 		return NULL;
9122389fc13SBoris Brezillon 
9139a45d33cSBoris Brezillon 	if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
9149a45d33cSBoris Brezillon 		kfree(copy);
9159a45d33cSBoris Brezillon 		return NULL;
9169a45d33cSBoris Brezillon 	}
9175957017dSBoris Brezillon 
9182389fc13SBoris Brezillon 	if (copy->base.fb)
919f3a73544SCihangir Akturk 		drm_framebuffer_get(copy->base.fb);
9202389fc13SBoris Brezillon 
9212389fc13SBoris Brezillon 	return &copy->base;
9222389fc13SBoris Brezillon }
9232389fc13SBoris Brezillon 
9249a45d33cSBoris Brezillon static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
9252389fc13SBoris Brezillon 						   struct drm_plane_state *s)
9262389fc13SBoris Brezillon {
9272389fc13SBoris Brezillon 	struct atmel_hlcdc_plane_state *state =
9282389fc13SBoris Brezillon 			drm_plane_state_to_atmel_hlcdc_plane_state(s);
9299a45d33cSBoris Brezillon 	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
9309a45d33cSBoris Brezillon 	int i;
9319a45d33cSBoris Brezillon 
9329a45d33cSBoris Brezillon 	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
9339a45d33cSBoris Brezillon 		dma_pool_free(dc->dscrpool, state->dscrs[i],
9349a45d33cSBoris Brezillon 			      state->dscrs[i]->self);
9359a45d33cSBoris Brezillon 	}
9362389fc13SBoris Brezillon 
9372389fc13SBoris Brezillon 	if (s->fb)
938f3a73544SCihangir Akturk 		drm_framebuffer_put(s->fb);
9392389fc13SBoris Brezillon 
9402389fc13SBoris Brezillon 	kfree(state);
9412389fc13SBoris Brezillon }
9422389fc13SBoris Brezillon 
943d95a8e7bSArvind Yadav static const struct drm_plane_funcs layer_plane_funcs = {
9442389fc13SBoris Brezillon 	.update_plane = drm_atomic_helper_update_plane,
9452389fc13SBoris Brezillon 	.disable_plane = drm_atomic_helper_disable_plane,
946952a08a2SVille Syrjälä 	.destroy = drm_plane_cleanup,
9472389fc13SBoris Brezillon 	.reset = atmel_hlcdc_plane_reset,
9482389fc13SBoris Brezillon 	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
9492389fc13SBoris Brezillon 	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
9501a396789SBoris Brezillon };
9511a396789SBoris Brezillon 
9529a45d33cSBoris Brezillon static int atmel_hlcdc_plane_create(struct drm_device *dev,
9537f73c10bSMaxime Ripard 				    const struct atmel_hlcdc_layer_desc *desc)
9541a396789SBoris Brezillon {
9559a45d33cSBoris Brezillon 	struct atmel_hlcdc_dc *dc = dev->dev_private;
9561a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane;
9571a396789SBoris Brezillon 	enum drm_plane_type type;
9581a396789SBoris Brezillon 	int ret;
9591a396789SBoris Brezillon 
9601a396789SBoris Brezillon 	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
9611a396789SBoris Brezillon 	if (!plane)
9629a45d33cSBoris Brezillon 		return -ENOMEM;
9631a396789SBoris Brezillon 
9649a45d33cSBoris Brezillon 	atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
9651a396789SBoris Brezillon 
9661a396789SBoris Brezillon 	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
9671a396789SBoris Brezillon 		type = DRM_PLANE_TYPE_PRIMARY;
9681a396789SBoris Brezillon 	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
9691a396789SBoris Brezillon 		type = DRM_PLANE_TYPE_CURSOR;
9701a396789SBoris Brezillon 	else
9711a396789SBoris Brezillon 		type = DRM_PLANE_TYPE_OVERLAY;
9721a396789SBoris Brezillon 
9731a396789SBoris Brezillon 	ret = drm_universal_plane_init(dev, &plane->base, 0,
9741a396789SBoris Brezillon 				       &layer_plane_funcs,
9751a396789SBoris Brezillon 				       desc->formats->formats,
976e6fc3b68SBen Widawsky 				       desc->formats->nformats,
977e6fc3b68SBen Widawsky 				       NULL, type, NULL);
9781a396789SBoris Brezillon 	if (ret)
9799a45d33cSBoris Brezillon 		return ret;
9801a396789SBoris Brezillon 
9812389fc13SBoris Brezillon 	drm_plane_helper_add(&plane->base,
9822389fc13SBoris Brezillon 			     &atmel_hlcdc_layer_plane_helper_funcs);
9832389fc13SBoris Brezillon 
9841a396789SBoris Brezillon 	/* Set default property values*/
9857f73c10bSMaxime Ripard 	ret = atmel_hlcdc_plane_init_properties(plane);
9869fe58f01SVille Syrjälä 	if (ret)
9879a45d33cSBoris Brezillon 		return ret;
9881a396789SBoris Brezillon 
9899a45d33cSBoris Brezillon 	dc->layers[desc->id] = &plane->layer;
9909a45d33cSBoris Brezillon 
9919a45d33cSBoris Brezillon 	return 0;
9921a396789SBoris Brezillon }
9931a396789SBoris Brezillon 
9949a45d33cSBoris Brezillon int atmel_hlcdc_create_planes(struct drm_device *dev)
9951a396789SBoris Brezillon {
9961a396789SBoris Brezillon 	struct atmel_hlcdc_dc *dc = dev->dev_private;
9971a396789SBoris Brezillon 	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
9981a396789SBoris Brezillon 	int nlayers = dc->desc->nlayers;
9999a45d33cSBoris Brezillon 	int i, ret;
10001a396789SBoris Brezillon 
10019a45d33cSBoris Brezillon 	dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
10029a45d33cSBoris Brezillon 				sizeof(struct atmel_hlcdc_dma_channel_dscr),
10039a45d33cSBoris Brezillon 				sizeof(u64), 0);
10049a45d33cSBoris Brezillon 	if (!dc->dscrpool)
10059a45d33cSBoris Brezillon 		return -ENOMEM;
10069a45d33cSBoris Brezillon 
10071a396789SBoris Brezillon 	for (i = 0; i < nlayers; i++) {
10089a45d33cSBoris Brezillon 		if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
10099a45d33cSBoris Brezillon 		    descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
10109a45d33cSBoris Brezillon 		    descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
10111a396789SBoris Brezillon 			continue;
10121a396789SBoris Brezillon 
10137f73c10bSMaxime Ripard 		ret = atmel_hlcdc_plane_create(dev, &descs[i]);
10149a45d33cSBoris Brezillon 		if (ret)
10159a45d33cSBoris Brezillon 			return ret;
10161a396789SBoris Brezillon 	}
10171a396789SBoris Brezillon 
10189a45d33cSBoris Brezillon 	return 0;
10191a396789SBoris Brezillon }
1020