summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Lin <lyenting@google.com>2023-09-05 09:05:28 +0000
committerKen Lin <lyenting@google.com>2023-09-12 05:49:04 +0000
commitcc6241281f12b6109618586b410272df7c4bf560 (patch)
treef1b609f6e87d608132f7cf431d32f7028a46121b
parent203b4bbb818e41f9ed51d0e9f198034fa14b3192 (diff)
downloaddisplay-cc6241281f12b6109618586b410272df7c4bf560.tar.gz
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.c67
-rw-r--r--samsung/panel/panel-samsung-drv.h18
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;
};
/**