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