Procházet zdrojové kódy

Merge "disp: msm: sde: pass sde_enc to sde_encoder_control_te"

qctecmdr před 2 roky
rodič
revize
abdb501164

+ 2 - 12
msm/sde/sde_crtc.c

@@ -5040,18 +5040,8 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
 		break;
 	case SDE_POWER_EVENT_PRE_DISABLE:
 		drm_for_each_encoder_mask(encoder, crtc->dev,
-				crtc->state->encoder_mask) {
-			/*
-			 * disable the vsync source after updating the
-			 * rsc state. rsc state update might have vsync wait
-			 * and vsync source must be disabled after it.
-			 * It will avoid generating any vsync from this point
-			 * till mode-2 entry. It is SW workaround for HW
-			 * limitation and should not be removed without
-			 * checking the updated design.
-			 */
-			sde_encoder_control_te(encoder, false);
-		}
+				crtc->state->encoder_mask)
+			sde_encoder_idle_pc_enter(encoder);
 
 		spin_lock_irqsave(&sde_crtc->spin_lock, flags);
 		node = NULL;

+ 38 - 22
msm/sde/sde_encoder.c

@@ -1453,6 +1453,22 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc,
 	}
 }
 
+static void sde_encoder_control_te(struct sde_encoder_virt *sde_enc, bool enable)
+{
+	struct sde_encoder_phys *phys;
+	int i;
+
+	if (!sde_enc) {
+		SDE_ERROR("invalid sde encoder\n");
+		return;
+	}
+
+	for (i = 0; i < sde_enc->num_phys_encs; i++) {
+		phys = sde_enc->phys_encs[i];
+		if (phys && phys->ops.control_te)
+			phys->ops.control_te(phys, enable);
+	}
+}
 
 
 int sde_encoder_helper_switch_vsync(struct drm_encoder *drm_enc,
@@ -1468,13 +1484,13 @@ int sde_encoder_helper_switch_vsync(struct drm_encoder *drm_enc,
 
 	sde_enc = to_sde_encoder_virt(drm_enc);
 
-	sde_encoder_control_te(drm_enc, false);
+	sde_encoder_control_te(sde_enc, false);
 
 	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);
 
-	sde_encoder_control_te(drm_enc, true);
+	sde_encoder_control_te(sde_enc, true);
 
 	return 0;
 }
@@ -2183,9 +2199,9 @@ static int _sde_encoder_rc_post_modeset(struct drm_encoder *drm_enc,
 	/* toggle te bit to update vsync source for sim cmd mode panels */
 	if (sde_encoder_check_curr_mode(&sde_enc->base, MSM_DISPLAY_CMD_MODE)
 			&& sde_enc->disp_info.is_te_using_watchdog_timer) {
-		sde_encoder_control_te(drm_enc, false);
+		sde_encoder_control_te(sde_enc, false);
 		_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info);
-		sde_encoder_control_te(drm_enc, true);
+		sde_encoder_control_te(sde_enc, true);
 	}
 
 	_sde_encoder_update_rsc_client(drm_enc, true);
@@ -2728,28 +2744,28 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
 	sde_encoder_virt_modeset_rc(drm_enc, adj_mode, msm_mode, false);
 }
 
-void sde_encoder_control_te(struct drm_encoder *drm_enc, bool enable)
+void sde_encoder_idle_pc_enter(struct drm_encoder *drm_enc)
 {
-	struct sde_encoder_virt *sde_enc;
-	struct sde_encoder_phys *phys;
-	int i;
+	struct sde_encoder_virt *sde_enc = NULL;
 
 	if (!drm_enc) {
-		SDE_ERROR("invalid parameters\n");
+		SDE_ERROR("invalid encoder\n");
 		return;
 	}
-
 	sde_enc = to_sde_encoder_virt(drm_enc);
-	if (!sde_enc) {
-		SDE_ERROR("invalid sde encoder\n");
-		return;
-	}
+	/*
+	 * disable the vsync source after updating the
+	 * rsc state. rsc state update might have vsync wait
+	 * and vsync source must be disabled after it.
+	 * It will avoid generating any vsync from this point
+	 * till mode-2 entry. It is SW workaround for HW
+	 * limitation and should not be removed without
+	 * checking the updated design.
+	 */
+	sde_encoder_control_te(sde_enc, false);
 
-	for (i = 0; i < sde_enc->num_phys_encs; i++) {
-		phys = sde_enc->phys_encs[i];
-		if (phys && phys->ops.control_te)
-			phys->ops.control_te(phys, enable);
-	}
+	if (sde_enc->cur_master && sde_enc->cur_master->ops.idle_pc_cache_display_status)
+		sde_enc->cur_master->ops.idle_pc_cache_display_status(sde_enc->cur_master);
 }
 
 static int _sde_encoder_input_connect(struct input_handler *handler,
@@ -3022,7 +3038,7 @@ void sde_encoder_virt_restore(struct drm_encoder *drm_enc)
 		sde_enc->cur_master->ops.restore(sde_enc->cur_master);
 
 	_sde_encoder_virt_enable_helper(drm_enc);
-	sde_encoder_control_te(drm_enc, true);
+	sde_encoder_control_te(sde_enc, true);
 
 	/*
 	 * During IPC misr ctl register is reset.
@@ -3180,11 +3196,11 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
 			sizeof(sde_enc->cur_master->intf_cfg_v1));
 
 	/* turn off vsync_in to update tear check configuration */
-	sde_encoder_control_te(drm_enc, false);
+	sde_encoder_control_te(sde_enc, false);
 	sde_encoder_populate_encoder_phys(drm_enc, sde_enc, msm_mode);
 
 	_sde_encoder_virt_enable_helper(drm_enc);
-	sde_encoder_control_te(drm_enc, true);
+	sde_encoder_control_te(sde_enc, true);
 }
 
 void sde_encoder_virt_reset(struct drm_encoder *drm_enc)

