ソースを参照

disp: msm: sde: add uidle fill level scaling

Kalama adds support for uidle fill level scaling to allow
fal10 mode for 90 and above fps use cases.

Pre-Kalama, the fill levels are clamped at 4-bit values supported
by the threshold registers. But to achieve the targeted 50us idle
time on fal10 modes with higher FPS use cases, we need fill levels
higher than 15 (max for 4 bit). The hardware change in Kalama
achieves by using a 5 bit scale factor in combination with the
programmed threshold values.

Change-Id: I638705355c03910a83e7d922b6fe48ab11c120a8
Signed-off-by: Jeykumar Sankaran <[email protected]>
Jeykumar Sankaran 4 年 前
コミット
e8e526b692
5 ファイル変更106 行追加43 行削除
  1. 41 39
      msm/sde/sde_hw_catalog.c
  2. 5 0
      msm/sde/sde_hw_catalog.h
  3. 21 1
      msm/sde/sde_hw_sspp.c
  4. 10 0
      msm/sde/sde_hw_sspp.h
  5. 29 3
      msm/sde/sde_plane.c

+ 41 - 39
msm/sde/sde_hw_catalog.c

@@ -155,7 +155,8 @@
 #define SDE_UIDLE_FAL10_TARGET_IDLE 50
 #define SDE_UIDLE_FAL1_TARGET_IDLE 40
 #define SDE_UIDLE_FAL1_MAX_THRESHOLD 15
-#define SDE_UIDLE_REV102_FAL1_MAX_THRESHOLD 255
+#define SDE_UIDLE_FAL1_MAX_THRESHOLD_EXT_REV_102 255
+#define SDE_UIDLE_FAL1_MAX_THRESHOLD_EXT_REV_103 255
 #define SDE_UIDLE_FAL10_THRESHOLD_60 12
 #define SDE_UIDLE_FAL10_THRESHOLD_90 13
 #define SDE_UIDLE_MAX_DWNSCALE 1500
@@ -1838,8 +1839,11 @@ static void sde_sspp_set_features(struct sde_mdss_cfg *sde_cfg,
 					&sspp->perf_features);
 		}
 
-		if (sde_cfg->uidle_cfg.uidle_rev)
+		if (sde_cfg->uidle_cfg.uidle_rev) {
 			set_bit(SDE_PERF_SSPP_UIDLE, &sspp->perf_features);
+			if (sde_cfg->uidle_cfg.uidle_rev >= SDE_UIDLE_VERSION_1_0_3)
+				set_bit(SDE_PERF_SSPP_UIDLE_FILL_LVL_SCALE, &sspp->perf_features);
+		}
 
 		if (sde_cfg->sc_cfg[SDE_SYS_CACHE_DISP].has_sys_cache)
 			set_bit(SDE_PERF_SSPP_SYS_CACHE, &sspp->perf_features);
@@ -4756,42 +4760,40 @@ static void _sde_hw_setup_uidle(struct sde_uidle_cfg *uidle_cfg)
 	if (!uidle_cfg->uidle_rev)
 		return;
 
