diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index c1fef54e12..ae373e7bec 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -1351,6 +1351,7 @@ struct sde_reg_dma_blk_info { * @broadcast_disabled flag indicating if broadcast usage should be avoided * @xin_id VBIF xin client-id for LUTDMA * @vbif_idx VBIF id (RT/NRT) + * @base_off Base offset of LUTDMA from the MDSS root * @clk_ctrl VBIF xin client clk-ctrl */ struct sde_reg_dma_cfg { @@ -1360,6 +1361,7 @@ struct sde_reg_dma_cfg { u32 broadcast_disabled; u32 xin_id; u32 vbif_idx; + u32 base_off; enum sde_clk_ctrl_type clk_ctrl; }; diff --git a/msm/sde/sde_hw_reg_dma_v1.c b/msm/sde/sde_hw_reg_dma_v1.c index 47dddd89a4..d73d32d98c 100644 --- a/msm/sde/sde_hw_reg_dma_v1.c +++ b/msm/sde/sde_hw_reg_dma_v1.c @@ -254,6 +254,9 @@ static int write_multi_reg(struct sde_reg_dma_setup_ops_cfg *cfg) cfg->dma_buf->next_op_allowed = REG_WRITE_OP | DECODE_SEL_OP; cfg->dma_buf->ops_completed |= REG_WRITE_OP; + if (cfg->blk == MDSS) + cfg->dma_buf->abs_write_cnt += SIZE_DWORD(cfg->data_size); + return 0; } @@ -319,8 +322,10 @@ static int write_single_reg(struct sde_reg_dma_setup_ops_cfg *cfg) cfg->dma_buf->index); loc[0] = SINGLE_REG_WRITE_OPCODE; loc[0] |= (cfg->blk_offset & MAX_RELATIVE_OFF); - if (cfg->blk == MDSS) + if (cfg->blk == MDSS) { loc[0] |= ABSOLUTE_RANGE; + cfg->dma_buf->abs_write_cnt++; + } loc[1] = *cfg->data; cfg->dma_buf->index += ops_mem_size[cfg->ops]; @@ -624,6 +629,32 @@ static int validate_kick_off_v1(struct sde_reg_dma_kickoff_cfg *cfg) return -EINVAL; } + if ((cfg->dma_buf->abs_write_cnt % 2) != 0) { + /* Touch up buffer to avoid HW issues with odd number of abs writes */ + u32 reg = 0; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + + dma_write_cfg.dma_buf = cfg->dma_buf; + dma_write_cfg.blk = MDSS; + dma_write_cfg.feature = REG_DMA_FEATURES_MAX; + dma_write_cfg.ops = HW_BLK_SELECT; + if (validate_write_decode_sel(&dma_write_cfg) || write_decode_sel(&dma_write_cfg)) { + DRM_ERROR("Failed setting MDSS decode select for LUTDMA touch up\n"); + return -EINVAL; + } + + /* Perform dummy write on LUTDMA RO version reg */ + dma_write_cfg.ops = REG_SINGLE_WRITE; + dma_write_cfg.blk_offset = reg_dma->caps->base_off + + reg_dma->caps->reg_dma_blks[cfg->dma_type].base; + dma_write_cfg.data = ® + dma_write_cfg.data_size = sizeof(uint32_t); + if (validate_write_reg(&dma_write_cfg) || write_single_reg(&dma_write_cfg)) { + DRM_ERROR("Failed to add touch up write to LUTDMA buffer\n"); + return -EINVAL; + } + } + return 0; } @@ -1110,6 +1141,7 @@ static int reset_reg_dma_buffer_v1(struct sde_reg_dma_buffer *lut_buf) lut_buf->index = 0; lut_buf->ops_completed = 0; lut_buf->next_op_allowed = DECODE_SEL_OP; + lut_buf->abs_write_cnt = 0; return 0; } diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 1ff25f18e6..5de7001b0c 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -4556,7 +4556,9 @@ static int _sde_kms_hw_init_ioremap(struct sde_kms *sde_kms, sde_kms->reg_dma = NULL; SDE_DEBUG("REG_DMA is not defined"); } else { + unsigned long mdp_addr = msm_get_phys_addr(platformdev, "mdp_phys"); sde_kms->reg_dma_len = msm_iomap_size(platformdev, "regdma_phys"); + sde_kms->reg_dma_off = msm_get_phys_addr(platformdev, "regdma_phys") - mdp_addr; rc = sde_dbg_reg_register_base("reg_dma", sde_kms->reg_dma, sde_kms->reg_dma_len, msm_get_phys_addr(platformdev, "regdma_phys"), @@ -4650,6 +4652,7 @@ static int _sde_kms_hw_init_blocks(struct sde_kms *sde_kms, } /* Initialize reg dma block which is a singleton */ + sde_kms->catalog->dma_cfg.base_off = sde_kms->reg_dma_off; rc = sde_reg_dma_init(sde_kms->reg_dma, sde_kms->catalog, sde_kms->dev); if (rc) { diff --git a/msm/sde/sde_kms.h b/msm/sde/sde_kms.h index fe78d4c727..1f809bf724 100644 --- a/msm/sde/sde_kms.h +++ b/msm/sde/sde_kms.h @@ -262,6 +262,7 @@ struct sde_kms { /* io/register spaces: */ void __iomem *mmio, *vbif[VBIF_MAX], *reg_dma, *sid; unsigned long mmio_len, vbif_len[VBIF_MAX], reg_dma_len, sid_len; + unsigned long reg_dma_off; struct regulator *vdd; struct regulator *mmagic; diff --git a/msm/sde/sde_reg_dma.h b/msm/sde/sde_reg_dma.h index eb1feb0298..1a5f2b74f0 100644 --- a/msm/sde/sde_reg_dma.h +++ b/msm/sde/sde_reg_dma.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _SDE_REG_DMA_H @@ -232,6 +232,7 @@ enum sde_reg_dma_last_cmd_mode { * @vaddr: cpu address * @next_op_allowed: operation allowed on the buffer * @ops_completed: operations completed on buffer + * @abs_write_cnt: count of mdss absolute addr writes in the current buffer */ struct sde_reg_dma_buffer { struct drm_gem_object *buf; @@ -242,6 +243,7 @@ struct sde_reg_dma_buffer { void *vaddr; u32 next_op_allowed; u32 ops_completed; + u32 abs_write_cnt; }; /**