From: Wenjing Liu <wenjing....@amd.com>

[how]
Call to DMUB to retrieve usb c cable ID data from PD firmware.
If cable id is retrieved from DMUB, skip reading cable ID from RX.

Reviewed-by: George Shen <george.s...@amd.com>
Acked-by: Solomon Chiu <solomon.c...@amd.com>
Signed-off-by: Wenjing Liu <wenjing....@amd.com>
---
 drivers/gpu/drm/amd/display/dc/core/dc_link.c |   4 +-
 .../gpu/drm/amd/display/dc/core/dc_link_dp.c  | 100 ++++++++++++------
 drivers/gpu/drm/amd/display/dc/dc.h           |   2 +-
 drivers/gpu/drm/amd/display/dc/dc_dp_types.h  |   2 +-
 drivers/gpu/drm/amd/display/dc/dc_link.h      |   8 +-
 .../gpu/drm/amd/display/dc/inc/dc_link_dp.h   |   2 +-
 .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h   |  40 +++++++
 7 files changed, 117 insertions(+), 41 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c 
b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index 1d6b6ed3f24c..34ca1ffcf4d1 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -1305,7 +1305,7 @@ static bool detect_link_and_local_sink(struct dc_link 
*link,
                 */
                link->dongle_max_pix_clk = 0;
 
-               dc_link_dp_clear_rx_status(link);
+               dc_link_clear_dprx_states(link);
        }
 
        LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p edid 
same=%d\n",
@@ -1986,7 +1986,7 @@ static enum dc_status enable_link_dp(struct dc_state 
*state,
                msleep(post_oui_delay);
 
        // similarly, mode switch can cause loss of cable ID
-       dpcd_update_cable_id(link);
+       dpcd_write_cable_id_to_dprx(link);
 
        skip_video_pattern = true;
 
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c 
b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
index bc6161f52bfa..bfd0e48d67a5 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
@@ -51,6 +51,13 @@ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA";
 
 #include "link_dpcd.h"
 
+#ifndef MAX
+#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+#endif
+#ifndef MIN
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#endif
+
        /* maximum pre emphasis level allowed for each voltage swing level*/
        static const enum dc_pre_emphasis
        voltage_swing_to_pre_emphasis[] = { PRE_EMPHASIS_LEVEL3,
@@ -2986,11 +2993,11 @@ static enum dc_link_rate get_cable_max_link_rate(struct 
dc_link *link)
 {
        enum dc_link_rate cable_max_link_rate = LINK_RATE_HIGH3;
 
-       if (link->dpcd_caps.cable_attributes.bits.UHBR10_20_CAPABILITY & 
DP_UHBR20)
+       if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR20)
                cable_max_link_rate = LINK_RATE_UHBR20;
-       else if (link->dpcd_caps.cable_attributes.bits.UHBR13_5_CAPABILITY)
+       else if (link->dpcd_caps.cable_id.bits.UHBR13_5_CAPABILITY)
                cable_max_link_rate = LINK_RATE_UHBR13_5;
-       else if (link->dpcd_caps.cable_attributes.bits.UHBR10_20_CAPABILITY & 
DP_UHBR10)
+       else if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR10)
                cable_max_link_rate = LINK_RATE_UHBR10;
 
        return cable_max_link_rate;
@@ -5051,11 +5058,52 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
        return is_lttpr_present;
 }
 
+static bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id 
*cable_id)
+{
+       union dmub_rb_cmd cmd;
+
+       if (!link->ctx->dmub_srv ||
+                       link->ep_type != DISPLAY_ENDPOINT_PHY ||
+                       link->link_enc->features.flags.bits.DP_IS_USB_C == 0)
+               return false;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cable_id.header.type = DMUB_CMD_GET_USBC_CABLE_ID;
+       cmd.cable_id.header.payload_bytes = sizeof(cmd.cable_id.data);
+       cmd.cable_id.data.input.phy_inst = resource_transmitter_to_phy_idx(
+                       link->dc, link->link_enc->transmitter);
+       if (dc_dmub_srv_cmd_with_reply_data(link->ctx->dmub_srv, &cmd) &&
+                       cmd.cable_id.header.ret_status == 1)
+               cable_id->raw = cmd.cable_id.data.output_raw;
 
-static bool is_usbc_connector(struct dc_link *link)
+       return cmd.cable_id.header.ret_status == 1;
+}
+
+static union dp_cable_id intersect_cable_id(
+               union dp_cable_id *a, union dp_cable_id *b)
 {
-       return link->link_enc &&
-                       link->link_enc->features.flags.bits.DP_IS_USB_C;
+       union dp_cable_id out;
+
+       out.bits.UHBR10_20_CAPABILITY = MIN(a->bits.UHBR10_20_CAPABILITY,
+                       b->bits.UHBR10_20_CAPABILITY);
+       out.bits.UHBR13_5_CAPABILITY = MIN(a->bits.UHBR13_5_CAPABILITY,
+                       b->bits.UHBR13_5_CAPABILITY);
+       out.bits.CABLE_TYPE = MAX(a->bits.CABLE_TYPE, b->bits.CABLE_TYPE);
+
+       return out;
+}
+
+static void retrieve_cable_id(struct dc_link *link)
+{
+       union dp_cable_id usbc_cable_id;
+
+       link->dpcd_caps.cable_id.raw = 0;
+       core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX,
+                       &link->dpcd_caps.cable_id.raw, sizeof(uint8_t));
+
+       if (get_usbc_cable_id(link, &usbc_cable_id))
+               link->dpcd_caps.cable_id = intersect_cable_id(
+                               &link->dpcd_caps.cable_id, &usbc_cable_id);
 }
 
 static bool retrieve_link_cap(struct dc_link *link)
