Jelajahi Sumber

disp: msm: sde: add support for WD timer on INTF

Watchdog timer is moving from TOP to INTF. This change adds
support for movement and ensures backwards compatibility.

Vsync select only needs to specify whether or not to use
Timer 0 associated with the interface. It does not need to
select between Timer 0-4.

Signed-off-by: Samantha Tran <[email protected]>
Change-Id: I9d89a8cb1ea607e9fc0bdbffa0a6a9acceff7f13
Samantha Tran 4 tahun lalu
induk
melakukan
e778d2688e

+ 8 - 15
msm/sde/sde_encoder.c

@@ -1083,8 +1083,7 @@ static int _sde_encoder_update_roi(struct drm_encoder *drm_enc)
 	return 0;
 }
 
-void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc,
-			u32 vsync_source, bool is_dummy)
+void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc, u32 vsync_source)
 {
 	struct sde_vsync_source_cfg vsync_cfg = { 0 };
 	struct sde_kms *sde_kms;
@@ -1123,14 +1122,13 @@ void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc,
 		vsync_cfg.pp_count = sde_enc->num_phys_encs;
 		vsync_cfg.frame_rate = sde_enc->mode_info.frame_rate;
 		vsync_cfg.vsync_source = vsync_source;
-		vsync_cfg.is_dummy = is_dummy;
 
 		hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg);
 	}
 }
 
 static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc,
-			struct msm_display_info *disp_info, bool is_dummy)
+			struct msm_display_info *disp_info)
 {
 	struct sde_encoder_phys *phys;
 	int i;
@@ -1148,24 +1146,19 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc,
 	}
 
 	if (sde_encoder_check_curr_mode(&sde_enc->base, MSM_DISPLAY_CMD_MODE)) {
-		if (is_dummy)
-			vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0 -
-					sde_enc->te_source;
-		else if (disp_info->is_te_using_watchdog_timer)
-			vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_4 +
-					sde_enc->te_source;
+		if (disp_info->is_te_using_watchdog_timer)
+			vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_4 + sde_enc->te_source;
 		else
 			vsync_source = sde_enc->te_source;
 
-		SDE_EVT32(DRMID(&sde_enc->base), vsync_source, is_dummy,
+		SDE_EVT32(DRMID(&sde_enc->base), vsync_source,
 				disp_info->is_te_using_watchdog_timer);
 
 		for (i = 0; i < sde_enc->num_phys_encs; i++) {
 			phys = sde_enc->phys_encs[i];
 
 			if (phys && phys->ops.setup_vsync_source)
-				phys->ops.setup_vsync_source(phys,
-					vsync_source, is_dummy);
+				phys->ops.setup_vsync_source(phys, vsync_source);
 		}
 	}
 }
@@ -1189,7 +1182,7 @@ int sde_encoder_helper_switch_vsync(struct drm_encoder *drm_enc,
 
 	memcpy(&disp_info, &sde_enc->disp_info, sizeof(disp_info));
 	disp_info.is_te_using_watchdog_timer = watchdog_te;
-	_sde_encoder_update_vsync_source(sde_enc, &disp_info, false);
+	_sde_encoder_update_vsync_source(sde_enc, &disp_info);
 
 	sde_encoder_control_te(drm_enc, true);
 
@@ -2567,7 +2560,7 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
 				sde_enc->cur_master->hw_ctl,
 				&sde_enc->cur_master->intf_cfg_v1);
 
-	_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false);
+	_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info);
 	sde_encoder_control_te(drm_enc, true);
 
 	memset(&sde_enc->prv_conn_roi, 0, sizeof(sde_enc->prv_conn_roi));

+ 3 - 6
msm/sde/sde_encoder_phys.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __SDE_ENCODER_PHYS_H__
@@ -185,8 +185,7 @@ struct sde_encoder_phys_ops {
 	int (*get_wr_line_count)(struct sde_encoder_phys *phys);
 	bool (*wait_dma_trigger)(struct sde_encoder_phys *phys);
 	int (*wait_for_active)(struct sde_encoder_phys *phys);
-	void (*setup_vsync_source)(struct sde_encoder_phys *phys,
-			u32 vsync_source, bool is_dummy);
+	void (*setup_vsync_source)(struct sde_encoder_phys *phys, u32 vsync_source);
 	u32 (*get_underrun_line_count)(struct sde_encoder_phys *phys);
 };
 
@@ -567,10 +566,8 @@ void sde_encoder_helper_trigger_start(struct sde_encoder_phys *phys_enc);
  * sde_encoder_helper_vsync_config - configure vsync source for cmd mode
  * @phys_enc: Pointer to physical encoder structure
  * @vsync_source: vsync source selection
