diff options
author | Ken Lin <lyenting@google.com> | 2023-09-05 09:05:28 +0000 |
---|---|---|
committer | Ken Lin <lyenting@google.com> | 2023-09-12 05:49:04 +0000 |
commit | cc6241281f12b6109618586b410272df7c4bf560 (patch) | |
tree | f1b609f6e87d608132f7cf431d32f7028a46121b | |
parent | 203b4bbb818e41f9ed51d0e9f198034fa14b3192 (diff) | |
download | display-cc6241281f12b6109618586b410272df7c4bf560.tar.gz |
panel: add the progress type of mode switch & keep higher BTS while booting for RRSandroid-u-qpr1-beta-2_r0.7android-u-qpr1-beta-2_r0.5android-u-qpr1-beta-2_r0.4android-u-qpr1-beta-2_r0.3android-u-qpr1-beta-2_r0.2android-u-qpr1-beta-2_r0.1
Add the variable to indicate the mode switch is in progress with
refresh rate or/and resolution change in the same atomic commit.
Keep higher BTS in case we switch resolution and refresh rate
from high to low at the same time to avoid noises.
Bug: 283929569
Test: Boot on successfully
Test: Verified by PTE
Change-Id: I97685717527b70353eec2a65dc1317d4c70cf67d
Signed-off-by: Ken Lin <lyenting@google.com>
-rw-r--r-- | samsung/panel/panel-samsung-drv.c | 67 | ||||
-rw-r--r-- | samsung/panel/panel-samsung-drv.h | 18 |
2 files changed, 85 insertions, 0 deletions
diff --git a/samsung/panel/panel-samsung-drv.c b/samsung/panel/panel-samsung-drv.c index 71c802c..080c7dc 100644 --- a/samsung/panel/panel-samsung-drv.c +++ b/samsung/panel/panel-samsung-drv.c @@ -3305,12 +3305,73 @@ static int exynos_panel_bridge_atomic_check(struct drm_bridge *bridge, { struct exynos_panel *ctx = bridge_to_exynos_panel(bridge); struct drm_atomic_state *state = new_crtc_state->state; + const struct drm_display_mode *current_mode = &ctx->current_mode->mode; const struct exynos_panel_funcs *funcs = ctx->desc->exynos_panel_func; int ret; if (unlikely(!new_crtc_state)) return 0; + if (unlikely(!current_mode)) { + dev_warn(ctx->dev, "%s: failed to get current mode, skip mode check\n", __func__); + } else { + struct drm_display_mode *target_mode = &new_crtc_state->adjusted_mode; + int current_vrefresh = drm_mode_vrefresh(current_mode); + int target_vrefresh = drm_mode_vrefresh(target_mode); + + if (current_mode->hdisplay != target_mode->hdisplay && + current_mode->vdisplay != target_mode->vdisplay) { + if (current_vrefresh != target_vrefresh) { + /* + * While switching resolution and refresh rate (from high to low) in + * the same commit, the frame transfer time will become longer due + * to BTS update. In the case, frame done time may cross to the next + * vsync, which will hit DDIC’s constraint and cause the noises. + * Keep the current BTS (higher one) for a few frames to avoid the + * problem. + */ + if (current_vrefresh > target_vrefresh) { + target_mode->clock = + target_mode->htotal * target_mode->vtotal * + current_vrefresh / 1000; + if (target_mode->clock != new_crtc_state->mode.clock) { + new_crtc_state->mode_changed = true; + dev_dbg(ctx->dev, + "%s: keep mode (%s) clock %dhz on rrs\n", + __func__, target_mode->name, + current_vrefresh); + } + } + + ctx->mode_in_progress = MODE_RES_AND_RR_IN_PROGRESS; + } else { + ctx->mode_in_progress = MODE_RES_IN_PROGRESS; + } + } else { + if (ctx->mode_in_progress == MODE_RES_AND_RR_IN_PROGRESS && + new_crtc_state->adjusted_mode.clock != new_crtc_state->mode.clock) { + new_crtc_state->mode_changed = true; + new_crtc_state->adjusted_mode.clock = new_crtc_state->mode.clock; + dev_dbg(ctx->dev, "%s: restore mode (%s) clock after rrs\n", + __func__, new_crtc_state->mode.name); + } + + if (current_vrefresh != target_vrefresh) + ctx->mode_in_progress = MODE_RR_IN_PROGRESS; + else + ctx->mode_in_progress = MODE_DONE; + } + + if (current_mode->hdisplay != target_mode->hdisplay || + current_mode->vdisplay != target_mode->vdisplay || + current_vrefresh != target_vrefresh) + dev_dbg(ctx->dev, + "%s: current %dx%d@%d, target %dx%d@%d, type %d\n", __func__, + current_mode->hdisplay, current_mode->vdisplay, current_vrefresh, + target_mode->hdisplay, target_mode->vdisplay, target_vrefresh, + ctx->mode_in_progress); + } + if (funcs && funcs->atomic_check) { ret = funcs->atomic_check(ctx, state); if (ret) @@ -3441,14 +3502,17 @@ void exynos_panel_wait_for_vsync_done(struct exynos_panel *ctx, u32 te_us, u32 p { u32 delay_us; + DPU_ATRACE_BEGIN(__func__); if (unlikely(exynos_panel_wait_for_vblank(ctx))) { delay_us = period_us + 1000; usleep_range(delay_us, delay_us + 10); + DPU_ATRACE_END(__func__); return; } delay_us = exynos_panel_vsync_start_time_us(te_us, period_us); usleep_range(delay_us, delay_us + 10); + DPU_ATRACE_END(__func__); } EXPORT_SYMBOL(exynos_panel_wait_for_vsync_done); @@ -4200,6 +4264,9 @@ int exynos_panel_common_init(struct mipi_dsi_device *dsi, if (ret) dev_err(ctx->dev, "unable to create cabc_mode\n"); } + + ctx->mode_in_progress = MODE_DONE; + exynos_panel_handoff(ctx); ret = mipi_dsi_attach(dsi); diff --git a/samsung/panel/panel-samsung-drv.h b/samsung/panel/panel-samsung-drv.h index b5b29ae..1d2896b 100644 --- a/samsung/panel/panel-samsung-drv.h +++ b/samsung/panel/panel-samsung-drv.h @@ -529,6 +529,21 @@ enum local_hbm_enable_state { LOCAL_HBM_ENABLING, }; +/** + * enum mode_progress_type - the type while mode switch is in progress + * @MODE_DONE: mode switch is done + * @MODE_RES_IN_PROGRESS: mode switch is in progress, only resolution is changed + * @MODE_RR_IN_PROGRESS: mode switch is in progress, only refresh rate is changed + * @MODE_RES_AND_RR_IN_PROGRESS: mode switch is in progress, both resolution and + * refresh rate are changed + */ +enum mode_progress_type { + MODE_DONE = 0, + MODE_RES_IN_PROGRESS, + MODE_RR_IN_PROGRESS, + MODE_RES_AND_RR_IN_PROGRESS, +}; + struct exynos_bl_notifier { u32 ranges[MAX_BL_RANGES]; u32 num_ranges; @@ -673,6 +688,9 @@ struct exynos_panel { struct workqueue_struct *wq; } hbm; + + /* current type of mode switch */ + enum mode_progress_type mode_in_progress; }; /** |