From 95300ca3df645b014aa2bdde3caebcdc0b89fb10 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Wed, 7 Jul 2021 11:21:29 -0700 Subject: [PATCH] disp: msm: sde: add programmable lineptr support for writeback From MDSS 9.0, writeback supports a programmable lineptr support, which generates an interrupt when the configured writeback output height is reached. Add software support to configure the prog_line and to process the interrupt. Change-Id: I3293ad2984c51417e4691c5b11e9c9a010067e1c Signed-off-by: Veera Sundaram Sankaran --- msm/sde/sde_encoder_phys.h | 2 ++ msm/sde/sde_encoder_phys_wb.c | 20 ++++++++++++++++++++ msm/sde/sde_hw_catalog.c | 9 +++++++++ msm/sde/sde_hw_catalog.h | 3 +++ msm/sde/sde_hw_interrupts.c | 24 ++++++++++++++++++++++++ msm/sde/sde_hw_interrupts.h | 2 ++ msm/sde/sde_hw_wb.c | 25 +++++++++++++++++++++++++ msm/sde/sde_hw_wb.h | 13 +++++++++++++ 8 files changed, 98 insertions(+) diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 96a9913c02..e06f76d36a 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -205,6 +205,7 @@ struct sde_encoder_phys_ops { * @INTR_IDX_AUTOREFRESH_DONE: Autorefresh done for cmd mode panel meaning * autorefresh has triggered a double buffer flip * @INTR_IDX_WRPTR: Writepointer start interrupt for cmd mode panel + * @INTR_IDX_WB_LINEPTR: Programmable lineptr interrupt for WB */ enum sde_intr_idx { INTR_IDX_VSYNC, @@ -221,6 +222,7 @@ enum sde_intr_idx { INTR_IDX_PP5_OVFL, INTR_IDX_PP_CWB_OVFL, INTR_IDX_WRPTR, + INTR_IDX_WB_LINEPTR, INTR_IDX_MAX, }; diff --git a/msm/sde/sde_encoder_phys_wb.c b/msm/sde/sde_encoder_phys_wb.c index f505d3da27..b51ab66946 100644 --- a/msm/sde/sde_encoder_phys_wb.c +++ b/msm/sde/sde_encoder_phys_wb.c @@ -1283,6 +1283,19 @@ static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx) _sde_encoder_phys_wb_frame_done_helper(arg, false); } +static void sde_encoder_phys_wb_lineptr_irq(void *arg, int irq_idx) +{ + struct sde_encoder_phys_wb *wb_enc = arg; + struct sde_encoder_phys *phys_enc; + + if (!wb_enc) + return; + + phys_enc = &wb_enc->base; + + SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc)); +} + /** * sde_encoder_phys_wb_irq_ctrl - irq control of WB * @phys: Pointer to physical encoder @@ -2133,6 +2146,13 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( irq->intr_idx = INTR_IDX_CTL_START; irq->cb.func = sde_encoder_phys_wb_ctl_start_irq; + irq = &phys_enc->irq[INTR_IDX_WB_LINEPTR]; + irq->name = "lineptr_irq"; + irq->hw_idx = wb_enc->hw_wb->idx; + irq->intr_type = SDE_IRQ_TYPE_WB_PROG_LINE; + irq->intr_idx = INTR_IDX_WB_LINEPTR; + irq->cb.func = sde_encoder_phys_wb_lineptr_irq; + if (wb_cfg && (wb_cfg->features & BIT(SDE_WB_HAS_DCWB))) { irq = &phys_enc->irq[INTR_IDX_PP_CWB_OVFL]; irq->name = "pp_cwb0_overflow"; diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 5d1da03133..0e13e6219f 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -1348,6 +1348,10 @@ static int _add_to_irq_offset_list(struct sde_mdss_cfg *sde_cfg, if (instance >= LTM_MAX) err = true; break; + case SDE_INTR_HWBLK_WB: + if (instance >= WB_MAX) + err = true; + break; default: SDE_ERROR("invalid hwblk_type: %d", blk_type); return -EINVAL; @@ -2555,6 +2559,11 @@ static int sde_wb_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) set_bit(SDE_WB_INPUT_CTRL, &wb->features); + if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_900)) + set_bit(SDE_WB_PROG_LINE, &wb->features); + + rc = _add_to_irq_offset_list(sde_cfg, SDE_INTR_HWBLK_WB, wb->id, wb->base); + if (test_bit(SDE_FEATURE_DEDICATED_CWB, sde_cfg->features)) { set_bit(SDE_WB_HAS_DCWB, &wb->features); if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 6f99579cd8..6ebf3cdb02 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -196,6 +196,7 @@ enum sde_intr_hwblk_type { SDE_INTR_HWBLK_AD4, SDE_INTR_HWBLK_INTF_TEAR, SDE_INTR_HWBLK_LTM, + SDE_INTR_HWBLK_WB, SDE_INTR_HWBLK_MAX }; @@ -552,6 +553,7 @@ enum { * @SDE_WB_CWB_CTRL Separate CWB control is available for configuring * @SDE_WB_DCWB_CTRL Separate DCWB control is available for configuring * @SDE_WB_CWB_DITHER_CTRL CWB dither is available for configuring + * @SDE_WB_PROG_LINE Writeback block supports programmable line ptr * @SDE_WB_MAX maximum value */ enum { @@ -573,6 +575,7 @@ enum { SDE_WB_CWB_CTRL, SDE_WB_DCWB_CTRL, SDE_WB_CWB_DITHER_CTRL, + SDE_WB_PROG_LINE, SDE_WB_MAX }; diff --git a/msm/sde/sde_hw_interrupts.c b/msm/sde/sde_hw_interrupts.c index 91528bbef7..539b9409b1 100644 --- a/msm/sde/sde_hw_interrupts.c +++ b/msm/sde/sde_hw_interrupts.c @@ -27,6 +27,9 @@ #define MDP_LTM_INTR_EN_OFF 0x50 #define MDP_LTM_INTR_STATUS_OFF 0x54 #define MDP_LTM_INTR_CLEAR_OFF 0x58 +#define MDP_WB_INTR_EN_OFF 0x18C +#define MDP_WB_INTR_STATUS_OFF 0x190 +#define MDP_WB_INTR_CLEAR_OFF 0x194 /** * WB interrupt status bit definitions @@ -193,6 +196,11 @@ #define SDE_INTR_LTM_STATS_DONE BIT(0) #define SDE_INTR_LTM_STATS_WB_PB BIT(5) +/** + * WB interrupt status bit definitions + */ +#define SDE_INTR_WB_PROG_LINE BIT(0) + /** * struct sde_intr_reg - array of SDE register sets * @clr_off: offset to CLEAR reg @@ -425,6 +433,10 @@ static struct sde_irq_type sde_irq_ltm_map[] = { { SDE_IRQ_TYPE_LTM_STATS_WB_PB, -1, SDE_INTR_LTM_STATS_WB_PB, -1}, }; +static struct sde_irq_type sde_irq_wb_map[] = { + { SDE_IRQ_TYPE_WB_PROG_LINE, -1, SDE_INTR_WB_PROG_LINE, -1}, +}; + static int sde_hw_intr_irqidx_lookup(struct sde_hw_intr *intr, enum sde_intr_type intr_type, u32 instance_idx) { @@ -867,6 +879,12 @@ static int _set_sde_irq_tbl_offset(struct sde_intr_reg *sde_irq, sde_irq->en_off = base_offset + MDP_LTM_INTR_EN_OFF; sde_irq->status_off = base_offset + MDP_LTM_INTR_STATUS_OFF; break; + case SDE_INTR_HWBLK_WB: + sde_irq->clr_off = base_offset + MDP_WB_INTR_CLEAR_OFF; + sde_irq->en_off = base_offset + MDP_WB_INTR_EN_OFF; + sde_irq->status_off = base_offset + MDP_WB_INTR_STATUS_OFF; + break; + default: pr_err("unrecognized intr blk type %d\n", item->type); @@ -956,6 +974,9 @@ static inline u32 _get_irq_map_size(struct sde_intr_irq_offsets *item) case SDE_INTR_HWBLK_LTM: ret = ARRAY_SIZE(sde_irq_ltm_map); break; + case SDE_INTR_HWBLK_WB: + ret = ARRAY_SIZE(sde_irq_wb_map); + break; default: pr_err("invalid type: %d\n", item->type); } @@ -1006,6 +1027,9 @@ static inline struct sde_irq_type *_get_irq_map_addr( case SDE_INTR_HWBLK_LTM: ret = sde_irq_ltm_map; break; + case SDE_INTR_HWBLK_WB: + ret = sde_irq_wb_map; + break; default: pr_err("invalid type: %d\n", item->type); } diff --git a/msm/sde/sde_hw_interrupts.h b/msm/sde/sde_hw_interrupts.h index 8dc4faea14..812395031f 100644 --- a/msm/sde/sde_hw_interrupts.h +++ b/msm/sde/sde_hw_interrupts.h @@ -56,6 +56,7 @@ * @SDE_IRQ_TYPE_INTF_TEAR_TE_CHECK: INTF Tear TE detection * @SDE_IRQ_TYPE_LTM_STATS_DONE: LTM stats done interrupt * @SDE_IRQ_TYPE_LTM_STATS_WB_PB: LTM stats WB push back interrupt + * @SDE_IRQ_TYPE_PROG_LINE: Programmable Line interrupt for WB * @SDE_IRQ_TYPE_RESERVED: Reserved for expansion */ enum sde_intr_type { @@ -93,6 +94,7 @@ enum sde_intr_type { SDE_IRQ_TYPE_INTF_TEAR_TE_CHECK, SDE_IRQ_TYPE_LTM_STATS_DONE, SDE_IRQ_TYPE_LTM_STATS_WB_PB, + SDE_IRQ_TYPE_WB_PROG_LINE, SDE_IRQ_TYPE_RESERVED, }; diff --git a/msm/sde/sde_hw_wb.c b/msm/sde/sde_hw_wb.c index 815a431e1a..2d952acb14 100644 --- a/msm/sde/sde_hw_wb.c +++ b/msm/sde/sde_hw_wb.c @@ -35,6 +35,8 @@ #define WB_CROP_OFFSET 0x158 #define WB_CLK_CTRL 0x178 #define WB_CLK_STATUS 0x17C +#define WB_LINE_COUNT 0x184 +#define WB_PROG_LINE_COUNT 0x188 #define WB_CSC_BASE 0x260 #define WB_DST_ADDR_SW_STATUS 0x2B0 #define WB_CDP_CNTL 0x2B4 @@ -530,6 +532,24 @@ static int sde_hw_wb_get_clk_ctrl_status(struct sde_hw_blk_reg_map *hw, return 0; } +static u32 sde_hw_wb_get_line_count(struct sde_hw_wb *ctx) +{ + struct sde_hw_blk_reg_map *c; + + c = &ctx->hw; + + return SDE_REG_READ(c, WB_LINE_COUNT) & 0xFFFF; +} + +static void sde_hw_wb_set_prog_line_count(struct sde_hw_wb *ctx, u32 val) +{ + struct sde_hw_blk_reg_map *c; + + c = &ctx->hw; + + SDE_REG_WRITE(c, WB_PROG_LINE_COUNT, val); +} + static void _setup_wb_ops(struct sde_hw_wb_ops *ops, unsigned long features) { @@ -557,6 +577,11 @@ static void _setup_wb_ops(struct sde_hw_wb_ops *ops, if (test_bit(SDE_WB_CWB_DITHER_CTRL, &features)) ops->program_cwb_dither_ctrl = sde_hw_wb_program_cwb_dither_ctrl; + + if (test_bit(SDE_WB_PROG_LINE, &features)) { + ops->get_line_count = sde_hw_wb_get_line_count; + ops->set_prog_line_count = sde_hw_wb_set_prog_line_count; + } } struct sde_hw_blk_reg_map *sde_hw_wb_init(enum sde_wb idx, diff --git a/msm/sde/sde_hw_wb.h b/msm/sde/sde_hw_wb.h index 379e1601c3..389d786d02 100644 --- a/msm/sde/sde_hw_wb.h +++ b/msm/sde/sde_hw_wb.h @@ -162,6 +162,19 @@ struct sde_hw_wb_ops { */ void (*program_cwb_dither_ctrl)(struct sde_hw_wb *ctx, const enum sde_dcwb dcwb_idx, void *cfg, size_t len, bool enable); + + /** + * get_line_count - get current wb output linecount + * @ctx: Pointer to wb context + */ + u32 (*get_line_count)(struct sde_hw_wb *ctx); + + /** + * set_prog_line_count - set wb programmable line + * @ctx: Pointer to wb context + * @line_count: programmable line-count value + */ + void (*set_prog_line_count)(struct sde_hw_wb *ctx, u32 line_count); }; /**