-	if ((IS_SDE_UIDLE_REV_102(uidle_cfg->uidle_rev)) ||
-			(IS_SDE_UIDLE_REV_101(uidle_cfg->uidle_rev)) ||
-			(IS_SDE_UIDLE_REV_100(uidle_cfg->uidle_rev))) {
-		uidle_cfg->fal10_exit_cnt = SDE_UIDLE_FAL10_EXIT_CNT;
-		uidle_cfg->fal10_exit_danger = SDE_UIDLE_FAL10_EXIT_DANGER;
-		uidle_cfg->fal10_danger = SDE_UIDLE_FAL10_DANGER;
-		uidle_cfg->fal10_target_idle_time = SDE_UIDLE_FAL10_TARGET_IDLE;
-		uidle_cfg->fal1_target_idle_time = SDE_UIDLE_FAL1_TARGET_IDLE;
-		uidle_cfg->max_dwnscale = SDE_UIDLE_MAX_DWNSCALE;
-		uidle_cfg->debugfs_ctrl = true;
-		uidle_cfg->fal1_max_threshold = SDE_UIDLE_FAL1_MAX_THRESHOLD;
-
-		if (IS_SDE_UIDLE_REV_100(uidle_cfg->uidle_rev)) {
-			uidle_cfg->fal10_threshold =
-				SDE_UIDLE_FAL10_THRESHOLD_60;
-			uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS_60;
-		} else if (IS_SDE_UIDLE_REV_101(uidle_cfg->uidle_rev)) {
-			set_bit(SDE_UIDLE_QACTIVE_OVERRIDE,
-					&uidle_cfg->features);
-			uidle_cfg->fal10_threshold =
-				SDE_UIDLE_FAL10_THRESHOLD_90;
-			uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS_90;
-		} else if (IS_SDE_UIDLE_REV_102(uidle_cfg->uidle_rev)) {
-			set_bit(SDE_UIDLE_QACTIVE_OVERRIDE,
-					&uidle_cfg->features);
-			uidle_cfg->fal10_threshold =
-				SDE_UIDLE_FAL10_THRESHOLD_90;
-			uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS_90;
-			uidle_cfg->max_fal1_fps = SDE_UIDLE_MAX_FPS_240;
-			uidle_cfg->fal1_max_threshold =
-					SDE_UIDLE_REV102_FAL1_MAX_THRESHOLD;
-		}
-	} else {
-		pr_err("invalid uidle rev:0x%x, disabling uidle\n",
-			uidle_cfg->uidle_rev);
-		uidle_cfg->uidle_rev = 0;
+	uidle_cfg->fal10_exit_cnt = SDE_UIDLE_FAL10_EXIT_CNT;
+	uidle_cfg->fal10_exit_danger = SDE_UIDLE_FAL10_EXIT_DANGER;
+	uidle_cfg->fal10_danger = SDE_UIDLE_FAL10_DANGER;
+	uidle_cfg->fal10_target_idle_time = SDE_UIDLE_FAL10_TARGET_IDLE;
+	uidle_cfg->fal1_target_idle_time = SDE_UIDLE_FAL1_TARGET_IDLE;
+	uidle_cfg->max_dwnscale = SDE_UIDLE_MAX_DWNSCALE;
+	uidle_cfg->debugfs_ctrl = true;
+	uidle_cfg->fal1_max_threshold = SDE_UIDLE_FAL1_MAX_THRESHOLD;
+
+	if (IS_SDE_UIDLE_REV_100(uidle_cfg->uidle_rev)) {
+		uidle_cfg->fal10_threshold =
+			SDE_UIDLE_FAL10_THRESHOLD_60;
+		uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS_60;
+	} else if (IS_SDE_UIDLE_REV_101(uidle_cfg->uidle_rev)) {
+		set_bit(SDE_UIDLE_QACTIVE_OVERRIDE,
+				&uidle_cfg->features);
+		uidle_cfg->fal10_threshold =
+			SDE_UIDLE_FAL10_THRESHOLD_90;
+		uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS_90;
+	} else if (IS_SDE_UIDLE_REV_102(uidle_cfg->uidle_rev)) {
+		set_bit(SDE_UIDLE_QACTIVE_OVERRIDE,
+				&uidle_cfg->features);
+		uidle_cfg->fal10_threshold =
+			SDE_UIDLE_FAL10_THRESHOLD_90;
+		uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS_90;
+		uidle_cfg->max_fal1_fps = SDE_UIDLE_MAX_FPS_240;
+		uidle_cfg->fal1_max_threshold =
+				SDE_UIDLE_FAL1_MAX_THRESHOLD_EXT_REV_102;
+	} else if (IS_SDE_UIDLE_REV_103(uidle_cfg->uidle_rev)) {
+		set_bit(SDE_UIDLE_QACTIVE_OVERRIDE, &uidle_cfg->features);
+		uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS_240;
+		uidle_cfg->max_fal1_fps = SDE_UIDLE_MAX_FPS_240;
+		uidle_cfg->fal1_max_threshold = SDE_UIDLE_FAL1_MAX_THRESHOLD_EXT_REV_103;
+		uidle_cfg->fal10_threshold = SDE_UIDLE_FAL10_THRESHOLD_60;
 	}
 }
 
@@ -5146,7 +5148,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
 		sde_cfg->ts_prefill_rev = 2;
 		sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0;
 		sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_1;
-		sde_cfg->uidle_cfg.uidle_rev = SDE_UIDLE_VERSION_1_0_2;
+		sde_cfg->uidle_cfg.uidle_rev = SDE_UIDLE_VERSION_1_0_3;
 		sde_cfg->mdss_hw_block_size = 0x158;
 		sde_cfg->demura_supported[SSPP_DMA1][0] = 0;
 		sde_cfg->demura_supported[SSPP_DMA1][1] = 1;

+ 5 - 0
msm/sde/sde_hw_catalog.h

