|
@@ -35,16 +35,54 @@ static struct intel_dp *lspcon_to_intel_dp(struct intel_lspcon *lspcon)
|
|
|
return &dig_port->dp;
|
|
|
}
|
|
|
|
|
|
+static const char *lspcon_mode_name(enum drm_lspcon_mode mode)
|
|
|
+{
|
|
|
+ switch (mode) {
|
|
|
+ case DRM_LSPCON_MODE_PCON:
|
|
|
+ return "PCON";
|
|
|
+ case DRM_LSPCON_MODE_LS:
|
|
|
+ return "LS";
|
|
|
+ case DRM_LSPCON_MODE_INVALID:
|
|
|
+ return "INVALID";
|
|
|
+ default:
|
|
|
+ MISSING_CASE(mode);
|
|
|
+ return "INVALID";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static enum drm_lspcon_mode lspcon_get_current_mode(struct intel_lspcon *lspcon)
|
|
|
{
|
|
|
- enum drm_lspcon_mode current_mode = DRM_LSPCON_MODE_INVALID;
|
|
|
+ enum drm_lspcon_mode current_mode;
|
|
|
struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
|
|
|
|
|
|
- if (drm_lspcon_get_mode(adapter, ¤t_mode))
|
|
|
+ if (drm_lspcon_get_mode(adapter, ¤t_mode)) {
|
|
|
DRM_ERROR("Error reading LSPCON mode\n");
|
|
|
- else
|
|
|
- DRM_DEBUG_KMS("Current LSPCON mode %s\n",
|
|
|
- current_mode == DRM_LSPCON_MODE_PCON ? "PCON" : "LS");
|
|
|
+ return DRM_LSPCON_MODE_INVALID;
|
|
|
+ }
|
|
|
+ return current_mode;
|
|
|
+}
|
|
|
+
|
|
|
+static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon,
|
|
|
+ enum drm_lspcon_mode mode)
|
|
|
+{
|
|
|
+ enum drm_lspcon_mode current_mode;
|
|
|
+
|
|
|
+ current_mode = lspcon_get_current_mode(lspcon);
|
|
|
+ if (current_mode == mode || current_mode == DRM_LSPCON_MODE_INVALID)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ DRM_DEBUG_KMS("Waiting for LSPCON mode %s to settle\n",
|
|
|
+ lspcon_mode_name(mode));
|
|
|
+
|
|
|
+ wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode ||
|
|
|
+ current_mode == DRM_LSPCON_MODE_INVALID, 100);
|
|
|
+ if (current_mode != mode)
|
|
|
+ DRM_DEBUG_KMS("LSPCON mode hasn't settled\n");
|
|
|
+
|
|
|
+out:
|
|
|
+ DRM_DEBUG_KMS("Current LSPCON mode %s\n",
|
|
|
+ lspcon_mode_name(current_mode));
|
|
|
+
|
|
|
return current_mode;
|
|
|
}
|
|
|
|
|
@@ -97,8 +135,10 @@ static bool lspcon_probe(struct intel_lspcon *lspcon)
|
|
|
{
|
|
|
enum drm_dp_dual_mode_type adaptor_type;
|
|
|
struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
|
|
|
+ enum drm_lspcon_mode expected_mode;
|
|
|
|
|
|
- lspcon_wake_native_aux_ch(lspcon);
|
|
|
+ expected_mode = lspcon_wake_native_aux_ch(lspcon) ?
|
|
|
+ DRM_LSPCON_MODE_PCON : DRM_LSPCON_MODE_LS;
|
|
|
|
|
|
/* Lets probe the adaptor and check its type */
|
|
|
adaptor_type = drm_dp_dual_mode_detect(adapter);
|
|
@@ -110,7 +150,7 @@ static bool lspcon_probe(struct intel_lspcon *lspcon)
|
|
|
|
|
|
/* Yay ... got a LSPCON device */
|
|
|
DRM_DEBUG_KMS("LSPCON detected\n");
|
|
|
- lspcon->mode = lspcon_get_current_mode(lspcon);
|
|
|
+ lspcon->mode = lspcon_wait_mode(lspcon, expected_mode);
|
|
|
lspcon->active = true;
|
|
|
return true;
|
|
|
}
|
|
@@ -150,8 +190,17 @@ static void lspcon_resume_in_pcon_wa(struct intel_lspcon *lspcon)
|
|
|
|
|
|
void lspcon_resume(struct intel_lspcon *lspcon)
|
|
|
{
|
|
|
- if (lspcon_wake_native_aux_ch(lspcon))
|
|
|
+ enum drm_lspcon_mode expected_mode;
|
|
|
+
|
|
|
+ if (lspcon_wake_native_aux_ch(lspcon)) {
|
|
|
+ expected_mode = DRM_LSPCON_MODE_PCON;
|
|
|
lspcon_resume_in_pcon_wa(lspcon);
|
|
|
+ } else {
|
|
|
+ expected_mode = DRM_LSPCON_MODE_LS;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (lspcon_wait_mode(lspcon, expected_mode) == DRM_LSPCON_MODE_PCON)
|
|
|
+ return;
|
|
|
|
|
|
if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON, true))
|
|
|
DRM_ERROR("LSPCON resume failed\n");
|
|
@@ -159,6 +208,11 @@ void lspcon_resume(struct intel_lspcon *lspcon)
|
|
|
DRM_DEBUG_KMS("LSPCON resume success\n");
|
|
|
}
|
|
|
|
|
|
+void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon)
|
|
|
+{
|
|
|
+ lspcon_wait_mode(lspcon, DRM_LSPCON_MODE_PCON);
|
|
|
+}
|
|
|
+
|
|
|
bool lspcon_init(struct intel_digital_port *intel_dig_port)
|
|
|
{
|
|
|
struct intel_dp *dp = &intel_dig_port->dp;
|