summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPixelBot AutoMerger <android-nexus-securitybot@system.gserviceaccount.com>2022-12-19 01:16:03 -0800
committerSecurityBot <android-nexus-securitybot@system.gserviceaccount.com>2022-12-19 01:16:04 -0800
commitdc04241ce93fe1de3fa764f2a8b7f02af9385cbe (patch)
tree50e55e6b9e9f960b016f033d3525bdff82cd2d98
parent880bb6f9e7a2082fac1c01389dde915f282bcca8 (diff)
parent190bd94c1f25067b73ead73b017b22c3e4161dad (diff)
downloaddisplay-android-gs-raviole-5.10-u-preview-1.tar.gz
SBMerger: 478053055 Change-Id: I9f306796e67a55227d55ca5b9c227734221d425a Signed-off-by: SecurityBot <android-nexus-securitybot@system.gserviceaccount.com>
-rw-r--r--include/trace/panel_trace.h76
-rw-r--r--samsung/cal_9845/dsim_reg.c9
-rw-r--r--samsung/exynos_drm_decon.c7
-rw-r--r--samsung/exynos_drm_dsim.c28
-rw-r--r--samsung/panel/panel-samsung-drv.c73
-rw-r--r--samsung/panel/panel-samsung-drv.h3
6 files changed, 184 insertions, 12 deletions
diff --git a/include/trace/panel_trace.h b/include/trace/panel_trace.h
new file mode 100644
index 0000000..adeb44d
--- /dev/null
+++ b/include/trace/panel_trace.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Panel command trace support
+ *
+ * Copyright (C) 2022 Google, Inc.
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM panel
+
+#if !defined(_PANEL_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _PANEL_TRACE_H_
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT_CONDITION(dsi_tx,
+ TP_PROTO(u8 type, const u8 *tx_buf, size_t length, bool last),
+ TP_ARGS(type, tx_buf, length, last),
+ TP_CONDITION(length > 0),
+ TP_STRUCT__entry(
+ __field( u8, type )
+ __dynamic_array(u8, tx_buf, length )
+ __field( bool, last )
+ ),
+ TP_fast_assign(
+ __entry->type = type;
+ memcpy(__get_dynamic_array(tx_buf), tx_buf, length);
+ __entry->last = last;
+ ),
+ TP_printk("type=0x%02x length=%u last=%d tx=[%s]", __entry->type,
+ __get_dynamic_array_len(tx_buf), __entry->last,
+ __print_hex(__get_dynamic_array(tx_buf),
+ __get_dynamic_array_len(tx_buf)))
+);
+
+TRACE_EVENT_CONDITION(dsi_rx,
+ TP_PROTO(u8 cmd, const u8 *rx_buf, size_t length),
+ TP_ARGS(cmd, rx_buf, length),
+ TP_CONDITION(length > 0),
+ TP_STRUCT__entry(
+ __field( u8, cmd )
+ __dynamic_array(u8, rx_buf, length )
+ ),
+ TP_fast_assign(
+ __entry->cmd = cmd;
+ memcpy(__get_dynamic_array(rx_buf), rx_buf, length);
+ ),
+ TP_printk("cmd=0x%02x length=%u rx=[%s]", __entry->cmd,
+ __get_dynamic_array_len(rx_buf),
+ __print_hex(__get_dynamic_array(rx_buf),
+ __get_dynamic_array_len(rx_buf)))
+);
+
+TRACE_EVENT(dsi_cmd_fifo_status,
+ TP_PROTO(u8 header, u16 payload),
+ TP_ARGS(header, payload),
+ TP_STRUCT__entry(
+ __field(u8, header )
+ __field(u16, payload)
+ ),
+ TP_fast_assign(
+ __entry->header = header;
+ __entry->payload = payload;
+ ),
+ TP_printk("header=%d payload=%d", __entry->header, __entry->payload)
+);
+
+#endif /* _PANEL_TRACE_H_ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH trace/.
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE panel_trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/samsung/cal_9845/dsim_reg.c b/samsung/cal_9845/dsim_reg.c
index 8645e0b..d67b6cc 100644
--- a/samsung/cal_9845/dsim_reg.c
+++ b/samsung/cal_9845/dsim_reg.c
@@ -90,10 +90,6 @@ static struct cal_regs_desc regs_desc[REGS_DSIM_TYPE_MAX][MAX_DSI_CNT];
#define PLL_LOCK_CNT_MARGIN (PLL_LOCK_CNT_MUL * \
PLL_LOCK_CNT_MARGIN_RATIO / 100)
-#if !defined(CONFIG_BOARD_EMULATOR)
-static DEFINE_MUTEX(dphy_lock);
-#endif
-
static const u32 DSIM_PHY_BIAS_CON_VAL[] = {
0x00000010,
0x00000110,
@@ -2088,13 +2084,14 @@ void dsim_reg_init(u32 id, struct dsim_reg_config *config,
dsim_reg_enable_word_clock(id, 1);
#if !defined(CONFIG_BOARD_EMULATOR)
- mutex_lock(&dphy_lock);
/* Enable DPHY reset : DPHY reset start */
dpu_sysreg_dphy_reset(id, 0);
+#endif
+
+#if !defined(CONFIG_BOARD_EMULATOR)
dsim_reg_set_clocks(id, config, clks, 1);
dsim_reg_set_lanes_dphy(id, lanes, true);
dpu_sysreg_dphy_reset(id, 1); /* Release DPHY reset */
- mutex_unlock(&dphy_lock);
#endif
dsim_reg_set_link_clock(id, 1); /* Selection to word clock */
diff --git a/samsung/exynos_drm_decon.c b/samsung/exynos_drm_decon.c
index 348de03..f2782fa 100644
--- a/samsung/exynos_drm_decon.c
+++ b/samsung/exynos_drm_decon.c
@@ -103,14 +103,17 @@ void decon_dump(const struct decon_device *decon)
continue;
if (d->state != DECON_STATE_ON) {
- drm_printf(&p, "%s[%u]: DECON disabled(%d)\n",
- decon->dev->driver->name, decon->id, decon->state);
+ drm_printf(&p, "%s[%u]: DECON state is not On(%d)\n",
+ d->dev->driver->name, d->id, d->state);
continue;
}
__decon_dump(&p, d->id, &d->regs, d->config.dsc.enabled, d->dqe != NULL);
}
+ if (decon->state != DECON_STATE_ON)
+ return;
+
for (i = 0; i < decon->dpp_cnt; ++i)
dpp_dump(&p, decon->dpp[i]);
diff --git a/samsung/exynos_drm_dsim.c b/samsung/exynos_drm_dsim.c
index 91b9f03..9ff30f3 100644
--- a/samsung/exynos_drm_dsim.c
+++ b/samsung/exynos_drm_dsim.c
@@ -56,6 +56,8 @@
#include <regs-dsim.h>
#include <trace/dpu_trace.h>
+#define CREATE_TRACE_POINTS
+#include <trace/panel_trace.h>
#include "exynos_drm_connector.h"
#include "exynos_drm_crtc.h"
@@ -64,6 +66,12 @@
struct dsim_device *dsim_drvdata[MAX_DSI_CNT];
+/*
+ * This global mutex lock protects to initialize or de-initialize DSIM and DPHY
+ * hardware when multi display is in operation
+ */
+DEFINE_MUTEX(g_dsim_lock);
+
#define PANEL_DRV_LEN 64
#define RETRY_READ_FIFO_MAX 10
@@ -238,8 +246,10 @@ static void _dsim_exit_ulps_locked(struct dsim_device *dsim)
dsim_phy_power_on(dsim);
+ mutex_lock(&g_dsim_lock);
dsim_reg_init(dsim->id, &dsim->config, &dsim->clk_param, false);
dsim_reg_exit_ulps_and_start(dsim->id, 0, 0x1F);
+ mutex_unlock(&g_dsim_lock);
dsim->state = DSIM_STATE_HSCLKEN;
enable_irq(dsim->irq);
@@ -291,10 +301,12 @@ static void _dsim_enable(struct dsim_device *dsim)
dsim_info(dsim, "dsim handover. skip_init=%d\n", skip_init);
}
+ mutex_lock(&g_dsim_lock);
if (!skip_init)
dsim_reg_init(dsim->id, &dsim->config, &dsim->clk_param, true);
dsim_reg_start(dsim->id);
+ mutex_unlock(&g_dsim_lock);
/* TODO: dsi start: enable irq, sfr configuration */
dsim->state = DSIM_STATE_HSCLKEN;
@@ -377,7 +389,9 @@ static void _dsim_enter_ulps_locked(struct dsim_device *dsim)
mutex_unlock(&dsim->cmd_lock);
disable_irq(dsim->irq);
+ mutex_lock(&g_dsim_lock);
dsim_reg_stop_and_enter_ulps(dsim->id, 0, 0x1F);
+ mutex_unlock(&g_dsim_lock);
dsim_phy_power_off(dsim);
@@ -415,8 +429,10 @@ static void _dsim_disable(struct dsim_device *dsim)
/* Wait for current read & write CMDs. */
mutex_lock(&dsim->cmd_lock);
+ mutex_lock(&g_dsim_lock);
/* TODO: 0x1F will be changed */
dsim_reg_stop(dsim->id, 0x1F);
+ mutex_unlock(&g_dsim_lock);
disable_irq(dsim->irq);
dsim->state = DSIM_STATE_SUSPEND;
@@ -805,11 +821,15 @@ getnode_fail:
static void dsim_restart(struct dsim_device *dsim)
{
mutex_lock(&dsim->cmd_lock);
+ mutex_lock(&g_dsim_lock);
dsim_reg_stop(dsim->id, 0x1F);
+ mutex_unlock(&g_dsim_lock);
disable_irq(dsim->irq);
+ mutex_lock(&g_dsim_lock);
dsim_reg_init(dsim->id, &dsim->config, &dsim->clk_param, true);
dsim_reg_start(dsim->id);
+ mutex_unlock(&g_dsim_lock);
enable_irq(dsim->irq);
mutex_unlock(&dsim->cmd_lock);
}
@@ -2033,6 +2053,7 @@ dsim_write_data(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
is_last = true;
}
+ trace_dsi_tx(msg->type, msg->tx_buf, msg->tx_len, is_last);
dsim_debug(dsim, "%s last command\n", is_last ? "" : "Not");
if (is_last) {
@@ -2073,6 +2094,7 @@ dsim_write_data(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
}
err:
+ trace_dsi_cmd_fifo_status(dsim->total_pend_ph, dsim->total_pend_pl);
DPU_ATRACE_END(__func__);
return ret;
}
@@ -2081,16 +2103,18 @@ static int
dsim_req_read_command(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
{
struct mipi_dsi_packet packet;
+ const u8 rx_len = msg->rx_len & 0xff;
dsim_reg_clear_int(dsim->id, DSIM_INTSRC_SFR_PH_FIFO_EMPTY);
reinit_completion(&dsim->ph_wr_comp);
-
+ trace_dsi_tx(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, &rx_len, 1, true);
/* set the maximum packet size returned */
dsim_reg_wr_tx_header(dsim->id, MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
msg->rx_len, 0, false);
/* read request */
mipi_dsi_create_packet(&packet, msg);
+ trace_dsi_tx(msg->type, msg->tx_buf, msg->tx_len, true);
dsim_reg_wr_tx_header(dsim->id, packet.header[0], packet.header[1],
packet.header[2], true);
@@ -2103,6 +2127,7 @@ dsim_read_data(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
u32 rx_fifo, rx_size = 0;
int i = 0, ret = 0;
u8 *rx_buf = msg->rx_buf;
+ const u8 *tx_buf = msg->tx_buf;
if (msg->rx_len > MAX_RX_FIFO) {
dsim_err(dsim, "invalid rx len(%lu) max(%d)\n", msg->rx_len,
@@ -2187,6 +2212,7 @@ dsim_read_data(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
} while (!dsim_reg_rx_fifo_is_empty(dsim->id) && --retry_cnt);
}
+ trace_dsi_rx(tx_buf[0], rx_buf, rx_size);
return rx_size;
}
diff --git a/samsung/panel/panel-samsung-drv.c b/samsung/panel/panel-samsung-drv.c
index 7bf0767..80eb6f2 100644
--- a/samsung/panel/panel-samsung-drv.c
+++ b/samsung/panel/panel-samsung-drv.c
@@ -3360,6 +3360,59 @@ static u64 exynos_panel_vsync_start_time_us(u32 te_us, u32 te_period_us)
return te_period_us * 55 / 100;
}
+/* avoid accumulate te varaince cause predicted value is not accurate enough */
+#define ACCEPTABLE_TE_PERIOD_DETLA_NS (3 * NSEC_PER_SEC)
+static ktime_t exynos_panel_te_ts_prediction(struct exynos_panel *ctx, ktime_t last_te,
+ s64 since_last_te_us, u32 te_period_us)
+{
+ const struct exynos_panel_desc *desc = ctx->desc;
+ s64 rr_switch_delta_us;
+ u32 te_period_before_rr_switch_us;
+ u32 rr_switch_applied_duration;
+ s64 te_period_delta_ns;
+
+ if (!desc || last_te == 0)
+ return 0;
+
+ rr_switch_delta_us = ktime_us_delta(last_te, ctx->last_rr_switch_ts);
+ te_period_before_rr_switch_us = ctx->last_rr != 0 ? USEC_PER_SEC / ctx->last_rr : 0;
+
+ if (ctx->last_rr_switch_ts == ctx->last_lp_exit_ts) {
+ /* new refresh rate should take effect at first vsync after exiting AOD mode */
+ rr_switch_applied_duration = 0;
+ } else {
+ /* If vrr_switch_duration is not set that mean we don't know the new refresh rate
+ * take effect timing. It may take effect at first or second vsync after sending
+ * rr switch commands.
+ */
+ rr_switch_applied_duration = desc->vrr_switch_duration != 0 ?
+ (desc->vrr_switch_duration - 1) : 1;
+ }
+
+ if (rr_switch_delta_us < 0 && te_period_before_rr_switch_us != 0) {
+ ktime_t first_te_after_rr_switch;
+
+ te_period_delta_ns = ((-rr_switch_delta_us / te_period_before_rr_switch_us) + 1) *
+ te_period_before_rr_switch_us * NSEC_PER_USEC;
+
+ if (te_period_delta_ns < ACCEPTABLE_TE_PERIOD_DETLA_NS) {
+ first_te_after_rr_switch = last_te + te_period_delta_ns;
+ rr_switch_delta_us =
+ ktime_us_delta(first_te_after_rr_switch, ctx->last_rr_switch_ts);
+ }
+ }
+
+ if (rr_switch_delta_us > (rr_switch_applied_duration * te_period_before_rr_switch_us)) {
+ te_period_delta_ns =
+ (since_last_te_us / te_period_us) * te_period_us * NSEC_PER_USEC;
+
+ if (te_period_delta_ns < ACCEPTABLE_TE_PERIOD_DETLA_NS)
+ return (last_te + te_period_delta_ns);
+ }
+
+ return 0;
+}
+
static void exynos_panel_check_mipi_sync_timing(struct drm_crtc *crtc,
const struct exynos_panel_mode *current_mode,
struct exynos_panel *ctx)
@@ -3368,6 +3421,7 @@ static void exynos_panel_check_mipi_sync_timing(struct drm_crtc *crtc,
int retry;
u64 left, right;
bool vblank_taken = false;
+ bool rr_applied = false;
if (WARN_ON(!current_mode))
return;
@@ -3402,7 +3456,7 @@ static void exynos_panel_check_mipi_sync_timing(struct drm_crtc *crtc,
retry = te_period_us / USEC_PER_MSEC + 1;
do {
- ktime_t last_te = 0, now;
+ ktime_t last_te = 0, now, predicted_te;
s64 since_last_te_us;
s64 rr_switch_delta_us;
s64 te_period_before_rr_switch_us;
@@ -3411,7 +3465,15 @@ static void exynos_panel_check_mipi_sync_timing(struct drm_crtc *crtc,
now = ktime_get();
since_last_te_us = ktime_us_delta(now, last_te);
/* Need a vblank as a reference point */
- if (since_last_te_us > te_period_us) {
+ predicted_te =
+ exynos_panel_te_ts_prediction(ctx, last_te, since_last_te_us, te_period_us);
+ if (predicted_te) {
+ DPU_ATRACE_BEGIN("predicted_te");
+ last_te = predicted_te;
+ since_last_te_us = ktime_us_delta(now, last_te);
+ rr_applied = true;
+ DPU_ATRACE_END("predicted_te");
+ } else if (since_last_te_us > te_period_us) {
DPU_ATRACE_BEGIN("time_window_wait_crtc");
if (vblank_taken || !drm_crtc_vblank_get(crtc)) {
drm_crtc_wait_one_vblank(crtc);
@@ -3430,7 +3492,8 @@ static void exynos_panel_check_mipi_sync_timing(struct drm_crtc *crtc,
*/
rr_switch_delta_us = ktime_us_delta(last_te, ctx->last_rr_switch_ts);
te_period_before_rr_switch_us = ctx->last_rr != 0 ? USEC_PER_SEC / ctx->last_rr : 0;
- if (rr_switch_delta_us > 0 && rr_switch_delta_us < te_period_before_rr_switch_us) {
+ if (rr_switch_delta_us > 0 && rr_switch_delta_us < te_period_before_rr_switch_us &&
+ !rr_applied) {
DPU_ATRACE_BEGIN("time_window_wait_crtc2");
if (vblank_taken || !drm_crtc_vblank_get(crtc)) {
drm_crtc_wait_one_vblank(crtc);
@@ -3549,6 +3612,7 @@ static void exynos_panel_bridge_mode_set(struct drm_bridge *bridge,
const struct exynos_panel_funcs *funcs = ctx->desc->exynos_panel_func;
const struct exynos_panel_mode *old_mode;
bool need_update_backlight = false;
+ bool come_out_lp_mode = false;
if (WARN_ON(!pmode))
return;
@@ -3599,6 +3663,7 @@ static void exynos_panel_bridge_mode_set(struct drm_bridge *bridge,
ctx->panel_state = PANEL_STATE_NORMAL;
need_update_backlight = true;
state_changed = true;
+ come_out_lp_mode = true;
}
ctx->current_binned_lp = NULL;
} else if (funcs->mode_set) {
@@ -3641,6 +3706,8 @@ static void exynos_panel_bridge_mode_set(struct drm_bridge *bridge,
if (old_mode && drm_mode_vrefresh(&pmode->mode) != drm_mode_vrefresh(&old_mode->mode)) {
ctx->last_rr_switch_ts = ktime_get();
ctx->last_rr = drm_mode_vrefresh(&old_mode->mode);
+ if (come_out_lp_mode)
+ ctx->last_lp_exit_ts = ctx->last_rr_switch_ts;
}
mutex_unlock(&ctx->mode_lock);
diff --git a/samsung/panel/panel-samsung-drv.h b/samsung/panel/panel-samsung-drv.h
index 1f23297..f42d586 100644
--- a/samsung/panel/panel-samsung-drv.h
+++ b/samsung/panel/panel-samsung-drv.h
@@ -484,6 +484,7 @@ struct exynos_panel_desc {
bool is_partial;
bool is_panel_idle_supported;
bool no_lhbm_rr_constraints;
+ bool mipi_sync_te_prediction;
const u32 lhbm_effective_delay_frames;
const unsigned int delay_dsc_reg_init_us;
const struct brightness_capability *brt_capability;
@@ -625,6 +626,8 @@ struct exynos_panel {
* mean rr switch so it differs from last_mode_set_ts
*/
ktime_t last_rr_switch_ts;
+ /* Record the last come out lp mode timestamp */
+ ktime_t last_lp_exit_ts;
u32 last_rr;
struct {