summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPixelBot AutoMerger <android-nexus-securitybot@system.gserviceaccount.com>2023-03-12 18:38:33 -0700
committerSecurityBot <android-nexus-securitybot@system.gserviceaccount.com>2023-03-12 18:38:34 -0700
commit39d0f1e423c02468d72b2f23d912f3394f90fda5 (patch)
treec6077a761de4a58715fccdef161906b1bc899c92
parent1a562ba0f0ec75b670294b11e107f572e19dc5a4 (diff)
parentf49bb252bd7fca78a7d819c1f697e742e6be6966 (diff)
downloaddisplay-android-gs-raviole-5.10-u-beta1.tar.gz
SBMerger: 478053055 Change-Id: I8726c62d1951fbe135641c68d260a5de742db741 Signed-off-by: SecurityBot <android-nexus-securitybot@system.gserviceaccount.com>
-rw-r--r--samsung/exynos_drm_dsim.c221
-rw-r--r--samsung/exynos_drm_recovery.c50
2 files changed, 195 insertions, 76 deletions
diff --git a/samsung/exynos_drm_dsim.c b/samsung/exynos_drm_dsim.c
index 9ff30f3..7ce6ce0 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);
@@ -1815,10 +1847,16 @@ static int __dsim_wait_for_ph_fifo_empty(struct dsim_device *dsim)
{
const struct decon_device *decon = dsim_get_decon(dsim);
+ if (dsim_reg_header_fifo_is_empty(dsim->id)) {
+ dsim_debug(dsim, "no need to wait for packet header fifo empty\n");
+ return 0;
+ }
+
dsim_debug(dsim, "wait for packet header fifo empty\n");
if (!wait_for_completion_timeout(&dsim->ph_wr_comp, MIPI_WR_TIMEOUT)) {
if (dsim_reg_header_fifo_is_empty(dsim->id)) {
+ dsim_warn(dsim, "timed out but header fifo was empty\n");
dsim_reg_clear_int(dsim->id,
DSIM_INTSRC_SFR_PH_FIFO_EMPTY);
return 0;
@@ -1841,10 +1879,16 @@ static int __dsim_wait_for_pl_fifo_empty(struct dsim_device *dsim)
{
const struct decon_device *decon = dsim_get_decon(dsim);
+ if (dsim_reg_payload_fifo_is_empty(dsim->id)) {
+ dsim_debug(dsim, "no need to wait for payload fifo empty\n");
+ return 0;
+ }
+
dsim_debug(dsim, "wait for packet payload fifo empty\n");
if (!wait_for_completion_timeout(&dsim->pl_wr_comp, MIPI_WR_TIMEOUT)) {
if (dsim_reg_payload_fifo_is_empty(dsim->id)) {
+ dsim_warn(dsim, "timed out but payload fifo was empty\n");
dsim_reg_clear_int(dsim->id,
DSIM_INTSRC_SFR_PL_FIFO_EMPTY);
return 0;
@@ -1908,39 +1952,79 @@ 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_packet *packet)
{
- struct mipi_dsi_packet packet;
+ WARN_ON(!mutex_is_locked(&dsim->cmd_lock));
- mipi_dsi_create_packet(&packet, msg);
+ if (packet->payload_length > 0)
+ dsim_write_payload(dsim, packet->payload, packet->payload_length);
+ dsim_reg_wr_tx_header(dsim->id, packet->header[0], packet->header[1], packet->header[2],
+ false);
- if (is_long)
- dsim_write_payload(dsim, packet.payload, packet.payload_length);
- dsim_reg_wr_tx_header(dsim->id, packet.header[0], packet.header[1],
- packet.header[2], false);
-
- dsim_debug(dsim, "header(0x%x 0x%x 0x%x) size(%lu) ph fifo(%d)\n",
- packet.header[0], packet.header[1], packet.header[2],
- packet.size, dsim_reg_get_ph_cnt(dsim->id));
+ dsim_debug(dsim, "header(0x%x 0x%x 0x%x) size(%lu) ph fifo(%d)\n", packet->header[0],
+ packet->header[1], packet->header[2], packet->size,
+ dsim_reg_get_ph_cnt(dsim->id));
}
-static int dsim_write_single_cmd_locked(struct dsim_device *dsim,
- const struct mipi_dsi_msg *msg, bool is_long)
+static void dsim_cmd_packetgo_queue_locked(struct dsim_device *dsim,
+ const struct mipi_dsi_packet *packet)
{
- const u8 *tx_buf = msg->tx_buf;
+ /* 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(packet->payload_length, 4);
+ __dsim_cmd_write_locked(dsim, packet);
+
+ dsim_debug(dsim, "total pending packet header(%u) payload(%u)\n", dsim->total_pend_ph,
+ dsim->total_pend_pl);
+}
+
+static void __dsim_cmd_prepare(struct dsim_device *dsim)
+{
WARN_ON(!mutex_is_locked(&dsim->cmd_lock));
- DPU_EVENT_LOG_CMD(dsim, msg->type, tx_buf[0], msg->tx_len);
+ dsim_reg_clear_int(dsim->id, DSIM_INTSRC_SFR_PH_FIFO_EMPTY | DSIM_INTSRC_SFR_PL_FIFO_EMPTY);
- dsim_reg_clear_int(dsim->id, DSIM_INTSRC_SFR_PH_FIFO_EMPTY);
+ reinit_completion(&dsim->ph_wr_comp);
+ reinit_completion(&dsim->pl_wr_comp);
+}
+
+static int dsim_cmd_packetgo_flush_locked(struct dsim_device *dsim)
+{
+ int ret;
+
+ /* this should only be called with pending packets */
+ WARN_ON(!dsim->total_pend_ph);
+
+ __dsim_cmd_prepare(dsim);
+
+ 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, dsim->total_pend_pl > 0);
+ 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;
+}
- reinit_completion(is_long ? &dsim->pl_wr_comp : &dsim->ph_wr_comp);
+static int dsim_write_single_cmd_locked(struct dsim_device *dsim,
+ const struct mipi_dsi_packet *packet)
+{
+ WARN_ON(dsim_cmd_packetgo_is_enabled(dsim));
+
+ __dsim_cmd_prepare(dsim);
- __dsim_write_data(dsim, msg, is_long);
+ __dsim_cmd_write_locked(dsim, packet);
- return dsim_wait_for_cmd_fifo_empty(dsim, is_long);
+ return dsim_wait_for_cmd_fifo_empty(dsim, packet->payload_length > 0);
}
/*
@@ -2001,24 +2085,33 @@ 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;
- bool is_long;
- bool is_empty_msg;
+ const u16 flags = msg->flags;
bool is_last;
+ struct mipi_dsi_packet packet = { .size = 0 };
+
+ WARN_ON(!mutex_is_locked(&dsim->cmd_lock));
+
+ if (msg->tx_len > 0) {
+ const u8 *tx_buf = msg->tx_buf;
+ ret = mipi_dsi_create_packet(&packet, msg);
+ if (ret) {
+ dsim_err(dsim, "unable to create dsi packet (%d)\n", ret);
+ return 0;
+ }
+
+ DPU_EVENT_LOG_CMD(dsim, msg->type, tx_buf[0], msg->tx_len);
+ }
DPU_ATRACE_BEGIN(__func__);
- is_empty_msg = !msg->tx_buf || msg->tx_len == 0;
- is_long = mipi_dsi_packet_format_is_long(msg->type);
if (dsim->config.mode == DSIM_VIDEO_MODE) {
if (flags & (EXYNOS_DSI_MSG_FORCE_BATCH | EXYNOS_DSI_MSG_FORCE_FLUSH))
dsim_warn(dsim, "force batching is attempted in video mode\n");
- if (!is_empty_msg)
- ret = dsim_write_single_cmd_locked(dsim, msg, is_long);
+ if (packet.size)
+ ret = dsim_write_single_cmd_locked(dsim, &packet);
goto err;
}
@@ -2028,8 +2121,8 @@ dsim_write_data(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
goto err;
}
- if (((dsim->total_pend_pl + msg->tx_len) > MAX_PL_FIFO) ||
- (dsim->total_pend_ph == MAX_PH_FIFO)) {
+ if (((dsim->total_pend_pl + packet.payload_length) > MAX_PL_FIFO) ||
+ (dsim->total_pend_ph >= MAX_PH_FIFO)) {
dsim_err(dsim, "fifo would be full. ph(%u) pl(%lu) max(%d/%d)\n",
dsim->total_pend_ph,
dsim->total_pend_pl + msg->tx_len,
@@ -2042,14 +2135,15 @@ dsim_write_data(struct dsim_device *dsim, const struct mipi_dsi_msg *msg)
if (flags & EXYNOS_DSI_MSG_FORCE_FLUSH) {
dsim->force_batching = false;
- WARN_ON(!is_empty_msg);
+ /* force batching should happen only with empty msg */
+ WARN_ON(packet.size);
}
- if (!is_last && !is_empty_msg &&
- (((dsim->total_pend_ph + 1) == MAX_PH_FIFO) ||
- ((dsim->total_pend_pl + msg->tx_len) > PL_FIFO_THRESHOLD))) {
- dsim_warn(dsim, "warning. changed last command. pend pl/pl(%u,%u)\n",
- dsim->total_pend_ph, dsim->total_pend_pl);
+ if (!is_last && packet.size &&
+ (((dsim->total_pend_ph + 1) >= MAX_PH_FIFO) ||
+ ((dsim->total_pend_pl + packet.payload_length) > PL_FIFO_THRESHOLD))) {
+ dsim_warn(dsim, "warning. changed last command. pend pl/pl(%u,%u) new pl(%zu)\n",
+ dsim->total_pend_ph, dsim->total_pend_pl, packet.payload_length);
is_last = true;
}
@@ -2057,40 +2151,19 @@ 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) {
- reinit_completion(is_long ?
- &dsim->pl_wr_comp : &dsim->ph_wr_comp);
-
- if (!is_empty_msg)
- __dsim_write_data(dsim, msg, is_long);
+ if (dsim_cmd_packetgo_is_enabled(dsim)) {
+ if (packet.size > 0)
+ dsim_cmd_packetgo_queue_locked(dsim, &packet);
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);
- } 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);
+ ret = dsim_cmd_packetgo_flush_locked(dsim);
+ } else if (packet.size > 0) {
+ ret = dsim_write_single_cmd_locked(dsim, &packet);
}
- 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);
+ } else if (packet.size > 0) {
+ dsim_cmd_packetgo_queue_locked(dsim, &packet);
}
err:
@@ -2229,7 +2302,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 +2340,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)
diff --git a/samsung/exynos_drm_recovery.c b/samsung/exynos_drm_recovery.c
index 093a1ba..8963147 100644
--- a/samsung/exynos_drm_recovery.c
+++ b/samsung/exynos_drm_recovery.c
@@ -28,6 +28,52 @@
#include "exynos_drm_decon.h"
#include "exynos_drm_recovery.h"
+static struct drm_atomic_state *_duplicate_active_crtc_state(struct drm_crtc *crtc,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_atomic_state *state;
+ struct drm_crtc_state *crtc_state;
+ int err;
+
+ state = drm_atomic_state_alloc(dev);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ state->acquire_ctx = ctx;
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state)) {
+ err = PTR_ERR(crtc_state);
+ goto free_state;
+ }
+
+ if (!crtc_state->active) {
+ pr_warn("crtc[%s]: skipping duplication of inactive crtc state\n", crtc->name);
+ err = -EINVAL;
+ goto free_state;
+ }
+
+ err = drm_atomic_add_affected_planes(state, crtc);
+ if (err)
+ goto free_state;
+
+ err = drm_atomic_add_affected_connectors(state, crtc);
+ if (err)
+ goto free_state;
+
+ /* clear the acquire context so that it isn't accidentally reused */
+ state->acquire_ctx = NULL;
+
+free_state:
+ if (err < 0) {
+ drm_atomic_state_put(state);
+ state = ERR_PTR(err);
+ }
+
+ return state;
+}
+
static void exynos_recovery_handler(struct work_struct *work)
{
struct exynos_recovery *recovery = container_of(work,
@@ -49,7 +95,7 @@ static void exynos_recovery_handler(struct work_struct *work)
drm_modeset_acquire_init(&ctx, 0);
- rcv_state = drm_atomic_helper_duplicate_state(dev, &ctx);
+ rcv_state = _duplicate_active_crtc_state(crtc, &ctx);
if (IS_ERR(rcv_state)) {
ret = PTR_ERR(rcv_state);
goto out_drop_locks;
@@ -57,6 +103,7 @@ static void exynos_recovery_handler(struct work_struct *work)
state = drm_atomic_state_alloc(dev);
if (!state) {
+ drm_atomic_state_put(rcv_state);
ret = -ENOMEM;
goto out_drop_locks;
}
@@ -102,7 +149,6 @@ retry:
if (ret)
goto out;
- drm_mode_config_reset(dev);
ret = drm_atomic_helper_commit_duplicated_state(rcv_state, &ctx);
if (ret)
goto out;