summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Salido <salidoa@google.com>2023-02-23 17:11:50 -0800
committerKen Huang <kenbshuang@google.com>2023-03-01 14:42:59 +0800
commitd23808b6234881e723ec707d0863c00f5e4b76fb (patch)
tree798cc5ac3e8d143791ac988b2d9fdb4abdef4396
parent467e6f0334ebbcb6ac948e0b4c45204e4ff38e77 (diff)
downloaddisplay-d23808b6234881e723ec707d0863c00f5e4b76fb.tar.gz
drm: samsung: dsim: cleanup packet-go even after failure
When there's a timeout sending a series of commands using packet-go feature, sending of commands could fail due to unexpected issues. In such cases we still need to ensure that the state of the feature is cleared even if it timed out, otherwise we may land in unexpected sw state. Bug: 269702366 Test: turn screen on/off, check dynamic debug logs Change-Id: I65648964372daa1519fbe68d796425f4bb5cf56b Signed-off-by: Adrian Salido <salidoa@google.com>
-rw-r--r--samsung/exynos_drm_dsim.c125
1 files changed, 90 insertions, 35 deletions
diff --git a/samsung/exynos_drm_dsim.c b/samsung/exynos_drm_dsim.c
index 9ff30f3..f5a6b92 100644
--- a/samsung/exynos_drm_dsim.c
+++ b/samsung/exynos_drm_dsim.c
@@ -371,6 +371,40 @@ static void dsim_encoder_enable(struct drm_encoder *encoder, struct drm_atomic_s
}
}
+static inline bool dsim_cmd_packetgo_is_enabled(const struct dsim_device *dsim)
+{
+ return dsim->total_pend_ph > 0;
+}
+
+static void __dsim_cmd_packetgo_enable_locked(struct dsim_device *dsim, bool en)
+{
+ if (en) {
+ pm_runtime_get_sync(dsim->dev);
+ dsim_debug(dsim, "enabling packetgo\n");
+ }
+
+ dsim_reg_enable_packetgo(dsim->id, en);
+ if (!en) {
+ pm_runtime_put(dsim->dev);
+
+ dsim->total_pend_ph = 0;
+ dsim->total_pend_pl = 0;
+ dsim_debug(dsim, "packetgo disabled\n");
+ }
+}
+
+static void __dsim_check_pend_cmd_locked(struct dsim_device *dsim)
+{
+ WARN_ON(!mutex_is_locked(&dsim->cmd_lock));
+
+ if (WARN_ON(dsim_reg_has_pend_cmd(dsim->id)))
+ dsim_dump(dsim);
+
+ if (WARN(dsim_cmd_packetgo_is_enabled(dsim), "pending packets remaining ph(%u) pl(%u)\n",
+ dsim->total_pend_ph, dsim->total_pend_pl))
+ __dsim_cmd_packetgo_enable_locked(dsim, false);
+}
+
static void _dsim_enter_ulps_locked(struct dsim_device *dsim)
{
const struct decon_device *decon = dsim_get_decon(dsim);
@@ -383,8 +417,7 @@ static void _dsim_enter_ulps_locked(struct dsim_device *dsim)
/* Wait for current read & write CMDs. */
mutex_lock(&dsim->cmd_lock);
- if (WARN_ON(dsim_reg_has_pend_cmd(dsim->id)))
- dsim_dump(dsim);
+ __dsim_check_pend_cmd_locked(dsim);
dsim->state = DSIM_STATE_ULPS;
mutex_unlock(&dsim->cmd_lock);
@@ -436,14 +469,13 @@ static void _dsim_disable(struct dsim_device *dsim)
disable_irq(dsim->irq);
dsim->state = DSIM_STATE_SUSPEND;
- WARN_ON(dsim_reg_has_pend_cmd(dsim->id));
+ __dsim_check_pend_cmd_locked(dsim);
+
+ dsim->force_batching = false;
mutex_unlock(&dsim->cmd_lock);
mutex_unlock(&dsim->state_lock);
dsim_phy_power_off(dsim);
- dsim->total_pend_ph = 0;
- dsim->total_pend_pl = 0;
- dsim->force_batching = false;
#if defined(CONFIG_CPU_IDLE)
exynos_update_ip_idle_status(dsim->idle_ip_index, 1);
@@ -1908,11 +1940,13 @@ dsim_write_payload(struct dsim_device *dsim, const u8* buf, size_t len)
}
}
-static void __dsim_write_data(struct dsim_device *dsim,
- const struct mipi_dsi_msg *msg, bool is_long)
+static void __dsim_cmd_write_locked(struct dsim_device *dsim, const struct mipi_dsi_msg *msg,
+ bool is_long)
{
struct mipi_dsi_packet packet;
+ WARN_ON(!mutex_is_locked(&dsim->cmd_lock));
+
mipi_dsi_create_packet(&packet, msg);
if (is_long)
@@ -1925,12 +1959,50 @@ static void __dsim_write_data(struct dsim_device *dsim,
packet.size, dsim_reg_get_ph_cnt(dsim->id));
}
+static void dsim_cmd_packetgo_queue_locked(struct dsim_device *dsim, const struct mipi_dsi_msg *msg,
+ bool is_long)
+{
+ /* if this is the first packet being queued, enable packet go feature */
+ if (!dsim->total_pend_ph)
+ __dsim_cmd_packetgo_enable_locked(dsim, true);
+
+ dsim->total_pend_ph++;
+ dsim->total_pend_pl += ALIGN(msg->tx_len, 4);
+
+ __dsim_cmd_write_locked(dsim, msg, is_long);
+
+ dsim_debug(dsim, "total pending packet header(%u) payload(%u)\n", dsim->total_pend_ph,
+ dsim->total_pend_pl);
+}
+
+static int dsim_cmd_packetgo_flush_locked(struct dsim_device *dsim, bool is_long)
+{
+ int ret;
+
+ /* this should only be called with pending packets */
+ WARN_ON(!dsim->total_pend_ph);
+
+ dsim_reg_ready_packetgo(dsim->id, true);
+ dsim_debug(dsim, "packet go ready (ph: %d, pl: %d)\n", dsim->total_pend_ph,
+ dsim->total_pend_pl);
+
+ ret = dsim_wait_for_cmd_fifo_empty(dsim, is_long);
+ if (ret)
+ dsim_warn(dsim, "packetgo failed on wait for cmd fifo empty (%d)\n", ret);
+
+ /* clear packetgo pending (even if it timed out) */
+ __dsim_cmd_packetgo_enable_locked(dsim, false);
+
+ return ret;
+}
+
static int dsim_write_single_cmd_locked(struct dsim_device *dsim,
const struct mipi_dsi_msg *msg, bool is_long)
{
const u8 *tx_buf = msg->tx_buf;
WARN_ON(!mutex_is_locked(&dsim->cmd_lock));
+ WARN_ON(dsim_cmd_packetgo_is_enabled(dsim));
DPU_EVENT_LOG_CMD(dsim, msg->type, tx_buf[0], msg->tx_len);
@@ -1938,7 +2010,7 @@ static int dsim_write_single_cmd_locked(struct dsim_device *dsim,
reinit_completion(is_long ? &dsim->pl_wr_comp : &dsim->ph_wr_comp);
- __dsim_write_data(dsim, msg, is_long);
+ __dsim_cmd_write_locked(dsim, msg, is_long);
return dsim_wait_for_cmd_fifo_empty(dsim, is_long);
}
@@ -2001,8 +2073,7 @@ static void need_wait_vblank(struct dsim_device *dsim)
#define PL_FIFO_THRESHOLD mult_frac(MAX_PL_FIFO, 75, 100) /* 75% */
#define IS_LAST(flags) (((flags) & MIPI_DSI_MSG_LASTCOMMAND) != 0)
-static int
-dsim_write_data(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
+static int dsim_write_data_locked(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
{
int ret = 0;
u16 flags = msg->flags;
@@ -2010,6 +2081,8 @@ dsim_write_data(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
bool is_empty_msg;
bool is_last;
+ WARN_ON(!mutex_is_locked(&dsim->cmd_lock));
+
DPU_ATRACE_BEGIN(__func__);
is_empty_msg = !msg->tx_buf || msg->tx_len == 0;
@@ -2057,40 +2130,22 @@ dsim_write_data(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
dsim_debug(dsim, "%s last command\n", is_last ? "" : "Not");
if (is_last) {
- if (dsim->total_pend_ph) {
+ if (dsim_cmd_packetgo_is_enabled(dsim)) {
reinit_completion(is_long ?
&dsim->pl_wr_comp : &dsim->ph_wr_comp);
if (!is_empty_msg)
- __dsim_write_data(dsim, msg, is_long);
+ dsim_cmd_packetgo_queue_locked(dsim, msg, is_long);
if (!(flags & EXYNOS_DSI_MSG_IGNORE_VBLANK))
need_wait_vblank(dsim);
- dsim_reg_ready_packetgo(dsim->id, true);
- dsim_debug(dsim, "packet go ready\n");
-
- ret = dsim_wait_for_cmd_fifo_empty(dsim, is_long);
- if (!ret) {
- dsim_reg_enable_packetgo(dsim->id, false);
- dsim->total_pend_ph = 0;
- dsim->total_pend_pl = 0;
- }
-
- pm_runtime_put_sync(dsim->dev);
+ ret = dsim_cmd_packetgo_flush_locked(dsim, is_long);
} else if (!is_empty_msg) {
ret = dsim_write_single_cmd_locked(dsim, msg, is_long);
}
} else if (!is_empty_msg) {
- if (!dsim->total_pend_ph) {
- pm_runtime_get_sync(dsim->dev);
- dsim_reg_enable_packetgo(dsim->id, true);
- }
- dsim->total_pend_ph++;
- dsim->total_pend_pl += ALIGN(msg->tx_len, 4);
- __dsim_write_data(dsim, msg, is_long);
- dsim_debug(dsim, "total pending packet header(%u) payload(%u)\n",
- dsim->total_pend_ph, dsim->total_pend_pl);
+ dsim_cmd_packetgo_queue_locked(dsim, msg, is_long);
}
err:
@@ -2229,7 +2284,7 @@ dsim_write_data_dual(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
mutex_lock(&dsim->cmd_lock);
- ret = dsim_write_data(dsim, msg);
+ ret = dsim_write_data_locked(dsim, msg);
mutex_unlock(&dsim->cmd_lock);
@@ -2267,7 +2322,7 @@ static ssize_t dsim_host_transfer(struct mipi_dsi_host *host,
ret = dsim_read_data(dsim, msg);
break;
default:
- ret = dsim_write_data(dsim, msg);
+ ret = dsim_write_data_locked(dsim, msg);
if (dsim->dual_dsi == DSIM_DUAL_DSI_MAIN) {
sec_dsi = exynos_get_dual_dsi(DSIM_DUAL_DSI_SEC);
if (sec_dsi)