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