1 From 976daf9d1199932df80e7b04546d1a1bd4ed5ece Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Sat, 16 Mar 2019 16:57:12 +0100
4 Subject: usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps
6 From: Hans de Goede <hdegoede@redhat.com>
8 commit 976daf9d1199932df80e7b04546d1a1bd4ed5ece upstream.
10 PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
11 simply ignore any src PDOs which the sink does not understand such as PPS
12 but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
13 causing contract negotiation to fail.
15 This commit fixes such sinks not working by re-trying the contract
16 negotiation with PD-2.0 source-caps messages if we don't have a contract
17 after PD_N_HARD_RESET_COUNT hard-reset attempts.
19 The problem fixed by this commit was noticed with a Type-C to VGA dongle.
21 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
22 Reviewed-by: Guenter Roeck <linux@roeck-us.net>
23 Cc: stable <stable@vger.kernel.org>
24 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
27 drivers/usb/typec/tcpm/tcpm.c | 27 ++++++++++++++++++++++++++-
28 1 file changed, 26 insertions(+), 1 deletion(-)
30 --- a/drivers/usb/typec/tcpm/tcpm.c
31 +++ b/drivers/usb/typec/tcpm/tcpm.c
35 S(SRC_SEND_CAPABILITIES), \
36 + S(SRC_SEND_CAPABILITIES_TIMEOUT), \
37 S(SRC_NEGOTIATE_CAPABILITIES), \
38 S(SRC_TRANSITION_SUPPLY), \
40 @@ -2966,10 +2967,34 @@ static void run_state_machine(struct tcp
41 /* port->hard_reset_count = 0; */
43 port->pd_capable = true;
44 - tcpm_set_state_cond(port, hard_reset_state(port),
45 + tcpm_set_state_cond(port, SRC_SEND_CAPABILITIES_TIMEOUT,
46 PD_T_SEND_SOURCE_CAP);
49 + case SRC_SEND_CAPABILITIES_TIMEOUT:
51 + * Error recovery for a PD_DATA_SOURCE_CAP reply timeout.
53 + * PD 2.0 sinks are supposed to accept src-capabilities with a
54 + * 3.0 header and simply ignore any src PDOs which the sink does
55 + * not understand such as PPS but some 2.0 sinks instead ignore
56 + * the entire PD_DATA_SOURCE_CAP message, causing contract
57 + * negotiation to fail.
59 + * After PD_N_HARD_RESET_COUNT hard-reset attempts, we try
60 + * sending src-capabilities with a lower PD revision to
61 + * make these broken sinks work.
63 + if (port->hard_reset_count < PD_N_HARD_RESET_COUNT) {
64 + tcpm_set_state(port, HARD_RESET_SEND, 0);
65 + } else if (port->negotiated_rev > PD_REV20) {
66 + port->negotiated_rev--;
67 + port->hard_reset_count = 0;
68 + tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
70 + tcpm_set_state(port, hard_reset_state(port), 0);
73 case SRC_NEGOTIATE_CAPABILITIES:
74 ret = tcpm_pd_check_request(port);