]>
Commit | Line | Data |
---|---|---|
4d6421f7 GKH |
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 | |
5 | ||
6 | From: Hans de Goede <hdegoede@redhat.com> | |
7 | ||
8 | commit 976daf9d1199932df80e7b04546d1a1bd4ed5ece upstream. | |
9 | ||
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. | |
14 | ||
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. | |
18 | ||
19 | The problem fixed by this commit was noticed with a Type-C to VGA dongle. | |
20 | ||
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> | |
25 | ||
26 | --- | |
27 | drivers/usb/typec/tcpm/tcpm.c | 27 ++++++++++++++++++++++++++- | |
28 | 1 file changed, 26 insertions(+), 1 deletion(-) | |
29 | ||
30 | --- a/drivers/usb/typec/tcpm/tcpm.c | |
31 | +++ b/drivers/usb/typec/tcpm/tcpm.c | |
32 | @@ -37,6 +37,7 @@ | |
33 | S(SRC_ATTACHED), \ | |
34 | S(SRC_STARTUP), \ | |
35 | S(SRC_SEND_CAPABILITIES), \ | |
36 | + S(SRC_SEND_CAPABILITIES_TIMEOUT), \ | |
37 | S(SRC_NEGOTIATE_CAPABILITIES), \ | |
38 | S(SRC_TRANSITION_SUPPLY), \ | |
39 | S(SRC_READY), \ | |
40 | @@ -2966,10 +2967,34 @@ static void run_state_machine(struct tcp | |
41 | /* port->hard_reset_count = 0; */ | |
42 | port->caps_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); | |
47 | } | |
48 | break; | |
49 | + case SRC_SEND_CAPABILITIES_TIMEOUT: | |
50 | + /* | |
51 | + * Error recovery for a PD_DATA_SOURCE_CAP reply timeout. | |
52 | + * | |
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. | |
58 | + * | |
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. | |
62 | + */ | |
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); | |
69 | + } else { | |
70 | + tcpm_set_state(port, hard_reset_state(port), 0); | |
71 | + } | |
72 | + break; | |
73 | case SRC_NEGOTIATE_CAPABILITIES: | |
74 | ret = tcpm_pd_check_request(port); | |
75 | if (ret < 0) { |