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 <veeras@codeaurora.org>
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
||||
|
@@ -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";
|
||||
|
@@ -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))
|
||||
|
@@ -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
|
||||
};
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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,
|
||||
};
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user