diff options
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_display_debugfs.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_display_types.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_dp.c | 171 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_dp.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_dp_link_training.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_dp_link_training.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 18 |
7 files changed, 210 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 9f736420d83f..bdeea2e02642 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -1320,6 +1320,16 @@ static int i915_displayport_test_data_show(struct seq_file *m, void *data) intel_dp->compliance.test_data.vdisplay); seq_printf(m, "bpc: %u\n", intel_dp->compliance.test_data.bpc); + } else if (intel_dp->compliance.test_type == + DP_TEST_LINK_PHY_TEST_PATTERN) { + seq_printf(m, "pattern: %d\n", + intel_dp->compliance.test_data.phytest.phy_pattern); + seq_printf(m, "Number of lanes: %d\n", + intel_dp->compliance.test_data.phytest.num_lanes); + seq_printf(m, "Link Rate: %d\n", + intel_dp->compliance.test_data.phytest.link_rate); + seq_printf(m, "level: %02x\n", + intel_dp->train_set[0]); } } else seq_puts(m, "0"); @@ -1352,7 +1362,7 @@ static int i915_displayport_test_type_show(struct seq_file *m, void *data) if (encoder && connector->status == connector_status_connected) { intel_dp = enc_to_intel_dp(encoder); - seq_printf(m, "%02lx", intel_dp->compliance.test_type); + seq_printf(m, "%02lx\n", intel_dp->compliance.test_type); } else seq_puts(m, "0"); } diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index e67474a71761..1170a1ce4b56 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1238,6 +1238,7 @@ struct intel_dp_compliance_data { u8 video_pattern; u16 hdisplay, vdisplay; u8 bpc; + struct drm_dp_phy_test_params phytest; }; struct intel_dp_compliance { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 804b1d966f66..f2ee2a0f286a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5001,9 +5001,180 @@ static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp) return test_result; } +static u8 intel_dp_prepare_phytest(struct intel_dp *intel_dp) +{ + struct drm_dp_phy_test_params *data = + &intel_dp->compliance.test_data.phytest; + + if (drm_dp_get_phy_test_pattern(&intel_dp->aux, data)) { + DRM_DEBUG_KMS("DP Phy Test pattern AUX read failure\n"); + return DP_TEST_NAK; + } + + /* + * link_mst is set to false to avoid executing mst related code + * during compliance testing. + */ + intel_dp->link_mst = false; + + return DP_TEST_ACK; +} + +static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = + to_i915(dp_to_dig_port(intel_dp)->base.base.dev); + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_dp_phy_test_params *data = + &intel_dp->compliance.test_data.phytest; + struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc); + enum pipe pipe = crtc->pipe; + u32 pattern_val; + + switch (data->phy_pattern) { + case DP_PHY_TEST_PATTERN_NONE: + DRM_DEBUG_KMS("Disable Phy Test Pattern\n"); + intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), 0x0); + break; + case DP_PHY_TEST_PATTERN_D10_2: + DRM_DEBUG_KMS("Set D10.2 Phy Test Pattern\n"); + intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), + DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_D10_2); + break; + case DP_PHY_TEST_PATTERN_ERROR_COUNT: + DRM_DEBUG_KMS("Set Error Count Phy Test Pattern\n"); + intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), + DDI_DP_COMP_CTL_ENABLE | + DDI_DP_COMP_CTL_SCRAMBLED_0); + break; + case DP_PHY_TEST_PATTERN_PRBS7: + DRM_DEBUG_KMS("Set PRBS7 Phy Test Pattern\n"); + intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), + DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_PRBS7); + break; + case DP_PHY_TEST_PATTERN_80BIT_CUSTOM: + /* + * FIXME: Ideally pattern should come from DPCD 0x250. As + * current firmware of DPR-100 could not set it, so hardcoding + * now for complaince test. + */ + DRM_DEBUG_KMS("Set 80Bit Custom Phy Test Pattern 0x3e0f83e0 0x0f83e0f8 0x0000f83e\n"); + pattern_val = 0x3e0f83e0; + intel_de_write(dev_priv, DDI_DP_COMP_PAT(pipe, 0), pattern_val); + pattern_val = 0x0f83e0f8; + intel_de_write(dev_priv, DDI_DP_COMP_PAT(pipe, 1), pattern_val); + pattern_val = 0x0000f83e; + intel_de_write(dev_priv, DDI_DP_COMP_PAT(pipe, 2), pattern_val); + intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), + DDI_DP_COMP_CTL_ENABLE | + DDI_DP_COMP_CTL_CUSTOM80); + break; + case DP_PHY_TEST_PATTERN_CP2520: + /* + * FIXME: Ideally pattern should come from DPCD 0x24A. As + * current firmware of DPR-100 could not set it, so hardcoding + * now for complaince test. + */ + DRM_DEBUG_KMS("Set HBR2 compliance Phy Test Pattern\n"); + pattern_val = 0xFB; + intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), + DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_HBR2 | + pattern_val); + break; + default: + WARN(1, "Invalid Phy Test Pattern\n"); + } +} + +static void +intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc); + enum pipe pipe = crtc->pipe; + u32 trans_ddi_func_ctl_value, trans_conf_value, dp_tp_ctl_value; + + trans_ddi_func_ctl_value = intel_de_read(dev_priv, + TRANS_DDI_FUNC_CTL(pipe)); + trans_conf_value = intel_de_read(dev_priv, PIPECONF(pipe)); + dp_tp_ctl_value = intel_de_read(dev_priv, TGL_DP_TP_CTL(pipe)); + + trans_ddi_func_ctl_value &= ~(TRANS_DDI_FUNC_ENABLE | + TGL_TRANS_DDI_PORT_MASK); + trans_conf_value &= ~PIPECONF_ENABLE; + dp_tp_ctl_value &= ~DP_TP_CTL_ENABLE; + + intel_de_write(dev_priv, PIPECONF(pipe), trans_conf_value); + intel_de_write(dev_priv, TRANS_DDI_FUNC_CTL(pipe), + trans_ddi_func_ctl_value); + intel_de_write(dev_priv, TGL_DP_TP_CTL(pipe), dp_tp_ctl_value); +} + +static void +intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp, uint8_t lane_cnt) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + enum port port = intel_dig_port->base.port; + struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc); + enum pipe pipe = crtc->pipe; + u32 trans_ddi_func_ctl_value, trans_conf_value, dp_tp_ctl_value; + + trans_ddi_func_ctl_value = intel_de_read(dev_priv, + TRANS_DDI_FUNC_CTL(pipe)); + trans_conf_value = intel_de_read(dev_priv, PIPECONF(pipe)); + dp_tp_ctl_value = intel_de_read(dev_priv, TGL_DP_TP_CTL(pipe)); + + trans_ddi_func_ctl_value |= TRANS_DDI_FUNC_ENABLE | + TGL_TRANS_DDI_SELECT_PORT(port); + trans_conf_value |= PIPECONF_ENABLE; + dp_tp_ctl_value |= DP_TP_CTL_ENABLE; + + intel_de_write(dev_priv, PIPECONF(pipe), trans_conf_value); + intel_de_write(dev_priv, TGL_DP_TP_CTL(pipe), dp_tp_ctl_value); + intel_de_write(dev_priv, TRANS_DDI_FUNC_CTL(pipe), + trans_ddi_func_ctl_value); +} + +void intel_dp_process_phy_request(struct intel_dp *intel_dp) +{ + struct drm_dp_phy_test_params *data = + &intel_dp->compliance.test_data.phytest; + u8 link_status[DP_LINK_STATUS_SIZE]; + + if (!intel_dp_get_link_status(intel_dp, link_status)) { + DRM_DEBUG_KMS("failed to get link status\n"); + return; + } + + /* retrieve vswing & pre-emphasis setting */ + intel_dp_get_adjust_train(intel_dp, link_status); + + intel_dp_autotest_phy_ddi_disable(intel_dp); + + intel_dp_set_signal_levels(intel_dp); + + intel_dp_phy_pattern_update(intel_dp); + + intel_dp_autotest_phy_ddi_enable(intel_dp, data->num_lanes); + + drm_dp_set_phy_test_pattern(&intel_dp->aux, data, + link_status[DP_DPCD_REV]); +} + static u8 intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp) { u8 test_result = DP_TEST_NAK; + + test_result = intel_dp_prepare_phytest(intel_dp); + if (test_result != DP_TEST_ACK) + DRM_ERROR("Phy test preparation failed\n"); + + intel_dp_process_phy_request(intel_dp); + return test_result; } diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 0c7be8ed1423..0d22a230b32d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -115,6 +115,7 @@ void intel_dp_hdr_metadata_enable(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); bool intel_digital_port_connected(struct intel_encoder *encoder); +void intel_dp_process_phy_request(struct intel_dp *intel_dp); static inline unsigned int intel_dp_unused_lane_mask(int lane_count) { diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index a7defb37ab00..e4f1843170b7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -34,9 +34,8 @@ intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE]) link_status[3], link_status[4], link_status[5]); } -static void -intel_get_adjust_train(struct intel_dp *intel_dp, - const u8 link_status[DP_LINK_STATUS_SIZE]) +void intel_dp_get_adjust_train(struct intel_dp *intel_dp, + const u8 link_status[DP_LINK_STATUS_SIZE]) { u8 v = 0; u8 p = 0; @@ -219,7 +218,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; /* Update training set as requested by target */ - intel_get_adjust_train(intel_dp, link_status); + intel_dp_get_adjust_train(intel_dp, link_status); if (!intel_dp_update_link_train(intel_dp)) { drm_err(&i915->drm, "failed to update link training\n"); @@ -338,7 +337,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp) } /* Update training set as requested by target */ - intel_get_adjust_train(intel_dp, link_status); + intel_dp_get_adjust_train(intel_dp, link_status); if (!intel_dp_update_link_train(intel_dp)) { drm_err(&i915->drm, "failed to update link training\n"); diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h index 174566adcc92..01f1dabbb060 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h @@ -6,8 +6,12 @@ #ifndef __INTEL_DP_LINK_TRAINING_H__ #define __INTEL_DP_LINK_TRAINING_H__ +#include <drm/drm_dp_helper.h> + struct intel_dp; +void intel_dp_get_adjust_train(struct intel_dp *intel_dp, + const u8 link_status[DP_LINK_STATUS_SIZE]); void intel_dp_start_link_train(struct intel_dp *intel_dp); void intel_dp_stop_link_train(struct intel_dp *intel_dp); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 59e64acc2c56..490e9f4a287a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -9794,6 +9794,24 @@ enum skl_power_gate { #define DDI_BUF_BALANCE_LEG_ENABLE (1 << 31) #define DDI_BUF_TRANS_HI(port, i) _MMIO(_PORT(port, _DDI_BUF_TRANS_A, _DDI_BUF_TRANS_B) + (i) * 8 + 4) +/* DDI DP Compliance Control */ +#define _DDI_DP_COMP_CTL_A 0x605F0 +#define _DDI_DP_COMP_CTL_B 0x615F0 +#define DDI_DP_COMP_CTL(pipe) _MMIO_PIPE(pipe, _DDI_DP_COMP_CTL_A, _DDI_DP_COMP_CTL_B) +#define DDI_DP_COMP_CTL_ENABLE (1 << 31) +#define DDI_DP_COMP_CTL_D10_2 (0 << 28) +#define DDI_DP_COMP_CTL_SCRAMBLED_0 (1 << 28) +#define DDI_DP_COMP_CTL_PRBS7 (2 << 28) +#define DDI_DP_COMP_CTL_CUSTOM80 (3 << 28) +#define DDI_DP_COMP_CTL_HBR2 (4 << 28) +#define DDI_DP_COMP_CTL_SCRAMBLED_1 (5 << 28) +#define DDI_DP_COMP_CTL_HBR2_RESET (0xFC << 0) + +/* DDI DP Compliance Pattern */ +#define _DDI_DP_COMP_PAT_A 0x605F4 +#define _DDI_DP_COMP_PAT_B 0x615F4 +#define DDI_DP_COMP_PAT(pipe, i) _MMIO(_PIPE(pipe, _DDI_DP_COMP_PAT_A, _DDI_DP_COMP_PAT_B) + (i) * 4) + /* Sideband Interface (SBI) is programmed indirectly, via * SBI_ADDR, which contains the register offset; and SBI_DATA, * which contains the payload */ |