#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,
{
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;
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)
*/
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,
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;
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);
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: ");
}
}
-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,
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)
* 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.
*/
};
+/**
+ * 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.
*/
* 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;
};
/**