drm/i915: Write AVI infoframes for MCA LSPCON
authorShashank Sharma <shashank.sharma@intel.com>
Fri, 12 Oct 2018 06:23:12 +0000 (11:53 +0530)
committerJani Nikula <jani.nikula@intel.com>
Mon, 15 Oct 2018 13:01:51 +0000 (16:01 +0300)
LSPCON is a DP branch device, so LSPCON vendors define
specific methods to pass AVI infoframes to the the chip.
This patch adds:
- a generic wrapper function for writing AVI infoframes for
  all LSPCON devices.
- a vendor specific function to wrire AVI infoframes into
  MCA LSPCON devices.

V2: Rebase
V3: Added r-b from Maarten
V4: Rebase
V5: Rebase
V6: Rebase
V7: Fixed checkpatch warnings for alignment
V8: Rebase
V9: Added the retry logic, with 50ms incremental delays while
    writing AVI IF
V10: Changed the return value check
V11: Fixed checkpatch warning
V12: Rebase

Cc: Imre Deak <imre.deak@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1539325394-20788-6-git-send-email-shashank.sharma@intel.com
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lspcon.c

index 8c402d01f66340d89bc25aa2c2d02784946b1ebf..b8e5f9569f5ab7964baf23e50c24feb03085648c 100644 (file)
@@ -2215,6 +2215,10 @@ void intel_color_load_luts(struct drm_crtc_state *crtc_state);
 bool lspcon_init(struct intel_digital_port *intel_dig_port);
 void lspcon_resume(struct intel_lspcon *lspcon);
 void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon);
+void lspcon_write_infoframe(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *crtc_state,
+                           unsigned int type,
+                           const void *buf, ssize_t len);
 void lspcon_set_infoframes(struct intel_encoder *encoder,
                           bool enable,
                           const struct intel_crtc_state *crtc_state,
index d2232e32a059962cfe235ed802e1efe0fd9bcf98..89d5e3984452884308642c9731a8e358fca650a4 100644 (file)
@@ -2322,6 +2322,8 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
                intel_dig_port->infoframe_enabled = g4x_infoframe_enabled;
        } else if (HAS_DDI(dev_priv)) {
                if (intel_dig_port->lspcon.active) {
+                       intel_dig_port->write_infoframe =
+                                       lspcon_write_infoframe;
                        intel_dig_port->set_infoframes = lspcon_set_infoframes;
                        intel_dig_port->infoframe_enabled =
                                                lspcon_infoframe_enabled;
index 8d497279ee9cbc11851afcc98cf48ccafa351ba0..b806803238d4569e1160a6c1c41dc026142501e5 100644 (file)
 #define LSPCON_VENDOR_PARADE_OUI 0x001CF8
 #define LSPCON_VENDOR_MCA_OUI 0x0060AD
 
+/* AUX addresses to write MCA AVI IF */
+#define LSPCON_MCA_AVI_IF_WRITE_OFFSET 0x5C0
+#define LSPCON_MCA_AVI_IF_CTRL 0x5DF
+#define  LSPCON_MCA_AVI_IF_KICKOFF (1 << 0)
+#define  LSPCON_MCA_AVI_IF_HANDLED (1 << 1)
+
 static struct intel_dp *lspcon_to_intel_dp(struct intel_lspcon *lspcon)
 {
        struct intel_digital_port *dig_port =
@@ -234,6 +240,88 @@ static void lspcon_resume_in_pcon_wa(struct intel_lspcon *lspcon)
        DRM_DEBUG_KMS("LSPCON DP descriptor mismatch after resume\n");
 }
 
+static bool _lspcon_write_avi_infoframe_mca(struct drm_dp_aux *aux,
+                                           const uint8_t *buffer, ssize_t len)
+{
+       int ret;
+       uint32_t val = 0;
+       uint32_t retry;
+       uint16_t reg;
+       const uint8_t *data = buffer;
+
+       reg = LSPCON_MCA_AVI_IF_WRITE_OFFSET;
+       while (val < len) {
+               /* DPCD write for AVI IF can fail on a slow FW day, so retry */
+               for (retry = 0; retry < 5; retry++) {
+                       ret = drm_dp_dpcd_write(aux, reg, (void *)data, 1);
+                       if (ret == 1) {
+                               break;
+                       } else if (retry < 4) {
+                               mdelay(50);
+                               continue;
+                       } else {
+                               DRM_ERROR("DPCD write failed at:0x%x\n", reg);
+                               return false;
+                       }
+               }
+               val++; reg++; data++;
+       }
+
+       val = 0;
+       reg = LSPCON_MCA_AVI_IF_CTRL;
+       ret = drm_dp_dpcd_read(aux, reg, &val, 1);
+       if (ret < 0) {
+               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
+               return false;
+       }
+
+       /* Indicate LSPCON chip about infoframe, clear bit 1 and set bit 0 */
+       val &= ~LSPCON_MCA_AVI_IF_HANDLED;
+       val |= LSPCON_MCA_AVI_IF_KICKOFF;
+
+       ret = drm_dp_dpcd_write(aux, reg, &val, 1);
+       if (ret < 0) {
+               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
+               return false;
+       }
+
+       val = 0;
+       ret = drm_dp_dpcd_read(aux, reg, &val, 1);
+       if (ret < 0) {
+               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
+               return false;
+       }
+
+       if (val == LSPCON_MCA_AVI_IF_HANDLED)
+               DRM_DEBUG_KMS("AVI IF handled by FW\n");
+
+       return true;
+}
+
+void lspcon_write_infoframe(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *crtc_state,
+                           unsigned int type,
+                           const void *frame, ssize_t len)
+{
+       bool ret = true;
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_lspcon *lspcon = enc_to_intel_lspcon(&encoder->base);
+
+       /* LSPCON only needs AVI IF */
+       if (type != HDMI_INFOFRAME_TYPE_AVI)
+               return;
+
+       if (lspcon->vendor == LSPCON_VENDOR_MCA)
+               ret = _lspcon_write_avi_infoframe_mca(&intel_dp->aux,
+                                                     frame, len);
+       if (!ret) {
+               DRM_ERROR("Failed to write AVI infoframes\n");
+               return;
+       }
+
+       DRM_DEBUG_DRIVER("AVI infoframes updated successfully\n");
+}
+
 void lspcon_set_infoframes(struct intel_encoder *encoder,
                           bool enable,
                           const struct intel_crtc_state *crtc_state,