drm/i915/icl: Wait for header/payload credits release
authorMadhav Chauhan <madhav.chauhan@intel.com>
Tue, 30 Oct 2018 11:56:11 +0000 (13:56 +0200)
committerJani Nikula <jani.nikula@intel.com>
Wed, 31 Oct 2018 11:12:56 +0000 (13:12 +0200)
Driver needs payload/header credits for sending any command
and data over DSI link. These credits are released once command
or data sent to link. This patch adds functions to wait for releasing
of payload and header credits.

As per BSPEC, driver needs to ensure that all of commands/data
has been dispatched to panel before the transcoder is enabled.
This patch implement those steps i.e. sending NOP DCS command,
wait for header/payload credit to be released etc.

v2 by Jani:
 - squash the credit wait helpers patch with the first user
 - pass dev_priv to the credit wait helpers
 - bikeshed credit helper names
 - wait for *at least* the current maximum number of credits
 - indentation fix
 - add helpers for credits available

Signed-off-by: Madhav Chauhan <madhav.chauhan@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/84bc509beabf2a2d1324a9f2a67ab4ebe05b10a6.1540900289.git.jani.nikula@intel.com
drivers/gpu/drm/i915/icl_dsi.c

index d9c91001f107a5b589e867ac1acbe437050176fb..0f0447b6b1be3529d2c11a9cf4613c825de46c65 100644 (file)
 #include <drm/drm_mipi_dsi.h>
 #include "intel_dsi.h"
 
+static inline int header_credits_available(struct drm_i915_private *dev_priv,
+                                          enum transcoder dsi_trans)
+{
+       return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_HEADER_CREDIT_MASK)
+               >> FREE_HEADER_CREDIT_SHIFT;
+}
+
+static inline int payload_credits_available(struct drm_i915_private *dev_priv,
+                                           enum transcoder dsi_trans)
+{
+       return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_PLOAD_CREDIT_MASK)
+               >> FREE_PLOAD_CREDIT_SHIFT;
+}
+
+static void wait_for_header_credits(struct drm_i915_private *dev_priv,
+                                   enum transcoder dsi_trans)
+{
+       if (wait_for_us(header_credits_available(dev_priv, dsi_trans) >=
+                       MAX_HEADER_CREDIT, 100))
+               DRM_ERROR("DSI header credits not released\n");
+}
+
+static void wait_for_payload_credits(struct drm_i915_private *dev_priv,
+                                    enum transcoder dsi_trans)
+{
+       if (wait_for_us(payload_credits_available(dev_priv, dsi_trans) >=
+                       MAX_PLOAD_CREDIT, 100))
+               DRM_ERROR("DSI payload credits not released\n");
+}
+
 static enum transcoder dsi_port_to_transcoder(enum port port)
 {
        if (port == PORT_A)
@@ -36,6 +66,47 @@ static enum transcoder dsi_port_to_transcoder(enum port port)
                return TRANSCODER_DSI_1;
 }
 
+static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct mipi_dsi_device *dsi;
+       enum port port;
+       enum transcoder dsi_trans;
+       int ret;
+
+       /* wait for header/payload credits to be released */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               wait_for_header_credits(dev_priv, dsi_trans);
+               wait_for_payload_credits(dev_priv, dsi_trans);
+       }
+
+       /* send nop DCS command */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi = intel_dsi->dsi_hosts[port]->device;
+               dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+               dsi->channel = 0;
+               ret = mipi_dsi_dcs_nop(dsi);
+               if (ret < 0)
+                       DRM_ERROR("error sending DCS NOP command\n");
+       }
+
+       /* wait for header credits to be released */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               wait_for_header_credits(dev_priv, dsi_trans);
+       }
+
+       /* wait for LP TX in progress bit to be cleared */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               if (wait_for_us(!(I915_READ(DSI_LP_MSG(dsi_trans)) &
+                                 LPTX_IN_PROGRESS), 20))
+                       DRM_ERROR("LPTX bit not cleared\n");
+       }
+}
+
 static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -671,6 +742,9 @@ static void gen11_dsi_powerup_panel(struct intel_encoder *encoder)
        intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
        intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
        intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
+
+       /* ensure all panel commands dispatched before enabling transcoder */
+       wait_for_cmds_dispatched_to_panel(encoder);
 }
 
 static void __attribute__((unused))