@@ -5114,9 +5162,6 @@ static bool retrieve_link_cap(struct dc_link *link)
         */
        msleep(post_oui_delay);
 
-       /* Read cable ID and update receiver */
-       dpcd_update_cable_id(link);
-
        for (i = 0; i < read_dpcd_retry_cnt; i++) {
                status = core_link_read_dpcd(
                                link,
@@ -5236,7 +5281,8 @@ static bool retrieve_link_cap(struct dc_link *link)
                edp_config_cap.bits.ALT_SCRAMBLER_RESET;
        link->dpcd_caps.dpcd_display_control_capable =
                edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
-
+       link->dpcd_caps.channel_coding_cap.raw =
+                       dpcd_data[DP_MAIN_LINK_CHANNEL_CODING - DP_DPCD_REV];
        link->test_pattern_enabled = false;
        link->compliance_test_state.raw = 0;
 
@@ -5363,8 +5409,6 @@ static bool retrieve_link_cap(struct dc_link *link)
        if (!dpcd_read_sink_ext_caps(link))
                link->dpcd_sink_ext_caps.raw = 0;
 
-       link->dpcd_caps.channel_coding_cap.raw = 
dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_CAP - DP_DPCD_REV];
-
        if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
                DC_LOG_DP2("128b/132b encoding is supported at link %d", 
link->link_index);
 
@@ -5410,6 +5454,9 @@ static bool retrieve_link_cap(struct dc_link *link)
                        DC_LOG_DP2("\tFEC aggregated error counters are 
supported");
        }
 
+       retrieve_cable_id(link);
+       dpcd_write_cable_id_to_dprx(link);
+
        /* Connectivity log: detection */
        CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
 
@@ -6342,29 +6389,18 @@ void dpcd_set_source_specific_data(struct dc_link *link)
        }
 }
 
-void dpcd_update_cable_id(struct dc_link *link)
+void dpcd_write_cable_id_to_dprx(struct dc_link *link)
 {
-       struct link_encoder *link_enc = NULL;
-
-       link_enc = link_enc_cfg_get_link_enc(link);
-
-       if (!link_enc ||
-                       !link_enc->features.flags.bits.IS_UHBR10_CAPABLE ||
-                       link->dprx_status.cable_id_updated)
+       if (!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED ||
+                       link->dpcd_caps.cable_id.raw == 0 ||
+                       link->dprx_states.cable_id_written)
                return;
 
-       /* Retrieve cable attributes */
-       if (!is_usbc_connector(link))
-               core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX,
-                               &link->dpcd_caps.cable_attributes.raw,
-                               sizeof(uint8_t));
-
-       /* Update receiver with cable attributes */
        core_link_write_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX,
-                       &link->dpcd_caps.cable_attributes.raw,
-                       sizeof(link->dpcd_caps.cable_attributes.raw));
+                       &link->dpcd_caps.cable_id.raw,
+                       sizeof(link->dpcd_caps.cable_id.raw));
 
-       link->dprx_status.cable_id_updated = 1;
+       link->dprx_states.cable_id_written = 1;
 }
 
 bool dc_link_set_backlight_level_nits(struct dc_link *link,
@@ -6765,9 +6801,9 @@ void edp_panel_backlight_power_on(struct dc_link *link)
                link->dc->hwss.edp_backlight_control(link, true);
 }
 