@@ -148,6 +148,7 @@
 #define SDE_UIDLE_VERSION_1_0_0		0x100
 #define SDE_UIDLE_VERSION_1_0_1		0x101
 #define SDE_UIDLE_VERSION_1_0_2		0x102
+#define SDE_UIDLE_VERSION_1_0_3		0x103
 
 #define IS_SDE_UIDLE_REV_100(rev) \
 	((rev) == SDE_UIDLE_VERSION_1_0_0)
@@ -155,6 +156,8 @@
 	((rev) == SDE_UIDLE_VERSION_1_0_1)
 #define IS_SDE_UIDLE_REV_102(rev) \
 	((rev) == SDE_UIDLE_VERSION_1_0_2)
+#define IS_SDE_UIDLE_REV_103(rev) \
+	((rev) == SDE_UIDLE_VERSION_1_0_3)
 
 #define SDE_UIDLE_MAJOR(rev)		((rev) >> 8)
 
@@ -345,6 +348,7 @@ enum {
  * @SDE_PERF_SSPP_CDP             Supports client driven prefetch
  * @SDE_PERF_SSPP_SYS_CACHE,      SSPP supports system cache
  * @SDE_PERF_SSPP_UIDLE,          sspp supports uidle
+ * @SDE_PERF_SSPP_UIDLE_FILL_LVL_SCALE,          sspp supports uidle fill level scaling
  * @SDE_PERF_SSPP_MAX             Maximum value
  */
 enum {
@@ -355,6 +359,7 @@ enum {
 	SDE_PERF_SSPP_CDP,
 	SDE_PERF_SSPP_SYS_CACHE,
 	SDE_PERF_SSPP_UIDLE,
+	SDE_PERF_SSPP_UIDLE_FILL_LVL_SCALE,
 	SDE_PERF_SSPP_MAX
 };
 

+ 21 - 1
msm/sde/sde_hw_sspp.c

@@ -46,6 +46,7 @@
 
 #define SSPP_UIDLE_CTRL_VALUE              0x1f0
 #define SSPP_UIDLE_CTRL_VALUE_REC1         0x1f4
+#define SSPP_FILL_LEVEL_SCALE              0x1f8
 
 /* SSPP_DGM */
 #define SSPP_DGM_0                         0x9F0
@@ -1167,6 +1168,22 @@ static void sde_hw_sspp_setup_sys_cache(struct sde_hw_pipe *ctx,
 	SDE_REG_WRITE(&ctx->hw, SSPP_SYS_CACHE_MODE + idx, val);
 }
 
+static void sde_hw_sspp_setup_uidle_fill_scale(struct sde_hw_pipe *ctx,
+		struct sde_hw_pipe_uidle_cfg *cfg)
+{
+	u32 idx, fill_lvl;
+
+	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+		return;
+
+	/* duplicate the v1 scale values for V2 and fal10 exit */
+	fill_lvl = cfg->fill_level_scale & 0xF;
+	fill_lvl |= (cfg->fill_level_scale & 0xF) << 8;
+	fill_lvl |= (cfg->fill_level_scale & 0xF) << 16;
+
+	SDE_REG_WRITE(&ctx->hw, SSPP_FILL_LEVEL_SCALE + idx, fill_lvl);
+}
+
 static void sde_hw_sspp_setup_uidle(struct sde_hw_pipe *ctx,
 		struct sde_hw_pipe_uidle_cfg *cfg,
 		enum sde_sspp_multirect_index index)
@@ -1501,8 +1518,11 @@ static void _setup_layer_ops(struct sde_hw_pipe *c,
 	if (test_bit(SDE_PERF_SSPP_CDP, &perf_features))
 		c->ops.setup_cdp = sde_hw_sspp_setup_cdp;
 
-	if (test_bit(SDE_PERF_SSPP_UIDLE, &perf_features))
+	if (test_bit(SDE_PERF_SSPP_UIDLE, &perf_features)) {
 		c->ops.setup_uidle = sde_hw_sspp_setup_uidle;
+		if (test_bit(SDE_PERF_SSPP_UIDLE_FILL_LVL_SCALE, &perf_features))
+			c->ops.setup_uidle_fill_scale = sde_hw_sspp_setup_uidle_fill_scale;
+	}
 
 	_setup_layer_ops_colorproc(c, features, is_virtual_pipe);
 

+ 10 - 0
msm/sde/sde_hw_sspp.h

@@ -265,6 +265,7 @@ struct sde_hw_pipe_sc_cfg {
  * @fal10_exit_threshold: number of lines to indicate fal_10_exit is okay
  * @fal10_threshold: number of lines where fal_10_is okay
  * @fal1_threshold: number of lines where fal_1 is okay
+ * @fill_level_scale: scale factor on the fal10 threshold
  */
 struct sde_hw_pipe_uidle_cfg {
 	u32 enable;
@@ -272,6 +273,7 @@ struct sde_hw_pipe_uidle_cfg {
 	u32 fal10_exit_threshold;
 	u32 fal10_threshold;
 	u32 fal1_threshold;
+	u32 fill_level_scale;
 };
 
 /**
@@ -534,6 +536,14 @@ struct sde_hw_sspp_ops {
 			 struct sde_hw_pipe_uidle_cfg *cfg,
 			 enum sde_sspp_multirect_index index);
 
+	/**
+	 * setup_uidle_fill_scale - set uidle fill scale factor
+	 * @ctx: Pointer to pipe context
+	 * @cfg: Pointer to uidle configuration
+	 */
+	void (*setup_uidle_fill_scale)(struct sde_hw_pipe *ctx,
+			 struct sde_hw_pipe_uidle_cfg *cfg);
+
 	/**
 	 * setup_ts_prefill - setup prefill traffic shaper
 	 * @ctx: Pointer to pipe context

+ 29 - 3
msm/sde/sde_plane.c

@@ -2942,6 +2942,28 @@ static void _sde_plane_setup_uidle(struct drm_crtc *crtc,
 			psde->catalog->uidle_cfg.fal1_max_threshold);
 		cfg.fal_allowed_threshold = fal10_threshold +
 			(fal10_target_idle_time_ns*1000/line_time*2)/1000;
+		cfg.fill_level_scale = 0;
+
+		/*
+		 * if uidle fill scale is supported, determing the scale value
+		 * and adjust fal10 thresholds to their scaled values.
+		 * fal1 thresholds and fal_allowed are not scaled.
+		 */
+		if (psde->pipe_hw->ops.setup_uidle_fill_scale) {
+			u32 fl_require0 = psde->catalog->qos_target_time_ns / line_time * 2;
+			u32 fl_require = max(fal10_threshold * 1000, fl_require0);
+			u32 fl_scale = fl_require / fal10_threshold;
+			u32 fal10_threshold_noscale;
+
+			cfg.fill_level_scale = (fl_scale <= 1) ? 0 : (32 / fl_scale);
+
+			if (cfg.fill_level_scale) {
+				fal10_threshold_noscale = fal10_threshold *
+					32/cfg.fill_level_scale;
+				cfg.fal_allowed_threshold = fal10_threshold_noscale +
+					(fal10_target_idle_time_ns * 1000 / line_time * 2) / 1000;
+			}
+		}
 	} else {
 		SDE_ERROR("invalid settings, will disable UIDLE %d %d %d %d\n",
 			line_time, fal10_threshold, fal10_target_idle_time_ns,
@@ -2950,9 +2972,10 @@ static void _sde_plane_setup_uidle(struct drm_crtc *crtc,
 	}
 
 	SDE_DEBUG_PLANE(psde,
-		"tholds: fal10=%d fal10_exit=%d fal1=%d fal_allowed=%d\n",
+		"tholds: fal10=%d fal10_exit=%d fal1=%d fal_allowed=%d fill_scale=%d\n",
 			cfg.fal10_threshold, cfg.fal10_exit_threshold,
-			cfg.fal1_threshold, cfg.fal_allowed_threshold);
+			cfg.fal1_threshold, cfg.fal_allowed_threshold,
+			cfg.fill_level_scale);
 	SDE_DEBUG_PLANE(psde,
 		"times: line:%d fal1_idle:%d fal10_idle:%d dwnscale:%d\n",
 			line_time, fal1_target_idle_time_ns,
@@ -2961,7 +2984,10 @@ static void _sde_plane_setup_uidle(struct drm_crtc *crtc,
 	SDE_EVT32_VERBOSE(cfg.enable,
 		cfg.fal10_threshold, cfg.fal10_exit_threshold,
 		cfg.fal1_threshold, cfg.fal_allowed_threshold,
-		psde->catalog->uidle_cfg.max_dwnscale);
+		cfg.fill_level_scale, psde->catalog->uidle_cfg.max_dwnscale);
+
+	if (psde->pipe_hw->ops.setup_uidle_fill_scale)
+		psde->pipe_hw->ops.setup_uidle_fill_scale(psde->pipe_hw, &cfg);
 
 	psde->pipe_hw->ops.setup_uidle(
 		psde->pipe_hw, &cfg,