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 
221a396789SBoris Brezillon #define SUBPIXEL_MASK			0xffff
231a396789SBoris Brezillon 
241a396789SBoris Brezillon static uint32_t rgb_formats[] = {
251a396789SBoris Brezillon 	DRM_FORMAT_XRGB4444,
261a396789SBoris Brezillon 	DRM_FORMAT_ARGB4444,
271a396789SBoris Brezillon 	DRM_FORMAT_RGBA4444,
281a396789SBoris Brezillon 	DRM_FORMAT_ARGB1555,
291a396789SBoris Brezillon 	DRM_FORMAT_RGB565,
301a396789SBoris Brezillon 	DRM_FORMAT_RGB888,
311a396789SBoris Brezillon 	DRM_FORMAT_XRGB8888,
321a396789SBoris Brezillon 	DRM_FORMAT_ARGB8888,
331a396789SBoris Brezillon 	DRM_FORMAT_RGBA8888,
341a396789SBoris Brezillon };
351a396789SBoris Brezillon 
361a396789SBoris Brezillon struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
371a396789SBoris Brezillon 	.formats = rgb_formats,
381a396789SBoris Brezillon 	.nformats = ARRAY_SIZE(rgb_formats),
391a396789SBoris Brezillon };
401a396789SBoris Brezillon 
411a396789SBoris Brezillon static uint32_t rgb_and_yuv_formats[] = {
421a396789SBoris Brezillon 	DRM_FORMAT_XRGB4444,
431a396789SBoris Brezillon 	DRM_FORMAT_ARGB4444,
441a396789SBoris Brezillon 	DRM_FORMAT_RGBA4444,
451a396789SBoris Brezillon 	DRM_FORMAT_ARGB1555,
461a396789SBoris Brezillon 	DRM_FORMAT_RGB565,
471a396789SBoris Brezillon 	DRM_FORMAT_RGB888,
481a396789SBoris Brezillon 	DRM_FORMAT_XRGB8888,
491a396789SBoris Brezillon 	DRM_FORMAT_ARGB8888,
501a396789SBoris Brezillon 	DRM_FORMAT_RGBA8888,
511a396789SBoris Brezillon 	DRM_FORMAT_AYUV,
521a396789SBoris Brezillon 	DRM_FORMAT_YUYV,
531a396789SBoris Brezillon 	DRM_FORMAT_UYVY,
541a396789SBoris Brezillon 	DRM_FORMAT_YVYU,
551a396789SBoris Brezillon 	DRM_FORMAT_VYUY,
561a396789SBoris Brezillon 	DRM_FORMAT_NV21,
571a396789SBoris Brezillon 	DRM_FORMAT_NV61,
581a396789SBoris Brezillon 	DRM_FORMAT_YUV422,
591a396789SBoris Brezillon 	DRM_FORMAT_YUV420,
601a396789SBoris Brezillon };
611a396789SBoris Brezillon 
621a396789SBoris Brezillon struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
631a396789SBoris Brezillon 	.formats = rgb_and_yuv_formats,
641a396789SBoris Brezillon 	.nformats = ARRAY_SIZE(rgb_and_yuv_formats),
651a396789SBoris Brezillon };
661a396789SBoris Brezillon 
671a396789SBoris Brezillon static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
681a396789SBoris Brezillon {
691a396789SBoris Brezillon 	switch (format) {
701a396789SBoris Brezillon 	case DRM_FORMAT_XRGB4444:
711a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_XRGB4444_MODE;
721a396789SBoris Brezillon 		break;
731a396789SBoris Brezillon 	case DRM_FORMAT_ARGB4444:
741a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_ARGB4444_MODE;
751a396789SBoris Brezillon 		break;
761a396789SBoris Brezillon 	case DRM_FORMAT_RGBA4444:
771a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGBA4444_MODE;
781a396789SBoris Brezillon 		break;
791a396789SBoris Brezillon 	case DRM_FORMAT_RGB565:
801a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGB565_MODE;
811a396789SBoris Brezillon 		break;
821a396789SBoris Brezillon 	case DRM_FORMAT_RGB888:
831a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGB888_MODE;
841a396789SBoris Brezillon 		break;
851a396789SBoris Brezillon 	case DRM_FORMAT_ARGB1555:
861a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_ARGB1555_MODE;
871a396789SBoris Brezillon 		break;
881a396789SBoris Brezillon 	case DRM_FORMAT_XRGB8888:
891a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_XRGB8888_MODE;
901a396789SBoris Brezillon 		break;
911a396789SBoris Brezillon 	case DRM_FORMAT_ARGB8888:
921a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_ARGB8888_MODE;
931a396789SBoris Brezillon 		break;
941a396789SBoris Brezillon 	case DRM_FORMAT_RGBA8888:
951a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_RGBA8888_MODE;
961a396789SBoris Brezillon 		break;
971a396789SBoris Brezillon 	case DRM_FORMAT_AYUV:
981a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_AYUV_MODE;
991a396789SBoris Brezillon 		break;
1001a396789SBoris Brezillon 	case DRM_FORMAT_YUYV:
1011a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YUYV_MODE;
1021a396789SBoris Brezillon 		break;
1031a396789SBoris Brezillon 	case DRM_FORMAT_UYVY:
1041a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_UYVY_MODE;
1051a396789SBoris Brezillon 		break;
1061a396789SBoris Brezillon 	case DRM_FORMAT_YVYU:
1071a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YVYU_MODE;
1081a396789SBoris Brezillon 		break;
1091a396789SBoris Brezillon 	case DRM_FORMAT_VYUY:
1101a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_VYUY_MODE;
1111a396789SBoris Brezillon 		break;
1121a396789SBoris Brezillon 	case DRM_FORMAT_NV21:
1131a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_NV21_MODE;
1141a396789SBoris Brezillon 		break;
1151a396789SBoris Brezillon 	case DRM_FORMAT_NV61:
1161a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_NV61_MODE;
1171a396789SBoris Brezillon 		break;
1181a396789SBoris Brezillon 	case DRM_FORMAT_YUV420:
1191a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YUV420_MODE;
1201a396789SBoris Brezillon 		break;
1211a396789SBoris Brezillon 	case DRM_FORMAT_YUV422:
1221a396789SBoris Brezillon 		*mode = ATMEL_HLCDC_YUV422_MODE;
1231a396789SBoris Brezillon 		break;
1241a396789SBoris Brezillon 	default:
1251a396789SBoris Brezillon 		return -ENOTSUPP;
1261a396789SBoris Brezillon 	}
1271a396789SBoris Brezillon 
1281a396789SBoris Brezillon 	return 0;
1291a396789SBoris Brezillon }
1301a396789SBoris Brezillon 
1311a396789SBoris Brezillon static bool atmel_hlcdc_format_embedds_alpha(u32 format)
1321a396789SBoris Brezillon {
1331a396789SBoris Brezillon 	int i;
1341a396789SBoris Brezillon 
1351a396789SBoris Brezillon 	for (i = 0; i < sizeof(format); i++) {
1361a396789SBoris Brezillon 		char tmp = (format >> (8 * i)) & 0xff;
1371a396789SBoris Brezillon 
1381a396789SBoris Brezillon 		if (tmp == 'A')
1391a396789SBoris Brezillon 			return true;
1401a396789SBoris Brezillon 	}
1411a396789SBoris Brezillon 
1421a396789SBoris Brezillon 	return false;
1431a396789SBoris Brezillon }
1441a396789SBoris Brezillon 
1451a396789SBoris Brezillon static u32 heo_downscaling_xcoef[] = {
1461a396789SBoris Brezillon 	0x11343311,
1471a396789SBoris Brezillon 	0x000000f7,
1481a396789SBoris Brezillon 	0x1635300c,
1491a396789SBoris Brezillon 	0x000000f9,
1501a396789SBoris Brezillon 	0x1b362c08,
1511a396789SBoris Brezillon 	0x000000fb,
1521a396789SBoris Brezillon 	0x1f372804,
1531a396789SBoris Brezillon 	0x000000fe,
1541a396789SBoris Brezillon 	0x24382400,
1551a396789SBoris Brezillon 	0x00000000,
1561a396789SBoris Brezillon 	0x28371ffe,
1571a396789SBoris Brezillon 	0x00000004,
1581a396789SBoris Brezillon 	0x2c361bfb,
1591a396789SBoris Brezillon 	0x00000008,
1601a396789SBoris Brezillon 	0x303516f9,
1611a396789SBoris Brezillon 	0x0000000c,
1621a396789SBoris Brezillon };
1631a396789SBoris Brezillon 
1641a396789SBoris Brezillon static u32 heo_downscaling_ycoef[] = {
1651a396789SBoris Brezillon 	0x00123737,
1661a396789SBoris Brezillon 	0x00173732,
1671a396789SBoris Brezillon 	0x001b382d,
1681a396789SBoris Brezillon 	0x001f3928,
1691a396789SBoris Brezillon 	0x00243824,
1701a396789SBoris Brezillon 	0x0028391f,
1711a396789SBoris Brezillon 	0x002d381b,
1721a396789SBoris Brezillon 	0x00323717,
1731a396789SBoris Brezillon };
1741a396789SBoris Brezillon 
1751a396789SBoris Brezillon static u32 heo_upscaling_xcoef[] = {
1761a396789SBoris Brezillon 	0xf74949f7,
1771a396789SBoris Brezillon 	0x00000000,
1781a396789SBoris Brezillon 	0xf55f33fb,
1791a396789SBoris Brezillon 	0x000000fe,
1801a396789SBoris Brezillon 	0xf5701efe,
1811a396789SBoris Brezillon 	0x000000ff,
1821a396789SBoris Brezillon 	0xf87c0dff,
1831a396789SBoris Brezillon 	0x00000000,
1841a396789SBoris Brezillon 	0x00800000,
1851a396789SBoris Brezillon 	0x00000000,
1861a396789SBoris Brezillon 	0x0d7cf800,
1871a396789SBoris Brezillon 	0x000000ff,
1881a396789SBoris Brezillon 	0x1e70f5ff,
1891a396789SBoris Brezillon 	0x000000fe,
1901a396789SBoris Brezillon 	0x335ff5fe,
1911a396789SBoris Brezillon 	0x000000fb,
1921a396789SBoris Brezillon };
1931a396789SBoris Brezillon 
1941a396789SBoris Brezillon static u32 heo_upscaling_ycoef[] = {
1951a396789SBoris Brezillon 	0x00004040,
1961a396789SBoris Brezillon 	0x00075920,
1971a396789SBoris Brezillon 	0x00056f0c,
1981a396789SBoris Brezillon 	0x00027b03,
1991a396789SBoris Brezillon 	0x00008000,
2001a396789SBoris Brezillon 	0x00037b02,
2011a396789SBoris Brezillon 	0x000c6f05,
2021a396789SBoris Brezillon 	0x00205907,
2031a396789SBoris Brezillon };
2041a396789SBoris Brezillon 
2051a396789SBoris Brezillon static void
2061a396789SBoris Brezillon atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
2071a396789SBoris Brezillon 				struct atmel_hlcdc_plane_update_req *req)
2081a396789SBoris Brezillon {
2091a396789SBoris Brezillon 	const struct atmel_hlcdc_layer_cfg_layout *layout =
2101a396789SBoris Brezillon 						&plane->layer.desc->layout;
2111a396789SBoris Brezillon 
2121a396789SBoris Brezillon 	if (layout->size)
2131a396789SBoris Brezillon 		atmel_hlcdc_layer_update_cfg(&plane->layer,
2141a396789SBoris Brezillon 					     layout->size,
2151a396789SBoris Brezillon 					     0xffffffff,
2161a396789SBoris Brezillon 					     (req->crtc_w - 1) |
2171a396789SBoris Brezillon 					     ((req->crtc_h - 1) << 16));
2181a396789SBoris Brezillon 
2191a396789SBoris Brezillon 	if (layout->memsize)
2201a396789SBoris Brezillon 		atmel_hlcdc_layer_update_cfg(&plane->layer,
2211a396789SBoris Brezillon 					     layout->memsize,
2221a396789SBoris Brezillon 					     0xffffffff,
2231a396789SBoris Brezillon 					     (req->src_w - 1) |
2241a396789SBoris Brezillon 					     ((req->src_h - 1) << 16));
2251a396789SBoris Brezillon 
2261a396789SBoris Brezillon 	if (layout->pos)
2271a396789SBoris Brezillon 		atmel_hlcdc_layer_update_cfg(&plane->layer,
2281a396789SBoris Brezillon 					     layout->pos,
2291a396789SBoris Brezillon 					     0xffffffff,
2301a396789SBoris Brezillon 					     req->crtc_x |
2311a396789SBoris Brezillon 					     (req->crtc_y  << 16));
2321a396789SBoris Brezillon 
2331a396789SBoris Brezillon 	/* TODO: rework the rescaling part */
2341a396789SBoris Brezillon 	if (req->crtc_w != req->src_w || req->crtc_h != req->src_h) {
2351a396789SBoris Brezillon 		u32 factor_reg = 0;
2361a396789SBoris Brezillon 
2371a396789SBoris Brezillon 		if (req->crtc_w != req->src_w) {
2381a396789SBoris Brezillon 			int i;
2391a396789SBoris Brezillon 			u32 factor;
2401a396789SBoris Brezillon 			u32 *coeff_tab = heo_upscaling_xcoef;
2411a396789SBoris Brezillon 			u32 max_memsize;
2421a396789SBoris Brezillon 
2431a396789SBoris Brezillon 			if (req->crtc_w < req->src_w)
2441a396789SBoris Brezillon 				coeff_tab = heo_downscaling_xcoef;
2451a396789SBoris Brezillon 			for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
2461a396789SBoris Brezillon 				atmel_hlcdc_layer_update_cfg(&plane->layer,
2471a396789SBoris Brezillon 							     17 + i,
2481a396789SBoris Brezillon 							     0xffffffff,
2491a396789SBoris Brezillon 							     coeff_tab[i]);
2501a396789SBoris Brezillon 			factor = ((8 * 256 * req->src_w) - (256 * 4)) /
2511a396789SBoris Brezillon 				 req->crtc_w;
2521a396789SBoris Brezillon 			factor++;
2531a396789SBoris Brezillon 			max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
2541a396789SBoris Brezillon 				      2048;
2551a396789SBoris Brezillon 			if (max_memsize > req->src_w)
2561a396789SBoris Brezillon 				factor--;
2571a396789SBoris Brezillon 			factor_reg |= factor | 0x80000000;
2581a396789SBoris Brezillon 		}
2591a396789SBoris Brezillon 
2601a396789SBoris Brezillon 		if (req->crtc_h != req->src_h) {
2611a396789SBoris Brezillon 			int i;
2621a396789SBoris Brezillon 			u32 factor;
2631a396789SBoris Brezillon 			u32 *coeff_tab = heo_upscaling_ycoef;
2641a396789SBoris Brezillon 			u32 max_memsize;
2651a396789SBoris Brezillon 
2661a396789SBoris Brezillon 			if (req->crtc_w < req->src_w)
2671a396789SBoris Brezillon 				coeff_tab = heo_downscaling_ycoef;
2681a396789SBoris Brezillon 			for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
2691a396789SBoris Brezillon 				atmel_hlcdc_layer_update_cfg(&plane->layer,
2701a396789SBoris Brezillon 							     33 + i,
2711a396789SBoris Brezillon 							     0xffffffff,
2721a396789SBoris Brezillon 							     coeff_tab[i]);
2731a396789SBoris Brezillon 			factor = ((8 * 256 * req->src_w) - (256 * 4)) /
2741a396789SBoris Brezillon 				 req->crtc_w;
2751a396789SBoris Brezillon 			factor++;
2761a396789SBoris Brezillon 			max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
2771a396789SBoris Brezillon 				      2048;
2781a396789SBoris Brezillon 			if (max_memsize > req->src_w)
2791a396789SBoris Brezillon 				factor--;
2801a396789SBoris Brezillon 			factor_reg |= (factor << 16) | 0x80000000;
2811a396789SBoris Brezillon 		}
2821a396789SBoris Brezillon 
2831a396789SBoris Brezillon 		atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
2841a396789SBoris Brezillon 					     factor_reg);
2851a396789SBoris Brezillon 	}
2861a396789SBoris Brezillon }
2871a396789SBoris Brezillon 
2881a396789SBoris Brezillon static void
2891a396789SBoris Brezillon atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
2901a396789SBoris Brezillon 				struct atmel_hlcdc_plane_update_req *req)
2911a396789SBoris Brezillon {
2921a396789SBoris Brezillon 	const struct atmel_hlcdc_layer_cfg_layout *layout =
2931a396789SBoris Brezillon 						&plane->layer.desc->layout;
2941a396789SBoris Brezillon 	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
2951a396789SBoris Brezillon 
2961a396789SBoris Brezillon 	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
2971a396789SBoris Brezillon 		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
2981a396789SBoris Brezillon 		       ATMEL_HLCDC_LAYER_ITER;
2991a396789SBoris Brezillon 
3001a396789SBoris Brezillon 		if (atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format))
3011a396789SBoris Brezillon 			cfg |= ATMEL_HLCDC_LAYER_LAEN;
3021a396789SBoris Brezillon 		else
3031a396789SBoris Brezillon 			cfg |= ATMEL_HLCDC_LAYER_GAEN;
3041a396789SBoris Brezillon 	}
3051a396789SBoris Brezillon 
3061a396789SBoris Brezillon 	atmel_hlcdc_layer_update_cfg(&plane->layer,
3071a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_DMA_CFG_ID,
3081a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_DMA_BLEN_MASK,
3091a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16);
3101a396789SBoris Brezillon 
3111a396789SBoris Brezillon 	atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
3121a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_ITER2BL |
3131a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_ITER |
3141a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_GAEN |
3151a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_LAEN |
3161a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_OVR |
3171a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_DMA, cfg);
3181a396789SBoris Brezillon }
3191a396789SBoris Brezillon 
3201a396789SBoris Brezillon static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
3211a396789SBoris Brezillon 				struct atmel_hlcdc_plane_update_req *req)
3221a396789SBoris Brezillon {
3231a396789SBoris Brezillon 	u32 cfg;
3241a396789SBoris Brezillon 	int ret;
3251a396789SBoris Brezillon 
3261a396789SBoris Brezillon 	ret = atmel_hlcdc_format_to_plane_mode(req->fb->pixel_format, &cfg);
3271a396789SBoris Brezillon 	if (ret)
3281a396789SBoris Brezillon 		return;
3291a396789SBoris Brezillon 
3301a396789SBoris Brezillon 	if ((req->fb->pixel_format == DRM_FORMAT_YUV422 ||
3311a396789SBoris Brezillon 	     req->fb->pixel_format == DRM_FORMAT_NV61) &&
3321a396789SBoris Brezillon 	    (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
3331a396789SBoris Brezillon 		cfg |= ATMEL_HLCDC_YUV422ROT;
3341a396789SBoris Brezillon 
3351a396789SBoris Brezillon 	atmel_hlcdc_layer_update_cfg(&plane->layer,
3361a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
3371a396789SBoris Brezillon 				     0xffffffff,
3381a396789SBoris Brezillon 				     cfg);
3391a396789SBoris Brezillon 
3401a396789SBoris Brezillon 	/*
3411a396789SBoris Brezillon 	 * Rotation optimization is not working on RGB888 (rotation is still
3421a396789SBoris Brezillon 	 * working but without any optimization).
3431a396789SBoris Brezillon 	 */
3441a396789SBoris Brezillon 	if (req->fb->pixel_format == DRM_FORMAT_RGB888)
3451a396789SBoris Brezillon 		cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
3461a396789SBoris Brezillon 	else
3471a396789SBoris Brezillon 		cfg = 0;
3481a396789SBoris Brezillon 
3491a396789SBoris Brezillon 	atmel_hlcdc_layer_update_cfg(&plane->layer,
3501a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_DMA_CFG_ID,
3511a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
3521a396789SBoris Brezillon }
3531a396789SBoris Brezillon 
3541a396789SBoris Brezillon static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
3551a396789SBoris Brezillon 				struct atmel_hlcdc_plane_update_req *req)
3561a396789SBoris Brezillon {
3571a396789SBoris Brezillon 	struct atmel_hlcdc_layer *layer = &plane->layer;
3581a396789SBoris Brezillon 	const struct atmel_hlcdc_layer_cfg_layout *layout =
3591a396789SBoris Brezillon 							&layer->desc->layout;
3601a396789SBoris Brezillon 	int i;
3611a396789SBoris Brezillon 
3621a396789SBoris Brezillon 	atmel_hlcdc_layer_update_set_fb(&plane->layer, req->fb, req->offsets);
3631a396789SBoris Brezillon 
3641a396789SBoris Brezillon 	for (i = 0; i < req->nplanes; i++) {
3651a396789SBoris Brezillon 		if (layout->xstride[i]) {
3661a396789SBoris Brezillon 			atmel_hlcdc_layer_update_cfg(&plane->layer,
3671a396789SBoris Brezillon 						layout->xstride[i],
3681a396789SBoris Brezillon 						0xffffffff,
3691a396789SBoris Brezillon 						req->xstride[i]);
3701a396789SBoris Brezillon 		}
3711a396789SBoris Brezillon 
3721a396789SBoris Brezillon 		if (layout->pstride[i]) {
3731a396789SBoris Brezillon 			atmel_hlcdc_layer_update_cfg(&plane->layer,
3741a396789SBoris Brezillon 						layout->pstride[i],
3751a396789SBoris Brezillon 						0xffffffff,
3761a396789SBoris Brezillon 						req->pstride[i]);
3771a396789SBoris Brezillon 		}
3781a396789SBoris Brezillon 	}
3791a396789SBoris Brezillon }
3801a396789SBoris Brezillon 
3811a396789SBoris Brezillon static int atmel_hlcdc_plane_check_update_req(struct drm_plane *p,
3821a396789SBoris Brezillon 				struct atmel_hlcdc_plane_update_req *req,
3831a396789SBoris Brezillon 				const struct drm_display_mode *mode)
3841a396789SBoris Brezillon {
3851a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
3861a396789SBoris Brezillon 	const struct atmel_hlcdc_layer_cfg_layout *layout =
3871a396789SBoris Brezillon 						&plane->layer.desc->layout;
3881a396789SBoris Brezillon 
3891a396789SBoris Brezillon 	if (!layout->size &&
3901a396789SBoris Brezillon 	    (mode->hdisplay != req->crtc_w ||
3911a396789SBoris Brezillon 	     mode->vdisplay != req->crtc_h))
3921a396789SBoris Brezillon 		return -EINVAL;
3931a396789SBoris Brezillon 
3941a396789SBoris Brezillon 	if (plane->layer.desc->max_height &&
3951a396789SBoris Brezillon 	    req->crtc_h > plane->layer.desc->max_height)
3961a396789SBoris Brezillon 		return -EINVAL;
3971a396789SBoris Brezillon 
3981a396789SBoris Brezillon 	if (plane->layer.desc->max_width &&
3991a396789SBoris Brezillon 	    req->crtc_w > plane->layer.desc->max_width)
4001a396789SBoris Brezillon 		return -EINVAL;
4011a396789SBoris Brezillon 
4021a396789SBoris Brezillon 	if ((req->crtc_h != req->src_h || req->crtc_w != req->src_w) &&
4031a396789SBoris Brezillon 	    (!layout->memsize ||
4041a396789SBoris Brezillon 	     atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format)))
4051a396789SBoris Brezillon 		return -EINVAL;
4061a396789SBoris Brezillon 
4071a396789SBoris Brezillon 	if (req->crtc_x < 0 || req->crtc_y < 0)
4081a396789SBoris Brezillon 		return -EINVAL;
4091a396789SBoris Brezillon 
4101a396789SBoris Brezillon 	if (req->crtc_w + req->crtc_x > mode->hdisplay ||
4111a396789SBoris Brezillon 	    req->crtc_h + req->crtc_y > mode->vdisplay)
4121a396789SBoris Brezillon 		return -EINVAL;
4131a396789SBoris Brezillon 
4141a396789SBoris Brezillon 	return 0;
4151a396789SBoris Brezillon }
4161a396789SBoris Brezillon 
4171a396789SBoris Brezillon int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
4181a396789SBoris Brezillon 				struct atmel_hlcdc_plane_update_req *req,
4191a396789SBoris Brezillon 				const struct drm_display_mode *mode)
4201a396789SBoris Brezillon {
4211a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
4221a396789SBoris Brezillon 	unsigned int patched_crtc_w;
4231a396789SBoris Brezillon 	unsigned int patched_crtc_h;
4241a396789SBoris Brezillon 	unsigned int patched_src_w;
4251a396789SBoris Brezillon 	unsigned int patched_src_h;
4261a396789SBoris Brezillon 	unsigned int tmp;
4271a396789SBoris Brezillon 	int x_offset = 0;
4281a396789SBoris Brezillon 	int y_offset = 0;
4291a396789SBoris Brezillon 	int hsub = 1;
4301a396789SBoris Brezillon 	int vsub = 1;
4311a396789SBoris Brezillon 	int i;
4321a396789SBoris Brezillon 
4331a396789SBoris Brezillon 	if ((req->src_x | req->src_y | req->src_w | req->src_h) &
4341a396789SBoris Brezillon 	    SUBPIXEL_MASK)
4351a396789SBoris Brezillon 		return -EINVAL;
4361a396789SBoris Brezillon 
4371a396789SBoris Brezillon 	req->src_x >>= 16;
4381a396789SBoris Brezillon 	req->src_y >>= 16;
4391a396789SBoris Brezillon 	req->src_w >>= 16;
4401a396789SBoris Brezillon 	req->src_h >>= 16;
4411a396789SBoris Brezillon 
4421a396789SBoris Brezillon 	req->nplanes = drm_format_num_planes(req->fb->pixel_format);
4431a396789SBoris Brezillon 	if (req->nplanes > ATMEL_HLCDC_MAX_PLANES)
4441a396789SBoris Brezillon 		return -EINVAL;
4451a396789SBoris Brezillon 
4461a396789SBoris Brezillon 	/*
4471a396789SBoris Brezillon 	 * Swap width and size in case of 90 or 270 degrees rotation
4481a396789SBoris Brezillon 	 */
4491a396789SBoris Brezillon 	if (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
4501a396789SBoris Brezillon 		tmp = req->crtc_w;
4511a396789SBoris Brezillon 		req->crtc_w = req->crtc_h;
4521a396789SBoris Brezillon 		req->crtc_h = tmp;
4531a396789SBoris Brezillon 		tmp = req->src_w;
4541a396789SBoris Brezillon 		req->src_w = req->src_h;
4551a396789SBoris Brezillon 		req->src_h = tmp;
4561a396789SBoris Brezillon 	}
4571a396789SBoris Brezillon 
4581a396789SBoris Brezillon 	if (req->crtc_x + req->crtc_w > mode->hdisplay)
4591a396789SBoris Brezillon 		patched_crtc_w = mode->hdisplay - req->crtc_x;
4601a396789SBoris Brezillon 	else
4611a396789SBoris Brezillon 		patched_crtc_w = req->crtc_w;
4621a396789SBoris Brezillon 
4631a396789SBoris Brezillon 	if (req->crtc_x < 0) {
4641a396789SBoris Brezillon 		patched_crtc_w += req->crtc_x;
4651a396789SBoris Brezillon 		x_offset = -req->crtc_x;
4661a396789SBoris Brezillon 		req->crtc_x = 0;
4671a396789SBoris Brezillon 	}
4681a396789SBoris Brezillon 
4691a396789SBoris Brezillon 	if (req->crtc_y + req->crtc_h > mode->vdisplay)
4701a396789SBoris Brezillon 		patched_crtc_h = mode->vdisplay - req->crtc_y;
4711a396789SBoris Brezillon 	else
4721a396789SBoris Brezillon 		patched_crtc_h = req->crtc_h;
4731a396789SBoris Brezillon 
4741a396789SBoris Brezillon 	if (req->crtc_y < 0) {
4751a396789SBoris Brezillon 		patched_crtc_h += req->crtc_y;
4761a396789SBoris Brezillon 		y_offset = -req->crtc_y;
4771a396789SBoris Brezillon 		req->crtc_y = 0;
4781a396789SBoris Brezillon 	}
4791a396789SBoris Brezillon 
4801a396789SBoris Brezillon 	patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * req->src_w,
4811a396789SBoris Brezillon 					  req->crtc_w);
4821a396789SBoris Brezillon 	patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * req->src_h,
4831a396789SBoris Brezillon 					  req->crtc_h);
4841a396789SBoris Brezillon 
4851a396789SBoris Brezillon 	hsub = drm_format_horz_chroma_subsampling(req->fb->pixel_format);
4861a396789SBoris Brezillon 	vsub = drm_format_vert_chroma_subsampling(req->fb->pixel_format);
4871a396789SBoris Brezillon 
4881a396789SBoris Brezillon 	for (i = 0; i < req->nplanes; i++) {
4891a396789SBoris Brezillon 		unsigned int offset = 0;
4901a396789SBoris Brezillon 		int xdiv = i ? hsub : 1;
4911a396789SBoris Brezillon 		int ydiv = i ? vsub : 1;
4921a396789SBoris Brezillon 
4931a396789SBoris Brezillon 		req->bpp[i] = drm_format_plane_cpp(req->fb->pixel_format, i);
4941a396789SBoris Brezillon 		if (!req->bpp[i])
4951a396789SBoris Brezillon 			return -EINVAL;
4961a396789SBoris Brezillon 
4971a396789SBoris Brezillon 		switch (plane->rotation & 0xf) {
4981a396789SBoris Brezillon 		case BIT(DRM_ROTATE_90):
4991a396789SBoris Brezillon 			offset = ((y_offset + req->src_y + patched_src_w - 1) /
5001a396789SBoris Brezillon 				  ydiv) * req->fb->pitches[i];
5011a396789SBoris Brezillon 			offset += ((x_offset + req->src_x) / xdiv) *
5021a396789SBoris Brezillon 				  req->bpp[i];
5031a396789SBoris Brezillon 			req->xstride[i] = ((patched_src_w - 1) / ydiv) *
5041a396789SBoris Brezillon 					  req->fb->pitches[i];
5051a396789SBoris Brezillon 			req->pstride[i] = -req->fb->pitches[i] - req->bpp[i];
5061a396789SBoris Brezillon 			break;
5071a396789SBoris Brezillon 		case BIT(DRM_ROTATE_180):
5081a396789SBoris Brezillon 			offset = ((y_offset + req->src_y + patched_src_h - 1) /
5091a396789SBoris Brezillon 				  ydiv) * req->fb->pitches[i];
5101a396789SBoris Brezillon 			offset += ((x_offset + req->src_x + patched_src_w - 1) /
5111a396789SBoris Brezillon 				   xdiv) * req->bpp[i];
5121a396789SBoris Brezillon 			req->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
5131a396789SBoris Brezillon 					   req->bpp[i]) - req->fb->pitches[i];
5141a396789SBoris Brezillon 			req->pstride[i] = -2 * req->bpp[i];
5151a396789SBoris Brezillon 			break;
5161a396789SBoris Brezillon 		case BIT(DRM_ROTATE_270):
5171a396789SBoris Brezillon 			offset = ((y_offset + req->src_y) / ydiv) *
5181a396789SBoris Brezillon 				 req->fb->pitches[i];
5191a396789SBoris Brezillon 			offset += ((x_offset + req->src_x + patched_src_h - 1) /
5201a396789SBoris Brezillon 				   xdiv) * req->bpp[i];
5211a396789SBoris Brezillon 			req->xstride[i] = -(((patched_src_w - 1) / ydiv) *
5221a396789SBoris Brezillon 					    req->fb->pitches[i]) -
5231a396789SBoris Brezillon 					  (2 * req->bpp[i]);
5241a396789SBoris Brezillon 			req->pstride[i] = req->fb->pitches[i] - req->bpp[i];
5251a396789SBoris Brezillon 			break;
5261a396789SBoris Brezillon 		case BIT(DRM_ROTATE_0):
5271a396789SBoris Brezillon 		default:
5281a396789SBoris Brezillon 			offset = ((y_offset + req->src_y) / ydiv) *
5291a396789SBoris Brezillon 				 req->fb->pitches[i];
5301a396789SBoris Brezillon 			offset += ((x_offset + req->src_x) / xdiv) *
5311a396789SBoris Brezillon 				  req->bpp[i];
5321a396789SBoris Brezillon 			req->xstride[i] = req->fb->pitches[i] -
5331a396789SBoris Brezillon 					  ((patched_src_w / xdiv) *
5341a396789SBoris Brezillon 					   req->bpp[i]);
5351a396789SBoris Brezillon 			req->pstride[i] = 0;
5361a396789SBoris Brezillon 			break;
5371a396789SBoris Brezillon 		}
5381a396789SBoris Brezillon 
5391a396789SBoris Brezillon 		req->offsets[i] = offset + req->fb->offsets[i];
5401a396789SBoris Brezillon 	}
5411a396789SBoris Brezillon 
5421a396789SBoris Brezillon 	req->src_w = patched_src_w;
5431a396789SBoris Brezillon 	req->src_h = patched_src_h;
5441a396789SBoris Brezillon 	req->crtc_w = patched_crtc_w;
5451a396789SBoris Brezillon 	req->crtc_h = patched_crtc_h;
5461a396789SBoris Brezillon 
5471a396789SBoris Brezillon 	return atmel_hlcdc_plane_check_update_req(p, req, mode);
5481a396789SBoris Brezillon }
5491a396789SBoris Brezillon 
5501a396789SBoris Brezillon int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
5511a396789SBoris Brezillon 				struct atmel_hlcdc_plane_update_req *req)
5521a396789SBoris Brezillon {
5531a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
5541a396789SBoris Brezillon 	int ret;
5551a396789SBoris Brezillon 
5561a396789SBoris Brezillon 	ret = atmel_hlcdc_layer_update_start(&plane->layer);
5571a396789SBoris Brezillon 	if (ret)
5581a396789SBoris Brezillon 		return ret;
5591a396789SBoris Brezillon 
5601a396789SBoris Brezillon 	atmel_hlcdc_plane_update_pos_and_size(plane, req);
5611a396789SBoris Brezillon 	atmel_hlcdc_plane_update_general_settings(plane, req);
5621a396789SBoris Brezillon 	atmel_hlcdc_plane_update_format(plane, req);
5631a396789SBoris Brezillon 	atmel_hlcdc_plane_update_buffers(plane, req);
5641a396789SBoris Brezillon 
5651a396789SBoris Brezillon 	atmel_hlcdc_layer_update_commit(&plane->layer);
5661a396789SBoris Brezillon 
5671a396789SBoris Brezillon 	return 0;
5681a396789SBoris Brezillon }
5691a396789SBoris Brezillon 
5701a396789SBoris Brezillon int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p,
5711a396789SBoris Brezillon 				       struct drm_crtc *crtc,
5721a396789SBoris Brezillon 				       struct drm_framebuffer *fb,
5731a396789SBoris Brezillon 				       int crtc_x, int crtc_y,
5741a396789SBoris Brezillon 				       unsigned int crtc_w,
5751a396789SBoris Brezillon 				       unsigned int crtc_h,
5761a396789SBoris Brezillon 				       uint32_t src_x, uint32_t src_y,
5771a396789SBoris Brezillon 				       uint32_t src_w, uint32_t src_h,
5781a396789SBoris Brezillon 				       const struct drm_display_mode *mode)
5791a396789SBoris Brezillon {
5801a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
5811a396789SBoris Brezillon 	struct atmel_hlcdc_plane_update_req req;
5821a396789SBoris Brezillon 	int ret = 0;
5831a396789SBoris Brezillon 
5841a396789SBoris Brezillon 	memset(&req, 0, sizeof(req));
5851a396789SBoris Brezillon 	req.crtc_x = crtc_x;
5861a396789SBoris Brezillon 	req.crtc_y = crtc_y;
5871a396789SBoris Brezillon 	req.crtc_w = crtc_w;
5881a396789SBoris Brezillon 	req.crtc_h = crtc_h;
5891a396789SBoris Brezillon 	req.src_x = src_x;
5901a396789SBoris Brezillon 	req.src_y = src_y;
5911a396789SBoris Brezillon 	req.src_w = src_w;
5921a396789SBoris Brezillon 	req.src_h = src_h;
5931a396789SBoris Brezillon 	req.fb = fb;
5941a396789SBoris Brezillon 
5951a396789SBoris Brezillon 	ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req, mode);
5961a396789SBoris Brezillon 	if (ret)
5971a396789SBoris Brezillon 		return ret;
5981a396789SBoris Brezillon 
5991a396789SBoris Brezillon 	if (!req.crtc_h || !req.crtc_w)
6001a396789SBoris Brezillon 		return atmel_hlcdc_layer_disable(&plane->layer);
6011a396789SBoris Brezillon 
6021a396789SBoris Brezillon 	return atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
6031a396789SBoris Brezillon }
6041a396789SBoris Brezillon 
6051a396789SBoris Brezillon static int atmel_hlcdc_plane_update(struct drm_plane *p,
6061a396789SBoris Brezillon 				    struct drm_crtc *crtc,
6071a396789SBoris Brezillon 				    struct drm_framebuffer *fb,
6081a396789SBoris Brezillon 				    int crtc_x, int crtc_y,
6091a396789SBoris Brezillon 				    unsigned int crtc_w, unsigned int crtc_h,
6101a396789SBoris Brezillon 				    uint32_t src_x, uint32_t src_y,
6111a396789SBoris Brezillon 				    uint32_t src_w, uint32_t src_h)
6121a396789SBoris Brezillon {
6131a396789SBoris Brezillon 	return atmel_hlcdc_plane_update_with_mode(p, crtc, fb, crtc_x, crtc_y,
6141a396789SBoris Brezillon 						  crtc_w, crtc_h, src_x, src_y,
6151a396789SBoris Brezillon 						  src_w, src_h, &crtc->hwmode);
6161a396789SBoris Brezillon }
6171a396789SBoris Brezillon 
6181a396789SBoris Brezillon static int atmel_hlcdc_plane_disable(struct drm_plane *p)
6191a396789SBoris Brezillon {
6201a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
6211a396789SBoris Brezillon 
6221a396789SBoris Brezillon 	return atmel_hlcdc_layer_disable(&plane->layer);
6231a396789SBoris Brezillon }
6241a396789SBoris Brezillon 
6251a396789SBoris Brezillon static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
6261a396789SBoris Brezillon {
6271a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
6281a396789SBoris Brezillon 
6291a396789SBoris Brezillon 	if (plane->base.fb)
6301a396789SBoris Brezillon 		drm_framebuffer_unreference(plane->base.fb);
6311a396789SBoris Brezillon 
6321a396789SBoris Brezillon 	atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
6331a396789SBoris Brezillon 
6341a396789SBoris Brezillon 	drm_plane_cleanup(p);
6351a396789SBoris Brezillon 	devm_kfree(p->dev->dev, plane);
6361a396789SBoris Brezillon }
6371a396789SBoris Brezillon 
6381a396789SBoris Brezillon static int atmel_hlcdc_plane_set_alpha(struct atmel_hlcdc_plane *plane,
6391a396789SBoris Brezillon 				       u8 alpha)
6401a396789SBoris Brezillon {
6411a396789SBoris Brezillon 	atmel_hlcdc_layer_update_start(&plane->layer);
6421a396789SBoris Brezillon 	atmel_hlcdc_layer_update_cfg(&plane->layer,
6431a396789SBoris Brezillon 				     plane->layer.desc->layout.general_config,
6441a396789SBoris Brezillon 				     ATMEL_HLCDC_LAYER_GA_MASK,
6451a396789SBoris Brezillon 				     alpha << ATMEL_HLCDC_LAYER_GA_SHIFT);
6461a396789SBoris Brezillon 	atmel_hlcdc_layer_update_commit(&plane->layer);
6471a396789SBoris Brezillon 
6481a396789SBoris Brezillon 	return 0;
6491a396789SBoris Brezillon }
6501a396789SBoris Brezillon 
6511a396789SBoris Brezillon static int atmel_hlcdc_plane_set_rotation(struct atmel_hlcdc_plane *plane,
6521a396789SBoris Brezillon 					  unsigned int rotation)
6531a396789SBoris Brezillon {
6541a396789SBoris Brezillon 	plane->rotation = rotation;
6551a396789SBoris Brezillon 
6561a396789SBoris Brezillon 	return 0;
6571a396789SBoris Brezillon }
6581a396789SBoris Brezillon 
6591a396789SBoris Brezillon static int atmel_hlcdc_plane_set_property(struct drm_plane *p,
6601a396789SBoris Brezillon 					  struct drm_property *property,
6611a396789SBoris Brezillon 					  uint64_t value)
6621a396789SBoris Brezillon {
6631a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
6641a396789SBoris Brezillon 	struct atmel_hlcdc_plane_properties *props = plane->properties;
6651a396789SBoris Brezillon 
6661a396789SBoris Brezillon 	if (property == props->alpha)
6671a396789SBoris Brezillon 		atmel_hlcdc_plane_set_alpha(plane, value);
6681a396789SBoris Brezillon 	else if (property == props->rotation)
6691a396789SBoris Brezillon 		atmel_hlcdc_plane_set_rotation(plane, value);
6701a396789SBoris Brezillon 	else
6711a396789SBoris Brezillon 		return -EINVAL;
6721a396789SBoris Brezillon 
6731a396789SBoris Brezillon 	return 0;
6741a396789SBoris Brezillon }
6751a396789SBoris Brezillon 
6761a396789SBoris Brezillon static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
6771a396789SBoris Brezillon 				const struct atmel_hlcdc_layer_desc *desc,
6781a396789SBoris Brezillon 				struct atmel_hlcdc_plane_properties *props)
6791a396789SBoris Brezillon {
6801a396789SBoris Brezillon 	struct regmap *regmap = plane->layer.hlcdc->regmap;
6811a396789SBoris Brezillon 
6821a396789SBoris Brezillon 	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
6831a396789SBoris Brezillon 	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
6841a396789SBoris Brezillon 		drm_object_attach_property(&plane->base.base,
6851a396789SBoris Brezillon 					   props->alpha, 255);
6861a396789SBoris Brezillon 
6871a396789SBoris Brezillon 		/* Set default alpha value */
6881a396789SBoris Brezillon 		regmap_update_bits(regmap,
6891a396789SBoris Brezillon 				desc->regs_offset +
6901a396789SBoris Brezillon 				ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
6911a396789SBoris Brezillon 				ATMEL_HLCDC_LAYER_GA_MASK,
6921a396789SBoris Brezillon 				ATMEL_HLCDC_LAYER_GA_MASK);
6931a396789SBoris Brezillon 	}
6941a396789SBoris Brezillon 
6951a396789SBoris Brezillon 	if (desc->layout.xstride && desc->layout.pstride)
6961a396789SBoris Brezillon 		drm_object_attach_property(&plane->base.base,
6971a396789SBoris Brezillon 					   props->rotation,
6981a396789SBoris Brezillon 					   BIT(DRM_ROTATE_0));
6991a396789SBoris Brezillon 
7001a396789SBoris Brezillon 	if (desc->layout.csc) {
7011a396789SBoris Brezillon 		/*
7021a396789SBoris Brezillon 		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
7031a396789SBoris Brezillon 		 * userspace modify these factors (using a BLOB property ?).
7041a396789SBoris Brezillon 		 */
7051a396789SBoris Brezillon 		regmap_write(regmap,
7061a396789SBoris Brezillon 			     desc->regs_offset +
7071a396789SBoris Brezillon 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
7081a396789SBoris Brezillon 			     0x4c900091);
7091a396789SBoris Brezillon 		regmap_write(regmap,
7101a396789SBoris Brezillon 			     desc->regs_offset +
7111a396789SBoris Brezillon 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
7121a396789SBoris Brezillon 			     0x7a5f5090);
7131a396789SBoris Brezillon 		regmap_write(regmap,
7141a396789SBoris Brezillon 			     desc->regs_offset +
7151a396789SBoris Brezillon 			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
7161a396789SBoris Brezillon 			     0x40040890);
7171a396789SBoris Brezillon 	}
7181a396789SBoris Brezillon }
7191a396789SBoris Brezillon 
7201a396789SBoris Brezillon static struct drm_plane_funcs layer_plane_funcs = {
7211a396789SBoris Brezillon 	.update_plane = atmel_hlcdc_plane_update,
7221a396789SBoris Brezillon 	.disable_plane = atmel_hlcdc_plane_disable,
7231a396789SBoris Brezillon 	.set_property = atmel_hlcdc_plane_set_property,
7241a396789SBoris Brezillon 	.destroy = atmel_hlcdc_plane_destroy,
7251a396789SBoris Brezillon };
7261a396789SBoris Brezillon 
7271a396789SBoris Brezillon static struct atmel_hlcdc_plane *
7281a396789SBoris Brezillon atmel_hlcdc_plane_create(struct drm_device *dev,
7291a396789SBoris Brezillon 			 const struct atmel_hlcdc_layer_desc *desc,
7301a396789SBoris Brezillon 			 struct atmel_hlcdc_plane_properties *props)
7311a396789SBoris Brezillon {
7321a396789SBoris Brezillon 	struct atmel_hlcdc_plane *plane;
7331a396789SBoris Brezillon 	enum drm_plane_type type;
7341a396789SBoris Brezillon 	int ret;
7351a396789SBoris Brezillon 
7361a396789SBoris Brezillon 	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
7371a396789SBoris Brezillon 	if (!plane)
7381a396789SBoris Brezillon 		return ERR_PTR(-ENOMEM);
7391a396789SBoris Brezillon 
7401a396789SBoris Brezillon 	ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
7411a396789SBoris Brezillon 	if (ret)
7421a396789SBoris Brezillon 		return ERR_PTR(ret);
7431a396789SBoris Brezillon 
7441a396789SBoris Brezillon 	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
7451a396789SBoris Brezillon 		type = DRM_PLANE_TYPE_PRIMARY;
7461a396789SBoris Brezillon 	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
7471a396789SBoris Brezillon 		type = DRM_PLANE_TYPE_CURSOR;
7481a396789SBoris Brezillon 	else
7491a396789SBoris Brezillon 		type = DRM_PLANE_TYPE_OVERLAY;
7501a396789SBoris Brezillon 
7511a396789SBoris Brezillon 	ret = drm_universal_plane_init(dev, &plane->base, 0,
7521a396789SBoris Brezillon 				       &layer_plane_funcs,
7531a396789SBoris Brezillon 				       desc->formats->formats,
7541a396789SBoris Brezillon 				       desc->formats->nformats, type);
7551a396789SBoris Brezillon 	if (ret)
7561a396789SBoris Brezillon 		return ERR_PTR(ret);
7571a396789SBoris Brezillon 
7581a396789SBoris Brezillon 	/* Set default property values*/
7591a396789SBoris Brezillon 	atmel_hlcdc_plane_init_properties(plane, desc, props);
7601a396789SBoris Brezillon 
7611a396789SBoris Brezillon 	return plane;
7621a396789SBoris Brezillon }
7631a396789SBoris Brezillon 
7641a396789SBoris Brezillon static struct atmel_hlcdc_plane_properties *
7651a396789SBoris Brezillon atmel_hlcdc_plane_create_properties(struct drm_device *dev)
7661a396789SBoris Brezillon {
7671a396789SBoris Brezillon 	struct atmel_hlcdc_plane_properties *props;
7681a396789SBoris Brezillon 
7691a396789SBoris Brezillon 	props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
7701a396789SBoris Brezillon 	if (!props)
7711a396789SBoris Brezillon 		return ERR_PTR(-ENOMEM);
7721a396789SBoris Brezillon 
7731a396789SBoris Brezillon 	props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
7741a396789SBoris Brezillon 	if (!props->alpha)
7751a396789SBoris Brezillon 		return ERR_PTR(-ENOMEM);
7761a396789SBoris Brezillon 
7771a396789SBoris Brezillon 	props->rotation = drm_mode_create_rotation_property(dev,
7781a396789SBoris Brezillon 						BIT(DRM_ROTATE_0) |
7791a396789SBoris Brezillon 						BIT(DRM_ROTATE_90) |
7801a396789SBoris Brezillon 						BIT(DRM_ROTATE_180) |
7811a396789SBoris Brezillon 						BIT(DRM_ROTATE_270));
7821a396789SBoris Brezillon 	if (!props->rotation)
7831a396789SBoris Brezillon 		return ERR_PTR(-ENOMEM);
7841a396789SBoris Brezillon 
7851a396789SBoris Brezillon 	return props;
7861a396789SBoris Brezillon }
7871a396789SBoris Brezillon 
7881a396789SBoris Brezillon struct atmel_hlcdc_planes *
7891a396789SBoris Brezillon atmel_hlcdc_create_planes(struct drm_device *dev)
7901a396789SBoris Brezillon {
7911a396789SBoris Brezillon 	struct atmel_hlcdc_dc *dc = dev->dev_private;
7921a396789SBoris Brezillon 	struct atmel_hlcdc_plane_properties *props;
7931a396789SBoris Brezillon 	struct atmel_hlcdc_planes *planes;
7941a396789SBoris Brezillon 	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
7951a396789SBoris Brezillon 	int nlayers = dc->desc->nlayers;
7961a396789SBoris Brezillon 	int i;
7971a396789SBoris Brezillon 
7981a396789SBoris Brezillon 	planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
7991a396789SBoris Brezillon 	if (!planes)
8001a396789SBoris Brezillon 		return ERR_PTR(-ENOMEM);
8011a396789SBoris Brezillon 
8021a396789SBoris Brezillon 	for (i = 0; i < nlayers; i++) {
8031a396789SBoris Brezillon 		if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
8041a396789SBoris Brezillon 			planes->noverlays++;
8051a396789SBoris Brezillon 	}
8061a396789SBoris Brezillon 
8071a396789SBoris Brezillon 	if (planes->noverlays) {
8081a396789SBoris Brezillon 		planes->overlays = devm_kzalloc(dev->dev,
8091a396789SBoris Brezillon 						planes->noverlays *
8101a396789SBoris Brezillon 						sizeof(*planes->overlays),
8111a396789SBoris Brezillon 						GFP_KERNEL);
8121a396789SBoris Brezillon 		if (!planes->overlays)
8131a396789SBoris Brezillon 			return ERR_PTR(-ENOMEM);
8141a396789SBoris Brezillon 	}
8151a396789SBoris Brezillon 
8161a396789SBoris Brezillon 	props = atmel_hlcdc_plane_create_properties(dev);
8171a396789SBoris Brezillon 	if (IS_ERR(props))
8181a396789SBoris Brezillon 		return ERR_CAST(props);
8191a396789SBoris Brezillon 
8201a396789SBoris Brezillon 	planes->noverlays = 0;
8211a396789SBoris Brezillon 	for (i = 0; i < nlayers; i++) {
8221a396789SBoris Brezillon 		struct atmel_hlcdc_plane *plane;
8231a396789SBoris Brezillon 
8241a396789SBoris Brezillon 		if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
8251a396789SBoris Brezillon 			continue;
8261a396789SBoris Brezillon 
8271a396789SBoris Brezillon 		plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
8281a396789SBoris Brezillon 		if (IS_ERR(plane))
8291a396789SBoris Brezillon 			return ERR_CAST(plane);
8301a396789SBoris Brezillon 
8311a396789SBoris Brezillon 		plane->properties = props;
8321a396789SBoris Brezillon 
8331a396789SBoris Brezillon 		switch (descs[i].type) {
8341a396789SBoris Brezillon 		case ATMEL_HLCDC_BASE_LAYER:
8351a396789SBoris Brezillon 			if (planes->primary)
8361a396789SBoris Brezillon 				return ERR_PTR(-EINVAL);
8371a396789SBoris Brezillon 			planes->primary = plane;
8381a396789SBoris Brezillon 			break;
8391a396789SBoris Brezillon 
8401a396789SBoris Brezillon 		case ATMEL_HLCDC_OVERLAY_LAYER:
8411a396789SBoris Brezillon 			planes->overlays[planes->noverlays++] = plane;
8421a396789SBoris Brezillon 			break;
8431a396789SBoris Brezillon 
8441a396789SBoris Brezillon 		case ATMEL_HLCDC_CURSOR_LAYER:
8451a396789SBoris Brezillon 			if (planes->cursor)
8461a396789SBoris Brezillon 				return ERR_PTR(-EINVAL);
8471a396789SBoris Brezillon 			planes->cursor = plane;
8481a396789SBoris Brezillon 			break;
8491a396789SBoris Brezillon 
8501a396789SBoris Brezillon 		default:
8511a396789SBoris Brezillon 			break;
8521a396789SBoris Brezillon 		}
8531a396789SBoris Brezillon 	}
8541a396789SBoris Brezillon 
8551a396789SBoris Brezillon 	return planes;
8561a396789SBoris Brezillon }
857