summaryrefslogtreecommitdiff
path: root/common/usb_pd_alt_mode_dfp.c
diff options
context:
space:
mode:
authorAbe Levkoy <alevkoy@chromium.org>2020-04-28 23:45:06 -0600
committerCommit Bot <commit-bot@chromium.org>2020-05-12 01:03:07 +0000
commitce9f19e3a7f11762773ccad77acbe90703f3b836 (patch)
treee55527b0df4cdbe05247df2283e5402f5f7419ed /common/usb_pd_alt_mode_dfp.c
parent1d22c1c5ecd6050f3747ea59464331f6d78ae832 (diff)
downloadchrome-ec-ce9f19e3a7f11762773ccad77acbe90703f3b836.tar.gz
TCPMv2: Implement mode discovery for port partner
Implement PE_INIT_VDM_Modes_{Request,ACKed,NAKed}. Store mode discovery state for each discovered SVID and provide accessors for that state. Consider transmit type when consuming modes. BUG=b:152420269,b:152419795 TEST=Attach port partner; TCPM discovers modes for previously discovered TEST=SVIDs and then continues with discovery/mode-entering process. BRANCH=none Change-Id: I72a605fa500e7eea0a5fa3b65a74d8b567a78751 Signed-off-by: Abe Levkoy <alevkoy@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2174466 Reviewed-by: Diana Z <dzigterman@chromium.org>
Diffstat (limited to 'common/usb_pd_alt_mode_dfp.c')
-rw-r--r--common/usb_pd_alt_mode_dfp.c91
1 files changed, 85 insertions, 6 deletions
diff --git a/common/usb_pd_alt_mode_dfp.c b/common/usb_pd_alt_mode_dfp.c
index d0d337e0ab..1c04c51591 100644
--- a/common/usb_pd_alt_mode_dfp.c
+++ b/common/usb_pd_alt_mode_dfp.c
@@ -366,19 +366,48 @@ void dfp_consume_svids(int port, enum tcpm_transmit_type type, int cnt,
void dfp_consume_modes(int port, enum tcpm_transmit_type type, int cnt,
uint32_t *payload)
{
+ int svid_idx;
+ struct svid_mode_data *mode_discovery = NULL;
struct pd_discovery *disc = pd_get_am_discovery(port, type);
- int idx = disc->svid_idx;
+ uint16_t response_svid = (uint16_t) PD_VDO_VID(payload[0]);
- disc->svids[idx].mode_cnt = cnt - 1;
+ for (svid_idx = 0; svid_idx < disc->svid_cnt; ++svid_idx) {
+ uint16_t svid = disc->svids[svid_idx].svid;
- if (disc->svids[idx].mode_cnt < 0) {
+ if (svid == response_svid) {
+ mode_discovery = &disc->svids[svid_idx];
+ break;
+ }
+ }
+ if (!mode_discovery) {
+ const struct svid_mode_data *requested_mode_data =
+ pd_get_next_mode(port, type);
+ CPRINTF("C%d: Mode response for undiscovered SVID %x, but TCPM "
+ "requested SVID %x\n",
+ port, response_svid, requested_mode_data->svid);
+ /*
+ * Although SVIDs discovery seemed like it succeeded before, the
+ * partner is now responding with undiscovered SVIDs. Discovery
+ * cannot reasonably continue under these circumstances.
+ */
+ pd_set_modes_discovery(port, type, requested_mode_data->svid,
+ PD_DISC_FAIL);
+ return;
+ }
+
+ mode_discovery->mode_cnt = cnt - 1;
+ if (mode_discovery->mode_cnt < 1) {
CPRINTF("ERR:NOMODE\n");
- } else {
- memcpy(disc->svids[idx].mode_vdo, &payload[1],
- sizeof(uint32_t) * disc->svids[idx].mode_cnt);
+ pd_set_modes_discovery(port, type, mode_discovery->svid,
+ PD_DISC_FAIL);
+ return;
}
+ memcpy(mode_discovery->mode_vdo, &payload[1],
+ sizeof(uint32_t) * mode_discovery->mode_cnt);
disc->svid_idx++;
+ pd_set_modes_discovery(port, type, mode_discovery->svid,
+ PD_DISC_COMPLETE);
}
/*
@@ -485,6 +514,56 @@ uint16_t pd_get_svid(int port, uint16_t svid_idx, enum tcpm_transmit_type type)
return disc->svids[svid_idx].svid;
}
+void pd_set_modes_discovery(int port, enum tcpm_transmit_type type,
+ uint16_t svid, enum pd_discovery_state disc)
+{
+ struct pd_discovery *pd = pd_get_am_discovery(port, type);
+ int svid_idx;
+
+ for (svid_idx = 0; svid_idx < pd->svid_cnt; ++svid_idx) {
+ struct svid_mode_data *mode_data = &pd->svids[svid_idx];
+
+ if (mode_data->svid != svid)
+ continue;
+
+ mode_data->discovery = disc;
+ return;
+ }
+}
+
+enum pd_discovery_state pd_get_modes_discovery(int port,
+ enum tcpm_transmit_type type)
+{
+ const struct svid_mode_data *mode_data = pd_get_next_mode(port, type);
+
+ /*
+ * If there are no SVIDs for which to discover modes, mode discovery is
+ * trivially complete.
+ */
+ if (!mode_data)
+ return PD_DISC_COMPLETE;
+
+ return mode_data->discovery;
+}
+
+struct svid_mode_data *pd_get_next_mode(int port,
+ enum tcpm_transmit_type type)
+{
+ struct pd_discovery *disc = pd_get_am_discovery(port, type);
+ int svid_idx;
+
+ for (svid_idx = 0; svid_idx < disc->svid_cnt; ++svid_idx) {
+ struct svid_mode_data *mode_data = &disc->svids[svid_idx];
+
+ if (mode_data->discovery == PD_DISC_COMPLETE)
+ continue;
+
+ return mode_data;
+ }
+
+ return NULL;
+}
+
uint32_t *pd_get_mode_vdo(int port, uint16_t svid_idx,
enum tcpm_transmit_type type)
{