diff options
author | PixelBot AutoMerger <android-nexus-securitybot@system.gserviceaccount.com> | 2023-03-12 18:38:33 -0700 |
---|---|---|
committer | SecurityBot <android-nexus-securitybot@system.gserviceaccount.com> | 2023-03-12 18:38:34 -0700 |
commit | 39d0f1e423c02468d72b2f23d912f3394f90fda5 (patch) | |
tree | c6077a761de4a58715fccdef161906b1bc899c92 /samsung/exynos_drm_dsim.c | |
parent | 1a562ba0f0ec75b670294b11e107f572e19dc5a4 (diff) | |
parent | f49bb252bd7fca78a7d819c1f697e742e6be6966 (diff) | |
download | display-android-gs-pantah-5.10-u-beta1.tar.gz |
Merge android13-gs-pixel-5.10-tm-qpr3 into android13-gs-pixel-5.10-udcandroid-u-beta-1_r0.5android-u-beta-1_r0.4android-u-beta-1_r0.3android-gs-raviole-5.10-u-beta1android-gs-pantah-5.10-u-beta1android-gs-bluejay-5.10-u-beta1
SBMerger: 478053055
Change-Id: I8726c62d1951fbe135641c68d260a5de742db741
Signed-off-by: SecurityBot <android-nexus-securitybot@system.gserviceaccount.com>
Diffstat (limited to 'samsung/exynos_drm_dsim.c')
-rw-r--r-- | samsung/exynos_drm_dsim.c | 221 |
1 files changed, 147 insertions, 74 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) |