diff options
author | Abe Levkoy <alevkoy@chromium.org> | 2020-04-28 23:45:06 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-05-12 01:03:07 +0000 |
commit | ce9f19e3a7f11762773ccad77acbe90703f3b836 (patch) | |
tree | e55527b0df4cdbe05247df2283e5402f5f7419ed /common/usb_pd_alt_mode_dfp.c | |
parent | 1d22c1c5ecd6050f3747ea59464331f6d78ae832 (diff) | |
download | chrome-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.c | 91 |
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) { |