From c50cc550bfa0dd274edbe30cbe69acf6e4ea3de9 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Tue, 28 May 2024 15:03:21 +0800 Subject: [PATCH] usb: typec: tcpm: handle nak for discover modes command When a NAK is received in one Discover Modes, the Initiator should skip consuming modes and continue to request Discover Modes for the rest of SVIDs or register altmodes that have been consumed in previous ACK. This fixes a few USB-C Docking Stations failed to register DP alternate mode since they respond a ACK in the DP SID Discover Modes first and a NAK in the second VID Discover Modes. Signed-off-by: Frank Wang Change-Id: I52d3fae2731fbe88445f47be3ffee20751309ea4 --- drivers/usb/typec/tcpm/tcpm.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 3d6d775e5363..f246d1929cab 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -1777,7 +1777,27 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, } fallthrough; case CMD_DISCOVER_SVID: + break; case CMD_DISCOVER_MODES: + /* + * 6.4.4.3.3 + * A Responder that does not support any Modes Shall return a NAK. + * + * When Initiator meets this case, it should skip + * consuming modes and continue to request Discover + * Modes for the rest of SVIDs or register altmodes + * that have been consumed in previous ACK. + */ + modep->svid_index++; + if (modep->svid_index < modep->nsvids) { + u16 svid = modep->svids[modep->svid_index]; + + response[0] = VDO(svid, 1, svdm_version, CMD_DISCOVER_MODES); + rlen = 1; + } else if (port->data_role == TYPEC_HOST) { + tcpm_register_partner_altmodes(port); + } + break; case VDO_CMD_VENDOR(0) ... VDO_CMD_VENDOR(15): break; case CMD_ENTER_MODE: