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 349a45d33cSBoris Brezillon * @disc_x: x discard position 359a45d33cSBoris Brezillon * @disc_y: y discard position 369a45d33cSBoris Brezillon * @disc_w: discard width 379a45d33cSBoris Brezillon * @disc_h: discard height 382389fc13SBoris Brezillon * @bpp: bytes per pixel deduced from pixel_format 392389fc13SBoris Brezillon * @offsets: offsets to apply to the GEM buffers 402389fc13SBoris Brezillon * @xstride: value to add to the pixel pointer between each line 412389fc13SBoris Brezillon * @pstride: value to add to the pixel pointer between each pixel 422389fc13SBoris Brezillon * @nplanes: number of planes (deduced from pixel_format) 439a45d33cSBoris Brezillon * @dscrs: DMA descriptors 442389fc13SBoris Brezillon */ 452389fc13SBoris Brezillon struct atmel_hlcdc_plane_state { 462389fc13SBoris Brezillon struct drm_plane_state base; 472389fc13SBoris Brezillon int crtc_x; 482389fc13SBoris Brezillon int crtc_y; 492389fc13SBoris Brezillon unsigned int crtc_w; 502389fc13SBoris Brezillon unsigned int crtc_h; 512389fc13SBoris Brezillon uint32_t src_x; 522389fc13SBoris Brezillon uint32_t src_y; 532389fc13SBoris Brezillon uint32_t src_w; 542389fc13SBoris Brezillon uint32_t src_h; 552389fc13SBoris Brezillon 565957017dSBoris Brezillon int disc_x; 575957017dSBoris Brezillon int disc_y; 585957017dSBoris Brezillon int disc_w; 595957017dSBoris Brezillon int disc_h; 605957017dSBoris Brezillon 61ebab87abSBoris Brezillon int ahb_id; 62ebab87abSBoris Brezillon 632389fc13SBoris Brezillon /* These fields are private and should not be touched */ 649a45d33cSBoris Brezillon int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES]; 659a45d33cSBoris Brezillon unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES]; 669a45d33cSBoris Brezillon int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES]; 679a45d33cSBoris Brezillon int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES]; 682389fc13SBoris Brezillon int nplanes; 699a45d33cSBoris Brezillon 709a45d33cSBoris Brezillon /* DMA descriptors. */ 719a45d33cSBoris Brezillon struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES]; 722389fc13SBoris Brezillon }; 732389fc13SBoris Brezillon 742389fc13SBoris Brezillon static inline struct atmel_hlcdc_plane_state * 752389fc13SBoris Brezillon drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s) 762389fc13SBoris Brezillon { 772389fc13SBoris Brezillon return container_of(s, struct atmel_hlcdc_plane_state, base); 782389fc13SBoris Brezillon } 792389fc13SBoris Brezillon 801a396789SBoris Brezillon #define SUBPIXEL_MASK 0xffff 811a396789SBoris Brezillon 821a396789SBoris Brezillon static uint32_t rgb_formats[] = { 83364a7bf5SPeter Rosin DRM_FORMAT_C8, 841a396789SBoris Brezillon DRM_FORMAT_XRGB4444, 851a396789SBoris Brezillon DRM_FORMAT_ARGB4444, 861a396789SBoris Brezillon DRM_FORMAT_RGBA4444, 871a396789SBoris Brezillon DRM_FORMAT_ARGB1555, 881a396789SBoris Brezillon DRM_FORMAT_RGB565, 891a396789SBoris Brezillon DRM_FORMAT_RGB888, 901a396789SBoris Brezillon DRM_FORMAT_XRGB8888, 911a396789SBoris Brezillon DRM_FORMAT_ARGB8888, 921a396789SBoris Brezillon DRM_FORMAT_RGBA8888, 931a396789SBoris Brezillon }; 941a396789SBoris Brezillon 951a396789SBoris Brezillon struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = { 961a396789SBoris Brezillon .formats = rgb_formats, 971a396789SBoris Brezillon .nformats = ARRAY_SIZE(rgb_formats), 981a396789SBoris Brezillon }; 991a396789SBoris Brezillon 1001a396789SBoris Brezillon static uint32_t rgb_and_yuv_formats[] = { 101364a7bf5SPeter Rosin DRM_FORMAT_C8, 1021a396789SBoris Brezillon DRM_FORMAT_XRGB4444, 1031a396789SBoris Brezillon DRM_FORMAT_ARGB4444, 1041a396789SBoris Brezillon DRM_FORMAT_RGBA4444, 1051a396789SBoris Brezillon DRM_FORMAT_ARGB1555, 1061a396789SBoris Brezillon DRM_FORMAT_RGB565, 1071a396789SBoris Brezillon DRM_FORMAT_RGB888, 1081a396789SBoris Brezillon DRM_FORMAT_XRGB8888, 1091a396789SBoris Brezillon DRM_FORMAT_ARGB8888, 1101a396789SBoris Brezillon DRM_FORMAT_RGBA8888, 1111a396789SBoris Brezillon DRM_FORMAT_AYUV, 1121a396789SBoris Brezillon DRM_FORMAT_YUYV, 1131a396789SBoris Brezillon DRM_FORMAT_UYVY, 1141a396789SBoris Brezillon DRM_FORMAT_YVYU, 1151a396789SBoris Brezillon DRM_FORMAT_VYUY, 1161a396789SBoris Brezillon DRM_FORMAT_NV21, 1171a396789SBoris Brezillon DRM_FORMAT_NV61, 1181a396789SBoris Brezillon DRM_FORMAT_YUV422, 1191a396789SBoris Brezillon DRM_FORMAT_YUV420, 1201a396789SBoris Brezillon }; 1211a396789SBoris Brezillon 1221a396789SBoris Brezillon struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = { 1231a396789SBoris Brezillon .formats = rgb_and_yuv_formats, 1241a396789SBoris Brezillon .nformats = ARRAY_SIZE(rgb_and_yuv_formats), 1251a396789SBoris Brezillon }; 1261a396789SBoris Brezillon 1271a396789SBoris Brezillon static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode) 1281a396789SBoris Brezillon { 1291a396789SBoris Brezillon switch (format) { 130364a7bf5SPeter Rosin case DRM_FORMAT_C8: 131364a7bf5SPeter Rosin *mode = ATMEL_HLCDC_C8_MODE; 132364a7bf5SPeter Rosin break; 1331a396789SBoris Brezillon case DRM_FORMAT_XRGB4444: 1341a396789SBoris Brezillon *mode = ATMEL_HLCDC_XRGB4444_MODE; 1351a396789SBoris Brezillon break; 1361a396789SBoris Brezillon case DRM_FORMAT_ARGB4444: 1371a396789SBoris Brezillon *mode = ATMEL_HLCDC_ARGB4444_MODE; 1381a396789SBoris Brezillon break; 1391a396789SBoris Brezillon case DRM_FORMAT_RGBA4444: 1401a396789SBoris Brezillon *mode = ATMEL_HLCDC_RGBA4444_MODE; 1411a396789SBoris Brezillon break; 1421a396789SBoris Brezillon case DRM_FORMAT_RGB565: 1431a396789SBoris Brezillon *mode = ATMEL_HLCDC_RGB565_MODE; 1441a396789SBoris Brezillon break; 1451a396789SBoris Brezillon case DRM_FORMAT_RGB888: 1461a396789SBoris Brezillon *mode = ATMEL_HLCDC_RGB888_MODE; 1471a396789SBoris Brezillon break; 1481a396789SBoris Brezillon case DRM_FORMAT_ARGB1555: 1491a396789SBoris Brezillon *mode = ATMEL_HLCDC_ARGB1555_MODE; 1501a396789SBoris Brezillon break; 1511a396789SBoris Brezillon case DRM_FORMAT_XRGB8888: 1521a396789SBoris Brezillon *mode = ATMEL_HLCDC_XRGB8888_MODE; 1531a396789SBoris Brezillon break; 1541a396789SBoris Brezillon case DRM_FORMAT_ARGB8888: 1551a396789SBoris Brezillon *mode = ATMEL_HLCDC_ARGB8888_MODE; 1561a396789SBoris Brezillon break; 1571a396789SBoris Brezillon case DRM_FORMAT_RGBA8888: 1581a396789SBoris Brezillon *mode = ATMEL_HLCDC_RGBA8888_MODE; 1591a396789SBoris Brezillon break; 1601a396789SBoris Brezillon case DRM_FORMAT_AYUV: 1611a396789SBoris Brezillon *mode = ATMEL_HLCDC_AYUV_MODE; 1621a396789SBoris Brezillon break; 1631a396789SBoris Brezillon case DRM_FORMAT_YUYV: 1641a396789SBoris Brezillon *mode = ATMEL_HLCDC_YUYV_MODE; 1651a396789SBoris Brezillon break; 1661a396789SBoris Brezillon case DRM_FORMAT_UYVY: 1671a396789SBoris Brezillon *mode = ATMEL_HLCDC_UYVY_MODE; 1681a396789SBoris Brezillon break; 1691a396789SBoris Brezillon case DRM_FORMAT_YVYU: 1701a396789SBoris Brezillon *mode = ATMEL_HLCDC_YVYU_MODE; 1711a396789SBoris Brezillon break; 1721a396789SBoris Brezillon case DRM_FORMAT_VYUY: 1731a396789SBoris Brezillon *mode = ATMEL_HLCDC_VYUY_MODE; 1741a396789SBoris Brezillon break; 1751a396789SBoris Brezillon case DRM_FORMAT_NV21: 1761a396789SBoris Brezillon *mode = ATMEL_HLCDC_NV21_MODE; 1771a396789SBoris Brezillon break; 1781a396789SBoris Brezillon case DRM_FORMAT_NV61: 1791a396789SBoris Brezillon *mode = ATMEL_HLCDC_NV61_MODE; 1801a396789SBoris Brezillon break; 1811a396789SBoris Brezillon case DRM_FORMAT_YUV420: 1821a396789SBoris Brezillon *mode = ATMEL_HLCDC_YUV420_MODE; 1831a396789SBoris Brezillon break; 1841a396789SBoris Brezillon case DRM_FORMAT_YUV422: 1851a396789SBoris Brezillon *mode = ATMEL_HLCDC_YUV422_MODE; 1861a396789SBoris Brezillon break; 1871a396789SBoris Brezillon default: 1881a396789SBoris Brezillon return -ENOTSUPP; 1891a396789SBoris Brezillon } 1901a396789SBoris Brezillon 1911a396789SBoris Brezillon return 0; 1921a396789SBoris Brezillon } 1931a396789SBoris Brezillon 1941a396789SBoris Brezillon static u32 heo_downscaling_xcoef[] = { 1951a396789SBoris Brezillon 0x11343311, 1961a396789SBoris Brezillon 0x000000f7, 1971a396789SBoris Brezillon 0x1635300c, 1981a396789SBoris Brezillon 0x000000f9, 1991a396789SBoris Brezillon 0x1b362c08, 2001a396789SBoris Brezillon 0x000000fb, 2011a396789SBoris Brezillon 0x1f372804, 2021a396789SBoris Brezillon 0x000000fe, 2031a396789SBoris Brezillon 0x24382400, 2041a396789SBoris Brezillon 0x00000000, 2051a396789SBoris Brezillon 0x28371ffe, 2061a396789SBoris Brezillon 0x00000004, 2071a396789SBoris Brezillon 0x2c361bfb, 2081a396789SBoris Brezillon 0x00000008, 2091a396789SBoris Brezillon 0x303516f9, 2101a396789SBoris Brezillon 0x0000000c, 2111a396789SBoris Brezillon }; 2121a396789SBoris Brezillon 2131a396789SBoris Brezillon static u32 heo_downscaling_ycoef[] = { 2141a396789SBoris Brezillon 0x00123737, 2151a396789SBoris Brezillon 0x00173732, 2161a396789SBoris Brezillon 0x001b382d, 2171a396789SBoris Brezillon 0x001f3928, 2181a396789SBoris Brezillon 0x00243824, 2191a396789SBoris Brezillon 0x0028391f, 2201a396789SBoris Brezillon 0x002d381b, 2211a396789SBoris Brezillon 0x00323717, 2221a396789SBoris Brezillon }; 2231a396789SBoris Brezillon 2241a396789SBoris Brezillon static u32 heo_upscaling_xcoef[] = { 2251a396789SBoris Brezillon 0xf74949f7, 2261a396789SBoris Brezillon 0x00000000, 2271a396789SBoris Brezillon 0xf55f33fb, 2281a396789SBoris Brezillon 0x000000fe, 2291a396789SBoris Brezillon 0xf5701efe, 2301a396789SBoris Brezillon 0x000000ff, 2311a396789SBoris Brezillon 0xf87c0dff, 2321a396789SBoris Brezillon 0x00000000, 2331a396789SBoris Brezillon 0x00800000, 2341a396789SBoris Brezillon 0x00000000, 2351a396789SBoris Brezillon 0x0d7cf800, 2361a396789SBoris Brezillon 0x000000ff, 2371a396789SBoris Brezillon 0x1e70f5ff, 2381a396789SBoris Brezillon 0x000000fe, 2391a396789SBoris Brezillon 0x335ff5fe, 2401a396789SBoris Brezillon 0x000000fb, 2411a396789SBoris Brezillon }; 2421a396789SBoris Brezillon 2431a396789SBoris Brezillon static u32 heo_upscaling_ycoef[] = { 2441a396789SBoris Brezillon 0x00004040, 2451a396789SBoris Brezillon 0x00075920, 2461a396789SBoris Brezillon 0x00056f0c, 2471a396789SBoris Brezillon 0x00027b03, 2481a396789SBoris Brezillon 0x00008000, 2491a396789SBoris Brezillon 0x00037b02, 2501a396789SBoris Brezillon 0x000c6f05, 2511a396789SBoris Brezillon 0x00205907, 2521a396789SBoris Brezillon }; 2531a396789SBoris Brezillon 2549a45d33cSBoris Brezillon #define ATMEL_HLCDC_XPHIDEF 4 2559a45d33cSBoris Brezillon #define ATMEL_HLCDC_YPHIDEF 4 2569a45d33cSBoris Brezillon 2579a45d33cSBoris Brezillon static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize, 2589a45d33cSBoris Brezillon u32 dstsize, 2599a45d33cSBoris Brezillon u32 phidef) 2609a45d33cSBoris Brezillon { 2619a45d33cSBoris Brezillon u32 factor, max_memsize; 2629a45d33cSBoris Brezillon 2639a45d33cSBoris Brezillon factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1); 2649a45d33cSBoris Brezillon max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048; 2659a45d33cSBoris Brezillon 2669a45d33cSBoris Brezillon if (max_memsize > srcsize - 1) 2679a45d33cSBoris Brezillon factor--; 2689a45d33cSBoris Brezillon 2699a45d33cSBoris Brezillon return factor; 2709a45d33cSBoris Brezillon } 2719a45d33cSBoris Brezillon 2729a45d33cSBoris Brezillon static void 2739a45d33cSBoris Brezillon atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane, 2749a45d33cSBoris Brezillon const u32 *coeff_tab, int size, 2759a45d33cSBoris Brezillon unsigned int cfg_offs) 2769a45d33cSBoris Brezillon { 2779a45d33cSBoris Brezillon int i; 2789a45d33cSBoris Brezillon 2799a45d33cSBoris Brezillon for (i = 0; i < size; i++) 2809a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i, 2819a45d33cSBoris Brezillon coeff_tab[i]); 2829a45d33cSBoris Brezillon } 2839a45d33cSBoris Brezillon 2849a45d33cSBoris Brezillon void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane, 2859a45d33cSBoris Brezillon struct atmel_hlcdc_plane_state *state) 2869a45d33cSBoris Brezillon { 2879a45d33cSBoris Brezillon const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 2889a45d33cSBoris Brezillon u32 xfactor, yfactor; 2899a45d33cSBoris Brezillon 2909a45d33cSBoris Brezillon if (!desc->layout.scaler_config) 2919a45d33cSBoris Brezillon return; 2929a45d33cSBoris Brezillon 2939a45d33cSBoris Brezillon if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) { 2949a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, 2959a45d33cSBoris Brezillon desc->layout.scaler_config, 0); 2969a45d33cSBoris Brezillon return; 2979a45d33cSBoris Brezillon } 2989a45d33cSBoris Brezillon 2999a45d33cSBoris Brezillon if (desc->layout.phicoeffs.x) { 3009a45d33cSBoris Brezillon xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w, 3019a45d33cSBoris Brezillon state->crtc_w, 3029a45d33cSBoris Brezillon ATMEL_HLCDC_XPHIDEF); 3039a45d33cSBoris Brezillon 3049a45d33cSBoris Brezillon yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h, 3059a45d33cSBoris Brezillon state->crtc_h, 3069a45d33cSBoris Brezillon ATMEL_HLCDC_YPHIDEF); 3079a45d33cSBoris Brezillon 3089a45d33cSBoris Brezillon atmel_hlcdc_plane_scaler_set_phicoeff(plane, 3099a45d33cSBoris Brezillon state->crtc_w < state->src_w ? 3109a45d33cSBoris Brezillon heo_downscaling_xcoef : 3119a45d33cSBoris Brezillon heo_upscaling_xcoef, 3129a45d33cSBoris Brezillon ARRAY_SIZE(heo_upscaling_xcoef), 3139a45d33cSBoris Brezillon desc->layout.phicoeffs.x); 3149a45d33cSBoris Brezillon 3159a45d33cSBoris Brezillon atmel_hlcdc_plane_scaler_set_phicoeff(plane, 3169a45d33cSBoris Brezillon state->crtc_h < state->src_h ? 3179a45d33cSBoris Brezillon heo_downscaling_ycoef : 3189a45d33cSBoris Brezillon heo_upscaling_ycoef, 3199a45d33cSBoris Brezillon ARRAY_SIZE(heo_upscaling_ycoef), 3209a45d33cSBoris Brezillon desc->layout.phicoeffs.y); 3219a45d33cSBoris Brezillon } else { 3229a45d33cSBoris Brezillon xfactor = (1024 * state->src_w) / state->crtc_w; 3239a45d33cSBoris Brezillon yfactor = (1024 * state->src_h) / state->crtc_h; 3249a45d33cSBoris Brezillon } 3259a45d33cSBoris Brezillon 3269a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config, 3279a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_SCALER_ENABLE | 3289a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor, 3299a45d33cSBoris Brezillon yfactor)); 3309a45d33cSBoris Brezillon } 3319a45d33cSBoris Brezillon 3321a396789SBoris Brezillon static void 3331a396789SBoris Brezillon atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane, 3342389fc13SBoris Brezillon struct atmel_hlcdc_plane_state *state) 3351a396789SBoris Brezillon { 3369a45d33cSBoris Brezillon const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 3371a396789SBoris Brezillon 3389a45d33cSBoris Brezillon if (desc->layout.size) 3399a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size, 3409a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_SIZE(state->crtc_w, 3419a45d33cSBoris Brezillon state->crtc_h)); 3421a396789SBoris Brezillon 3439a45d33cSBoris Brezillon if (desc->layout.memsize) 3449a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, 3459a45d33cSBoris Brezillon desc->layout.memsize, 3469a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_SIZE(state->src_w, 3479a45d33cSBoris Brezillon state->src_h)); 3481a396789SBoris Brezillon 3499a45d33cSBoris Brezillon if (desc->layout.pos) 3509a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos, 3519a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_POS(state->crtc_x, 3529a45d33cSBoris Brezillon state->crtc_y)); 3531a396789SBoris Brezillon 3549a45d33cSBoris Brezillon atmel_hlcdc_plane_setup_scaler(plane, state); 3551a396789SBoris Brezillon } 3561a396789SBoris Brezillon 3571a396789SBoris Brezillon static void 3581a396789SBoris Brezillon atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane, 3592389fc13SBoris Brezillon struct atmel_hlcdc_plane_state *state) 3601a396789SBoris Brezillon { 3619a45d33cSBoris Brezillon unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id; 3629a45d33cSBoris Brezillon const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 363e2e287faSMaxime Ripard const struct drm_format_info *format = state->base.fb->format; 3649a45d33cSBoris Brezillon 3659a45d33cSBoris Brezillon /* 3669a45d33cSBoris Brezillon * Rotation optimization is not working on RGB888 (rotation is still 3679a45d33cSBoris Brezillon * working but without any optimization). 3689a45d33cSBoris Brezillon */ 369e2e287faSMaxime Ripard if (format->format == DRM_FORMAT_RGB888) 3709a45d33cSBoris Brezillon cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS; 3719a45d33cSBoris Brezillon 3729a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG, 3739a45d33cSBoris Brezillon cfg); 3749a45d33cSBoris Brezillon 3759a45d33cSBoris Brezillon cfg = ATMEL_HLCDC_LAYER_DMA; 3761a396789SBoris Brezillon 3771a396789SBoris Brezillon if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) { 3781a396789SBoris Brezillon cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL | 3791a396789SBoris Brezillon ATMEL_HLCDC_LAYER_ITER; 3801a396789SBoris Brezillon 381e2e287faSMaxime Ripard if (format->has_alpha) 3821a396789SBoris Brezillon cfg |= ATMEL_HLCDC_LAYER_LAEN; 3831a396789SBoris Brezillon else 3842389fc13SBoris Brezillon cfg |= ATMEL_HLCDC_LAYER_GAEN | 385cbb32079SClaudiu Beznea ATMEL_HLCDC_LAYER_GA(state->base.alpha); 3861a396789SBoris Brezillon } 3871a396789SBoris Brezillon 3889a45d33cSBoris Brezillon if (state->disc_h && state->disc_w) 3899a45d33cSBoris Brezillon cfg |= ATMEL_HLCDC_LAYER_DISCEN; 3901a396789SBoris Brezillon 3919a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config, 3929a45d33cSBoris Brezillon cfg); 3931a396789SBoris Brezillon } 3941a396789SBoris Brezillon 3951a396789SBoris Brezillon static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane, 3962389fc13SBoris Brezillon struct atmel_hlcdc_plane_state *state) 3971a396789SBoris Brezillon { 3981a396789SBoris Brezillon u32 cfg; 3991a396789SBoris Brezillon int ret; 4001a396789SBoris Brezillon 401438b74a5SVille Syrjälä ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format, 4022389fc13SBoris Brezillon &cfg); 4031a396789SBoris Brezillon if (ret) 4041a396789SBoris Brezillon return; 4051a396789SBoris Brezillon 406438b74a5SVille Syrjälä if ((state->base.fb->format->format == DRM_FORMAT_YUV422 || 407438b74a5SVille Syrjälä state->base.fb->format->format == DRM_FORMAT_NV61) && 408bd2ef25dSVille Syrjälä drm_rotation_90_or_270(state->base.rotation)) 4091a396789SBoris Brezillon cfg |= ATMEL_HLCDC_YUV422ROT; 4101a396789SBoris Brezillon 4119a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, 4129a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg); 4131a396789SBoris Brezillon } 4141a396789SBoris Brezillon 4150010ac3fSVille Syrjälä static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane, 4160010ac3fSVille Syrjälä struct atmel_hlcdc_plane_state *state) 417364a7bf5SPeter Rosin { 4180010ac3fSVille Syrjälä struct drm_crtc *crtc = state->base.crtc; 419364a7bf5SPeter Rosin struct drm_color_lut *lut; 420364a7bf5SPeter Rosin int idx; 421364a7bf5SPeter Rosin 422364a7bf5SPeter Rosin if (!crtc || !crtc->state) 423364a7bf5SPeter Rosin return; 424364a7bf5SPeter Rosin 425364a7bf5SPeter Rosin if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut) 426364a7bf5SPeter Rosin return; 427364a7bf5SPeter Rosin 428364a7bf5SPeter Rosin lut = (struct drm_color_lut *)crtc->state->gamma_lut->data; 429364a7bf5SPeter Rosin 430364a7bf5SPeter Rosin for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) { 431364a7bf5SPeter Rosin u32 val = ((lut->red << 8) & 0xff0000) | 432364a7bf5SPeter Rosin (lut->green & 0xff00) | 433364a7bf5SPeter Rosin (lut->blue >> 8); 434364a7bf5SPeter Rosin 435364a7bf5SPeter Rosin atmel_hlcdc_layer_write_clut(&plane->layer, idx, val); 436364a7bf5SPeter Rosin } 437364a7bf5SPeter Rosin } 438364a7bf5SPeter Rosin 4391a396789SBoris Brezillon static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane, 4402389fc13SBoris Brezillon struct atmel_hlcdc_plane_state *state) 4411a396789SBoris Brezillon { 4429a45d33cSBoris Brezillon const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 4439a45d33cSBoris Brezillon struct drm_framebuffer *fb = state->base.fb; 4449a45d33cSBoris Brezillon u32 sr; 4451a396789SBoris Brezillon int i; 4461a396789SBoris Brezillon 4479a45d33cSBoris Brezillon sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR); 4481a396789SBoris Brezillon 4492389fc13SBoris Brezillon for (i = 0; i < state->nplanes; i++) { 4509a45d33cSBoris Brezillon struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i); 4519a45d33cSBoris Brezillon 4529a45d33cSBoris Brezillon state->dscrs[i]->addr = gem->paddr + state->offsets[i]; 4539a45d33cSBoris Brezillon 4549a45d33cSBoris Brezillon atmel_hlcdc_layer_write_reg(&plane->layer, 4559a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_PLANE_HEAD(i), 4569a45d33cSBoris Brezillon state->dscrs[i]->self); 4579a45d33cSBoris Brezillon 4589a45d33cSBoris Brezillon if (!(sr & ATMEL_HLCDC_LAYER_EN)) { 4599a45d33cSBoris Brezillon atmel_hlcdc_layer_write_reg(&plane->layer, 4609a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_PLANE_ADDR(i), 4619a45d33cSBoris Brezillon state->dscrs[i]->addr); 4629a45d33cSBoris Brezillon atmel_hlcdc_layer_write_reg(&plane->layer, 4639a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_PLANE_CTRL(i), 4649a45d33cSBoris Brezillon state->dscrs[i]->ctrl); 4659a45d33cSBoris Brezillon atmel_hlcdc_layer_write_reg(&plane->layer, 4669a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_PLANE_NEXT(i), 4679a45d33cSBoris Brezillon state->dscrs[i]->self); 4681a396789SBoris Brezillon } 4691a396789SBoris Brezillon 4709a45d33cSBoris Brezillon if (desc->layout.xstride[i]) 4719a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, 4729a45d33cSBoris Brezillon desc->layout.xstride[i], 4739a45d33cSBoris Brezillon state->xstride[i]); 4749a45d33cSBoris Brezillon 4759a45d33cSBoris Brezillon if (desc->layout.pstride[i]) 4769a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, 4779a45d33cSBoris Brezillon desc->layout.pstride[i], 4782389fc13SBoris Brezillon state->pstride[i]); 4791a396789SBoris Brezillon } 4801a396789SBoris Brezillon } 4811a396789SBoris Brezillon 482ebab87abSBoris Brezillon int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state) 483ebab87abSBoris Brezillon { 484ebab87abSBoris Brezillon unsigned int ahb_load[2] = { }; 485ebab87abSBoris Brezillon struct drm_plane *plane; 486ebab87abSBoris Brezillon 487ebab87abSBoris Brezillon drm_atomic_crtc_state_for_each_plane(plane, c_state) { 488ebab87abSBoris Brezillon struct atmel_hlcdc_plane_state *plane_state; 489ebab87abSBoris Brezillon struct drm_plane_state *plane_s; 490ebab87abSBoris Brezillon unsigned int pixels, load = 0; 491ebab87abSBoris Brezillon int i; 492ebab87abSBoris Brezillon 493ebab87abSBoris Brezillon plane_s = drm_atomic_get_plane_state(c_state->state, plane); 494ebab87abSBoris Brezillon if (IS_ERR(plane_s)) 495ebab87abSBoris Brezillon return PTR_ERR(plane_s); 496ebab87abSBoris Brezillon 497ebab87abSBoris Brezillon plane_state = 498ebab87abSBoris Brezillon drm_plane_state_to_atmel_hlcdc_plane_state(plane_s); 499ebab87abSBoris Brezillon 500ebab87abSBoris Brezillon pixels = (plane_state->src_w * plane_state->src_h) - 501ebab87abSBoris Brezillon (plane_state->disc_w * plane_state->disc_h); 502ebab87abSBoris Brezillon 503ebab87abSBoris Brezillon for (i = 0; i < plane_state->nplanes; i++) 504ebab87abSBoris Brezillon load += pixels * plane_state->bpp[i]; 505ebab87abSBoris Brezillon 506ebab87abSBoris Brezillon if (ahb_load[0] <= ahb_load[1]) 507ebab87abSBoris Brezillon plane_state->ahb_id = 0; 508ebab87abSBoris Brezillon else 509ebab87abSBoris Brezillon plane_state->ahb_id = 1; 510ebab87abSBoris Brezillon 511ebab87abSBoris Brezillon ahb_load[plane_state->ahb_id] += load; 512ebab87abSBoris Brezillon } 513ebab87abSBoris Brezillon 514ebab87abSBoris Brezillon return 0; 515ebab87abSBoris Brezillon } 516ebab87abSBoris Brezillon 5175957017dSBoris Brezillon int 5185957017dSBoris Brezillon atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state) 5195957017dSBoris Brezillon { 5205957017dSBoris Brezillon int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0; 5215957017dSBoris Brezillon const struct atmel_hlcdc_layer_cfg_layout *layout; 5225957017dSBoris Brezillon struct atmel_hlcdc_plane_state *primary_state; 5235957017dSBoris Brezillon struct drm_plane_state *primary_s; 5245957017dSBoris Brezillon struct atmel_hlcdc_plane *primary; 5255957017dSBoris Brezillon struct drm_plane *ovl; 5265957017dSBoris Brezillon 5275957017dSBoris Brezillon primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary); 5285957017dSBoris Brezillon layout = &primary->layer.desc->layout; 5295957017dSBoris Brezillon if (!layout->disc_pos || !layout->disc_size) 5305957017dSBoris Brezillon return 0; 5315957017dSBoris Brezillon 5325957017dSBoris Brezillon primary_s = drm_atomic_get_plane_state(c_state->state, 5335957017dSBoris Brezillon &primary->base); 5345957017dSBoris Brezillon if (IS_ERR(primary_s)) 5355957017dSBoris Brezillon return PTR_ERR(primary_s); 5365957017dSBoris Brezillon 5375957017dSBoris Brezillon primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s); 5385957017dSBoris Brezillon 5395957017dSBoris Brezillon drm_atomic_crtc_state_for_each_plane(ovl, c_state) { 5405957017dSBoris Brezillon struct atmel_hlcdc_plane_state *ovl_state; 5415957017dSBoris Brezillon struct drm_plane_state *ovl_s; 5425957017dSBoris Brezillon 5435957017dSBoris Brezillon if (ovl == c_state->crtc->primary) 5445957017dSBoris Brezillon continue; 5455957017dSBoris Brezillon 5465957017dSBoris Brezillon ovl_s = drm_atomic_get_plane_state(c_state->state, ovl); 5475957017dSBoris Brezillon if (IS_ERR(ovl_s)) 5485957017dSBoris Brezillon return PTR_ERR(ovl_s); 5495957017dSBoris Brezillon 5505957017dSBoris Brezillon ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s); 5515957017dSBoris Brezillon 552ac109c82SPeter Rosin if (!ovl_s->visible || 553ac109c82SPeter Rosin !ovl_s->fb || 554e2e287faSMaxime Ripard ovl_s->fb->format->has_alpha || 5557f73c10bSMaxime Ripard ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE) 5565957017dSBoris Brezillon continue; 5575957017dSBoris Brezillon 5585957017dSBoris Brezillon /* TODO: implement a smarter hidden area detection */ 5595957017dSBoris Brezillon if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w) 5605957017dSBoris Brezillon continue; 5615957017dSBoris Brezillon 5625957017dSBoris Brezillon disc_x = ovl_state->crtc_x; 5635957017dSBoris Brezillon disc_y = ovl_state->crtc_y; 5645957017dSBoris Brezillon disc_h = ovl_state->crtc_h; 5655957017dSBoris Brezillon disc_w = ovl_state->crtc_w; 5665957017dSBoris Brezillon } 5675957017dSBoris Brezillon 5685957017dSBoris Brezillon primary_state->disc_x = disc_x; 5695957017dSBoris Brezillon primary_state->disc_y = disc_y; 5705957017dSBoris Brezillon primary_state->disc_w = disc_w; 5715957017dSBoris Brezillon primary_state->disc_h = disc_h; 5725957017dSBoris Brezillon 5735957017dSBoris Brezillon return 0; 5745957017dSBoris Brezillon } 5755957017dSBoris Brezillon 5765957017dSBoris Brezillon static void 5775957017dSBoris Brezillon atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane, 5785957017dSBoris Brezillon struct atmel_hlcdc_plane_state *state) 5795957017dSBoris Brezillon { 5809a45d33cSBoris Brezillon const struct atmel_hlcdc_layer_cfg_layout *layout; 5815957017dSBoris Brezillon 5829a45d33cSBoris Brezillon layout = &plane->layer.desc->layout; 5839a45d33cSBoris Brezillon if (!layout->disc_pos || !layout->disc_size) 5845957017dSBoris Brezillon return; 5855957017dSBoris Brezillon 5869a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos, 5879a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x, 5889a45d33cSBoris Brezillon state->disc_y)); 5895957017dSBoris Brezillon 5909a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size, 5919a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w, 5929a45d33cSBoris Brezillon state->disc_h)); 5935957017dSBoris Brezillon } 5945957017dSBoris Brezillon 5952389fc13SBoris Brezillon static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, 5962389fc13SBoris Brezillon struct drm_plane_state *s) 5971a396789SBoris Brezillon { 5981a396789SBoris Brezillon struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 5992389fc13SBoris Brezillon struct atmel_hlcdc_plane_state *state = 6002389fc13SBoris Brezillon drm_plane_state_to_atmel_hlcdc_plane_state(s); 6019a45d33cSBoris Brezillon const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 6022389fc13SBoris Brezillon struct drm_framebuffer *fb = state->base.fb; 6032389fc13SBoris Brezillon const struct drm_display_mode *mode; 6042389fc13SBoris Brezillon struct drm_crtc_state *crtc_state; 6051a396789SBoris Brezillon unsigned int tmp; 606ac109c82SPeter Rosin int ret; 6071a396789SBoris Brezillon int i; 6081a396789SBoris Brezillon 6092389fc13SBoris Brezillon if (!state->base.crtc || !fb) 6102389fc13SBoris Brezillon return 0; 6112389fc13SBoris Brezillon 612b47ff7e6SAndrzej Hajda crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc); 6132389fc13SBoris Brezillon mode = &crtc_state->adjusted_mode; 6142389fc13SBoris Brezillon 615ac109c82SPeter Rosin ret = drm_atomic_helper_check_plane_state(s, crtc_state, 616ac109c82SPeter Rosin (1 << 16) / 2048, 617ac109c82SPeter Rosin INT_MAX, true, true); 618ac109c82SPeter Rosin if (ret || !s->visible) 619ac109c82SPeter Rosin return ret; 620ac109c82SPeter Rosin 621ac109c82SPeter Rosin state->src_x = s->src.x1; 622ac109c82SPeter Rosin state->src_y = s->src.y1; 623ac109c82SPeter Rosin state->src_w = drm_rect_width(&s->src); 624ac109c82SPeter Rosin state->src_h = drm_rect_height(&s->src); 625ac109c82SPeter Rosin state->crtc_x = s->dst.x1; 626ac109c82SPeter Rosin state->crtc_y = s->dst.y1; 627ac109c82SPeter Rosin state->crtc_w = drm_rect_width(&s->dst); 628ac109c82SPeter Rosin state->crtc_h = drm_rect_height(&s->dst); 629ac109c82SPeter Rosin 6302389fc13SBoris Brezillon if ((state->src_x | state->src_y | state->src_w | state->src_h) & 6311a396789SBoris Brezillon SUBPIXEL_MASK) 6321a396789SBoris Brezillon return -EINVAL; 6331a396789SBoris Brezillon 6342389fc13SBoris Brezillon state->src_x >>= 16; 6352389fc13SBoris Brezillon state->src_y >>= 16; 6362389fc13SBoris Brezillon state->src_w >>= 16; 6372389fc13SBoris Brezillon state->src_h >>= 16; 6381a396789SBoris Brezillon 639bcb0b461SVille Syrjälä state->nplanes = fb->format->num_planes; 6409a45d33cSBoris Brezillon if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES) 6411a396789SBoris Brezillon return -EINVAL; 6421a396789SBoris Brezillon 6432389fc13SBoris Brezillon for (i = 0; i < state->nplanes; i++) { 6441a396789SBoris Brezillon unsigned int offset = 0; 645f3e9632cSMaxime Ripard int xdiv = i ? fb->format->hsub : 1; 646f3e9632cSMaxime Ripard int ydiv = i ? fb->format->vsub : 1; 6471a396789SBoris Brezillon 648353c8598SVille Syrjälä state->bpp[i] = fb->format->cpp[i]; 6492389fc13SBoris Brezillon if (!state->bpp[i]) 6501a396789SBoris Brezillon return -EINVAL; 6511a396789SBoris Brezillon 652c2c446adSRobert Foss switch (state->base.rotation & DRM_MODE_ROTATE_MASK) { 653c2c446adSRobert Foss case DRM_MODE_ROTATE_90: 654ac109c82SPeter Rosin offset = (state->src_y / ydiv) * 6552389fc13SBoris Brezillon fb->pitches[i]; 656ac109c82SPeter Rosin offset += ((state->src_x + state->src_w - 1) / 6578cdb00a5SPeter Rosin xdiv) * state->bpp[i]; 658ac109c82SPeter Rosin state->xstride[i] = -(((state->src_h - 1) / ydiv) * 6598cdb00a5SPeter Rosin fb->pitches[i]) - 6608cdb00a5SPeter Rosin (2 * state->bpp[i]); 6618cdb00a5SPeter Rosin state->pstride[i] = fb->pitches[i] - state->bpp[i]; 6621a396789SBoris Brezillon break; 663c2c446adSRobert Foss case DRM_MODE_ROTATE_180: 664ac109c82SPeter Rosin offset = ((state->src_y + state->src_h - 1) / 6652389fc13SBoris Brezillon ydiv) * fb->pitches[i]; 666ac109c82SPeter Rosin offset += ((state->src_x + state->src_w - 1) / 6672389fc13SBoris Brezillon xdiv) * state->bpp[i]; 668ac109c82SPeter Rosin state->xstride[i] = ((((state->src_w - 1) / xdiv) - 1) * 6692389fc13SBoris Brezillon state->bpp[i]) - fb->pitches[i]; 6702389fc13SBoris Brezillon state->pstride[i] = -2 * state->bpp[i]; 6711a396789SBoris Brezillon break; 672c2c446adSRobert Foss case DRM_MODE_ROTATE_270: 673ac109c82SPeter Rosin offset = ((state->src_y + state->src_h - 1) / 6748cdb00a5SPeter Rosin ydiv) * fb->pitches[i]; 675ac109c82SPeter Rosin offset += (state->src_x / xdiv) * state->bpp[i]; 676ac109c82SPeter Rosin state->xstride[i] = ((state->src_h - 1) / ydiv) * 6772389fc13SBoris Brezillon fb->pitches[i]; 6788cdb00a5SPeter Rosin state->pstride[i] = -fb->pitches[i] - state->bpp[i]; 6791a396789SBoris Brezillon break; 680c2c446adSRobert Foss case DRM_MODE_ROTATE_0: 6811a396789SBoris Brezillon default: 682ac109c82SPeter Rosin offset = (state->src_y / ydiv) * fb->pitches[i]; 683ac109c82SPeter Rosin offset += (state->src_x / xdiv) * state->bpp[i]; 6842389fc13SBoris Brezillon state->xstride[i] = fb->pitches[i] - 685ac109c82SPeter Rosin ((state->src_w / xdiv) * 6862389fc13SBoris Brezillon state->bpp[i]); 6872389fc13SBoris Brezillon state->pstride[i] = 0; 6881a396789SBoris Brezillon break; 6891a396789SBoris Brezillon } 6901a396789SBoris Brezillon 6912389fc13SBoris Brezillon state->offsets[i] = offset + fb->offsets[i]; 6921a396789SBoris Brezillon } 6931a396789SBoris Brezillon 694ac109c82SPeter Rosin /* 695ac109c82SPeter Rosin * Swap width and size in case of 90 or 270 degrees rotation 696ac109c82SPeter Rosin */ 697ac109c82SPeter Rosin if (drm_rotation_90_or_270(state->base.rotation)) { 698ac109c82SPeter Rosin tmp = state->src_w; 699ac109c82SPeter Rosin state->src_w = state->src_h; 700ac109c82SPeter Rosin state->src_h = tmp; 701ac109c82SPeter Rosin } 7021a396789SBoris Brezillon 7039a45d33cSBoris Brezillon if (!desc->layout.size && 7042389fc13SBoris Brezillon (mode->hdisplay != state->crtc_w || 7052389fc13SBoris Brezillon mode->vdisplay != state->crtc_h)) 7062389fc13SBoris Brezillon return -EINVAL; 7071a396789SBoris Brezillon 7082389fc13SBoris Brezillon if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) && 7099a45d33cSBoris Brezillon (!desc->layout.memsize || 710e2e287faSMaxime Ripard state->base.fb->format->has_alpha)) 7112389fc13SBoris Brezillon return -EINVAL; 7121a396789SBoris Brezillon 7131a396789SBoris Brezillon return 0; 7141a396789SBoris Brezillon } 7151a396789SBoris Brezillon 716ac109c82SPeter Rosin static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p, 717ac109c82SPeter Rosin struct drm_plane_state *old_state) 718ac109c82SPeter Rosin { 719ac109c82SPeter Rosin struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 720ac109c82SPeter Rosin 721ac109c82SPeter Rosin /* Disable interrupts */ 722ac109c82SPeter Rosin atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR, 723ac109c82SPeter Rosin 0xffffffff); 724ac109c82SPeter Rosin 725ac109c82SPeter Rosin /* Disable the layer */ 726ac109c82SPeter Rosin atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR, 727ac109c82SPeter Rosin ATMEL_HLCDC_LAYER_RST | 728ac109c82SPeter Rosin ATMEL_HLCDC_LAYER_A2Q | 729ac109c82SPeter Rosin ATMEL_HLCDC_LAYER_UPDATE); 730ac109c82SPeter Rosin 731ac109c82SPeter Rosin /* Clear all pending interrupts */ 732ac109c82SPeter Rosin atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR); 733ac109c82SPeter Rosin } 734ac109c82SPeter Rosin 7352389fc13SBoris Brezillon static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p, 7362389fc13SBoris Brezillon struct drm_plane_state *old_s) 7372389fc13SBoris Brezillon { 7382389fc13SBoris Brezillon struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 7392389fc13SBoris Brezillon struct atmel_hlcdc_plane_state *state = 7402389fc13SBoris Brezillon drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 7419a45d33cSBoris Brezillon u32 sr; 7422389fc13SBoris Brezillon 7432389fc13SBoris Brezillon if (!p->state->crtc || !p->state->fb) 7442389fc13SBoris Brezillon return; 7452389fc13SBoris Brezillon 746ac109c82SPeter Rosin if (!state->base.visible) { 747ac109c82SPeter Rosin atmel_hlcdc_plane_atomic_disable(p, old_s); 748ac109c82SPeter Rosin return; 749ac109c82SPeter Rosin } 750ac109c82SPeter Rosin 7512389fc13SBoris Brezillon atmel_hlcdc_plane_update_pos_and_size(plane, state); 7522389fc13SBoris Brezillon atmel_hlcdc_plane_update_general_settings(plane, state); 7532389fc13SBoris Brezillon atmel_hlcdc_plane_update_format(plane, state); 7540010ac3fSVille Syrjälä atmel_hlcdc_plane_update_clut(plane, state); 7552389fc13SBoris Brezillon atmel_hlcdc_plane_update_buffers(plane, state); 7565957017dSBoris Brezillon atmel_hlcdc_plane_update_disc_area(plane, state); 7572389fc13SBoris Brezillon 7589a45d33cSBoris Brezillon /* Enable the overrun interrupts. */ 7599a45d33cSBoris Brezillon atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER, 7609a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_OVR_IRQ(0) | 7619a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_OVR_IRQ(1) | 7629a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_OVR_IRQ(2)); 7639a45d33cSBoris Brezillon 7649a45d33cSBoris Brezillon /* Apply the new config at the next SOF event. */ 7659a45d33cSBoris Brezillon sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR); 7669a45d33cSBoris Brezillon atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER, 7679a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_UPDATE | 7689a45d33cSBoris Brezillon (sr & ATMEL_HLCDC_LAYER_EN ? 7699a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN)); 7702389fc13SBoris Brezillon } 7712389fc13SBoris Brezillon 7727f73c10bSMaxime Ripard static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane) 7731a396789SBoris Brezillon { 7749a45d33cSBoris Brezillon const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 7751a396789SBoris Brezillon 7761a396789SBoris Brezillon if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER || 7777f73c10bSMaxime Ripard desc->type == ATMEL_HLCDC_CURSOR_LAYER) { 7787f73c10bSMaxime Ripard int ret; 7797f73c10bSMaxime Ripard 7807f73c10bSMaxime Ripard ret = drm_plane_create_alpha_property(&plane->base); 7817f73c10bSMaxime Ripard if (ret) 7827f73c10bSMaxime Ripard return ret; 7837f73c10bSMaxime Ripard } 7841a396789SBoris Brezillon 7859fcf2b3cSStefan Agner if (desc->layout.xstride[0] && desc->layout.pstride[0]) { 7869fe58f01SVille Syrjälä int ret; 7879fe58f01SVille Syrjälä 7889fe58f01SVille Syrjälä ret = drm_plane_create_rotation_property(&plane->base, 789c2c446adSRobert Foss DRM_MODE_ROTATE_0, 790c2c446adSRobert Foss DRM_MODE_ROTATE_0 | 791c2c446adSRobert Foss DRM_MODE_ROTATE_90 | 792c2c446adSRobert Foss DRM_MODE_ROTATE_180 | 793c2c446adSRobert Foss DRM_MODE_ROTATE_270); 7949fe58f01SVille Syrjälä if (ret) 7959fe58f01SVille Syrjälä return ret; 7969fe58f01SVille Syrjälä } 7971a396789SBoris Brezillon 7981a396789SBoris Brezillon if (desc->layout.csc) { 7991a396789SBoris Brezillon /* 8001a396789SBoris Brezillon * TODO: decare a "yuv-to-rgb-conv-factors" property to let 8011a396789SBoris Brezillon * userspace modify these factors (using a BLOB property ?). 8021a396789SBoris Brezillon */ 8039a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, 8049a45d33cSBoris Brezillon desc->layout.csc, 8051a396789SBoris Brezillon 0x4c900091); 8069a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, 8079a45d33cSBoris Brezillon desc->layout.csc + 1, 8081a396789SBoris Brezillon 0x7a5f5090); 8099a45d33cSBoris Brezillon atmel_hlcdc_layer_write_cfg(&plane->layer, 8109a45d33cSBoris Brezillon desc->layout.csc + 2, 8111a396789SBoris Brezillon 0x40040890); 8121a396789SBoris Brezillon } 8139fe58f01SVille Syrjälä 8149fe58f01SVille Syrjälä return 0; 8151a396789SBoris Brezillon } 8161a396789SBoris Brezillon 8179a45d33cSBoris Brezillon void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane) 8189a45d33cSBoris Brezillon { 8199a45d33cSBoris Brezillon const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 8209a45d33cSBoris Brezillon u32 isr; 8219a45d33cSBoris Brezillon 8229a45d33cSBoris Brezillon isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR); 8239a45d33cSBoris Brezillon 8249a45d33cSBoris Brezillon /* 8259a45d33cSBoris Brezillon * There's not much we can do in case of overrun except informing 8269a45d33cSBoris Brezillon * the user. However, we are in interrupt context here, hence the 8279a45d33cSBoris Brezillon * use of dev_dbg(). 8289a45d33cSBoris Brezillon */ 8299a45d33cSBoris Brezillon if (isr & 8309a45d33cSBoris Brezillon (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) | 8319a45d33cSBoris Brezillon ATMEL_HLCDC_LAYER_OVR_IRQ(2))) 8329a45d33cSBoris Brezillon dev_dbg(plane->base.dev->dev, "overrun on plane %s\n", 8339a45d33cSBoris Brezillon desc->name); 8349a45d33cSBoris Brezillon } 8359a45d33cSBoris Brezillon 836d95a8e7bSArvind Yadav static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = { 8372389fc13SBoris Brezillon .atomic_check = atmel_hlcdc_plane_atomic_check, 8382389fc13SBoris Brezillon .atomic_update = atmel_hlcdc_plane_atomic_update, 8392389fc13SBoris Brezillon .atomic_disable = atmel_hlcdc_plane_atomic_disable, 8402389fc13SBoris Brezillon }; 8412389fc13SBoris Brezillon 8429a45d33cSBoris Brezillon static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p, 8439a45d33cSBoris Brezillon struct atmel_hlcdc_plane_state *state) 8449a45d33cSBoris Brezillon { 8459a45d33cSBoris Brezillon struct atmel_hlcdc_dc *dc = p->dev->dev_private; 8469a45d33cSBoris Brezillon int i; 8479a45d33cSBoris Brezillon 8489a45d33cSBoris Brezillon for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) { 8499a45d33cSBoris Brezillon struct atmel_hlcdc_dma_channel_dscr *dscr; 8509a45d33cSBoris Brezillon dma_addr_t dscr_dma; 8519a45d33cSBoris Brezillon 8529a45d33cSBoris Brezillon dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma); 8539a45d33cSBoris Brezillon if (!dscr) 8549a45d33cSBoris Brezillon goto err; 8559a45d33cSBoris Brezillon 8569a45d33cSBoris Brezillon dscr->addr = 0; 8579a45d33cSBoris Brezillon dscr->next = dscr_dma; 8589a45d33cSBoris Brezillon dscr->self = dscr_dma; 8599a45d33cSBoris Brezillon dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH; 8609a45d33cSBoris Brezillon 8619a45d33cSBoris Brezillon state->dscrs[i] = dscr; 8629a45d33cSBoris Brezillon } 8639a45d33cSBoris Brezillon 8649a45d33cSBoris Brezillon return 0; 8659a45d33cSBoris Brezillon 8669a45d33cSBoris Brezillon err: 8679a45d33cSBoris Brezillon for (i--; i >= 0; i--) { 8689a45d33cSBoris Brezillon dma_pool_free(dc->dscrpool, state->dscrs[i], 8699a45d33cSBoris Brezillon state->dscrs[i]->self); 8709a45d33cSBoris Brezillon } 8719a45d33cSBoris Brezillon 8729a45d33cSBoris Brezillon return -ENOMEM; 8739a45d33cSBoris Brezillon } 8749a45d33cSBoris Brezillon 8752389fc13SBoris Brezillon static void atmel_hlcdc_plane_reset(struct drm_plane *p) 8762389fc13SBoris Brezillon { 8772389fc13SBoris Brezillon struct atmel_hlcdc_plane_state *state; 8782389fc13SBoris Brezillon 8792389fc13SBoris Brezillon if (p->state) { 8802389fc13SBoris Brezillon state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 8812389fc13SBoris Brezillon 8822389fc13SBoris Brezillon if (state->base.fb) 883f3a73544SCihangir Akturk drm_framebuffer_put(state->base.fb); 8842389fc13SBoris Brezillon 8852389fc13SBoris Brezillon kfree(state); 8862389fc13SBoris Brezillon p->state = NULL; 8872389fc13SBoris Brezillon } 8882389fc13SBoris Brezillon 8892389fc13SBoris Brezillon state = kzalloc(sizeof(*state), GFP_KERNEL); 8902389fc13SBoris Brezillon if (state) { 8919a45d33cSBoris Brezillon if (atmel_hlcdc_plane_alloc_dscrs(p, state)) { 8929a45d33cSBoris Brezillon kfree(state); 8939a45d33cSBoris Brezillon dev_err(p->dev->dev, 8949a45d33cSBoris Brezillon "Failed to allocate initial plane state\n"); 8959a45d33cSBoris Brezillon return; 8969a45d33cSBoris Brezillon } 897e2512172SAlexandru Gheorghe __drm_atomic_helper_plane_reset(p, &state->base); 8982389fc13SBoris Brezillon } 8992389fc13SBoris Brezillon } 9002389fc13SBoris Brezillon 9012389fc13SBoris Brezillon static struct drm_plane_state * 9022389fc13SBoris Brezillon atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p) 9032389fc13SBoris Brezillon { 9042389fc13SBoris Brezillon struct atmel_hlcdc_plane_state *state = 9052389fc13SBoris Brezillon drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 9062389fc13SBoris Brezillon struct atmel_hlcdc_plane_state *copy; 9072389fc13SBoris Brezillon 9082389fc13SBoris Brezillon copy = kmemdup(state, sizeof(*state), GFP_KERNEL); 9092389fc13SBoris Brezillon if (!copy) 9102389fc13SBoris Brezillon return NULL; 9112389fc13SBoris Brezillon 9129a45d33cSBoris Brezillon if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) { 9139a45d33cSBoris Brezillon kfree(copy); 9149a45d33cSBoris Brezillon return NULL; 9159a45d33cSBoris Brezillon } 9165957017dSBoris Brezillon 9172389fc13SBoris Brezillon if (copy->base.fb) 918f3a73544SCihangir Akturk drm_framebuffer_get(copy->base.fb); 9192389fc13SBoris Brezillon 9202389fc13SBoris Brezillon return ©->base; 9212389fc13SBoris Brezillon } 9222389fc13SBoris Brezillon 9239a45d33cSBoris Brezillon static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p, 9242389fc13SBoris Brezillon struct drm_plane_state *s) 9252389fc13SBoris Brezillon { 9262389fc13SBoris Brezillon struct atmel_hlcdc_plane_state *state = 9272389fc13SBoris Brezillon drm_plane_state_to_atmel_hlcdc_plane_state(s); 9289a45d33cSBoris Brezillon struct atmel_hlcdc_dc *dc = p->dev->dev_private; 9299a45d33cSBoris Brezillon int i; 9309a45d33cSBoris Brezillon 9319a45d33cSBoris Brezillon for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) { 9329a45d33cSBoris Brezillon dma_pool_free(dc->dscrpool, state->dscrs[i], 9339a45d33cSBoris Brezillon state->dscrs[i]->self); 9349a45d33cSBoris Brezillon } 9352389fc13SBoris Brezillon 9362389fc13SBoris Brezillon if (s->fb) 937f3a73544SCihangir Akturk drm_framebuffer_put(s->fb); 9382389fc13SBoris Brezillon 9392389fc13SBoris Brezillon kfree(state); 9402389fc13SBoris Brezillon } 9412389fc13SBoris Brezillon 942d95a8e7bSArvind Yadav static const struct drm_plane_funcs layer_plane_funcs = { 9432389fc13SBoris Brezillon .update_plane = drm_atomic_helper_update_plane, 9442389fc13SBoris Brezillon .disable_plane = drm_atomic_helper_disable_plane, 945952a08a2SVille Syrjälä .destroy = drm_plane_cleanup, 9462389fc13SBoris Brezillon .reset = atmel_hlcdc_plane_reset, 9472389fc13SBoris Brezillon .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state, 9482389fc13SBoris Brezillon .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state, 9491a396789SBoris Brezillon }; 9501a396789SBoris Brezillon 9519a45d33cSBoris Brezillon static int atmel_hlcdc_plane_create(struct drm_device *dev, 9527f73c10bSMaxime Ripard const struct atmel_hlcdc_layer_desc *desc) 9531a396789SBoris Brezillon { 9549a45d33cSBoris Brezillon struct atmel_hlcdc_dc *dc = dev->dev_private; 9551a396789SBoris Brezillon struct atmel_hlcdc_plane *plane; 9561a396789SBoris Brezillon enum drm_plane_type type; 9571a396789SBoris Brezillon int ret; 9581a396789SBoris Brezillon 9591a396789SBoris Brezillon plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL); 9601a396789SBoris Brezillon if (!plane) 9619a45d33cSBoris Brezillon return -ENOMEM; 9621a396789SBoris Brezillon 9639a45d33cSBoris Brezillon atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap); 9641a396789SBoris Brezillon 9651a396789SBoris Brezillon if (desc->type == ATMEL_HLCDC_BASE_LAYER) 9661a396789SBoris Brezillon type = DRM_PLANE_TYPE_PRIMARY; 9671a396789SBoris Brezillon else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER) 9681a396789SBoris Brezillon type = DRM_PLANE_TYPE_CURSOR; 9691a396789SBoris Brezillon else 9701a396789SBoris Brezillon type = DRM_PLANE_TYPE_OVERLAY; 9711a396789SBoris Brezillon 9721a396789SBoris Brezillon ret = drm_universal_plane_init(dev, &plane->base, 0, 9731a396789SBoris Brezillon &layer_plane_funcs, 9741a396789SBoris Brezillon desc->formats->formats, 975e6fc3b68SBen Widawsky desc->formats->nformats, 976e6fc3b68SBen Widawsky NULL, type, NULL); 9771a396789SBoris Brezillon if (ret) 9789a45d33cSBoris Brezillon return ret; 9791a396789SBoris Brezillon 9802389fc13SBoris Brezillon drm_plane_helper_add(&plane->base, 9812389fc13SBoris Brezillon &atmel_hlcdc_layer_plane_helper_funcs); 9822389fc13SBoris Brezillon 9831a396789SBoris Brezillon /* Set default property values*/ 9847f73c10bSMaxime Ripard ret = atmel_hlcdc_plane_init_properties(plane); 9859fe58f01SVille Syrjälä if (ret) 9869a45d33cSBoris Brezillon return ret; 9871a396789SBoris Brezillon 9889a45d33cSBoris Brezillon dc->layers[desc->id] = &plane->layer; 9899a45d33cSBoris Brezillon 9909a45d33cSBoris Brezillon return 0; 9911a396789SBoris Brezillon } 9921a396789SBoris Brezillon 9939a45d33cSBoris Brezillon int atmel_hlcdc_create_planes(struct drm_device *dev) 9941a396789SBoris Brezillon { 9951a396789SBoris Brezillon struct atmel_hlcdc_dc *dc = dev->dev_private; 9961a396789SBoris Brezillon const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers; 9971a396789SBoris Brezillon int nlayers = dc->desc->nlayers; 9989a45d33cSBoris Brezillon int i, ret; 9991a396789SBoris Brezillon 10009a45d33cSBoris Brezillon dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev, 10019a45d33cSBoris Brezillon sizeof(struct atmel_hlcdc_dma_channel_dscr), 10029a45d33cSBoris Brezillon sizeof(u64), 0); 10039a45d33cSBoris Brezillon if (!dc->dscrpool) 10049a45d33cSBoris Brezillon return -ENOMEM; 10059a45d33cSBoris Brezillon 10061a396789SBoris Brezillon for (i = 0; i < nlayers; i++) { 10079a45d33cSBoris Brezillon if (descs[i].type != ATMEL_HLCDC_BASE_LAYER && 10089a45d33cSBoris Brezillon descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER && 10099a45d33cSBoris Brezillon descs[i].type != ATMEL_HLCDC_CURSOR_LAYER) 10101a396789SBoris Brezillon continue; 10111a396789SBoris Brezillon 10127f73c10bSMaxime Ripard ret = atmel_hlcdc_plane_create(dev, &descs[i]); 10139a45d33cSBoris Brezillon if (ret) 10149a45d33cSBoris Brezillon return ret; 10151a396789SBoris Brezillon } 10161a396789SBoris Brezillon 10179a45d33cSBoris Brezillon return 0; 10181a396789SBoris Brezillon } 1019