18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2016 Linaro Ltd. 48c2ecf20Sopenharmony_ci * Copyright 2016 ZTE Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h> 88c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 98c2ecf20Sopenharmony_ci#include <drm/drm_fb_cma_helper.h> 108c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 118c2ecf20Sopenharmony_ci#include <drm/drm_gem_cma_helper.h> 128c2ecf20Sopenharmony_ci#include <drm/drm_modeset_helper_vtables.h> 138c2ecf20Sopenharmony_ci#include <drm/drm_plane_helper.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "zx_common_regs.h" 168c2ecf20Sopenharmony_ci#include "zx_drm_drv.h" 178c2ecf20Sopenharmony_ci#include "zx_plane.h" 188c2ecf20Sopenharmony_ci#include "zx_plane_regs.h" 198c2ecf20Sopenharmony_ci#include "zx_vou.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic const uint32_t gl_formats[] = { 228c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB8888, 238c2ecf20Sopenharmony_ci DRM_FORMAT_XRGB8888, 248c2ecf20Sopenharmony_ci DRM_FORMAT_RGB888, 258c2ecf20Sopenharmony_ci DRM_FORMAT_RGB565, 268c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB1555, 278c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB4444, 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic const uint32_t vl_formats[] = { 318c2ecf20Sopenharmony_ci DRM_FORMAT_NV12, /* Semi-planar YUV420 */ 328c2ecf20Sopenharmony_ci DRM_FORMAT_YUV420, /* Planar YUV420 */ 338c2ecf20Sopenharmony_ci DRM_FORMAT_YUYV, /* Packed YUV422 */ 348c2ecf20Sopenharmony_ci DRM_FORMAT_YVYU, 358c2ecf20Sopenharmony_ci DRM_FORMAT_UYVY, 368c2ecf20Sopenharmony_ci DRM_FORMAT_VYUY, 378c2ecf20Sopenharmony_ci DRM_FORMAT_YUV444, /* YUV444 8bit */ 388c2ecf20Sopenharmony_ci /* 398c2ecf20Sopenharmony_ci * TODO: add formats below that HW supports: 408c2ecf20Sopenharmony_ci * - YUV420 P010 418c2ecf20Sopenharmony_ci * - YUV420 Hantro 428c2ecf20Sopenharmony_ci * - YUV444 10bit 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define FRAC_16_16(mult, div) (((mult) << 16) / (div)) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int zx_vl_plane_atomic_check(struct drm_plane *plane, 498c2ecf20Sopenharmony_ci struct drm_plane_state *plane_state) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct drm_framebuffer *fb = plane_state->fb; 528c2ecf20Sopenharmony_ci struct drm_crtc *crtc = plane_state->crtc; 538c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 548c2ecf20Sopenharmony_ci int min_scale = FRAC_16_16(1, 8); 558c2ecf20Sopenharmony_ci int max_scale = FRAC_16_16(8, 1); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (!crtc || WARN_ON(!fb)) 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state, 618c2ecf20Sopenharmony_ci crtc); 628c2ecf20Sopenharmony_ci if (WARN_ON(!crtc_state)) 638c2ecf20Sopenharmony_ci return -EINVAL; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* nothing to check when disabling or disabled */ 668c2ecf20Sopenharmony_ci if (!crtc_state->enable) 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* plane must be enabled */ 708c2ecf20Sopenharmony_ci if (!plane_state->crtc) 718c2ecf20Sopenharmony_ci return -EINVAL; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return drm_atomic_helper_check_plane_state(plane_state, crtc_state, 748c2ecf20Sopenharmony_ci min_scale, max_scale, 758c2ecf20Sopenharmony_ci true, true); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int zx_vl_get_fmt(uint32_t format) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci switch (format) { 818c2ecf20Sopenharmony_ci case DRM_FORMAT_NV12: 828c2ecf20Sopenharmony_ci return VL_FMT_YUV420; 838c2ecf20Sopenharmony_ci case DRM_FORMAT_YUV420: 848c2ecf20Sopenharmony_ci return VL_YUV420_PLANAR | VL_FMT_YUV420; 858c2ecf20Sopenharmony_ci case DRM_FORMAT_YUYV: 868c2ecf20Sopenharmony_ci return VL_YUV422_YUYV | VL_FMT_YUV422; 878c2ecf20Sopenharmony_ci case DRM_FORMAT_YVYU: 888c2ecf20Sopenharmony_ci return VL_YUV422_YVYU | VL_FMT_YUV422; 898c2ecf20Sopenharmony_ci case DRM_FORMAT_UYVY: 908c2ecf20Sopenharmony_ci return VL_YUV422_UYVY | VL_FMT_YUV422; 918c2ecf20Sopenharmony_ci case DRM_FORMAT_VYUY: 928c2ecf20Sopenharmony_ci return VL_YUV422_VYUY | VL_FMT_YUV422; 938c2ecf20Sopenharmony_ci case DRM_FORMAT_YUV444: 948c2ecf20Sopenharmony_ci return VL_FMT_YUV444_8BIT; 958c2ecf20Sopenharmony_ci default: 968c2ecf20Sopenharmony_ci WARN_ONCE(1, "invalid pixel format %d\n", format); 978c2ecf20Sopenharmony_ci return -EINVAL; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic inline void zx_vl_set_update(struct zx_plane *zplane) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci void __iomem *layer = zplane->layer; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci zx_writel_mask(layer + VL_CTRL0, VL_UPDATE, VL_UPDATE); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic inline void zx_vl_rsz_set_update(struct zx_plane *zplane) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int zx_vl_rsz_get_fmt(uint32_t format) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci switch (format) { 1168c2ecf20Sopenharmony_ci case DRM_FORMAT_NV12: 1178c2ecf20Sopenharmony_ci case DRM_FORMAT_YUV420: 1188c2ecf20Sopenharmony_ci return RSZ_VL_FMT_YCBCR420; 1198c2ecf20Sopenharmony_ci case DRM_FORMAT_YUYV: 1208c2ecf20Sopenharmony_ci case DRM_FORMAT_YVYU: 1218c2ecf20Sopenharmony_ci case DRM_FORMAT_UYVY: 1228c2ecf20Sopenharmony_ci case DRM_FORMAT_VYUY: 1238c2ecf20Sopenharmony_ci return RSZ_VL_FMT_YCBCR422; 1248c2ecf20Sopenharmony_ci case DRM_FORMAT_YUV444: 1258c2ecf20Sopenharmony_ci return RSZ_VL_FMT_YCBCR444; 1268c2ecf20Sopenharmony_ci default: 1278c2ecf20Sopenharmony_ci WARN_ONCE(1, "invalid pixel format %d\n", format); 1288c2ecf20Sopenharmony_ci return -EINVAL; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic inline u32 rsz_step_value(u32 src, u32 dst) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci u32 val = 0; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (src == dst) 1378c2ecf20Sopenharmony_ci val = 0; 1388c2ecf20Sopenharmony_ci else if (src < dst) 1398c2ecf20Sopenharmony_ci val = RSZ_PARA_STEP((src << 16) / dst); 1408c2ecf20Sopenharmony_ci else if (src > dst) 1418c2ecf20Sopenharmony_ci val = RSZ_DATA_STEP(src / dst) | 1428c2ecf20Sopenharmony_ci RSZ_PARA_STEP(((src << 16) / dst) & 0xffff); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return val; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void zx_vl_rsz_setup(struct zx_plane *zplane, uint32_t format, 1488c2ecf20Sopenharmony_ci u32 src_w, u32 src_h, u32 dst_w, u32 dst_h) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci void __iomem *rsz = zplane->rsz; 1518c2ecf20Sopenharmony_ci u32 src_chroma_w = src_w; 1528c2ecf20Sopenharmony_ci u32 src_chroma_h = src_h; 1538c2ecf20Sopenharmony_ci int fmt; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Set up source and destination resolution */ 1568c2ecf20Sopenharmony_ci zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1)); 1578c2ecf20Sopenharmony_ci zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1)); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* Configure data format for VL RSZ */ 1608c2ecf20Sopenharmony_ci fmt = zx_vl_rsz_get_fmt(format); 1618c2ecf20Sopenharmony_ci if (fmt >= 0) 1628c2ecf20Sopenharmony_ci zx_writel_mask(rsz + RSZ_VL_CTRL_CFG, RSZ_VL_FMT_MASK, fmt); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* Calculate Chroma height and width */ 1658c2ecf20Sopenharmony_ci if (fmt == RSZ_VL_FMT_YCBCR420) { 1668c2ecf20Sopenharmony_ci src_chroma_w = src_w >> 1; 1678c2ecf20Sopenharmony_ci src_chroma_h = src_h >> 1; 1688c2ecf20Sopenharmony_ci } else if (fmt == RSZ_VL_FMT_YCBCR422) { 1698c2ecf20Sopenharmony_ci src_chroma_w = src_w >> 1; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* Set up Luma and Chroma step registers */ 1738c2ecf20Sopenharmony_ci zx_writel(rsz + RSZ_VL_LUMA_HOR, rsz_step_value(src_w, dst_w)); 1748c2ecf20Sopenharmony_ci zx_writel(rsz + RSZ_VL_LUMA_VER, rsz_step_value(src_h, dst_h)); 1758c2ecf20Sopenharmony_ci zx_writel(rsz + RSZ_VL_CHROMA_HOR, rsz_step_value(src_chroma_w, dst_w)); 1768c2ecf20Sopenharmony_ci zx_writel(rsz + RSZ_VL_CHROMA_VER, rsz_step_value(src_chroma_h, dst_h)); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci zx_vl_rsz_set_update(zplane); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void zx_vl_plane_atomic_update(struct drm_plane *plane, 1828c2ecf20Sopenharmony_ci struct drm_plane_state *old_state) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct zx_plane *zplane = to_zx_plane(plane); 1858c2ecf20Sopenharmony_ci struct drm_plane_state *state = plane->state; 1868c2ecf20Sopenharmony_ci struct drm_framebuffer *fb = state->fb; 1878c2ecf20Sopenharmony_ci struct drm_rect *src = &state->src; 1888c2ecf20Sopenharmony_ci struct drm_rect *dst = &state->dst; 1898c2ecf20Sopenharmony_ci struct drm_gem_cma_object *cma_obj; 1908c2ecf20Sopenharmony_ci void __iomem *layer = zplane->layer; 1918c2ecf20Sopenharmony_ci void __iomem *hbsc = zplane->hbsc; 1928c2ecf20Sopenharmony_ci void __iomem *paddr_reg; 1938c2ecf20Sopenharmony_ci dma_addr_t paddr; 1948c2ecf20Sopenharmony_ci u32 src_x, src_y, src_w, src_h; 1958c2ecf20Sopenharmony_ci u32 dst_x, dst_y, dst_w, dst_h; 1968c2ecf20Sopenharmony_ci uint32_t format; 1978c2ecf20Sopenharmony_ci int fmt; 1988c2ecf20Sopenharmony_ci int i; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (!fb) 2018c2ecf20Sopenharmony_ci return; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci format = fb->format->format; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci src_x = src->x1 >> 16; 2068c2ecf20Sopenharmony_ci src_y = src->y1 >> 16; 2078c2ecf20Sopenharmony_ci src_w = drm_rect_width(src) >> 16; 2088c2ecf20Sopenharmony_ci src_h = drm_rect_height(src) >> 16; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci dst_x = dst->x1; 2118c2ecf20Sopenharmony_ci dst_y = dst->y1; 2128c2ecf20Sopenharmony_ci dst_w = drm_rect_width(dst); 2138c2ecf20Sopenharmony_ci dst_h = drm_rect_height(dst); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* Set up data address registers for Y, Cb and Cr planes */ 2168c2ecf20Sopenharmony_ci paddr_reg = layer + VL_Y; 2178c2ecf20Sopenharmony_ci for (i = 0; i < fb->format->num_planes; i++) { 2188c2ecf20Sopenharmony_ci cma_obj = drm_fb_cma_get_gem_obj(fb, i); 2198c2ecf20Sopenharmony_ci paddr = cma_obj->paddr + fb->offsets[i]; 2208c2ecf20Sopenharmony_ci paddr += src_y * fb->pitches[i]; 2218c2ecf20Sopenharmony_ci paddr += src_x * fb->format->cpp[i]; 2228c2ecf20Sopenharmony_ci zx_writel(paddr_reg, paddr); 2238c2ecf20Sopenharmony_ci paddr_reg += 4; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Set up source height/width register */ 2278c2ecf20Sopenharmony_ci zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h)); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Set up start position register */ 2308c2ecf20Sopenharmony_ci zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y)); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Set up end position register */ 2338c2ecf20Sopenharmony_ci zx_writel(layer + VL_POS_END, 2348c2ecf20Sopenharmony_ci GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h)); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Strides of Cb and Cr planes should be identical */ 2378c2ecf20Sopenharmony_ci zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) | 2388c2ecf20Sopenharmony_ci CHROMA_STRIDE(fb->pitches[1])); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Set up video layer data format */ 2418c2ecf20Sopenharmony_ci fmt = zx_vl_get_fmt(format); 2428c2ecf20Sopenharmony_ci if (fmt >= 0) 2438c2ecf20Sopenharmony_ci zx_writel(layer + VL_CTRL1, fmt); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Always use scaler since it exists (set for not bypass) */ 2468c2ecf20Sopenharmony_ci zx_writel_mask(layer + VL_CTRL2, VL_SCALER_BYPASS_MODE, 2478c2ecf20Sopenharmony_ci VL_SCALER_BYPASS_MODE); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci zx_vl_rsz_setup(zplane, format, src_w, src_h, dst_w, dst_h); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* Enable HBSC block */ 2528c2ecf20Sopenharmony_ci zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci zx_vou_layer_enable(plane); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci zx_vl_set_update(zplane); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void zx_plane_atomic_disable(struct drm_plane *plane, 2608c2ecf20Sopenharmony_ci struct drm_plane_state *old_state) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct zx_plane *zplane = to_zx_plane(plane); 2638c2ecf20Sopenharmony_ci void __iomem *hbsc = zplane->hbsc; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci zx_vou_layer_disable(plane, old_state); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Disable HBSC block */ 2688c2ecf20Sopenharmony_ci zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs = { 2728c2ecf20Sopenharmony_ci .atomic_check = zx_vl_plane_atomic_check, 2738c2ecf20Sopenharmony_ci .atomic_update = zx_vl_plane_atomic_update, 2748c2ecf20Sopenharmony_ci .atomic_disable = zx_plane_atomic_disable, 2758c2ecf20Sopenharmony_ci}; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int zx_gl_plane_atomic_check(struct drm_plane *plane, 2788c2ecf20Sopenharmony_ci struct drm_plane_state *plane_state) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct drm_framebuffer *fb = plane_state->fb; 2818c2ecf20Sopenharmony_ci struct drm_crtc *crtc = plane_state->crtc; 2828c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (!crtc || WARN_ON(!fb)) 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state, 2888c2ecf20Sopenharmony_ci crtc); 2898c2ecf20Sopenharmony_ci if (WARN_ON(!crtc_state)) 2908c2ecf20Sopenharmony_ci return -EINVAL; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* nothing to check when disabling or disabled */ 2938c2ecf20Sopenharmony_ci if (!crtc_state->enable) 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* plane must be enabled */ 2978c2ecf20Sopenharmony_ci if (!plane_state->crtc) 2988c2ecf20Sopenharmony_ci return -EINVAL; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return drm_atomic_helper_check_plane_state(plane_state, crtc_state, 3018c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 3028c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 3038c2ecf20Sopenharmony_ci false, true); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int zx_gl_get_fmt(uint32_t format) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci switch (format) { 3098c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB8888: 3108c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB8888: 3118c2ecf20Sopenharmony_ci return GL_FMT_ARGB8888; 3128c2ecf20Sopenharmony_ci case DRM_FORMAT_RGB888: 3138c2ecf20Sopenharmony_ci return GL_FMT_RGB888; 3148c2ecf20Sopenharmony_ci case DRM_FORMAT_RGB565: 3158c2ecf20Sopenharmony_ci return GL_FMT_RGB565; 3168c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB1555: 3178c2ecf20Sopenharmony_ci return GL_FMT_ARGB1555; 3188c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB4444: 3198c2ecf20Sopenharmony_ci return GL_FMT_ARGB4444; 3208c2ecf20Sopenharmony_ci default: 3218c2ecf20Sopenharmony_ci WARN_ONCE(1, "invalid pixel format %d\n", format); 3228c2ecf20Sopenharmony_ci return -EINVAL; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic inline void zx_gl_set_update(struct zx_plane *zplane) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci void __iomem *layer = zplane->layer; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic inline void zx_gl_rsz_set_update(struct zx_plane *zplane) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h, 3398c2ecf20Sopenharmony_ci u32 dst_w, u32 dst_h) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci void __iomem *rsz = zplane->rsz; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1)); 3448c2ecf20Sopenharmony_ci zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1)); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci zx_gl_rsz_set_update(zplane); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic void zx_gl_plane_atomic_update(struct drm_plane *plane, 3508c2ecf20Sopenharmony_ci struct drm_plane_state *old_state) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct zx_plane *zplane = to_zx_plane(plane); 3538c2ecf20Sopenharmony_ci struct drm_framebuffer *fb = plane->state->fb; 3548c2ecf20Sopenharmony_ci struct drm_gem_cma_object *cma_obj; 3558c2ecf20Sopenharmony_ci void __iomem *layer = zplane->layer; 3568c2ecf20Sopenharmony_ci void __iomem *csc = zplane->csc; 3578c2ecf20Sopenharmony_ci void __iomem *hbsc = zplane->hbsc; 3588c2ecf20Sopenharmony_ci u32 src_x, src_y, src_w, src_h; 3598c2ecf20Sopenharmony_ci u32 dst_x, dst_y, dst_w, dst_h; 3608c2ecf20Sopenharmony_ci unsigned int bpp; 3618c2ecf20Sopenharmony_ci uint32_t format; 3628c2ecf20Sopenharmony_ci dma_addr_t paddr; 3638c2ecf20Sopenharmony_ci u32 stride; 3648c2ecf20Sopenharmony_ci int fmt; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (!fb) 3678c2ecf20Sopenharmony_ci return; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci format = fb->format->format; 3708c2ecf20Sopenharmony_ci stride = fb->pitches[0]; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci src_x = plane->state->src_x >> 16; 3738c2ecf20Sopenharmony_ci src_y = plane->state->src_y >> 16; 3748c2ecf20Sopenharmony_ci src_w = plane->state->src_w >> 16; 3758c2ecf20Sopenharmony_ci src_h = plane->state->src_h >> 16; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci dst_x = plane->state->crtc_x; 3788c2ecf20Sopenharmony_ci dst_y = plane->state->crtc_y; 3798c2ecf20Sopenharmony_ci dst_w = plane->state->crtc_w; 3808c2ecf20Sopenharmony_ci dst_h = plane->state->crtc_h; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci bpp = fb->format->cpp[0]; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 3858c2ecf20Sopenharmony_ci paddr = cma_obj->paddr + fb->offsets[0]; 3868c2ecf20Sopenharmony_ci paddr += src_y * stride + src_x * bpp / 8; 3878c2ecf20Sopenharmony_ci zx_writel(layer + GL_ADDR, paddr); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Set up source height/width register */ 3908c2ecf20Sopenharmony_ci zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h)); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* Set up start position register */ 3938c2ecf20Sopenharmony_ci zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y)); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* Set up end position register */ 3968c2ecf20Sopenharmony_ci zx_writel(layer + GL_POS_END, 3978c2ecf20Sopenharmony_ci GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h)); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* Set up stride register */ 4008c2ecf20Sopenharmony_ci zx_writel(layer + GL_STRIDE, stride & 0xffff); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* Set up graphic layer data format */ 4038c2ecf20Sopenharmony_ci fmt = zx_gl_get_fmt(format); 4048c2ecf20Sopenharmony_ci if (fmt >= 0) 4058c2ecf20Sopenharmony_ci zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK, 4068c2ecf20Sopenharmony_ci fmt << GL_DATA_FMT_SHIFT); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* Initialize global alpha with a sane value */ 4098c2ecf20Sopenharmony_ci zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK, 4108c2ecf20Sopenharmony_ci 0xff << GL_GLOBAL_ALPHA_SHIFT); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Setup CSC for the GL */ 4138c2ecf20Sopenharmony_ci if (dst_h > 720) 4148c2ecf20Sopenharmony_ci zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK, 4158c2ecf20Sopenharmony_ci CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT); 4168c2ecf20Sopenharmony_ci else 4178c2ecf20Sopenharmony_ci zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK, 4188c2ecf20Sopenharmony_ci CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT); 4198c2ecf20Sopenharmony_ci zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* Always use scaler since it exists (set for not bypass) */ 4228c2ecf20Sopenharmony_ci zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE, 4238c2ecf20Sopenharmony_ci GL_SCALER_BYPASS_MODE); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Enable HBSC block */ 4288c2ecf20Sopenharmony_ci zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci zx_vou_layer_enable(plane); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci zx_gl_set_update(zplane); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = { 4368c2ecf20Sopenharmony_ci .atomic_check = zx_gl_plane_atomic_check, 4378c2ecf20Sopenharmony_ci .atomic_update = zx_gl_plane_atomic_update, 4388c2ecf20Sopenharmony_ci .atomic_disable = zx_plane_atomic_disable, 4398c2ecf20Sopenharmony_ci}; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic void zx_plane_destroy(struct drm_plane *plane) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci drm_plane_cleanup(plane); 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic const struct drm_plane_funcs zx_plane_funcs = { 4478c2ecf20Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 4488c2ecf20Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 4498c2ecf20Sopenharmony_ci .destroy = zx_plane_destroy, 4508c2ecf20Sopenharmony_ci .reset = drm_atomic_helper_plane_reset, 4518c2ecf20Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 4528c2ecf20Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 4538c2ecf20Sopenharmony_ci}; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_civoid zx_plane_set_update(struct drm_plane *plane) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct zx_plane *zplane = to_zx_plane(plane); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* Do nothing if the plane is not enabled */ 4608c2ecf20Sopenharmony_ci if (!plane->state->crtc) 4618c2ecf20Sopenharmony_ci return; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci switch (plane->type) { 4648c2ecf20Sopenharmony_ci case DRM_PLANE_TYPE_PRIMARY: 4658c2ecf20Sopenharmony_ci zx_gl_rsz_set_update(zplane); 4668c2ecf20Sopenharmony_ci zx_gl_set_update(zplane); 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci case DRM_PLANE_TYPE_OVERLAY: 4698c2ecf20Sopenharmony_ci zx_vl_rsz_set_update(zplane); 4708c2ecf20Sopenharmony_ci zx_vl_set_update(zplane); 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci default: 4738c2ecf20Sopenharmony_ci WARN_ONCE(1, "unsupported plane type %d\n", plane->type); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic void zx_plane_hbsc_init(struct zx_plane *zplane) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci void __iomem *hbsc = zplane->hbsc; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* 4828c2ecf20Sopenharmony_ci * Initialize HBSC block with a sane configuration per recommedation 4838c2ecf20Sopenharmony_ci * from ZTE BSP code. 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_ci zx_writel(hbsc + HBSC_SATURATION, 0x200); 4868c2ecf20Sopenharmony_ci zx_writel(hbsc + HBSC_HUE, 0x0); 4878c2ecf20Sopenharmony_ci zx_writel(hbsc + HBSC_BRIGHT, 0x0); 4888c2ecf20Sopenharmony_ci zx_writel(hbsc + HBSC_CONTRAST, 0x200); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40); 4918c2ecf20Sopenharmony_ci zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40); 4928c2ecf20Sopenharmony_ci zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40); 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ciint zx_plane_init(struct drm_device *drm, struct zx_plane *zplane, 4968c2ecf20Sopenharmony_ci enum drm_plane_type type) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci const struct drm_plane_helper_funcs *helper; 4998c2ecf20Sopenharmony_ci struct drm_plane *plane = &zplane->plane; 5008c2ecf20Sopenharmony_ci struct device *dev = zplane->dev; 5018c2ecf20Sopenharmony_ci const uint32_t *formats; 5028c2ecf20Sopenharmony_ci unsigned int format_count; 5038c2ecf20Sopenharmony_ci int ret; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci zx_plane_hbsc_init(zplane); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci switch (type) { 5088c2ecf20Sopenharmony_ci case DRM_PLANE_TYPE_PRIMARY: 5098c2ecf20Sopenharmony_ci helper = &zx_gl_plane_helper_funcs; 5108c2ecf20Sopenharmony_ci formats = gl_formats; 5118c2ecf20Sopenharmony_ci format_count = ARRAY_SIZE(gl_formats); 5128c2ecf20Sopenharmony_ci break; 5138c2ecf20Sopenharmony_ci case DRM_PLANE_TYPE_OVERLAY: 5148c2ecf20Sopenharmony_ci helper = &zx_vl_plane_helper_funcs; 5158c2ecf20Sopenharmony_ci formats = vl_formats; 5168c2ecf20Sopenharmony_ci format_count = ARRAY_SIZE(vl_formats); 5178c2ecf20Sopenharmony_ci break; 5188c2ecf20Sopenharmony_ci default: 5198c2ecf20Sopenharmony_ci return -ENODEV; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK, 5238c2ecf20Sopenharmony_ci &zx_plane_funcs, formats, format_count, 5248c2ecf20Sopenharmony_ci NULL, type, NULL); 5258c2ecf20Sopenharmony_ci if (ret) { 5268c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret); 5278c2ecf20Sopenharmony_ci return ret; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci drm_plane_helper_add(plane, helper); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci return 0; 5338c2ecf20Sopenharmony_ci} 534