kernel_samsung_a34x-permissive/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
2024-04-28 15:49:01 +02:00

3952 lines
120 KiB
C
Executable file

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <drm/drmP.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#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 <linux/iommu.h>
#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,
},
};