18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016-2018 Texas Instruments Incorporated - https://www.ti.com/ 48c2ecf20Sopenharmony_ci * Author: Jyri Sarha <jsarha@ti.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/clk.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/of_graph.h> 188c2ecf20Sopenharmony_ci#include <linux/of_device.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 218c2ecf20Sopenharmony_ci#include <linux/regmap.h> 228c2ecf20Sopenharmony_ci#include <linux/sys_soc.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 258c2ecf20Sopenharmony_ci#include <drm/drm_fb_cma_helper.h> 268c2ecf20Sopenharmony_ci#include <drm/drm_gem_cma_helper.h> 278c2ecf20Sopenharmony_ci#include <drm/drm_panel.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "tidss_crtc.h" 308c2ecf20Sopenharmony_ci#include "tidss_dispc.h" 318c2ecf20Sopenharmony_ci#include "tidss_drv.h" 328c2ecf20Sopenharmony_ci#include "tidss_irq.h" 338c2ecf20Sopenharmony_ci#include "tidss_plane.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "tidss_dispc_regs.h" 368c2ecf20Sopenharmony_ci#include "tidss_scale_coefs.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic const u16 tidss_k2g_common_regs[DISPC_COMMON_REG_TABLE_LEN] = { 398c2ecf20Sopenharmony_ci [DSS_REVISION_OFF] = 0x00, 408c2ecf20Sopenharmony_ci [DSS_SYSCONFIG_OFF] = 0x04, 418c2ecf20Sopenharmony_ci [DSS_SYSSTATUS_OFF] = 0x08, 428c2ecf20Sopenharmony_ci [DISPC_IRQ_EOI_OFF] = 0x20, 438c2ecf20Sopenharmony_ci [DISPC_IRQSTATUS_RAW_OFF] = 0x24, 448c2ecf20Sopenharmony_ci [DISPC_IRQSTATUS_OFF] = 0x28, 458c2ecf20Sopenharmony_ci [DISPC_IRQENABLE_SET_OFF] = 0x2c, 468c2ecf20Sopenharmony_ci [DISPC_IRQENABLE_CLR_OFF] = 0x30, 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci [DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] = 0x40, 498c2ecf20Sopenharmony_ci [DISPC_GLOBAL_BUFFER_OFF] = 0x44, 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci [DISPC_DBG_CONTROL_OFF] = 0x4c, 528c2ecf20Sopenharmony_ci [DISPC_DBG_STATUS_OFF] = 0x50, 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci [DISPC_CLKGATING_DISABLE_OFF] = 0x54, 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciconst struct dispc_features dispc_k2g_feats = { 588c2ecf20Sopenharmony_ci .min_pclk_khz = 4375, 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci .max_pclk_khz = { 618c2ecf20Sopenharmony_ci [DISPC_VP_DPI] = 150000, 628c2ecf20Sopenharmony_ci }, 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* 658c2ecf20Sopenharmony_ci * XXX According TRM the RGB input buffer width up to 2560 should 668c2ecf20Sopenharmony_ci * work on 3 taps, but in practice it only works up to 1280. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci .scaling = { 698c2ecf20Sopenharmony_ci .in_width_max_5tap_rgb = 1280, 708c2ecf20Sopenharmony_ci .in_width_max_3tap_rgb = 1280, 718c2ecf20Sopenharmony_ci .in_width_max_5tap_yuv = 2560, 728c2ecf20Sopenharmony_ci .in_width_max_3tap_yuv = 2560, 738c2ecf20Sopenharmony_ci .upscale_limit = 16, 748c2ecf20Sopenharmony_ci .downscale_limit_5tap = 4, 758c2ecf20Sopenharmony_ci .downscale_limit_3tap = 2, 768c2ecf20Sopenharmony_ci /* 778c2ecf20Sopenharmony_ci * The max supported pixel inc value is 255. The value 788c2ecf20Sopenharmony_ci * of pixel inc is calculated like this: 1+(xinc-1)*bpp. 798c2ecf20Sopenharmony_ci * The maximum bpp of all formats supported by the HW 808c2ecf20Sopenharmony_ci * is 8. So the maximum supported xinc value is 32, 818c2ecf20Sopenharmony_ci * because 1+(32-1)*8 < 255 < 1+(33-1)*4. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci .xinc_max = 32, 848c2ecf20Sopenharmony_ci }, 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci .subrev = DISPC_K2G, 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci .common = "common", 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci .common_regs = tidss_k2g_common_regs, 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci .num_vps = 1, 938c2ecf20Sopenharmony_ci .vp_name = { "vp1" }, 948c2ecf20Sopenharmony_ci .ovr_name = { "ovr1" }, 958c2ecf20Sopenharmony_ci .vpclk_name = { "vp1" }, 968c2ecf20Sopenharmony_ci .vp_bus_type = { DISPC_VP_DPI }, 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci .vp_feat = { .color = { 998c2ecf20Sopenharmony_ci .has_ctm = true, 1008c2ecf20Sopenharmony_ci .gamma_size = 256, 1018c2ecf20Sopenharmony_ci .gamma_type = TIDSS_GAMMA_8BIT, 1028c2ecf20Sopenharmony_ci }, 1038c2ecf20Sopenharmony_ci }, 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci .num_planes = 1, 1068c2ecf20Sopenharmony_ci .vid_name = { "vid1" }, 1078c2ecf20Sopenharmony_ci .vid_lite = { false }, 1088c2ecf20Sopenharmony_ci .vid_order = { 0 }, 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const u16 tidss_am65x_common_regs[DISPC_COMMON_REG_TABLE_LEN] = { 1128c2ecf20Sopenharmony_ci [DSS_REVISION_OFF] = 0x4, 1138c2ecf20Sopenharmony_ci [DSS_SYSCONFIG_OFF] = 0x8, 1148c2ecf20Sopenharmony_ci [DSS_SYSSTATUS_OFF] = 0x20, 1158c2ecf20Sopenharmony_ci [DISPC_IRQ_EOI_OFF] = 0x24, 1168c2ecf20Sopenharmony_ci [DISPC_IRQSTATUS_RAW_OFF] = 0x28, 1178c2ecf20Sopenharmony_ci [DISPC_IRQSTATUS_OFF] = 0x2c, 1188c2ecf20Sopenharmony_ci [DISPC_IRQENABLE_SET_OFF] = 0x30, 1198c2ecf20Sopenharmony_ci [DISPC_IRQENABLE_CLR_OFF] = 0x40, 1208c2ecf20Sopenharmony_ci [DISPC_VID_IRQENABLE_OFF] = 0x44, 1218c2ecf20Sopenharmony_ci [DISPC_VID_IRQSTATUS_OFF] = 0x58, 1228c2ecf20Sopenharmony_ci [DISPC_VP_IRQENABLE_OFF] = 0x70, 1238c2ecf20Sopenharmony_ci [DISPC_VP_IRQSTATUS_OFF] = 0x7c, 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci [WB_IRQENABLE_OFF] = 0x88, 1268c2ecf20Sopenharmony_ci [WB_IRQSTATUS_OFF] = 0x8c, 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci [DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] = 0x90, 1298c2ecf20Sopenharmony_ci [DISPC_GLOBAL_OUTPUT_ENABLE_OFF] = 0x94, 1308c2ecf20Sopenharmony_ci [DISPC_GLOBAL_BUFFER_OFF] = 0x98, 1318c2ecf20Sopenharmony_ci [DSS_CBA_CFG_OFF] = 0x9c, 1328c2ecf20Sopenharmony_ci [DISPC_DBG_CONTROL_OFF] = 0xa0, 1338c2ecf20Sopenharmony_ci [DISPC_DBG_STATUS_OFF] = 0xa4, 1348c2ecf20Sopenharmony_ci [DISPC_CLKGATING_DISABLE_OFF] = 0xa8, 1358c2ecf20Sopenharmony_ci [DISPC_SECURE_DISABLE_OFF] = 0xac, 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ciconst struct dispc_features dispc_am65x_feats = { 1398c2ecf20Sopenharmony_ci .max_pclk_khz = { 1408c2ecf20Sopenharmony_ci [DISPC_VP_DPI] = 165000, 1418c2ecf20Sopenharmony_ci [DISPC_VP_OLDI] = 165000, 1428c2ecf20Sopenharmony_ci }, 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci .scaling = { 1458c2ecf20Sopenharmony_ci .in_width_max_5tap_rgb = 1280, 1468c2ecf20Sopenharmony_ci .in_width_max_3tap_rgb = 2560, 1478c2ecf20Sopenharmony_ci .in_width_max_5tap_yuv = 2560, 1488c2ecf20Sopenharmony_ci .in_width_max_3tap_yuv = 4096, 1498c2ecf20Sopenharmony_ci .upscale_limit = 16, 1508c2ecf20Sopenharmony_ci .downscale_limit_5tap = 4, 1518c2ecf20Sopenharmony_ci .downscale_limit_3tap = 2, 1528c2ecf20Sopenharmony_ci /* 1538c2ecf20Sopenharmony_ci * The max supported pixel inc value is 255. The value 1548c2ecf20Sopenharmony_ci * of pixel inc is calculated like this: 1+(xinc-1)*bpp. 1558c2ecf20Sopenharmony_ci * The maximum bpp of all formats supported by the HW 1568c2ecf20Sopenharmony_ci * is 8. So the maximum supported xinc value is 32, 1578c2ecf20Sopenharmony_ci * because 1+(32-1)*8 < 255 < 1+(33-1)*4. 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci .xinc_max = 32, 1608c2ecf20Sopenharmony_ci }, 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci .subrev = DISPC_AM65X, 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci .common = "common", 1658c2ecf20Sopenharmony_ci .common_regs = tidss_am65x_common_regs, 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci .num_vps = 2, 1688c2ecf20Sopenharmony_ci .vp_name = { "vp1", "vp2" }, 1698c2ecf20Sopenharmony_ci .ovr_name = { "ovr1", "ovr2" }, 1708c2ecf20Sopenharmony_ci .vpclk_name = { "vp1", "vp2" }, 1718c2ecf20Sopenharmony_ci .vp_bus_type = { DISPC_VP_OLDI, DISPC_VP_DPI }, 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci .vp_feat = { .color = { 1748c2ecf20Sopenharmony_ci .has_ctm = true, 1758c2ecf20Sopenharmony_ci .gamma_size = 256, 1768c2ecf20Sopenharmony_ci .gamma_type = TIDSS_GAMMA_8BIT, 1778c2ecf20Sopenharmony_ci }, 1788c2ecf20Sopenharmony_ci }, 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci .num_planes = 2, 1818c2ecf20Sopenharmony_ci /* note: vid is plane_id 0 and vidl1 is plane_id 1 */ 1828c2ecf20Sopenharmony_ci .vid_name = { "vid", "vidl1" }, 1838c2ecf20Sopenharmony_ci .vid_lite = { false, true, }, 1848c2ecf20Sopenharmony_ci .vid_order = { 1, 0 }, 1858c2ecf20Sopenharmony_ci}; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic const u16 tidss_j721e_common_regs[DISPC_COMMON_REG_TABLE_LEN] = { 1888c2ecf20Sopenharmony_ci [DSS_REVISION_OFF] = 0x4, 1898c2ecf20Sopenharmony_ci [DSS_SYSCONFIG_OFF] = 0x8, 1908c2ecf20Sopenharmony_ci [DSS_SYSSTATUS_OFF] = 0x20, 1918c2ecf20Sopenharmony_ci [DISPC_IRQ_EOI_OFF] = 0x80, 1928c2ecf20Sopenharmony_ci [DISPC_IRQSTATUS_RAW_OFF] = 0x28, 1938c2ecf20Sopenharmony_ci [DISPC_IRQSTATUS_OFF] = 0x2c, 1948c2ecf20Sopenharmony_ci [DISPC_IRQENABLE_SET_OFF] = 0x30, 1958c2ecf20Sopenharmony_ci [DISPC_IRQENABLE_CLR_OFF] = 0x34, 1968c2ecf20Sopenharmony_ci [DISPC_VID_IRQENABLE_OFF] = 0x38, 1978c2ecf20Sopenharmony_ci [DISPC_VID_IRQSTATUS_OFF] = 0x48, 1988c2ecf20Sopenharmony_ci [DISPC_VP_IRQENABLE_OFF] = 0x58, 1998c2ecf20Sopenharmony_ci [DISPC_VP_IRQSTATUS_OFF] = 0x68, 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci [WB_IRQENABLE_OFF] = 0x78, 2028c2ecf20Sopenharmony_ci [WB_IRQSTATUS_OFF] = 0x7c, 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci [DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] = 0x98, 2058c2ecf20Sopenharmony_ci [DISPC_GLOBAL_OUTPUT_ENABLE_OFF] = 0x9c, 2068c2ecf20Sopenharmony_ci [DISPC_GLOBAL_BUFFER_OFF] = 0xa0, 2078c2ecf20Sopenharmony_ci [DSS_CBA_CFG_OFF] = 0xa4, 2088c2ecf20Sopenharmony_ci [DISPC_DBG_CONTROL_OFF] = 0xa8, 2098c2ecf20Sopenharmony_ci [DISPC_DBG_STATUS_OFF] = 0xac, 2108c2ecf20Sopenharmony_ci [DISPC_CLKGATING_DISABLE_OFF] = 0xb0, 2118c2ecf20Sopenharmony_ci [DISPC_SECURE_DISABLE_OFF] = 0x90, 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci [FBDC_REVISION_1_OFF] = 0xb8, 2148c2ecf20Sopenharmony_ci [FBDC_REVISION_2_OFF] = 0xbc, 2158c2ecf20Sopenharmony_ci [FBDC_REVISION_3_OFF] = 0xc0, 2168c2ecf20Sopenharmony_ci [FBDC_REVISION_4_OFF] = 0xc4, 2178c2ecf20Sopenharmony_ci [FBDC_REVISION_5_OFF] = 0xc8, 2188c2ecf20Sopenharmony_ci [FBDC_REVISION_6_OFF] = 0xcc, 2198c2ecf20Sopenharmony_ci [FBDC_COMMON_CONTROL_OFF] = 0xd0, 2208c2ecf20Sopenharmony_ci [FBDC_CONSTANT_COLOR_0_OFF] = 0xd4, 2218c2ecf20Sopenharmony_ci [FBDC_CONSTANT_COLOR_1_OFF] = 0xd8, 2228c2ecf20Sopenharmony_ci [DISPC_CONNECTIONS_OFF] = 0xe4, 2238c2ecf20Sopenharmony_ci [DISPC_MSS_VP1_OFF] = 0xe8, 2248c2ecf20Sopenharmony_ci [DISPC_MSS_VP3_OFF] = 0xec, 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ciconst struct dispc_features dispc_j721e_feats = { 2288c2ecf20Sopenharmony_ci .max_pclk_khz = { 2298c2ecf20Sopenharmony_ci [DISPC_VP_DPI] = 170000, 2308c2ecf20Sopenharmony_ci [DISPC_VP_INTERNAL] = 600000, 2318c2ecf20Sopenharmony_ci }, 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci .scaling = { 2348c2ecf20Sopenharmony_ci .in_width_max_5tap_rgb = 2048, 2358c2ecf20Sopenharmony_ci .in_width_max_3tap_rgb = 4096, 2368c2ecf20Sopenharmony_ci .in_width_max_5tap_yuv = 4096, 2378c2ecf20Sopenharmony_ci .in_width_max_3tap_yuv = 4096, 2388c2ecf20Sopenharmony_ci .upscale_limit = 16, 2398c2ecf20Sopenharmony_ci .downscale_limit_5tap = 4, 2408c2ecf20Sopenharmony_ci .downscale_limit_3tap = 2, 2418c2ecf20Sopenharmony_ci /* 2428c2ecf20Sopenharmony_ci * The max supported pixel inc value is 255. The value 2438c2ecf20Sopenharmony_ci * of pixel inc is calculated like this: 1+(xinc-1)*bpp. 2448c2ecf20Sopenharmony_ci * The maximum bpp of all formats supported by the HW 2458c2ecf20Sopenharmony_ci * is 8. So the maximum supported xinc value is 32, 2468c2ecf20Sopenharmony_ci * because 1+(32-1)*8 < 255 < 1+(33-1)*4. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci .xinc_max = 32, 2498c2ecf20Sopenharmony_ci }, 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci .subrev = DISPC_J721E, 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci .common = "common_m", 2548c2ecf20Sopenharmony_ci .common_regs = tidss_j721e_common_regs, 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci .num_vps = 4, 2578c2ecf20Sopenharmony_ci .vp_name = { "vp1", "vp2", "vp3", "vp4" }, 2588c2ecf20Sopenharmony_ci .ovr_name = { "ovr1", "ovr2", "ovr3", "ovr4" }, 2598c2ecf20Sopenharmony_ci .vpclk_name = { "vp1", "vp2", "vp3", "vp4" }, 2608c2ecf20Sopenharmony_ci /* Currently hard coded VP routing (see dispc_initial_config()) */ 2618c2ecf20Sopenharmony_ci .vp_bus_type = { DISPC_VP_INTERNAL, DISPC_VP_DPI, 2628c2ecf20Sopenharmony_ci DISPC_VP_INTERNAL, DISPC_VP_DPI, }, 2638c2ecf20Sopenharmony_ci .vp_feat = { .color = { 2648c2ecf20Sopenharmony_ci .has_ctm = true, 2658c2ecf20Sopenharmony_ci .gamma_size = 1024, 2668c2ecf20Sopenharmony_ci .gamma_type = TIDSS_GAMMA_10BIT, 2678c2ecf20Sopenharmony_ci }, 2688c2ecf20Sopenharmony_ci }, 2698c2ecf20Sopenharmony_ci .num_planes = 4, 2708c2ecf20Sopenharmony_ci .vid_name = { "vid1", "vidl1", "vid2", "vidl2" }, 2718c2ecf20Sopenharmony_ci .vid_lite = { 0, 1, 0, 1, }, 2728c2ecf20Sopenharmony_ci .vid_order = { 1, 3, 0, 2 }, 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic const u16 *dispc_common_regmap; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistruct dss_vp_data { 2788c2ecf20Sopenharmony_ci u32 *gamma_table; 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistruct dispc_device { 2828c2ecf20Sopenharmony_ci struct tidss_device *tidss; 2838c2ecf20Sopenharmony_ci struct device *dev; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci void __iomem *base_common; 2868c2ecf20Sopenharmony_ci void __iomem *base_vid[TIDSS_MAX_PLANES]; 2878c2ecf20Sopenharmony_ci void __iomem *base_ovr[TIDSS_MAX_PORTS]; 2888c2ecf20Sopenharmony_ci void __iomem *base_vp[TIDSS_MAX_PORTS]; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci struct regmap *oldi_io_ctrl; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci struct clk *vp_clk[TIDSS_MAX_PORTS]; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci const struct dispc_features *feat; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci struct clk *fclk; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci bool is_enabled; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci struct dss_vp_data vp_data[TIDSS_MAX_PORTS]; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci u32 *fourccs; 3038c2ecf20Sopenharmony_ci u32 num_fourccs; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci u32 memory_bandwidth_limit; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci struct dispc_errata errata; 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic void dispc_write(struct dispc_device *dispc, u16 reg, u32 val) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci iowrite32(val, dispc->base_common + reg); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic u32 dispc_read(struct dispc_device *dispc, u16 reg) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci return ioread32(dispc->base_common + reg); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic 3218c2ecf20Sopenharmony_civoid dispc_vid_write(struct dispc_device *dispc, u32 hw_plane, u16 reg, u32 val) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci void __iomem *base = dispc->base_vid[hw_plane]; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci iowrite32(val, base + reg); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic u32 dispc_vid_read(struct dispc_device *dispc, u32 hw_plane, u16 reg) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci void __iomem *base = dispc->base_vid[hw_plane]; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return ioread32(base + reg); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic void dispc_ovr_write(struct dispc_device *dispc, u32 hw_videoport, 3368c2ecf20Sopenharmony_ci u16 reg, u32 val) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci void __iomem *base = dispc->base_ovr[hw_videoport]; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci iowrite32(val, base + reg); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic u32 dispc_ovr_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci void __iomem *base = dispc->base_ovr[hw_videoport]; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return ioread32(base + reg); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic void dispc_vp_write(struct dispc_device *dispc, u32 hw_videoport, 3518c2ecf20Sopenharmony_ci u16 reg, u32 val) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci void __iomem *base = dispc->base_vp[hw_videoport]; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci iowrite32(val, base + reg); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic u32 dispc_vp_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci void __iomem *base = dispc->base_vp[hw_videoport]; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return ioread32(base + reg); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci/* 3668c2ecf20Sopenharmony_ci * TRM gives bitfields as start:end, where start is the higher bit 3678c2ecf20Sopenharmony_ci * number. For example 7:0 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic u32 FLD_MASK(u32 start, u32 end) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci return ((1 << (start - end + 1)) - 1) << end; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic u32 FLD_VAL(u32 val, u32 start, u32 end) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci return (val << end) & FLD_MASK(start, end); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic u32 FLD_GET(u32 val, u32 start, u32 end) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci return (val & FLD_MASK(start, end)) >> end; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic u32 FLD_MOD(u32 orig, u32 val, u32 start, u32 end) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci return (orig & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic u32 REG_GET(struct dispc_device *dispc, u32 idx, u32 start, u32 end) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci return FLD_GET(dispc_read(dispc, idx), start, end); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic void REG_FLD_MOD(struct dispc_device *dispc, u32 idx, u32 val, 3968c2ecf20Sopenharmony_ci u32 start, u32 end) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci dispc_write(dispc, idx, FLD_MOD(dispc_read(dispc, idx), val, 3998c2ecf20Sopenharmony_ci start, end)); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic u32 VID_REG_GET(struct dispc_device *dispc, u32 hw_plane, u32 idx, 4038c2ecf20Sopenharmony_ci u32 start, u32 end) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci return FLD_GET(dispc_vid_read(dispc, hw_plane, idx), start, end); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic void VID_REG_FLD_MOD(struct dispc_device *dispc, u32 hw_plane, u32 idx, 4098c2ecf20Sopenharmony_ci u32 val, u32 start, u32 end) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, idx, 4128c2ecf20Sopenharmony_ci FLD_MOD(dispc_vid_read(dispc, hw_plane, idx), 4138c2ecf20Sopenharmony_ci val, start, end)); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic u32 VP_REG_GET(struct dispc_device *dispc, u32 vp, u32 idx, 4178c2ecf20Sopenharmony_ci u32 start, u32 end) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci return FLD_GET(dispc_vp_read(dispc, vp, idx), start, end); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic void VP_REG_FLD_MOD(struct dispc_device *dispc, u32 vp, u32 idx, u32 val, 4238c2ecf20Sopenharmony_ci u32 start, u32 end) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci dispc_vp_write(dispc, vp, idx, FLD_MOD(dispc_vp_read(dispc, vp, idx), 4268c2ecf20Sopenharmony_ci val, start, end)); 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci__maybe_unused 4308c2ecf20Sopenharmony_cistatic u32 OVR_REG_GET(struct dispc_device *dispc, u32 ovr, u32 idx, 4318c2ecf20Sopenharmony_ci u32 start, u32 end) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci return FLD_GET(dispc_ovr_read(dispc, ovr, idx), start, end); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic void OVR_REG_FLD_MOD(struct dispc_device *dispc, u32 ovr, u32 idx, 4378c2ecf20Sopenharmony_ci u32 val, u32 start, u32 end) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci dispc_ovr_write(dispc, ovr, idx, 4408c2ecf20Sopenharmony_ci FLD_MOD(dispc_ovr_read(dispc, ovr, idx), 4418c2ecf20Sopenharmony_ci val, start, end)); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_vp_irq_from_raw(u32 stat, u32 hw_videoport) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci dispc_irq_t vp_stat = 0; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (stat & BIT(0)) 4498c2ecf20Sopenharmony_ci vp_stat |= DSS_IRQ_VP_FRAME_DONE(hw_videoport); 4508c2ecf20Sopenharmony_ci if (stat & BIT(1)) 4518c2ecf20Sopenharmony_ci vp_stat |= DSS_IRQ_VP_VSYNC_EVEN(hw_videoport); 4528c2ecf20Sopenharmony_ci if (stat & BIT(2)) 4538c2ecf20Sopenharmony_ci vp_stat |= DSS_IRQ_VP_VSYNC_ODD(hw_videoport); 4548c2ecf20Sopenharmony_ci if (stat & BIT(4)) 4558c2ecf20Sopenharmony_ci vp_stat |= DSS_IRQ_VP_SYNC_LOST(hw_videoport); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return vp_stat; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic u32 dispc_vp_irq_to_raw(dispc_irq_t vpstat, u32 hw_videoport) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci u32 stat = 0; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (vpstat & DSS_IRQ_VP_FRAME_DONE(hw_videoport)) 4658c2ecf20Sopenharmony_ci stat |= BIT(0); 4668c2ecf20Sopenharmony_ci if (vpstat & DSS_IRQ_VP_VSYNC_EVEN(hw_videoport)) 4678c2ecf20Sopenharmony_ci stat |= BIT(1); 4688c2ecf20Sopenharmony_ci if (vpstat & DSS_IRQ_VP_VSYNC_ODD(hw_videoport)) 4698c2ecf20Sopenharmony_ci stat |= BIT(2); 4708c2ecf20Sopenharmony_ci if (vpstat & DSS_IRQ_VP_SYNC_LOST(hw_videoport)) 4718c2ecf20Sopenharmony_ci stat |= BIT(4); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return stat; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_vid_irq_from_raw(u32 stat, u32 hw_plane) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci dispc_irq_t vid_stat = 0; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (stat & BIT(0)) 4818c2ecf20Sopenharmony_ci vid_stat |= DSS_IRQ_PLANE_FIFO_UNDERFLOW(hw_plane); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return vid_stat; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic u32 dispc_vid_irq_to_raw(dispc_irq_t vidstat, u32 hw_plane) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci u32 stat = 0; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (vidstat & DSS_IRQ_PLANE_FIFO_UNDERFLOW(hw_plane)) 4918c2ecf20Sopenharmony_ci stat |= BIT(0); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return stat; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_k2g_vp_read_irqstatus(struct dispc_device *dispc, 4978c2ecf20Sopenharmony_ci u32 hw_videoport) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci u32 stat = dispc_vp_read(dispc, hw_videoport, DISPC_VP_K2G_IRQSTATUS); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return dispc_vp_irq_from_raw(stat, hw_videoport); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic void dispc_k2g_vp_write_irqstatus(struct dispc_device *dispc, 5058c2ecf20Sopenharmony_ci u32 hw_videoport, dispc_irq_t vpstat) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_IRQSTATUS, stat); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_k2g_vid_read_irqstatus(struct dispc_device *dispc, 5138c2ecf20Sopenharmony_ci u32 hw_plane) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci u32 stat = dispc_vid_read(dispc, hw_plane, DISPC_VID_K2G_IRQSTATUS); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return dispc_vid_irq_from_raw(stat, hw_plane); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic void dispc_k2g_vid_write_irqstatus(struct dispc_device *dispc, 5218c2ecf20Sopenharmony_ci u32 hw_plane, dispc_irq_t vidstat) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_IRQSTATUS, stat); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_k2g_vp_read_irqenable(struct dispc_device *dispc, 5298c2ecf20Sopenharmony_ci u32 hw_videoport) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci u32 stat = dispc_vp_read(dispc, hw_videoport, DISPC_VP_K2G_IRQENABLE); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci return dispc_vp_irq_from_raw(stat, hw_videoport); 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic void dispc_k2g_vp_set_irqenable(struct dispc_device *dispc, 5378c2ecf20Sopenharmony_ci u32 hw_videoport, dispc_irq_t vpstat) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_IRQENABLE, stat); 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_k2g_vid_read_irqenable(struct dispc_device *dispc, 5458c2ecf20Sopenharmony_ci u32 hw_plane) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci u32 stat = dispc_vid_read(dispc, hw_plane, DISPC_VID_K2G_IRQENABLE); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return dispc_vid_irq_from_raw(stat, hw_plane); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic void dispc_k2g_vid_set_irqenable(struct dispc_device *dispc, 5538c2ecf20Sopenharmony_ci u32 hw_plane, dispc_irq_t vidstat) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_IRQENABLE, stat); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic void dispc_k2g_clear_irqstatus(struct dispc_device *dispc, 5618c2ecf20Sopenharmony_ci dispc_irq_t mask) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci dispc_k2g_vp_write_irqstatus(dispc, 0, mask); 5648c2ecf20Sopenharmony_ci dispc_k2g_vid_write_irqstatus(dispc, 0, mask); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic 5688c2ecf20Sopenharmony_cidispc_irq_t dispc_k2g_read_and_clear_irqstatus(struct dispc_device *dispc) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci dispc_irq_t stat = 0; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* always clear the top level irqstatus */ 5738c2ecf20Sopenharmony_ci dispc_write(dispc, DISPC_IRQSTATUS, 5748c2ecf20Sopenharmony_ci dispc_read(dispc, DISPC_IRQSTATUS)); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci stat |= dispc_k2g_vp_read_irqstatus(dispc, 0); 5778c2ecf20Sopenharmony_ci stat |= dispc_k2g_vid_read_irqstatus(dispc, 0); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci dispc_k2g_clear_irqstatus(dispc, stat); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci return stat; 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_k2g_read_irqenable(struct dispc_device *dispc) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci dispc_irq_t stat = 0; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci stat |= dispc_k2g_vp_read_irqenable(dispc, 0); 5898c2ecf20Sopenharmony_ci stat |= dispc_k2g_vid_read_irqenable(dispc, 0); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci return stat; 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic 5958c2ecf20Sopenharmony_civoid dispc_k2g_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci dispc_irq_t old_mask = dispc_k2g_read_irqenable(dispc); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* clear the irqstatus for newly enabled irqs */ 6008c2ecf20Sopenharmony_ci dispc_k2g_clear_irqstatus(dispc, (mask ^ old_mask) & mask); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci dispc_k2g_vp_set_irqenable(dispc, 0, mask); 6038c2ecf20Sopenharmony_ci dispc_k2g_vid_set_irqenable(dispc, 0, mask); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci dispc_write(dispc, DISPC_IRQENABLE_SET, (1 << 0) | (1 << 7)); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* flush posted write */ 6088c2ecf20Sopenharmony_ci dispc_k2g_read_irqenable(dispc); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_k3_vp_read_irqstatus(struct dispc_device *dispc, 6128c2ecf20Sopenharmony_ci u32 hw_videoport) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci u32 stat = dispc_read(dispc, DISPC_VP_IRQSTATUS(hw_videoport)); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return dispc_vp_irq_from_raw(stat, hw_videoport); 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic void dispc_k3_vp_write_irqstatus(struct dispc_device *dispc, 6208c2ecf20Sopenharmony_ci u32 hw_videoport, dispc_irq_t vpstat) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci dispc_write(dispc, DISPC_VP_IRQSTATUS(hw_videoport), stat); 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_k3_vid_read_irqstatus(struct dispc_device *dispc, 6288c2ecf20Sopenharmony_ci u32 hw_plane) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci u32 stat = dispc_read(dispc, DISPC_VID_IRQSTATUS(hw_plane)); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return dispc_vid_irq_from_raw(stat, hw_plane); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic void dispc_k3_vid_write_irqstatus(struct dispc_device *dispc, 6368c2ecf20Sopenharmony_ci u32 hw_plane, dispc_irq_t vidstat) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci dispc_write(dispc, DISPC_VID_IRQSTATUS(hw_plane), stat); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_k3_vp_read_irqenable(struct dispc_device *dispc, 6448c2ecf20Sopenharmony_ci u32 hw_videoport) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci u32 stat = dispc_read(dispc, DISPC_VP_IRQENABLE(hw_videoport)); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci return dispc_vp_irq_from_raw(stat, hw_videoport); 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic void dispc_k3_vp_set_irqenable(struct dispc_device *dispc, 6528c2ecf20Sopenharmony_ci u32 hw_videoport, dispc_irq_t vpstat) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci dispc_write(dispc, DISPC_VP_IRQENABLE(hw_videoport), stat); 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_k3_vid_read_irqenable(struct dispc_device *dispc, 6608c2ecf20Sopenharmony_ci u32 hw_plane) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci u32 stat = dispc_read(dispc, DISPC_VID_IRQENABLE(hw_plane)); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci return dispc_vid_irq_from_raw(stat, hw_plane); 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic void dispc_k3_vid_set_irqenable(struct dispc_device *dispc, 6688c2ecf20Sopenharmony_ci u32 hw_plane, dispc_irq_t vidstat) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci dispc_write(dispc, DISPC_VID_IRQENABLE(hw_plane), stat); 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic 6768c2ecf20Sopenharmony_civoid dispc_k3_clear_irqstatus(struct dispc_device *dispc, dispc_irq_t clearmask) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci unsigned int i; 6798c2ecf20Sopenharmony_ci u32 top_clear = 0; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci for (i = 0; i < dispc->feat->num_vps; ++i) { 6828c2ecf20Sopenharmony_ci if (clearmask & DSS_IRQ_VP_MASK(i)) { 6838c2ecf20Sopenharmony_ci dispc_k3_vp_write_irqstatus(dispc, i, clearmask); 6848c2ecf20Sopenharmony_ci top_clear |= BIT(i); 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci for (i = 0; i < dispc->feat->num_planes; ++i) { 6888c2ecf20Sopenharmony_ci if (clearmask & DSS_IRQ_PLANE_MASK(i)) { 6898c2ecf20Sopenharmony_ci dispc_k3_vid_write_irqstatus(dispc, i, clearmask); 6908c2ecf20Sopenharmony_ci top_clear |= BIT(4 + i); 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci if (dispc->feat->subrev == DISPC_K2G) 6948c2ecf20Sopenharmony_ci return; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci dispc_write(dispc, DISPC_IRQSTATUS, top_clear); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* Flush posted writes */ 6998c2ecf20Sopenharmony_ci dispc_read(dispc, DISPC_IRQSTATUS); 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic 7038c2ecf20Sopenharmony_cidispc_irq_t dispc_k3_read_and_clear_irqstatus(struct dispc_device *dispc) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci dispc_irq_t status = 0; 7068c2ecf20Sopenharmony_ci unsigned int i; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci for (i = 0; i < dispc->feat->num_vps; ++i) 7098c2ecf20Sopenharmony_ci status |= dispc_k3_vp_read_irqstatus(dispc, i); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci for (i = 0; i < dispc->feat->num_planes; ++i) 7128c2ecf20Sopenharmony_ci status |= dispc_k3_vid_read_irqstatus(dispc, i); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci dispc_k3_clear_irqstatus(dispc, status); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci return status; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic dispc_irq_t dispc_k3_read_irqenable(struct dispc_device *dispc) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci dispc_irq_t enable = 0; 7228c2ecf20Sopenharmony_ci unsigned int i; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci for (i = 0; i < dispc->feat->num_vps; ++i) 7258c2ecf20Sopenharmony_ci enable |= dispc_k3_vp_read_irqenable(dispc, i); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci for (i = 0; i < dispc->feat->num_planes; ++i) 7288c2ecf20Sopenharmony_ci enable |= dispc_k3_vid_read_irqenable(dispc, i); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci return enable; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic void dispc_k3_set_irqenable(struct dispc_device *dispc, 7348c2ecf20Sopenharmony_ci dispc_irq_t mask) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci unsigned int i; 7378c2ecf20Sopenharmony_ci u32 main_enable = 0, main_disable = 0; 7388c2ecf20Sopenharmony_ci dispc_irq_t old_mask; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci old_mask = dispc_k3_read_irqenable(dispc); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* clear the irqstatus for newly enabled irqs */ 7438c2ecf20Sopenharmony_ci dispc_k3_clear_irqstatus(dispc, (old_mask ^ mask) & mask); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci for (i = 0; i < dispc->feat->num_vps; ++i) { 7468c2ecf20Sopenharmony_ci dispc_k3_vp_set_irqenable(dispc, i, mask); 7478c2ecf20Sopenharmony_ci if (mask & DSS_IRQ_VP_MASK(i)) 7488c2ecf20Sopenharmony_ci main_enable |= BIT(i); /* VP IRQ */ 7498c2ecf20Sopenharmony_ci else 7508c2ecf20Sopenharmony_ci main_disable |= BIT(i); /* VP IRQ */ 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci for (i = 0; i < dispc->feat->num_planes; ++i) { 7548c2ecf20Sopenharmony_ci dispc_k3_vid_set_irqenable(dispc, i, mask); 7558c2ecf20Sopenharmony_ci if (mask & DSS_IRQ_PLANE_MASK(i)) 7568c2ecf20Sopenharmony_ci main_enable |= BIT(i + 4); /* VID IRQ */ 7578c2ecf20Sopenharmony_ci else 7588c2ecf20Sopenharmony_ci main_disable |= BIT(i + 4); /* VID IRQ */ 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (main_enable) 7628c2ecf20Sopenharmony_ci dispc_write(dispc, DISPC_IRQENABLE_SET, main_enable); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (main_disable) 7658c2ecf20Sopenharmony_ci dispc_write(dispc, DISPC_IRQENABLE_CLR, main_disable); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci /* Flush posted writes */ 7688c2ecf20Sopenharmony_ci dispc_read(dispc, DISPC_IRQENABLE_SET); 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cidispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci switch (dispc->feat->subrev) { 7748c2ecf20Sopenharmony_ci case DISPC_K2G: 7758c2ecf20Sopenharmony_ci return dispc_k2g_read_and_clear_irqstatus(dispc); 7768c2ecf20Sopenharmony_ci case DISPC_AM65X: 7778c2ecf20Sopenharmony_ci case DISPC_J721E: 7788c2ecf20Sopenharmony_ci return dispc_k3_read_and_clear_irqstatus(dispc); 7798c2ecf20Sopenharmony_ci default: 7808c2ecf20Sopenharmony_ci WARN_ON(1); 7818c2ecf20Sopenharmony_ci return 0; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_civoid dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci switch (dispc->feat->subrev) { 7888c2ecf20Sopenharmony_ci case DISPC_K2G: 7898c2ecf20Sopenharmony_ci dispc_k2g_set_irqenable(dispc, mask); 7908c2ecf20Sopenharmony_ci break; 7918c2ecf20Sopenharmony_ci case DISPC_AM65X: 7928c2ecf20Sopenharmony_ci case DISPC_J721E: 7938c2ecf20Sopenharmony_ci dispc_k3_set_irqenable(dispc, mask); 7948c2ecf20Sopenharmony_ci break; 7958c2ecf20Sopenharmony_ci default: 7968c2ecf20Sopenharmony_ci WARN_ON(1); 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cienum dispc_oldi_mode_reg_val { SPWG_18 = 0, JEIDA_24 = 1, SPWG_24 = 2 }; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistruct dispc_bus_format { 8048c2ecf20Sopenharmony_ci u32 bus_fmt; 8058c2ecf20Sopenharmony_ci u32 data_width; 8068c2ecf20Sopenharmony_ci bool is_oldi_fmt; 8078c2ecf20Sopenharmony_ci enum dispc_oldi_mode_reg_val oldi_mode_reg_val; 8088c2ecf20Sopenharmony_ci}; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic const struct dispc_bus_format dispc_bus_formats[] = { 8118c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_RGB444_1X12, 12, false, 0 }, 8128c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_RGB565_1X16, 16, false, 0 }, 8138c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_RGB666_1X18, 18, false, 0 }, 8148c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_RGB888_1X24, 24, false, 0 }, 8158c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_RGB101010_1X30, 30, false, 0 }, 8168c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_RGB121212_1X36, 36, false, 0 }, 8178c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 18, true, SPWG_18 }, 8188c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 24, true, SPWG_24 }, 8198c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, true, JEIDA_24 }, 8208c2ecf20Sopenharmony_ci}; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic const 8238c2ecf20Sopenharmony_cistruct dispc_bus_format *dispc_vp_find_bus_fmt(struct dispc_device *dispc, 8248c2ecf20Sopenharmony_ci u32 hw_videoport, 8258c2ecf20Sopenharmony_ci u32 bus_fmt, u32 bus_flags) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci unsigned int i; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dispc_bus_formats); ++i) { 8308c2ecf20Sopenharmony_ci if (dispc_bus_formats[i].bus_fmt == bus_fmt) 8318c2ecf20Sopenharmony_ci return &dispc_bus_formats[i]; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci return NULL; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ciint dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport, 8388c2ecf20Sopenharmony_ci const struct drm_crtc_state *state) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state); 8418c2ecf20Sopenharmony_ci const struct dispc_bus_format *fmt; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format, 8448c2ecf20Sopenharmony_ci tstate->bus_flags); 8458c2ecf20Sopenharmony_ci if (!fmt) { 8468c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "%s: Unsupported bus format: %u\n", 8478c2ecf20Sopenharmony_ci __func__, tstate->bus_format); 8488c2ecf20Sopenharmony_ci return -EINVAL; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI && 8528c2ecf20Sopenharmony_ci fmt->is_oldi_fmt) { 8538c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n", 8548c2ecf20Sopenharmony_ci __func__, dispc->feat->vp_name[hw_videoport]); 8558c2ecf20Sopenharmony_ci return -EINVAL; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci return 0; 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic void dispc_oldi_tx_power(struct dispc_device *dispc, bool power) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci u32 val = power ? 0 : OLDI_PWRDN_TX; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (WARN_ON(!dispc->oldi_io_ctrl)) 8668c2ecf20Sopenharmony_ci return; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT0_IO_CTRL, 8698c2ecf20Sopenharmony_ci OLDI_PWRDN_TX, val); 8708c2ecf20Sopenharmony_ci regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT1_IO_CTRL, 8718c2ecf20Sopenharmony_ci OLDI_PWRDN_TX, val); 8728c2ecf20Sopenharmony_ci regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT2_IO_CTRL, 8738c2ecf20Sopenharmony_ci OLDI_PWRDN_TX, val); 8748c2ecf20Sopenharmony_ci regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT3_IO_CTRL, 8758c2ecf20Sopenharmony_ci OLDI_PWRDN_TX, val); 8768c2ecf20Sopenharmony_ci regmap_update_bits(dispc->oldi_io_ctrl, OLDI_CLK_IO_CTRL, 8778c2ecf20Sopenharmony_ci OLDI_PWRDN_TX, val); 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic void dispc_set_num_datalines(struct dispc_device *dispc, 8818c2ecf20Sopenharmony_ci u32 hw_videoport, int num_lines) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci int v; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci switch (num_lines) { 8868c2ecf20Sopenharmony_ci case 12: 8878c2ecf20Sopenharmony_ci v = 0; break; 8888c2ecf20Sopenharmony_ci case 16: 8898c2ecf20Sopenharmony_ci v = 1; break; 8908c2ecf20Sopenharmony_ci case 18: 8918c2ecf20Sopenharmony_ci v = 2; break; 8928c2ecf20Sopenharmony_ci case 24: 8938c2ecf20Sopenharmony_ci v = 3; break; 8948c2ecf20Sopenharmony_ci case 30: 8958c2ecf20Sopenharmony_ci v = 4; break; 8968c2ecf20Sopenharmony_ci case 36: 8978c2ecf20Sopenharmony_ci v = 5; break; 8988c2ecf20Sopenharmony_ci default: 8998c2ecf20Sopenharmony_ci WARN_ON(1); 9008c2ecf20Sopenharmony_ci v = 3; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, v, 10, 8); 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic void dispc_enable_oldi(struct dispc_device *dispc, u32 hw_videoport, 9078c2ecf20Sopenharmony_ci const struct dispc_bus_format *fmt) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci u32 oldi_cfg = 0; 9108c2ecf20Sopenharmony_ci u32 oldi_reset_bit = BIT(5 + hw_videoport); 9118c2ecf20Sopenharmony_ci int count = 0; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* 9148c2ecf20Sopenharmony_ci * For the moment DUALMODESYNC, MASTERSLAVE, MODE, and SRC 9158c2ecf20Sopenharmony_ci * bits of DISPC_VP_DSS_OLDI_CFG are set statically to 0. 9168c2ecf20Sopenharmony_ci */ 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (fmt->data_width == 24) 9198c2ecf20Sopenharmony_ci oldi_cfg |= BIT(8); /* MSB */ 9208c2ecf20Sopenharmony_ci else if (fmt->data_width != 18) 9218c2ecf20Sopenharmony_ci dev_warn(dispc->dev, "%s: %d port width not supported\n", 9228c2ecf20Sopenharmony_ci __func__, fmt->data_width); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci oldi_cfg |= BIT(7); /* DEPOL */ 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci oldi_cfg = FLD_MOD(oldi_cfg, fmt->oldi_mode_reg_val, 3, 1); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci oldi_cfg |= BIT(12); /* SOFTRST */ 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci oldi_cfg |= BIT(0); /* ENABLE */ 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, oldi_cfg); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci while (!(oldi_reset_bit & dispc_read(dispc, DSS_SYSSTATUS)) && 9358c2ecf20Sopenharmony_ci count < 10000) 9368c2ecf20Sopenharmony_ci count++; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (!(oldi_reset_bit & dispc_read(dispc, DSS_SYSSTATUS))) 9398c2ecf20Sopenharmony_ci dev_warn(dispc->dev, "%s: timeout waiting OLDI reset done\n", 9408c2ecf20Sopenharmony_ci __func__); 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_civoid dispc_vp_prepare(struct dispc_device *dispc, u32 hw_videoport, 9448c2ecf20Sopenharmony_ci const struct drm_crtc_state *state) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state); 9478c2ecf20Sopenharmony_ci const struct dispc_bus_format *fmt; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format, 9508c2ecf20Sopenharmony_ci tstate->bus_flags); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (WARN_ON(!fmt)) 9538c2ecf20Sopenharmony_ci return; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) { 9568c2ecf20Sopenharmony_ci dispc_oldi_tx_power(dispc, true); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci dispc_enable_oldi(dispc, hw_videoport, fmt); 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_civoid dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport, 9638c2ecf20Sopenharmony_ci const struct drm_crtc_state *state) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci const struct drm_display_mode *mode = &state->adjusted_mode; 9668c2ecf20Sopenharmony_ci const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state); 9678c2ecf20Sopenharmony_ci bool align, onoff, rf, ieo, ipc, ihs, ivs; 9688c2ecf20Sopenharmony_ci const struct dispc_bus_format *fmt; 9698c2ecf20Sopenharmony_ci u32 hsw, hfp, hbp, vsw, vfp, vbp; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format, 9728c2ecf20Sopenharmony_ci tstate->bus_flags); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (WARN_ON(!fmt)) 9758c2ecf20Sopenharmony_ci return; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci dispc_set_num_datalines(dispc, hw_videoport, fmt->data_width); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci hfp = mode->hsync_start - mode->hdisplay; 9808c2ecf20Sopenharmony_ci hsw = mode->hsync_end - mode->hsync_start; 9818c2ecf20Sopenharmony_ci hbp = mode->htotal - mode->hsync_end; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci vfp = mode->vsync_start - mode->vdisplay; 9848c2ecf20Sopenharmony_ci vsw = mode->vsync_end - mode->vsync_start; 9858c2ecf20Sopenharmony_ci vbp = mode->vtotal - mode->vsync_end; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, DISPC_VP_TIMING_H, 9888c2ecf20Sopenharmony_ci FLD_VAL(hsw - 1, 7, 0) | 9898c2ecf20Sopenharmony_ci FLD_VAL(hfp - 1, 19, 8) | 9908c2ecf20Sopenharmony_ci FLD_VAL(hbp - 1, 31, 20)); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, DISPC_VP_TIMING_V, 9938c2ecf20Sopenharmony_ci FLD_VAL(vsw - 1, 7, 0) | 9948c2ecf20Sopenharmony_ci FLD_VAL(vfp, 19, 8) | 9958c2ecf20Sopenharmony_ci FLD_VAL(vbp, 31, 20)); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci ivs = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci ihs = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci ieo = !!(tstate->bus_flags & DRM_BUS_FLAG_DE_LOW); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci ipc = !!(tstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* always use the 'rf' setting */ 10068c2ecf20Sopenharmony_ci onoff = true; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci rf = !!(tstate->bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* always use aligned syncs */ 10118c2ecf20Sopenharmony_ci align = true; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci /* always use DE_HIGH for OLDI */ 10148c2ecf20Sopenharmony_ci if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) 10158c2ecf20Sopenharmony_ci ieo = false; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, DISPC_VP_POL_FREQ, 10188c2ecf20Sopenharmony_ci FLD_VAL(align, 18, 18) | 10198c2ecf20Sopenharmony_ci FLD_VAL(onoff, 17, 17) | 10208c2ecf20Sopenharmony_ci FLD_VAL(rf, 16, 16) | 10218c2ecf20Sopenharmony_ci FLD_VAL(ieo, 15, 15) | 10228c2ecf20Sopenharmony_ci FLD_VAL(ipc, 14, 14) | 10238c2ecf20Sopenharmony_ci FLD_VAL(ihs, 13, 13) | 10248c2ecf20Sopenharmony_ci FLD_VAL(ivs, 12, 12)); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, DISPC_VP_SIZE_SCREEN, 10278c2ecf20Sopenharmony_ci FLD_VAL(mode->hdisplay - 1, 11, 0) | 10288c2ecf20Sopenharmony_ci FLD_VAL(mode->vdisplay - 1, 27, 16)); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 1, 0, 0); 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_civoid dispc_vp_disable(struct dispc_device *dispc, u32 hw_videoport) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 0, 0, 0); 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_civoid dispc_vp_unprepare(struct dispc_device *dispc, u32 hw_videoport) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) { 10418c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, 0); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci dispc_oldi_tx_power(dispc, false); 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cibool dispc_vp_go_busy(struct dispc_device *dispc, u32 hw_videoport) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci return VP_REG_GET(dispc, hw_videoport, DISPC_VP_CONTROL, 5, 5); 10508c2ecf20Sopenharmony_ci} 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_civoid dispc_vp_go(struct dispc_device *dispc, u32 hw_videoport) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci WARN_ON(VP_REG_GET(dispc, hw_videoport, DISPC_VP_CONTROL, 5, 5)); 10558c2ecf20Sopenharmony_ci VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 1, 5, 5); 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_cienum c8_to_c12_mode { C8_TO_C12_REPLICATE, C8_TO_C12_MAX, C8_TO_C12_MIN }; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cistatic u16 c8_to_c12(u8 c8, enum c8_to_c12_mode mode) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci u16 c12; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci c12 = c8 << 4; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci switch (mode) { 10678c2ecf20Sopenharmony_ci case C8_TO_C12_REPLICATE: 10688c2ecf20Sopenharmony_ci /* Copy c8 4 MSB to 4 LSB for full scale c12 */ 10698c2ecf20Sopenharmony_ci c12 |= c8 >> 4; 10708c2ecf20Sopenharmony_ci break; 10718c2ecf20Sopenharmony_ci case C8_TO_C12_MAX: 10728c2ecf20Sopenharmony_ci c12 |= 0xF; 10738c2ecf20Sopenharmony_ci break; 10748c2ecf20Sopenharmony_ci default: 10758c2ecf20Sopenharmony_ci case C8_TO_C12_MIN: 10768c2ecf20Sopenharmony_ci break; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci return c12; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic u64 argb8888_to_argb12121212(u32 argb8888, enum c8_to_c12_mode m) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci u8 a, r, g, b; 10858c2ecf20Sopenharmony_ci u64 v; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci a = (argb8888 >> 24) & 0xff; 10888c2ecf20Sopenharmony_ci r = (argb8888 >> 16) & 0xff; 10898c2ecf20Sopenharmony_ci g = (argb8888 >> 8) & 0xff; 10908c2ecf20Sopenharmony_ci b = (argb8888 >> 0) & 0xff; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci v = ((u64)c8_to_c12(a, m) << 36) | ((u64)c8_to_c12(r, m) << 24) | 10938c2ecf20Sopenharmony_ci ((u64)c8_to_c12(g, m) << 12) | (u64)c8_to_c12(b, m); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return v; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic void dispc_vp_set_default_color(struct dispc_device *dispc, 10998c2ecf20Sopenharmony_ci u32 hw_videoport, u32 default_color) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci u64 v; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci v = argb8888_to_argb12121212(default_color, C8_TO_C12_REPLICATE); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci dispc_ovr_write(dispc, hw_videoport, 11068c2ecf20Sopenharmony_ci DISPC_OVR_DEFAULT_COLOR, v & 0xffffffff); 11078c2ecf20Sopenharmony_ci dispc_ovr_write(dispc, hw_videoport, 11088c2ecf20Sopenharmony_ci DISPC_OVR_DEFAULT_COLOR2, (v >> 32) & 0xffff); 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cienum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc, 11128c2ecf20Sopenharmony_ci u32 hw_videoport, 11138c2ecf20Sopenharmony_ci const struct drm_display_mode *mode) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci u32 hsw, hfp, hbp, vsw, vfp, vbp; 11168c2ecf20Sopenharmony_ci enum dispc_vp_bus_type bus_type; 11178c2ecf20Sopenharmony_ci int max_pclk; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci bus_type = dispc->feat->vp_bus_type[hw_videoport]; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci max_pclk = dispc->feat->max_pclk_khz[bus_type]; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (WARN_ON(max_pclk == 0)) 11248c2ecf20Sopenharmony_ci return MODE_BAD; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (mode->clock < dispc->feat->min_pclk_khz) 11278c2ecf20Sopenharmony_ci return MODE_CLOCK_LOW; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci if (mode->clock > max_pclk) 11308c2ecf20Sopenharmony_ci return MODE_CLOCK_HIGH; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (mode->hdisplay > 4096) 11338c2ecf20Sopenharmony_ci return MODE_BAD; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (mode->vdisplay > 4096) 11368c2ecf20Sopenharmony_ci return MODE_BAD; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci /* TODO: add interlace support */ 11398c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 11408c2ecf20Sopenharmony_ci return MODE_NO_INTERLACE; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* 11438c2ecf20Sopenharmony_ci * Enforce the output width is divisible by 2. Actually this 11448c2ecf20Sopenharmony_ci * is only needed in following cases: 11458c2ecf20Sopenharmony_ci * - YUV output selected (BT656, BT1120) 11468c2ecf20Sopenharmony_ci * - Dithering enabled 11478c2ecf20Sopenharmony_ci * - TDM with TDMCycleFormat == 3 11488c2ecf20Sopenharmony_ci * But for simplicity we enforce that always. 11498c2ecf20Sopenharmony_ci */ 11508c2ecf20Sopenharmony_ci if ((mode->hdisplay % 2) != 0) 11518c2ecf20Sopenharmony_ci return MODE_BAD_HVALUE; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci hfp = mode->hsync_start - mode->hdisplay; 11548c2ecf20Sopenharmony_ci hsw = mode->hsync_end - mode->hsync_start; 11558c2ecf20Sopenharmony_ci hbp = mode->htotal - mode->hsync_end; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci vfp = mode->vsync_start - mode->vdisplay; 11588c2ecf20Sopenharmony_ci vsw = mode->vsync_end - mode->vsync_start; 11598c2ecf20Sopenharmony_ci vbp = mode->vtotal - mode->vsync_end; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci if (hsw < 1 || hsw > 256 || 11628c2ecf20Sopenharmony_ci hfp < 1 || hfp > 4096 || 11638c2ecf20Sopenharmony_ci hbp < 1 || hbp > 4096) 11648c2ecf20Sopenharmony_ci return MODE_BAD_HVALUE; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (vsw < 1 || vsw > 256 || 11678c2ecf20Sopenharmony_ci vfp > 4095 || vbp > 4095) 11688c2ecf20Sopenharmony_ci return MODE_BAD_VVALUE; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (dispc->memory_bandwidth_limit) { 11718c2ecf20Sopenharmony_ci const unsigned int bpp = 4; 11728c2ecf20Sopenharmony_ci u64 bandwidth; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci bandwidth = 1000 * mode->clock; 11758c2ecf20Sopenharmony_ci bandwidth = bandwidth * mode->hdisplay * mode->vdisplay * bpp; 11768c2ecf20Sopenharmony_ci bandwidth = div_u64(bandwidth, mode->htotal * mode->vtotal); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (dispc->memory_bandwidth_limit < bandwidth) 11798c2ecf20Sopenharmony_ci return MODE_BAD; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci return MODE_OK; 11838c2ecf20Sopenharmony_ci} 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ciint dispc_vp_enable_clk(struct dispc_device *dispc, u32 hw_videoport) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci int ret = clk_prepare_enable(dispc->vp_clk[hw_videoport]); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci if (ret) 11908c2ecf20Sopenharmony_ci dev_err(dispc->dev, "%s: enabling clk failed: %d\n", __func__, 11918c2ecf20Sopenharmony_ci ret); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci return ret; 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_civoid dispc_vp_disable_clk(struct dispc_device *dispc, u32 hw_videoport) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci clk_disable_unprepare(dispc->vp_clk[hw_videoport]); 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci/* 12028c2ecf20Sopenharmony_ci * Calculate the percentage difference between the requested pixel clock rate 12038c2ecf20Sopenharmony_ci * and the effective rate resulting from calculating the clock divider value. 12048c2ecf20Sopenharmony_ci */ 12058c2ecf20Sopenharmony_cistatic 12068c2ecf20Sopenharmony_ciunsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate) 12078c2ecf20Sopenharmony_ci{ 12088c2ecf20Sopenharmony_ci int r = rate / 100, rr = real_rate / 100; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci return (unsigned int)(abs(((rr - r) * 100) / r)); 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ciint dispc_vp_set_clk_rate(struct dispc_device *dispc, u32 hw_videoport, 12148c2ecf20Sopenharmony_ci unsigned long rate) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci int r; 12178c2ecf20Sopenharmony_ci unsigned long new_rate; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci r = clk_set_rate(dispc->vp_clk[hw_videoport], rate); 12208c2ecf20Sopenharmony_ci if (r) { 12218c2ecf20Sopenharmony_ci dev_err(dispc->dev, "vp%d: failed to set clk rate to %lu\n", 12228c2ecf20Sopenharmony_ci hw_videoport, rate); 12238c2ecf20Sopenharmony_ci return r; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci new_rate = clk_get_rate(dispc->vp_clk[hw_videoport]); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci if (dispc_pclk_diff(rate, new_rate) > 5) 12298c2ecf20Sopenharmony_ci dev_warn(dispc->dev, 12308c2ecf20Sopenharmony_ci "vp%d: Clock rate %lu differs over 5%% from requested %lu\n", 12318c2ecf20Sopenharmony_ci hw_videoport, new_rate, rate); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "vp%d: new rate %lu Hz (requested %lu Hz)\n", 12348c2ecf20Sopenharmony_ci hw_videoport, clk_get_rate(dispc->vp_clk[hw_videoport]), rate); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci return 0; 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci/* OVR */ 12408c2ecf20Sopenharmony_cistatic void dispc_k2g_ovr_set_plane(struct dispc_device *dispc, 12418c2ecf20Sopenharmony_ci u32 hw_plane, u32 hw_videoport, 12428c2ecf20Sopenharmony_ci u32 x, u32 y, u32 layer) 12438c2ecf20Sopenharmony_ci{ 12448c2ecf20Sopenharmony_ci /* On k2g there is only one plane and no need for ovr */ 12458c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_POSITION, 12468c2ecf20Sopenharmony_ci x | (y << 16)); 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_cistatic void dispc_am65x_ovr_set_plane(struct dispc_device *dispc, 12508c2ecf20Sopenharmony_ci u32 hw_plane, u32 hw_videoport, 12518c2ecf20Sopenharmony_ci u32 x, u32 y, u32 layer) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer), 12548c2ecf20Sopenharmony_ci hw_plane, 4, 1); 12558c2ecf20Sopenharmony_ci OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer), 12568c2ecf20Sopenharmony_ci x, 17, 6); 12578c2ecf20Sopenharmony_ci OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer), 12588c2ecf20Sopenharmony_ci y, 30, 19); 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistatic void dispc_j721e_ovr_set_plane(struct dispc_device *dispc, 12628c2ecf20Sopenharmony_ci u32 hw_plane, u32 hw_videoport, 12638c2ecf20Sopenharmony_ci u32 x, u32 y, u32 layer) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer), 12668c2ecf20Sopenharmony_ci hw_plane, 4, 1); 12678c2ecf20Sopenharmony_ci OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(layer), 12688c2ecf20Sopenharmony_ci x, 13, 0); 12698c2ecf20Sopenharmony_ci OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(layer), 12708c2ecf20Sopenharmony_ci y, 29, 16); 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_civoid dispc_ovr_set_plane(struct dispc_device *dispc, u32 hw_plane, 12748c2ecf20Sopenharmony_ci u32 hw_videoport, u32 x, u32 y, u32 layer) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci switch (dispc->feat->subrev) { 12778c2ecf20Sopenharmony_ci case DISPC_K2G: 12788c2ecf20Sopenharmony_ci dispc_k2g_ovr_set_plane(dispc, hw_plane, hw_videoport, 12798c2ecf20Sopenharmony_ci x, y, layer); 12808c2ecf20Sopenharmony_ci break; 12818c2ecf20Sopenharmony_ci case DISPC_AM65X: 12828c2ecf20Sopenharmony_ci dispc_am65x_ovr_set_plane(dispc, hw_plane, hw_videoport, 12838c2ecf20Sopenharmony_ci x, y, layer); 12848c2ecf20Sopenharmony_ci break; 12858c2ecf20Sopenharmony_ci case DISPC_J721E: 12868c2ecf20Sopenharmony_ci dispc_j721e_ovr_set_plane(dispc, hw_plane, hw_videoport, 12878c2ecf20Sopenharmony_ci x, y, layer); 12888c2ecf20Sopenharmony_ci break; 12898c2ecf20Sopenharmony_ci default: 12908c2ecf20Sopenharmony_ci WARN_ON(1); 12918c2ecf20Sopenharmony_ci break; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci} 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_civoid dispc_ovr_enable_layer(struct dispc_device *dispc, 12968c2ecf20Sopenharmony_ci u32 hw_videoport, u32 layer, bool enable) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci if (dispc->feat->subrev == DISPC_K2G) 12998c2ecf20Sopenharmony_ci return; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer), 13028c2ecf20Sopenharmony_ci !!enable, 0, 0); 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci/* CSC */ 13068c2ecf20Sopenharmony_cienum csc_ctm { 13078c2ecf20Sopenharmony_ci CSC_RR, CSC_RG, CSC_RB, 13088c2ecf20Sopenharmony_ci CSC_GR, CSC_GG, CSC_GB, 13098c2ecf20Sopenharmony_ci CSC_BR, CSC_BG, CSC_BB, 13108c2ecf20Sopenharmony_ci}; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cienum csc_yuv2rgb { 13138c2ecf20Sopenharmony_ci CSC_RY, CSC_RCB, CSC_RCR, 13148c2ecf20Sopenharmony_ci CSC_GY, CSC_GCB, CSC_GCR, 13158c2ecf20Sopenharmony_ci CSC_BY, CSC_BCB, CSC_BCR, 13168c2ecf20Sopenharmony_ci}; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cienum csc_rgb2yuv { 13198c2ecf20Sopenharmony_ci CSC_YR, CSC_YG, CSC_YB, 13208c2ecf20Sopenharmony_ci CSC_CBR, CSC_CBG, CSC_CBB, 13218c2ecf20Sopenharmony_ci CSC_CRR, CSC_CRG, CSC_CRB, 13228c2ecf20Sopenharmony_ci}; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cistruct dispc_csc_coef { 13258c2ecf20Sopenharmony_ci void (*to_regval)(const struct dispc_csc_coef *csc, u32 *regval); 13268c2ecf20Sopenharmony_ci int m[9]; 13278c2ecf20Sopenharmony_ci int preoffset[3]; 13288c2ecf20Sopenharmony_ci int postoffset[3]; 13298c2ecf20Sopenharmony_ci enum { CLIP_LIMITED_RANGE = 0, CLIP_FULL_RANGE = 1, } cliping; 13308c2ecf20Sopenharmony_ci const char *name; 13318c2ecf20Sopenharmony_ci}; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci#define DISPC_CSC_REGVAL_LEN 8 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_cistatic 13368c2ecf20Sopenharmony_civoid dispc_csc_offset_regval(const struct dispc_csc_coef *csc, u32 *regval) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci#define OVAL(x, y) (FLD_VAL(x, 15, 3) | FLD_VAL(y, 31, 19)) 13398c2ecf20Sopenharmony_ci regval[5] = OVAL(csc->preoffset[0], csc->preoffset[1]); 13408c2ecf20Sopenharmony_ci regval[6] = OVAL(csc->preoffset[2], csc->postoffset[0]); 13418c2ecf20Sopenharmony_ci regval[7] = OVAL(csc->postoffset[1], csc->postoffset[2]); 13428c2ecf20Sopenharmony_ci#undef OVAL 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci#define CVAL(x, y) (FLD_VAL(x, 10, 0) | FLD_VAL(y, 26, 16)) 13468c2ecf20Sopenharmony_cistatic 13478c2ecf20Sopenharmony_civoid dispc_csc_yuv2rgb_regval(const struct dispc_csc_coef *csc, u32 *regval) 13488c2ecf20Sopenharmony_ci{ 13498c2ecf20Sopenharmony_ci regval[0] = CVAL(csc->m[CSC_RY], csc->m[CSC_RCR]); 13508c2ecf20Sopenharmony_ci regval[1] = CVAL(csc->m[CSC_RCB], csc->m[CSC_GY]); 13518c2ecf20Sopenharmony_ci regval[2] = CVAL(csc->m[CSC_GCR], csc->m[CSC_GCB]); 13528c2ecf20Sopenharmony_ci regval[3] = CVAL(csc->m[CSC_BY], csc->m[CSC_BCR]); 13538c2ecf20Sopenharmony_ci regval[4] = CVAL(csc->m[CSC_BCB], 0); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci dispc_csc_offset_regval(csc, regval); 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci__maybe_unused static 13598c2ecf20Sopenharmony_civoid dispc_csc_rgb2yuv_regval(const struct dispc_csc_coef *csc, u32 *regval) 13608c2ecf20Sopenharmony_ci{ 13618c2ecf20Sopenharmony_ci regval[0] = CVAL(csc->m[CSC_YR], csc->m[CSC_YG]); 13628c2ecf20Sopenharmony_ci regval[1] = CVAL(csc->m[CSC_YB], csc->m[CSC_CRR]); 13638c2ecf20Sopenharmony_ci regval[2] = CVAL(csc->m[CSC_CRG], csc->m[CSC_CRB]); 13648c2ecf20Sopenharmony_ci regval[3] = CVAL(csc->m[CSC_CBR], csc->m[CSC_CBG]); 13658c2ecf20Sopenharmony_ci regval[4] = CVAL(csc->m[CSC_CBB], 0); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci dispc_csc_offset_regval(csc, regval); 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic void dispc_csc_cpr_regval(const struct dispc_csc_coef *csc, 13718c2ecf20Sopenharmony_ci u32 *regval) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci regval[0] = CVAL(csc->m[CSC_RR], csc->m[CSC_RG]); 13748c2ecf20Sopenharmony_ci regval[1] = CVAL(csc->m[CSC_RB], csc->m[CSC_GR]); 13758c2ecf20Sopenharmony_ci regval[2] = CVAL(csc->m[CSC_GG], csc->m[CSC_GB]); 13768c2ecf20Sopenharmony_ci regval[3] = CVAL(csc->m[CSC_BR], csc->m[CSC_BG]); 13778c2ecf20Sopenharmony_ci regval[4] = CVAL(csc->m[CSC_BB], 0); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci dispc_csc_offset_regval(csc, regval); 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci#undef CVAL 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic void dispc_k2g_vid_write_csc(struct dispc_device *dispc, u32 hw_plane, 13858c2ecf20Sopenharmony_ci const struct dispc_csc_coef *csc) 13868c2ecf20Sopenharmony_ci{ 13878c2ecf20Sopenharmony_ci static const u16 dispc_vid_csc_coef_reg[] = { 13888c2ecf20Sopenharmony_ci DISPC_VID_CSC_COEF(0), DISPC_VID_CSC_COEF(1), 13898c2ecf20Sopenharmony_ci DISPC_VID_CSC_COEF(2), DISPC_VID_CSC_COEF(3), 13908c2ecf20Sopenharmony_ci DISPC_VID_CSC_COEF(4), DISPC_VID_CSC_COEF(5), 13918c2ecf20Sopenharmony_ci DISPC_VID_CSC_COEF(6), /* K2G has no post offset support */ 13928c2ecf20Sopenharmony_ci }; 13938c2ecf20Sopenharmony_ci u32 regval[DISPC_CSC_REGVAL_LEN]; 13948c2ecf20Sopenharmony_ci unsigned int i; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci csc->to_regval(csc, regval); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (regval[7] != 0) 13998c2ecf20Sopenharmony_ci dev_warn(dispc->dev, "%s: No post offset support for %s\n", 14008c2ecf20Sopenharmony_ci __func__, csc->name); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dispc_vid_csc_coef_reg); i++) 14038c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, dispc_vid_csc_coef_reg[i], 14048c2ecf20Sopenharmony_ci regval[i]); 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_cistatic void dispc_k3_vid_write_csc(struct dispc_device *dispc, u32 hw_plane, 14088c2ecf20Sopenharmony_ci const struct dispc_csc_coef *csc) 14098c2ecf20Sopenharmony_ci{ 14108c2ecf20Sopenharmony_ci static const u16 dispc_vid_csc_coef_reg[DISPC_CSC_REGVAL_LEN] = { 14118c2ecf20Sopenharmony_ci DISPC_VID_CSC_COEF(0), DISPC_VID_CSC_COEF(1), 14128c2ecf20Sopenharmony_ci DISPC_VID_CSC_COEF(2), DISPC_VID_CSC_COEF(3), 14138c2ecf20Sopenharmony_ci DISPC_VID_CSC_COEF(4), DISPC_VID_CSC_COEF(5), 14148c2ecf20Sopenharmony_ci DISPC_VID_CSC_COEF(6), DISPC_VID_CSC_COEF7, 14158c2ecf20Sopenharmony_ci }; 14168c2ecf20Sopenharmony_ci u32 regval[DISPC_CSC_REGVAL_LEN]; 14178c2ecf20Sopenharmony_ci unsigned int i; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci csc->to_regval(csc, regval); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dispc_vid_csc_coef_reg); i++) 14228c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, dispc_vid_csc_coef_reg[i], 14238c2ecf20Sopenharmony_ci regval[i]); 14248c2ecf20Sopenharmony_ci} 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci/* YUV -> RGB, ITU-R BT.601, full range */ 14278c2ecf20Sopenharmony_cistatic const struct dispc_csc_coef csc_yuv2rgb_bt601_full = { 14288c2ecf20Sopenharmony_ci dispc_csc_yuv2rgb_regval, 14298c2ecf20Sopenharmony_ci { 256, 0, 358, /* ry, rcb, rcr |1.000 0.000 1.402|*/ 14308c2ecf20Sopenharmony_ci 256, -88, -182, /* gy, gcb, gcr |1.000 -0.344 -0.714|*/ 14318c2ecf20Sopenharmony_ci 256, 452, 0, }, /* by, bcb, bcr |1.000 1.772 0.000|*/ 14328c2ecf20Sopenharmony_ci { 0, -2048, -2048, }, /* full range */ 14338c2ecf20Sopenharmony_ci { 0, 0, 0, }, 14348c2ecf20Sopenharmony_ci CLIP_FULL_RANGE, 14358c2ecf20Sopenharmony_ci "BT.601 Full", 14368c2ecf20Sopenharmony_ci}; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci/* YUV -> RGB, ITU-R BT.601, limited range */ 14398c2ecf20Sopenharmony_cistatic const struct dispc_csc_coef csc_yuv2rgb_bt601_lim = { 14408c2ecf20Sopenharmony_ci dispc_csc_yuv2rgb_regval, 14418c2ecf20Sopenharmony_ci { 298, 0, 409, /* ry, rcb, rcr |1.164 0.000 1.596|*/ 14428c2ecf20Sopenharmony_ci 298, -100, -208, /* gy, gcb, gcr |1.164 -0.392 -0.813|*/ 14438c2ecf20Sopenharmony_ci 298, 516, 0, }, /* by, bcb, bcr |1.164 2.017 0.000|*/ 14448c2ecf20Sopenharmony_ci { -256, -2048, -2048, }, /* limited range */ 14458c2ecf20Sopenharmony_ci { 0, 0, 0, }, 14468c2ecf20Sopenharmony_ci CLIP_FULL_RANGE, 14478c2ecf20Sopenharmony_ci "BT.601 Limited", 14488c2ecf20Sopenharmony_ci}; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci/* YUV -> RGB, ITU-R BT.709, full range */ 14518c2ecf20Sopenharmony_cistatic const struct dispc_csc_coef csc_yuv2rgb_bt709_full = { 14528c2ecf20Sopenharmony_ci dispc_csc_yuv2rgb_regval, 14538c2ecf20Sopenharmony_ci { 256, 0, 402, /* ry, rcb, rcr |1.000 0.000 1.570|*/ 14548c2ecf20Sopenharmony_ci 256, -48, -120, /* gy, gcb, gcr |1.000 -0.187 -0.467|*/ 14558c2ecf20Sopenharmony_ci 256, 475, 0, }, /* by, bcb, bcr |1.000 1.856 0.000|*/ 14568c2ecf20Sopenharmony_ci { 0, -2048, -2048, }, /* full range */ 14578c2ecf20Sopenharmony_ci { 0, 0, 0, }, 14588c2ecf20Sopenharmony_ci CLIP_FULL_RANGE, 14598c2ecf20Sopenharmony_ci "BT.709 Full", 14608c2ecf20Sopenharmony_ci}; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci/* YUV -> RGB, ITU-R BT.709, limited range */ 14638c2ecf20Sopenharmony_cistatic const struct dispc_csc_coef csc_yuv2rgb_bt709_lim = { 14648c2ecf20Sopenharmony_ci dispc_csc_yuv2rgb_regval, 14658c2ecf20Sopenharmony_ci { 298, 0, 459, /* ry, rcb, rcr |1.164 0.000 1.793|*/ 14668c2ecf20Sopenharmony_ci 298, -55, -136, /* gy, gcb, gcr |1.164 -0.213 -0.533|*/ 14678c2ecf20Sopenharmony_ci 298, 541, 0, }, /* by, bcb, bcr |1.164 2.112 0.000|*/ 14688c2ecf20Sopenharmony_ci { -256, -2048, -2048, }, /* limited range */ 14698c2ecf20Sopenharmony_ci { 0, 0, 0, }, 14708c2ecf20Sopenharmony_ci CLIP_FULL_RANGE, 14718c2ecf20Sopenharmony_ci "BT.709 Limited", 14728c2ecf20Sopenharmony_ci}; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_cistatic const struct { 14758c2ecf20Sopenharmony_ci enum drm_color_encoding encoding; 14768c2ecf20Sopenharmony_ci enum drm_color_range range; 14778c2ecf20Sopenharmony_ci const struct dispc_csc_coef *csc; 14788c2ecf20Sopenharmony_ci} dispc_csc_table[] = { 14798c2ecf20Sopenharmony_ci { DRM_COLOR_YCBCR_BT601, DRM_COLOR_YCBCR_FULL_RANGE, 14808c2ecf20Sopenharmony_ci &csc_yuv2rgb_bt601_full, }, 14818c2ecf20Sopenharmony_ci { DRM_COLOR_YCBCR_BT601, DRM_COLOR_YCBCR_LIMITED_RANGE, 14828c2ecf20Sopenharmony_ci &csc_yuv2rgb_bt601_lim, }, 14838c2ecf20Sopenharmony_ci { DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_FULL_RANGE, 14848c2ecf20Sopenharmony_ci &csc_yuv2rgb_bt709_full, }, 14858c2ecf20Sopenharmony_ci { DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE, 14868c2ecf20Sopenharmony_ci &csc_yuv2rgb_bt709_lim, }, 14878c2ecf20Sopenharmony_ci}; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_cistatic const 14908c2ecf20Sopenharmony_cistruct dispc_csc_coef *dispc_find_csc(enum drm_color_encoding encoding, 14918c2ecf20Sopenharmony_ci enum drm_color_range range) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci unsigned int i; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dispc_csc_table); i++) { 14968c2ecf20Sopenharmony_ci if (dispc_csc_table[i].encoding == encoding && 14978c2ecf20Sopenharmony_ci dispc_csc_table[i].range == range) { 14988c2ecf20Sopenharmony_ci return dispc_csc_table[i].csc; 14998c2ecf20Sopenharmony_ci } 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci return NULL; 15028c2ecf20Sopenharmony_ci} 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_cistatic void dispc_vid_csc_setup(struct dispc_device *dispc, u32 hw_plane, 15058c2ecf20Sopenharmony_ci const struct drm_plane_state *state) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci const struct dispc_csc_coef *coef; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci coef = dispc_find_csc(state->color_encoding, state->color_range); 15108c2ecf20Sopenharmony_ci if (!coef) { 15118c2ecf20Sopenharmony_ci dev_err(dispc->dev, "%s: CSC (%u,%u) not found\n", 15128c2ecf20Sopenharmony_ci __func__, state->color_encoding, state->color_range); 15138c2ecf20Sopenharmony_ci return; 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (dispc->feat->subrev == DISPC_K2G) 15178c2ecf20Sopenharmony_ci dispc_k2g_vid_write_csc(dispc, hw_plane, coef); 15188c2ecf20Sopenharmony_ci else 15198c2ecf20Sopenharmony_ci dispc_k3_vid_write_csc(dispc, hw_plane, coef); 15208c2ecf20Sopenharmony_ci} 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_cistatic void dispc_vid_csc_enable(struct dispc_device *dispc, u32 hw_plane, 15238c2ecf20Sopenharmony_ci bool enable) 15248c2ecf20Sopenharmony_ci{ 15258c2ecf20Sopenharmony_ci VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, !!enable, 9, 9); 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci/* SCALER */ 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_cistatic u32 dispc_calc_fir_inc(u32 in, u32 out) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci return (u32)div_u64(0x200000ull * in, out); 15338c2ecf20Sopenharmony_ci} 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_cienum dispc_vid_fir_coef_set { 15368c2ecf20Sopenharmony_ci DISPC_VID_FIR_COEF_HORIZ, 15378c2ecf20Sopenharmony_ci DISPC_VID_FIR_COEF_HORIZ_UV, 15388c2ecf20Sopenharmony_ci DISPC_VID_FIR_COEF_VERT, 15398c2ecf20Sopenharmony_ci DISPC_VID_FIR_COEF_VERT_UV, 15408c2ecf20Sopenharmony_ci}; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_cistatic void dispc_vid_write_fir_coefs(struct dispc_device *dispc, 15438c2ecf20Sopenharmony_ci u32 hw_plane, 15448c2ecf20Sopenharmony_ci enum dispc_vid_fir_coef_set coef_set, 15458c2ecf20Sopenharmony_ci const struct tidss_scale_coefs *coefs) 15468c2ecf20Sopenharmony_ci{ 15478c2ecf20Sopenharmony_ci static const u16 c0_regs[] = { 15488c2ecf20Sopenharmony_ci [DISPC_VID_FIR_COEF_HORIZ] = DISPC_VID_FIR_COEFS_H0, 15498c2ecf20Sopenharmony_ci [DISPC_VID_FIR_COEF_HORIZ_UV] = DISPC_VID_FIR_COEFS_H0_C, 15508c2ecf20Sopenharmony_ci [DISPC_VID_FIR_COEF_VERT] = DISPC_VID_FIR_COEFS_V0, 15518c2ecf20Sopenharmony_ci [DISPC_VID_FIR_COEF_VERT_UV] = DISPC_VID_FIR_COEFS_V0_C, 15528c2ecf20Sopenharmony_ci }; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci static const u16 c12_regs[] = { 15558c2ecf20Sopenharmony_ci [DISPC_VID_FIR_COEF_HORIZ] = DISPC_VID_FIR_COEFS_H12, 15568c2ecf20Sopenharmony_ci [DISPC_VID_FIR_COEF_HORIZ_UV] = DISPC_VID_FIR_COEFS_H12_C, 15578c2ecf20Sopenharmony_ci [DISPC_VID_FIR_COEF_VERT] = DISPC_VID_FIR_COEFS_V12, 15588c2ecf20Sopenharmony_ci [DISPC_VID_FIR_COEF_VERT_UV] = DISPC_VID_FIR_COEFS_V12_C, 15598c2ecf20Sopenharmony_ci }; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci const u16 c0_base = c0_regs[coef_set]; 15628c2ecf20Sopenharmony_ci const u16 c12_base = c12_regs[coef_set]; 15638c2ecf20Sopenharmony_ci int phase; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci if (!coefs) { 15668c2ecf20Sopenharmony_ci dev_err(dispc->dev, "%s: No coefficients given.\n", __func__); 15678c2ecf20Sopenharmony_ci return; 15688c2ecf20Sopenharmony_ci } 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci for (phase = 0; phase <= 8; ++phase) { 15718c2ecf20Sopenharmony_ci u16 reg = c0_base + phase * 4; 15728c2ecf20Sopenharmony_ci u16 c0 = coefs->c0[phase]; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, reg, c0); 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci for (phase = 0; phase <= 15; ++phase) { 15788c2ecf20Sopenharmony_ci u16 reg = c12_base + phase * 4; 15798c2ecf20Sopenharmony_ci s16 c1, c2; 15808c2ecf20Sopenharmony_ci u32 c12; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci c1 = coefs->c1[phase]; 15838c2ecf20Sopenharmony_ci c2 = coefs->c2[phase]; 15848c2ecf20Sopenharmony_ci c12 = FLD_VAL(c1, 19, 10) | FLD_VAL(c2, 29, 20); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, reg, c12); 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci} 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_cistatic bool dispc_fourcc_is_yuv(u32 fourcc) 15918c2ecf20Sopenharmony_ci{ 15928c2ecf20Sopenharmony_ci switch (fourcc) { 15938c2ecf20Sopenharmony_ci case DRM_FORMAT_YUYV: 15948c2ecf20Sopenharmony_ci case DRM_FORMAT_UYVY: 15958c2ecf20Sopenharmony_ci case DRM_FORMAT_NV12: 15968c2ecf20Sopenharmony_ci return true; 15978c2ecf20Sopenharmony_ci default: 15988c2ecf20Sopenharmony_ci return false; 15998c2ecf20Sopenharmony_ci } 16008c2ecf20Sopenharmony_ci} 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_cistruct dispc_scaling_params { 16038c2ecf20Sopenharmony_ci int xinc, yinc; 16048c2ecf20Sopenharmony_ci u32 in_w, in_h, in_w_uv, in_h_uv; 16058c2ecf20Sopenharmony_ci u32 fir_xinc, fir_yinc, fir_xinc_uv, fir_yinc_uv; 16068c2ecf20Sopenharmony_ci bool scale_x, scale_y; 16078c2ecf20Sopenharmony_ci const struct tidss_scale_coefs *xcoef, *ycoef, *xcoef_uv, *ycoef_uv; 16088c2ecf20Sopenharmony_ci bool five_taps; 16098c2ecf20Sopenharmony_ci}; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_cistatic int dispc_vid_calc_scaling(struct dispc_device *dispc, 16128c2ecf20Sopenharmony_ci const struct drm_plane_state *state, 16138c2ecf20Sopenharmony_ci struct dispc_scaling_params *sp, 16148c2ecf20Sopenharmony_ci bool lite_plane) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci const struct dispc_features_scaling *f = &dispc->feat->scaling; 16178c2ecf20Sopenharmony_ci u32 fourcc = state->fb->format->format; 16188c2ecf20Sopenharmony_ci u32 in_width_max_5tap = f->in_width_max_5tap_rgb; 16198c2ecf20Sopenharmony_ci u32 in_width_max_3tap = f->in_width_max_3tap_rgb; 16208c2ecf20Sopenharmony_ci u32 downscale_limit; 16218c2ecf20Sopenharmony_ci u32 in_width_max; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci memset(sp, 0, sizeof(*sp)); 16248c2ecf20Sopenharmony_ci sp->xinc = 1; 16258c2ecf20Sopenharmony_ci sp->yinc = 1; 16268c2ecf20Sopenharmony_ci sp->in_w = state->src_w >> 16; 16278c2ecf20Sopenharmony_ci sp->in_w_uv = sp->in_w; 16288c2ecf20Sopenharmony_ci sp->in_h = state->src_h >> 16; 16298c2ecf20Sopenharmony_ci sp->in_h_uv = sp->in_h; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci sp->scale_x = sp->in_w != state->crtc_w; 16328c2ecf20Sopenharmony_ci sp->scale_y = sp->in_h != state->crtc_h; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci if (dispc_fourcc_is_yuv(fourcc)) { 16358c2ecf20Sopenharmony_ci in_width_max_5tap = f->in_width_max_5tap_yuv; 16368c2ecf20Sopenharmony_ci in_width_max_3tap = f->in_width_max_3tap_yuv; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci sp->in_w_uv >>= 1; 16398c2ecf20Sopenharmony_ci sp->scale_x = true; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if (fourcc == DRM_FORMAT_NV12) { 16428c2ecf20Sopenharmony_ci sp->in_h_uv >>= 1; 16438c2ecf20Sopenharmony_ci sp->scale_y = true; 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci /* Skip the rest if no scaling is used */ 16488c2ecf20Sopenharmony_ci if ((!sp->scale_x && !sp->scale_y) || lite_plane) 16498c2ecf20Sopenharmony_ci return 0; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci if (sp->in_w > in_width_max_5tap) { 16528c2ecf20Sopenharmony_ci sp->five_taps = false; 16538c2ecf20Sopenharmony_ci in_width_max = in_width_max_3tap; 16548c2ecf20Sopenharmony_ci downscale_limit = f->downscale_limit_3tap; 16558c2ecf20Sopenharmony_ci } else { 16568c2ecf20Sopenharmony_ci sp->five_taps = true; 16578c2ecf20Sopenharmony_ci in_width_max = in_width_max_5tap; 16588c2ecf20Sopenharmony_ci downscale_limit = f->downscale_limit_5tap; 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (sp->scale_x) { 16628c2ecf20Sopenharmony_ci sp->fir_xinc = dispc_calc_fir_inc(sp->in_w, state->crtc_w); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci if (sp->fir_xinc < dispc_calc_fir_inc(1, f->upscale_limit)) { 16658c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, 16668c2ecf20Sopenharmony_ci "%s: X-scaling factor %u/%u > %u\n", 16678c2ecf20Sopenharmony_ci __func__, state->crtc_w, state->src_w >> 16, 16688c2ecf20Sopenharmony_ci f->upscale_limit); 16698c2ecf20Sopenharmony_ci return -EINVAL; 16708c2ecf20Sopenharmony_ci } 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if (sp->fir_xinc >= dispc_calc_fir_inc(downscale_limit, 1)) { 16738c2ecf20Sopenharmony_ci sp->xinc = DIV_ROUND_UP(DIV_ROUND_UP(sp->in_w, 16748c2ecf20Sopenharmony_ci state->crtc_w), 16758c2ecf20Sopenharmony_ci downscale_limit); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (sp->xinc > f->xinc_max) { 16788c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, 16798c2ecf20Sopenharmony_ci "%s: X-scaling factor %u/%u < 1/%u\n", 16808c2ecf20Sopenharmony_ci __func__, state->crtc_w, 16818c2ecf20Sopenharmony_ci state->src_w >> 16, 16828c2ecf20Sopenharmony_ci downscale_limit * f->xinc_max); 16838c2ecf20Sopenharmony_ci return -EINVAL; 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci sp->in_w = (state->src_w >> 16) / sp->xinc; 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci while (sp->in_w > in_width_max) { 16908c2ecf20Sopenharmony_ci sp->xinc++; 16918c2ecf20Sopenharmony_ci sp->in_w = (state->src_w >> 16) / sp->xinc; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci if (sp->xinc > f->xinc_max) { 16958c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, 16968c2ecf20Sopenharmony_ci "%s: Too wide input buffer %u > %u\n", __func__, 16978c2ecf20Sopenharmony_ci state->src_w >> 16, in_width_max * f->xinc_max); 16988c2ecf20Sopenharmony_ci return -EINVAL; 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci /* 17028c2ecf20Sopenharmony_ci * We need even line length for YUV formats. Decimation 17038c2ecf20Sopenharmony_ci * can lead to odd length, so we need to make it even 17048c2ecf20Sopenharmony_ci * again. 17058c2ecf20Sopenharmony_ci */ 17068c2ecf20Sopenharmony_ci if (dispc_fourcc_is_yuv(fourcc)) 17078c2ecf20Sopenharmony_ci sp->in_w &= ~1; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci sp->fir_xinc = dispc_calc_fir_inc(sp->in_w, state->crtc_w); 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (sp->scale_y) { 17138c2ecf20Sopenharmony_ci sp->fir_yinc = dispc_calc_fir_inc(sp->in_h, state->crtc_h); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if (sp->fir_yinc < dispc_calc_fir_inc(1, f->upscale_limit)) { 17168c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, 17178c2ecf20Sopenharmony_ci "%s: Y-scaling factor %u/%u > %u\n", 17188c2ecf20Sopenharmony_ci __func__, state->crtc_h, state->src_h >> 16, 17198c2ecf20Sopenharmony_ci f->upscale_limit); 17208c2ecf20Sopenharmony_ci return -EINVAL; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci if (sp->fir_yinc >= dispc_calc_fir_inc(downscale_limit, 1)) { 17248c2ecf20Sopenharmony_ci sp->yinc = DIV_ROUND_UP(DIV_ROUND_UP(sp->in_h, 17258c2ecf20Sopenharmony_ci state->crtc_h), 17268c2ecf20Sopenharmony_ci downscale_limit); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci sp->in_h /= sp->yinc; 17298c2ecf20Sopenharmony_ci sp->fir_yinc = dispc_calc_fir_inc(sp->in_h, 17308c2ecf20Sopenharmony_ci state->crtc_h); 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, 17358c2ecf20Sopenharmony_ci "%s: %ux%u decim %ux%u -> %ux%u firinc %u.%03ux%u.%03u taps %u -> %ux%u\n", 17368c2ecf20Sopenharmony_ci __func__, state->src_w >> 16, state->src_h >> 16, 17378c2ecf20Sopenharmony_ci sp->xinc, sp->yinc, sp->in_w, sp->in_h, 17388c2ecf20Sopenharmony_ci sp->fir_xinc / 0x200000u, 17398c2ecf20Sopenharmony_ci ((sp->fir_xinc & 0x1FFFFFu) * 999u) / 0x1FFFFFu, 17408c2ecf20Sopenharmony_ci sp->fir_yinc / 0x200000u, 17418c2ecf20Sopenharmony_ci ((sp->fir_yinc & 0x1FFFFFu) * 999u) / 0x1FFFFFu, 17428c2ecf20Sopenharmony_ci sp->five_taps ? 5 : 3, 17438c2ecf20Sopenharmony_ci state->crtc_w, state->crtc_h); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci if (dispc_fourcc_is_yuv(fourcc)) { 17468c2ecf20Sopenharmony_ci if (sp->scale_x) { 17478c2ecf20Sopenharmony_ci sp->in_w_uv /= sp->xinc; 17488c2ecf20Sopenharmony_ci sp->fir_xinc_uv = dispc_calc_fir_inc(sp->in_w_uv, 17498c2ecf20Sopenharmony_ci state->crtc_w); 17508c2ecf20Sopenharmony_ci sp->xcoef_uv = tidss_get_scale_coefs(dispc->dev, 17518c2ecf20Sopenharmony_ci sp->fir_xinc_uv, 17528c2ecf20Sopenharmony_ci true); 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci if (sp->scale_y) { 17558c2ecf20Sopenharmony_ci sp->in_h_uv /= sp->yinc; 17568c2ecf20Sopenharmony_ci sp->fir_yinc_uv = dispc_calc_fir_inc(sp->in_h_uv, 17578c2ecf20Sopenharmony_ci state->crtc_h); 17588c2ecf20Sopenharmony_ci sp->ycoef_uv = tidss_get_scale_coefs(dispc->dev, 17598c2ecf20Sopenharmony_ci sp->fir_yinc_uv, 17608c2ecf20Sopenharmony_ci sp->five_taps); 17618c2ecf20Sopenharmony_ci } 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci if (sp->scale_x) 17658c2ecf20Sopenharmony_ci sp->xcoef = tidss_get_scale_coefs(dispc->dev, sp->fir_xinc, 17668c2ecf20Sopenharmony_ci true); 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci if (sp->scale_y) 17698c2ecf20Sopenharmony_ci sp->ycoef = tidss_get_scale_coefs(dispc->dev, sp->fir_yinc, 17708c2ecf20Sopenharmony_ci sp->five_taps); 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci return 0; 17738c2ecf20Sopenharmony_ci} 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_cistatic void dispc_vid_set_scaling(struct dispc_device *dispc, 17768c2ecf20Sopenharmony_ci u32 hw_plane, 17778c2ecf20Sopenharmony_ci struct dispc_scaling_params *sp, 17788c2ecf20Sopenharmony_ci u32 fourcc) 17798c2ecf20Sopenharmony_ci{ 17808c2ecf20Sopenharmony_ci /* HORIZONTAL RESIZE ENABLE */ 17818c2ecf20Sopenharmony_ci VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 17828c2ecf20Sopenharmony_ci sp->scale_x, 7, 7); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci /* VERTICAL RESIZE ENABLE */ 17858c2ecf20Sopenharmony_ci VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 17868c2ecf20Sopenharmony_ci sp->scale_y, 8, 8); 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci /* Skip the rest if no scaling is used */ 17898c2ecf20Sopenharmony_ci if (!sp->scale_x && !sp->scale_y) 17908c2ecf20Sopenharmony_ci return; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci /* VERTICAL 5-TAPS */ 17938c2ecf20Sopenharmony_ci VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 17948c2ecf20Sopenharmony_ci sp->five_taps, 21, 21); 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (dispc_fourcc_is_yuv(fourcc)) { 17978c2ecf20Sopenharmony_ci if (sp->scale_x) { 17988c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRH2, 17998c2ecf20Sopenharmony_ci sp->fir_xinc_uv); 18008c2ecf20Sopenharmony_ci dispc_vid_write_fir_coefs(dispc, hw_plane, 18018c2ecf20Sopenharmony_ci DISPC_VID_FIR_COEF_HORIZ_UV, 18028c2ecf20Sopenharmony_ci sp->xcoef_uv); 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci if (sp->scale_y) { 18058c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRV2, 18068c2ecf20Sopenharmony_ci sp->fir_yinc_uv); 18078c2ecf20Sopenharmony_ci dispc_vid_write_fir_coefs(dispc, hw_plane, 18088c2ecf20Sopenharmony_ci DISPC_VID_FIR_COEF_VERT_UV, 18098c2ecf20Sopenharmony_ci sp->ycoef_uv); 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci if (sp->scale_x) { 18148c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRH, sp->fir_xinc); 18158c2ecf20Sopenharmony_ci dispc_vid_write_fir_coefs(dispc, hw_plane, 18168c2ecf20Sopenharmony_ci DISPC_VID_FIR_COEF_HORIZ, 18178c2ecf20Sopenharmony_ci sp->xcoef); 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci if (sp->scale_y) { 18218c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRV, sp->fir_yinc); 18228c2ecf20Sopenharmony_ci dispc_vid_write_fir_coefs(dispc, hw_plane, 18238c2ecf20Sopenharmony_ci DISPC_VID_FIR_COEF_VERT, sp->ycoef); 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci} 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci/* OTHER */ 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_cistatic const struct { 18308c2ecf20Sopenharmony_ci u32 fourcc; 18318c2ecf20Sopenharmony_ci u8 dss_code; 18328c2ecf20Sopenharmony_ci} dispc_color_formats[] = { 18338c2ecf20Sopenharmony_ci { DRM_FORMAT_ARGB4444, 0x0, }, 18348c2ecf20Sopenharmony_ci { DRM_FORMAT_ABGR4444, 0x1, }, 18358c2ecf20Sopenharmony_ci { DRM_FORMAT_RGBA4444, 0x2, }, 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci { DRM_FORMAT_RGB565, 0x3, }, 18388c2ecf20Sopenharmony_ci { DRM_FORMAT_BGR565, 0x4, }, 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci { DRM_FORMAT_ARGB1555, 0x5, }, 18418c2ecf20Sopenharmony_ci { DRM_FORMAT_ABGR1555, 0x6, }, 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci { DRM_FORMAT_ARGB8888, 0x7, }, 18448c2ecf20Sopenharmony_ci { DRM_FORMAT_ABGR8888, 0x8, }, 18458c2ecf20Sopenharmony_ci { DRM_FORMAT_RGBA8888, 0x9, }, 18468c2ecf20Sopenharmony_ci { DRM_FORMAT_BGRA8888, 0xa, }, 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci { DRM_FORMAT_RGB888, 0xb, }, 18498c2ecf20Sopenharmony_ci { DRM_FORMAT_BGR888, 0xc, }, 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci { DRM_FORMAT_ARGB2101010, 0xe, }, 18528c2ecf20Sopenharmony_ci { DRM_FORMAT_ABGR2101010, 0xf, }, 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci { DRM_FORMAT_XRGB4444, 0x20, }, 18558c2ecf20Sopenharmony_ci { DRM_FORMAT_XBGR4444, 0x21, }, 18568c2ecf20Sopenharmony_ci { DRM_FORMAT_RGBX4444, 0x22, }, 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci { DRM_FORMAT_XRGB1555, 0x25, }, 18598c2ecf20Sopenharmony_ci { DRM_FORMAT_XBGR1555, 0x26, }, 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci { DRM_FORMAT_XRGB8888, 0x27, }, 18628c2ecf20Sopenharmony_ci { DRM_FORMAT_XBGR8888, 0x28, }, 18638c2ecf20Sopenharmony_ci { DRM_FORMAT_RGBX8888, 0x29, }, 18648c2ecf20Sopenharmony_ci { DRM_FORMAT_BGRX8888, 0x2a, }, 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci { DRM_FORMAT_XRGB2101010, 0x2e, }, 18678c2ecf20Sopenharmony_ci { DRM_FORMAT_XBGR2101010, 0x2f, }, 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci { DRM_FORMAT_YUYV, 0x3e, }, 18708c2ecf20Sopenharmony_ci { DRM_FORMAT_UYVY, 0x3f, }, 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci { DRM_FORMAT_NV12, 0x3d, }, 18738c2ecf20Sopenharmony_ci}; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_cistatic void dispc_plane_set_pixel_format(struct dispc_device *dispc, 18768c2ecf20Sopenharmony_ci u32 hw_plane, u32 fourcc) 18778c2ecf20Sopenharmony_ci{ 18788c2ecf20Sopenharmony_ci unsigned int i; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) { 18818c2ecf20Sopenharmony_ci if (dispc_color_formats[i].fourcc == fourcc) { 18828c2ecf20Sopenharmony_ci VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 18838c2ecf20Sopenharmony_ci dispc_color_formats[i].dss_code, 18848c2ecf20Sopenharmony_ci 6, 1); 18858c2ecf20Sopenharmony_ci return; 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci } 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci WARN_ON(1); 18908c2ecf20Sopenharmony_ci} 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ciconst u32 *dispc_plane_formats(struct dispc_device *dispc, unsigned int *len) 18938c2ecf20Sopenharmony_ci{ 18948c2ecf20Sopenharmony_ci WARN_ON(!dispc->fourccs); 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci *len = dispc->num_fourccs; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci return dispc->fourccs; 18998c2ecf20Sopenharmony_ci} 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_cistatic s32 pixinc(int pixels, u8 ps) 19028c2ecf20Sopenharmony_ci{ 19038c2ecf20Sopenharmony_ci if (pixels == 1) 19048c2ecf20Sopenharmony_ci return 1; 19058c2ecf20Sopenharmony_ci else if (pixels > 1) 19068c2ecf20Sopenharmony_ci return 1 + (pixels - 1) * ps; 19078c2ecf20Sopenharmony_ci else if (pixels < 0) 19088c2ecf20Sopenharmony_ci return 1 - (-pixels + 1) * ps; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci WARN_ON(1); 19118c2ecf20Sopenharmony_ci return 0; 19128c2ecf20Sopenharmony_ci} 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ciint dispc_plane_check(struct dispc_device *dispc, u32 hw_plane, 19158c2ecf20Sopenharmony_ci const struct drm_plane_state *state, 19168c2ecf20Sopenharmony_ci u32 hw_videoport) 19178c2ecf20Sopenharmony_ci{ 19188c2ecf20Sopenharmony_ci bool lite = dispc->feat->vid_lite[hw_plane]; 19198c2ecf20Sopenharmony_ci u32 fourcc = state->fb->format->format; 19208c2ecf20Sopenharmony_ci bool need_scaling = state->src_w >> 16 != state->crtc_w || 19218c2ecf20Sopenharmony_ci state->src_h >> 16 != state->crtc_h; 19228c2ecf20Sopenharmony_ci struct dispc_scaling_params scaling; 19238c2ecf20Sopenharmony_ci int ret; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci if (dispc_fourcc_is_yuv(fourcc)) { 19268c2ecf20Sopenharmony_ci if (!dispc_find_csc(state->color_encoding, 19278c2ecf20Sopenharmony_ci state->color_range)) { 19288c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, 19298c2ecf20Sopenharmony_ci "%s: Unsupported CSC (%u,%u) for HW plane %u\n", 19308c2ecf20Sopenharmony_ci __func__, state->color_encoding, 19318c2ecf20Sopenharmony_ci state->color_range, hw_plane); 19328c2ecf20Sopenharmony_ci return -EINVAL; 19338c2ecf20Sopenharmony_ci } 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci if (need_scaling) { 19378c2ecf20Sopenharmony_ci if (lite) { 19388c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, 19398c2ecf20Sopenharmony_ci "%s: Lite plane %u can't scale %ux%u!=%ux%u\n", 19408c2ecf20Sopenharmony_ci __func__, hw_plane, 19418c2ecf20Sopenharmony_ci state->src_w >> 16, state->src_h >> 16, 19428c2ecf20Sopenharmony_ci state->crtc_w, state->crtc_h); 19438c2ecf20Sopenharmony_ci return -EINVAL; 19448c2ecf20Sopenharmony_ci } 19458c2ecf20Sopenharmony_ci ret = dispc_vid_calc_scaling(dispc, state, &scaling, false); 19468c2ecf20Sopenharmony_ci if (ret) 19478c2ecf20Sopenharmony_ci return ret; 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci return 0; 19518c2ecf20Sopenharmony_ci} 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_cistatic 19548c2ecf20Sopenharmony_cidma_addr_t dispc_plane_state_paddr(const struct drm_plane_state *state) 19558c2ecf20Sopenharmony_ci{ 19568c2ecf20Sopenharmony_ci struct drm_framebuffer *fb = state->fb; 19578c2ecf20Sopenharmony_ci struct drm_gem_cma_object *gem; 19588c2ecf20Sopenharmony_ci u32 x = state->src_x >> 16; 19598c2ecf20Sopenharmony_ci u32 y = state->src_y >> 16; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci gem = drm_fb_cma_get_gem_obj(state->fb, 0); 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci return gem->paddr + fb->offsets[0] + x * fb->format->cpp[0] + 19648c2ecf20Sopenharmony_ci y * fb->pitches[0]; 19658c2ecf20Sopenharmony_ci} 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_cistatic 19688c2ecf20Sopenharmony_cidma_addr_t dispc_plane_state_p_uv_addr(const struct drm_plane_state *state) 19698c2ecf20Sopenharmony_ci{ 19708c2ecf20Sopenharmony_ci struct drm_framebuffer *fb = state->fb; 19718c2ecf20Sopenharmony_ci struct drm_gem_cma_object *gem; 19728c2ecf20Sopenharmony_ci u32 x = state->src_x >> 16; 19738c2ecf20Sopenharmony_ci u32 y = state->src_y >> 16; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci if (WARN_ON(state->fb->format->num_planes != 2)) 19768c2ecf20Sopenharmony_ci return 0; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci gem = drm_fb_cma_get_gem_obj(fb, 1); 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci return gem->paddr + fb->offsets[1] + 19818c2ecf20Sopenharmony_ci (x * fb->format->cpp[1] / fb->format->hsub) + 19828c2ecf20Sopenharmony_ci (y * fb->pitches[1] / fb->format->vsub); 19838c2ecf20Sopenharmony_ci} 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ciint dispc_plane_setup(struct dispc_device *dispc, u32 hw_plane, 19868c2ecf20Sopenharmony_ci const struct drm_plane_state *state, 19878c2ecf20Sopenharmony_ci u32 hw_videoport) 19888c2ecf20Sopenharmony_ci{ 19898c2ecf20Sopenharmony_ci bool lite = dispc->feat->vid_lite[hw_plane]; 19908c2ecf20Sopenharmony_ci u32 fourcc = state->fb->format->format; 19918c2ecf20Sopenharmony_ci u16 cpp = state->fb->format->cpp[0]; 19928c2ecf20Sopenharmony_ci u32 fb_width = state->fb->pitches[0] / cpp; 19938c2ecf20Sopenharmony_ci dma_addr_t paddr = dispc_plane_state_paddr(state); 19948c2ecf20Sopenharmony_ci struct dispc_scaling_params scale; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci dispc_vid_calc_scaling(dispc, state, &scale, lite); 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci dispc_plane_set_pixel_format(dispc, hw_plane, fourcc); 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_0, paddr & 0xffffffff); 20018c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_0, (u64)paddr >> 32); 20028c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_1, paddr & 0xffffffff); 20038c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_1, (u64)paddr >> 32); 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_PICTURE_SIZE, 20068c2ecf20Sopenharmony_ci (scale.in_w - 1) | ((scale.in_h - 1) << 16)); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci /* For YUV422 format we use the macropixel size for pixel inc */ 20098c2ecf20Sopenharmony_ci if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY) 20108c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_PIXEL_INC, 20118c2ecf20Sopenharmony_ci pixinc(scale.xinc, cpp * 2)); 20128c2ecf20Sopenharmony_ci else 20138c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_PIXEL_INC, 20148c2ecf20Sopenharmony_ci pixinc(scale.xinc, cpp)); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_ROW_INC, 20178c2ecf20Sopenharmony_ci pixinc(1 + (scale.yinc * fb_width - 20188c2ecf20Sopenharmony_ci scale.xinc * scale.in_w), 20198c2ecf20Sopenharmony_ci cpp)); 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci if (state->fb->format->num_planes == 2) { 20228c2ecf20Sopenharmony_ci u16 cpp_uv = state->fb->format->cpp[1]; 20238c2ecf20Sopenharmony_ci u32 fb_width_uv = state->fb->pitches[1] / cpp_uv; 20248c2ecf20Sopenharmony_ci dma_addr_t p_uv_addr = dispc_plane_state_p_uv_addr(state); 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, 20278c2ecf20Sopenharmony_ci DISPC_VID_BA_UV_0, p_uv_addr & 0xffffffff); 20288c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, 20298c2ecf20Sopenharmony_ci DISPC_VID_BA_UV_EXT_0, (u64)p_uv_addr >> 32); 20308c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, 20318c2ecf20Sopenharmony_ci DISPC_VID_BA_UV_1, p_uv_addr & 0xffffffff); 20328c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, 20338c2ecf20Sopenharmony_ci DISPC_VID_BA_UV_EXT_1, (u64)p_uv_addr >> 32); 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_ROW_INC_UV, 20368c2ecf20Sopenharmony_ci pixinc(1 + (scale.yinc * fb_width_uv - 20378c2ecf20Sopenharmony_ci scale.xinc * scale.in_w_uv), 20388c2ecf20Sopenharmony_ci cpp_uv)); 20398c2ecf20Sopenharmony_ci } 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci if (!lite) { 20428c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_SIZE, 20438c2ecf20Sopenharmony_ci (state->crtc_w - 1) | 20448c2ecf20Sopenharmony_ci ((state->crtc_h - 1) << 16)); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci dispc_vid_set_scaling(dispc, hw_plane, &scale, fourcc); 20478c2ecf20Sopenharmony_ci } 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci /* enable YUV->RGB color conversion */ 20508c2ecf20Sopenharmony_ci if (dispc_fourcc_is_yuv(fourcc)) { 20518c2ecf20Sopenharmony_ci dispc_vid_csc_setup(dispc, hw_plane, state); 20528c2ecf20Sopenharmony_ci dispc_vid_csc_enable(dispc, hw_plane, true); 20538c2ecf20Sopenharmony_ci } else { 20548c2ecf20Sopenharmony_ci dispc_vid_csc_enable(dispc, hw_plane, false); 20558c2ecf20Sopenharmony_ci } 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_GLOBAL_ALPHA, 20588c2ecf20Sopenharmony_ci 0xFF & (state->alpha >> 8)); 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci if (state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) 20618c2ecf20Sopenharmony_ci VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1, 20628c2ecf20Sopenharmony_ci 28, 28); 20638c2ecf20Sopenharmony_ci else 20648c2ecf20Sopenharmony_ci VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 0, 20658c2ecf20Sopenharmony_ci 28, 28); 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci return 0; 20688c2ecf20Sopenharmony_ci} 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ciint dispc_plane_enable(struct dispc_device *dispc, u32 hw_plane, bool enable) 20718c2ecf20Sopenharmony_ci{ 20728c2ecf20Sopenharmony_ci VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, !!enable, 0, 0); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci return 0; 20758c2ecf20Sopenharmony_ci} 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_cistatic u32 dispc_vid_get_fifo_size(struct dispc_device *dispc, u32 hw_plane) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci return VID_REG_GET(dispc, hw_plane, DISPC_VID_BUF_SIZE_STATUS, 15, 0); 20808c2ecf20Sopenharmony_ci} 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_cistatic void dispc_vid_set_mflag_threshold(struct dispc_device *dispc, 20838c2ecf20Sopenharmony_ci u32 hw_plane, u32 low, u32 high) 20848c2ecf20Sopenharmony_ci{ 20858c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_MFLAG_THRESHOLD, 20868c2ecf20Sopenharmony_ci FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0)); 20878c2ecf20Sopenharmony_ci} 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_cistatic void dispc_vid_set_buf_threshold(struct dispc_device *dispc, 20908c2ecf20Sopenharmony_ci u32 hw_plane, u32 low, u32 high) 20918c2ecf20Sopenharmony_ci{ 20928c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_BUF_THRESHOLD, 20938c2ecf20Sopenharmony_ci FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0)); 20948c2ecf20Sopenharmony_ci} 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_cistatic void dispc_k2g_plane_init(struct dispc_device *dispc) 20978c2ecf20Sopenharmony_ci{ 20988c2ecf20Sopenharmony_ci unsigned int hw_plane; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "%s()\n", __func__); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci /* MFLAG_CTRL = ENABLED */ 21038c2ecf20Sopenharmony_ci REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 2, 1, 0); 21048c2ecf20Sopenharmony_ci /* MFLAG_START = MFLAGNORMALSTARTMODE */ 21058c2ecf20Sopenharmony_ci REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 0, 6, 6); 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci for (hw_plane = 0; hw_plane < dispc->feat->num_planes; hw_plane++) { 21088c2ecf20Sopenharmony_ci u32 size = dispc_vid_get_fifo_size(dispc, hw_plane); 21098c2ecf20Sopenharmony_ci u32 thr_low, thr_high; 21108c2ecf20Sopenharmony_ci u32 mflag_low, mflag_high; 21118c2ecf20Sopenharmony_ci u32 preload; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci thr_high = size - 1; 21148c2ecf20Sopenharmony_ci thr_low = size / 2; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci mflag_high = size * 2 / 3; 21178c2ecf20Sopenharmony_ci mflag_low = size / 3; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci preload = thr_low; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, 21228c2ecf20Sopenharmony_ci "%s: bufsize %u, buf_threshold %u/%u, mflag threshold %u/%u preload %u\n", 21238c2ecf20Sopenharmony_ci dispc->feat->vid_name[hw_plane], 21248c2ecf20Sopenharmony_ci size, 21258c2ecf20Sopenharmony_ci thr_high, thr_low, 21268c2ecf20Sopenharmony_ci mflag_high, mflag_low, 21278c2ecf20Sopenharmony_ci preload); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci dispc_vid_set_buf_threshold(dispc, hw_plane, 21308c2ecf20Sopenharmony_ci thr_low, thr_high); 21318c2ecf20Sopenharmony_ci dispc_vid_set_mflag_threshold(dispc, hw_plane, 21328c2ecf20Sopenharmony_ci mflag_low, mflag_high); 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_PRELOAD, preload); 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci /* 21378c2ecf20Sopenharmony_ci * Prefetch up to fifo high-threshold value to minimize the 21388c2ecf20Sopenharmony_ci * possibility of underflows. Note that this means the PRELOAD 21398c2ecf20Sopenharmony_ci * register is ignored. 21408c2ecf20Sopenharmony_ci */ 21418c2ecf20Sopenharmony_ci VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1, 21428c2ecf20Sopenharmony_ci 19, 19); 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci} 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_cistatic void dispc_k3_plane_init(struct dispc_device *dispc) 21478c2ecf20Sopenharmony_ci{ 21488c2ecf20Sopenharmony_ci unsigned int hw_plane; 21498c2ecf20Sopenharmony_ci u32 cba_lo_pri = 1; 21508c2ecf20Sopenharmony_ci u32 cba_hi_pri = 0; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "%s()\n", __func__); 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci REG_FLD_MOD(dispc, DSS_CBA_CFG, cba_lo_pri, 2, 0); 21558c2ecf20Sopenharmony_ci REG_FLD_MOD(dispc, DSS_CBA_CFG, cba_hi_pri, 5, 3); 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci /* MFLAG_CTRL = ENABLED */ 21588c2ecf20Sopenharmony_ci REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 2, 1, 0); 21598c2ecf20Sopenharmony_ci /* MFLAG_START = MFLAGNORMALSTARTMODE */ 21608c2ecf20Sopenharmony_ci REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 0, 6, 6); 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci for (hw_plane = 0; hw_plane < dispc->feat->num_planes; hw_plane++) { 21638c2ecf20Sopenharmony_ci u32 size = dispc_vid_get_fifo_size(dispc, hw_plane); 21648c2ecf20Sopenharmony_ci u32 thr_low, thr_high; 21658c2ecf20Sopenharmony_ci u32 mflag_low, mflag_high; 21668c2ecf20Sopenharmony_ci u32 preload; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci thr_high = size - 1; 21698c2ecf20Sopenharmony_ci thr_low = size / 2; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci mflag_high = size * 2 / 3; 21728c2ecf20Sopenharmony_ci mflag_low = size / 3; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci preload = thr_low; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, 21778c2ecf20Sopenharmony_ci "%s: bufsize %u, buf_threshold %u/%u, mflag threshold %u/%u preload %u\n", 21788c2ecf20Sopenharmony_ci dispc->feat->vid_name[hw_plane], 21798c2ecf20Sopenharmony_ci size, 21808c2ecf20Sopenharmony_ci thr_high, thr_low, 21818c2ecf20Sopenharmony_ci mflag_high, mflag_low, 21828c2ecf20Sopenharmony_ci preload); 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci dispc_vid_set_buf_threshold(dispc, hw_plane, 21858c2ecf20Sopenharmony_ci thr_low, thr_high); 21868c2ecf20Sopenharmony_ci dispc_vid_set_mflag_threshold(dispc, hw_plane, 21878c2ecf20Sopenharmony_ci mflag_low, mflag_high); 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci dispc_vid_write(dispc, hw_plane, DISPC_VID_PRELOAD, preload); 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci /* Prefech up to PRELOAD value */ 21928c2ecf20Sopenharmony_ci VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 0, 21938c2ecf20Sopenharmony_ci 19, 19); 21948c2ecf20Sopenharmony_ci } 21958c2ecf20Sopenharmony_ci} 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_cistatic void dispc_plane_init(struct dispc_device *dispc) 21988c2ecf20Sopenharmony_ci{ 21998c2ecf20Sopenharmony_ci switch (dispc->feat->subrev) { 22008c2ecf20Sopenharmony_ci case DISPC_K2G: 22018c2ecf20Sopenharmony_ci dispc_k2g_plane_init(dispc); 22028c2ecf20Sopenharmony_ci break; 22038c2ecf20Sopenharmony_ci case DISPC_AM65X: 22048c2ecf20Sopenharmony_ci case DISPC_J721E: 22058c2ecf20Sopenharmony_ci dispc_k3_plane_init(dispc); 22068c2ecf20Sopenharmony_ci break; 22078c2ecf20Sopenharmony_ci default: 22088c2ecf20Sopenharmony_ci WARN_ON(1); 22098c2ecf20Sopenharmony_ci } 22108c2ecf20Sopenharmony_ci} 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_cistatic void dispc_vp_init(struct dispc_device *dispc) 22138c2ecf20Sopenharmony_ci{ 22148c2ecf20Sopenharmony_ci unsigned int i; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "%s()\n", __func__); 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci /* Enable the gamma Shadow bit-field for all VPs*/ 22198c2ecf20Sopenharmony_ci for (i = 0; i < dispc->feat->num_vps; i++) 22208c2ecf20Sopenharmony_ci VP_REG_FLD_MOD(dispc, i, DISPC_VP_CONFIG, 1, 2, 2); 22218c2ecf20Sopenharmony_ci} 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_cistatic void dispc_initial_config(struct dispc_device *dispc) 22248c2ecf20Sopenharmony_ci{ 22258c2ecf20Sopenharmony_ci dispc_plane_init(dispc); 22268c2ecf20Sopenharmony_ci dispc_vp_init(dispc); 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci /* Note: Hardcoded DPI routing on J721E for now */ 22298c2ecf20Sopenharmony_ci if (dispc->feat->subrev == DISPC_J721E) { 22308c2ecf20Sopenharmony_ci dispc_write(dispc, DISPC_CONNECTIONS, 22318c2ecf20Sopenharmony_ci FLD_VAL(2, 3, 0) | /* VP1 to DPI0 */ 22328c2ecf20Sopenharmony_ci FLD_VAL(8, 7, 4) /* VP3 to DPI1 */ 22338c2ecf20Sopenharmony_ci ); 22348c2ecf20Sopenharmony_ci } 22358c2ecf20Sopenharmony_ci} 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_cistatic void dispc_k2g_vp_write_gamma_table(struct dispc_device *dispc, 22388c2ecf20Sopenharmony_ci u32 hw_videoport) 22398c2ecf20Sopenharmony_ci{ 22408c2ecf20Sopenharmony_ci u32 *table = dispc->vp_data[hw_videoport].gamma_table; 22418c2ecf20Sopenharmony_ci u32 hwlen = dispc->feat->vp_feat.color.gamma_size; 22428c2ecf20Sopenharmony_ci unsigned int i; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport); 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_8BIT)) 22478c2ecf20Sopenharmony_ci return; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci for (i = 0; i < hwlen; ++i) { 22508c2ecf20Sopenharmony_ci u32 v = table[i]; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci v |= i << 24; 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_GAMMA_TABLE, 22558c2ecf20Sopenharmony_ci v); 22568c2ecf20Sopenharmony_ci } 22578c2ecf20Sopenharmony_ci} 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_cistatic void dispc_am65x_vp_write_gamma_table(struct dispc_device *dispc, 22608c2ecf20Sopenharmony_ci u32 hw_videoport) 22618c2ecf20Sopenharmony_ci{ 22628c2ecf20Sopenharmony_ci u32 *table = dispc->vp_data[hw_videoport].gamma_table; 22638c2ecf20Sopenharmony_ci u32 hwlen = dispc->feat->vp_feat.color.gamma_size; 22648c2ecf20Sopenharmony_ci unsigned int i; 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport); 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_8BIT)) 22698c2ecf20Sopenharmony_ci return; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci for (i = 0; i < hwlen; ++i) { 22728c2ecf20Sopenharmony_ci u32 v = table[i]; 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci v |= i << 24; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, DISPC_VP_GAMMA_TABLE, v); 22778c2ecf20Sopenharmony_ci } 22788c2ecf20Sopenharmony_ci} 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_cistatic void dispc_j721e_vp_write_gamma_table(struct dispc_device *dispc, 22818c2ecf20Sopenharmony_ci u32 hw_videoport) 22828c2ecf20Sopenharmony_ci{ 22838c2ecf20Sopenharmony_ci u32 *table = dispc->vp_data[hw_videoport].gamma_table; 22848c2ecf20Sopenharmony_ci u32 hwlen = dispc->feat->vp_feat.color.gamma_size; 22858c2ecf20Sopenharmony_ci unsigned int i; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport); 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_10BIT)) 22908c2ecf20Sopenharmony_ci return; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci for (i = 0; i < hwlen; ++i) { 22938c2ecf20Sopenharmony_ci u32 v = table[i]; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci if (i == 0) 22968c2ecf20Sopenharmony_ci v |= 1 << 31; 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, DISPC_VP_GAMMA_TABLE, v); 22998c2ecf20Sopenharmony_ci } 23008c2ecf20Sopenharmony_ci} 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_cistatic void dispc_vp_write_gamma_table(struct dispc_device *dispc, 23038c2ecf20Sopenharmony_ci u32 hw_videoport) 23048c2ecf20Sopenharmony_ci{ 23058c2ecf20Sopenharmony_ci switch (dispc->feat->subrev) { 23068c2ecf20Sopenharmony_ci case DISPC_K2G: 23078c2ecf20Sopenharmony_ci dispc_k2g_vp_write_gamma_table(dispc, hw_videoport); 23088c2ecf20Sopenharmony_ci break; 23098c2ecf20Sopenharmony_ci case DISPC_AM65X: 23108c2ecf20Sopenharmony_ci dispc_am65x_vp_write_gamma_table(dispc, hw_videoport); 23118c2ecf20Sopenharmony_ci break; 23128c2ecf20Sopenharmony_ci case DISPC_J721E: 23138c2ecf20Sopenharmony_ci dispc_j721e_vp_write_gamma_table(dispc, hw_videoport); 23148c2ecf20Sopenharmony_ci break; 23158c2ecf20Sopenharmony_ci default: 23168c2ecf20Sopenharmony_ci WARN_ON(1); 23178c2ecf20Sopenharmony_ci break; 23188c2ecf20Sopenharmony_ci } 23198c2ecf20Sopenharmony_ci} 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_cistatic const struct drm_color_lut dispc_vp_gamma_default_lut[] = { 23228c2ecf20Sopenharmony_ci { .red = 0, .green = 0, .blue = 0, }, 23238c2ecf20Sopenharmony_ci { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, }, 23248c2ecf20Sopenharmony_ci}; 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_cistatic void dispc_vp_set_gamma(struct dispc_device *dispc, 23278c2ecf20Sopenharmony_ci u32 hw_videoport, 23288c2ecf20Sopenharmony_ci const struct drm_color_lut *lut, 23298c2ecf20Sopenharmony_ci unsigned int length) 23308c2ecf20Sopenharmony_ci{ 23318c2ecf20Sopenharmony_ci u32 *table = dispc->vp_data[hw_videoport].gamma_table; 23328c2ecf20Sopenharmony_ci u32 hwlen = dispc->feat->vp_feat.color.gamma_size; 23338c2ecf20Sopenharmony_ci u32 hwbits; 23348c2ecf20Sopenharmony_ci unsigned int i; 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "%s: hw_videoport %d, lut len %u, hw len %u\n", 23378c2ecf20Sopenharmony_ci __func__, hw_videoport, length, hwlen); 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci if (dispc->feat->vp_feat.color.gamma_type == TIDSS_GAMMA_10BIT) 23408c2ecf20Sopenharmony_ci hwbits = 10; 23418c2ecf20Sopenharmony_ci else 23428c2ecf20Sopenharmony_ci hwbits = 8; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci if (!lut || length < 2) { 23458c2ecf20Sopenharmony_ci lut = dispc_vp_gamma_default_lut; 23468c2ecf20Sopenharmony_ci length = ARRAY_SIZE(dispc_vp_gamma_default_lut); 23478c2ecf20Sopenharmony_ci } 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci for (i = 0; i < length - 1; ++i) { 23508c2ecf20Sopenharmony_ci unsigned int first = i * (hwlen - 1) / (length - 1); 23518c2ecf20Sopenharmony_ci unsigned int last = (i + 1) * (hwlen - 1) / (length - 1); 23528c2ecf20Sopenharmony_ci unsigned int w = last - first; 23538c2ecf20Sopenharmony_ci u16 r, g, b; 23548c2ecf20Sopenharmony_ci unsigned int j; 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci if (w == 0) 23578c2ecf20Sopenharmony_ci continue; 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci for (j = 0; j <= w; j++) { 23608c2ecf20Sopenharmony_ci r = (lut[i].red * (w - j) + lut[i + 1].red * j) / w; 23618c2ecf20Sopenharmony_ci g = (lut[i].green * (w - j) + lut[i + 1].green * j) / w; 23628c2ecf20Sopenharmony_ci b = (lut[i].blue * (w - j) + lut[i + 1].blue * j) / w; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci r >>= 16 - hwbits; 23658c2ecf20Sopenharmony_ci g >>= 16 - hwbits; 23668c2ecf20Sopenharmony_ci b >>= 16 - hwbits; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci table[first + j] = (r << (hwbits * 2)) | 23698c2ecf20Sopenharmony_ci (g << hwbits) | b; 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci } 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci dispc_vp_write_gamma_table(dispc, hw_videoport); 23748c2ecf20Sopenharmony_ci} 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_cistatic s16 dispc_S31_32_to_s2_8(s64 coef) 23778c2ecf20Sopenharmony_ci{ 23788c2ecf20Sopenharmony_ci u64 sign_bit = 1ULL << 63; 23798c2ecf20Sopenharmony_ci u64 cbits = (u64)coef; 23808c2ecf20Sopenharmony_ci s16 ret; 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci if (cbits & sign_bit) 23838c2ecf20Sopenharmony_ci ret = -clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x200); 23848c2ecf20Sopenharmony_ci else 23858c2ecf20Sopenharmony_ci ret = clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x1FF); 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci return ret; 23888c2ecf20Sopenharmony_ci} 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_cistatic void dispc_k2g_cpr_from_ctm(const struct drm_color_ctm *ctm, 23918c2ecf20Sopenharmony_ci struct dispc_csc_coef *cpr) 23928c2ecf20Sopenharmony_ci{ 23938c2ecf20Sopenharmony_ci memset(cpr, 0, sizeof(*cpr)); 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci cpr->to_regval = dispc_csc_cpr_regval; 23968c2ecf20Sopenharmony_ci cpr->m[CSC_RR] = dispc_S31_32_to_s2_8(ctm->matrix[0]); 23978c2ecf20Sopenharmony_ci cpr->m[CSC_RG] = dispc_S31_32_to_s2_8(ctm->matrix[1]); 23988c2ecf20Sopenharmony_ci cpr->m[CSC_RB] = dispc_S31_32_to_s2_8(ctm->matrix[2]); 23998c2ecf20Sopenharmony_ci cpr->m[CSC_GR] = dispc_S31_32_to_s2_8(ctm->matrix[3]); 24008c2ecf20Sopenharmony_ci cpr->m[CSC_GG] = dispc_S31_32_to_s2_8(ctm->matrix[4]); 24018c2ecf20Sopenharmony_ci cpr->m[CSC_GB] = dispc_S31_32_to_s2_8(ctm->matrix[5]); 24028c2ecf20Sopenharmony_ci cpr->m[CSC_BR] = dispc_S31_32_to_s2_8(ctm->matrix[6]); 24038c2ecf20Sopenharmony_ci cpr->m[CSC_BG] = dispc_S31_32_to_s2_8(ctm->matrix[7]); 24048c2ecf20Sopenharmony_ci cpr->m[CSC_BB] = dispc_S31_32_to_s2_8(ctm->matrix[8]); 24058c2ecf20Sopenharmony_ci} 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci#define CVAL(xR, xG, xB) (FLD_VAL(xR, 9, 0) | FLD_VAL(xG, 20, 11) | \ 24088c2ecf20Sopenharmony_ci FLD_VAL(xB, 31, 22)) 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_cistatic void dispc_k2g_vp_csc_cpr_regval(const struct dispc_csc_coef *csc, 24118c2ecf20Sopenharmony_ci u32 *regval) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci regval[0] = CVAL(csc->m[CSC_BB], csc->m[CSC_BG], csc->m[CSC_BR]); 24148c2ecf20Sopenharmony_ci regval[1] = CVAL(csc->m[CSC_GB], csc->m[CSC_GG], csc->m[CSC_GR]); 24158c2ecf20Sopenharmony_ci regval[2] = CVAL(csc->m[CSC_RB], csc->m[CSC_RG], csc->m[CSC_RR]); 24168c2ecf20Sopenharmony_ci} 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci#undef CVAL 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_cistatic void dispc_k2g_vp_write_csc(struct dispc_device *dispc, u32 hw_videoport, 24218c2ecf20Sopenharmony_ci const struct dispc_csc_coef *csc) 24228c2ecf20Sopenharmony_ci{ 24238c2ecf20Sopenharmony_ci static const u16 dispc_vp_cpr_coef_reg[] = { 24248c2ecf20Sopenharmony_ci DISPC_VP_CSC_COEF0, DISPC_VP_CSC_COEF1, DISPC_VP_CSC_COEF2, 24258c2ecf20Sopenharmony_ci /* K2G CPR is packed to three registers. */ 24268c2ecf20Sopenharmony_ci }; 24278c2ecf20Sopenharmony_ci u32 regval[DISPC_CSC_REGVAL_LEN]; 24288c2ecf20Sopenharmony_ci unsigned int i; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci dispc_k2g_vp_csc_cpr_regval(csc, regval); 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dispc_vp_cpr_coef_reg); i++) 24338c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, dispc_vp_cpr_coef_reg[i], 24348c2ecf20Sopenharmony_ci regval[i]); 24358c2ecf20Sopenharmony_ci} 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_cistatic void dispc_k2g_vp_set_ctm(struct dispc_device *dispc, u32 hw_videoport, 24388c2ecf20Sopenharmony_ci struct drm_color_ctm *ctm) 24398c2ecf20Sopenharmony_ci{ 24408c2ecf20Sopenharmony_ci u32 cprenable = 0; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci if (ctm) { 24438c2ecf20Sopenharmony_ci struct dispc_csc_coef cpr; 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci dispc_k2g_cpr_from_ctm(ctm, &cpr); 24468c2ecf20Sopenharmony_ci dispc_k2g_vp_write_csc(dispc, hw_videoport, &cpr); 24478c2ecf20Sopenharmony_ci cprenable = 1; 24488c2ecf20Sopenharmony_ci } 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONFIG, 24518c2ecf20Sopenharmony_ci cprenable, 15, 15); 24528c2ecf20Sopenharmony_ci} 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_cistatic s16 dispc_S31_32_to_s3_8(s64 coef) 24558c2ecf20Sopenharmony_ci{ 24568c2ecf20Sopenharmony_ci u64 sign_bit = 1ULL << 63; 24578c2ecf20Sopenharmony_ci u64 cbits = (u64)coef; 24588c2ecf20Sopenharmony_ci s16 ret; 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci if (cbits & sign_bit) 24618c2ecf20Sopenharmony_ci ret = -clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x400); 24628c2ecf20Sopenharmony_ci else 24638c2ecf20Sopenharmony_ci ret = clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x3FF); 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci return ret; 24668c2ecf20Sopenharmony_ci} 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_cistatic void dispc_csc_from_ctm(const struct drm_color_ctm *ctm, 24698c2ecf20Sopenharmony_ci struct dispc_csc_coef *cpr) 24708c2ecf20Sopenharmony_ci{ 24718c2ecf20Sopenharmony_ci memset(cpr, 0, sizeof(*cpr)); 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci cpr->to_regval = dispc_csc_cpr_regval; 24748c2ecf20Sopenharmony_ci cpr->m[CSC_RR] = dispc_S31_32_to_s3_8(ctm->matrix[0]); 24758c2ecf20Sopenharmony_ci cpr->m[CSC_RG] = dispc_S31_32_to_s3_8(ctm->matrix[1]); 24768c2ecf20Sopenharmony_ci cpr->m[CSC_RB] = dispc_S31_32_to_s3_8(ctm->matrix[2]); 24778c2ecf20Sopenharmony_ci cpr->m[CSC_GR] = dispc_S31_32_to_s3_8(ctm->matrix[3]); 24788c2ecf20Sopenharmony_ci cpr->m[CSC_GG] = dispc_S31_32_to_s3_8(ctm->matrix[4]); 24798c2ecf20Sopenharmony_ci cpr->m[CSC_GB] = dispc_S31_32_to_s3_8(ctm->matrix[5]); 24808c2ecf20Sopenharmony_ci cpr->m[CSC_BR] = dispc_S31_32_to_s3_8(ctm->matrix[6]); 24818c2ecf20Sopenharmony_ci cpr->m[CSC_BG] = dispc_S31_32_to_s3_8(ctm->matrix[7]); 24828c2ecf20Sopenharmony_ci cpr->m[CSC_BB] = dispc_S31_32_to_s3_8(ctm->matrix[8]); 24838c2ecf20Sopenharmony_ci} 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_cistatic void dispc_k3_vp_write_csc(struct dispc_device *dispc, u32 hw_videoport, 24868c2ecf20Sopenharmony_ci const struct dispc_csc_coef *csc) 24878c2ecf20Sopenharmony_ci{ 24888c2ecf20Sopenharmony_ci static const u16 dispc_vp_csc_coef_reg[DISPC_CSC_REGVAL_LEN] = { 24898c2ecf20Sopenharmony_ci DISPC_VP_CSC_COEF0, DISPC_VP_CSC_COEF1, DISPC_VP_CSC_COEF2, 24908c2ecf20Sopenharmony_ci DISPC_VP_CSC_COEF3, DISPC_VP_CSC_COEF4, DISPC_VP_CSC_COEF5, 24918c2ecf20Sopenharmony_ci DISPC_VP_CSC_COEF6, DISPC_VP_CSC_COEF7, 24928c2ecf20Sopenharmony_ci }; 24938c2ecf20Sopenharmony_ci u32 regval[DISPC_CSC_REGVAL_LEN]; 24948c2ecf20Sopenharmony_ci unsigned int i; 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci csc->to_regval(csc, regval); 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regval); i++) 24998c2ecf20Sopenharmony_ci dispc_vp_write(dispc, hw_videoport, dispc_vp_csc_coef_reg[i], 25008c2ecf20Sopenharmony_ci regval[i]); 25018c2ecf20Sopenharmony_ci} 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_cistatic void dispc_k3_vp_set_ctm(struct dispc_device *dispc, u32 hw_videoport, 25048c2ecf20Sopenharmony_ci struct drm_color_ctm *ctm) 25058c2ecf20Sopenharmony_ci{ 25068c2ecf20Sopenharmony_ci u32 colorconvenable = 0; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci if (ctm) { 25098c2ecf20Sopenharmony_ci struct dispc_csc_coef csc; 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci dispc_csc_from_ctm(ctm, &csc); 25128c2ecf20Sopenharmony_ci dispc_k3_vp_write_csc(dispc, hw_videoport, &csc); 25138c2ecf20Sopenharmony_ci colorconvenable = 1; 25148c2ecf20Sopenharmony_ci } 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONFIG, 25178c2ecf20Sopenharmony_ci colorconvenable, 24, 24); 25188c2ecf20Sopenharmony_ci} 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_cistatic void dispc_vp_set_color_mgmt(struct dispc_device *dispc, 25218c2ecf20Sopenharmony_ci u32 hw_videoport, 25228c2ecf20Sopenharmony_ci const struct drm_crtc_state *state, 25238c2ecf20Sopenharmony_ci bool newmodeset) 25248c2ecf20Sopenharmony_ci{ 25258c2ecf20Sopenharmony_ci struct drm_color_lut *lut = NULL; 25268c2ecf20Sopenharmony_ci struct drm_color_ctm *ctm = NULL; 25278c2ecf20Sopenharmony_ci unsigned int length = 0; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci if (!(state->color_mgmt_changed || newmodeset)) 25308c2ecf20Sopenharmony_ci return; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci if (state->gamma_lut) { 25338c2ecf20Sopenharmony_ci lut = (struct drm_color_lut *)state->gamma_lut->data; 25348c2ecf20Sopenharmony_ci length = state->gamma_lut->length / sizeof(*lut); 25358c2ecf20Sopenharmony_ci } 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci dispc_vp_set_gamma(dispc, hw_videoport, lut, length); 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci if (state->ctm) 25408c2ecf20Sopenharmony_ci ctm = (struct drm_color_ctm *)state->ctm->data; 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci if (dispc->feat->subrev == DISPC_K2G) 25438c2ecf20Sopenharmony_ci dispc_k2g_vp_set_ctm(dispc, hw_videoport, ctm); 25448c2ecf20Sopenharmony_ci else 25458c2ecf20Sopenharmony_ci dispc_k3_vp_set_ctm(dispc, hw_videoport, ctm); 25468c2ecf20Sopenharmony_ci} 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_civoid dispc_vp_setup(struct dispc_device *dispc, u32 hw_videoport, 25498c2ecf20Sopenharmony_ci const struct drm_crtc_state *state, bool newmodeset) 25508c2ecf20Sopenharmony_ci{ 25518c2ecf20Sopenharmony_ci dispc_vp_set_default_color(dispc, hw_videoport, 0); 25528c2ecf20Sopenharmony_ci dispc_vp_set_color_mgmt(dispc, hw_videoport, state, newmodeset); 25538c2ecf20Sopenharmony_ci} 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ciint dispc_runtime_suspend(struct dispc_device *dispc) 25568c2ecf20Sopenharmony_ci{ 25578c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "suspend\n"); 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci dispc->is_enabled = false; 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci clk_disable_unprepare(dispc->fclk); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci return 0; 25648c2ecf20Sopenharmony_ci} 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ciint dispc_runtime_resume(struct dispc_device *dispc) 25678c2ecf20Sopenharmony_ci{ 25688c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "resume\n"); 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci clk_prepare_enable(dispc->fclk); 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci if (REG_GET(dispc, DSS_SYSSTATUS, 0, 0) == 0) 25738c2ecf20Sopenharmony_ci dev_warn(dispc->dev, "DSS FUNC RESET not done!\n"); 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "OMAP DSS7 rev 0x%x\n", 25768c2ecf20Sopenharmony_ci dispc_read(dispc, DSS_REVISION)); 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "VP RESETDONE %d,%d,%d\n", 25798c2ecf20Sopenharmony_ci REG_GET(dispc, DSS_SYSSTATUS, 1, 1), 25808c2ecf20Sopenharmony_ci REG_GET(dispc, DSS_SYSSTATUS, 2, 2), 25818c2ecf20Sopenharmony_ci REG_GET(dispc, DSS_SYSSTATUS, 3, 3)); 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci if (dispc->feat->subrev == DISPC_AM65X) 25848c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "OLDI RESETDONE %d,%d,%d\n", 25858c2ecf20Sopenharmony_ci REG_GET(dispc, DSS_SYSSTATUS, 5, 5), 25868c2ecf20Sopenharmony_ci REG_GET(dispc, DSS_SYSSTATUS, 6, 6), 25878c2ecf20Sopenharmony_ci REG_GET(dispc, DSS_SYSSTATUS, 7, 7)); 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci dev_dbg(dispc->dev, "DISPC IDLE %d\n", 25908c2ecf20Sopenharmony_ci REG_GET(dispc, DSS_SYSSTATUS, 9, 9)); 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci dispc_initial_config(dispc); 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci dispc->is_enabled = true; 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci tidss_irq_resume(dispc->tidss); 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci return 0; 25998c2ecf20Sopenharmony_ci} 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_civoid dispc_remove(struct tidss_device *tidss) 26028c2ecf20Sopenharmony_ci{ 26038c2ecf20Sopenharmony_ci dev_dbg(tidss->dev, "%s\n", __func__); 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci tidss->dispc = NULL; 26068c2ecf20Sopenharmony_ci} 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_cistatic int dispc_iomap_resource(struct platform_device *pdev, const char *name, 26098c2ecf20Sopenharmony_ci void __iomem **base) 26108c2ecf20Sopenharmony_ci{ 26118c2ecf20Sopenharmony_ci struct resource *res; 26128c2ecf20Sopenharmony_ci void __iomem *b; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); 26158c2ecf20Sopenharmony_ci if (!res) { 26168c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot get mem resource '%s'\n", name); 26178c2ecf20Sopenharmony_ci return -EINVAL; 26188c2ecf20Sopenharmony_ci } 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci b = devm_ioremap_resource(&pdev->dev, res); 26218c2ecf20Sopenharmony_ci if (IS_ERR(b)) { 26228c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot ioremap resource '%s'\n", name); 26238c2ecf20Sopenharmony_ci return PTR_ERR(b); 26248c2ecf20Sopenharmony_ci } 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci *base = b; 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci return 0; 26298c2ecf20Sopenharmony_ci} 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_cistatic int dispc_init_am65x_oldi_io_ctrl(struct device *dev, 26328c2ecf20Sopenharmony_ci struct dispc_device *dispc) 26338c2ecf20Sopenharmony_ci{ 26348c2ecf20Sopenharmony_ci dispc->oldi_io_ctrl = 26358c2ecf20Sopenharmony_ci syscon_regmap_lookup_by_phandle(dev->of_node, 26368c2ecf20Sopenharmony_ci "ti,am65x-oldi-io-ctrl"); 26378c2ecf20Sopenharmony_ci if (PTR_ERR(dispc->oldi_io_ctrl) == -ENODEV) { 26388c2ecf20Sopenharmony_ci dispc->oldi_io_ctrl = NULL; 26398c2ecf20Sopenharmony_ci } else if (IS_ERR(dispc->oldi_io_ctrl)) { 26408c2ecf20Sopenharmony_ci dev_err(dev, "%s: syscon_regmap_lookup_by_phandle failed %ld\n", 26418c2ecf20Sopenharmony_ci __func__, PTR_ERR(dispc->oldi_io_ctrl)); 26428c2ecf20Sopenharmony_ci return PTR_ERR(dispc->oldi_io_ctrl); 26438c2ecf20Sopenharmony_ci } 26448c2ecf20Sopenharmony_ci return 0; 26458c2ecf20Sopenharmony_ci} 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_cistatic void dispc_init_errata(struct dispc_device *dispc) 26488c2ecf20Sopenharmony_ci{ 26498c2ecf20Sopenharmony_ci static const struct soc_device_attribute am65x_sr10_soc_devices[] = { 26508c2ecf20Sopenharmony_ci { .family = "AM65X", .revision = "SR1.0" }, 26518c2ecf20Sopenharmony_ci { /* sentinel */ } 26528c2ecf20Sopenharmony_ci }; 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci if (soc_device_match(am65x_sr10_soc_devices)) { 26558c2ecf20Sopenharmony_ci dispc->errata.i2000 = true; 26568c2ecf20Sopenharmony_ci dev_info(dispc->dev, "WA for erratum i2000: YUV formats disabled\n"); 26578c2ecf20Sopenharmony_ci } 26588c2ecf20Sopenharmony_ci} 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ciint dispc_init(struct tidss_device *tidss) 26618c2ecf20Sopenharmony_ci{ 26628c2ecf20Sopenharmony_ci struct device *dev = tidss->dev; 26638c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 26648c2ecf20Sopenharmony_ci struct dispc_device *dispc; 26658c2ecf20Sopenharmony_ci const struct dispc_features *feat; 26668c2ecf20Sopenharmony_ci unsigned int i, num_fourccs; 26678c2ecf20Sopenharmony_ci int r = 0; 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci dev_dbg(dev, "%s\n", __func__); 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci feat = tidss->feat; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci if (feat->subrev != DISPC_K2G) { 26748c2ecf20Sopenharmony_ci r = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); 26758c2ecf20Sopenharmony_ci if (r) 26768c2ecf20Sopenharmony_ci dev_warn(dev, "cannot set DMA masks to 48-bit\n"); 26778c2ecf20Sopenharmony_ci } 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci dispc = devm_kzalloc(dev, sizeof(*dispc), GFP_KERNEL); 26808c2ecf20Sopenharmony_ci if (!dispc) 26818c2ecf20Sopenharmony_ci return -ENOMEM; 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci dispc->tidss = tidss; 26848c2ecf20Sopenharmony_ci dispc->dev = dev; 26858c2ecf20Sopenharmony_ci dispc->feat = feat; 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci dispc_init_errata(dispc); 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci dispc->fourccs = devm_kcalloc(dev, ARRAY_SIZE(dispc_color_formats), 26908c2ecf20Sopenharmony_ci sizeof(*dispc->fourccs), GFP_KERNEL); 26918c2ecf20Sopenharmony_ci if (!dispc->fourccs) 26928c2ecf20Sopenharmony_ci return -ENOMEM; 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci num_fourccs = 0; 26958c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) { 26968c2ecf20Sopenharmony_ci if (dispc->errata.i2000 && 26978c2ecf20Sopenharmony_ci dispc_fourcc_is_yuv(dispc_color_formats[i].fourcc)) { 26988c2ecf20Sopenharmony_ci continue; 26998c2ecf20Sopenharmony_ci } 27008c2ecf20Sopenharmony_ci dispc->fourccs[num_fourccs++] = dispc_color_formats[i].fourcc; 27018c2ecf20Sopenharmony_ci } 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci dispc->num_fourccs = num_fourccs; 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci dispc_common_regmap = dispc->feat->common_regs; 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci r = dispc_iomap_resource(pdev, dispc->feat->common, 27088c2ecf20Sopenharmony_ci &dispc->base_common); 27098c2ecf20Sopenharmony_ci if (r) 27108c2ecf20Sopenharmony_ci return r; 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_ci for (i = 0; i < dispc->feat->num_planes; i++) { 27138c2ecf20Sopenharmony_ci r = dispc_iomap_resource(pdev, dispc->feat->vid_name[i], 27148c2ecf20Sopenharmony_ci &dispc->base_vid[i]); 27158c2ecf20Sopenharmony_ci if (r) 27168c2ecf20Sopenharmony_ci return r; 27178c2ecf20Sopenharmony_ci } 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci for (i = 0; i < dispc->feat->num_vps; i++) { 27208c2ecf20Sopenharmony_ci u32 gamma_size = dispc->feat->vp_feat.color.gamma_size; 27218c2ecf20Sopenharmony_ci u32 *gamma_table; 27228c2ecf20Sopenharmony_ci struct clk *clk; 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci r = dispc_iomap_resource(pdev, dispc->feat->ovr_name[i], 27258c2ecf20Sopenharmony_ci &dispc->base_ovr[i]); 27268c2ecf20Sopenharmony_ci if (r) 27278c2ecf20Sopenharmony_ci return r; 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci r = dispc_iomap_resource(pdev, dispc->feat->vp_name[i], 27308c2ecf20Sopenharmony_ci &dispc->base_vp[i]); 27318c2ecf20Sopenharmony_ci if (r) 27328c2ecf20Sopenharmony_ci return r; 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci clk = devm_clk_get(dev, dispc->feat->vpclk_name[i]); 27358c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 27368c2ecf20Sopenharmony_ci dev_err(dev, "%s: Failed to get clk %s:%ld\n", __func__, 27378c2ecf20Sopenharmony_ci dispc->feat->vpclk_name[i], PTR_ERR(clk)); 27388c2ecf20Sopenharmony_ci return PTR_ERR(clk); 27398c2ecf20Sopenharmony_ci } 27408c2ecf20Sopenharmony_ci dispc->vp_clk[i] = clk; 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci gamma_table = devm_kmalloc_array(dev, gamma_size, 27438c2ecf20Sopenharmony_ci sizeof(*gamma_table), 27448c2ecf20Sopenharmony_ci GFP_KERNEL); 27458c2ecf20Sopenharmony_ci if (!gamma_table) 27468c2ecf20Sopenharmony_ci return -ENOMEM; 27478c2ecf20Sopenharmony_ci dispc->vp_data[i].gamma_table = gamma_table; 27488c2ecf20Sopenharmony_ci } 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci if (feat->subrev == DISPC_AM65X) { 27518c2ecf20Sopenharmony_ci r = dispc_init_am65x_oldi_io_ctrl(dev, dispc); 27528c2ecf20Sopenharmony_ci if (r) 27538c2ecf20Sopenharmony_ci return r; 27548c2ecf20Sopenharmony_ci } 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci dispc->fclk = devm_clk_get(dev, "fck"); 27578c2ecf20Sopenharmony_ci if (IS_ERR(dispc->fclk)) { 27588c2ecf20Sopenharmony_ci dev_err(dev, "%s: Failed to get fclk: %ld\n", 27598c2ecf20Sopenharmony_ci __func__, PTR_ERR(dispc->fclk)); 27608c2ecf20Sopenharmony_ci return PTR_ERR(dispc->fclk); 27618c2ecf20Sopenharmony_ci } 27628c2ecf20Sopenharmony_ci dev_dbg(dev, "DSS fclk %lu Hz\n", clk_get_rate(dispc->fclk)); 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci of_property_read_u32(dispc->dev->of_node, "max-memory-bandwidth", 27658c2ecf20Sopenharmony_ci &dispc->memory_bandwidth_limit); 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci tidss->dispc = dispc; 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci return 0; 27708c2ecf20Sopenharmony_ci} 2771