+ 2 - 3
msm/sde/sde_encoder.h

@@ -396,11 +396,10 @@ bool sde_encoder_get_vblank_timestamp(struct drm_encoder *encoder,
 		ktime_t *tvblank);
 
 /**
- * sde_encoder_control_te - control enabling/disabling VSYNC_IN_EN
+ * sde_encoder_idle_pc_enter - control enable/disable VSYNC_IN_EN & cache display status at ipc
  * @encoder:	encoder pointer
- * @enable:	boolean to indicate enable/disable
  */
-void sde_encoder_control_te(struct drm_encoder *encoder, bool enable);
+void sde_encoder_idle_pc_enter(struct drm_encoder *encoder);
 
 /**
  * sde_encoder_virt_restore - restore the encoder configs

+ 4 - 0
msm/sde/sde_encoder_phys.h

@@ -140,6 +140,7 @@ struct sde_encoder_virt_ops {
  *                              count and underrun line count
  * @add_to_minidump:		Add this phys_enc data to minidumps
  * @disable_autorefresh:	Disable autorefresh
+ * @idle_pc_cache_display_status:	caches display status at idle power collapse
  */
 
 struct sde_encoder_phys_ops {
@@ -194,6 +195,7 @@ struct sde_encoder_phys_ops {
 	u32 (*get_underrun_line_count)(struct sde_encoder_phys *phys);
 	void (*add_to_minidump)(struct sde_encoder_phys *phys);
 	void (*disable_autorefresh)(struct sde_encoder_phys *phys);
+	void (*idle_pc_cache_display_status)(struct sde_encoder_phys *phys);
 };
 
 /**
@@ -275,6 +277,7 @@ struct sde_encoder_irq {
  * @hw_dnsc_blur:	Hardware interface to the downscale blur registers
  * @sde_kms:		Pointer to the sde_kms top level
  * @cached_mode:	DRM mode cached at mode_set time, acted on in enable
+ * @wd_jitter : Pointer to watchdog jitter prams
  * @enabled:		Whether the encoder has enabled and running a mode
  * @split_role:		Role to play in a split-panel configuration
  * @intf_mode:		Interface mode
@@ -333,6 +336,7 @@ struct sde_encoder_phys {
 	struct sde_hw_dnsc_blur *hw_dnsc_blur;
 	struct sde_kms *sde_kms;
 	struct drm_display_mode cached_mode;
+	struct intf_wd_jitter_params wd_jitter;
 	enum sde_enc_split_role split_role;
 	enum sde_intf_mode intf_mode;
 	enum sde_intf intf_idx;

+ 21 - 9
msm/sde/sde_encoder_phys_cmd.c

@@ -2037,30 +2037,42 @@ 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)
+static void _sde_encoder_phys_cmd_calculate_wd_params(struct sde_encoder_phys *phys_enc)
 {
 	u32 nominal_te_value;
 	struct sde_encoder_virt *sde_enc;
 	struct msm_mode_info *mode_info;
 	const u32 multiplier = 1 << 10;
+	struct intf_wd_jitter_params wd_jtr;
 
 	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,
+	if (mode_info->wd_jitter.jitter_type & MSM_DISPLAY_WD_INSTANTANEOUS_JITTER) {
+		wd_jtr.jitter = mult_frac(multiplier,
+				mode_info->wd_jitter.inst_jitter_numer,
 				(mode_info->wd_jitter.inst_jitter_denom * 100));
+		phys_enc->wd_jitter.jitter = wd_jtr.jitter;
+	}
 
 	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,
+		wd_jtr.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,
+		wd_jtr.ltj_slope = mult_frac((1 << 16), wd_jtr.ltj_max,
 				(mode_info->wd_jitter.ltj_time_sec * mode_info->frame_rate));
+		phys_enc->wd_jitter.ltj_max = wd_jtr.ltj_max;
+		phys_enc->wd_jitter.ltj_slope = wd_jtr.ltj_slope;
 	}
 
-	phys_enc->hw_intf->ops.configure_wd_jitter(phys_enc->hw_intf, wd_jitter);
+	phys_enc->hw_intf->ops.configure_wd_jitter(phys_enc->hw_intf, &phys_enc->wd_jitter);
+}
+
+static void sde_encoder_phys_cmd_store_ltj_values(struct sde_encoder_phys *phys_enc)
+{
+	if (phys_enc && phys_enc->hw_intf->ops.get_wd_ltj_status)
+		phys_enc->hw_intf->ops.get_wd_ltj_status(phys_enc->hw_intf, &phys_enc->wd_jitter);
 }
 
 static void sde_encoder_phys_cmd_setup_vsync_source(struct sde_encoder_phys *phys_enc,
@@ -2068,7 +2080,6 @@ static void sde_encoder_phys_cmd_setup_vsync_source(struct sde_encoder_phys *phy
 {
 	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;
@@ -2083,7 +2094,7 @@ static void sde_encoder_phys_cmd_setup_vsync_source(struct sde_encoder_phys *phy
 			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);
+			_sde_encoder_phys_cmd_calculate_wd_params(phys_enc);
 		phys_enc->hw_intf->ops.setup_vsync_source(phys_enc->hw_intf,
 				sde_enc->mode_info.frame_rate);
 	} else {
@@ -2136,6 +2147,7 @@ static void sde_encoder_phys_cmd_init_ops(struct sde_encoder_phys_ops *ops)
 	ops->collect_misr = sde_encoder_helper_collect_misr;
 	ops->add_to_minidump = sde_encoder_phys_cmd_add_enc_to_minidump;
 	ops->disable_autorefresh = _sde_encoder_phys_disable_autorefresh;
+	ops->idle_pc_cache_display_status = sde_encoder_phys_cmd_store_ltj_values;
 }
 
 static inline bool sde_encoder_phys_cmd_intf_te_supported(

+ 1 - 0
msm/sde/sde_hw_catalog.c

@@ -2493,6 +2493,7 @@ static int sde_intf_parse_dt(struct device_node *np,
 			set_bit(SDE_INTF_MDP_VSYNC_FC, &intf->features);
 			set_bit(SDE_INTF_TE_32BIT, &intf->features);
 			set_bit(SDE_INTF_TE_SINGLE_UPDATE, &intf->features);
+			set_bit(SDE_INTF_WD_LTJ_CTL, &intf->features);
 		}
 	}
 

+ 2 - 0
msm/sde/sde_hw_catalog.h

@@ -606,6 +606,7 @@ enum {
  * @SDE_INTF_MDP_VSYNC_FC       INTF block has mdp vsync frame counter
  * @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_WD_LTJ_CTL         INTF block has WD long term jitter control support
  * @SDE_INTF_MAX
  */
 enum {
@@ -622,6 +623,7 @@ enum {
 	SDE_INTF_MDP_VSYNC_FC,
 	SDE_INTF_AVR_STATUS,
 	SDE_INTF_WD_JITTER,
+	SDE_INTF_WD_LTJ_CTL,
 	SDE_INTF_MAX
 };
 

+ 41 - 0
msm/sde/sde_hw_intf.c

@@ -65,6 +65,8 @@
 #define INTF_MISR_CTRL                  0x180
 #define INTF_MISR_SIGNATURE             0x184
 
+#define INTF_WD_TIMER_0_LTJ_CTL         0x200
+#define INTF_WD_TIMER_0_LTJ_CTL1        0x204
 #define INTF_VSYNC_TIMESTAMP_CTRL       0x210
 #define INTF_VSYNC_TIMESTAMP0           0x214
 #define INTF_VSYNC_TIMESTAMP1           0x218
@@ -76,6 +78,8 @@
 #define INTF_WD_TIMER_0_CTL             0x230
 #define INTF_WD_TIMER_0_CTL2            0x234
 #define INTF_WD_TIMER_0_LOAD_VALUE      0x238
+#define INTF_WD_TIMER_0_LTJ_INT_STATUS  0x240
+#define INTF_WD_TIMER_0_LTJ_FRAC_STATUS 0x244
 #define INTF_MUX                        0x25C
 #define INTF_UNDERRUN_COUNT             0x268
 #define INTF_STATUS                     0x26C
@@ -496,6 +500,40 @@ static void sde_hw_intf_configure_wd_timer_jitter(struct sde_hw_intf *intf,
 	if (wd_jitter->ltj_max)
 		reg |= BIT(30);
 	SDE_REG_WRITE(c, INTF_WD_TIMER_0_JITTER_CTL, reg);
+
+	if (intf->cap->features & BIT(SDE_INTF_WD_LTJ_CTL)) {
+		if (wd_jitter->ltj_step_dir && wd_jitter->ltj_initial_val) {
+			reg = ((wd_jitter->ltj_step_dir & 0x1) << 31) |
+					(wd_jitter->ltj_initial_val  & 0x1FFFFF);
+			SDE_REG_WRITE(c, INTF_WD_TIMER_0_LTJ_CTL, reg);
+			wd_jitter->ltj_step_dir = 0;
+			wd_jitter->ltj_initial_val = 0;
+		}
+
+		if (wd_jitter->ltj_fractional_val) {
+			SDE_REG_WRITE(c, INTF_WD_TIMER_0_LTJ_CTL1, wd_jitter->ltj_fractional_val);
+			wd_jitter->ltj_fractional_val = 0;
+		}
+	}
+
+}
+
+static void sde_hw_intf_read_wd_ltj_ctl(struct sde_hw_intf *intf,
+		struct intf_wd_jitter_params *wd_jitter)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 reg;
+
+	c = &intf->hw;
+
+	if (intf->cap->features & BIT(SDE_INTF_WD_LTJ_CTL)) {
+		reg = SDE_REG_READ(c, INTF_WD_TIMER_0_LTJ_INT_STATUS);
+		wd_jitter->ltj_step_dir =  reg & BIT(31);
+		wd_jitter->ltj_initial_val = (reg & 0x1FFFFF);
+
+		reg = SDE_REG_READ(c, INTF_WD_TIMER_0_LTJ_FRAC_STATUS);
+		wd_jitter->ltj_fractional_val = (reg & 0xFFFF);
+	}
 }
 
 static void sde_hw_intf_setup_vsync_source(struct sde_hw_intf *intf, u32 frame_rate)
@@ -1039,6 +1077,9 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
 
 	if (cap & BIT(SDE_INTF_WD_JITTER))
 		ops->configure_wd_jitter = sde_hw_intf_configure_wd_timer_jitter;
+
+	if (cap & BIT(SDE_INTF_WD_LTJ_CTL))
+		ops->get_wd_ltj_status = sde_hw_intf_read_wd_ltj_ctl;
 }
 
 struct sde_hw_blk_reg_map *sde_hw_intf_init(enum sde_intf idx,

+ 12 - 1
msm/sde/sde_hw_intf.h

@@ -73,13 +73,18 @@ struct intf_avr_params {
  * jitter : max instantaneous jitter.
  * ltj_max : max long term jitter value.
  * ltj_slope : slope of long term jitter.
+ *ltj_step_dir: direction of the step in LTJ
+ *ltj_initial_val: LTJ initial value
+ *ltj_fractional_val:  LTJ fractional initial value
  */
 struct intf_wd_jitter_params {
 	u32 jitter;
 	u32 ltj_max;
 	u32 ltj_slope;
+	u8 ltj_step_dir;
+	u32 ltj_initial_val;
+	u32 ltj_fractional_val;
 };
-
 /**
  * struct sde_hw_intf_ops : Interface to the interface Hw driver functions
  *  Assumption is these functions will be called after clocks are enabled
@@ -95,6 +100,8 @@ struct intf_wd_jitter_params {
  *                            converts it into line count
  * @setup_vsync_source: Configure vsync source selection for intf
  * @configure_wd_jitter: Configure WD jitter.
+ * @ write_wd_ltj: Write WD long term jitter.
+ * @get_wd_ltj_status: Read WD long term jitter status.
  * @bind_pingpong_blk: enable/disable the connection with pingpong which will
  *                     feed pixels to this interface
  */
@@ -132,6 +139,10 @@ struct sde_hw_intf_ops {
 	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 (*write_wd_ltj)(struct sde_hw_intf *intf,
+			struct intf_wd_jitter_params *wd_jitter);
+	void (*get_wd_ltj_status)(struct sde_hw_intf *intf,
+			struct intf_wd_jitter_params *wd_jitter);
 
 	void (*bind_pingpong_blk)(struct sde_hw_intf *intf,
 			bool enable,