- * @is_dummy: used only for RSC
  */
-void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc,
-			u32 vsync_source, bool is_dummy);
+void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc, u32 vsync_source);
 
 /**
  * sde_encoder_helper_wait_event_timeout - wait for event with timeout

+ 15 - 3
msm/sde/sde_encoder_phys_cmd.c

@@ -1935,13 +1935,25 @@ static void sde_encoder_phys_cmd_trigger_start(
 }
 
 static void sde_encoder_phys_cmd_setup_vsync_source(
-		struct sde_encoder_phys *phys_enc,
-		u32 vsync_source, bool is_dummy)
+		struct sde_encoder_phys *phys_enc, u32 vsync_source)
 {
+	struct sde_encoder_virt *sde_enc;
+
 	if (!phys_enc || !phys_enc->hw_intf)
 		return;
 
-	sde_encoder_helper_vsync_config(phys_enc, vsync_source, is_dummy);
+	sde_enc = to_sde_encoder_virt(phys_enc->parent);
+	if (!sde_enc)
+		return;
+
+	if (sde_enc->disp_info.is_te_using_watchdog_timer &&
+			phys_enc->hw_intf->ops.setup_vsync_source) {
+		vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0;
+		phys_enc->hw_intf->ops.setup_vsync_source(phys_enc->hw_intf,
+				sde_enc->mode_info.frame_rate);
+	} else {
+		sde_encoder_helper_vsync_config(phys_enc, vsync_source);
+	}
 
 	if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel)
 		phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf,

+ 7 - 1
msm/sde/sde_hw_catalog.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
@@ -2245,6 +2245,10 @@ static int sde_intf_parse_dt(struct device_node *np,
 		if (SDE_HW_MAJOR(sde_cfg->hwversion) >=
 				SDE_HW_MAJOR(SDE_HW_VER_700))
 			set_bit(SDE_INTF_TE_ALIGN_VSYNC, &intf->features);
+
+		if (SDE_HW_MAJOR(sde_cfg->hwversion) >=
+				SDE_HW_MAJOR(SDE_HW_VER_810))
+			set_bit(SDE_INTF_WD_TIMER, &intf->features);
 	}
 
 end:
@@ -3804,6 +3808,8 @@ static int sde_top_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
 	major_version = SDE_HW_MAJOR(cfg->hwversion);
 	if (major_version < SDE_HW_MAJOR(SDE_HW_VER_500))
 		set_bit(SDE_MDP_VSYNC_SEL, &cfg->mdp[0].features);
+	else if (major_version < SDE_HW_MAJOR(SDE_HW_VER_810))
+		set_bit(SDE_MDP_WD_TIMER, &cfg->mdp[0].features);
 
 	rc = _add_to_irq_offset_list(cfg, SDE_INTR_HWBLK_TOP,
 			SDE_INTR_TOP_INTR, cfg->mdp[0].base);

+ 5 - 1
msm/sde/sde_hw_catalog.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SDE_HW_CATALOG_H
@@ -208,6 +208,7 @@ struct sde_intr_irq_offsets {
  *                         compression initial revision
  * @SDE_MDP_UBWC_1_5,      Universal Bandwidth compression version 1.5
  * @SDE_MDP_VSYNC_SEL      Vsync selection for command mode panels
+ * @SDE_MDP_WD_TIMER      WD timer support
  * @SDE_MDP_DHDR_MEMPOOL   Dynamic HDR Metadata mempool present
  * @SDE_MDP_DHDR_MEMPOOL_4K Dynamic HDR mempool is 4k aligned
  * @SDE_MDP_MAX            Maximum value
@@ -220,6 +221,7 @@ enum {
 	SDE_MDP_UBWC_1_0,
 	SDE_MDP_UBWC_1_5,
 	SDE_MDP_VSYNC_SEL,
+	SDE_MDP_WD_TIMER,
 	SDE_MDP_DHDR_MEMPOOL,
 	SDE_MDP_DHDR_MEMPOOL_4K,
 	SDE_MDP_MAX
@@ -473,6 +475,7 @@ enum {
  *                              pixel data arrives to this INTF
  * @SDE_INTF_TE                 INTF block has TE configuration support
  * @SDE_INTF_TE_ALIGN_VSYNC     INTF block has POMS Align vsync support
+ * @SDE_INTF_WD_TIMER          INTF block has WD Timer support
  * @SDE_INTF_STATUS             INTF block has INTF_STATUS register
  * @SDE_INTF_MAX
  */
