+static bool dsi_vc_is_enabled(int channel)
+{
+ return REG_GET(DSI_VC_CTRL(channel), 0, 0);
+}
+
+static void dsi_packet_sent_handler_vp(void *data, u32 mask)
+{
+ const int channel = dsi.update_channel;
+ u8 bit = dsi.te_enabled ? 30 : 31;
+
+ if (REG_GET(DSI_VC_TE(channel), bit, bit) == 0)
+ complete((struct completion *)data);
+}
+
+static int dsi_sync_vc_vp(int channel)
+{
+ int r = 0;
+ u8 bit;
+
+ DECLARE_COMPLETION_ONSTACK(completion);
+
+ bit = dsi.te_enabled ? 30 : 31;
+
+ r = dsi_register_isr_vc(channel, dsi_packet_sent_handler_vp,
+ &completion, DSI_VC_IRQ_PACKET_SENT);
+ if (r)
+ goto err0;
+
+ /* Wait for completion only if TE_EN/TE_START is still set */
+ if (REG_GET(DSI_VC_TE(channel), bit, bit)) {
+ if (wait_for_completion_timeout(&completion,
+ msecs_to_jiffies(10)) == 0) {
+ DSSERR("Failed to complete previous frame transfer\n");
+ r = -EIO;
+ goto err1;
+ }
+ }
+
+ dsi_unregister_isr_vc(channel, dsi_packet_sent_handler_vp,
+ &completion, DSI_VC_IRQ_PACKET_SENT);
+
+ return 0;
+err1:
+ dsi_unregister_isr_vc(channel, dsi_packet_sent_handler_vp, &completion,
+ DSI_VC_IRQ_PACKET_SENT);
+err0:
+ return r;
+}
+
+static void dsi_packet_sent_handler_l4(void *data, u32 mask)
+{
+ const int channel = dsi.update_channel;
+
+ if (REG_GET(DSI_VC_CTRL(channel), 5, 5) == 0)
+ complete((struct completion *)data);
+}
+
+static int dsi_sync_vc_l4(int channel)
+{
+ int r = 0;
+
+ DECLARE_COMPLETION_ONSTACK(completion);
+
+ r = dsi_register_isr_vc(channel, dsi_packet_sent_handler_l4,
+ &completion, DSI_VC_IRQ_PACKET_SENT);
+ if (r)
+ goto err0;
+
+ /* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */
+ if (REG_GET(DSI_VC_CTRL(channel), 5, 5)) {
+ if (wait_for_completion_timeout(&completion,
+ msecs_to_jiffies(10)) == 0) {
+ DSSERR("Failed to complete previous l4 transfer\n");
+ r = -EIO;
+ goto err1;
+ }
+ }
+
+ dsi_unregister_isr_vc(channel, dsi_packet_sent_handler_l4,
+ &completion, DSI_VC_IRQ_PACKET_SENT);
+
+ return 0;
+err1:
+ dsi_unregister_isr_vc(channel, dsi_packet_sent_handler_l4,
+ &completion, DSI_VC_IRQ_PACKET_SENT);
+err0:
+ return r;
+}
+
+static int dsi_sync_vc(int channel)
+{
+ WARN_ON(!dsi_bus_is_locked());
+
+ WARN_ON(in_interrupt());
+
+ if (!dsi_vc_is_enabled(channel))
+ return 0;
+
+ switch (dsi.vc[channel].mode) {
+ case DSI_VC_MODE_VP:
+ return dsi_sync_vc_vp(channel);
+ case DSI_VC_MODE_L4:
+ return dsi_sync_vc_l4(channel);
+ default:
+ BUG();
+ }
+}
+