浏览代码

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 <[email protected]>
Veera Sundaram Sankaran 4 年之前
父节点
当前提交
95300ca3df

+ 2 - 0
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,
 };
 

+ 20 - 0
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";

+ 9 - 0
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))

+ 3 - 0
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
 };
 

+ 24 - 0
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);
 	}

+ 2 - 0
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,
 };
 

+ 25 - 0
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,

+ 13 - 0
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);
 };
 
 /**