From e8e526b692f84312f44dd8f019da24e332b1c8f1 Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran Date: Fri, 9 Jul 2021 14:08:10 -0700 Subject: [PATCH] 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 --- msm/sde/sde_hw_catalog.c | 78 ++++++++++++++++++++-------------------- msm/sde/sde_hw_catalog.h | 5 +++ msm/sde/sde_hw_sspp.c | 22 +++++++++++- msm/sde/sde_hw_sspp.h | 10 ++++++ msm/sde/sde_plane.c | 32 +++++++++++++++-- 5 files changed, 105 insertions(+), 42 deletions(-) diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index da9dd52460..1690621f30 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/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; + 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; + 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; diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 91cf4da165..1e80a16171 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/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 }; diff --git a/msm/sde/sde_hw_sspp.c b/msm/sde/sde_hw_sspp.c index 2276de5c20..282763385d 100644 --- a/msm/sde/sde_hw_sspp.c +++ b/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); diff --git a/msm/sde/sde_hw_sspp.h b/msm/sde/sde_hw_sspp.h index e69d7dd104..65557e6bdf 100644 --- a/msm/sde/sde_hw_sspp.h +++ b/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 diff --git a/msm/sde/sde_plane.c b/msm/sde/sde_plane.c index f63b6a0745..6e0f0d4c01 100644 --- a/msm/sde/sde_plane.c +++ b/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,