فهرست منبع

disp: msm: add support for INTF WD jitter

Change adds support for the INTF watchdog timer jitter feature
for MDSS 9.x.

Change-Id: I2cf821b5b5724f9adee95c282e0ec09719489a85
Signed-off-by: Satya Rama Aditya Pinapala <[email protected]>
Signed-off-by: Narendra Muppalla <[email protected]>
Satya Rama Aditya Pinapala 3 سال پیش
والد
کامیت
718cd25496
9فایلهای تغییر یافته به همراه188 افزوده شده و 8 حذف شده
  1. 3 0
      msm/dsi/dsi_defs.h
  2. 1 0
      msm/dsi/dsi_drm.c
  3. 60 4
      msm/dsi/dsi_panel.c
  4. 32 0
      msm/msm_drv.h
  5. 29 0
      msm/sde/sde_encoder_phys_cmd.c
  6. 1 0
      msm/sde/sde_hw_catalog.c
  7. 2 0
      msm/sde/sde_hw_catalog.h
  8. 45 4
      msm/sde/sde_hw_intf.c
  9. 15 0
      msm/sde/sde_hw_intf.h

+ 3 - 0
msm/dsi/dsi_defs.h

@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  */
 
@@ -620,6 +621,7 @@ struct dsi_host_config {
  * @topology:             Topology selected for the panel
  * @dsc:                  DSC compression info
  * @vdc:                  VDC compression info
+ * @wd_jitter:            WD Jitter config.
  * @dsc_enabled:          DSC compression enabled
  * @vdc_enabled:          VDC compression enabled
  * @pclk_scale:           pclk scale factor, target bpp to source bpp
@@ -647,6 +649,7 @@ struct dsi_display_mode_priv_info {
 	struct msm_display_topology topology;
 	struct msm_display_dsc_info dsc;
 	struct msm_display_vdc_info vdc;
+	struct msm_display_wd_jitter_config wd_jitter;
 	bool dsc_enabled;
 	bool vdc_enabled;
 	struct msm_ratio pclk_scale;

+ 1 - 0
msm/dsi/dsi_drm.c

@@ -638,6 +638,7 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
 		dsi_mode->priv_info->mdp_transfer_time_us;
 	mode_info->disable_rsc_solver = dsi_mode->priv_info->disable_rsc_solver;
 	mode_info->qsync_min_fps = dsi_mode->timing.qsync_min_fps;
+	mode_info->wd_jitter = dsi_mode->priv_info->wd_jitter;
 
 	memcpy(&mode_info->topology, &dsi_mode->priv_info->topology,
 			sizeof(struct msm_display_topology));

+ 60 - 4
msm/dsi/dsi_panel.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  */
 
@@ -2203,16 +2203,71 @@ static int dsi_panel_parse_misc_features(struct dsi_panel *panel)
 	return 0;
 }
 
+static int dsi_panel_parse_wd_jitter_config(struct dsi_display_mode_priv_info *priv_info,
+		struct dsi_parser_utils *utils, u32 *jitter)
+{
+	int rc = 0;
+	struct msm_display_wd_jitter_config *wd_jitter = &priv_info->wd_jitter;
+	u32 ltj[DEFAULT_PANEL_JITTER_ARRAY_SIZE] = {0, 1};
+	u32 ltj_time = 0;
+	const u32 min_ltj = 10;
+
+	if (!(utils->read_bool(utils->data, "qcom,dsi-wd-jitter-enable"))) {
+		priv_info->panel_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR;
+		priv_info->panel_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR;
+		return 0;
+	}
+
+	rc = utils->read_u32_array(utils->data, "qcom,dsi-wd-ltj-max-jitter", ltj,
+			DEFAULT_PANEL_JITTER_ARRAY_SIZE);
+	rc |= utils->read_u32(utils->data, "qcom,dsi-wd-ltj-time-sec", &ltj_time);
+	if (rc || !ltj[1] || !ltj_time || (ltj[0] / ltj[1] < min_ltj)) {
+		DSI_DEBUG("No valid long term jitter defined\n");
+		priv_info->panel_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR;
+		priv_info->panel_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR;
+		rc = -EINVAL;
+	} else {
+		wd_jitter->ltj_max_numer = ltj[0];
+		wd_jitter->ltj_max_denom = ltj[1];
+		wd_jitter->ltj_time_sec = ltj_time;
+		wd_jitter->jitter_type = MSM_DISPLAY_WD_LTJ_JITTER;
+	}
+
+	if (jitter[0] && jitter[1]) {
+		if (jitter[0] / jitter[1] > MAX_PANEL_JITTER) {
+			wd_jitter->inst_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR;
+			wd_jitter->inst_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR;
+		} else {
+			wd_jitter->inst_jitter_numer = jitter[0];
+			wd_jitter->inst_jitter_denom = jitter[1];
+		}
+		wd_jitter->jitter_type |= MSM_DISPLAY_WD_INSTANTANEOUS_JITTER;
+	} else if (rc) {
+		wd_jitter->inst_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR;
+		wd_jitter->inst_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR;
+		wd_jitter->jitter_type |= MSM_DISPLAY_WD_INSTANTANEOUS_JITTER;
+	}
+
+	priv_info->panel_jitter_numer = rc ?
+			wd_jitter->inst_jitter_numer : wd_jitter->ltj_max_numer;
+	priv_info->panel_jitter_denom = rc ?
+			wd_jitter->inst_jitter_denom : wd_jitter->ltj_max_denom;
+
+	return 0;
+}
+
 static int dsi_panel_parse_jitter_config(
 				struct dsi_display_mode *mode,
 				struct dsi_parser_utils *utils)
 {
 	int rc;
 	struct dsi_display_mode_priv_info *priv_info;
+	struct dsi_panel *panel;
 	u32 jitter[DEFAULT_PANEL_JITTER_ARRAY_SIZE] = {0, 0};
 	u64 jitter_val = 0;
 
 	priv_info = mode->priv_info;
+	panel = container_of(utils, struct dsi_panel, utils);
 
 	rc = utils->read_u32_array(utils->data, "qcom,mdss-dsi-panel-jitter",
 				jitter, DEFAULT_PANEL_JITTER_ARRAY_SIZE);
@@ -2223,10 +2278,11 @@ static int dsi_panel_parse_jitter_config(
 		jitter_val = div_u64(jitter_val, jitter[1]);
 	}
 
-	if (rc || !jitter_val || (jitter_val > MAX_PANEL_JITTER)) {
+	if (panel->te_using_watchdog_timer) {
+		dsi_panel_parse_wd_jitter_config(priv_info, utils, jitter);
+	} else if (rc || !jitter_val || (jitter_val > MAX_PANEL_JITTER)) {
 		priv_info->panel_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR;
-		priv_info->panel_jitter_denom =
-					DEFAULT_PANEL_JITTER_DENOMINATOR;
+		priv_info->panel_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR;
 	} else {
 		priv_info->panel_jitter_numer = jitter[0];
 		priv_info->panel_jitter_denom = jitter[1];

+ 32 - 0
msm/msm_drv.h

@@ -257,6 +257,18 @@ enum msm_display_compression_type {
 	MSM_DISPLAY_COMPRESSION_VDC
 };
 
+/**
+ * enum msm_display_wd_jitter_type - Type of WD jitter used
+ * @MSM_DISPLAY_WD_JITTER_NONE:      No WD timer jitter enabled
+ * @MSM_DISPLAY_WD_INSTANTANEOUS_JITTER:  Instantaneous WD jitter enabled
+ * @MSM_DISPLAY_WD_LTJ_JITTER:       LTJ WD jitter enabled
+ */
+enum msm_display_wd_jitter_type {
+	MSM_DISPLAY_WD_JITTER_NONE = BIT(0),
+	MSM_DISPLAY_WD_INSTANTANEOUS_JITTER = BIT(1),
+	MSM_DISPLAY_WD_LTJ_JITTER = BIT(2),
+};
+
 #define MSM_DISPLAY_COMPRESSION_RATIO_NONE 1
 #define MSM_DISPLAY_COMPRESSION_RATIO_MAX 5
 
@@ -744,6 +756,24 @@ struct msm_dyn_clk_list {
 	u32 *pixel_clks_khz;
 };
 
+/**
+ * struct msm_display_wd_jitter_config - defines jitter properties for WD timer
+ * @jitter_type:        Type of WD jitter enabled.
+ * @inst_jitter_numer:  Instantaneous jitter numerator.
+ * @inst_jitter_denom:  Instantaneous jitter denominator.
+ * @ltj_max_numer:      LTJ max numerator.
+ * @ltj_max_denom:      LTJ max denominator.
+ * @ltj_time_sec:       LTJ time in seconds.
+ */
+struct msm_display_wd_jitter_config {
+	enum msm_display_wd_jitter_type jitter_type;
+	u32 inst_jitter_numer;
+	u32 inst_jitter_denom;
+	u32 ltj_max_numer;
+	u32 ltj_max_denom;
+	u32 ltj_time_sec;
+};
+
 /**
  * struct msm_mode_info - defines all msm custom mode info
  * @frame_rate:      frame_rate of the mode
@@ -764,6 +794,7 @@ struct msm_dyn_clk_list {
  * @disable_rsc_solver: Dynamically disable RSC solver for the timing mode due to lower bitclk rate.
  * @dyn_clk_list: List of dynamic clock rates for RFI.
  * @qsync_min_fps: qsync min fps rate
+ * @wd_jitter:         Info for WD jitter.
  */
 struct msm_mode_info {
 	uint32_t frame_rate;
@@ -783,6 +814,7 @@ struct msm_mode_info {
 	bool disable_rsc_solver;
 	struct msm_dyn_clk_list dyn_clk_list;
 	u32 qsync_min_fps;
+	struct msm_display_wd_jitter_config wd_jitter;
 };
 
 /**

+ 29 - 0
msm/sde/sde_encoder_phys_cmd.c

@@ -1894,11 +1894,38 @@ static void sde_encoder_phys_cmd_trigger_start(
 	cmd_enc->wr_ptr_wait_success = false;
 }
 
+static void _sde_encoder_phys_cmd_calculate_wd_params(struct sde_encoder_phys *phys_enc,
+		struct intf_wd_jitter_params *wd_jitter)
+{
+	u32 nominal_te_value;
+	struct sde_encoder_virt *sde_enc;
+	struct msm_mode_info *mode_info;
+	const u32 multiplier = 1 << 10;
+
+	sde_enc = to_sde_encoder_virt(phys_enc->parent);
+	mode_info = &sde_enc->mode_info;
+
+	if (mode_info->wd_jitter.jitter_type & MSM_DISPLAY_WD_INSTANTANEOUS_JITTER)
+		wd_jitter->jitter = mult_frac(multiplier, mode_info->wd_jitter.inst_jitter_numer,
+				(mode_info->wd_jitter.inst_jitter_denom * 100));
+
+	if (mode_info->wd_jitter.jitter_type & MSM_DISPLAY_WD_LTJ_JITTER) {
+		nominal_te_value = CALCULATE_WD_LOAD_VALUE(mode_info->frame_rate) * MDP_TICK_COUNT;
+		wd_jitter->ltj_max = mult_frac(nominal_te_value, mode_info->wd_jitter.ltj_max_numer,
+				(mode_info->wd_jitter.ltj_max_denom) * 100);
+		wd_jitter->ltj_slope = mult_frac((1 << 16), wd_jitter->ltj_max,
+				(mode_info->wd_jitter.ltj_time_sec * mode_info->frame_rate));
+	}
+
+	phys_enc->hw_intf->ops.configure_wd_jitter(phys_enc->hw_intf, wd_jitter);
+}
+
 static void sde_encoder_phys_cmd_setup_vsync_source(struct sde_encoder_phys *phys_enc,
 		u32 vsync_source, struct msm_display_info *disp_info)
 {
 	struct sde_encoder_virt *sde_enc;
 	struct sde_connector *sde_conn;
+	struct intf_wd_jitter_params wd_jitter = {0, 0};
 
 	if (!phys_enc || !phys_enc->hw_intf)
 		return;
@@ -1912,6 +1939,8 @@ static void sde_encoder_phys_cmd_setup_vsync_source(struct sde_encoder_phys *phy
 	if ((disp_info->is_te_using_watchdog_timer || sde_conn->panel_dead) &&
 			phys_enc->hw_intf->ops.setup_vsync_source) {
 		vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0;
+		if (phys_enc->hw_intf->ops.configure_wd_jitter)
+			_sde_encoder_phys_cmd_calculate_wd_params(phys_enc, &wd_jitter);
 		phys_enc->hw_intf->ops.setup_vsync_source(phys_enc->hw_intf,
 				sde_enc->mode_info.frame_rate);
 	} else {

+ 1 - 0
msm/sde/sde_hw_catalog.c

@@ -2366,6 +2366,7 @@ static int sde_intf_parse_dt(struct device_node *np,
 
 		if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_900)) {
 			set_bit(SDE_INTF_MDP_VSYNC_TS, &intf->features);
+			set_bit(SDE_INTF_WD_JITTER, &intf->features);
 		}
 	}
 

+ 2 - 0
msm/sde/sde_hw_catalog.h

@@ -567,6 +567,7 @@ enum {
  * @SDE_INTF_PANEL_VSYNC_TS     INTF block has panel vsync timestamp logged
  * @SDE_INTF_MDP_VSYNC_TS       INTF block has mdp vsync timestamp logged
  * @SDE_INTF_AVR_STATUS         INTF block has AVR_STATUS field in AVR_CONTROL register
+ * @SDE_INTF_WD_JITTER          INTF block has WD timer jitter support
  * @SDE_INTF_MAX
  */
 enum {
@@ -579,6 +580,7 @@ enum {
 	SDE_INTF_PANEL_VSYNC_TS,
 	SDE_INTF_MDP_VSYNC_TS,
 	SDE_INTF_AVR_STATUS,
+	SDE_INTF_WD_JITTER,
 	SDE_INTF_MAX
 };
 

+ 45 - 4
msm/sde/sde_hw_intf.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
@@ -69,6 +69,9 @@
 #define INTF_VSYNC_TIMESTAMP1           0x218
 #define INTF_MDP_VSYNC_TIMESTAMP0       0x21C
 #define INTF_MDP_VSYNC_TIMESTAMP1       0x220
+#define INTF_WD_TIMER_0_JITTER_CTL      0x224
+#define INTF_WD_TIMER_0_LTJ_SLOPE       0x228
+#define INTF_WD_TIMER_0_LTJ_MAX         0x22C
 #define INTF_WD_TIMER_0_CTL             0x230
 #define INTF_WD_TIMER_0_CTL2            0x234
 #define INTF_WD_TIMER_0_LOAD_VALUE      0x238
@@ -455,8 +458,39 @@ 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)
+static void sde_hw_intf_configure_wd_timer_jitter(struct sde_hw_intf *intf,
+		struct intf_wd_jitter_params *wd_jitter)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 reg, jitter_ctl = 0;
+
+	c = &intf->hw;
+
+	/*
+	 * Load Jitter values with jitter feature disabled.
+	 */
+	SDE_REG_WRITE(c, INTF_WD_TIMER_0_JITTER_CTL, 0x1);
+
+	if (wd_jitter->jitter)
+		jitter_ctl |= ((wd_jitter->jitter & 0x3FF) << 16);
+
+	if (wd_jitter->ltj_max) {
+		SDE_REG_WRITE(c, INTF_WD_TIMER_0_LTJ_MAX, wd_jitter->ltj_max);
+		SDE_REG_WRITE(c, INTF_WD_TIMER_0_LTJ_SLOPE, wd_jitter->ltj_slope);
+	}
+
+	reg = SDE_REG_READ(c, INTF_WD_TIMER_0_JITTER_CTL);
+	reg |= jitter_ctl;
+	SDE_REG_WRITE(c, INTF_WD_TIMER_0_JITTER_CTL, reg);
+
+	if (wd_jitter->jitter)
+		reg |= BIT(31);
+	if (wd_jitter->ltj_max)
+		reg |= BIT(30);
+	SDE_REG_WRITE(c, INTF_WD_TIMER_0_JITTER_CTL, reg);
+}
+
+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;
@@ -466,7 +500,11 @@ static void sde_hw_intf_setup_vsync_source(struct sde_hw_intf *intf,
 
 	c = &intf->hw;
 
-	SDE_REG_WRITE(c, INTF_WD_TIMER_0_LOAD_VALUE, CALCULATE_WD_LOAD_VALUE(frame_rate));
+	reg = CALCULATE_WD_LOAD_VALUE(frame_rate);
+	if (intf->cap->features & BIT(SDE_INTF_WD_JITTER))
+		reg *= MDP_TICK_COUNT;
+
+	SDE_REG_WRITE(c, INTF_WD_TIMER_0_LOAD_VALUE, reg);
 
 	SDE_REG_WRITE(c, INTF_WD_TIMER_0_CTL, BIT(0)); /* clear timer */
 	reg = SDE_REG_READ(c, INTF_WD_TIMER_0_CTL2);
@@ -928,6 +966,9 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
 
 	if (cap & (BIT(SDE_INTF_PANEL_VSYNC_TS) | BIT(SDE_INTF_MDP_VSYNC_TS)))
 		ops->get_vsync_timestamp = sde_hw_intf_get_vsync_timestamp;
+
+	if (cap & BIT(SDE_INTF_WD_JITTER))
+		ops->configure_wd_jitter = sde_hw_intf_configure_wd_timer_jitter;
 }
 
 struct sde_hw_blk_reg_map *sde_hw_intf_init(enum sde_intf idx,

+ 15 - 0
msm/sde/sde_hw_intf.h

@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
@@ -65,6 +66,17 @@ struct intf_avr_params {
 	u32 avr_mode; /* one of enum @sde_rm_qsync_modes */
 	u32 avr_step_lines; /* 0 or 1 means disabled */
 };
+/**
+ * struct intf_wd_jitter_params : Interface to the INTF WD Jitter params.
+ * jitter : max instantaneous jitter.
+ * ltj_max : max long term jitter value.
+ * ltj_slope : slope of long term jitter.
+ */
+struct intf_wd_jitter_params {
+	u32 jitter;
+	u32 ltj_max;
+	u32 ltj_slope;
+};
 
 /**
  * struct sde_hw_intf_ops : Interface to the interface Hw driver functions
@@ -80,6 +92,7 @@ struct intf_avr_params {
  * @ 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
+ * @configure_wd_jitter: Configure WD jitter.
  * @bind_pingpong_blk: enable/disable the connection with pingpong which will
  *                     feed pixels to this interface
  */
@@ -115,6 +128,8 @@ struct sde_hw_intf_ops {
 	u32 (*get_underrun_line_count)(struct sde_hw_intf *intf);
 
 	void (*setup_vsync_source)(struct sde_hw_intf *intf, u32 frame_rate);
+	void (*configure_wd_jitter)(struct sde_hw_intf *intf,
+			struct intf_wd_jitter_params *wd_jitter);
 
 	void (*bind_pingpong_blk)(struct sde_hw_intf *intf,
 			bool enable,