-void dc_link_dp_clear_rx_status(struct dc_link *link)
+void dc_link_clear_dprx_states(struct dc_link *link)
 {
-       memset(&link->dprx_status, 0, sizeof(link->dprx_status));
+       memset(&link->dprx_states, 0, sizeof(link->dprx_states));
 }
 
 void dp_receiver_power_ctrl(struct dc_link *link, bool on)
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h 
b/drivers/gpu/drm/amd/display/dc/dc.h
index 6176904e22fc..9fa87a426f9c 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -1236,7 +1236,7 @@ struct dpcd_caps {
        union dp_main_line_channel_coding_cap channel_coding_cap;
        union dp_sink_video_fallback_formats fallback_formats;
        union dp_fec_capability1 fec_cap1;
-       union dp_cable_attributes cable_attributes;
+       union dp_cable_id cable_id;
        uint8_t edp_rev;
        union edp_alpm_caps alpm_caps;
        struct edp_psr_info psr_info;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h 
b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
index 5f848a2fa21d..a66460858783 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
@@ -1017,7 +1017,7 @@ union dp_fec_capability1 {
        uint8_t raw;
 };
 
-union dp_cable_attributes {
+union dp_cable_id {
        struct {
                uint8_t UHBR10_20_CAPABILITY    :2;
                uint8_t UHBR13_5_CAPABILITY     :1;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h 
b/drivers/gpu/drm/amd/display/dc/dc_link.h
index 9ad3ee4079c3..ce6e8d013459 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_link.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
@@ -43,8 +43,8 @@ struct dc_link_status {
        struct dpcd_caps *dpcd_caps;
 };
 
-struct dp_receiver_status {
-       bool cable_id_updated;
+struct dprx_states {
+       bool cable_id_written;
 };
 
 /* DP MST stream allocation (payload bandwidth number) */
@@ -205,7 +205,7 @@ struct dc_link {
        struct link_mst_stream_allocation_table mst_stream_alloc_table;
 
        struct dc_link_status link_status;
-       struct dp_receiver_status dprx_status;
+       struct dprx_states dprx_states;
 
        struct link_trace link_trace;
        struct gpio *hpd_gpio;
@@ -466,7 +466,7 @@ void dc_link_get_cur_link_res(const struct dc_link *link,
 void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map);
 /* restore link resource allocation state from a snapshot */
 void dc_restore_link_res_map(const struct dc *dc, uint32_t *map);
-void dc_link_dp_clear_rx_status(struct dc_link *link);
+void dc_link_clear_dprx_states(struct dc_link *link);
 struct gpio *get_hpd_gpio(struct dc_bios *dcb,
                struct graphics_object_id link_id,
                struct gpio_service *gpio_service);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h 
b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
index 477c4d9a972f..ab9939db8cea 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
@@ -106,7 +106,7 @@ bool dp_overwrite_extended_receiver_cap(struct dc_link 
*link);
 
 void dpcd_set_source_specific_data(struct dc_link *link);
 
-void dpcd_update_cable_id(struct dc_link *link);
+void dpcd_write_cable_id_to_dprx(struct dc_link *link);
 
 /* Write DPCD link configuration data. */
 enum dc_status dpcd_set_link_settings(
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h 
b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index b01cb5493b76..bc889492f9d7 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -668,6 +668,10 @@ enum dmub_cmd_type {
         * Command type used for EDID CEA parsing
         */
        DMUB_CMD__EDID_CEA = 79,
+       /**
+        * Command type used for getting usbc cable ID
+        */
+       DMUB_CMD_GET_USBC_CABLE_ID = 81,
        /**
         * Command type used for all VBIOS interface commands.
         */
@@ -2484,6 +2488,38 @@ struct dmub_rb_cmd_edid_cea {
 
 };
 
+/**
+ * struct dmub_cmd_cable_id_input - Defines the input of 
DMUB_CMD_GET_USBC_CABLE_ID command.
+ */
+struct dmub_cmd_cable_id_input {
+       uint8_t phy_inst;  /**< phy inst for cable id data */
+};
+
+/**
+ * struct dmub_cmd_cable_id_input - Defines the output of 
DMUB_CMD_GET_USBC_CABLE_ID command.
+ */
+struct dmub_cmd_cable_id_output {
+       uint8_t UHBR10_20_CAPABILITY    :2; /**< b'01 for UHBR10 support, b'10 
for both UHBR10 and UHBR20 support */
+       uint8_t UHBR13_5_CAPABILITY     :1; /**< b'1 for UHBR13.5 support */
+       uint8_t CABLE_TYPE              :3; /**< b'01 for passive cable, b'10 
for active LRD cable, b'11 for active retimer cable */
+       uint8_t RESERVED                :2; /**< reserved means not defined */
+};
+
+/**
+ * Definition of a DMUB_CMD_GET_USBC_CABLE_ID command
+ */
+struct dmub_rb_cmd_get_usbc_cable_id {
+       struct dmub_cmd_header header; /**< Command header */
+       /**
+        * Data passed from driver to FW in a DMUB_CMD_GET_USBC_CABLE_ID 
command.
+        */
+       union dmub_cmd_cable_id_data {
+               struct dmub_cmd_cable_id_input input; /**< Input */
+               struct dmub_cmd_cable_id_output output; /**< Output */
+               uint8_t output_raw; /**< Raw data output */
+       } data;
+};
+
 /**
  * union dmub_rb_cmd - DMUB inbox command.
  */
@@ -2649,6 +2685,10 @@ union dmub_rb_cmd {
         * Definition of a DMUB_CMD__EDID_CEA command.
         */
        struct dmub_rb_cmd_edid_cea edid_cea;
+       /**
+        * Definition of a DMUB_CMD_GET_USBC_CABLE_ID command.
+        */
+       struct dmub_rb_cmd_get_usbc_cable_id cable_id;
 };
 
 /**
-- 
2.25.1

Reply via email to