diff options
Diffstat (limited to 'drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c')
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 529 |
1 files changed, 343 insertions, 186 deletions
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index a35ecb6676c8..ac834db2e4c1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/delay.h> + +#include <drm/drm_managed.h> + #include "dpu_hwio.h" #include "dpu_hw_ctl.h" #include "dpu_kms.h" @@ -17,6 +20,8 @@ (0x70 + (((lm) - LM_0) * 0x004)) #define CTL_LAYER_EXT3(lm) \ (0xA0 + (((lm) - LM_0) * 0x004)) +#define CTL_LAYER_EXT4(lm) \ + (0xB8 + (((lm) - LM_0) * 0x004)) #define CTL_TOP 0x014 #define CTL_FLUSH 0x018 #define CTL_START 0x01C @@ -24,15 +29,23 @@ #define CTL_SW_RESET 0x030 #define CTL_LAYER_EXTN_OFFSET 0x40 #define CTL_MERGE_3D_ACTIVE 0x0E4 +#define CTL_DSC_ACTIVE 0x0E8 #define CTL_WB_ACTIVE 0x0EC +#define CTL_CWB_ACTIVE 0x0F0 #define CTL_INTF_ACTIVE 0x0F4 +#define CTL_CDM_ACTIVE 0x0F8 +#define CTL_FETCH_PIPE_ACTIVE 0x0FC #define CTL_MERGE_3D_FLUSH 0x100 -#define CTL_DSC_ACTIVE 0x0E8 #define CTL_DSC_FLUSH 0x104 #define CTL_WB_FLUSH 0x108 +#define CTL_CWB_FLUSH 0x10C #define CTL_INTF_FLUSH 0x110 +#define CTL_CDM_FLUSH 0x114 +#define CTL_PERIPH_FLUSH 0x128 +#define CTL_PIPE_ACTIVE 0x12c +#define CTL_LAYER_ACTIVE 0x130 #define CTL_INTF_MASTER 0x134 -#define CTL_FETCH_PIPE_ACTIVE 0x0FC +#define CTL_DSPP_n_FLUSH(n) ((0x13C) + ((n) * 4)) #define CTL_MIXER_BORDER_OUT BIT(24) #define CTL_FLUSH_MASK_CTL BIT(17) @@ -40,31 +53,20 @@ #define DPU_REG_RESET_TIMEOUT_US 2000 #define MERGE_3D_IDX 23 #define DSC_IDX 22 +#define CDM_IDX 26 +#define PERIPH_IDX 30 #define INTF_IDX 31 #define WB_IDX 16 +#define CWB_IDX 28 +#define DSPP_IDX 29 /* From DPU hw rev 7.x.x */ #define CTL_INVALID_BIT 0xffff #define CTL_DEFAULT_GROUP_ID 0xf static const u32 fetch_tbl[SSPP_MAX] = {CTL_INVALID_BIT, 16, 17, 18, 19, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, 0, - 1, 2, 3, CTL_INVALID_BIT, CTL_INVALID_BIT}; + 1, 2, 3, 4, 5}; -static const struct dpu_ctl_cfg *_ctl_offset(enum dpu_ctl ctl, - const struct dpu_mdss_cfg *m, - void __iomem *addr, - struct dpu_hw_blk_reg_map *b) -{ - int i; - - for (i = 0; i < m->ctl_count; i++) { - if (ctl == m->ctl[i].id) { - b->blk_addr = addr + m->ctl[i].base; - b->log_mask = DPU_DBG_MASK_CTL; - return &m->ctl[i]; - } - } - return ERR_PTR(-ENOMEM); -} +static const u32 lm_tbl[LM_MAX] = {CTL_INVALID_BIT, 0, 1, 2, 3, 4, 5, 6, 7}; static int _mixer_stages(const struct dpu_lm_cfg *mixer, int count, enum dpu_lm lm) @@ -113,6 +115,15 @@ static inline void dpu_hw_ctl_clear_pending_flush(struct dpu_hw_ctl *ctx) trace_dpu_hw_ctl_clear_pending_flush(ctx->pending_flush_mask, dpu_hw_ctl_get_flush_register(ctx)); ctx->pending_flush_mask = 0x0; + ctx->pending_intf_flush_mask = 0; + ctx->pending_wb_flush_mask = 0; + ctx->pending_cwb_flush_mask = 0; + ctx->pending_merge_3d_flush_mask = 0; + ctx->pending_dsc_flush_mask = 0; + ctx->pending_cdm_flush_mask = 0; + + memset(ctx->pending_dspp_flush_mask, 0, + sizeof(ctx->pending_dspp_flush_mask)); } static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx, @@ -130,6 +141,8 @@ static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx) static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx) { + int dspp; + if (ctx->pending_flush_mask & BIT(MERGE_3D_IDX)) DPU_REG_WRITE(&ctx->hw, CTL_MERGE_3D_FLUSH, ctx->pending_merge_3d_flush_mask); @@ -139,6 +152,29 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx) if (ctx->pending_flush_mask & BIT(WB_IDX)) DPU_REG_WRITE(&ctx->hw, CTL_WB_FLUSH, ctx->pending_wb_flush_mask); + if (ctx->pending_flush_mask & BIT(CWB_IDX)) + DPU_REG_WRITE(&ctx->hw, CTL_CWB_FLUSH, + ctx->pending_cwb_flush_mask); + + if (ctx->pending_flush_mask & BIT(DSPP_IDX)) + for (dspp = DSPP_0; dspp < DSPP_MAX; dspp++) { + if (ctx->pending_dspp_flush_mask[dspp - DSPP_0]) + DPU_REG_WRITE(&ctx->hw, + CTL_DSPP_n_FLUSH(dspp - DSPP_0), + ctx->pending_dspp_flush_mask[dspp - DSPP_0]); + } + + if (ctx->pending_flush_mask & BIT(PERIPH_IDX)) + DPU_REG_WRITE(&ctx->hw, CTL_PERIPH_FLUSH, + ctx->pending_periph_flush_mask); + + if (ctx->pending_flush_mask & BIT(DSC_IDX)) + DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH, + ctx->pending_dsc_flush_mask); + + if (ctx->pending_flush_mask & BIT(CDM_IDX)) + DPU_REG_WRITE(&ctx->hw, CTL_CDM_FLUSH, + ctx->pending_cdm_flush_mask); DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask); } @@ -190,6 +226,12 @@ static void dpu_hw_ctl_update_pending_flush_sspp(struct dpu_hw_ctl *ctx, case SSPP_DMA3: ctx->pending_flush_mask |= BIT(25); break; + case SSPP_DMA4: + ctx->pending_flush_mask |= BIT(13); + break; + case SSPP_DMA5: + ctx->pending_flush_mask |= BIT(14); + break; case SSPP_CURSOR0: ctx->pending_flush_mask |= BIT(22); break; @@ -223,6 +265,12 @@ static void dpu_hw_ctl_update_pending_flush_mixer(struct dpu_hw_ctl *ctx, case LM_5: ctx->pending_flush_mask |= BIT(20); break; + case LM_6: + ctx->pending_flush_mask |= BIT(21); + break; + case LM_7: + ctx->pending_flush_mask |= BIT(27); + break; default: break; } @@ -265,6 +313,13 @@ static void dpu_hw_ctl_update_pending_flush_wb(struct dpu_hw_ctl *ctx, } } +static void dpu_hw_ctl_update_pending_flush_cdm(struct dpu_hw_ctl *ctx, enum dpu_cdm cdm_num) +{ + /* update pending flush only if CDM_0 is flushed */ + if (cdm_num == CDM_0) + ctx->pending_flush_mask |= BIT(CDM_IDX); +} + static void dpu_hw_ctl_update_pending_flush_wb_v1(struct dpu_hw_ctl *ctx, enum dpu_wb wb) { @@ -272,6 +327,13 @@ static void dpu_hw_ctl_update_pending_flush_wb_v1(struct dpu_hw_ctl *ctx, ctx->pending_flush_mask |= BIT(WB_IDX); } +static void dpu_hw_ctl_update_pending_flush_cwb_v1(struct dpu_hw_ctl *ctx, + enum dpu_cwb cwb) +{ + ctx->pending_cwb_flush_mask |= BIT(cwb - CWB_0); + ctx->pending_flush_mask |= BIT(CWB_IDX); +} + static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx, enum dpu_intf intf) { @@ -279,6 +341,13 @@ static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx, ctx->pending_flush_mask |= BIT(INTF_IDX); } +static void dpu_hw_ctl_update_pending_flush_periph_v1(struct dpu_hw_ctl *ctx, + enum dpu_intf intf) +{ + ctx->pending_periph_flush_mask |= BIT(intf - INTF_0); + ctx->pending_flush_mask |= BIT(PERIPH_IDX); +} + static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx, enum dpu_merge_3d merge_3d) { @@ -286,8 +355,21 @@ static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx, ctx->pending_flush_mask |= BIT(MERGE_3D_IDX); } +static void dpu_hw_ctl_update_pending_flush_dsc_v1(struct dpu_hw_ctl *ctx, + enum dpu_dsc dsc_num) +{ + ctx->pending_dsc_flush_mask |= BIT(dsc_num - DSC_0); + ctx->pending_flush_mask |= BIT(DSC_IDX); +} + +static void dpu_hw_ctl_update_pending_flush_cdm_v1(struct dpu_hw_ctl *ctx, enum dpu_cdm cdm_num) +{ + ctx->pending_cdm_flush_mask |= BIT(cdm_num - CDM_0); + ctx->pending_flush_mask |= BIT(CDM_IDX); +} + static void dpu_hw_ctl_update_pending_flush_dspp(struct dpu_hw_ctl *ctx, - enum dpu_dspp dspp) + enum dpu_dspp dspp, u32 dspp_sub_blk) { switch (dspp) { case DSPP_0: @@ -307,6 +389,23 @@ static void dpu_hw_ctl_update_pending_flush_dspp(struct dpu_hw_ctl *ctx, } } +static void dpu_hw_ctl_update_pending_flush_dspp_sub_blocks( + struct dpu_hw_ctl *ctx, enum dpu_dspp dspp, u32 dspp_sub_blk) +{ + if (dspp >= DSPP_MAX) + return; + + switch (dspp_sub_blk) { + case DPU_DSPP_PCC: + ctx->pending_dspp_flush_mask[dspp - DSPP_0] |= BIT(4); + break; + default: + return; + } + + ctx->pending_flush_mask |= BIT(DSPP_IDX); +} + static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us) { struct dpu_hw_blk_reg_map *c = &ctx->hw; @@ -377,12 +476,37 @@ static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx) DPU_REG_WRITE(c, CTL_FETCH_PIPE_ACTIVE, 0); } +struct ctl_blend_config { + int idx, shift, ext_shift; +}; + +static const struct ctl_blend_config ctl_blend_config[][2] = { + [SSPP_NONE] = { { -1 }, { -1 } }, + [SSPP_MAX] = { { -1 }, { -1 } }, + [SSPP_VIG0] = { { 0, 0, 0 }, { 3, 0 } }, + [SSPP_VIG1] = { { 0, 3, 2 }, { 3, 4 } }, + [SSPP_VIG2] = { { 0, 6, 4 }, { 3, 8 } }, + [SSPP_VIG3] = { { 0, 26, 6 }, { 3, 12 } }, + [SSPP_RGB0] = { { 0, 9, 8 }, { -1 } }, + [SSPP_RGB1] = { { 0, 12, 10 }, { -1 } }, + [SSPP_RGB2] = { { 0, 15, 12 }, { -1 } }, + [SSPP_RGB3] = { { 0, 29, 14 }, { -1 } }, + [SSPP_DMA0] = { { 0, 18, 16 }, { 2, 8 } }, + [SSPP_DMA1] = { { 0, 21, 18 }, { 2, 12 } }, + [SSPP_DMA2] = { { 2, 0 }, { 2, 16 } }, + [SSPP_DMA3] = { { 2, 4 }, { 2, 20 } }, + [SSPP_DMA4] = { { 4, 0 }, { 4, 8 } }, + [SSPP_DMA5] = { { 4, 4 }, { 4, 12 } }, + [SSPP_CURSOR0] = { { 1, 20 }, { -1 } }, + [SSPP_CURSOR1] = { { 1, 26 }, { -1 } }, +}; + static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx, enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg) { struct dpu_hw_blk_reg_map *c = &ctx->hw; - u32 mixercfg = 0, mixercfg_ext = 0, mix, ext; - u32 mixercfg_ext2 = 0, mixercfg_ext3 = 0; + u32 mix, ext, mix_ext; + u32 mixercfg[5] = { 0 }; int i, j; int stages; int pipes_per_stage; @@ -397,7 +521,7 @@ static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx, else pipes_per_stage = 1; - mixercfg = CTL_MIXER_BORDER_OUT; /* always set BORDER_OUT */ + mixercfg[0] = CTL_MIXER_BORDER_OUT; /* always set BORDER_OUT */ if (!stage_cfg) goto exit; @@ -406,109 +530,37 @@ static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx, /* overflow to ext register if 'i + 1 > 7' */ mix = (i + 1) & 0x7; ext = i >= 7; + mix_ext = (i + 1) & 0xf; for (j = 0 ; j < pipes_per_stage; j++) { enum dpu_sspp_multirect_index rect_index = stage_cfg->multirect_index[i][j]; - - switch (stage_cfg->stage[i][j]) { - case SSPP_VIG0: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext3 |= ((i + 1) & 0xF) << 0; - } else { - mixercfg |= mix << 0; - mixercfg_ext |= ext << 0; - } - break; - case SSPP_VIG1: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext3 |= ((i + 1) & 0xF) << 4; - } else { - mixercfg |= mix << 3; - mixercfg_ext |= ext << 2; - } - break; - case SSPP_VIG2: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext3 |= ((i + 1) & 0xF) << 8; - } else { - mixercfg |= mix << 6; - mixercfg_ext |= ext << 4; - } - break; - case SSPP_VIG3: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext3 |= ((i + 1) & 0xF) << 12; - } else { - mixercfg |= mix << 26; - mixercfg_ext |= ext << 6; - } - break; - case SSPP_RGB0: - mixercfg |= mix << 9; - mixercfg_ext |= ext << 8; - break; - case SSPP_RGB1: - mixercfg |= mix << 12; - mixercfg_ext |= ext << 10; - break; - case SSPP_RGB2: - mixercfg |= mix << 15; - mixercfg_ext |= ext << 12; - break; - case SSPP_RGB3: - mixercfg |= mix << 29; - mixercfg_ext |= ext << 14; - break; - case SSPP_DMA0: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext2 |= ((i + 1) & 0xF) << 8; - } else { - mixercfg |= mix << 18; - mixercfg_ext |= ext << 16; - } - break; - case SSPP_DMA1: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext2 |= ((i + 1) & 0xF) << 12; - } else { - mixercfg |= mix << 21; - mixercfg_ext |= ext << 18; - } - break; - case SSPP_DMA2: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext2 |= ((i + 1) & 0xF) << 16; - } else { - mix |= (i + 1) & 0xF; - mixercfg_ext2 |= mix << 0; - } - break; - case SSPP_DMA3: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext2 |= ((i + 1) & 0xF) << 20; - } else { - mix |= (i + 1) & 0xF; - mixercfg_ext2 |= mix << 4; - } - break; - case SSPP_CURSOR0: - mixercfg_ext |= ((i + 1) & 0xF) << 20; - break; - case SSPP_CURSOR1: - mixercfg_ext |= ((i + 1) & 0xF) << 26; - break; - default: - break; + enum dpu_sspp pipe = stage_cfg->stage[i][j]; + const struct ctl_blend_config *cfg = + &ctl_blend_config[pipe][rect_index == DPU_SSPP_RECT_1]; + + /* + * CTL_LAYER has 3-bit field (and extra bits in EXT register), + * all EXT registers has 4-bit fields. + */ + if (cfg->idx == -1) { + continue; + } else if (cfg->idx == 0) { + mixercfg[0] |= mix << cfg->shift; + mixercfg[1] |= ext << cfg->ext_shift; + } else { + mixercfg[cfg->idx] |= mix_ext << cfg->shift; } } } exit: - DPU_REG_WRITE(c, CTL_LAYER(lm), mixercfg); - DPU_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg_ext); - DPU_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg_ext2); - DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg_ext3); + DPU_REG_WRITE(c, CTL_LAYER(lm), mixercfg[0]); + DPU_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg[1]); + DPU_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg[2]); + DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg[3]); + if (ctx->mdss_ver->core_major_ver >= 9) + DPU_REG_WRITE(c, CTL_LAYER_EXT4(lm), mixercfg[4]); } @@ -517,24 +569,27 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx, { struct dpu_hw_blk_reg_map *c = &ctx->hw; u32 intf_active = 0; + u32 dsc_active = 0; u32 wb_active = 0; + u32 cwb_active = 0; u32 mode_sel = 0; + u32 merge_3d_active = 0; /* CTL_TOP[31:28] carries group_id to collate CTL paths * per VM. Explicitly disable it until VM support is * added in SW. Power on reset value is not disable. */ - if ((test_bit(DPU_CTL_VM_CFG, &ctx->caps->features))) + if (ctx->mdss_ver->core_major_ver >= 7) mode_sel = CTL_DEFAULT_GROUP_ID << 28; - if (cfg->dsc) - DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH, cfg->dsc); - if (cfg->intf_mode_sel == DPU_CTL_MODE_SEL_CMD) mode_sel |= BIT(17); intf_active = DPU_REG_READ(c, CTL_INTF_ACTIVE); wb_active = DPU_REG_READ(c, CTL_WB_ACTIVE); + cwb_active = DPU_REG_READ(c, CTL_CWB_ACTIVE); + dsc_active = DPU_REG_READ(c, CTL_DSC_ACTIVE); + merge_3d_active = DPU_REG_READ(c, CTL_MERGE_3D_ACTIVE); if (cfg->intf) intf_active |= BIT(cfg->intf - INTF_0); @@ -542,17 +597,27 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx, if (cfg->wb) wb_active |= BIT(cfg->wb - WB_0); + if (cfg->cwb) + cwb_active |= cfg->cwb; + + if (cfg->dsc) + dsc_active |= cfg->dsc; + + if (cfg->merge_3d) + merge_3d_active |= BIT(cfg->merge_3d - MERGE_3D_0); + DPU_REG_WRITE(c, CTL_TOP, mode_sel); DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active); DPU_REG_WRITE(c, CTL_WB_ACTIVE, wb_active); + DPU_REG_WRITE(c, CTL_CWB_ACTIVE, cwb_active); + DPU_REG_WRITE(c, CTL_DSC_ACTIVE, dsc_active); + DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, merge_3d_active); - if (cfg->merge_3d) - DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, - BIT(cfg->merge_3d - MERGE_3D_0)); - if (cfg->dsc) { - DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, DSC_IDX); - DPU_REG_WRITE(c, CTL_DSC_ACTIVE, cfg->dsc); - } + if (cfg->intf_master) + DPU_REG_WRITE(c, CTL_INTF_MASTER, BIT(cfg->intf_master - INTF_0)); + + if (cfg->cdm) + DPU_REG_WRITE(c, CTL_CDM_ACTIVE, cfg->cdm); } static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx, @@ -593,8 +658,12 @@ static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx, { struct dpu_hw_blk_reg_map *c = &ctx->hw; u32 intf_active = 0; + u32 intf_master = 0; u32 wb_active = 0; + u32 cwb_active = 0; u32 merge3d_active = 0; + u32 dsc_active; + u32 cdm_active; /* * This API resets each portion of the CTL path namely, @@ -611,12 +680,36 @@ static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx, merge3d_active); } - dpu_hw_ctl_clear_all_blendstages(ctx); + if (ctx->ops.clear_all_blendstages) + ctx->ops.clear_all_blendstages(ctx); + + if (ctx->ops.set_active_lms) + ctx->ops.set_active_lms(ctx, NULL); + + if (ctx->ops.set_active_fetch_pipes) + ctx->ops.set_active_fetch_pipes(ctx, NULL); + + if (ctx->ops.set_active_pipes) + ctx->ops.set_active_pipes(ctx, NULL); if (cfg->intf) { intf_active = DPU_REG_READ(c, CTL_INTF_ACTIVE); intf_active &= ~BIT(cfg->intf - INTF_0); DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active); + + intf_master = DPU_REG_READ(c, CTL_INTF_MASTER); + + /* Unset this intf as master, if it is the current master */ + if (intf_master == BIT(cfg->intf - INTF_0)) { + DPU_DEBUG_DRIVER("Unsetting INTF_%d master\n", cfg->intf - INTF_0); + DPU_REG_WRITE(c, CTL_INTF_MASTER, 0); + } + } + + if (cfg->cwb) { + cwb_active = DPU_REG_READ(c, CTL_CWB_ACTIVE); + cwb_active &= ~cfg->cwb; + DPU_REG_WRITE(c, CTL_CWB_ACTIVE, cwb_active); } if (cfg->wb) { @@ -624,10 +717,22 @@ static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx, wb_active &= ~BIT(cfg->wb - WB_0); DPU_REG_WRITE(c, CTL_WB_ACTIVE, wb_active); } + + if (cfg->dsc) { + dsc_active = DPU_REG_READ(c, CTL_DSC_ACTIVE); + dsc_active &= ~cfg->dsc; + DPU_REG_WRITE(c, CTL_DSC_ACTIVE, dsc_active); + } + + if (cfg->cdm) { + cdm_active = DPU_REG_READ(c, CTL_CDM_ACTIVE); + cdm_active &= ~cfg->cdm; + DPU_REG_WRITE(c, CTL_CDM_ACTIVE, cdm_active); + } } -static void dpu_hw_ctl_set_fetch_pipe_active(struct dpu_hw_ctl *ctx, - unsigned long *fetch_active) +static void dpu_hw_ctl_set_active_fetch_pipes(struct dpu_hw_ctl *ctx, + unsigned long *fetch_active) { int i; u32 val = 0; @@ -643,71 +748,123 @@ static void dpu_hw_ctl_set_fetch_pipe_active(struct dpu_hw_ctl *ctx, DPU_REG_WRITE(&ctx->hw, CTL_FETCH_PIPE_ACTIVE, val); } -static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops, - unsigned long cap) +static void dpu_hw_ctl_set_active_pipes(struct dpu_hw_ctl *ctx, + unsigned long *active_pipes) { - if (cap & BIT(DPU_CTL_ACTIVE_CFG)) { - ops->trigger_flush = dpu_hw_ctl_trigger_flush_v1; - ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg_v1; - ops->reset_intf_cfg = dpu_hw_ctl_reset_intf_cfg_v1; - ops->update_pending_flush_intf = - dpu_hw_ctl_update_pending_flush_intf_v1; - ops->update_pending_flush_merge_3d = - dpu_hw_ctl_update_pending_flush_merge_3d_v1; - ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb_v1; - } else { - ops->trigger_flush = dpu_hw_ctl_trigger_flush; - ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg; - ops->update_pending_flush_intf = - dpu_hw_ctl_update_pending_flush_intf; - ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb; + int i; + u32 val = 0; + + if (active_pipes) { + for (i = 0; i < SSPP_MAX; i++) { + if (test_bit(i, active_pipes) && + fetch_tbl[i] != CTL_INVALID_BIT) + val |= BIT(fetch_tbl[i]); + } } - ops->clear_pending_flush = dpu_hw_ctl_clear_pending_flush; - ops->update_pending_flush = dpu_hw_ctl_update_pending_flush; - ops->get_pending_flush = dpu_hw_ctl_get_pending_flush; - ops->get_flush_register = dpu_hw_ctl_get_flush_register; - ops->trigger_start = dpu_hw_ctl_trigger_start; - ops->is_started = dpu_hw_ctl_is_started; - ops->trigger_pending = dpu_hw_ctl_trigger_pending; - ops->reset = dpu_hw_ctl_reset_control; - ops->wait_reset_status = dpu_hw_ctl_wait_reset_status; - ops->clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages; - ops->setup_blendstage = dpu_hw_ctl_setup_blendstage; - ops->update_pending_flush_sspp = dpu_hw_ctl_update_pending_flush_sspp; - ops->update_pending_flush_mixer = dpu_hw_ctl_update_pending_flush_mixer; - ops->update_pending_flush_dspp = dpu_hw_ctl_update_pending_flush_dspp; - if (cap & BIT(DPU_CTL_FETCH_ACTIVE)) - ops->set_active_pipes = dpu_hw_ctl_set_fetch_pipe_active; -}; -struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx, - void __iomem *addr, - const struct dpu_mdss_cfg *m) + DPU_REG_WRITE(&ctx->hw, CTL_PIPE_ACTIVE, val); +} + +static void dpu_hw_ctl_set_active_lms(struct dpu_hw_ctl *ctx, + unsigned long *active_lms) +{ + int i; + u32 val = 0; + + if (active_lms) { + for (i = LM_0; i < LM_MAX; i++) { + if (test_bit(i, active_lms) && + lm_tbl[i] != CTL_INVALID_BIT) + val |= BIT(lm_tbl[i]); + } + } + + DPU_REG_WRITE(&ctx->hw, CTL_LAYER_ACTIVE, val); +} + +/** + * dpu_hw_ctl_init() - Initializes the ctl_path hw driver object. + * Should be called before accessing any ctl_path register. + * @dev: Corresponding device for devres management + * @cfg: ctl_path catalog entry for which driver object is required + * @addr: mapped register io address of MDP + * @mdss_ver: dpu core's major and minor versions + * @mixer_count: Number of mixers in @mixer + * @mixer: Pointer to an array of Layer Mixers defined in the catalog + */ +struct dpu_hw_ctl *dpu_hw_ctl_init(struct drm_device *dev, + const struct dpu_ctl_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_ver, + u32 mixer_count, + const struct dpu_lm_cfg *mixer) { struct dpu_hw_ctl *c; - const struct dpu_ctl_cfg *cfg; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); - cfg = _ctl_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { - kfree(c); - pr_err("failed to create dpu_hw_ctl %d\n", idx); - return ERR_PTR(-EINVAL); - } + c->hw.blk_addr = addr + cfg->base; + c->hw.log_mask = DPU_DBG_MASK_CTL; c->caps = cfg; - _setup_ctl_ops(&c->ops, c->caps->features); - c->idx = idx; - c->mixer_count = m->mixer_count; - c->mixer_hw_caps = m->mixer; + c->mdss_ver = mdss_ver; - return c; -} + if (mdss_ver->core_major_ver >= 5) { + c->ops.trigger_flush = dpu_hw_ctl_trigger_flush_v1; + c->ops.setup_intf_cfg = dpu_hw_ctl_intf_cfg_v1; + c->ops.reset_intf_cfg = dpu_hw_ctl_reset_intf_cfg_v1; + c->ops.update_pending_flush_intf = + dpu_hw_ctl_update_pending_flush_intf_v1; -void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx) -{ - kfree(ctx); + c->ops.update_pending_flush_periph = + dpu_hw_ctl_update_pending_flush_periph_v1; + + c->ops.update_pending_flush_merge_3d = + dpu_hw_ctl_update_pending_flush_merge_3d_v1; + c->ops.update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb_v1; + c->ops.update_pending_flush_cwb = dpu_hw_ctl_update_pending_flush_cwb_v1; + c->ops.update_pending_flush_dsc = + dpu_hw_ctl_update_pending_flush_dsc_v1; + c->ops.update_pending_flush_cdm = dpu_hw_ctl_update_pending_flush_cdm_v1; + } else { + c->ops.trigger_flush = dpu_hw_ctl_trigger_flush; + c->ops.setup_intf_cfg = dpu_hw_ctl_intf_cfg; + c->ops.update_pending_flush_intf = + dpu_hw_ctl_update_pending_flush_intf; + c->ops.update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb; + c->ops.update_pending_flush_cdm = dpu_hw_ctl_update_pending_flush_cdm; + } + c->ops.clear_pending_flush = dpu_hw_ctl_clear_pending_flush; + c->ops.update_pending_flush = dpu_hw_ctl_update_pending_flush; + c->ops.get_pending_flush = dpu_hw_ctl_get_pending_flush; + c->ops.get_flush_register = dpu_hw_ctl_get_flush_register; + c->ops.trigger_start = dpu_hw_ctl_trigger_start; + c->ops.is_started = dpu_hw_ctl_is_started; + c->ops.trigger_pending = dpu_hw_ctl_trigger_pending; + c->ops.reset = dpu_hw_ctl_reset_control; + c->ops.wait_reset_status = dpu_hw_ctl_wait_reset_status; + if (mdss_ver->core_major_ver < 12) { + c->ops.clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages; + c->ops.setup_blendstage = dpu_hw_ctl_setup_blendstage; + } else { + c->ops.set_active_pipes = dpu_hw_ctl_set_active_pipes; + c->ops.set_active_lms = dpu_hw_ctl_set_active_lms; + } + c->ops.update_pending_flush_sspp = dpu_hw_ctl_update_pending_flush_sspp; + c->ops.update_pending_flush_mixer = dpu_hw_ctl_update_pending_flush_mixer; + if (mdss_ver->core_major_ver >= 7) + c->ops.update_pending_flush_dspp = dpu_hw_ctl_update_pending_flush_dspp_sub_blocks; + else + c->ops.update_pending_flush_dspp = dpu_hw_ctl_update_pending_flush_dspp; + + if (mdss_ver->core_major_ver >= 7) + c->ops.set_active_fetch_pipes = dpu_hw_ctl_set_active_fetch_pipes; + + c->idx = cfg->id; + c->mixer_count = mixer_count; + c->mixer_hw_caps = mixer; + + return c; } |
