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