/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2019 MediaTek Inc. */ #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_MTK_IOMMU_V2 #include "mt_iommu.h" #include "mtk_iommu_ext.h" #endif #include "mtk_drm_drv.h" #include "mtk_drm_plane.h" #include "mtk_drm_ddp_comp.h" #include "mtk_drm_crtc.h" #include "mtk_drm_gem.h" #include "mtk_dump.h" #ifdef CONFIG_MTK_SMI_EXT #include "smi_public.h" #endif #define DISP_OD_EN 0x0000 #define DISP_OD_INTEN 0x0008 #define DISP_OD_INTSTA 0x000c #define DISP_OD_CFG 0x0020 #define DISP_OD_SIZE 0x0030 #define DISP_DITHER_5 0x0114 #define DISP_DITHER_7 0x011c #define DISP_DITHER_15 0x013c #define DISP_DITHER_16 0x0140 #define DISP_REG_SPLIT_START 0x0000 #define DISP_REG_UFO_START 0x0000 #define DISP_REG_UFO_WIDTH 0x0050 #define DISP_REG_UFO_HEIGHT 0x0054 #define OD_RELAYMODE BIT(0) #define UFO_BYPASS BIT(2) #define UFO_LR (BIT(3) | BIT(0)) #define DISP_DITHERING BIT(2) #define DITHER_LSB_ERR_SHIFT_R(x) (((x)&0x7) << 28) #define DITHER_OVFLW_BIT_R(x) (((x)&0x7) << 24) #define DITHER_ADD_LSHIFT_R(x) (((x)&0x7) << 20) #define DITHER_ADD_RSHIFT_R(x) (((x)&0x7) << 16) #define DITHER_NEW_BIT_MODE BIT(0) #define DITHER_LSB_ERR_SHIFT_B(x) (((x)&0x7) << 28) #define DITHER_OVFLW_BIT_B(x) (((x)&0x7) << 24) #define DITHER_ADD_LSHIFT_B(x) (((x)&0x7) << 20) #define DITHER_ADD_RSHIFT_B(x) (((x)&0x7) << 16) #define DITHER_LSB_ERR_SHIFT_G(x) (((x)&0x7) << 12) #define DITHER_OVFLW_BIT_G(x) (((x)&0x7) << 8) #define DITHER_ADD_LSHIFT_G(x) (((x)&0x7) << 4) #define DITHER_ADD_RSHIFT_G(x) (((x)&0x7) << 0) #define MMSYS_SODI_REQ_MASK 0xF4 #define SODI_REQ_SEL_ALL REG_FLD_MSB_LSB(11, 8) #define MT6873_SODI_REQ_SEL_ALL REG_FLD_MSB_LSB(9, 8) #define SODI_REQ_SEL_RDMA0_PD_MODE REG_FLD_MSB_LSB(8, 8) #define SODI_REQ_SEL_RDMA0_CG_MODE REG_FLD_MSB_LSB(9, 9) #define SODI_REQ_SEL_RDMA1_PD_MODE REG_FLD_MSB_LSB(10, 10) #define SODI_REQ_SEL_RDMA1_CG_MODE REG_FLD_MSB_LSB(11, 11) #define SODI_REQ_VAL_ALL REG_FLD_MSB_LSB(15, 12) #define MT6873_SODI_REQ_VAL_ALL REG_FLD_MSB_LSB(13, 12) #define SODI_REQ_VAL_RDMA0_PD_MODE REG_FLD_MSB_LSB(12, 12) #define SODI_REQ_VAL_RDMA0_CG_MODE REG_FLD_MSB_LSB(13, 13) #define SODI_REQ_VAL_RDMA1_PD_MODE REG_FLD_MSB_LSB(14, 14) #define SODI_REQ_VAL_RDMA1_CG_MODE REG_FLD_MSB_LSB(15, 15) #define MMSYS_EMI_REQ_CTL 0xF8 #define HRT_URGENT_CTL_SEL_ALL REG_FLD_MSB_LSB(7, 0) #define HRT_URGENT_CTL_SEL_RDMA0 REG_FLD_MSB_LSB(0, 0) #define HRT_URGENT_CTL_SEL_WDMA0 REG_FLD_MSB_LSB(1, 1) #define HRT_URGENT_CTL_SEL_RDMA1 REG_FLD_MSB_LSB(2, 2) #define HRT_URGENT_CTL_SEL_WDMA1 REG_FLD_MSB_LSB(3, 3) #define HRT_URGENT_CTL_SEL_RDMA4 REG_FLD_MSB_LSB(4, 4) #define HRT_URGENT_CTL_SEL_RDMA5 REG_FLD_MSB_LSB(5, 5) #define HRT_URGENT_CTL_SEL_MDP_RDMA4 REG_FLD_MSB_LSB(6, 6) #define HRT_URGENT_CTL_VAL_ALL REG_FLD_MSB_LSB(16, 9) #define HRT_URGENT_CTL_VAL_RDMA0 REG_FLD_MSB_LSB(9, 9) #define HRT_URGENT_CTL_VAL_WDMA0 REG_FLD_MSB_LSB(10, 10) #define HRT_URGENT_CTL_VAL_RDMA4 REG_FLD_MSB_LSB(13, 13) #define HRT_URGENT_CTL_VAL_MDP_RDMA4 REG_FLD_MSB_LSB(15, 15) #define DVFS_HALT_MASK_SEL_ALL REG_FLD_MSB_LSB(23, 18) #define DVFS_HALT_MASK_SEL_RDMA0 REG_FLD_MSB_LSB(18, 18) #define DVFS_HALT_MASK_SEL_RDMA1 REG_FLD_MSB_LSB(19, 19) #define DVFS_HALT_MASK_SEL_RDMA4 REG_FLD_MSB_LSB(20, 20) #define DVFS_HALT_MASK_SEL_RDMA5 REG_FLD_MSB_LSB(21, 21) #define DVFS_HALT_MASK_SEL_WDMA0 REG_FLD_MSB_LSB(22, 22) #define DVFS_HALT_MASK_SEL_WDMA1 REG_FLD_MSB_LSB(23, 23) #define MT6877_INFRA_MEM_IDLE_ASYNC_2 0x178 #define MT6877_MM_PORT0_AXI_IDLE_ASYNC REG_FLD_MSB_LSB(2, 2) #define MT6877_MM_PORT1_AXI_IDLE_ASYNC REG_FLD_MSB_LSB(3, 3) #define MT6877_INFRA_MEM_IDLE_ASYNC_3 0x17c #define MT6877_MDP2INFRA0_GALS_TX_AXI_IDLE REG_FLD_MSB_LSB(12, 12) #define MT6877_COMM0_GALS_TX_AXI_IDLE REG_FLD_MSB_LSB(13, 13) #define MT6833_INFRA_DISP_DDR_CTL 0x2C #define MT6833_INFRA_FLD_DDR_MASK REG_FLD_MSB_LSB(7, 4) #define MT6781_INFRA_DISP_DDR_CTL 0xB8 #define MT6781_INFRA_DISP_DDR_MASK 0xC02 #define SMI_LARB_NON_SEC_CON 0x0380 #define MTK_DDP_COMP_USER "DISP" void mtk_ddp_write(struct mtk_ddp_comp *comp, unsigned int value, unsigned int offset, void *handle) { #ifdef CONFIG_MTK_DISPLAY_CMDQ cmdq_pkt_write((struct cmdq_pkt *)handle, comp->cmdq_base, comp->regs_pa + offset, value, ~0); #else writel(value, comp->regs + offset); #endif } void mtk_ddp_write_relaxed(struct mtk_ddp_comp *comp, unsigned int value, unsigned int offset, void *handle) { #ifdef CONFIG_MTK_DISPLAY_CMDQ cmdq_pkt_write((struct cmdq_pkt *)handle, comp->cmdq_base, comp->regs_pa + offset, value, ~0); #else writel_relaxed(value, comp->regs + offset); #endif } void mtk_ddp_write_mask(struct mtk_ddp_comp *comp, unsigned int value, unsigned int offset, unsigned int mask, void *handle) { #ifdef CONFIG_MTK_DISPLAY_CMDQ cmdq_pkt_write((struct cmdq_pkt *)handle, comp->cmdq_base, comp->regs_pa + offset, value, mask); #else unsigned int tmp = readl(comp->regs + offset); tmp = (tmp & ~mask) | (value & mask); writel(tmp, comp->regs + offset); #endif } void mtk_ddp_write_mask_cpu(struct mtk_ddp_comp *comp, unsigned int value, unsigned int offset, unsigned int mask) { unsigned int tmp = readl(comp->regs + offset); tmp = (tmp & ~mask) | (value & mask); writel(tmp, comp->regs + offset); } static void mtk_write_cpu_relaxed(void __iomem *addr, unsigned int value, unsigned int mask) { unsigned int tmp = readl(addr); tmp = (tmp & ~mask) | (value & mask); writel_relaxed(tmp, addr); } void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc, unsigned int CFG, struct cmdq_pkt *handle) { /* If bpc equal to 0, the dithering function didn't be enabled */ if (bpc == 0) return; if (bpc >= MTK_MIN_BPC) { cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_DITHER_5, 0, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_DITHER_7, 0, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_DITHER_15, DITHER_LSB_ERR_SHIFT_R(MTK_MAX_BPC - bpc) | DITHER_ADD_LSHIFT_R(MTK_MAX_BPC - bpc) | DITHER_NEW_BIT_MODE, ~0); cmdq_pkt_write( handle, comp->cmdq_base, comp->regs_pa + DISP_DITHER_16, DITHER_LSB_ERR_SHIFT_B(MTK_MAX_BPC - bpc) | DITHER_ADD_LSHIFT_B(MTK_MAX_BPC - bpc) | DITHER_LSB_ERR_SHIFT_G(MTK_MAX_BPC - bpc) | DITHER_ADD_LSHIFT_G(MTK_MAX_BPC - bpc), ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + CFG, DISP_DITHERING, ~0); } } static void mtk_od_config(struct mtk_ddp_comp *comp, struct mtk_ddp_config *cfg, struct cmdq_pkt *handle) { cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_OD_SIZE, cfg->w << 16 | cfg->h, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_OD_CFG, OD_RELAYMODE, ~0); mtk_dither_set(comp, cfg->bpc, DISP_OD_CFG, handle); } static void mtk_od_start(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle) { cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_OD_EN, 1, ~0); } static void mtk_ufoe_config(struct mtk_ddp_comp *comp, struct mtk_ddp_config *cfg, struct cmdq_pkt *handle) { cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_UFO_WIDTH, cfg->w, ~0); cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_UFO_HEIGHT, cfg->h, ~0); } static void mtk_ufoe_start(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle) { cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_UFO_START, UFO_BYPASS, ~0); } static void mtk_split_start(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle) { cmdq_pkt_write(handle, comp->cmdq_base, comp->regs_pa + DISP_REG_SPLIT_START, 1, ~0); } static const struct mtk_ddp_comp_funcs ddp_od = { .config = mtk_od_config, .start = mtk_od_start, }; static const struct mtk_ddp_comp_funcs ddp_ufoe = { .start = mtk_ufoe_start, .config = mtk_ufoe_config, }; static const struct mtk_ddp_comp_funcs ddp_split = { .start = mtk_split_start, }; static const char *const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = { [MTK_DISP_OVL] = "ovl", [MTK_DISP_RDMA] = "rdma", [MTK_DISP_WDMA] = "wdma", [MTK_DISP_COLOR] = "color", [MTK_DISP_CCORR] = "ccorr", [MTK_DISP_AAL] = "aal", [MTK_DISP_GAMMA] = "gamma", [MTK_DISP_DITHER] = "dither", [MTK_DISP_UFOE] = "ufoe", [MTK_DSI] = "dsi", [MTK_DP_INTF] = "dp_intf", [MTK_DPI] = "dpi", [MTK_DISP_PWM] = "pwm", [MTK_DISP_MUTEX] = "mutex", [MTK_DISP_OD] = "od", [MTK_DISP_BLS] = "bls", [MTK_DISP_RSZ] = "rsz", [MTK_DISP_POSTMASK] = "postmask", [MTK_DMDP_RDMA] = "mrdma", [MTK_DMDP_HDR] = "mhdr", [MTK_DMDP_AAL] = "maal", [MTK_DMDP_RSZ] = "mrsz", [MTK_DMDP_TDSHP] = "mtdshp", [MTK_DISP_DSC] = "dsc", [MTK_DISP_MERGE] = "merge", [MTK_DISP_DPTX] = "dptx", [MTK_DISP_VIRTUAL] = "virtual", }; struct mtk_ddp_comp_match { enum mtk_ddp_comp_id index; enum mtk_ddp_comp_type type; int alias_id; const struct mtk_ddp_comp_funcs *funcs; bool is_output; }; static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { {DDP_COMPONENT_AAL0, MTK_DISP_AAL, 0, NULL, 0}, {DDP_COMPONENT_AAL1, MTK_DISP_AAL, 1, NULL, 0}, {DDP_COMPONENT_BLS, MTK_DISP_BLS, 0, NULL, 0}, {DDP_COMPONENT_CCORR0, MTK_DISP_CCORR, 0, NULL, 0}, {DDP_COMPONENT_CCORR1, MTK_DISP_CCORR, 1, NULL, 0}, {DDP_COMPONENT_COLOR0, MTK_DISP_COLOR, 0, NULL, 0}, {DDP_COMPONENT_COLOR1, MTK_DISP_COLOR, 1, NULL, 0}, {DDP_COMPONENT_COLOR2, MTK_DISP_COLOR, 2, NULL, 0}, {DDP_COMPONENT_DITHER0, MTK_DISP_DITHER, 0, NULL, 0}, {DDP_COMPONENT_DITHER1, MTK_DISP_DITHER, 1, NULL, 0}, {DDP_COMPONENT_DPI0, MTK_DPI, 0, NULL, 1}, {DDP_COMPONENT_DPI1, MTK_DPI, 1, NULL, 1}, {DDP_COMPONENT_DSI0, MTK_DSI, 0, NULL, 1}, {DDP_COMPONENT_DSI1, MTK_DSI, 1, NULL, 1}, {DDP_COMPONENT_GAMMA0, MTK_DISP_GAMMA, 0, NULL, 0}, {DDP_COMPONENT_GAMMA1, MTK_DISP_GAMMA, 1, NULL, 0}, {DDP_COMPONENT_OD, MTK_DISP_OD, 0, &ddp_od, 0}, {DDP_COMPONENT_OD1, MTK_DISP_OD, 1, &ddp_od, 0}, {DDP_COMPONENT_OVL0, MTK_DISP_OVL, 0, NULL, 0}, {DDP_COMPONENT_OVL1, MTK_DISP_OVL, 1, NULL, 0}, {DDP_COMPONENT_OVL2, MTK_DISP_OVL, 2, NULL, 0}, {DDP_COMPONENT_OVL0_2L, MTK_DISP_OVL, 3, NULL, 0}, {DDP_COMPONENT_OVL1_2L, MTK_DISP_OVL, 4, NULL, 0}, {DDP_COMPONENT_OVL2_2L, MTK_DISP_OVL, 5, NULL, 0}, {DDP_COMPONENT_OVL3_2L, MTK_DISP_OVL, 6, NULL, 0}, {DDP_COMPONENT_OVL0_2L_VIRTUAL0, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_OVL1_2L_VIRTUAL0, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_OVL0_VIRTUAL0, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_OVL1_VIRTUAL0, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_OVL0_OVL0_2L_VIRTUAL0, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_PWM0, MTK_DISP_PWM, 0, NULL, 0}, {DDP_COMPONENT_PWM1, MTK_DISP_PWM, 1, NULL, 0}, {DDP_COMPONENT_PWM2, MTK_DISP_PWM, 2, NULL, 0}, {DDP_COMPONENT_RDMA0, MTK_DISP_RDMA, 0, NULL, 0}, {DDP_COMPONENT_RDMA1, MTK_DISP_RDMA, 1, NULL, 0}, {DDP_COMPONENT_RDMA2, MTK_DISP_RDMA, 2, NULL, 0}, {DDP_COMPONENT_RDMA3, MTK_DISP_RDMA, 3, NULL, 0}, {DDP_COMPONENT_RDMA4, MTK_DISP_RDMA, 4, NULL, 0}, {DDP_COMPONENT_RDMA5, MTK_DISP_RDMA, 5, NULL, 0}, {DDP_COMPONENT_RDMA0_VIRTUAL0, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_RDMA1_VIRTUAL0, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_RDMA2_VIRTUAL0, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_RSZ0, MTK_DISP_RSZ, 0, NULL, 0}, {DDP_COMPONENT_RSZ1, MTK_DISP_RSZ, 1, NULL, 0}, {DDP_COMPONENT_UFOE, MTK_DISP_UFOE, 0, &ddp_ufoe, 0}, {DDP_COMPONENT_WDMA0, MTK_DISP_WDMA, 0, NULL, 1}, {DDP_COMPONENT_WDMA1, MTK_DISP_WDMA, 1, NULL, 1}, {DDP_COMPONENT_UFBC_WDMA0, MTK_DISP_WDMA, 2, NULL, 1}, {DDP_COMPONENT_WDMA_VIRTUAL0, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_WDMA_VIRTUAL1, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_POSTMASK0, MTK_DISP_POSTMASK, 0, NULL, 0}, {DDP_COMPONENT_POSTMASK1, MTK_DISP_POSTMASK, 1, NULL, 0}, {DDP_COMPONENT_DMDP_RDMA0, MTK_DMDP_RDMA, 0, NULL, 0}, {DDP_COMPONENT_DMDP_HDR0, MTK_DMDP_HDR, 0, NULL, 0}, {DDP_COMPONENT_DMDP_AAL0, MTK_DMDP_AAL, 0, NULL, 0}, {DDP_COMPONENT_DMDP_RSZ0, MTK_DMDP_RSZ, 0, NULL, 0}, {DDP_COMPONENT_DMDP_TDSHP0, MTK_DMDP_TDSHP, 0, NULL, 0}, {DDP_COMPONENT_DMDP_RDMA1, MTK_DMDP_RDMA, 1, NULL, 0}, {DDP_COMPONENT_DMDP_HDR1, MTK_DMDP_HDR, 1, NULL, 0}, {DDP_COMPONENT_DMDP_AAL1, MTK_DMDP_AAL, 1, NULL, 0}, {DDP_COMPONENT_DMDP_RSZ1, MTK_DMDP_RSZ, 1, NULL, 0}, {DDP_COMPONENT_DMDP_TDSHP1, MTK_DMDP_TDSHP, 1, NULL, 0}, {DDP_COMPONENT_DSC0, MTK_DISP_DSC, 0, NULL, 0}, {DDP_COMPONENT_MERGE0, MTK_DISP_MERGE, 0, NULL, 0}, {DDP_COMPONENT_DPTX, MTK_DISP_DPTX, 0, NULL, 1}, {DDP_COMPONENT_DP_INTF0, MTK_DP_INTF, 0, NULL, 1}, {DDP_COMPONENT_RDMA4_VIRTUAL0, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_RDMA5_VIRTUAL0, MTK_DISP_VIRTUAL, -1, NULL, 0}, {DDP_COMPONENT_MERGE1, MTK_DISP_MERGE, 1, NULL, 0}, {DDP_COMPONENT_SPR0_VIRTUAL, MTK_DISP_VIRTUAL, -1, NULL, 0}, }; bool mtk_ddp_comp_is_output(struct mtk_ddp_comp *comp) { if (comp->id < 0 || comp->id >= DDP_COMPONENT_ID_MAX) return false; return mtk_ddp_matches[comp->id].is_output; } void mtk_ddp_comp_get_name(struct mtk_ddp_comp *comp, char *buf, int buf_len) { int r; if (comp->id < 0 || comp->id >= DDP_COMPONENT_ID_MAX) { DDPPR_ERR("%s(), invalid id %d, set buf to 0\n", __func__, comp->id); memset(buf, 0, buf_len); return; } if (buf_len > sizeof(buf)) buf_len = sizeof(buf); if (mtk_ddp_matches[comp->id].type < 0) { DDPPR_ERR("%s invalid type\n", __func__); return; } r = snprintf(buf, buf_len, "%s%d", mtk_ddp_comp_stem[mtk_ddp_matches[comp->id].type], mtk_ddp_matches[comp->id].alias_id); if (r < 0) { /* Handle snprintf() error */ DDPPR_ERR("snprintf error\n"); } } int mtk_ddp_comp_get_type(enum mtk_ddp_comp_id comp_id) { if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX) return -EINVAL; return mtk_ddp_matches[comp_id].type; } static bool mtk_drm_find_comp_in_ddp(struct mtk_ddp_comp ddp_comp, const struct mtk_crtc_path_data *path_data) { unsigned int i, j, ddp_mode; const enum mtk_ddp_comp_id *path = NULL; if (path_data == NULL) return false; for (ddp_mode = 0U; ddp_mode < DDP_MODE_NR; ddp_mode++) for (i = 0U; i < DDP_PATH_NR; i++) { path = path_data->path[ddp_mode][i]; for (j = 0U; j < path_data->path_len[ddp_mode][i]; j++) if (ddp_comp.id == path[j]) return true; } return false; } enum mtk_ddp_comp_id mtk_ddp_comp_get_id(struct device_node *node, enum mtk_ddp_comp_type comp_type) { int id; int i; if (comp_type < 0) return -EINVAL; id = of_alias_get_id(node, mtk_ddp_comp_stem[comp_type]); DDPINFO("id:%d, comp_type:%d\n", id, comp_type); for (i = 0; i < ARRAY_SIZE(mtk_ddp_matches); i++) { if (comp_type == mtk_ddp_matches[i].type && (id < 0 || id == mtk_ddp_matches[i].alias_id)) return mtk_ddp_matches[i].index; } return -EINVAL; } struct mtk_ddp_comp *mtk_ddp_comp_find_by_id(struct drm_crtc *crtc, enum mtk_ddp_comp_id comp_id) { unsigned int i = 0, j = 0, ddp_mode = 0; struct mtk_drm_crtc *mtk_crtc = container_of(crtc, struct mtk_drm_crtc, base); struct mtk_ddp_comp *comp; for_each_comp_in_all_crtc_mode(comp, mtk_crtc, i, j, ddp_mode) if (comp_id == comp->id) return comp; return NULL; } static void mtk_ddp_comp_set_larb(struct device *dev, struct device_node *node, struct mtk_ddp_comp *comp) { int ret; struct device_node *larb_node = NULL; struct platform_device *larb_pdev = NULL; enum mtk_ddp_comp_type type = mtk_ddp_comp_get_type(comp->id); unsigned int larb_id; comp->larb_dev = NULL; larb_node = of_parse_phandle(node, "mediatek,larb", 0); if (larb_node) { larb_pdev = of_find_device_by_node(larb_node); if (larb_pdev) comp->larb_dev = &larb_pdev->dev; of_node_put(larb_node); } if (!comp->larb_dev) return; ret = of_property_read_u32(node, "mediatek,smi-id", &larb_id); if (ret) { dev_err(comp->larb_dev, "read smi-id failed:%d\n", ret); return; } comp->larb_id = larb_id; /* check if this module need larb_dev */ if (type == MTK_DISP_OVL || type == MTK_DISP_RDMA || type == MTK_DISP_WDMA || type == MTK_DISP_POSTMASK) { dev_warn(dev, "%s: %s need larb device\n", __func__, mtk_dump_comp_str(comp)); DDPPR_ERR("%s: smi-id:%d\n", mtk_dump_comp_str(comp), comp->larb_id); } } unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm, struct mtk_ddp_comp ddp_comp) { struct mtk_drm_private *private = drm->dev_private; unsigned int ret; if (mtk_drm_find_comp_in_ddp(ddp_comp, private->data->main_path_data) == true) { ret = BIT(0); } else if (mtk_drm_find_comp_in_ddp( ddp_comp, private->data->ext_path_data) == true) { ret = BIT(1); } else if (mtk_drm_find_comp_in_ddp( ddp_comp, private->data->third_path_data) == true) { ret = BIT(2); } else { DRM_INFO("Failed to find comp in ddp table\n"); ret = 0; } return ret; } int mtk_ddp_comp_init(struct device *dev, struct device_node *node, struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id comp_id, const struct mtk_ddp_comp_funcs *funcs) { enum mtk_ddp_comp_type type; struct platform_device *comp_pdev = NULL; struct resource res; DDPINFO("%s+\n", __func__); if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX) return -EINVAL; type = mtk_ddp_matches[comp_id].type; comp->id = comp_id; comp->funcs = funcs ?: mtk_ddp_matches[comp_id].funcs; comp->dev = dev; /* get the first clk in the device node */ comp->clk = of_clk_get(node, 0); if (IS_ERR(comp->clk)) { comp->clk = NULL; DDPPR_ERR("comp:%d get clock fail!\n", comp_id); } if (comp_id == DDP_COMPONENT_BLS || comp_id == DDP_COMPONENT_PWM0) { comp->regs_pa = 0; comp->regs = NULL; comp->irq = 0; return 0; } if (of_address_to_resource(node, 0, &res) != 0) { dev_err(dev, "Missing reg in %s node\n", node->full_name); return -EINVAL; } comp->regs_pa = res.start; if (comp_id == DDP_COMPONENT_DPI0 || comp_id == DDP_COMPONENT_DPI1 || comp_id == DDP_COMPONENT_DSI0 || comp_id == DDP_COMPONENT_DSI1) comp->irq = 0; else comp->irq = of_irq_get(node, 0); comp->regs = of_iomap(node, 0); DDPINFO("[DRM]regs_pa:0x%lx, regs:0x%p, node:%s\n", (unsigned long)comp->regs_pa, comp->regs, node->full_name); /* handle cmdq related resources */ comp_pdev = of_find_device_by_node(node); if (!comp_pdev) { dev_warn(dev, "Waiting for comp device %s\n", node->full_name); return -EPROBE_DEFER; } comp->cmdq_base = cmdq_register_device(&comp_pdev->dev); #if 0 /* TODO: if no subsys id, use 99 instead. CMDQ owner would define 99 in * DTS afterward. */ if (of_property_read_u8(node, "my_subsys_id", &comp->cmdq_subsys)) comp->cmdq_subsys = 99; #endif /* handle larb resources */ mtk_ddp_comp_set_larb(dev, node, comp); DDPINFO("%s-\n", __func__); return 0; } int mtk_ddp_comp_register(struct drm_device *drm, struct mtk_ddp_comp *comp) { struct mtk_drm_private *private = drm->dev_private; if (private->ddp_comp[comp->id]) return -EBUSY; if (comp->id < 0) return -EINVAL; private->ddp_comp[comp->id] = comp; return 0; } void mtk_ddp_comp_unregister(struct drm_device *drm, struct mtk_ddp_comp *comp) { struct mtk_drm_private *private = drm->dev_private; if (comp && comp->id >= 0 && comp->id < DDP_COMPONENT_ID_MAX) private->ddp_comp[comp->id] = NULL; } void mtk_ddp_comp_clk_prepare(struct mtk_ddp_comp *comp) { int ret; if (comp == NULL) return; #ifdef CONFIG_MTK_SMI_EXT if (comp->larb_dev) smi_bus_prepare_enable(comp->larb_id, MTK_DDP_COMP_USER); #endif if (comp->clk) { ret = clk_prepare_enable(comp->clk); if (ret) DDPPR_ERR("clk prepare enable failed:%s\n", mtk_dump_comp_str(comp)); } } void mtk_ddp_comp_clk_unprepare(struct mtk_ddp_comp *comp) { if (comp == NULL) return; if (comp->clk) clk_disable_unprepare(comp->clk); #ifdef CONFIG_MTK_SMI_EXT if (comp->larb_dev) smi_bus_disable_unprepare(comp->larb_id, MTK_DDP_COMP_USER); #endif } #ifdef CONFIG_MTK_IOMMU_V2 static enum mtk_iommu_callback_ret_t mtk_ddp_m4u_callback(int port, unsigned long mva, void *data) { struct mtk_ddp_comp *comp = (struct mtk_ddp_comp *)data; DDPPR_ERR("fault call port=%d, mva=0x%lx, data=0x%p\n", port, mva, data); if (comp && comp->mtk_crtc) { mtk_drm_crtc_analysis(&(comp->mtk_crtc->base)); mtk_drm_crtc_dump(&(comp->mtk_crtc->base)); } return MTK_IOMMU_CALLBACK_HANDLED; } #endif #define GET_M4U_PORT 0x1F void mtk_ddp_comp_iommu_enable(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle) { int port, index, ret; struct resource res; if (!comp->dev || !comp->larb_dev) return; index = 0; while (1) { ret = of_property_read_u32_index(comp->dev->of_node, "iommus", index * 2 + 1, &port); if (ret < 0) break; #ifdef CONFIG_MTK_IOMMU_V2 mtk_iommu_register_fault_callback( port, (mtk_iommu_fault_callback_t)mtk_ddp_m4u_callback, (void *)comp); #endif port &= (unsigned int)GET_M4U_PORT; if (of_address_to_resource(comp->larb_dev->of_node, 0, &res) != 0) { dev_err(comp->dev, "Missing reg in %s node\n", comp->larb_dev->of_node->full_name); return; } #ifndef CONFIG_MTK_DISPLAY_M4U //bypass m4u cmdq_pkt_write(handle, NULL, res.start + SMI_LARB_NON_SEC_CON + port * 4, 0, 0x1); #else cmdq_pkt_write(handle, NULL, res.start + SMI_LARB_NON_SEC_CON + port * 4, 0x1, 0x1); #endif index++; } } void mt6779_mtk_sodi_config(struct drm_device *drm, enum mtk_ddp_comp_id id, struct cmdq_pkt *handle, void *data) { struct mtk_drm_private *priv = drm->dev_private; unsigned int val = 0, mask = 0; bool en = *((bool *)data); if (id == DDP_COMPONENT_ID_MAX) { /* config when top clk on */ if (!en) return; val = 0x0F005506; mask = 0xFFFFFFFF; } else if (id == DDP_COMPONENT_RDMA0) { mask |= (BIT(9) + BIT(16)); val |= (((!(unsigned int)en) << 9) + ((en) << 16)); } else if (id == DDP_COMPONENT_RDMA1) { mask |= (BIT(11) + BIT(17)); val |= (((!(unsigned int)en) << 11) + ((en) << 17)); } else if (id == DDP_COMPONENT_WDMA0) { mask |= BIT(18); val |= ((en) << 18); } else return; if (handle == NULL) { unsigned int v = (readl(priv->config_regs + 0xF8) & (~mask)); v += (val & mask); writel_relaxed(v, priv->config_regs + 0xF8); } else cmdq_pkt_write(handle, NULL, priv->config_regs_pa + 0xF8, val, mask); } void mt6853_mtk_sodi_config(struct drm_device *drm, enum mtk_ddp_comp_id id, struct cmdq_pkt *handle, void *data) { struct mtk_drm_private *priv = drm->dev_private; unsigned int sodi_req_val = 0, sodi_req_mask = 0; unsigned int emi_req_val = 0, emi_req_mask = 0; bool en = *((bool *)data); if (id == DDP_COMPONENT_ID_MAX) { /* config when top clk on */ if (!en) return; SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, MT6873_SODI_REQ_SEL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, MT6873_SODI_REQ_VAL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_SEL_RDMA0_PD_MODE); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_VAL_RDMA0_PD_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_MDP_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_WDMA0); } else if (id == DDP_COMPONENT_RDMA0) { SET_VAL_MASK(sodi_req_val, sodi_req_mask, (!en), SODI_REQ_SEL_RDMA0_CG_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, (!en), HRT_URGENT_CTL_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_RDMA0); } else if (id == DDP_COMPONENT_WDMA0) { SET_VAL_MASK(emi_req_val, emi_req_mask, (!en), HRT_URGENT_CTL_SEL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_WDMA0); } else return; if (handle == NULL) { unsigned int v; v = (readl(priv->config_regs + MMSYS_SODI_REQ_MASK) & (~sodi_req_mask)); v += (sodi_req_val & sodi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_SODI_REQ_MASK); v = (readl(priv->config_regs + MMSYS_EMI_REQ_CTL) & (~emi_req_mask)); v += (emi_req_val & emi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_EMI_REQ_CTL); } else { cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_SODI_REQ_MASK, sodi_req_val, sodi_req_mask); cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_EMI_REQ_CTL, emi_req_val, emi_req_mask); } } void mt6781_mtk_sodi_config(struct drm_device *drm, enum mtk_ddp_comp_id id, struct cmdq_pkt *handle, void *data) { struct mtk_drm_private *priv = drm->dev_private; unsigned int sodi_req_val = 0, sodi_req_mask = 0; unsigned int emi_req_val = 0, emi_req_mask = 0; bool en = *((bool *)data); if (id == DDP_COMPONENT_ID_MAX) { /* config when top clk on */ if (!en) return; SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, MT6873_SODI_REQ_SEL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, MT6873_SODI_REQ_VAL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_SEL_RDMA0_PD_MODE); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_VAL_RDMA0_PD_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_WDMA0); } else if (id == DDP_COMPONENT_RDMA0) { SET_VAL_MASK(sodi_req_val, sodi_req_mask, (!en), SODI_REQ_SEL_RDMA0_CG_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, (!en), HRT_URGENT_CTL_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_RDMA0); } else if (id == DDP_COMPONENT_WDMA0) { SET_VAL_MASK(emi_req_val, emi_req_mask, (!en), HRT_URGENT_CTL_SEL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_WDMA0); } else return; if (handle == NULL) { unsigned int v; v = (readl(priv->config_regs + MMSYS_SODI_REQ_MASK) & (~sodi_req_mask)); v += (sodi_req_val & sodi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_SODI_REQ_MASK); v = (readl(priv->config_regs + MMSYS_EMI_REQ_CTL) & (~emi_req_mask)); v += (emi_req_val & emi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_EMI_REQ_CTL); if (priv->data->bypass_infra_ddr_control) { if (!IS_ERR(priv->infra_regs)) { v = (readl(priv->infra_regs + MT6781_INFRA_DISP_DDR_CTL) | MT6781_INFRA_DISP_DDR_MASK); writel_relaxed(v, priv->infra_regs + MT6781_INFRA_DISP_DDR_CTL); } else DDPINFO("%s: failed to disable infra ddr control\n", __func__); } } else { cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_SODI_REQ_MASK, sodi_req_val, sodi_req_mask); cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_EMI_REQ_CTL, emi_req_val, emi_req_mask); if (priv->data->bypass_infra_ddr_control) { if (priv->infra_regs_pa) { cmdq_pkt_write(handle, NULL, priv->infra_regs_pa + MT6781_INFRA_DISP_DDR_CTL, MT6781_INFRA_DISP_DDR_MASK, MT6781_INFRA_DISP_DDR_MASK); } else DDPINFO("%s: failed to disable infra ddr control\n", __func__); } } } void mt6877_mtk_sodi_config(struct drm_device *drm, enum mtk_ddp_comp_id id, struct cmdq_pkt *handle, void *data) { struct mtk_drm_private *priv = drm->dev_private; unsigned int sodi_req_val = 0, sodi_req_mask = 0; unsigned int emi_req_val = 0, emi_req_mask = 0; unsigned int infra_req_val1 = 0, infra_req_mask1 = 0; unsigned int infra_req_val2 = 0, infra_req_mask2 = 0; unsigned int infra_req_val3 = 0, infra_req_mask3 = 0; unsigned int infra_req_val4 = 0, infra_req_mask4 = 0; bool en = *((bool *)data); if (id == DDP_COMPONENT_ID_MAX) { /* config when top clk on */ if (!en) return; SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, MT6873_SODI_REQ_SEL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, MT6873_SODI_REQ_VAL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_SEL_RDMA0_PD_MODE); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_VAL_RDMA0_PD_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_MDP_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_WDMA0); } else if (id == DDP_COMPONENT_RDMA0) { SET_VAL_MASK(sodi_req_val, sodi_req_mask, (!en), SODI_REQ_SEL_RDMA0_CG_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, (!en), HRT_URGENT_CTL_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_RDMA0); } else if (id == DDP_COMPONENT_WDMA0) { SET_VAL_MASK(emi_req_val, emi_req_mask, (!en), HRT_URGENT_CTL_SEL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_WDMA0); } else return; if (priv->data->bypass_infra_ddr_control) { SET_VAL_MASK(infra_req_val1, infra_req_mask1, 0x0, MT6877_MM_PORT0_AXI_IDLE_ASYNC); SET_VAL_MASK(infra_req_val2, infra_req_mask2, 0x0, MT6877_MM_PORT1_AXI_IDLE_ASYNC); SET_VAL_MASK(infra_req_val3, infra_req_mask3, 0x0, MT6877_MDP2INFRA0_GALS_TX_AXI_IDLE); SET_VAL_MASK(infra_req_val4, infra_req_mask4, 0x0, MT6877_COMM0_GALS_TX_AXI_IDLE); } if (handle == NULL) { unsigned int v; v = (readl(priv->config_regs + MMSYS_SODI_REQ_MASK) & (~sodi_req_mask)); v += (sodi_req_val & sodi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_SODI_REQ_MASK); v = (readl(priv->config_regs + MMSYS_EMI_REQ_CTL) & (~emi_req_mask)); v += (emi_req_val & emi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_EMI_REQ_CTL); if (priv->data->bypass_infra_ddr_control) { if (!IS_ERR(priv->infra_regs)) { mtk_write_cpu_relaxed( priv->infra_regs + MT6877_INFRA_MEM_IDLE_ASYNC_2, infra_req_val1, infra_req_mask1); mtk_write_cpu_relaxed( priv->infra_regs + MT6877_INFRA_MEM_IDLE_ASYNC_2, infra_req_val2, infra_req_mask2); mtk_write_cpu_relaxed( priv->infra_regs + MT6877_INFRA_MEM_IDLE_ASYNC_3, infra_req_val3, infra_req_mask3); mtk_write_cpu_relaxed( priv->infra_regs + MT6877_INFRA_MEM_IDLE_ASYNC_3, infra_req_val4, infra_req_mask4); } else DDPINFO("%s: failed to disable infra ddr control\n", __func__); } } else { cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_SODI_REQ_MASK, sodi_req_val, sodi_req_mask); cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_EMI_REQ_CTL, emi_req_val, emi_req_mask); if (priv->data->bypass_infra_ddr_control) { if (priv->infra_regs_pa) { cmdq_pkt_write(handle, NULL, priv->infra_regs_pa + MT6877_INFRA_MEM_IDLE_ASYNC_2, infra_req_val1, infra_req_mask1); cmdq_pkt_write(handle, NULL, priv->infra_regs_pa + MT6877_INFRA_MEM_IDLE_ASYNC_2, infra_req_val2, infra_req_mask2); cmdq_pkt_write(handle, NULL, priv->infra_regs_pa + MT6877_INFRA_MEM_IDLE_ASYNC_3, infra_req_val3, infra_req_mask3); cmdq_pkt_write(handle, NULL, priv->infra_regs_pa + MT6877_INFRA_MEM_IDLE_ASYNC_3, infra_req_val4, infra_req_mask4); } else DDPINFO("%s: failed to disable infra ddr control\n", __func__); } } } void mt6833_mtk_sodi_config(struct drm_device *drm, enum mtk_ddp_comp_id id, struct cmdq_pkt *handle, void *data) { struct mtk_drm_private *priv = drm->dev_private; unsigned int sodi_req_val = 0, sodi_req_mask = 0; unsigned int emi_req_val = 0, emi_req_mask = 0; unsigned int infra_req_val = 0, infra_req_mask = 0; bool en = *((bool *)data); if (id == DDP_COMPONENT_ID_MAX) { /* config when top clk on */ if (!en) return; SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, MT6873_SODI_REQ_SEL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, MT6873_SODI_REQ_VAL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_SEL_RDMA0_PD_MODE); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_VAL_RDMA0_PD_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_MDP_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_WDMA0); } else if (id == DDP_COMPONENT_RDMA0) { SET_VAL_MASK(sodi_req_val, sodi_req_mask, (!en), SODI_REQ_SEL_RDMA0_CG_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, (!en), HRT_URGENT_CTL_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_RDMA0); } else if (id == DDP_COMPONENT_WDMA0) { SET_VAL_MASK(emi_req_val, emi_req_mask, (!en), HRT_URGENT_CTL_SEL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_WDMA0); } else return; if (priv->data->bypass_infra_ddr_control) SET_VAL_MASK(infra_req_val, infra_req_mask, 0x0, MT6833_INFRA_FLD_DDR_MASK); if (handle == NULL) { unsigned int v; v = (readl(priv->config_regs + MMSYS_SODI_REQ_MASK) & (~sodi_req_mask)); v += (sodi_req_val & sodi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_SODI_REQ_MASK); v = (readl(priv->config_regs + MMSYS_EMI_REQ_CTL) & (~emi_req_mask)); v += (emi_req_val & emi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_EMI_REQ_CTL); if (priv->data->bypass_infra_ddr_control) { if (!IS_ERR(priv->infra_regs)) mtk_write_cpu_relaxed( priv->infra_regs + MT6833_INFRA_DISP_DDR_CTL, infra_req_val, infra_req_mask); else DDPINFO("%s: failed to disable infra ddr control\n", __func__); } } else { cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_SODI_REQ_MASK, sodi_req_val, sodi_req_mask); cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_EMI_REQ_CTL, emi_req_val, emi_req_mask); if (priv->data->bypass_infra_ddr_control) { if (priv->infra_regs_pa) { cmdq_pkt_write(handle, NULL, priv->infra_regs_pa + MT6833_INFRA_DISP_DDR_CTL, infra_req_val, infra_req_mask); } else DDPINFO("%s: failed to disable infra ddr control\n", __func__); } } } void mt6873_mtk_sodi_config(struct drm_device *drm, enum mtk_ddp_comp_id id, struct cmdq_pkt *handle, void *data) { struct mtk_drm_private *priv = drm->dev_private; unsigned int sodi_req_val = 0, sodi_req_mask = 0; unsigned int emi_req_val = 0, emi_req_mask = 0; bool en = *((bool *)data); if (id == DDP_COMPONENT_ID_MAX) { /* config when top clk on */ if (!en) return; SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, MT6873_SODI_REQ_SEL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, MT6873_SODI_REQ_VAL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_SEL_RDMA0_PD_MODE); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_VAL_RDMA0_PD_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0x1, HRT_URGENT_CTL_SEL_MDP_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_MDP_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_WDMA0); } else if (id == DDP_COMPONENT_RDMA0) { SET_VAL_MASK(sodi_req_val, sodi_req_mask, (!(unsigned int)en), SODI_REQ_SEL_RDMA0_CG_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, (!(unsigned int)en), HRT_URGENT_CTL_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_RDMA0); } else if (id == DDP_COMPONENT_RDMA4) { SET_VAL_MASK(emi_req_val, emi_req_mask, (!(unsigned int)en), HRT_URGENT_CTL_SEL_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, (unsigned int)en, DVFS_HALT_MASK_SEL_RDMA4); } else if (id == DDP_COMPONENT_WDMA0) { SET_VAL_MASK(emi_req_val, emi_req_mask, (!(unsigned int)en), HRT_URGENT_CTL_SEL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_WDMA0); } else return; if (handle == NULL) { unsigned int v; v = (readl(priv->config_regs + MMSYS_SODI_REQ_MASK) & (~sodi_req_mask)); v += (sodi_req_val & sodi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_SODI_REQ_MASK); v = (readl(priv->config_regs + MMSYS_EMI_REQ_CTL) & (~emi_req_mask)); v += (emi_req_val & emi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_EMI_REQ_CTL); } else { cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_SODI_REQ_MASK, sodi_req_val, sodi_req_mask); cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_EMI_REQ_CTL, emi_req_val, emi_req_mask); } } void mt6885_mtk_sodi_config(struct drm_device *drm, enum mtk_ddp_comp_id id, struct cmdq_pkt *handle, void *data) { struct mtk_drm_private *priv = drm->dev_private; unsigned int sodi_req_val = 0, sodi_req_mask = 0; unsigned int emi_req_val = 0, emi_req_mask = 0; bool en = *((bool *)data); if (id == DDP_COMPONENT_ID_MAX) { /* config when top clk on */ if (!en) return; SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, SODI_REQ_SEL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 0, SODI_REQ_VAL_ALL); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_SEL_RDMA0_PD_MODE); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_VAL_RDMA0_PD_MODE); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_SEL_RDMA1_PD_MODE); SET_VAL_MASK(sodi_req_val, sodi_req_mask, 1, SODI_REQ_VAL_RDMA1_PD_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, 0xFF, HRT_URGENT_CTL_SEL_ALL); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, HRT_URGENT_CTL_VAL_ALL); SET_VAL_MASK(emi_req_val, emi_req_mask, 0, DVFS_HALT_MASK_SEL_ALL); } else if (id == DDP_COMPONENT_RDMA0) { SET_VAL_MASK(sodi_req_val, sodi_req_mask, (!(unsigned int)en), SODI_REQ_SEL_RDMA0_CG_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, (!(unsigned int)en), HRT_URGENT_CTL_SEL_RDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_RDMA0); } else if (id == DDP_COMPONENT_RDMA1) { SET_VAL_MASK(sodi_req_val, sodi_req_mask, (!(unsigned int)en), SODI_REQ_SEL_RDMA1_CG_MODE); SET_VAL_MASK(emi_req_val, emi_req_mask, (!(unsigned int)en), HRT_URGENT_CTL_SEL_RDMA1); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_RDMA1); } else if (id == DDP_COMPONENT_RDMA4) { SET_VAL_MASK(emi_req_val, emi_req_mask, (!(unsigned int)en), HRT_URGENT_CTL_SEL_RDMA4); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_RDMA4); } else if (id == DDP_COMPONENT_RDMA5) { SET_VAL_MASK(emi_req_val, emi_req_mask, (!(unsigned int)en), HRT_URGENT_CTL_SEL_RDMA5); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_RDMA5); } else if (id == DDP_COMPONENT_WDMA0) { SET_VAL_MASK(emi_req_val, emi_req_mask, (!(unsigned int)en), HRT_URGENT_CTL_SEL_WDMA0); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_WDMA0); } else if (id == DDP_COMPONENT_WDMA1) { SET_VAL_MASK(emi_req_val, emi_req_mask, (!(unsigned int)en), HRT_URGENT_CTL_SEL_WDMA1); SET_VAL_MASK(emi_req_val, emi_req_mask, en, DVFS_HALT_MASK_SEL_WDMA1); } else return; if (handle == NULL) { unsigned int v; v = (readl(priv->config_regs + MMSYS_SODI_REQ_MASK) & (~sodi_req_mask)); v += (sodi_req_val & sodi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_SODI_REQ_MASK); v = (readl(priv->config_regs + MMSYS_EMI_REQ_CTL) & (~emi_req_mask)); v += (emi_req_val & emi_req_mask); writel_relaxed(v, priv->config_regs + MMSYS_EMI_REQ_CTL); } else { cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_SODI_REQ_MASK, sodi_req_val, sodi_req_mask); cmdq_pkt_write(handle, NULL, priv->config_regs_pa + MMSYS_EMI_REQ_CTL, emi_req_val, emi_req_mask); } } int mtk_ddp_comp_helper_get_opt(struct mtk_ddp_comp *comp, enum MTK_DRM_HELPER_OPT option) { struct mtk_drm_crtc *mtk_crtc = comp->mtk_crtc; struct mtk_drm_private *priv = NULL; struct mtk_drm_helper *helper_opt = NULL; if (!mtk_crtc) { DDPINFO("%s: crtc is empty\n", __func__); return -EINVAL; } priv = mtk_crtc->base.dev->dev_private; helper_opt = priv->helper_opt; return mtk_drm_helper_get_opt(helper_opt, option); }