@@ -480,6 +483,7 @@ enum {
 	SDE_INTF_INPUT_CTRL = 0x1,
 	SDE_INTF_TE,
 	SDE_INTF_TE_ALIGN_VSYNC,
+	SDE_INTF_WD_TIMER,
 	SDE_INTF_STATUS,
 	SDE_INTF_MAX
 };

+ 3 - 1
msm/sde/sde_hw_interrupts.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/bitops.h>
@@ -166,6 +166,7 @@
 #define SDE_INTR_DSICMD_2_INTO_STATIC BIT(6)
 #define SDE_INTR_DSICMD_2_OUTOF_STATIC BIT(7)
 #define SDE_INTR_PROG_LINE BIT(8)
+#define SDE_INTR_INTF_WD_TIMER_0_DONE BIT(13)
 
 /**
  * AD4 interrupt status bit definitions
@@ -398,6 +399,7 @@ static struct sde_irq_type sde_irq_intf_map[] = {
 		SDE_INTR_DSICMD_2_OUTOF_STATIC, -1},
 
 	{ SDE_IRQ_TYPE_PROG_LINE, -1, SDE_INTR_PROG_LINE, -1},
+	{ SDE_IRQ_TYPE_WD_TIMER, -1, SDE_INTR_WD_TIMER_0_DONE, -1},
 };
 
 static struct sde_irq_type sde_irq_ad4_map[] = {

+ 30 - 1
msm/sde/sde_hw_intf.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 #include <linux/iopoll.h>
 
@@ -61,6 +61,9 @@
 #define INTF_MISR_CTRL                  0x180
 #define INTF_MISR_SIGNATURE             0x184
 
+#define INTF_WD_TIMER_0_CTL             0x230
+#define INTF_WD_TIMER_0_CTL2            0x234
+#define INTF_WD_TIMER_0_LOAD_VALUE      0x238
 #define INTF_MUX                        0x25C
 #define INTF_UNDERRUN_COUNT             0x268
 #define INTF_STATUS                     0x26C
@@ -396,6 +399,29 @@ static void sde_hw_intf_setup_prg_fetch(
 	SDE_REG_WRITE(c, INTF_CONFIG, fetch_enable);
 }
 
+static void sde_hw_intf_setup_vsync_source(struct sde_hw_intf *intf,
+		u32 frame_rate)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 reg;
+
+	if (!intf)
+		return;
+
+	c = &intf->hw;
+
+	SDE_REG_WRITE(c, INTF_WD_TIMER_0_LOAD_VALUE, CALCULATE_WD_LOAD_VALUE(frame_rate));
+
+	SDE_REG_WRITE(c, INTF_WD_TIMER_0_CTL, BIT(0)); /* clear timer */
+	reg = SDE_REG_READ(c, INTF_WD_TIMER_0_CTL2);
+	reg |= BIT(8); /* enable heartbeat timer */
+	reg |= BIT(0); /* enable WD timer */
+	SDE_REG_WRITE(c, INTF_WD_TIMER_0_CTL2, reg);
+
+	/* make sure that timers are enabled/disabled for vsync state */
+	wmb();
+}
+
 static void sde_hw_intf_bind_pingpong_blk(
 		struct sde_hw_intf *intf,
 		bool enable,
@@ -805,6 +831,9 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
 	if (cap & BIT(SDE_INTF_INPUT_CTRL))
 		ops->bind_pingpong_blk = sde_hw_intf_bind_pingpong_blk;
 
+	if (cap & BIT(SDE_INTF_WD_TIMER))
+		ops->setup_vsync_source = sde_hw_intf_setup_vsync_source;
+
 	if (cap & BIT(SDE_INTF_TE)) {
 		ops->setup_tearcheck = sde_hw_intf_setup_te_config;
 		ops->enable_tearcheck = sde_hw_intf_enable_te;

+ 4 - 1
msm/sde/sde_hw_intf.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SDE_HW_INTF_H
@@ -78,6 +78,7 @@ struct intf_avr_params {
  * @ get_line_count: reads current vertical line counter
  * @ get_underrun_line_count: reads current underrun pixel clock count and
  *                            converts it into line count
+ * @setup_vsync_source: Configure vsync source selection for intf
  * @bind_pingpong_blk: enable/disable the connection with pingpong which will
  *                     feed pixels to this interface
  */
@@ -112,6 +113,8 @@ struct sde_hw_intf_ops {
 	u32 (*get_line_count)(struct sde_hw_intf *intf);
 	u32 (*get_underrun_line_count)(struct sde_hw_intf *intf);
 
+	void (*setup_vsync_source)(struct sde_hw_intf *intf, u32 frame_rate);
+
 	void (*bind_pingpong_blk)(struct sde_hw_intf *intf,
 			bool enable,
 			const enum sde_pingpong pp);

+ 8 - 1
msm/sde/sde_hw_mdss.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SDE_HW_MDSS_H
@@ -61,6 +61,13 @@ enum sde_format_flags {
 	(((X)->fetch_mode == SDE_FETCH_UBWC) && \
 			test_bit(SDE_FORMAT_FLAG_COMPRESSED_BIT, (X)->flag))
 
+#define MDP_TICK_COUNT                    16
+#define XO_CLK_RATE                       19200
+#define MS_TICKS_IN_SEC                   1000
+
+#define CALCULATE_WD_LOAD_VALUE(fps) \
+	((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps)))
+
 #define SDE_BLEND_FG_ALPHA_FG_CONST	(0 << 0)
 #define SDE_BLEND_FG_ALPHA_BG_CONST	(1 << 0)
 #define SDE_BLEND_FG_ALPHA_FG_PIXEL	(2 << 0)

+ 9 - 22
msm/sde/sde_hw_top.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #include "sde_hwio.h"
@@ -50,16 +50,9 @@
 #define MDP_WD_TIMER_4_CTL2               0x444
 #define MDP_WD_TIMER_4_LOAD_VALUE         0x448
 
-#define MDP_TICK_COUNT                    16
-#define XO_CLK_RATE                       19200
-#define MS_TICKS_IN_SEC                   1000
-
 #define AUTOREFRESH_TEST_POINT	0x2
 #define TEST_MASK(id, tp)	((id << 4) | (tp << 1) | BIT(0))
 
-#define CALCULATE_WD_LOAD_VALUE(fps) \
-	((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps)))
-
 #define DCE_SEL                           0x450
 
 #define MDP_SID_VIG0			  0x0
@@ -316,18 +309,13 @@ static void _update_vsync_source(struct sde_hw_mdp *mdp,
 			break;
 		}
 
-		if (cfg->is_dummy) {
-			SDE_REG_WRITE(c, wd_ctl2, 0x0);
-		} else {
-			SDE_REG_WRITE(c, wd_load_value,
-				CALCULATE_WD_LOAD_VALUE(cfg->frame_rate));
-
-			SDE_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */
-			reg = SDE_REG_READ(c, wd_ctl2);
-			reg |= BIT(8);		/* enable heartbeat timer */
-			reg |= BIT(0);		/* enable WD timer */
-			SDE_REG_WRITE(c, wd_ctl2, reg);
-		}
+		SDE_REG_WRITE(c, wd_load_value, CALCULATE_WD_LOAD_VALUE(cfg->frame_rate));
+
+		SDE_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */
+		reg = SDE_REG_READ(c, wd_ctl2);
+		reg |= BIT(8); /* enable heartbeat timer */
+		reg |= BIT(0); /* enable WD timer */
+		SDE_REG_WRITE(c, wd_ctl2, reg);
 
 		/* make sure that timers are enabled/disabled for vsync state */
 		wmb();
@@ -623,7 +611,6 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
 	ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl;
 	ops->get_clk_ctrl_status = sde_hw_get_clk_ctrl_status;
 	ops->get_danger_status = sde_hw_get_danger_status;
-	ops->setup_vsync_source = sde_hw_setup_vsync_source;
 	ops->set_cwb_ppb_cntl = sde_hw_program_cwb_ppb_ctrl;
 	ops->get_safe_status = sde_hw_get_safe_status;
 	ops->get_split_flush_status = sde_hw_get_split_flush;
@@ -633,7 +620,7 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
 	ops->set_mdp_hw_events = sde_hw_mdp_events;
 	if (cap & BIT(SDE_MDP_VSYNC_SEL))
 		ops->setup_vsync_source = sde_hw_setup_vsync_source;
-	else
+	else if (cap & BIT(SDE_MDP_WD_TIMER))
 		ops->setup_vsync_source = sde_hw_setup_vsync_source_v1;
 
 	if (cap & BIT(SDE_MDP_DHDR_MEMPOOL_4K) ||

+ 1 - 4
msm/sde/sde_hw_top.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SDE_HW_TOP_H
@@ -79,15 +79,12 @@ struct sde_danger_safe_status {
  * @frame_rate: Display frame rate
  * @ppnumber: ping pong index array
  * @vsync_source: vsync source selection
- * @is_dummy: a dummy source of vsync selection. It must not be selected for
- *           any case other than sde rsc idle request.
  */
 struct sde_vsync_source_cfg {
 	u32 pp_count;
 	u32 frame_rate;
 	u32 ppnumber[PINGPONG_MAX];
 	u32 vsync_source;
-	bool is_dummy;
 };
 
 /**