summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Collyer <scollyer@google.com>2021-02-12 01:01:54 -0800
committerCommit Bot <commit-bot@chromium.org>2021-04-01 17:59:35 +0000
commitf75da1ae8c5b622c7b85e484362116aa729f8505 (patch)
tree0466f0491202a064a5d6b7c331be5053f12a2752
parent6c9e2e410a3dddf65b4616d549ecb8abc25ddd6c (diff)
downloadchrome-ec-f75da1ae8c5b622c7b85e484362116aa729f8505.tar.gz
TCPMv2: DPM: Add support for sending SVDM Attention message
This CL adds a new DPM function to generate a request to the PE to send a SVDM Attention message via the DPM. This change deprecates pd_send_hpd from TCPMv2, which existed for the same purpose. pd_send_hpd is now part of the hpd->DP Attention converter. This path replaces the need to use pd_send_vdm which can't be reliably used with its current design. BUG=b:175660576,b:180465870 BRANCH=None TEST=Verified on quiche that can enter ALT-DP mode as a UFP-D and that display is extended properly via display port or hdmi connector. Signed-off-by: Scott Collyer <scollyer@google.com> Change-Id: I9f8817cb8d40f32b878abdc09db605097a32548b Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2691969 Tested-by: Keith Short <keithshort@chromium.org> Tested-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Diana Z <dzigterman@chromium.org> Commit-Queue: Scott Collyer <scollyer@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2799916 Tested-by: Abe Levkoy <alevkoy@chromium.org> Reviewed-by: Abe Levkoy <alevkoy@chromium.org> Commit-Queue: Abe Levkoy <alevkoy@chromium.org>
-rw-r--r--common/usbc/usb_pd_dp_ufp.c43
-rw-r--r--common/usbc/usb_pd_dpm.c82
-rw-r--r--common/usbc/usb_tc_drp_acc_trysrc_sm.c22
-rw-r--r--include/usb_pd.h31
4 files changed, 151 insertions, 27 deletions
diff --git a/common/usbc/usb_pd_dp_ufp.c b/common/usbc/usb_pd_dp_ufp.c
index e9da5b55e0..2c651052e5 100644
--- a/common/usbc/usb_pd_dp_ufp.c
+++ b/common/usbc/usb_pd_dp_ufp.c
@@ -59,13 +59,54 @@ struct hpd_info {
static struct hpd_info hpd;
static struct mutex hpd_mutex;
+static int alt_dp_mode_opos[CONFIG_USB_PD_PORT_MAX_COUNT];
+
+void pd_ufp_set_dp_opos(int port, int opos)
+{
+ alt_dp_mode_opos[port] = opos;
+}
+
+int pd_ufp_get_dp_opos(int port)
+{
+ return alt_dp_mode_opos[port];
+}
static void hpd_to_dp_attention(void)
{
+ int port = hpd_config.port;
int evt_index = hpd.count - 1;
+ uint32_t vdm[2];
+ uint32_t svdm_header;
+ enum hpd_event evt;
+ int opos = pd_ufp_get_dp_opos(port);
+
+ if (!opos)
+ return;
+ /* Get the next hpd event from the queue */
+ evt = hpd.queue[evt_index];
+ /* Save timestamp of when most recent DP attention message was sent */
hpd.last_send_ts = get_time().val;
- pd_send_hpd(hpd_config.port, hpd.queue[evt_index]);
+
+ /*
+ * Construct DP Attention message. This consists of the VDM header and
+ * the DP_STATUS VDO.
+ */
+ svdm_header = VDO_SVDM_VERS(pd_get_vdo_ver(port, TCPC_TX_SOP)) |
+ VDO_OPOS(opos) | CMD_ATTENTION;
+ vdm[0] = VDO(USB_SID_DISPLAYPORT, 1, svdm_header);
+
+ vdm[1] = VDO_DP_STATUS((evt == hpd_irq), /* IRQ_HPD */
+ (evt != hpd_low), /* HPD_HI|LOW */
+ 0, /* request exit DP */
+ 0, /* request exit USB */
+ 0, /* MF pref */
+ 1, /* enabled */
+ 0, /* power low */
+ 0x2);
+
+ /* Send request to DPM to send an attention VDM */
+ pd_request_vdm_attention(port, vdm, ARRAY_SIZE(vdm));
/* If there are still events, need to shift the buffer */
if (--hpd.count) {
diff --git a/common/usbc/usb_pd_dpm.c b/common/usbc/usb_pd_dpm.c
index 1c579d7630..9aefa97649 100644
--- a/common/usbc/usb_pd_dpm.c
+++ b/common/usbc/usb_pd_dpm.c
@@ -30,8 +30,14 @@
#define CPRINTS(format, args...)
#endif
+/* Max Attention length is header + 1 VDO */
+#define DPM_ATTENION_MAX_VDO 2
+
static struct {
uint32_t flags;
+ uint32_t vdm_attention[DPM_ATTENION_MAX_VDO];
+ int vdm_cnt;
+ mutex_t vdm_attention_mutex;
} dpm[CONFIG_USB_PD_PORT_MAX_COUNT];
#define DPM_SET_FLAG(port, flag) atomic_or(&dpm[(port)].flags, (flag))
@@ -44,6 +50,55 @@ static struct {
#define DPM_FLAG_ENTER_DP BIT(2)
#define DPM_FLAG_ENTER_TBT BIT(3)
#define DPM_FLAG_ENTER_USB4 BIT(4)
+#define DPM_FLAG_SEND_ATTENTION BIT(5)
+
+#ifdef CONFIG_ZEPHYR
+static int init_vdm_attention_mutex(const struct device *dev)
+{
+ int port;
+
+ ARG_UNUSED(dev);
+
+ for (port = 0; port < CONFIG_USB_PD_PORT_MAX_COUNT; port++)
+ k_mutex_init(&dpm[port].vdm_attention_mutex);
+
+ return 0;
+}
+SYS_INIT(init_vdm_attention_mutex, POST_KERNEL, 50);
+#endif /* CONFIG_ZEPHYR */
+
+enum ec_status pd_request_vdm_attention(int port, const uint32_t *data,
+ int vdo_count)
+{
+ mutex_lock(&dpm[port].vdm_attention_mutex);
+
+ /* Only one Attention message may be pending */
+ if (DPM_CHK_FLAG(port, DPM_FLAG_SEND_ATTENTION)) {
+ mutex_unlock(&dpm[port].vdm_attention_mutex);
+ return EC_RES_UNAVAILABLE;
+ }
+
+ /* SVDM Attention message must be 1 or 2 VDOs in length */
+ if (!vdo_count || (vdo_count > DPM_ATTENION_MAX_VDO)) {
+ mutex_unlock(&dpm[port].vdm_attention_mutex);
+ return EC_RES_INVALID_PARAM;
+ }
+
+ /* Save contents of Attention message */
+ memcpy(dpm[port].vdm_attention, data, vdo_count * sizeof(uint32_t));
+ dpm[port].vdm_cnt = vdo_count;
+
+ /*
+ * Indicate to DPM that an Attention message needs to be sent. This flag
+ * will be cleared when the Attention message is sent to the policy
+ * engine.
+ */
+ DPM_SET_FLAG(port, DPM_FLAG_SEND_ATTENTION);
+
+ mutex_unlock(&dpm[port].vdm_attention_mutex);
+
+ return EC_RES_SUCCESS;
+}
enum ec_status pd_request_enter_mode(int port, enum typec_mode mode)
{
@@ -333,12 +388,31 @@ static void dpm_attempt_mode_exit(int port)
pd_dpm_request(port, DPM_REQUEST_VDM);
}
+static void dpm_send_attention_vdm(int port)
+{
+ /* Set up VDM ATTEN msg that was passed in previously */
+ if (pd_setup_vdm_request(port, TCPC_TX_SOP, dpm[port].vdm_attention,
+ dpm[port].vdm_cnt) == true)
+ /* Trigger PE to start a VDM command run */
+ pd_dpm_request(port, DPM_REQUEST_VDM);
+
+ /* Clear flag after message is sent to PE layer */
+ DPM_CLR_FLAG(port, DPM_FLAG_SEND_ATTENTION);
+}
+
void dpm_run(int port)
{
- if (DPM_CHK_FLAG(port, DPM_FLAG_EXIT_REQUEST))
- dpm_attempt_mode_exit(port);
- else if (!DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE))
- dpm_attempt_mode_entry(port);
+ if (pd_get_data_role(port) == PD_ROLE_DFP) {
+ /* Run DFP related DPM requests */
+ if (DPM_CHK_FLAG(port, DPM_FLAG_EXIT_REQUEST))
+ dpm_attempt_mode_exit(port);
+ else if (!DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE))
+ dpm_attempt_mode_entry(port);
+ } else {
+ /* Run UFP related DPM requests */
+ if (DPM_CHK_FLAG(port, DPM_FLAG_SEND_ATTENTION))
+ dpm_send_attention_vdm(port);
+ }
}
/*
diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
index 269ded1159..fad4c0cb5d 100644
--- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c
+++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
@@ -1860,28 +1860,6 @@ __maybe_unused static void handle_new_power_state(int port)
}
}
-#if defined(CONFIG_USB_PD_ALT_MODE) && !defined(CONFIG_USB_PD_ALT_MODE_DFP)
-void pd_send_hpd(int port, enum hpd_event hpd)
-{
- uint32_t data[1];
- int opos = pd_alt_mode(port, TCPC_TX_SOP, USB_SID_DISPLAYPORT);
-
- if (!opos)
- return;
-
- data[0] = VDO_DP_STATUS((hpd == hpd_irq), /* IRQ_HPD */
- (hpd != hpd_low), /* HPD_HI|LOW */
- 0, /* request exit DP */
- 0, /* request exit USB */
- 0, /* MF pref */
- 1, /* enabled */
- 0, /* power low */
- 0x2);
- pd_send_vdm(port, USB_SID_DISPLAYPORT, VDO_OPOS(opos) | CMD_ATTENTION,
- data, 1);
-}
-#endif
-
#ifdef CONFIG_USBC_VCONN_SWAP
void pd_request_vconn_swap_off(int port)
{
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 7e4b2fadef..1f91af14c7 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -2163,6 +2163,23 @@ struct partner_active_modes *pd_get_partner_active_modes(int port,
enum tcpm_transmit_type type);
/*
+ * Sets the current object position for DP alt-mode
+ * Note: opos == 0 means the mode is not active
+ *
+ * @param port USB-C port number
+ * @param opos Object position for DP alternate mode
+ */
+void pd_ufp_set_dp_opos(int port, int opos);
+
+/*
+ * Gets the current object position for DP alt-mode
+ *
+ * @param port USB-C port number
+ * @return Alt-DP object position value for the given port
+ */
+int pd_ufp_get_dp_opos(int port);
+
+/*
* Returns True if cable supports USB2 connection
*
* @param port USB-C port number
@@ -2783,6 +2800,20 @@ void pd_notify_event(int port, uint32_t event_mask);
void pd_clear_events(int port, uint32_t clear_mask);
/*
+ * Requests a VDM Attention message be sent. Attention is the only SVDM message
+ * that does not result in a response from the port partner. In addition, if
+ * it's a DP Attention message, then it will be requested from outside of the
+ * port's PD task.
+ *
+ * @param port USB-C port number
+ * @param *data pointer to the VDM Attention message
+ * @param vdo_count number of VDOs (must be 1 or 2)
+ * @return EC_RES_SUCCESS if a VDM message is scheduled.
+ */
+enum ec_status pd_request_vdm_attention(int port, const uint32_t *data,
+ int vdo_count);
+
+/*
* Requests that the port enter the specified mode. A successful result just
* means that the request was received, not that the mode has been entered yet.
*