/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2019 MediaTek Inc. */ #include #include #include #include #include #include #include #include #include "mtk_drm_drv.h" #include "mtk_drm_crtc.h" #include "mtk_drm_ddp_comp.h" #include "mtk_dump.h" #include "mtk_layering_rule_base.h" #include "mtk_rect.h" #include "mtk_drm_mmp.h" #include "mtk_drm_graphics_base.h" #include "mtk_drm_helper.h" #include "mtk_drm_drv.h" #include "mtk_disp_pmqos.h" #ifdef CONFIG_MTK_IOMMU_V2 #include #include "mtk_iommu_ext.h" #endif #include "cmdq-sec.h" #include "mtk_layer_layout_trace.h" #include "mtk_drm_mmp.h" #ifdef CONFIG_MTK_SMI_EXT #include "smi_public.h" #endif #include "mtk_drm_crtc.h" #define REG_FLD(width, shift) \ ((unsigned int)((((width)&0xFF) << 16) | ((shift)&0xFF))) #define REG_FLD_MSB_LSB(msb, lsb) REG_FLD((msb) - (lsb) + 1, (lsb)) #define REG_FLD_WIDTH(field) ((unsigned int)(((field) >> 16) & 0xFF)) #define REG_FLD_SHIFT(field) ((unsigned int)((field)&0xFF)) #define REG_FLD_MASK(field) \ ((unsigned int)((1ULL << REG_FLD_WIDTH(field)) - 1) \ << REG_FLD_SHIFT(field)) #define REG_FLD_VAL(field, val) \ (((val) << REG_FLD_SHIFT(field)) & REG_FLD_MASK(field)) #define DISP_REG_OVL_STA (0x000UL) #define DISP_REG_OVL_INTEN 0x0004 #define INTEN_FLD_REG_CMT_INTEN REG_FLD_MSB_LSB(0, 0) #define INTEN_FLD_FME_CPL_INTEN REG_FLD_MSB_LSB(1, 1) #define INTEN_FLD_FME_UND_INTEN REG_FLD_MSB_LSB(2, 2) #define INTEN_FLD_FME_SWRST_DONE_INTEN REG_FLD_MSB_LSB(3, 3) #define INTEN_FLD_FME_HWRST_DONE_INTEN REG_FLD_MSB_LSB(4, 4) #define INTEN_FLD_RDMA0_EOF_ABNORMAL_INTEN REG_FLD_MSB_LSB(5, 5) #define INTEN_FLD_RDMA1_EOF_ABNORMAL_INTEN REG_FLD_MSB_LSB(6, 6) #define INTEN_FLD_RDMA2_EOF_ABNORMAL_INTEN REG_FLD_MSB_LSB(7, 7) #define INTEN_FLD_RDMA3_EOF_ABNORMAL_INTEN REG_FLD_MSB_LSB(8, 8) #define INTEN_FLD_RDMA0_SMI_UNDERFLOW_INTEN REG_FLD_MSB_LSB(9, 9) #define INTEN_FLD_RDMA1_SMI_UNDERFLOW_INTEN REG_FLD_MSB_LSB(10, 10) #define INTEN_FLD_RDMA2_SMI_UNDERFLOW_INTEN REG_FLD_MSB_LSB(11, 11) #define INTEN_FLD_RDMA3_SMI_UNDERFLOW_INTEN REG_FLD_MSB_LSB(12, 12) #define INTEN_FLD_ABNORMAL_SOF REG_FLD_MSB_LSB(13, 13) #define INTEN_FLD_START_INTEN REG_FLD_MSB_LSB(14, 14) #define DISP_REG_OVL_INTSTA 0x0008 #define DISP_REG_OVL_EN (0x000CUL) #define EN_FLD_BLOCK_EXT_ULTRA REG_FLD_MSB_LSB(18, 18) #define EN_FLD_BLOCK_EXT_PREULTRA REG_FLD_MSB_LSB(19, 19) #define DISP_OVL_READ_WRK_REG BIT(20) #define DISP_OVL_BYPASS_SHADOW BIT(22) #define DISP_REG_OVL_TRIG (0x010UL) #define DISP_REG_OVL_RST 0x0014 #define DISP_REG_OVL_ROI_SIZE 0x0020 #define DISP_REG_OVL_DATAPATH_CON (0x024UL) #define DISP_OVL_BGCLR_IN_SEL BIT(2) #define DISP_OVL_OUTPUT_CLAMP BIT(26) #define DATAPATH_CON_FLD_LAYER_SMI_ID_EN REG_FLD_MSB_LSB(0, 0) #define DATAPATH_CON_FLD_GCLAST_EN REG_FLD_MSB_LSB(24, 24) #define DATAPATH_CON_FLD_HDR_GCLAST_EN REG_FLD_MSB_LSB(25, 25) #define DATAPATH_CON_FLD_OUTPUT_CLAMP REG_FLD_MSB_LSB(26, 26) #define DISP_REG_OVL_ROI_BGCLR 0x0028 #define DISP_REG_OVL_SRC_CON 0x002c #define DISP_OVL_FORCE_RELAY_MODE BIT(8) #define DISP_REG_OVL_CON(n) (0x0030 + 0x20 * (n)) #define L_CON_FLD_APHA REG_FLD_MSB_LSB(7, 0) #define L_CON_FLD_AEN REG_FLD_MSB_LSB(8, 8) #define L_CON_FLD_VIRTICAL_FLIP REG_FLD_MSB_LSB(9, 9) #define L_CON_FLD_HORI_FLIP REG_FLD_MSB_LSB(10, 10) #define L_CON_FLD_EXT_MTX_EN REG_FLD_MSB_LSB(11, 11) #define L_CON_FLD_CFMT REG_FLD_MSB_LSB(15, 12) #define L_CON_FLD_MTX REG_FLD_MSB_LSB(19, 16) #define L_CON_FLD_EN_3D REG_FLD_MSB_LSB(20, 20) #define L_CON_FLD_EN_LANDSCAPE REG_FLD_MSB_LSB(21, 21) #define L_CON_FLD_EN_R_FIRST REG_FLD_MSB_LSB(22, 22) #define L_CON_FLD_CLRFMT_MAN REG_FLD_MSB_LSB(23, 23) #define L_CON_FLD_BTSW REG_FLD_MSB_LSB(24, 24) #define L_CON_FLD_RGB_SWAP REG_FLD_MSB_LSB(25, 25) #define L_CON_FLD_LSRC REG_FLD_MSB_LSB(29, 28) #define L_CON_FLD_SKEN REG_FLD_MSB_LSB(30, 30) #define L_CON_FLD_DKEN REG_FLD_MSB_LSB(31, 31) #define CON_LSRC_RES BIT(28) #define CON_VERTICAL_FLIP BIT(9) #define CON_HORI_FLIP BIT(10) #define DISP_REG_OVL_SRCKEY(n) (0x0034 + 0x20 * (n)) #define DISP_REG_OVL_SRC_SIZE(n) (0x0038 + 0x20 * (n)) #define DISP_REG_OVL_OFFSET(n) (0x003c + 0x20 * (n)) #define DISP_REG_OVL_PITCH_MSB(n) (0x0040 + 0x20 * (n)) #define L_PITCH_MSB_FLD_YUV_TRANS REG_FLD_MSB_LSB(20, 20) #define L_PITCH_MSB_FLD_2ND_SUBBUF REG_FLD_MSB_LSB(16, 16) #define L_PITCH_MSB_FLD_SRC_PITCH_MSB REG_FLD_MSB_LSB(3, 0) #define DISP_REG_OVL_PITCH(n) (0x0044 + 0x20 * (n)) #define DISP_REG_OVL_CLIP(n) (0x04CUL + 0x20 * (n)) #define OVL_L_CLIP_FLD_LEFT REG_FLD_MSB_LSB(7, 0) #define OVL_L_CLIP_FLD_RIGHT REG_FLD_MSB_LSB(15, 8) #define OVL_L_CLIP_FLD_TOP REG_FLD_MSB_LSB(23, 16) #define OVL_L_CLIP_FLD_BOTTOM REG_FLD_MSB_LSB(31, 24) #define DISP_REG_OVL_RDMA_CTRL(n) (0x00c0 + 0x20 * (n)) #define DISP_REG_OVL_RDMA_GMC(n) (0x00c8 + 0x20 * (n)) #define DISP_REG_OVL_RDMA_FIFO_CTRL(n) (0x00d0 + 0x20 * (n)) #define DISP_REG_OVL_RDMA0_MEM_GMC_S2 (0x1E0UL) #define FLD_OVL_RDMA_MEM_GMC2_ISSUE_REQ_THRES REG_FLD_MSB_LSB(11, 0) #define FLD_OVL_RDMA_MEM_GMC2_ISSUE_REQ_THRES_URG REG_FLD_MSB_LSB(27, 16) #define FLD_OVL_RDMA_MEM_GMC2_REQ_THRES_PREULTRA REG_FLD_MSB_LSB(28, 28) #define FLD_OVL_RDMA_MEM_GMC2_REQ_THRES_ULTRA REG_FLD_MSB_LSB(29, 29) #define FLD_OVL_RDMA_MEM_GMC2_FORCE_REQ_THRES REG_FLD_MSB_LSB(30, 30) #define DISP_REG_OVL_RDMA1_MEM_GMC_S2 (0x1E4UL) #define DISP_REG_OVL_RDMA2_MEM_GMC_S2 (0x1E8UL) #define DISP_REG_OVL_RDMA3_MEM_GMC_S2 (0x1ECUL) #define DISP_REG_OVL_RDMA_BURST_CON1 (0x1F4UL) #define FLD_RDMA_BURST_CON1_BURST16_EN REG_FLD_MSB_LSB(28, 28) #define DISP_REG_OVL_GDRDY_PRD (0x208UL) #define DISP_REG_OVL_RDMA0_DBG (0x24CUL) #define DISP_REG_OVL_RDMA1_DBG (0x250UL) #define DISP_REG_OVL_RDMA2_DBG (0x254UL) #define DISP_REG_OVL_RDMA3_DBG (0x258UL) #define DISP_REG_OVL_L0_CLR(n) (0x25cUL + 0x4 * (n)) #define DISP_REG_OVL_LC_CON (0x280UL) #define DISP_REG_OVL_LC_SRCKEY (0x284UL) #define DISP_REG_OVL_LC_SRC_SIZE (0x288UL) #define DISP_REG_OVL_LC_OFFSET (0x28cUL) #define DISP_REG_OVL_LC_SRC_SEL (0x290UL) #define DISP_REG_OVL_BANK_CON (0x29cUL) #define DISP_REG_OVL_DEBUG_MON_SEL (0x1D4UL) #define DISP_REG_OVL_RDMA_GREQ_NUM (0x1F8UL) #define FLD_OVL_RDMA_GREQ_LAYER0_GREQ_NUM REG_FLD_MSB_LSB(3, 0) #define FLD_OVL_RDMA_GREQ_LAYER1_GREQ_NUM REG_FLD_MSB_LSB(7, 4) #define FLD_OVL_RDMA_GREQ_LAYER2_GREQ_NUM REG_FLD_MSB_LSB(11, 8) #define FLD_OVL_RDMA_GREQ_LAYER3_GREQ_NUM REG_FLD_MSB_LSB(15, 12) #define FLD_OVL_RDMA_GREQ_OSTD_GREQ_NUM REG_FLD_MSB_LSB(23, 16) #define FLD_OVL_RDMA_GREQ_GREQ_DIS_CNT REG_FLD_MSB_LSB(26, 24) #define FLD_OVL_RDMA_GREQ_STOP_EN REG_FLD_MSB_LSB(27, 27) #define FLD_OVL_RDMA_GREQ_GRP_END_STOP REG_FLD_MSB_LSB(28, 28) #define FLD_OVL_RDMA_GREQ_GRP_BRK_STOP REG_FLD_MSB_LSB(29, 29) #define FLD_OVL_RDMA_GREQ_IOBUF_FLUSH_PREULTRA REG_FLD_MSB_LSB(30, 30) #define FLD_OVL_RDMA_GREQ_IOBUF_FLUSH_ULTRA REG_FLD_MSB_LSB(31, 31) #define DISP_REG_OVL_RDMA_GREQ_URG_NUM (0x1FCUL) #define FLD_OVL_RDMA_GREQ_LAYER0_GREQ_URG_NUM REG_FLD_MSB_LSB(3, 0) #define FLD_OVL_RDMA_GREQ_LAYER1_GREQ_URG_NUM REG_FLD_MSB_LSB(7, 4) #define FLD_OVL_RDMA_GREQ_LAYER2_GREQ_URG_NUM REG_FLD_MSB_LSB(11, 8) #define FLD_OVL_RDMA_GREQ_LAYER3_GREQ_URG_NUM REG_FLD_MSB_LSB(15, 12) #define FLD_OVL_RDMA_GREQ_ARG_GREQ_URG_TH REG_FLD_MSB_LSB(25, 16) #define FLD_OVL_RDMA_GREQ_ARG_URG_BIAS REG_FLD_MSB_LSB(28, 28) #define FLD_OVL_RDMA_GREQ_NUM_SHT_VAL REG_FLD_MSB_LSB(29, 29) #define DISP_REG_OVL_DUMMY_REG (0x200UL) #define DISP_REG_OVL_RDMA_ULTRA_SRC (0x20CUL) #define FLD_OVL_RDMA_PREULTRA_BUF_SRC REG_FLD_MSB_LSB(1, 0) #define FLD_OVL_RDMA_PREULTRA_SMI_SRC REG_FLD_MSB_LSB(3, 2) #define FLD_OVL_RDMA_PREULTRA_ROI_END_SRC REG_FLD_MSB_LSB(5, 4) #define FLD_OVL_RDMA_PREULTRA_RDMA_SRC REG_FLD_MSB_LSB(7, 6) #define FLD_OVL_RDMA_ULTRA_BUF_SRC REG_FLD_MSB_LSB(9, 8) #define FLD_OVL_RDMA_ULTRA_SMI_SRC REG_FLD_MSB_LSB(11, 10) #define FLD_OVL_RDMA_ULTRA_ROI_END_SRC REG_FLD_MSB_LSB(13, 12) #define FLD_OVL_RDMA_ULTRA_RDMA_SRC REG_FLD_MSB_LSB(15, 14) #define DISP_OVL_REG_GDRDY_PRD (0x208UL) #define DISP_REG_OVL_RDMAn_BUF_LOW(layer) (0x210UL + ((layer) << 2)) #define FLD_OVL_RDMA_BUF_LOW_ULTRA_TH REG_FLD_MSB_LSB(11, 0) #define FLD_OVL_RDMA_BUF_LOW_PREULTRA_TH REG_FLD_MSB_LSB(23, 12) #define DISP_REG_OVL_RDMAn_BUF_HIGH(layer) (0x220UL + ((layer) << 2)) #define FLD_OVL_RDMA_BUF_HIGH_PREULTRA_TH REG_FLD_MSB_LSB(23, 12) #define FLD_OVL_RDMA_BUF_HIGH_PREULTRA_DIS REG_FLD_MSB_LSB(31, 31) #define DISP_REG_OVL_SMI_DBG (0x230UL) #define DISP_REG_OVL_GREQ_LAYER_CNT (0x234UL) #define DISP_REG_OVL_GDRDY_PRD_NUM (0x238UL) #define DISP_REG_OVL_FLOW_CTRL_DBG (0x240UL) #define DISP_REG_OVL_ADDCON_DBG (0x244UL) #define DISP_REG_OVL_FUNC_DCM0 (0x2a0UL) #define DISP_REG_OVL_FUNC_DCM1 (0x2a4UL) #define DISP_REG_OVL_CLRFMT_EXT (0x2D0UL) #define FLD_Ln_CLRFMT_NB(n) REG_FLD_MSB_LSB((n)*4 + 1, (n)*4) #define FLD_ELn_CLRFMT_NB(n) REG_FLD_MSB_LSB((n)*4 + 17, (n)*4 + 16) #define DISP_REG_OVL_WCG_CFG1 (0x2D8UL) #define FLD_Ln_IGAMMA_EN(n) REG_FLD_MSB_LSB((n)*4, (n)*4) #define FLD_Ln_CSC_EN(n) REG_FLD_MSB_LSB((n)*4 + 1, (n)*4 + 1) #define FLD_Ln_GAMMA_EN(n) REG_FLD_MSB_LSB((n)*4 + 2, (n)*4 + 2) #define FLD_ELn_IGAMMA_EN(n) REG_FLD_MSB_LSB((n)*4 + 16, (n)*4 + 16) #define FLD_ELn_CSC_EN(n) REG_FLD_MSB_LSB((n)*4 + 17, (n)*4 + 17) #define FLD_ELn_GAMMA_EN(n) REG_FLD_MSB_LSB((n)*4 + 18, (n)*4 + 18) #define DISP_REG_OVL_WCG_CFG2 (0x2DCUL) #define FLD_Ln_IGAMMA_SEL(n) REG_FLD_MSB_LSB((n)*4 + 1, (n)*4) #define FLD_Ln_GAMMA_SEL(n) REG_FLD_MSB_LSB((n)*4 + 3, (n)*4 + 2) #define FLD_ELn_IGAMMA_SEL(n) REG_FLD_MSB_LSB((n)*4 + 17, (n)*4 + 16) #define FLD_ELn_GAMMA_SEL(n) REG_FLD_MSB_LSB((n)*4 + 19, (n)*4 + 18) #define DISP_REG_OVL_DATAPATH_EXT_CON (0x324UL) #define DISP_REG_OVL_EL_CON(n) (0x330UL + 0x20 * (n)) #define DISP_REG_OVL_EL_SRCKEY(n) (0x334UL + 0x20 * (n)) #define DISP_REG_OVL_EL_SRC_SIZE(n) (0x338UL + 0x20 * (n)) #define DISP_REG_OVL_EL_OFFSET(n) (0x33CUL + 0x20 * (n)) #define DISP_REG_OVL_EL_ADDR(n) (0xFB0UL + 0x04 * (n)) #define DISP_REG_OVL_EL_PITCH_MSB(n) (0x340U + 0x20 * (n)) #define DISP_REG_OVL_EL_PITCH(n) (0x344U + 0x20 * (n)) #define DISP_REG_OVL_EL_TILE(n) (0x348UL + 0x20 * (n)) #define DISP_REG_OVL_EL_CLIP(n) (0x34CUL + 0x20 * (n)) #define DISP_REG_OVL_EL0_CLR(n) (0x390UL + 0x4 * (n)) #define DISP_REG_OVL_ADDR_MT2701 0x0040 #define DISP_REG_OVL_ADDR_MT6779 0x0f40 #define DISP_REG_OVL_ADDR_MT6885 0x0f40 #define DISP_REG_OVL_ADDR_MT6873 0x0f40 #define DISP_REG_OVL_ADDR_MT6853 0x0f40 #define DISP_REG_OVL_ADDR_MT6877 0x0f40 #define DISP_REG_OVL_ADDR_MT6833 0x0f40 #define DISP_REG_OVL_ADDR_MT6781 0x0f40 #define DISP_REG_OVL_ADDR_MT8173 0x0f40 #define DISP_REG_OVL_ADDR(module, n) ((module)->data->addr + 0x20 * (n)) #define OVL_LAYER_OFFSET (0x20) #define DISP_REG_OVL_L0_HDR_ADDR (0xF44UL) #define DISP_REG_OVL_LX_HDR_ADDR(n) (0xF44UL + 0x20 * (n)) #define DISP_REG_OVL_L0_HDR_PITCH (0xF48UL) #define DISP_REG_OVL_L1_HDR_ADDR (0xF64UL) #define DISP_REG_OVL_LX_HDR_PITCH(n) (0xF48UL + 0x20 * (n)) #define DISP_REG_OVL_EL0_HDR_ADDR (0xFD0UL) #define DISP_REG_OVL_EL1_HDR_ADDR (0xFD8UL) #define DISP_REG_OVL_ELX_HDR_ADDR(n) (0xFD0UL + 0x8 * (n)) #define DISP_REG_OVL_ELX_HDR_PITCH(n) (0xFD4UL + 0x8 * (n)) #define DISP_REG_OVL_L0_OFFSET (0x03CUL) #define DISP_REG_OVL_L0_SRC_SIZE (0x038UL) #define DISP_REG_OVL_L0_PITCH (0x044UL) #define L_PITCH_FLD_SRC_PITCH REG_FLD_MSB_LSB(15, 0) #define ADDCON_DBG_FLD_ROI_X REG_FLD_MSB_LSB(12, 0) #define ADDCON_DBG_FLD_L0_WIN_HIT REG_FLD_MSB_LSB(14, 14) #define ADDCON_DBG_FLD_L1_WIN_HIT REG_FLD_MSB_LSB(15, 15) #define ADDCON_DBG_FLD_ROI_Y REG_FLD_MSB_LSB(28, 16) #define ADDCON_DBG_FLD_L2_WIN_HIT REG_FLD_MSB_LSB(30, 30) #define ADDCON_DBG_FLD_L3_WIN_HIT REG_FLD_MSB_LSB(31, 31) #define DATAPATH_CON_FLD_BGCLR_IN_SEL REG_FLD_MSB_LSB(2, 2) #define DISP_REG_OVL_RDMA0_CTRL (0x0C0UL) #define RDMA0_CTRL_FLD_RDMA_EN REG_FLD_MSB_LSB(0, 0) #define RDMA0_CTRL_FLD_RDMA_INTERLACE REG_FLD_MSB_LSB(4, 4) #define RDMA0_CTRL_FLD_RMDA_FIFO_USED_SZ REG_FLD_MSB_LSB(27, 16) #define DISP_REG_OVL_RDMA0_MEM_GMC_SETTING (0x0C8UL) #define FLD_OVL_RDMA_MEM_GMC_ULTRA_THRESHOLD REG_FLD_MSB_LSB(9, 0) #define FLD_OVL_RDMA_MEM_GMC_PRE_ULTRA_THRESHOLD REG_FLD_MSB_LSB(25, 16) #define FLD_OVL_RDMA_MEM_GMC_ULTRA_THRESHOLD_HIGH_OFS REG_FLD_MSB_LSB(28, 28) #define FLD_OVL_RDMA_MEM_GMC_PRE_ULTRA_THRESHOLD_HIGH_OFS \ REG_FLD_MSB_LSB(31, 31) #define DISP_REG_OVL_RDMA0_MEM_SLOW_CON (0x0CCUL) #define DISP_REG_OVL_RDMA0_FIFO_CTRL (0x0D0UL) #define FLD_OVL_RDMA_FIFO_THRD REG_FLD_MSB_LSB(9, 0) #define FLD_OVL_RDMA_FIFO_SIZE REG_FLD_MSB_LSB(27, 16) #define FLD_OVL_RDMA_FIFO_UND_EN REG_FLD_MSB_LSB(31, 31) #define DISP_REG_OVL_Ln_R2R_PARA(n) (0x500UL + 0x40 * (n)) #define DISP_REG_OVL_ELn_R2R_PARA(n) (0x600UL + 0x40 * (n)) #define DISP_REG_OVL_FBDC_CFG1 (0x804UL) #define FLD_FBDC_8XE_MODE REG_FLD_MSB_LSB(24, 24) #define FLD_FBDC_FILTER_EN REG_FLD_MSB_LSB(28, 28) #define FBDC_8XE_MODE BIT(24) #define FBDC_FILTER_EN BIT(28) #define OVL_SECURE 0xfc0 #define EXT_SECURE_OFFSET 4 #define OVL_LAYER_DOMAIN 0xfc4 #define OVL_LAYER_EXT_DOMAIN 0xfc8 #define OVL_LAYER_Lx_DOMAIN(id) REG_FLD_MSB_LSB((4 + 8 * id), (0 + 8 * id)) #define OVL_LAYER_ELx_DOMAIN(id) REG_FLD_MSB_LSB((4 + 8 * id), (0 + 8 * id)) #ifdef CONFIG_MTK_SVP_ON_MTEE_SUPPORT #define OVL_LAYER_SVP_DOMAIN_INDEX (4) #endif #define OVL_RDMA_DEBUG_OFFSET (0x4) #define OVL_RDMA_MEM_GMC 0x40402020 #define OVL_ROI_BGCLR (0xFF000000) #define OVL_CON_CLRFMT_MAN BIT(23) #define OVL_CON_BYTE_SWAP BIT(24) #define OVL_CON_RGB_SWAP BIT(25) #define OVL_CON_MTX_JPEG_TO_RGB (4UL << 16) #define OVL_CON_MTX_BT601_TO_RGB (6UL << 16) #define OVL_CON_MTX_BT709_TO_RGB (7UL << 16) #define OVL_CON_CLRFMT_RGB (1UL << 12) #define OVL_CON_CLRFMT_RGBA8888 (2 << 12) #define OVL_CON_CLRFMT_ARGB8888 (3 << 12) #define OVL_CON_CLRFMT_DIM (1 << 28) #define OVL_CON_CLRFMT_RGB565(module) \ (((module)->data->fmt_rgb565_is_0 == true) ? 0UL : OVL_CON_CLRFMT_RGB) #define OVL_CON_CLRFMT_RGB888(module) \ (((module)->data->fmt_rgb565_is_0 == true) ? OVL_CON_CLRFMT_RGB : 0UL) #define OVL_CON_CLRFMT_UYVY(module) ((module)->data->fmt_uyvy) #define OVL_CON_CLRFMT_YUYV(module) ((module)->data->fmt_yuyv) #define OVL_CON_AEN BIT(8) #define OVL_CON_ALPHA 0xff #define M4U_PORT_DISP_OVL0_HDR 1 #define M4U_PORT_DISP_OVL0 3 #define M4U_PORT_DISP_OVL0_2L_HDR ((1 << 5) + 0) #define M4U_PORT_DISP_OVL0_2L ((1 << 5) + 2) /* define for AFBC_V1_2 */ #define AFBC_V1_2_TILE_W (32) #define AFBC_V1_2_TILE_H (8) #define AFBC_V1_2_HEADER_ALIGN_BYTES (1024) #define AFBC_V1_2_HEADER_SIZE_PER_TILE_BYTES (16) enum GS_OVL_FLD { GS_OVL_RDMA_ULTRA_TH = 0, GS_OVL_RDMA_PRE_ULTRA_TH, GS_OVL_RDMA_FIFO_THRD, GS_OVL_RDMA_FIFO_SIZE, GS_OVL_RDMA_ISSUE_REQ_TH, GS_OVL_RDMA_ISSUE_REQ_TH_URG, GS_OVL_RDMA_REQ_TH_PRE_ULTRA, GS_OVL_RDMA_REQ_TH_ULTRA, GS_OVL_RDMA_FORCE_REQ_TH, GS_OVL_RDMA_GREQ_NUM, /* whole reg */ GS_OVL_RDMA_GREQ_URG_NUM, /* whole reg */ GS_OVL_RDMA_ULTRA_SRC, /* whole reg */ GS_OVL_RDMA_ULTRA_LOW_TH, GS_OVL_RDMA_PRE_ULTRA_LOW_TH, GS_OVL_RDMA_PRE_ULTRA_HIGH_TH, GS_OVL_RDMA_PRE_ULTRA_HIGH_DIS, GS_OVL_BLOCK_EXT_ULTRA, GS_OVL_BLOCK_EXT_PRE_ULTRA, GS_OVL_FLD_NUM, }; #define CSC_COEF_NUM 9 static u32 sRGB_to_DCI_P3[CSC_COEF_NUM] = {215603, 46541, 0, 8702, 253442, 0, 4478, 18979, 238687}; static u32 DCI_P3_to_sRGB[CSC_COEF_NUM] = { 321111, -58967, 0, -11025, 273169, 0, -5148, -20614, 287906}; #define DECLARE_MTK_OVL_COLORSPACE(EXPR) \ EXPR(OVL_SRGB) \ EXPR(OVL_P3) \ EXPR(OVL_CS_NUM) \ EXPR(OVL_CS_UNKNOWN) enum mtk_ovl_colorspace { DECLARE_MTK_OVL_COLORSPACE(DECLARE_NUM) }; static const char * const mtk_ovl_colorspace_str[] = { DECLARE_MTK_OVL_COLORSPACE(DECLARE_STR)}; #define DECLARE_MTK_OVL_TRANSFER(EXPR) \ EXPR(OVL_GAMMA2) \ EXPR(OVL_GAMMA2_2) \ EXPR(OVL_LINEAR) \ EXPR(OVL_GAMMA_NUM) \ EXPR(OVL_GAMMA_UNKNOWN) enum mtk_ovl_transfer { DECLARE_MTK_OVL_TRANSFER(DECLARE_NUM) }; static const char * const mtk_ovl_transfer_str[] = { DECLARE_MTK_OVL_TRANSFER(DECLARE_STR)}; struct compress_info { /* naming rule: tech_version_MTK_sub-version, * i.e.: PVRIC_V3_1_MTK_1 * sub-version is used when compression version is the same * but mtk decoder is different among platforms. */ const char name[25]; bool (*l_config)(struct mtk_ddp_comp *comp, unsigned int idx, struct mtk_plane_state *state, struct cmdq_pkt *handle); }; struct mtk_disp_ovl_data { unsigned int addr; bool fmt_rgb565_is_0; unsigned int fmt_uyvy; unsigned int fmt_yuyv; const struct compress_info *compr_info; bool support_shadow; }; #define MAX_LAYER_NUM 4 struct mtk_ovl_backup_info { unsigned int layer; unsigned int layer_en; unsigned int con; unsigned long addr; unsigned int src_size; unsigned int src_pitch; unsigned int data_path_con; }; /** * struct mtk_disp_ovl - DISP_OVL driver structure * @ddp_comp - structure containing type enum and hardware resources * @crtc - associated crtc to report vblank events to */ struct mtk_disp_ovl { struct mtk_ddp_comp ddp_comp; const struct mtk_disp_ovl_data *data; unsigned int underflow_cnt; int bg_w, bg_h; struct clk *fbdc_clk; struct mtk_ovl_backup_info backup_info[MAX_LAYER_NUM]; }; static inline struct mtk_disp_ovl *comp_to_ovl(struct mtk_ddp_comp *comp) { return container_of(comp, struct mtk_disp_ovl, ddp_comp); } int mtk_ovl_layer_num(struct mtk_ddp_comp *comp) { switch (comp->id) { case DDP_COMPONENT_OVL0: case DDP_COMPONENT_OVL1: return 4; case DDP_COMPONENT_OVL0_2L: case DDP_COMPONENT_OVL1_2L: case DDP_COMPONENT_OVL2_2L: case DDP_COMPONENT_OVL3_2L: return 2; default: DDPPR_ERR("invalid ovl module=%d\n", comp->id); return -1; } return 0; } static void dump_ovl_layer_trace(struct mtk_drm_crtc *mtk_crtc, struct mtk_ddp_comp *ovl) { struct cmdq_pkt_buffer *cmdq_buf = NULL; u32 offset = 0; u32 idx = 0; u32 gdrdy_num = 0, layer_en = 0, compress = 0; u32 ext_layer_en = 0, ext_layer_compress = 0; const int lnr = mtk_ovl_layer_num(ovl); int i = 0; u32 w = 0, h = 0, size = 0, con = 0, fmt = 0, src = 0; struct mtk_drm_private *priv = NULL; const int len = 1000; char msg[len]; int n = 0; if (!mtk_crtc) return; priv = mtk_crtc->base.dev->dev_private; if (!(mtk_drm_helper_get_opt(priv->helper_opt, MTK_DRM_OPT_LAYER_REC) && mtk_crtc->layer_rec_en)) return; if (ovl->id == DDP_COMPONENT_OVL0_2L) offset = DISP_SLOT_LAYER_REC_OVL0_2L; else if (ovl->id == DDP_COMPONENT_OVL0) offset = DISP_SLOT_LAYER_REC_OVL0; else return; cmdq_buf = &mtk_crtc->gce_obj.buf; idx = *(u32 *)(cmdq_buf->va_base + DISP_SLOT_TRIG_CNT); gdrdy_num = *(u32 *)(cmdq_buf->va_base + offset); gdrdy_num <<= 4; n = snprintf(msg, len, "idx:%u,ovl%s:bw:%u", idx, ovl->id == DDP_COMPONENT_OVL0 ? "0" : "0_2l", gdrdy_num); offset += 4; layer_en = *(u32 *)(cmdq_buf->va_base + offset); layer_en &= 0xf; offset += 4; compress = *(u32 *)(cmdq_buf->va_base + offset); compress = (compress >> 4) & 0xf; offset += 4; ext_layer_en = *(u32 *)(cmdq_buf->va_base + offset); ext_layer_compress = (ext_layer_en >> 4) & 0x7; ext_layer_en &= 0x7; for (i = 0; i < lnr + 3; i++) { if (i < lnr) { if (!(layer_en & 0x1)) { offset += (0x4 * 2); goto next; } } else { if (!(ext_layer_en & 0x1)) { offset += (0x4 * 2); goto next; } } offset += 0x4; con = *(u32 *)(cmdq_buf->va_base + offset); fmt = (con >> 12) & 0xf; src = (con >> 28) & 0x3; offset += 0x4; size = *(u32 *)(cmdq_buf->va_base + offset); w = size & 0x1fff; h = (size >> 16) & 0x1fff; if (i < lnr) { n += snprintf(msg + n, len - n, "|L%d:%dx%d,f:0x%x,c:%d,src:%d", i, w, h, fmt, compress & 0x1, src); } else { n += snprintf(msg + n, len - n, "|L%d:%dx%d,f:0x%x,c:%d,src:%d", i, w, h, fmt, ext_layer_compress & 0x1, src); } next: if (i < lnr) { layer_en >>= 1; compress >>= 1; } else { ext_layer_en >>= 1; ext_layer_compress >>= 1; } } n += snprintf(msg + n, len - n, "\n"); trace_layer_bw(msg); } static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id) { struct mtk_disp_ovl *priv = dev_id; struct mtk_ddp_comp *ovl = &priv->ddp_comp; struct mtk_drm_private *drv_priv = NULL; struct mtk_drm_crtc *mtk_crtc = ovl->mtk_crtc; unsigned int val = 0; unsigned int ret = 0; if (mtk_drm_top_clk_isr_get("ovl_irq") == false) { DDPIRQ("%s, top clk off\n", __func__); return IRQ_NONE; } val = readl(ovl->regs + DISP_REG_OVL_INTSTA); if (!val) { ret = IRQ_NONE; goto out; } DRM_MMP_MARK(IRQ, irq, val); if (ovl->id == DDP_COMPONENT_OVL0) DRM_MMP_MARK(ovl0, val, 0); else if (ovl->id == DDP_COMPONENT_OVL1) DRM_MMP_MARK(ovl1, val, 0); else if (ovl->id == DDP_COMPONENT_OVL0_2L) DRM_MMP_MARK(ovl0_2l, val, 0); else if (ovl->id == DDP_COMPONENT_OVL1_2L) DRM_MMP_MARK(ovl1_2l, val, 0); else if (ovl->id == DDP_COMPONENT_OVL2_2L) DRM_MMP_MARK(ovl2_2l, val, 0); else if (ovl->id == DDP_COMPONENT_OVL3_2L) DRM_MMP_MARK(ovl3_2l, val, 0); if (val & 0x1e0) DRM_MMP_MARK(abnormal_irq, val, ovl->id); DDPIRQ("%s irq, val:0x%x\n", mtk_dump_comp_str(ovl), val); writel(~val, ovl->regs + DISP_REG_OVL_INTSTA); if (val & (1 << 0)) DDPIRQ("[IRQ] %s: reg commit!\n", mtk_dump_comp_str(ovl)); if (val & (1 << 1)) { DDPIRQ("[IRQ] %s: frame done!\n", mtk_dump_comp_str(ovl)); dump_ovl_layer_trace(mtk_crtc, ovl); } if (val & (1 << 2)) { DDPPR_ERR("[IRQ] %s: frame underflow! cnt=%d\n", mtk_dump_comp_str(ovl), priv->underflow_cnt); if ((priv->underflow_cnt % 50) == 0) { if (ovl->mtk_crtc) { mtk_drm_crtc_analysis(&(ovl->mtk_crtc->base)); mtk_drm_crtc_dump(&(ovl->mtk_crtc->base)); } DDPAEE(" %s: frame underflow! cnt=%d\n", mtk_dump_comp_str(ovl), priv->underflow_cnt); } priv->underflow_cnt++; } if (val & (1 << 3)) DDPIRQ("[IRQ] %s: sw reset done!\n", mtk_dump_comp_str(ovl)); if (val & (1 << 4)) DDPPR_ERR("[IRQ] %s: hw reset done!\n", mtk_dump_comp_str(ovl)); if (val & (1 << 5)) DDPPR_ERR("[IRQ] %s: L0 not complete until EOF!\n", mtk_dump_comp_str(ovl)); if (val & (1 << 6)) DDPPR_ERR("[IRQ] %s: L1 not complete until EOF!\n", mtk_dump_comp_str(ovl)); if (val & (1 << 7)) DDPPR_ERR("[IRQ] %s: L2 not complete until EOF!\n", mtk_dump_comp_str(ovl)); if (val & (1 << 8)) DDPPR_ERR("[IRQ] %s: L3 not complete until EOF!\n", mtk_dump_comp_str(ovl)); if (mtk_crtc) { drv_priv = mtk_crtc->base.dev->dev_private; if (!mtk_drm_helper_get_opt( drv_priv->helper_opt, MTK_DRM_OPT_COMMIT_NO_WAIT_VBLANK)) { mtk_crtc_vblank_irq(&mtk_crtc->base); } } ret = IRQ_HANDLED; out: mtk_drm_top_clk_isr_put("ovl_irq"); return ret; } #if 0 static void mtk_ovl_enable_vblank(struct mtk_ddp_comp *comp, struct drm_crtc *crtc, struct cmdq_pkt *handle) { unsigned int inten; writel(0x0, comp->regs + DISP_REG_OVL_INTSTA); inten = 0x1E0 | REG_FLD_VAL(INTEN_FLD_ABNORMAL_SOF, 1) | REG_FLD_VAL(INTEN_FLD_START_INTEN, 1); writel_relaxed(inten, comp->regs + DISP_REG_OVL_INTEN); } static void mtk_ovl_disable_vblank(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle) { writel_relaxed(0x0, comp->regs + DISP_REG_OVL_INTEN); } #endif static int mtk_ovl_io_cmd(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle, enum mtk_ddp_io_cmd io_cmd, void *params); static void mtk_ovl_start(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle) { int ret; unsigned int val; struct mtk_disp_ovl *ovl = comp_to_ovl(comp); const struct compress_info *compr_info = ovl->data->compr_info; unsigned int value = 0, mask = 0; DDPDBG("%s+ %s\n", __func__, mtk_dump_comp_str(comp)); ret = pm_runtime_get_sync(comp->dev); if (ret < 0) DRM_ERROR("Failed to enable power domain: %d\n", ret); mtk_ovl_io_cmd(comp, handle, IRQ_LEVEL_ALL, NULL); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EN, 0x1, 0x1); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_INTEN, 0x61F2, ~0); /* In 6779 we need to set DISP_OVL_FORCE_RELAY_MODE */ if (compr_info && strncmp(compr_info->name, "PVRIC_V3_1", 10) == 0) { val = FBDC_8XE_MODE | FBDC_FILTER_EN; cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_FBDC_CFG1, val, val); } cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_SRC_CON, DISP_OVL_FORCE_RELAY_MODE, DISP_OVL_FORCE_RELAY_MODE); SET_VAL_MASK(value, mask, 1, FLD_RDMA_BURST_CON1_BURST16_EN); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_RDMA_BURST_CON1, value, mask); value = 0; mask = 0; SET_VAL_MASK(value, mask, 1, DATAPATH_CON_FLD_LAYER_SMI_ID_EN); SET_VAL_MASK(value, mask, 1, DATAPATH_CON_FLD_GCLAST_EN); SET_VAL_MASK(value, mask, 1, DATAPATH_CON_FLD_OUTPUT_CLAMP); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_CON, value, mask); #if defined(CONFIG_MACH_MT6873) || defined(CONFIG_MACH_MT6853) \ || defined(CONFIG_MACH_MT6833) || defined(CONFIG_MACH_MT6877) \ || defined(CONFIG_MACH_MT6781) /* Enable feedback real BW consumed from OVL */ cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_GDRDY_PRD, 0xFFFFFFFF, 0xFFFFFFFF); #endif DDPDBG("%s-\n", __func__); } static void mtk_ovl_stop(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle) { int ret; DDPDBG("%s+\n", __func__); ret = pm_runtime_put(comp->dev); if (ret < 0) DRM_ERROR("Failed to disable power domain: %d\n", ret); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_INTEN, 0, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EN, 0x0, 0x1); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_RST, 1, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_INTSTA, 0, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_RST, 0, ~0); comp->qos_bw = 0; comp->fbdc_bw = 0; DDPDBG("%s-\n", __func__); } static void _store_bg_roi(struct mtk_ddp_comp *comp, int h, int w) { struct mtk_disp_ovl *ovl = comp_to_ovl(comp); ovl->bg_h = h; ovl->bg_w = w; } static void _get_bg_roi(struct mtk_ddp_comp *comp, int *h, int *w) { struct mtk_disp_ovl *ovl = comp_to_ovl(comp); *h = ovl->bg_h; *w = ovl->bg_w; } static int mtk_ovl_golden_setting(struct mtk_ddp_comp *comp, struct mtk_ddp_config *cfg, struct cmdq_pkt *handle); static void mtk_ovl_config(struct mtk_ddp_comp *comp, struct mtk_ddp_config *cfg, struct cmdq_pkt *handle) { unsigned int width; if (comp->mtk_crtc->is_dual_pipe) { width = cfg->w / 2; DDPMSG("\n"); } else width = cfg->w; if (cfg->w != 0 && cfg->h != 0) { cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ROI_SIZE, cfg->h << 16 | width, ~0); _store_bg_roi(comp, cfg->h, width); } cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ROI_BGCLR, OVL_ROI_BGCLR, ~0); mtk_ovl_golden_setting(comp, cfg, handle); } static void mtk_ovl_layer_on(struct mtk_ddp_comp *comp, unsigned int idx, unsigned int ext_idx, struct cmdq_pkt *handle) { unsigned int con; if (ext_idx != LYE_NORMAL) { unsigned int con_mask; con_mask = BIT(ext_idx - 1) | (0xFFFF << ((ext_idx - 1) * 4 + 16)); con = BIT(ext_idx - 1) | (idx << ((ext_idx - 1) * 4 + 16)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_RDMA_CTRL(idx), 0x1, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_EXT_CON, con, con_mask); return; } cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_RDMA_CTRL(idx), 0x1, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_SRC_CON, BIT(idx), BIT(idx)); } static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx, unsigned int ext_idx, struct cmdq_pkt *handle) { u32 wcg_mask = 0, wcg_value = 0, sel_value = 0, sel_mask = 0; if (ext_idx != LYE_NORMAL) { SET_VAL_MASK(wcg_value, wcg_mask, 0, FLD_ELn_IGAMMA_EN(ext_idx - 1)); SET_VAL_MASK(wcg_value, wcg_mask, 0, FLD_ELn_GAMMA_EN(ext_idx - 1)); SET_VAL_MASK(wcg_value, wcg_mask, 0, FLD_ELn_CSC_EN(ext_idx - 1)); SET_VAL_MASK(sel_value, sel_mask, 0, FLD_ELn_IGAMMA_SEL(ext_idx - 1)); SET_VAL_MASK(sel_value, sel_mask, 0, FLD_ELn_GAMMA_SEL(ext_idx - 1)); } else { SET_VAL_MASK(wcg_value, wcg_mask, 0, FLD_Ln_IGAMMA_EN(idx)); SET_VAL_MASK(wcg_value, wcg_mask, 0, FLD_Ln_GAMMA_EN(idx)); SET_VAL_MASK(wcg_value, wcg_mask, 0, FLD_Ln_CSC_EN(idx)); SET_VAL_MASK(sel_value, sel_mask, 0, FLD_Ln_IGAMMA_SEL(idx)); SET_VAL_MASK(sel_value, sel_mask, 0, FLD_Ln_GAMMA_SEL(idx)); } cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_WCG_CFG1, wcg_value, wcg_mask); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_WCG_CFG2, sel_value, sel_mask); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_WCG_CFG1, wcg_value, wcg_mask); if (ext_idx != LYE_NORMAL) cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_EXT_CON, 0, BIT(ext_idx - 1) | BIT(ext_idx + 3)); else { cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_CON, 0, BIT(idx + 4)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_SRC_CON, 0, BIT(idx)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_RDMA_CTRL(idx), 0, ~0); } } static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt, uint64_t modifier, unsigned int compress) { switch (fmt) { default: case DRM_FORMAT_RGB565: return OVL_CON_CLRFMT_RGB565(ovl) | (compress ? OVL_CON_BYTE_SWAP : 0UL); case DRM_FORMAT_BGR565: return (unsigned int)OVL_CON_CLRFMT_RGB565(ovl) | OVL_CON_BYTE_SWAP; case DRM_FORMAT_RGB888: return OVL_CON_CLRFMT_RGB888(ovl); case DRM_FORMAT_BGR888: return (unsigned int)OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP; case DRM_FORMAT_RGBX8888: case DRM_FORMAT_RGBA8888: if (modifier & MTK_FMT_PREMULTIPLIED) return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_CLRFMT_MAN; else return OVL_CON_CLRFMT_ARGB8888; case DRM_FORMAT_BGRX8888: case DRM_FORMAT_BGRA8888: if (modifier & MTK_FMT_PREMULTIPLIED) return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP | OVL_CON_CLRFMT_MAN; else return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP; case DRM_FORMAT_XRGB8888: case DRM_FORMAT_ARGB8888: if (modifier & MTK_FMT_PREMULTIPLIED) return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP | OVL_CON_CLRFMT_MAN | OVL_CON_RGB_SWAP; else return OVL_CON_CLRFMT_RGBA8888; case DRM_FORMAT_XBGR8888: case DRM_FORMAT_ABGR8888: if (modifier & MTK_FMT_PREMULTIPLIED) return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_CLRFMT_MAN | OVL_CON_RGB_SWAP; else return OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP; case DRM_FORMAT_UYVY: return OVL_CON_CLRFMT_UYVY(ovl); case DRM_FORMAT_YUYV: return OVL_CON_CLRFMT_YUYV(ovl); case DRM_FORMAT_ABGR2101010: if (modifier & MTK_FMT_PREMULTIPLIED) return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_CLRFMT_MAN | OVL_CON_RGB_SWAP; return OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP; case DRM_FORMAT_ABGR16161616F: if (modifier & MTK_FMT_PREMULTIPLIED) return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_CLRFMT_MAN | OVL_CON_RGB_SWAP; return OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP; case DRM_FORMAT_C8: return OVL_CON_CLRFMT_DIM | OVL_CON_CLRFMT_RGB888(ovl); } } static const char *mtk_ovl_get_transfer_str(enum mtk_ovl_transfer transfer) { if (transfer < 0) { DDPPR_ERR("%s: Invalid ovl transfer:%d\n", __func__, transfer); transfer = 0; } return mtk_ovl_transfer_str[transfer]; } static const char * mtk_ovl_get_colorspace_str(enum mtk_ovl_colorspace colorspace) { return mtk_ovl_colorspace_str[colorspace]; } static enum mtk_ovl_colorspace mtk_ovl_map_cs(enum mtk_drm_dataspace ds) { enum mtk_ovl_colorspace cs = OVL_SRGB; switch (ds & MTK_DRM_DATASPACE_STANDARD_MASK) { case MTK_DRM_DATASPACE_STANDARD_DCI_P3: cs = OVL_P3; break; case MTK_DRM_DATASPACE_STANDARD_ADOBE_RGB: DDPPR_ERR("%s: ovl get cs ADOBE_RGB\n", __func__); case MTK_DRM_DATASPACE_STANDARD_BT2020: DDPPR_ERR("%s: ovl does not support BT2020\n", __func__); default: cs = OVL_SRGB; break; } return cs; } static enum mtk_ovl_transfer mtk_ovl_map_transfer(enum mtk_drm_dataspace ds) { enum mtk_ovl_transfer xfr = OVL_GAMMA_UNKNOWN; switch (ds & MTK_DRM_DATASPACE_TRANSFER_MASK) { case MTK_DRM_DATASPACE_TRANSFER_LINEAR: xfr = OVL_LINEAR; break; case MTK_DRM_DATASPACE_TRANSFER_GAMMA2_6: case MTK_DRM_DATASPACE_TRANSFER_GAMMA2_8: DDPPR_ERR("%s: ovl does not support gamma 2.6/2.8\n", __func__); case MTK_DRM_DATASPACE_TRANSFER_ST2084: case MTK_DRM_DATASPACE_TRANSFER_HLG: DDPPR_ERR("%s: HDR transfer\n", __func__); default: xfr = OVL_GAMMA2_2; break; } return xfr; } static int mtk_ovl_do_transfer(unsigned int idx, enum mtk_drm_dataspace plane_ds, enum mtk_drm_dataspace lcm_ds, bool *gamma_en, bool *igamma_en, u32 *gamma_sel, u32 *igamma_sel) { enum mtk_ovl_transfer xfr_in = OVL_GAMMA2_2, xfr_out = OVL_GAMMA2_2; enum mtk_ovl_colorspace cs_in = OVL_CS_UNKNOWN, cs_out = OVL_CS_UNKNOWN; bool en = false; xfr_in = mtk_ovl_map_transfer(plane_ds); xfr_out = mtk_ovl_map_transfer(lcm_ds); cs_in = mtk_ovl_map_cs(plane_ds); cs_out = mtk_ovl_map_cs(lcm_ds); DDPDBG("%s+ idx:%d transfer:%s->%s\n", __func__, idx, mtk_ovl_get_transfer_str(xfr_in), mtk_ovl_get_transfer_str(xfr_out)); en = xfr_in != OVL_LINEAR && (xfr_in != xfr_out || cs_in != cs_out); if (en) { *igamma_en = true; *igamma_sel = xfr_in; } else *igamma_en = false; en = xfr_out != OVL_LINEAR && (xfr_in != xfr_out || cs_in != cs_out); if (en) { *gamma_en = true; *gamma_sel = xfr_out; } else *gamma_en = false; return 0; } static u32 *mtk_get_ovl_csc(enum mtk_ovl_colorspace in, enum mtk_ovl_colorspace out) { static u32 *ovl_csc[OVL_CS_NUM][OVL_CS_NUM]; static bool inited; if (out < 0) { DDPPR_ERR("%s: Invalid ovl colorspace out:%d\n", __func__, out); out = 0; } if (in < 0) { DDPPR_ERR("%s: Invalid ovl colorspace in:%d\n", __func__, in); in = 0; } if (inited) goto done; ovl_csc[OVL_SRGB][OVL_P3] = sRGB_to_DCI_P3; ovl_csc[OVL_P3][OVL_SRGB] = DCI_P3_to_sRGB; inited = true; done: return ovl_csc[in][out]; } static int mtk_ovl_do_csc(unsigned int idx, enum mtk_drm_dataspace plane_ds, enum mtk_drm_dataspace lcm_ds, bool *csc_en, u32 **csc) { enum mtk_ovl_colorspace in = OVL_SRGB, out = OVL_SRGB; bool en = false; in = mtk_ovl_map_cs(plane_ds); out = mtk_ovl_map_cs(lcm_ds); DDPDBG("%s+ idx:%d csc:%s->%s\n", __func__, idx, mtk_ovl_get_colorspace_str(in), mtk_ovl_get_colorspace_str(out)); en = in != out; if (en) *csc_en = true; else *csc_en = false; if (!en) return 0; if (!csc) { DDPPR_ERR("%s+ invalid csc\n", __func__); return 0; } *csc = mtk_get_ovl_csc(in, out); if (!(*csc)) { DDPPR_ERR("%s+ idx:%d no ovl csc %s to %s, disable csc\n", __func__, idx, mtk_ovl_get_colorspace_str(in), mtk_ovl_get_colorspace_str(out)); *csc_en = false; } return 0; } static enum mtk_drm_dataspace mtk_ovl_map_lcm_color_mode(enum mtk_drm_color_mode cm) { enum mtk_drm_dataspace ds = MTK_DRM_DATASPACE_SRGB; switch (cm) { case MTK_DRM_COLOR_MODE_DISPLAY_P3: ds = MTK_DRM_DATASPACE_DISPLAY_P3; break; default: ds = MTK_DRM_DATASPACE_SRGB; break; } return ds; } static int mtk_ovl_color_manage(struct mtk_ddp_comp *comp, unsigned int idx, struct mtk_plane_state *state, struct cmdq_pkt *handle) { unsigned int lye_idx = 0, ext_lye_idx = 0; struct mtk_plane_pending_state *pending = &state->pending; struct drm_crtc *crtc = state->crtc; struct mtk_drm_private *priv; bool gamma_en = false, igamma_en = false, csc_en = false; u32 gamma_sel = 0, igamma_sel = 0; u32 *csc = NULL; u32 wcg_mask = 0, wcg_value = 0, sel_mask = 0, sel_value = 0, reg = 0; enum mtk_drm_color_mode lcm_cm; enum mtk_drm_dataspace lcm_ds, plane_ds; struct mtk_panel_params *params; int i; if (state->comp_state.comp_id) { lye_idx = state->comp_state.lye_id; ext_lye_idx = state->comp_state.ext_lye_id; } else lye_idx = idx; if (!crtc) goto done; priv = crtc->dev->dev_private; if (!mtk_drm_helper_get_opt(priv->helper_opt, MTK_DRM_OPT_OVL_WCG) || !pending->enable) goto done; params = mtk_drm_get_lcm_ext_params(crtc); if (params) lcm_cm = params->lcm_color_mode; else lcm_cm = MTK_DRM_COLOR_MODE_NATIVE; lcm_ds = mtk_ovl_map_lcm_color_mode(lcm_cm); plane_ds = (enum mtk_drm_dataspace)pending->prop_val[PLANE_PROP_DATASPACE]; DDPDBG("%s+ idx:%d ds:0x%08x->0x%08x\n", __func__, idx, plane_ds, lcm_ds); mtk_ovl_do_transfer(idx, plane_ds, lcm_ds, &gamma_en, &igamma_en, &gamma_sel, &igamma_sel); mtk_ovl_do_csc(idx, plane_ds, lcm_ds, &csc_en, &csc); done: if (ext_lye_idx != LYE_NORMAL) { SET_VAL_MASK(wcg_value, wcg_mask, igamma_en, FLD_ELn_IGAMMA_EN(ext_lye_idx - 1)); SET_VAL_MASK(wcg_value, wcg_mask, gamma_en, FLD_ELn_GAMMA_EN(ext_lye_idx - 1)); SET_VAL_MASK(wcg_value, wcg_mask, csc_en, FLD_ELn_CSC_EN(ext_lye_idx - 1)); SET_VAL_MASK(sel_value, sel_mask, igamma_sel, FLD_ELn_IGAMMA_SEL(ext_lye_idx - 1)); SET_VAL_MASK(sel_value, sel_mask, gamma_sel, FLD_ELn_GAMMA_SEL(ext_lye_idx - 1)); } else { SET_VAL_MASK(wcg_value, wcg_mask, igamma_en, FLD_Ln_IGAMMA_EN(lye_idx)); SET_VAL_MASK(wcg_value, wcg_mask, gamma_en, FLD_Ln_GAMMA_EN(lye_idx)); SET_VAL_MASK(wcg_value, wcg_mask, csc_en, FLD_Ln_CSC_EN(lye_idx)); SET_VAL_MASK(sel_value, sel_mask, igamma_sel, FLD_Ln_IGAMMA_SEL(lye_idx)); SET_VAL_MASK(sel_value, sel_mask, gamma_sel, FLD_Ln_GAMMA_SEL(lye_idx)); } cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_WCG_CFG1, wcg_value, wcg_mask); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_WCG_CFG2, sel_value, sel_mask); if (csc_en) { if (ext_lye_idx != LYE_NORMAL) reg = DISP_REG_OVL_ELn_R2R_PARA(ext_lye_idx - 1); else reg = DISP_REG_OVL_Ln_R2R_PARA(lye_idx); for (i = 0; i < CSC_COEF_NUM; i++) cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + reg + 4 * i, csc[i], ~0); } return 0; } static int mtk_ovl_yuv_matrix_convert(enum mtk_drm_dataspace plane_ds) { int ret = 0; switch (plane_ds & MTK_DRM_DATASPACE_STANDARD_MASK) { case MTK_DRM_DATASPACE_STANDARD_BT601_625: case MTK_DRM_DATASPACE_STANDARD_BT601_625_UNADJUSTED: case MTK_DRM_DATASPACE_STANDARD_BT601_525: case MTK_DRM_DATASPACE_STANDARD_BT601_525_UNADJUSTED: ret = ((plane_ds & MTK_DRM_DATASPACE_RANGE_MASK) == MTK_DRM_DATASPACE_RANGE_FULL) ? OVL_CON_MTX_JPEG_TO_RGB : OVL_CON_MTX_BT601_TO_RGB; break; case MTK_DRM_DATASPACE_STANDARD_BT709: case MTK_DRM_DATASPACE_STANDARD_DCI_P3: case MTK_DRM_DATASPACE_STANDARD_BT2020: ret = OVL_CON_MTX_BT709_TO_RGB; break; case 0: switch (plane_ds & 0xffff) { case MTK_DRM_DATASPACE_JFIF: case MTK_DRM_DATASPACE_BT601_625: case MTK_DRM_DATASPACE_BT601_525: ret = OVL_CON_MTX_BT601_TO_RGB; break; case MTK_DRM_DATASPACE_SRGB_LINEAR: case MTK_DRM_DATASPACE_SRGB: case MTK_DRM_DATASPACE_BT709: ret = OVL_CON_MTX_BT709_TO_RGB; break; } } if (ret) return ret; return OVL_CON_MTX_BT601_TO_RGB; } /* config addr, pitch, src_size */ static void _ovl_common_config(struct mtk_ddp_comp *comp, unsigned int idx, struct mtk_plane_state *state, struct cmdq_pkt *handle) { struct mtk_disp_ovl *ovl = comp_to_ovl(comp); struct mtk_plane_pending_state *pending = &state->pending; unsigned int addr = pending->addr; unsigned int fmt = pending->format; unsigned int pitch = pending->pitch & 0xffff; unsigned int pitch_msb = ((pending->pitch >> 16) & 0xf); unsigned int dst_h = pending->height; unsigned int dst_w = pending->width; unsigned int src_x = pending->src_x; unsigned int src_y = pending->src_y; unsigned int lye_idx = 0, ext_lye_idx = 0; unsigned int src_size = (dst_h << 16) | dst_w; unsigned int offset = 0; unsigned int clip = 0; unsigned int buf_size = 0; int rotate = 0; #ifdef CONFIG_MTK_SVP_ON_MTEE_SUPPORT unsigned int domain_val = 0, domain_mask = 0; #endif if (fmt == DRM_FORMAT_YUYV || fmt == DRM_FORMAT_YVYU || fmt == DRM_FORMAT_UYVY || fmt == DRM_FORMAT_VYUY) { if (src_x % 2) { src_x -= 1; dst_w += 1; clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_LEFT, 1); } if ((src_x + dst_w) % 2) { dst_w += 1; clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_RIGHT, 1); } } #ifdef CONFIG_MTK_LCM_PHYSICAL_ROTATION_HW if (drm_crtc_index(&comp->mtk_crtc->base) == 0) rotate = 1; #endif if (rotate) offset = (src_x + dst_w) * drm_format_plane_cpp(fmt, 0) + (src_y + dst_h - 1) * pitch - 1; else offset = src_x * drm_format_plane_cpp(fmt, 0) + src_y * pitch; addr += offset; if (state->comp_state.comp_id) { lye_idx = state->comp_state.lye_id; ext_lye_idx = state->comp_state.ext_lye_id; } else lye_idx = idx; src_size = (dst_h << 16) | dst_w; buf_size = (dst_h - 1) * pending->pitch + dst_w * drm_format_plane_cpp(fmt, 0); if (ext_lye_idx != LYE_NORMAL) { unsigned int id = ext_lye_idx - 1; cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_PITCH_MSB(id), pitch_msb, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_PITCH(id), pitch, ~0); #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) if (comp->mtk_crtc->sec_on) { u32 size, meta_type, regs_addr; size = buf_size; regs_addr = comp->regs_pa + DISP_REG_OVL_EL_ADDR(id); if (state->pending.is_sec && pending->addr) { meta_type = CMDQ_IWC_H_2_MVA; cmdq_sec_pkt_write_reg(handle, regs_addr, pending->addr, meta_type, offset, size, 0, pending->sec_id); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, BIT(id + EXT_SECURE_OFFSET), BIT(id + EXT_SECURE_OFFSET)); #else SET_VAL_MASK(domain_val, domain_mask, OVL_LAYER_SVP_DOMAIN_INDEX, OVL_LAYER_ELx_DOMAIN(id)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,EL%dSet dom(0x%x,0x%x,0x%x),addr(0x%x+0x%x),sz:%d\n", __func__, __LINE__, id, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask, &pending->addr, offset, size); #endif } else { cmdq_pkt_write(handle, comp->cmdq_base, regs_addr, addr, ~0); DDPDBG("%s:%d, addr:0x%x, size:%d\n", __func__, __LINE__, addr, size); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, 0, BIT(id + EXT_SECURE_OFFSET)); #else SET_VAL_MASK(domain_val, domain_mask, 0, OVL_LAYER_ELx_DOMAIN(id)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,EL%d,clr dom(0x%x,0x%x,0x%x),addr:0x%x,sz:%d\n", __func__, __LINE__, id, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask, addr, size); #endif } } else { #endif cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_ADDR(id), addr, ~0); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, 0, BIT(id + EXT_SECURE_OFFSET)); #else SET_VAL_MASK(domain_val, domain_mask, 0, OVL_LAYER_ELx_DOMAIN(id)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,EL%d(0x%x,0x%x,0x%x),clr dom,addr:0x%x,sz:%d\n", __func__, __LINE__, id, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask, addr, 0); #endif #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) } #endif cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_SRC_SIZE(id), src_size, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_CLIP(id), clip, ~0); } else { cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_PITCH_MSB(lye_idx), pitch_msb, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_PITCH(lye_idx), pitch, ~0); #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) if (comp->mtk_crtc->sec_on) { u32 size, meta_type, regs_addr; size = buf_size; regs_addr = comp->regs_pa + DISP_REG_OVL_ADDR(ovl, lye_idx); if (state->pending.is_sec && pending->addr) { meta_type = CMDQ_IWC_H_2_MVA; cmdq_sec_pkt_write_reg(handle, regs_addr, pending->addr, meta_type, offset, size, 0, pending->sec_id); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, BIT(lye_idx), BIT(lye_idx)); DDPDBG("%s:%d, addr:(%pad,0x%x), size:%d\n", __func__, __LINE__, &pending->addr, offset, size); #else SET_VAL_MASK(domain_val, domain_mask, OVL_LAYER_SVP_DOMAIN_INDEX, OVL_LAYER_Lx_DOMAIN(lye_idx)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,L%dSet dom(0x%x,0x%x,0x%x),addr:(%pad,0x%x),sz:%d\n", __func__, __LINE__, lye_idx, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask, &pending->addr, offset, size); #endif } else { cmdq_pkt_write(handle, comp->cmdq_base, regs_addr, addr, ~0); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, 0, BIT(lye_idx)); #else SET_VAL_MASK(domain_val, domain_mask, 0, OVL_LAYER_Lx_DOMAIN(lye_idx)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,L%dClr dom(0x%x,0x%x,0x%x),addr:(%pad,0x%x),sz:%d\n", __func__, __LINE__, lye_idx, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask, &pending->addr, offset, size); #endif } } else { #endif cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ADDR(ovl, lye_idx), addr, ~0); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, 0, BIT(lye_idx)); #else SET_VAL_MASK(domain_val, domain_mask, 0, OVL_LAYER_Lx_DOMAIN(lye_idx)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,L%d clr dom(0x%x,0x%x,0x%x)addr(%pad,0x%x),sz:%d\n", __func__, __LINE__, lye_idx, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask, &pending->addr, offset, 0); #endif #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) } #endif cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_SRC_SIZE(lye_idx), src_size, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_CLIP(lye_idx), clip, ~0); } } static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx, struct mtk_plane_state *state, struct cmdq_pkt *handle) { struct mtk_disp_ovl *ovl = comp_to_ovl(comp); struct mtk_plane_pending_state *pending = &state->pending; int rotate = 0; unsigned int fmt = pending->format; unsigned int offset; unsigned int con; unsigned int lye_idx = 0, ext_lye_idx = 0; unsigned int alpha; unsigned int alpha_con; unsigned int value = 0, mask = 0, fmt_ex = 0; unsigned long long temp_bw; unsigned int dim_color; /* handle dim layer for compression flag & color dim*/ if (fmt == DRM_FORMAT_C8) { pending->prop_val[PLANE_PROP_COMPRESS] = 0; dim_color = pending->prop_val[PLANE_PROP_DIM_COLOR]; } else { dim_color = 0xff000000; } /* handle buffer de-compression */ if (ovl->data->compr_info && ovl->data->compr_info->l_config) { if (ovl->data->compr_info->l_config(comp, idx, state, handle)) { DDPPR_ERR("wrong fbdc input config\n"); return; } } else { /* Config common register which would be different according * with * this layer is compressed or not, i.e.: addr, pitch... */ _ovl_common_config(comp, idx, state, handle); } #ifdef CONFIG_MTK_LCM_PHYSICAL_ROTATION_HW if (drm_crtc_index(&comp->mtk_crtc->base) == 0) rotate = 1; #endif if (state->comp_state.comp_id) { lye_idx = state->comp_state.lye_id; ext_lye_idx = state->comp_state.ext_lye_id; } else lye_idx = idx; DDPINFO("%s+ idx:%d, enable:%d, fmt:0x%x\n", __func__, idx, pending->enable, pending->format); if (!pending->enable) mtk_ovl_layer_off(comp, lye_idx, ext_lye_idx, handle); mtk_ovl_color_manage(comp, idx, state, handle); alpha_con = pending->prop_val[PLANE_PROP_ALPHA_CON]; alpha = 0xFF & pending->prop_val[PLANE_PROP_PLANE_ALPHA]; if (alpha == 0xFF && (fmt == DRM_FORMAT_RGBX8888 || fmt == DRM_FORMAT_BGRX8888 || fmt == DRM_FORMAT_XRGB8888 || fmt == DRM_FORMAT_XBGR8888)) alpha_con = 0; con = ovl_fmt_convert(ovl, fmt, state->pending.modifier, pending->prop_val[PLANE_PROP_COMPRESS]); con |= (alpha_con << 8) | alpha; if (fmt == DRM_FORMAT_UYVY || fmt == DRM_FORMAT_YUYV) { unsigned int prop = pending->prop_val[PLANE_PROP_DATASPACE]; con |= mtk_ovl_yuv_matrix_convert((enum mtk_drm_dataspace)prop); } if (!pending->addr) con |= BIT(28); DDPINFO("%s+ id %d, idx:%d, enable:%d, fmt:0x%x, ", __func__, comp->id, idx, pending->enable, pending->format); DDPINFO("addr 0x%lx, compr %d, con 0x%x\n", pending->addr, pending->prop_val[PLANE_PROP_COMPRESS], con); if (rotate) { unsigned int bg_w = 0, bg_h = 0; _get_bg_roi(comp, &bg_h, &bg_w); offset = ((bg_h - pending->height - pending->dst_y) << 16) + (bg_w - pending->width - pending->dst_x); DDPINFO("bg(%d,%d) (%d,%d,%dx%d)\n", bg_w, bg_h, pending->dst_x, pending->dst_y, pending->width, pending->height); con |= (CON_HORI_FLIP + CON_VERTICAL_FLIP); } else { offset = (pending->dst_y << 16) | pending->dst_x; } if (fmt == DRM_FORMAT_ABGR2101010) fmt_ex = 1; else if (fmt == DRM_FORMAT_ABGR16161616F) fmt_ex = 3; if (ext_lye_idx != LYE_NORMAL) { unsigned int id = ext_lye_idx - 1; SET_VAL_MASK(value, mask, fmt_ex, FLD_ELn_CLRFMT_NB(id)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_CLRFMT_EXT, value, mask); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_CON(id), con, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_OFFSET(id), offset, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL0_CLR(id), dim_color, ~0); } else { SET_VAL_MASK(value, mask, fmt_ex, FLD_Ln_CLRFMT_NB(lye_idx)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_CLRFMT_EXT, value, mask); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_CON(lye_idx), con, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_OFFSET(lye_idx), offset, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_L0_CLR(lye_idx), dim_color, ~0); } if (pending->enable) { struct drm_crtc *crtc; struct mtk_drm_crtc *mtk_crtc; u32 vrefresh; u32 ratio_tmp = 0; unsigned int vact = 0; unsigned int vtotal = 0; struct mtk_ddp_comp *output_comp; mtk_crtc = comp->mtk_crtc; crtc = &mtk_crtc->base; output_comp = mtk_ddp_comp_request_output(comp->mtk_crtc); vrefresh = crtc->state->adjusted_mode.vrefresh; if (output_comp && ((output_comp->id == DDP_COMPONENT_DSI0) || (output_comp->id == DDP_COMPONENT_DSI1)) && !(mtk_dsi_is_cmd_mode(output_comp))) { vtotal = crtc->state->adjusted_mode.vtotal; vact = crtc->state->adjusted_mode.vdisplay; ratio_tmp = vtotal * 100 / vact; } else ratio_tmp = 125; DDPDBG("%s, vrefresh=%d, ratio_tmp=%d\n", __func__, vrefresh, ratio_tmp); DDPDBG("%s, vtotal=%d, vact=%d\n", __func__, vtotal, vact); if (drm_crtc_index(&comp->mtk_crtc->base) == 2 && (fmt == DRM_FORMAT_RGBA8888 || fmt == DRM_FORMAT_BGRA8888 || fmt == DRM_FORMAT_ARGB8888 || fmt == DRM_FORMAT_ABGR8888)) cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ROI_BGCLR, 0x0, ~0); else cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ROI_BGCLR, OVL_ROI_BGCLR, ~0); mtk_ovl_layer_on(comp, lye_idx, ext_lye_idx, handle); /*constant color :non RDMA source*/ /* TODO: cause RPO abnormal */ // if (!pending->addr) // cmdq_pkt_write(handle, comp->cmdq_base, // comp->regs_pa + DISP_REG_OVL_RDMA_CTRL(idx), 0x0, ~0); /* TODO: consider FBDC */ /* SRT BW (one layer) = * layer_w * layer_h * bpp * vrefresh * max fps blanking_ratio * Sum_SRT(all layer) *= 1.33 */ temp_bw = (unsigned long long)pending->width * pending->height; temp_bw *= mtk_get_format_bpp(fmt); do_div(temp_bw, 1000); temp_bw *= ratio_tmp; do_div(temp_bw, 100); temp_bw = temp_bw * vrefresh; do_div(temp_bw, 1000); DDPDBG("comp %d bw %llu vtotal:%d vact:%d\n", comp->id, temp_bw, vtotal, vact); if (pending->prop_val[PLANE_PROP_COMPRESS]) comp->fbdc_bw += temp_bw; else comp->qos_bw += temp_bw; mtk_dprec_mmp_dump_ovl_layer(state); } } static bool compr_l_config_PVRIC_V3_1(struct mtk_ddp_comp *comp, unsigned int idx, struct mtk_plane_state *state, struct cmdq_pkt *handle) { /* input config */ struct mtk_disp_ovl *ovl = comp_to_ovl(comp); struct mtk_plane_pending_state *pending = &state->pending; unsigned int addr = pending->addr; unsigned int pitch = pending->pitch & 0xffff; unsigned int vpitch = pending->prop_val[PLANE_PROP_VPITCH]; unsigned int dst_h = pending->height; unsigned int dst_w = pending->width; unsigned int src_x = pending->src_x, src_y = pending->src_y; unsigned int src_w = pending->width, src_h = pending->height; unsigned int fmt = pending->format; unsigned int Bpp = drm_format_plane_cpp(fmt, 0); unsigned int lye_idx = 0, ext_lye_idx = 0; unsigned int compress = pending->prop_val[PLANE_PROP_COMPRESS]; int rotate = 0; /* variable to do calculation */ unsigned int tile_w = 16, tile_h = 4; unsigned int tile_body_size = tile_w * tile_h * Bpp; unsigned int src_x_align, src_y_align; unsigned int src_w_align, src_h_align; unsigned int header_offset, tile_offset; unsigned int buf_addr; unsigned int src_buf_tile_num = 0; unsigned int buf_size = 0; unsigned int buf_total_size = 0; /* variable to config into register */ unsigned int lx_fbdc_en; unsigned int lx_addr, lx_pitch; unsigned int lx_hdr_addr, lx_hdr_pitch; unsigned int lx_clip, lx_src_size; #ifdef CONFIG_MTK_SVP_ON_MTEE_SUPPORT unsigned int domain_val = 0, domain_mask = 0; #endif #ifdef CONFIG_MTK_LCM_PHYSICAL_ROTATION_HW if (drm_crtc_index(&comp->mtk_crtc->base) == 0) rotate = 1; #endif if (state->comp_state.comp_id) { lye_idx = state->comp_state.lye_id; ext_lye_idx = state->comp_state.ext_lye_id; } else lye_idx = idx; /* 1. cal & set OVL_LX_FBDC_EN */ lx_fbdc_en = (compress != 0); if (ext_lye_idx != LYE_NORMAL) cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_EXT_CON, lx_fbdc_en << (ext_lye_idx + 3), BIT(ext_lye_idx + 3)); else cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_CON, lx_fbdc_en << (lye_idx + 4), BIT(lye_idx + 4)); /* if no compress, do common config and return */ if (compress == 0) { _ovl_common_config(comp, idx, state, handle); return 0; } /* 2. pre-calculation */ if (fmt == DRM_FORMAT_RGB888 || fmt == DRM_FORMAT_BGR888) { pitch = (4 * pitch / 3); Bpp = 4; } src_buf_tile_num = ALIGN_TO(pitch / 4, tile_w) * ALIGN_TO(vpitch, tile_h); src_buf_tile_num /= (tile_w * tile_h); header_offset = (src_buf_tile_num + 255) / 256 * 128; buf_addr = addr + header_offset; src_x_align = (src_x / tile_w) * tile_w; src_w_align = (1 + (src_x + src_w - 1) / tile_w) * tile_w - src_x_align; src_y_align = (src_y / tile_h) * tile_h; src_h_align = (1 + (src_y + src_h - 1) / tile_h) * tile_h - src_y_align; if (rotate) tile_offset = (src_x_align + src_w_align - tile_w) / tile_w + (pitch / tile_w / 4) * (src_y_align + src_h_align - tile_h) / tile_h; else tile_offset = src_x_align / tile_w + (pitch / tile_w / 4) * src_y_align / tile_h; /* 3. cal OVL_LX_ADDR * OVL_LX_PITCH */ lx_addr = buf_addr + tile_offset * 256; lx_pitch = pitch * tile_h; /* 4. cal OVL_LX_HDR_ADDR, OVL_LX_HDR_PITCH */ lx_hdr_addr = buf_addr - (tile_offset / 2) - 1; lx_hdr_pitch = (pitch / tile_w / 8) | (((pitch / tile_w / 4) % 2) << 16) | (((tile_offset + 1) % 2) << 20); /* 5. calculate OVL_LX_SRC_SIZE */ lx_src_size = (src_h_align << 16) | src_w_align; /* 6. calculate OVL_LX_CLIP */ lx_clip = 0; if (rotate) { if (src_x > src_x_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_RIGHT, src_x - src_x_align); if (src_x + src_w < src_x_align + src_w_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_LEFT, src_x_align + src_w_align - src_x - src_w); if (src_y > src_y_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_BOTTOM, src_y - src_y_align); if (src_y + src_h < src_y_align + src_h_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_TOP, src_y_align + src_h_align - src_y - src_h); } else { if (src_x > src_x_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_LEFT, src_x - src_x_align); if (src_x + src_w < src_x_align + src_w_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_RIGHT, src_x_align + src_w_align - src_x - src_w); if (src_y > src_y_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_TOP, src_y - src_y_align); if (src_y + src_h < src_y_align + src_h_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_BOTTOM, src_y_align + src_h_align - src_y - src_h); } /* 7. config register */ buf_size = (dst_h - 1) * pending->pitch + dst_w * drm_format_plane_cpp(fmt, 0); buf_total_size = header_offset + src_buf_tile_num * tile_body_size; if (ext_lye_idx != LYE_NORMAL) { unsigned int id = ext_lye_idx - 1; #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) if (comp->mtk_crtc->sec_on) { u32 size, meta_type, regs_addr; regs_addr = comp->regs_pa + DISP_REG_OVL_EL_ADDR(id); if (state->pending.is_sec && pending->addr) { size = buf_size; meta_type = CMDQ_IWC_H_2_MVA; cmdq_sec_pkt_write_reg(handle, regs_addr, pending->addr, meta_type, 0, size, 0, pending->sec_id); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, BIT(id + EXT_SECURE_OFFSET), BIT(id + EXT_SECURE_OFFSET)); DDPDBG("%s:%d, addr:%pad, size:%d\n", __func__, __LINE__, &pending->addr, size); #else SET_VAL_MASK(domain_val, domain_mask, OVL_LAYER_SVP_DOMAIN_INDEX, OVL_LAYER_ELx_DOMAIN(id)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,EL%d set dom(0x%x,0x%x,0x%x) addr:%pad,sz:%d\n", __func__, __LINE__, id, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask, &pending->addr, size); #endif } else { cmdq_pkt_write(handle, comp->cmdq_base, regs_addr, lx_addr, ~0); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, 0, BIT(id + EXT_SECURE_OFFSET)); #else SET_VAL_MASK(domain_val, domain_mask, 0, OVL_LAYER_ELx_DOMAIN(id)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,EL%d clear dom(0x%x, 0x%x, 0x%x) addr:%pad,sz:%d\n", __func__, __LINE__, id, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask, &pending->addr, size); #endif } } else { #endif cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_ADDR(id), lx_addr, ~0); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, 0, BIT(id + EXT_SECURE_OFFSET)); #else SET_VAL_MASK(domain_val, domain_mask, 0, OVL_LAYER_ELx_DOMAIN(id)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,EL%d clr dom(0x%x,0x%x,0x%x) addr:%pad,sz:%d\n", __func__, __LINE__, id, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask, &pending->addr, 0); #endif #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) } #endif cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_PITCH(id), lx_pitch, 0xffff); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_SRC_SIZE(id), lx_src_size, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_CLIP(id), lx_clip, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ELX_HDR_ADDR(id), lx_hdr_addr, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ELX_HDR_PITCH(id), lx_hdr_pitch, ~0); } else { #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) if (comp->mtk_crtc->sec_on) { u32 size, meta_type, regs_addr; regs_addr = comp->regs_pa + DISP_REG_OVL_ADDR(ovl, lye_idx); if (state->pending.is_sec && pending->addr) { size = buf_size; meta_type = CMDQ_IWC_H_2_MVA; cmdq_sec_pkt_write_reg(handle, regs_addr, pending->addr, meta_type, 0, size, 0, pending->sec_id); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, BIT(lye_idx), BIT(lye_idx)); DDPDBG("%s:%d, addr:%pad, size:%d\n", __func__, __LINE__, &pending->addr, size); #else SET_VAL_MASK(domain_val, domain_mask, OVL_LAYER_SVP_DOMAIN_INDEX, OVL_LAYER_Lx_DOMAIN(lye_idx)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,L%d set dom(0x%x,0x%x,0x%x) addr:%pad,sz:%d\n", __func__, __LINE__, lye_idx, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask, &pending->addr, size); #endif } else { cmdq_pkt_write(handle, comp->cmdq_base, regs_addr, lx_addr, ~0); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, 0, BIT(lye_idx)); #else SET_VAL_MASK(domain_val, domain_mask, 0, OVL_LAYER_Lx_DOMAIN(lye_idx)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,L%d clear dom(0x%x,0x%x,0x%x) addr:%pad,sz:%d\n", __func__, __LINE__, lye_idx, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask, &pending->addr, size); #endif } } else { #endif cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ADDR(ovl, lye_idx), lx_addr, ~0); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, 0, BIT(lye_idx)); #else SET_VAL_MASK(domain_val, domain_mask, 0, OVL_LAYER_Lx_DOMAIN(lye_idx)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,L%d clr dom(0x%x,0x%x,0x%x) addr:%pad,sz:%d\n", __func__, __LINE__, lye_idx, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask, &pending->addr, 0); #endif #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) } #endif cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_PITCH(lye_idx), lx_pitch, 0xffff); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_SRC_SIZE(lye_idx), lx_src_size, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_CLIP(lye_idx), lx_clip, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_LX_HDR_ADDR(lye_idx), lx_hdr_addr, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_LX_HDR_PITCH(lye_idx), lx_hdr_pitch, ~0); } return 0; } static bool compr_l_config_AFBC_V1_2(struct mtk_ddp_comp *comp, unsigned int idx, struct mtk_plane_state *state, struct cmdq_pkt *handle) { /* input config */ struct mtk_disp_ovl *ovl = comp_to_ovl(comp); struct mtk_plane_pending_state *pending = &state->pending; unsigned int addr = pending->addr; unsigned int pitch = pending->pitch & 0xffff; unsigned int vpitch = pending->prop_val[PLANE_PROP_VPITCH]; unsigned int src_x = pending->src_x, src_y = pending->src_y; unsigned int src_w = pending->width, src_h = pending->height; unsigned int fmt = pending->format; unsigned int Bpp = drm_format_plane_cpp(fmt, 0); unsigned int lye_idx = 0, ext_lye_idx = 0; unsigned int compress = pending->prop_val[PLANE_PROP_COMPRESS]; int rotate = 0; /* variable to do calculation */ unsigned int tile_w = AFBC_V1_2_TILE_W; unsigned int tile_h = AFBC_V1_2_TILE_H; unsigned int tile_body_size = tile_w * tile_h * Bpp; unsigned int dst_h = pending->height; unsigned int dst_w = pending->width; unsigned int src_x_align, src_w_align; unsigned int src_y_align, src_y_half_align; unsigned int src_y_end_align, src_y_end_half_align; unsigned int src_h_align, src_h_half_align = 0; unsigned int header_offset, tile_offset; unsigned int buf_addr; unsigned int src_buf_tile_num = 0; unsigned int buf_size = 0; unsigned int buf_total_size = 0; /* variable to config into register */ unsigned int lx_fbdc_en; unsigned int lx_addr, lx_pitch; unsigned int lx_hdr_addr, lx_hdr_pitch; unsigned int lx_clip, lx_src_size; unsigned int lx_2nd_subbuf = 0; unsigned int lx_pitch_msb = 0; #ifdef CONFIG_MTK_SVP_ON_MTEE_SUPPORT unsigned int domain_val = 0, domain_mask = 0; #endif DDPDBG("%s:%d, addr:0x%x, pitch:%d, vpitch:%d\n", __func__, __LINE__, addr, pitch, vpitch); DDPDBG("src:(%d,%d,%d,%d), fmt:%d, Bpp:%d, compress:%d\n", src_x, src_y, src_w, src_h, fmt, Bpp, compress); #ifdef CONFIG_MTK_LCM_PHYSICAL_ROTATION_HW if (drm_crtc_index(&comp->mtk_crtc->base) == 0) rotate = 1; #endif if (state->comp_state.comp_id) { lye_idx = state->comp_state.lye_id; ext_lye_idx = state->comp_state.ext_lye_id; } else lye_idx = idx; /* 1. cal & set OVL_LX_FBDC_EN */ lx_fbdc_en = (compress != 0); if (ext_lye_idx != LYE_NORMAL) cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_EXT_CON, lx_fbdc_en << (ext_lye_idx + 3), BIT(ext_lye_idx + 3)); else cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_CON, lx_fbdc_en << (lye_idx + 4), BIT(lye_idx + 4)); /* if no compress, do common config and return */ if (compress == 0) { _ovl_common_config(comp, idx, state, handle); return 0; } if (Bpp == 0) { DDPDBG("%s fail, no Bpp info\n", __func__); return 0; } /* 2. pre-calculation */ src_buf_tile_num = ALIGN_TO(pitch / Bpp, tile_w) * ALIGN_TO(vpitch, tile_h); src_buf_tile_num /= (tile_w * tile_h); header_offset = ALIGN_TO( src_buf_tile_num * AFBC_V1_2_HEADER_SIZE_PER_TILE_BYTES, AFBC_V1_2_HEADER_ALIGN_BYTES); buf_addr = addr + header_offset; /* calculate for alignment */ src_x_align = (src_x / tile_w) * tile_w; src_w_align = (1 + (src_x + src_w - 1) / tile_w) * tile_w - src_x_align; /* src_y_half_align, src_y_end_half_align, * the start y offset and stop y offset if half tile align * such as 0 and 3, then the src_h_align is 4 */ src_y_align = (src_y / tile_h) * tile_h; src_y_end_align = (1 + (src_y + src_h - 1) / tile_h) * tile_h - 1; src_h_align = src_y_end_align - src_y_align + 1; src_y_half_align = (src_y / (tile_h >> 1)) * (tile_h >> 1); src_y_end_half_align = (1 + (src_y + src_h - 1) / (tile_h >> 1)) * (tile_h >> 1) - 1; src_h_half_align = src_y_end_half_align - src_y_half_align + 1; if (rotate) { tile_offset = (src_x_align + src_w_align - tile_w) / tile_w + (pitch / tile_w / Bpp) * (src_y_align + src_h_align - tile_h) / tile_h; if (src_y_end_align == src_y_end_half_align) lx_2nd_subbuf = 1; } else { tile_offset = src_x_align / tile_w + (pitch / tile_w / Bpp) * src_y_align / tile_h; if (src_y_align != src_y_half_align) lx_2nd_subbuf = 1; } /* 3. cal OVL_LX_ADDR * OVL_LX_PITCH */ lx_addr = buf_addr + tile_offset * tile_body_size; lx_pitch = ((pitch * tile_h) & 0xFFFF); lx_pitch_msb = (REG_FLD_VAL((L_PITCH_MSB_FLD_YUV_TRANS), (1)) | REG_FLD_VAL((L_PITCH_MSB_FLD_2ND_SUBBUF), (lx_2nd_subbuf)) | REG_FLD_VAL((L_PITCH_MSB_FLD_SRC_PITCH_MSB), ((pitch * tile_h) >> 16) & 0xF)); /* 4. cal OVL_LX_HDR_ADDR, OVL_LX_HDR_PITCH */ lx_hdr_addr = addr + tile_offset * AFBC_V1_2_HEADER_SIZE_PER_TILE_BYTES; lx_hdr_pitch = pitch / tile_w / Bpp * AFBC_V1_2_HEADER_SIZE_PER_TILE_BYTES; /* 5. calculate OVL_LX_SRC_SIZE, RGB565 use layout 4, src_h needs align to tile_h*/ if (fmt != DRM_FORMAT_RGB565 && fmt != DRM_FORMAT_BGR565) { src_h_align = src_h_half_align; src_y_align = src_y_half_align; } lx_src_size = (src_h_align << 16) | src_w_align; /* 6. calculate OVL_LX_CLIP */ lx_clip = 0; if (rotate) { if (src_x > src_x_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_RIGHT, src_x - src_x_align); if (src_x + src_w < src_x_align + src_w_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_LEFT, src_x_align + src_w_align - src_x - src_w); if (src_y > src_y_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_BOTTOM, src_y - src_y_align); if (src_y + src_h < src_y_align + src_h_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_TOP, src_y_align + src_h_align - src_y - src_h); } else { if (src_x > src_x_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_LEFT, src_x - src_x_align); if (src_x + src_w < src_x_align + src_w_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_RIGHT, src_x_align + src_w_align - src_x - src_w); if (src_y > src_y_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_TOP, src_y - src_y_align); if (src_y + src_h < src_y_align + src_h_align) lx_clip |= REG_FLD_VAL(OVL_L_CLIP_FLD_BOTTOM, src_y_align + src_h_align - src_y - src_h); } /* 7. config register */ buf_size = (dst_h - 1) * pitch + dst_w * Bpp; buf_total_size = header_offset + src_buf_tile_num * tile_body_size; if (ext_lye_idx != LYE_NORMAL) { unsigned int id = ext_lye_idx - 1; unsigned int regs_addr, hdr_addr; regs_addr = comp->regs_pa + DISP_REG_OVL_EL_ADDR(id); hdr_addr = comp->regs_pa + DISP_REG_OVL_ELX_HDR_ADDR(id); #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) if (comp->mtk_crtc->sec_on && state->pending.is_sec) { u32 size, meta_type; u32 addr_offset; size = buf_size; meta_type = CMDQ_IWC_H_2_MVA; addr_offset = header_offset + tile_offset * tile_body_size; cmdq_sec_pkt_write_reg(handle, regs_addr, pending->addr, meta_type, addr_offset, size, 0, pending->sec_id); addr_offset = tile_offset * AFBC_V1_2_HEADER_SIZE_PER_TILE_BYTES; cmdq_sec_pkt_write_reg(handle, hdr_addr, pending->addr, meta_type, addr_offset, size, 0, pending->sec_id); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, BIT(id + EXT_SECURE_OFFSET), BIT(id + EXT_SECURE_OFFSET)); DDPDBG("%s:%d, addr:%pad, size:%d\n", __func__, __LINE__, &pending->addr, size); #else SET_VAL_MASK(domain_val, domain_mask, OVL_LAYER_SVP_DOMAIN_INDEX, OVL_LAYER_ELx_DOMAIN(id)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,EL%d set dom(0x%x,0x%x,0x%x) addr:%pad,sz:%d\n", __func__, __LINE__, id, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask, &pending->addr, size); #endif } else { #endif cmdq_pkt_write(handle, comp->cmdq_base, regs_addr, lx_addr, ~0); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, 0, BIT(id + EXT_SECURE_OFFSET)); #else SET_VAL_MASK(domain_val, domain_mask, 0, OVL_LAYER_ELx_DOMAIN(id)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,EL%d clr dom(0x%x,0x%x,0x%x), addr:%pad,sz:%d\n", __func__, __LINE__, id, comp->regs_pa + OVL_LAYER_EXT_DOMAIN, domain_val, domain_mask, &pending->addr, 0); #endif cmdq_pkt_write(handle, comp->cmdq_base, hdr_addr, lx_hdr_addr, ~0); #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) } #endif cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_PITCH_MSB(id), lx_pitch_msb, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_PITCH(id), lx_pitch, 0xffff); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_SRC_SIZE(id), lx_src_size, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_EL_CLIP(id), lx_clip, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ELX_HDR_PITCH(id), lx_hdr_pitch, ~0); } else { unsigned int regs_addr, hdr_addr; regs_addr = comp->regs_pa + DISP_REG_OVL_ADDR(ovl, lye_idx); hdr_addr = comp->regs_pa + DISP_REG_OVL_LX_HDR_ADDR(lye_idx); #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) if (comp->mtk_crtc->sec_on && state->pending.is_sec) { u32 size, meta_type, addr_offset; size = buf_size; meta_type = CMDQ_IWC_H_2_MVA; addr_offset = header_offset + tile_offset * tile_body_size; cmdq_sec_pkt_write_reg(handle, regs_addr, pending->addr, meta_type, addr_offset, size, 0, pending->sec_id); addr_offset = tile_offset * AFBC_V1_2_HEADER_SIZE_PER_TILE_BYTES; cmdq_sec_pkt_write_reg(handle, hdr_addr, pending->addr, meta_type, addr_offset, size, 0, pending->sec_id); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, BIT(lye_idx), BIT(lye_idx)); DDPDBG("%s:%d, addr:%pad, size:%d\n", __func__, __LINE__, &pending->addr, size); #else SET_VAL_MASK(domain_val, domain_mask, OVL_LAYER_SVP_DOMAIN_INDEX, OVL_LAYER_Lx_DOMAIN(lye_idx)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,L%d set dom(0x%x,0x%x,0x%x) addr:%pad,sz:%d\n", __func__, __LINE__, lye_idx, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask, &pending->addr, size); #endif } else { #endif cmdq_pkt_write(handle, comp->cmdq_base, regs_addr, lx_addr, ~0); #ifndef CONFIG_MTK_SVP_ON_MTEE_SUPPORT cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_SECURE, 0, BIT(lye_idx)); #else SET_VAL_MASK(domain_val, domain_mask, 0, OVL_LAYER_Lx_DOMAIN(lye_idx)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask); DDPINFO("%s:%d,L%d clr dom(0x%x,0x%x,0x%x) addr:%pad,sz:%d\n", __func__, __LINE__, lye_idx, comp->regs_pa + OVL_LAYER_DOMAIN, domain_val, domain_mask, &pending->addr, 0); #endif cmdq_pkt_write(handle, comp->cmdq_base, hdr_addr, lx_hdr_addr, ~0); #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT) } #endif cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_PITCH_MSB(lye_idx), lx_pitch_msb, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_PITCH(lye_idx), lx_pitch, 0xffff); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_SRC_SIZE(lye_idx), lx_src_size, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_CLIP(lye_idx), lx_clip, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_LX_HDR_PITCH(lye_idx), lx_hdr_pitch, ~0); } return 0; } static int _ovl_UFOd_in(struct mtk_ddp_comp *comp, int connect, struct cmdq_pkt *handle) { unsigned int value = 0, mask = 0; if (!connect) { cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_SRC_CON, 0, BIT(4)); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_LC_CON, 0, ~0); return 0; } SET_VAL_MASK(value, mask, 2, L_CON_FLD_LSRC); SET_VAL_MASK(value, mask, 0, L_CON_FLD_AEN); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_LC_CON, value, mask); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_LC_SRC_SEL, 0, 0x7); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_SRC_CON, 0x10, 0x10); return 0; } static void mtk_ovl_addon_rsz_config(struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id prev, enum mtk_ddp_comp_id next, struct mtk_rect rsz_src_roi, struct mtk_rect rsz_dst_roi, struct cmdq_pkt *handle) { if (prev == DDP_COMPONENT_RSZ0 || prev == DDP_COMPONENT_RSZ1) { int lc_x = rsz_dst_roi.x, lc_y = rsz_dst_roi.y; int lc_w = rsz_dst_roi.width, lc_h = rsz_dst_roi.height; #ifdef CONFIG_MTK_LCM_PHYSICAL_ROTATION_HW { int bg_w, bg_h; _get_bg_roi(comp, &bg_h, &bg_w); lc_y = bg_h - lc_h - lc_y; lc_x = bg_w - lc_w - lc_x; } #endif _ovl_UFOd_in(comp, 1, handle); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_LC_OFFSET, ((lc_y << 16) | lc_x), ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_LC_SRC_SIZE, ((lc_h << 16) | lc_w), ~0); } else _ovl_UFOd_in(comp, 0, handle); if (prev == DDP_COMPONENT_OVL0 || prev == DDP_COMPONENT_OVL0_2L || prev == DDP_COMPONENT_OVL1 || prev == DDP_COMPONENT_OVL1_2L) cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_CON, DISP_OVL_BGCLR_IN_SEL, DISP_OVL_BGCLR_IN_SEL); else cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_CON, 0, DISP_OVL_BGCLR_IN_SEL); if (prev == -1) { cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ROI_SIZE, rsz_src_roi.height << 16 | rsz_src_roi.width, ~0); _store_bg_roi(comp, rsz_src_roi.height, rsz_src_roi.width); } } static void mtk_ovl_addon_config(struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id prev, enum mtk_ddp_comp_id next, union mtk_addon_config *addon_config, struct cmdq_pkt *handle) { if ((addon_config->config_type.module == DISP_RSZ || addon_config->config_type.module == DISP_RSZ_v2 || addon_config->config_type.module == DISP_RSZ_v3) && addon_config->config_type.type == ADDON_BETWEEN) { struct mtk_addon_rsz_config *config = &addon_config->addon_rsz_config; mtk_ovl_addon_rsz_config(comp, prev, next, config->rsz_src_roi, config->rsz_dst_roi, handle); } } static void mtk_ovl_connect(struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id prev, enum mtk_ddp_comp_id next) { if (prev == DDP_COMPONENT_OVL0 || prev == DDP_COMPONENT_OVL0_2L || prev == DDP_COMPONENT_OVL1 || prev == DDP_COMPONENT_OVL1_2L) mtk_ddp_cpu_mask_write(comp, DISP_REG_OVL_DATAPATH_CON, DISP_OVL_BGCLR_IN_SEL, DISP_OVL_BGCLR_IN_SEL); else mtk_ddp_cpu_mask_write(comp, DISP_REG_OVL_DATAPATH_CON, DISP_OVL_BGCLR_IN_SEL, 0); } void mtk_ovl_cal_golden_setting(struct mtk_ddp_config *cfg, unsigned int *gs) { bool is_dc = cfg->p_golden_setting_context->is_dc; DDPDBG("%s,is_dc:%d\n", __func__, is_dc); #if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6893) /* OVL_RDMA_MEM_GMC_SETTING_1 */ gs[GS_OVL_RDMA_ULTRA_TH] = 0x3ff; gs[GS_OVL_RDMA_PRE_ULTRA_TH] = (!is_dc) ? 0x3ff : 0x15e; /* OVL_RDMA_FIFO_CTRL */ gs[GS_OVL_RDMA_FIFO_THRD] = 0; gs[GS_OVL_RDMA_FIFO_SIZE] = 384; /* OVL_RDMA_MEM_GMC_SETTING_2 */ gs[GS_OVL_RDMA_ISSUE_REQ_TH] = (!is_dc) ? 255 : 15; gs[GS_OVL_RDMA_ISSUE_REQ_TH_URG] = (!is_dc) ? 127 : 15; gs[GS_OVL_RDMA_REQ_TH_PRE_ULTRA] = 0; gs[GS_OVL_RDMA_REQ_TH_ULTRA] = 1; gs[GS_OVL_RDMA_FORCE_REQ_TH] = 0; /* OVL_RDMA_GREQ_NUM */ gs[GS_OVL_RDMA_GREQ_NUM] = (!is_dc) ? 0xF1FF7777 : 0xF1FF0000; /* OVL_RDMA_GREQURG_NUM */ gs[GS_OVL_RDMA_GREQ_URG_NUM] = (!is_dc) ? 0x7777 : 0x0; /* OVL_RDMA_ULTRA_SRC */ gs[GS_OVL_RDMA_ULTRA_SRC] = (!is_dc) ? 0x8040 : 0xA040; /* OVL_RDMA_BUF_LOW_TH */ gs[GS_OVL_RDMA_ULTRA_LOW_TH] = 0; gs[GS_OVL_RDMA_PRE_ULTRA_LOW_TH] = (!is_dc) ? 0 : (gs[GS_OVL_RDMA_FIFO_SIZE] / 8); /* OVL_RDMA_BUF_HIGH_TH */ gs[GS_OVL_RDMA_PRE_ULTRA_HIGH_TH] = (!is_dc) ? 0 : (gs[GS_OVL_RDMA_FIFO_SIZE] * 6 / 8); gs[GS_OVL_RDMA_PRE_ULTRA_HIGH_DIS] = 1; /* OVL_EN */ gs[GS_OVL_BLOCK_EXT_ULTRA] = (!is_dc) ? 0 : 1; gs[GS_OVL_BLOCK_EXT_PRE_ULTRA] = (!is_dc) ? 0 : 1; #endif #if defined(CONFIG_MACH_MT6873) || defined(CONFIG_MACH_MT6853) \ || defined(CONFIG_MACH_MT6833) || defined(CONFIG_MACH_MT6877) \ || defined(CONFIG_MACH_MT6781) /* OVL_RDMA_MEM_GMC_SETTING_1 */ gs[GS_OVL_RDMA_ULTRA_TH] = 0x3ff; gs[GS_OVL_RDMA_PRE_ULTRA_TH] = (!is_dc) ? 0x3ff : 0xe0; /* OVL_RDMA_FIFO_CTRL */ gs[GS_OVL_RDMA_FIFO_THRD] = 0; gs[GS_OVL_RDMA_FIFO_SIZE] = 288; /* OVL_RDMA_MEM_GMC_SETTING_2 */ gs[GS_OVL_RDMA_ISSUE_REQ_TH] = (!is_dc) ? 191 : 15; gs[GS_OVL_RDMA_ISSUE_REQ_TH_URG] = (!is_dc) ? 95 : 15; gs[GS_OVL_RDMA_REQ_TH_PRE_ULTRA] = 0; gs[GS_OVL_RDMA_REQ_TH_ULTRA] = 1; gs[GS_OVL_RDMA_FORCE_REQ_TH] = 0; /* OVL_RDMA_GREQ_NUM */ gs[GS_OVL_RDMA_GREQ_NUM] = (!is_dc) ? 0xF1FF5555 : 0xF1FF0000; /* OVL_RDMA_GREQURG_NUM */ gs[GS_OVL_RDMA_GREQ_URG_NUM] = (!is_dc) ? 0x5555 : 0x0; /* OVL_RDMA_ULTRA_SRC */ gs[GS_OVL_RDMA_ULTRA_SRC] = (!is_dc) ? 0x8040 : 0xA040; /* OVL_RDMA_BUF_LOW_TH */ gs[GS_OVL_RDMA_ULTRA_LOW_TH] = 0; gs[GS_OVL_RDMA_PRE_ULTRA_LOW_TH] = (!is_dc) ? 0 : 24; /* OVL_RDMA_BUF_HIGH_TH */ gs[GS_OVL_RDMA_PRE_ULTRA_HIGH_TH] = (!is_dc) ? 0 : (gs[GS_OVL_RDMA_FIFO_SIZE] * 6 / 8); gs[GS_OVL_RDMA_PRE_ULTRA_HIGH_DIS] = 1; /* OVL_EN */ gs[GS_OVL_BLOCK_EXT_ULTRA] = (!is_dc) ? 0 : 1; gs[GS_OVL_BLOCK_EXT_PRE_ULTRA] = (!is_dc) ? 0 : 1; #endif } static int mtk_ovl_golden_setting(struct mtk_ddp_comp *comp, struct mtk_ddp_config *cfg, struct cmdq_pkt *handle) { unsigned long baddr = comp->regs_pa; unsigned int regval; unsigned int gs[GS_OVL_FLD_NUM]; int i, layer_num; unsigned long Lx_base; layer_num = mtk_ovl_layer_num(comp); /* calculate ovl golden setting */ mtk_ovl_cal_golden_setting(cfg, gs); /* OVL_RDMA_MEM_GMC_SETTING_1 */ regval = gs[GS_OVL_RDMA_ULTRA_TH] + (gs[GS_OVL_RDMA_PRE_ULTRA_TH] << 16); for (i = 0; i < layer_num; i++) { Lx_base = i * OVL_LAYER_OFFSET + baddr; cmdq_pkt_write(handle, comp->cmdq_base, Lx_base + DISP_REG_OVL_RDMA0_MEM_GMC_SETTING, regval, ~0); } /* OVL_RDMA_FIFO_CTRL */ regval = gs[GS_OVL_RDMA_FIFO_THRD] + (gs[GS_OVL_RDMA_FIFO_SIZE] << 16); for (i = 0; i < layer_num; i++) { Lx_base = i * OVL_LAYER_OFFSET + baddr; cmdq_pkt_write(handle, comp->cmdq_base, Lx_base + DISP_REG_OVL_RDMA0_FIFO_CTRL, regval, ~0); } /* OVL_RDMA_MEM_GMC_SETTING_2 */ regval = gs[GS_OVL_RDMA_ISSUE_REQ_TH] + (gs[GS_OVL_RDMA_ISSUE_REQ_TH_URG] << 16) + (gs[GS_OVL_RDMA_REQ_TH_PRE_ULTRA] << 28) + (gs[GS_OVL_RDMA_REQ_TH_ULTRA] << 29) + (gs[GS_OVL_RDMA_FORCE_REQ_TH] << 30); for (i = 0; i < layer_num; i++) cmdq_pkt_write(handle, comp->cmdq_base, baddr + DISP_REG_OVL_RDMA0_MEM_GMC_S2 + i * 4, regval, ~0); /* DISP_REG_OVL_RDMA_GREQ_NUM */ regval = gs[GS_OVL_RDMA_GREQ_NUM]; cmdq_pkt_write(handle, comp->cmdq_base, baddr + DISP_REG_OVL_RDMA_GREQ_NUM, regval, ~0); /* DISP_REG_OVL_RDMA_GREQ_URG_NUM */ regval = gs[GS_OVL_RDMA_GREQ_URG_NUM]; cmdq_pkt_write(handle, comp->cmdq_base, baddr + DISP_REG_OVL_RDMA_GREQ_URG_NUM, regval, ~0); /* DISP_REG_OVL_RDMA_ULTRA_SRC */ regval = gs[GS_OVL_RDMA_ULTRA_SRC]; cmdq_pkt_write(handle, comp->cmdq_base, baddr + DISP_REG_OVL_RDMA_ULTRA_SRC, regval, ~0); /* DISP_REG_OVL_RDMAn_BUF_LOW */ regval = gs[GS_OVL_RDMA_ULTRA_LOW_TH] + (gs[GS_OVL_RDMA_PRE_ULTRA_LOW_TH] << 12); for (i = 0; i < layer_num; i++) cmdq_pkt_write(handle, comp->cmdq_base, baddr + DISP_REG_OVL_RDMAn_BUF_LOW(i), regval, ~0); /* DISP_REG_OVL_RDMAn_BUF_HIGH */ regval = (gs[GS_OVL_RDMA_PRE_ULTRA_HIGH_TH] << 12) + (gs[GS_OVL_RDMA_PRE_ULTRA_HIGH_DIS] << 31); for (i = 0; i < layer_num; i++) cmdq_pkt_write(handle, comp->cmdq_base, baddr + DISP_REG_OVL_RDMAn_BUF_HIGH(i), regval, ~0); /* OVL_EN */ regval = (gs[GS_OVL_BLOCK_EXT_ULTRA] << 18) + (gs[GS_OVL_BLOCK_EXT_PRE_ULTRA] << 19); cmdq_pkt_write(handle, comp->cmdq_base, baddr + DISP_REG_OVL_EN, regval, 0x3 << 18); return 0; } static void mtk_ovl_all_layer_off(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle, int keep_first_layer) { int i; unsigned int phy_layer0_on = 0; /* In 6779 we need to set DISP_OVL_FORCE_RELAY_MODE */ /* To make sure the OVL_SRC_CON register keep the same value * as readl while writing the new value in GCE. This function should * only used in driver probe. */ if (keep_first_layer) phy_layer0_on = readl(comp->regs + DISP_REG_OVL_SRC_CON) & 0x1; if (phy_layer0_on) cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_SRC_CON, 0x1, ~0); else cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_SRC_CON, DISP_OVL_FORCE_RELAY_MODE, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_EXT_CON, 0, ~0); for (i = phy_layer0_on ? 1 : 0; i < OVL_PHY_LAYER_NR; i++) cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_RDMA_CTRL(i), 0, ~0); } static int mtk_ovl_replace_bootup_mva(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle, void *params, struct mtk_ddp_fb_info *fb_info) { unsigned int src_on = readl(comp->regs + DISP_REG_OVL_SRC_CON); unsigned int layer_addr, layer_mva; struct mtk_disp_ovl *ovl = comp_to_ovl(comp); if (src_on & 0x1) { layer_addr = readl(comp->regs + DISP_REG_OVL_ADDR(ovl, 0)); layer_mva = layer_addr - fb_info->fb_pa + fb_info->fb_mva; cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ADDR(ovl, 0), layer_mva, ~0); } if (src_on & 0x2) { layer_addr = readl(comp->regs + DISP_REG_OVL_ADDR(ovl, 1)); layer_mva = layer_addr - fb_info->fb_pa + fb_info->fb_mva; cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ADDR(ovl, 1), layer_mva, ~0); } if (src_on & 0x4) { layer_addr = readl(comp->regs + DISP_REG_OVL_ADDR(ovl, 2)); layer_mva = layer_addr - fb_info->fb_pa + fb_info->fb_mva; cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ADDR(ovl, 2), layer_mva, ~0); } if (src_on & 0x8) { layer_addr = readl(comp->regs + DISP_REG_OVL_ADDR(ovl, 3)); layer_mva = layer_addr - fb_info->fb_pa + fb_info->fb_mva; cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_ADDR(ovl, 3), layer_mva, ~0); } return 0; } static void mtk_ovl_backup_info_cmp(struct mtk_ddp_comp *comp, bool *compare) { struct mtk_disp_ovl *ovl = comp_to_ovl(comp); void __iomem *baddr = comp->regs, *Lx_base = NULL; int i = 0; unsigned int src_on = readl(DISP_REG_OVL_SRC_CON + baddr); struct mtk_ovl_backup_info cur_info[MAX_LAYER_NUM]; memset(cur_info, 0, sizeof(cur_info)); for (i = 0; i < mtk_ovl_layer_num(comp); i++) { unsigned int val = 0; Lx_base = i * OVL_LAYER_OFFSET + baddr; cur_info[i].layer = i; cur_info[i].layer_en = src_on & (0x1 << i); if (!cur_info[i].layer_en) { DDPMSG("%s:layer%d,en %d,size 0x%x,addr %lu\n", __func__, i, cur_info[i].layer_en, cur_info[i].src_size, cur_info[i].addr); continue; } cur_info[i].con = readl(DISP_REG_OVL_CON(i) + baddr); cur_info[i].addr = readl(DISP_REG_OVL_ADDR(ovl, i) + baddr); cur_info[i].src_size = readl(DISP_REG_OVL_L0_SRC_SIZE + Lx_base); val = readl(DISP_REG_OVL_L0_PITCH + Lx_base); cur_info[i].src_pitch = REG_FLD_VAL_GET(L_PITCH_FLD_SRC_PITCH, val); val = readl(DISP_REG_OVL_DATAPATH_CON + Lx_base); cur_info[i].data_path_con = readl(DISP_REG_OVL_DATAPATH_CON + Lx_base); DDPMSG("%s:layer%d,en %d,size 0x%x, addr %lu\n", __func__, i, cur_info[i].layer_en, cur_info[i].src_size, cur_info[i].addr); if (memcmp(&cur_info[i], &ovl->backup_info[i], sizeof(struct mtk_ovl_backup_info)) != 0) *compare = true; } memcpy(ovl->backup_info, cur_info, sizeof(struct mtk_ovl_backup_info) * MAX_LAYER_NUM); } static int mtk_ovl_io_cmd(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle, enum mtk_ddp_io_cmd io_cmd, void *params) { int ret = 0; switch (io_cmd) { case MTK_IO_CMD_OVL_GOLDEN_SETTING: { struct mtk_ddp_config *cfg; cfg = (struct mtk_ddp_config *)params; mtk_ovl_golden_setting(comp, cfg, handle); break; } case OVL_ALL_LAYER_OFF: { int *keep_first_layer = params; mtk_ovl_all_layer_off(comp, handle, *keep_first_layer); break; } case IRQ_LEVEL_ALL: { unsigned int inten; inten = REG_FLD_VAL(INTEN_FLD_RDMA0_EOF_ABNORMAL_INTEN, 1) | REG_FLD_VAL(INTEN_FLD_RDMA1_EOF_ABNORMAL_INTEN, 1) | REG_FLD_VAL(INTEN_FLD_RDMA2_EOF_ABNORMAL_INTEN, 1) | REG_FLD_VAL(INTEN_FLD_RDMA3_EOF_ABNORMAL_INTEN, 1) | REG_FLD_VAL(INTEN_FLD_ABNORMAL_SOF, 1) | REG_FLD_VAL(INTEN_FLD_START_INTEN, 1); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_INTEN, inten, inten); break; } case IRQ_LEVEL_IDLE: { unsigned int inten; inten = REG_FLD_VAL(INTEN_FLD_REG_CMT_INTEN, 1) | REG_FLD_VAL(INTEN_FLD_FME_CPL_INTEN, 1) | REG_FLD_VAL(INTEN_FLD_START_INTEN, 1); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_INTEN, 0, inten); break; } #ifdef MTK_FB_MMDVFS_SUPPORT case PMQOS_SET_BW: { struct mtk_drm_crtc *mtk_crtc; struct cmdq_pkt_buffer *cmdq_buf; u32 ovl_bw, slot_num; mtk_crtc = comp->mtk_crtc; cmdq_buf = &(mtk_crtc->gce_obj.buf); /* process FBDC */ slot_num = __mtk_disp_pmqos_slot_look_up(comp->id, DISP_BW_FBDC_MODE); ovl_bw = *(unsigned int *)(cmdq_buf->va_base + DISP_SLOT_PMQOS_BW(slot_num)); __mtk_disp_set_module_bw(&comp->fbdc_qos_req, comp->id, ovl_bw, DISP_BW_FBDC_MODE); /* process normal */ slot_num = __mtk_disp_pmqos_slot_look_up(comp->id, DISP_BW_NORMAL_MODE); ovl_bw = *(unsigned int *)(cmdq_buf->va_base + DISP_SLOT_PMQOS_BW(slot_num)); __mtk_disp_set_module_bw(&comp->qos_req, comp->id, ovl_bw, DISP_BW_NORMAL_MODE); break; } case PMQOS_SET_HRT_BW: { u32 bw_val = *(unsigned int *)params; __mtk_disp_set_module_hrt(&comp->hrt_qos_req, bw_val); ret = OVL_REQ_HRT; break; } case PMQOS_UPDATE_BW: { struct drm_crtc *crtc; struct mtk_drm_crtc *mtk_crtc; struct cmdq_pkt_buffer *cmdq_buf; u32 slot_num; mtk_crtc = comp->mtk_crtc; crtc = &mtk_crtc->base; cmdq_buf = &(mtk_crtc->gce_obj.buf); /* process FBDC */ slot_num = __mtk_disp_pmqos_slot_look_up(comp->id, DISP_BW_FBDC_MODE); cmdq_pkt_write(handle, comp->cmdq_base, cmdq_buf->pa_base + DISP_SLOT_PMQOS_BW(slot_num), comp->fbdc_bw, ~0); /* process normal */ slot_num = __mtk_disp_pmqos_slot_look_up(comp->id, DISP_BW_NORMAL_MODE); cmdq_pkt_write(handle, comp->cmdq_base, cmdq_buf->pa_base + DISP_SLOT_PMQOS_BW(slot_num), comp->qos_bw, ~0); DDPDBG("update ovl fbdc_bw to %u, qos bw to %u\n", comp->fbdc_bw, comp->qos_bw); break; } #endif case OVL_REPLACE_BOOTUP_MVA: { struct mtk_ddp_fb_info *fb_info = (struct mtk_ddp_fb_info *)params; mtk_ovl_replace_bootup_mva(comp, handle, params, fb_info); break; } case BACKUP_INFO_CMP: { mtk_ovl_backup_info_cmp(comp, params); break; } case BACKUP_OVL_STATUS: { struct mtk_drm_crtc *mtk_crtc = comp->mtk_crtc; struct cmdq_pkt_buffer *cmdq_buf = NULL; dma_addr_t slot; DDPDBG("%s,+BACKUP_OVL_STATUS\n", __func__); if (mtk_crtc) { cmdq_buf = &(mtk_crtc->gce_obj.buf); if (cmdq_buf) { slot = cmdq_buf->pa_base + DISP_SLOT_OVL_STATUS; cmdq_pkt_mem_move(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_STA, slot, CMDQ_THR_SPR_IDX3); } } break; } default: break; } return ret; } void mtk_ovl_dump_golden_setting(struct mtk_ddp_comp *comp) { void __iomem *baddr = comp->regs; unsigned long rg0 = 0, rg1 = 0, rg2 = 0, rg3 = 0, rg4 = 0; int i = 0; unsigned int value; DDPDUMP("-- %s Golden Setting --\n", mtk_dump_comp_str(comp)); for (i = 0; i < mtk_ovl_layer_num(comp); i++) { rg0 = DISP_REG_OVL_RDMA0_MEM_GMC_SETTING + i * OVL_LAYER_OFFSET; rg1 = DISP_REG_OVL_RDMA0_FIFO_CTRL + i * OVL_LAYER_OFFSET; rg2 = DISP_REG_OVL_RDMA0_MEM_GMC_S2 + i * 0x4; rg3 = DISP_REG_OVL_RDMAn_BUF_LOW(i); rg4 = DISP_REG_OVL_RDMAn_BUF_HIGH(i); DDPDUMP("0x%03lx:0x%08x 0x%03lx:0x%08x 0x%03lx:0x%08x\n", rg0, readl(rg0 + baddr), rg1, readl(rg1 + baddr), rg2, readl(rg2 + baddr)); DDPDUMP("0x%03lx:0x%08x 0x%03lx:0x%08x\n", rg3, readl(rg3 + baddr), rg4, readl(rg4 + baddr)); } rg0 = DISP_REG_OVL_RDMA_BURST_CON1; DDPDUMP("0x%03lx:0x%08x\n", rg0, readl(rg0 + baddr)); rg0 = DISP_REG_OVL_RDMA_GREQ_NUM; rg1 = DISP_REG_OVL_RDMA_GREQ_URG_NUM; rg2 = DISP_REG_OVL_RDMA_ULTRA_SRC; DDPDUMP("0x%03lx:0x%08x 0x%03lx:0x%08x 0x%03lx:0x%08x\n", rg0, readl(rg0 + baddr), rg1, readl(rg1 + baddr), rg2, readl(rg2 + baddr)); rg0 = DISP_REG_OVL_EN; rg1 = DISP_REG_OVL_DATAPATH_CON; rg2 = DISP_REG_OVL_FBDC_CFG1; DDPDUMP("0x%03lx:0x%08x 0x%03lx:0x%08x 0x%03lx:0x%08x\n", rg0, readl(rg0 + baddr), rg1, readl(rg1 + baddr), rg2, readl(rg2 + baddr)); value = readl(DISP_REG_OVL_RDMA0_MEM_GMC_SETTING + baddr); DDPDUMP("RDMA0_MEM_GMC_SETTING1\n"); DDPDUMP("[9:0]:%x [25:16]:%x [28]:%x [31]:%x\n", REG_FLD_VAL_GET(FLD_OVL_RDMA_MEM_GMC_ULTRA_THRESHOLD, value), REG_FLD_VAL_GET( FLD_OVL_RDMA_MEM_GMC_PRE_ULTRA_THRESHOLD, value), REG_FLD_VAL_GET( FLD_OVL_RDMA_MEM_GMC_ULTRA_THRESHOLD_HIGH_OFS, value), REG_FLD_VAL_GET( FLD_OVL_RDMA_MEM_GMC_PRE_ULTRA_THRESHOLD_HIGH_OFS, value)); value = readl(DISP_REG_OVL_RDMA0_FIFO_CTRL + baddr); DDPDUMP("RDMA0_FIFO_CTRL\n"); DDPDUMP("[9:0]:%u [25:16]:%u\n", REG_FLD_VAL_GET(FLD_OVL_RDMA_FIFO_THRD, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_FIFO_SIZE, value)); value = readl(DISP_REG_OVL_RDMA0_MEM_GMC_S2 + baddr); DDPDUMP("RDMA0_MEM_GMC_SETTING2\n"); DDPDUMP("[11:0]:%u [27:16]:%u [28]:%u [29]:%u [30]:%u\n", REG_FLD_VAL_GET(FLD_OVL_RDMA_MEM_GMC2_ISSUE_REQ_THRES, value), REG_FLD_VAL_GET( FLD_OVL_RDMA_MEM_GMC2_ISSUE_REQ_THRES_URG, value), REG_FLD_VAL_GET( FLD_OVL_RDMA_MEM_GMC2_REQ_THRES_PREULTRA, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_MEM_GMC2_REQ_THRES_ULTRA, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_MEM_GMC2_FORCE_REQ_THRES, value)); value = readl(DISP_REG_OVL_RDMA_BURST_CON1 + baddr); DDPDUMP("OVL_RDMA_BURST_CON1\n"); DDPDUMP("[28]:%u\n", REG_FLD_VAL_GET(FLD_RDMA_BURST_CON1_BURST16_EN, value)); value = readl(DISP_REG_OVL_RDMA_GREQ_NUM + baddr); DDPDUMP("RDMA_GREQ_NUM\n"); DDPDUMP("[3:0]%u [7:4]%u [11:8]%u [15:12]%u [23:16]%x [26:24]%u\n", REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_LAYER0_GREQ_NUM, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_LAYER1_GREQ_NUM, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_LAYER2_GREQ_NUM, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_LAYER3_GREQ_NUM, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_OSTD_GREQ_NUM, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_GREQ_DIS_CNT, value)); DDPDUMP("[27]%u [28]%u [29]%u [30]%u [31]%u\n", REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_STOP_EN, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_GRP_END_STOP, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_GRP_BRK_STOP, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_IOBUF_FLUSH_PREULTRA, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_IOBUF_FLUSH_ULTRA, value)); value = readl(DISP_REG_OVL_RDMA_GREQ_URG_NUM + baddr); DDPDUMP("RDMA_GREQ_URG_NUM\n"); DDPDUMP("[3:0]:%u [7:4]:%u [11:8]:%u [15:12]:%u [25:16]:%u [28]:%u\n", REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_LAYER0_GREQ_URG_NUM, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_LAYER1_GREQ_URG_NUM, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_LAYER2_GREQ_URG_NUM, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_LAYER3_GREQ_URG_NUM, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_ARG_GREQ_URG_TH, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_GREQ_ARG_URG_BIAS, value)); value = readl(DISP_REG_OVL_RDMA_ULTRA_SRC + baddr); DDPDUMP("RDMA_ULTRA_SRC\n"); DDPDUMP("[1:0]%u [3:2]%u [5:4]%u [7:6]%u [9:8]%u\n", REG_FLD_VAL_GET(FLD_OVL_RDMA_PREULTRA_BUF_SRC, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_PREULTRA_SMI_SRC, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_PREULTRA_ROI_END_SRC, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_PREULTRA_RDMA_SRC, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_ULTRA_BUF_SRC, value)); DDPDUMP("[11:10]%u [13:12]%u [15:14]%u\n", REG_FLD_VAL_GET(FLD_OVL_RDMA_ULTRA_SMI_SRC, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_ULTRA_ROI_END_SRC, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_ULTRA_RDMA_SRC, value)); value = readl(DISP_REG_OVL_RDMAn_BUF_LOW(0) + baddr); DDPDUMP("RDMA0_BUF_LOW\n"); DDPDUMP("[11:0]:%x [23:12]:%x\n", REG_FLD_VAL_GET(FLD_OVL_RDMA_BUF_LOW_ULTRA_TH, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_BUF_LOW_PREULTRA_TH, value)); value = readl(DISP_REG_OVL_RDMAn_BUF_HIGH(0) + baddr); DDPDUMP("RDMA0_BUF_HIGH\n"); DDPDUMP("[23:12]:%x [31]:%x\n", REG_FLD_VAL_GET(FLD_OVL_RDMA_BUF_HIGH_PREULTRA_TH, value), REG_FLD_VAL_GET(FLD_OVL_RDMA_BUF_HIGH_PREULTRA_DIS, value)); value = readl(DISP_REG_OVL_EN + baddr); DDPDUMP("OVL_EN\n"); DDPDUMP("[18]:%x [19]:%x\n", REG_FLD_VAL_GET(EN_FLD_BLOCK_EXT_ULTRA, value), REG_FLD_VAL_GET(EN_FLD_BLOCK_EXT_PREULTRA, value)); value = readl(DISP_REG_OVL_DATAPATH_CON + baddr); DDPDUMP("DATAPATH_CON\n"); DDPDUMP("[0]:%u [24]:%u [25]:%u [26]:%u\n", REG_FLD_VAL_GET(DATAPATH_CON_FLD_LAYER_SMI_ID_EN, value), REG_FLD_VAL_GET(DATAPATH_CON_FLD_GCLAST_EN, value), REG_FLD_VAL_GET(DATAPATH_CON_FLD_HDR_GCLAST_EN, value), REG_FLD_VAL_GET(DATAPATH_CON_FLD_OUTPUT_CLAMP, value)); value = readl(DISP_REG_OVL_FBDC_CFG1 + baddr); DDPDUMP("OVL_FBDC_CFG1\n"); DDPDUMP("[24]:%u [28]:%u\n", REG_FLD_VAL_GET(FLD_FBDC_8XE_MODE, value), REG_FLD_VAL_GET(FLD_FBDC_FILTER_EN, value)); } int mtk_ovl_dump(struct mtk_ddp_comp *comp) { void __iomem *baddr = comp->regs; int i; if (comp->blank_mode) return 0; DDPDUMP("== %s REGS ==\n", mtk_dump_comp_str(comp)); if (mtk_ddp_comp_helper_get_opt(comp, MTK_DRM_OPT_REG_PARSER_RAW_DUMP)) { unsigned int i = 0; for (i = 0; i < 0x8e0; i += 0x10) mtk_serial_dump_reg(baddr, i, 4); /* ADDR */ mtk_cust_dump_reg(baddr, 0xF40, 0xF60, 0xF80, 0xFA0); mtk_cust_dump_reg(baddr, 0xFB0, 0xFB4, 0xFB8, -1); /* HDR_ADDR, HDR_PITCH */ mtk_cust_dump_reg(baddr, 0xF44, 0xF48, 0xF64, 0xF68); mtk_cust_dump_reg(baddr, 0xF84, 0xF88, 0xFA4, 0xFA8); mtk_cust_dump_reg(baddr, 0xFD0, 0xFD4, 0xFD8, 0xFDC); mtk_cust_dump_reg(baddr, 0xFE0, 0xFE4, -1, -1); } else { /* STA, INTEN, INTSTA, EN*/ mtk_serial_dump_reg(baddr, 0x0, 4); /* TRIG, RST */ mtk_serial_dump_reg(baddr, 0x10, 2); /* ROI_SIZE, DATAPATH_CON, OVL_ROI_BGCLR, OVL_SRC_CON */ mtk_serial_dump_reg(baddr, 0x20, 4); /* LX_CON... */ for (i = 0; i < 4; i++) { mtk_serial_dump_reg(baddr, 0x30 + i * 0x20, 4); mtk_serial_dump_reg(baddr, 0x40 + i * 0x20, 4); } mtk_cust_dump_reg(baddr, 0xF40, 0xF60, 0xF80, 0xFA0); /* RDMAX_CON... */ for (i = 0; i < 4; i++) { unsigned int off = 0xC0 + 0x20 * i; mtk_cust_dump_reg(baddr, off, off + 0x8, off + 0xC, off + 0x10); } mtk_serial_dump_reg(baddr, 0x200, 4); mtk_serial_dump_reg(baddr, 0x230, 4); /* LC_CON */ mtk_serial_dump_reg(baddr, 0x280, 4); mtk_serial_dump_reg(baddr, 0x2a0, 2); /* WCG */ mtk_serial_dump_reg(baddr, 0x2D8, 2); /* DATAPATH_EXT_CON */ mtk_serial_dump_reg(baddr, 0x324, 1); /* OVL_ELX_CON */ for (i = 0; i < 3; i++) { mtk_serial_dump_reg(baddr, 0x330 + i * 0x20, 4); mtk_serial_dump_reg(baddr, 0x340 + i * 0x20, 4); } mtk_cust_dump_reg(baddr, 0xFB0, 0xFB4, 0xFB8, -1); /* SBCH */ mtk_serial_dump_reg(baddr, 0x3A0, 3); /* WCG */ for (i = 0 ; i < 4 ; i++) { mtk_serial_dump_reg(baddr, 0x500 + i * 40, 4); mtk_serial_dump_reg(baddr, 0x510 + i * 40, 4); mtk_serial_dump_reg(baddr, 0x520 + i * 40, 1); } for (i = 0 ; i < 3 ; i++) { mtk_serial_dump_reg(baddr, 0x600 + i * 40, 4); mtk_serial_dump_reg(baddr, 0x610 + i * 40, 4); mtk_serial_dump_reg(baddr, 0x620 + i * 40, 1); } /* FBDC */ mtk_serial_dump_reg(baddr, 0x800, 3); for (i = 0; i < 4; i++) mtk_serial_dump_reg(baddr, 0xF44 + i * 0x20, 2); for (i = 0; i < 3; i++) mtk_serial_dump_reg(baddr, 0xFD0 + i * 0x8, 2); } /* For debug MPU violation issue */ mtk_cust_dump_reg(baddr, 0xFC0, 0xFC4, 0xFC8, -1); mtk_ovl_dump_golden_setting(comp); return 0; } static void ovl_printf_status(unsigned int status) { DDPDUMP("- OVL_FLOW_CONTROL_DEBUG -\n"); DDPDUMP("addcon_idle:%d,blend_idle:%d\n", (status >> 10) & (0x1), (status >> 11) & (0x1)); DDPDUMP("out_valid:%d,out_ready:%d,out_idle:%d\n", (status >> 12) & (0x1), (status >> 13) & (0x1), (status >> 15) & (0x1)); DDPDUMP("rdma_idle3-0:(%d,%d,%d,%d),rst:%d\n", (status >> 16) & (0x1), (status >> 17) & (0x1), (status >> 18) & (0x1), (status >> 19) & (0x1), (status >> 20) & (0x1)); DDPDUMP("trig:%d,frame_hwrst_done:%d\n", (status >> 21) & (0x1), (status >> 23) & (0x1)); DDPDUMP("frame_swrst_done:%d,frame_underrun:%d,frame_done:%d\n", (status >> 24) & (0x1), (status >> 25) & (0x1), (status >> 26) & (0x1)); DDPDUMP("ovl_running:%d,ovl_start:%d,ovl_clr:%d\n", (status >> 27) & (0x1), (status >> 28) & (0x1), (status >> 29) & (0x1)); DDPDUMP("reg_update:%d,ovl_upd_reg:%d\n", (status >> 30) & (0x1), (status >> 31) & (0x1)); DDPDUMP("ovl_fms_state:\n"); switch (status & 0x3ff) { case 0x1: DDPDUMP("idle\n"); break; case 0x2: DDPDUMP("wait_SOF\n"); break; case 0x4: DDPDUMP("prepare\n"); break; case 0x8: DDPDUMP("reg_update\n"); break; case 0x10: DDPDUMP("eng_clr(internal reset)\n"); break; case 0x20: DDPDUMP("eng_act(processing)\n"); break; case 0x40: DDPDUMP("h_wait_w_rst\n"); break; case 0x80: DDPDUMP("s_wait_w_rst\n"); break; case 0x100: DDPDUMP("h_w_rst\n"); break; case 0x200: DDPDUMP("s_w_rst\n"); break; default: DDPDUMP("ovl_fsm_unknown\n"); break; } } static void ovl_print_ovl_rdma_status(unsigned int status) { DDPDUMP("warm_rst_cs:%d,layer_greq:%d,out_data:0x%x\n", status & 0x7, (status >> 3) & 0x1, (status >> 4) & 0xffffff); DDPDUMP("out_ready:%d,out_valid:%d,smi_busy:%d,smi_greq:%d\n", (status >> 28) & 0x1, (status >> 29) & 0x1, (status >> 30) & 0x1, (status >> 31) & 0x1); } static void ovl_dump_layer_info_compress(struct mtk_ddp_comp *comp, int layer, bool is_ext_layer) { unsigned int compr_en = 0, pitch_msb; void __iomem *baddr = comp->regs; void __iomem *Lx_PVRIC_hdr_base; if (is_ext_layer) { compr_en = DISP_REG_GET_FIELD( REG_FLD(1, layer + 4), baddr + DISP_REG_OVL_DATAPATH_EXT_CON); Lx_PVRIC_hdr_base = baddr + layer * (DISP_REG_OVL_EL1_HDR_ADDR - DISP_REG_OVL_EL0_HDR_ADDR); Lx_PVRIC_hdr_base += (DISP_REG_OVL_EL0_HDR_ADDR - DISP_REG_OVL_L0_HDR_ADDR); pitch_msb = readl(baddr + DISP_REG_OVL_EL_PITCH_MSB(layer)); } else { compr_en = DISP_REG_GET_FIELD(REG_FLD(1, layer + 4), baddr + DISP_REG_OVL_DATAPATH_CON); Lx_PVRIC_hdr_base = baddr + layer * (DISP_REG_OVL_L1_HDR_ADDR - DISP_REG_OVL_L0_HDR_ADDR); pitch_msb = readl(baddr + DISP_REG_OVL_PITCH_MSB(layer)); } if (compr_en == 0) { DDPDUMP("compr_en:%u\n", compr_en); return; } DDPDUMP("compr_en:%u, pitch_msb:0x%x, hdr_addr:0x%x, hdr_pitch:0x%x\n", compr_en, pitch_msb, readl(DISP_REG_OVL_L0_HDR_ADDR + Lx_PVRIC_hdr_base), readl(DISP_REG_OVL_L0_HDR_PITCH + Lx_PVRIC_hdr_base)); } static void ovl_dump_layer_info(struct mtk_ddp_comp *comp, int layer, bool is_ext_layer) { unsigned int con, src_size, offset, pitch, addr, clip; /* enum UNIFIED_COLOR_FMT fmt; */ void __iomem *baddr = comp->regs; void __iomem *Lx_base; void __iomem *Lx_addr_base; if (is_ext_layer) { Lx_base = baddr + layer * OVL_LAYER_OFFSET; Lx_base += (DISP_REG_OVL_EL_CON(0) - DISP_REG_OVL_CON(0)); Lx_addr_base = baddr + layer * 0x4; #if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6893) Lx_addr_base += (DISP_REG_OVL_EL_ADDR(0) - DISP_REG_OVL_ADDR_MT6885); #endif #if defined(CONFIG_MACH_MT6873) || defined(CONFIG_MACH_MT6853) \ || defined(CONFIG_MACH_MT6833) || defined(CONFIG_MACH_MT6877) \ || defined(CONFIG_MACH_MT6781) Lx_addr_base += (DISP_REG_OVL_EL_ADDR(0) - DISP_REG_OVL_ADDR_MT6873); #endif } else { Lx_base = baddr + layer * OVL_LAYER_OFFSET; Lx_addr_base = baddr + layer * OVL_LAYER_OFFSET; } con = readl(DISP_REG_OVL_CON(0) + Lx_base); offset = readl(DISP_REG_OVL_L0_OFFSET + Lx_base); src_size = readl(DISP_REG_OVL_L0_SRC_SIZE + Lx_base); pitch = readl(DISP_REG_OVL_L0_PITCH + Lx_base); #if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6893) addr = readl(DISP_REG_OVL_ADDR_MT6885 + Lx_addr_base); #endif #if defined(CONFIG_MACH_MT6873) || defined(CONFIG_MACH_MT6853) \ || defined(CONFIG_MACH_MT6833) || defined(CONFIG_MACH_MT6877) \ || defined(CONFIG_MACH_MT6781) addr = readl(DISP_REG_OVL_ADDR_MT6873 + Lx_addr_base); #endif clip = readl(DISP_REG_OVL_CLIP(0) + Lx_base); /* TODO * fmt = display_fmt_reg_to_unified_fmt( * REG_FLD_VAL_GET(L_CON_FLD_CFMT, con), * REG_FLD_VAL_GET(L_CON_FLD_BTSW, con), * REG_FLD_VAL_GET(L_CON_FLD_RGB_SWAP, con)); */ DDPDUMP("%s_L%d:(%u,%u,%ux%u)\n", is_ext_layer ? "ext" : "phy", layer, offset & 0xfff, (offset >> 16) & 0xfff, src_size & 0xfff, (src_size >> 16) & 0xfff); DDPDUMP("pitch=%u,addr=0x%08x,source=%s,aen=%u,alpha=%u,cl=0x%x\n", pitch & 0xffff, addr, /* unified_color_fmt_name(fmt),*/ (REG_FLD_VAL_GET(L_CON_FLD_LSRC, con) == 0) ? "mem" : "constant_color", REG_FLD_VAL_GET(L_CON_FLD_AEN, con), REG_FLD_VAL_GET(L_CON_FLD_APHA, con), clip); ovl_dump_layer_info_compress(comp, layer, is_ext_layer); } int mtk_ovl_analysis(struct mtk_ddp_comp *comp) { int i = 0; void __iomem *Lx_base; void __iomem *rdma_offset; void __iomem *baddr = comp->regs; unsigned int src_con; unsigned int ext_con; unsigned int addcon; if (comp->blank_mode) return 0; src_con = readl(DISP_REG_OVL_SRC_CON + baddr); ext_con = readl(DISP_REG_OVL_DATAPATH_EXT_CON + baddr); addcon = readl(DISP_REG_OVL_ADDCON_DBG + baddr); DDPDUMP("== %s ANALYSIS ==\n", mtk_dump_comp_str(comp)); DDPDUMP("ovl_en=%d,layer_en(%d,%d,%d,%d),bg(%dx%d)\n", readl(DISP_REG_OVL_EN + baddr) & 0x1, src_con & 0x1, (src_con >> 1) & 0x1, (src_con >> 2) & 0x1, (src_con >> 3) & 0x1, readl(DISP_REG_OVL_ROI_SIZE + baddr) & 0xfff, (readl(DISP_REG_OVL_ROI_SIZE + baddr) >> 16) & 0xfff); DDPDUMP("ext_layer:layer_en(%d,%d,%d),attach_layer(%d,%d,%d)\n", ext_con & 0x1, (ext_con >> 1) & 0x1, (ext_con >> 2) & 0x1, (ext_con >> 16) & 0xf, (ext_con >> 20) & 0xf, (ext_con >> 24) & 0xf); DDPDUMP("cur_pos(%u,%u),layer_hit(%u,%u,%u,%u),bg_mode=%s,sta=0x%x\n", REG_FLD_VAL_GET(ADDCON_DBG_FLD_ROI_X, addcon), REG_FLD_VAL_GET(ADDCON_DBG_FLD_ROI_Y, addcon), REG_FLD_VAL_GET(ADDCON_DBG_FLD_L0_WIN_HIT, addcon), REG_FLD_VAL_GET(ADDCON_DBG_FLD_L1_WIN_HIT, addcon), REG_FLD_VAL_GET(ADDCON_DBG_FLD_L2_WIN_HIT, addcon), REG_FLD_VAL_GET(ADDCON_DBG_FLD_L3_WIN_HIT, addcon), DISP_REG_GET_FIELD(DATAPATH_CON_FLD_BGCLR_IN_SEL, DISP_REG_OVL_DATAPATH_CON + baddr) ? "DL" : "const", readl(DISP_REG_OVL_STA + baddr)); /* phy layer */ for (i = 0; i < mtk_ovl_layer_num(comp); i++) { unsigned int rdma_ctrl; if (src_con & (0x1 << i)) ovl_dump_layer_info(comp, i, false); else DDPDUMP("phy_L%d:disabled\n", i); Lx_base = i * OVL_LAYER_OFFSET + baddr; rdma_ctrl = readl(Lx_base + DISP_REG_OVL_RDMA0_CTRL); DDPDUMP("ovl rdma%d status:(en=%d,fifo_used:%d,GMC=0x%x)\n", i, REG_FLD_VAL_GET(RDMA0_CTRL_FLD_RDMA_EN, rdma_ctrl), REG_FLD_VAL_GET(RDMA0_CTRL_FLD_RMDA_FIFO_USED_SZ, rdma_ctrl), readl(Lx_base + DISP_REG_OVL_RDMA0_MEM_GMC_SETTING)); rdma_offset = i * OVL_RDMA_DEBUG_OFFSET + baddr; ovl_print_ovl_rdma_status( readl(DISP_REG_OVL_RDMA0_DBG + rdma_offset)); } /* ext layer */ for (i = 0; i < 3; i++) { if (ext_con & (0x1 << i)) ovl_dump_layer_info(comp, i, true); else DDPDUMP("ext_L%d:disabled\n", i); } ovl_printf_status(readl(DISP_REG_OVL_FLOW_CTRL_DBG + baddr)); return 0; } static void mtk_ovl_prepare(struct mtk_ddp_comp *comp) { struct mtk_disp_ovl *priv = NULL; int ret; #if defined(CONFIG_DRM_MTK_SHADOW_REGISTER_SUPPORT) struct mtk_disp_ovl *ovl = comp_to_ovl(comp); #endif struct mtk_drm_private *dev_priv = NULL; if (comp == NULL) { DDPPR_ERR("mtk_ddp_comp is NULL\n"); return; } priv = dev_get_drvdata(comp->dev); mtk_ddp_comp_clk_prepare(comp); if (priv->fbdc_clk != NULL) { ret = clk_prepare_enable(priv->fbdc_clk); if (ret) DDPPR_ERR("clk prepare enable failed:%s\n", mtk_dump_comp_str(comp)); } #if defined(CONFIG_DRM_MTK_SHADOW_REGISTER_SUPPORT) if (ovl->data->support_shadow) { /* Enable shadow register and read shadow register */ mtk_ddp_write_mask_cpu(comp, 0x0, DISP_REG_OVL_EN, DISP_OVL_BYPASS_SHADOW); } else { /* Bypass shadow register and read shadow register */ mtk_ddp_write_mask_cpu(comp, DISP_OVL_BYPASS_SHADOW, DISP_REG_OVL_EN, DISP_OVL_BYPASS_SHADOW); } #else #if defined(CONFIG_MACH_MT6873) || defined(CONFIG_MACH_MT6853) \ || defined(CONFIG_MACH_MT6877) || defined(CONFIG_MACH_MT6781) /* Bypass shadow register and read shadow register */ mtk_ddp_write_mask_cpu(comp, DISP_OVL_BYPASS_SHADOW, DISP_REG_OVL_EN, DISP_OVL_BYPASS_SHADOW); #endif #endif if (comp && comp->mtk_crtc) { dev_priv = comp->mtk_crtc->base.dev->dev_private; if (mtk_drm_helper_get_opt(dev_priv->helper_opt, MTK_DRM_OPT_LAYER_REC)) writel(0xffffffff, comp->regs + DISP_OVL_REG_GDRDY_PRD); } } static void mtk_ovl_unprepare(struct mtk_ddp_comp *comp) { struct mtk_disp_ovl *priv = dev_get_drvdata(comp->dev); if (priv->fbdc_clk != NULL) clk_disable_unprepare(priv->fbdc_clk); mtk_ddp_comp_clk_unprepare(comp); } static void mtk_ovl_config_trigger(struct mtk_ddp_comp *comp, struct cmdq_pkt *pkt, enum mtk_ddp_comp_trigger_flag flag) { switch (flag) { case MTK_TRIG_FLAG_PRE_TRIGGER: { /* not access HW which in blank mode */ if (comp->blank_mode) break; cmdq_pkt_write(pkt, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_RST, 0x1, 0x1); cmdq_pkt_write(pkt, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_RST, 0x0, 0x1); break; } case MTK_TRIG_FLAG_LAYER_REC: { u32 offset = 0; struct cmdq_pkt_buffer *qbuf; int i = 0; const int lnr = mtk_ovl_layer_num(comp); u32 ln_con = 0, ln_size = 0; struct mtk_drm_private *priv = NULL; if (!comp->mtk_crtc) return; priv = comp->mtk_crtc->base.dev->dev_private; if (!mtk_drm_helper_get_opt(priv->helper_opt, MTK_DRM_OPT_LAYER_REC)) return; if (comp->id == DDP_COMPONENT_OVL0_2L) offset = DISP_SLOT_LAYER_REC_OVL0_2L; else if (comp->id == DDP_COMPONENT_OVL0) offset = DISP_SLOT_LAYER_REC_OVL0; else return; qbuf = &comp->mtk_crtc->gce_obj.buf; cmdq_pkt_mem_move(pkt, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_GDRDY_PRD_NUM, qbuf->pa_base + offset, CMDQ_THR_SPR_IDX3); offset += 4; cmdq_pkt_mem_move(pkt, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_SRC_CON, qbuf->pa_base + offset, CMDQ_THR_SPR_IDX3); offset += 4; cmdq_pkt_mem_move(pkt, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_CON, qbuf->pa_base + offset, CMDQ_THR_SPR_IDX3); offset += 4; cmdq_pkt_mem_move(pkt, comp->cmdq_base, comp->regs_pa + DISP_REG_OVL_DATAPATH_EXT_CON, qbuf->pa_base + offset, CMDQ_THR_SPR_IDX3); for (i = 0; i < lnr + 3; i++) { if (i < lnr) { ln_con = DISP_REG_OVL_CON(i); ln_size = DISP_REG_OVL_SRC_SIZE(i); } else { ln_con = DISP_REG_OVL_EL_CON(i - lnr); ln_size = DISP_REG_OVL_EL_SRC_SIZE(i - lnr); } offset += 0x4; cmdq_pkt_mem_move(pkt, comp->cmdq_base, comp->regs_pa + ln_con, qbuf->pa_base + offset, CMDQ_THR_SPR_IDX3); offset += 0x4; cmdq_pkt_mem_move(pkt, comp->cmdq_base, comp->regs_pa + ln_size, qbuf->pa_base + offset, CMDQ_THR_SPR_IDX3); } if (comp->id == DDP_COMPONENT_OVL0_2L) { if (offset >= DISP_SLOT_LAYER_REC_OVL0) DDPMSG("%s:error:ovl0_2l:offset overflow:%u\n", __func__, offset); } else if (comp->id == DDP_COMPONENT_OVL0) { if (offset >= DISP_SLOT_LAYER_REC_END) DDPMSG("%s:error:ovl0:offset overflow:%u\n", __func__, offset); } break; } default: break; } } static const struct mtk_ddp_comp_funcs mtk_disp_ovl_funcs = { .config = mtk_ovl_config, .start = mtk_ovl_start, .stop = mtk_ovl_stop, #if 0 .enable_vblank = mtk_ovl_enable_vblank, .disable_vblank = mtk_ovl_disable_vblank, #endif .layer_on = mtk_ovl_layer_on, .layer_off = mtk_ovl_layer_off, .layer_config = mtk_ovl_layer_config, .addon_config = mtk_ovl_addon_config, .io_cmd = mtk_ovl_io_cmd, .prepare = mtk_ovl_prepare, .unprepare = mtk_ovl_unprepare, .connect = mtk_ovl_connect, .config_trigger = mtk_ovl_config_trigger, }; /* TODO: to be refactored */ int drm_ovl_tf_cb(int port, unsigned long mva, void *data) { struct mtk_disp_ovl *ovl = (struct mtk_disp_ovl *)data; DDPPR_ERR("%s tf mva: 0x%lx\n", mtk_dump_comp_str(&ovl->ddp_comp), mva); mtk_ovl_analysis(&ovl->ddp_comp); mtk_ovl_dump(&ovl->ddp_comp); return 0; } static int mtk_disp_ovl_bind(struct device *dev, struct device *master, void *data) { struct mtk_disp_ovl *priv = dev_get_drvdata(dev); struct drm_device *drm_dev = data; #ifdef MTK_FB_MMDVFS_SUPPORT struct mtk_drm_private *drm_priv = drm_dev->dev_private; int qos_req_port; #endif int ret; unsigned int bg_h, bg_w; void __iomem *baddr; ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp); if (ret < 0) { dev_err(dev, "Failed to register component %s: %d\n", dev->of_node->full_name, ret); return ret; } #ifdef MTK_FB_MMDVFS_SUPPORT qos_req_port = __mtk_disp_pmqos_port_look_up(priv->ddp_comp.id); if (qos_req_port < 0) { DDPPR_ERR("Failed to request QOS port\n"); } else { mm_qos_add_request(&drm_priv->bw_request_list, &priv->ddp_comp.qos_req, qos_req_port); mm_qos_add_request(&drm_priv->bw_request_list, &priv->ddp_comp.fbdc_qos_req, qos_req_port); mm_qos_add_request(&drm_priv->hrt_request_list, &priv->ddp_comp.hrt_qos_req, qos_req_port); } #endif baddr = priv->ddp_comp.regs; bg_w = readl(DISP_REG_OVL_ROI_SIZE + baddr) & 0xfff, bg_h = (readl(DISP_REG_OVL_ROI_SIZE + baddr) >> 16) & 0xfff, _store_bg_roi(&priv->ddp_comp, bg_h, bg_w); return 0; } static void mtk_disp_ovl_unbind(struct device *dev, struct device *master, void *data) { struct mtk_disp_ovl *priv = dev_get_drvdata(dev); struct drm_device *drm_dev = data; mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp); } static const struct component_ops mtk_disp_ovl_component_ops = { .bind = mtk_disp_ovl_bind, .unbind = mtk_disp_ovl_unbind, }; static int mtk_disp_ovl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_disp_ovl *priv; enum mtk_ddp_comp_id comp_id; int irq; int ret; DDPINFO("%s+\n", __func__); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_OVL); if ((int)comp_id < 0) { dev_err(dev, "Failed to identify by alias: %d\n", comp_id); return comp_id; } DDPINFO("%s comp_id:%d\n", __func__, comp_id); ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id, &mtk_disp_ovl_funcs); if (ret) { dev_err(dev, "Failed to initialize component: %d\n", ret); return ret; } priv->fbdc_clk = of_clk_get(dev->of_node, 1); if (IS_ERR(priv->fbdc_clk)) priv->fbdc_clk = NULL; priv->data = of_device_get_match_data(dev); platform_set_drvdata(pdev, priv); ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler, IRQF_TRIGGER_NONE | IRQF_SHARED, dev_name(dev), priv); if (ret < 0) { DDPAEE("%s:%d, failed to request irq:%d ret:%d comp_id:%d\n", __func__, __LINE__, irq, ret, comp_id); return ret; } pm_runtime_enable(dev); ret = component_add(dev, &mtk_disp_ovl_component_ops); if (ret != 0) { dev_err(dev, "Failed to add component: %d\n", ret); pm_runtime_disable(dev); } DDPINFO("%s-\n", __func__); return ret; } static int mtk_disp_ovl_remove(struct platform_device *pdev) { component_del(&pdev->dev, &mtk_disp_ovl_component_ops); pm_runtime_disable(&pdev->dev); return 0; } static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = { .addr = DISP_REG_OVL_ADDR_MT2701, .fmt_rgb565_is_0 = false, .fmt_uyvy = 9U << 12, .fmt_yuyv = 8U << 12, .support_shadow = false, }; static const struct compress_info compr_info_mt6779 = { .name = "PVRIC_V3_1_MTK_1", .l_config = &compr_l_config_PVRIC_V3_1, }; static const struct mtk_disp_ovl_data mt6779_ovl_driver_data = { .addr = DISP_REG_OVL_ADDR_MT6779, .fmt_rgb565_is_0 = true, .fmt_uyvy = 4U << 12, .fmt_yuyv = 5U << 12, .compr_info = &compr_info_mt6779, .support_shadow = false, }; static const struct compress_info compr_info_mt6885 = { .name = "AFBC_V1_2_MTK_1", .l_config = &compr_l_config_AFBC_V1_2, }; static const struct mtk_disp_ovl_data mt6885_ovl_driver_data = { .addr = DISP_REG_OVL_ADDR_MT6885, .fmt_rgb565_is_0 = true, .fmt_uyvy = 4U << 12, .fmt_yuyv = 5U << 12, .compr_info = &compr_info_mt6885, .support_shadow = false, }; static const struct compress_info compr_info_mt6873 = { .name = "AFBC_V1_2_MTK_1", .l_config = &compr_l_config_AFBC_V1_2, }; static const struct mtk_disp_ovl_data mt6873_ovl_driver_data = { .addr = DISP_REG_OVL_ADDR_MT6873, .fmt_rgb565_is_0 = true, .fmt_uyvy = 4U << 12, .fmt_yuyv = 5U << 12, .compr_info = &compr_info_mt6873, .support_shadow = false, }; static const struct compress_info compr_info_mt6853 = { .name = "AFBC_V1_2_MTK_1", .l_config = &compr_l_config_AFBC_V1_2, }; static const struct mtk_disp_ovl_data mt6853_ovl_driver_data = { .addr = DISP_REG_OVL_ADDR_MT6853, .fmt_rgb565_is_0 = true, .fmt_uyvy = 4U << 12, .fmt_yuyv = 5U << 12, .compr_info = &compr_info_mt6853, .support_shadow = false, }; static const struct compress_info compr_info_mt6877 = { .name = "AFBC_V1_2_MTK_1", .l_config = &compr_l_config_AFBC_V1_2, }; static const struct mtk_disp_ovl_data mt6877_ovl_driver_data = { .addr = DISP_REG_OVL_ADDR_MT6877, .fmt_rgb565_is_0 = true, .fmt_uyvy = 4U << 12, .fmt_yuyv = 5U << 12, .compr_info = &compr_info_mt6877, .support_shadow = false, }; static const struct compress_info compr_info_mt6833 = { .name = "AFBC_V1_2_MTK_1", .l_config = &compr_l_config_AFBC_V1_2, }; static const struct mtk_disp_ovl_data mt6833_ovl_driver_data = { .addr = DISP_REG_OVL_ADDR_MT6833, .fmt_rgb565_is_0 = true, .fmt_uyvy = 4U << 12, .fmt_yuyv = 5U << 12, .compr_info = &compr_info_mt6833, .support_shadow = false, }; static const struct compress_info compr_info_mt6781 = { .name = "AFBC_V1_2_MTK_1", .l_config = &compr_l_config_AFBC_V1_2, }; static const struct mtk_disp_ovl_data mt6781_ovl_driver_data = { .addr = DISP_REG_OVL_ADDR_MT6781, .fmt_rgb565_is_0 = true, .fmt_uyvy = 4U << 12, .fmt_yuyv = 5U << 12, .compr_info = &compr_info_mt6781, .support_shadow = false, }; static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = { .addr = DISP_REG_OVL_ADDR_MT8173, .fmt_rgb565_is_0 = true, .fmt_uyvy = 4U << 12, .fmt_yuyv = 5U << 12, .support_shadow = false, }; static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = { {.compatible = "mediatek,mt2701-disp-ovl", .data = &mt2701_ovl_driver_data}, {.compatible = "mediatek,mt6779-disp-ovl", .data = &mt6779_ovl_driver_data}, {.compatible = "mediatek,mt8173-disp-ovl", .data = &mt8173_ovl_driver_data}, {.compatible = "mediatek,mt6885-disp-ovl", .data = &mt6885_ovl_driver_data}, {.compatible = "mediatek,mt6873-disp-ovl", .data = &mt6873_ovl_driver_data}, {.compatible = "mediatek,mt6853-disp-ovl", .data = &mt6853_ovl_driver_data}, {.compatible = "mediatek,mt6877-disp-ovl", .data = &mt6877_ovl_driver_data}, {.compatible = "mediatek,mt6833-disp-ovl", .data = &mt6833_ovl_driver_data}, {.compatible = "mediatek,mt6781-disp-ovl", .data = &mt6781_ovl_driver_data}, {}, }; MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match); struct platform_driver mtk_disp_ovl_driver = { .probe = mtk_disp_ovl_probe, .remove = mtk_disp_ovl_remove, .driver = { .name = "mediatek-disp-ovl", .owner = THIS_MODULE, .of_match_table = mtk_disp_ovl_driver_dt_match, }, };