1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** USBX Component */
17 /** */
18 /** EHCI Controller Driver */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 /* Include necessary system files. */
25
26 #define UX_SOURCE_CODE
27
28 #include "ux_api.h"
29 #include "ux_hcd_ehci.h"
30 #include "ux_host_stack.h"
31
32
33 /* EHCI HCD extension for host mode select. */
34 #ifndef UX_HCD_EHCI_EXT_USBPHY_HIGHSPEED_MODE_SET
35
36 #if defined(K66)
37
38 #define UX_EHCI_USBPHY_CTRL_K66 0x400A2000
39 #define UX_EHCI_USBPHY_CTRL_SET_BIT1 ((*(volatile ULONG *)(UX_EHCI_USBPHY_CTRL_K66 + 0x34)) = 0x02)
40 #define UX_EHCI_USBPHY_CTRL_CLEAR_BIT1 ((*(volatile ULONG *)(UX_EHCI_USBPHY_CTRL_K66 + 0x38)) = 0x02)
41
42 #define UX_HCD_EHCI_EXT_USBPHY_HIGHSPEED_MODE_SET(hcd_ehci, on_off) do \
43 { \
44 if (on_off) \
45 UX_EHCI_USBPHY_CTRL_SET_BIT1; \
46 else \
47 UX_EHCI_USBPHY_CTRL_CLEAR_BIT1; \
48 } while(0)
49
50 #elif defined(IMX6UL) || defined(MIMXRT)
51
52 #if defined(IMX6UL)
53 #define UX_EHCI_USBPHY1 (0x020C9000)
54 #define UX_EHCI_USBPHY2 (0x020CA000)
55 #define UX_EHCI_BASE1 (0x02184100)
56 #define UX_EHCI_BASE2 (0x02184300)
57 #elif defined(MIMXRT)
58 #define UX_EHCI_USBPHY1 (0x400D9000u)
59 #define UX_EHCI_USBPHY2 (0x400DA000u)
60 #define UX_EHCI_BASE1 (0x402E0100u)
61 #define UX_EHCI_BASE2 (0x402E0300u)
62 #endif
63
64 #define UX_EHCI_USBPHY_CTRL_SET_BIT1(base) ((*(volatile ULONG *) ( base + 0x34)) = 0x02)
65 #define UX_EHCI_USBPHY_CTRL_CLEAR_BIT1(base) ((*(volatile ULONG *) ( base + 0x38)) = 0x02)
66
67 #define UX_HCD_EHCI_EXT_USBPHY_HIGHSPEED_MODE_SET(hcd_ehci, on_off) do \
68 { \
69 ULONG base; \
70 if ((ULONG)hcd_ehci -> ux_hcd_ehci_base == UX_EHCI_BASE1) \
71 base = (UX_EHCI_USBPHY1); \
72 else \
73 base = (UX_EHCI_USBPHY2); \
74 if (on_off) \
75 UX_EHCI_USBPHY_CTRL_SET_BIT1(base); \
76 else \
77 UX_EHCI_USBPHY_CTRL_CLEAR_BIT1(base); \
78 } while(0)
79
80 #else
81 #define UX_HCD_EHCI_EXT_USBPHY_HIGHSPEED_MODE_SET(hcd_ehci, on_off)
82 #endif
83
84 #endif /* ifndef UX_HCD_EHCI_EXT_USBPHY_HIGHSPEED_MODE_SET */
85
86 /**************************************************************************/
87 /* */
88 /* FUNCTION RELEASE */
89 /* */
90 /* _ux_hcd_ehci_port_reset PORTABLE C */
91 /* 6.1.8 */
92 /* AUTHOR */
93 /* */
94 /* Chaoqiong Xiao, Microsoft Corporation */
95 /* */
96 /* DESCRIPTION */
97 /* */
98 /* This function will reset a specific port attached to the root HUB. */
99 /* */
100 /* INPUT */
101 /* */
102 /* hcd_ehci Pointer to EHCI controller */
103 /* port_index Port index to reset */
104 /* */
105 /* OUTPUT */
106 /* */
107 /* Completion Status */
108 /* */
109 /* CALLS */
110 /* */
111 /* _ux_hcd_ehci_register_read Read EHCI register */
112 /* _ux_hcd_ehci_register_write Write EHCI register */
113 /* _ux_utility_delay_ms Delay */
114 /* */
115 /* CALLED BY */
116 /* */
117 /* EHCI Controller Driver */
118 /* */
119 /* RELEASE HISTORY */
120 /* */
121 /* DATE NAME DESCRIPTION */
122 /* */
123 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
124 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
125 /* fixed NXP register base, */
126 /* resulting in version 6.1 */
127 /* 08-02-2021 Wen Wang Modified comment(s), */
128 /* fixed spelling error, */
129 /* resulting in version 6.1.8 */
130 /* */
131 /**************************************************************************/
_ux_hcd_ehci_port_reset(UX_HCD_EHCI * hcd_ehci,ULONG port_index)132 UINT _ux_hcd_ehci_port_reset(UX_HCD_EHCI *hcd_ehci, ULONG port_index)
133 {
134
135 ULONG ehci_register_port_status;
136 INT i;
137
138
139 /* Check to see if this port is valid on this controller. */
140 if (hcd_ehci -> ux_hcd_ehci_nb_root_hubs < port_index)
141 {
142
143 /* Error trap. */
144 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_PORT_INDEX_UNKNOWN);
145
146 /* If trace is enabled, insert this event into the trace buffer. */
147 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_PORT_INDEX_UNKNOWN, port_index, 0, 0, UX_TRACE_ERRORS, 0, 0)
148
149 return(UX_PORT_INDEX_UNKNOWN);
150 }
151
152 /* Ensure that the downstream port has a device attached. It is unnatural to perform
153 a port reset if there is no device. */
154 ehci_register_port_status = _ux_hcd_ehci_register_read(hcd_ehci, EHCI_HCOR_PORT_SC + port_index);
155
156 /* Check Device Connection Status. */
157 if ((ehci_register_port_status & EHCI_HC_PS_CCS) == 0)
158 {
159
160 /* Error trap. */
161 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_NO_DEVICE_CONNECTED);
162
163 /* If trace is enabled, insert this event into the trace buffer. */
164 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_DEVICE_CONNECTED, port_index, 0, 0, UX_TRACE_ERRORS, 0, 0)
165
166 return(UX_NO_DEVICE_CONNECTED);
167 }
168
169 /* Check for the speed of the device. If low speed, we need to send the connection signal
170 to the companion chip. Unless we are on a controller with a built-in TT. */
171 if ((ehci_register_port_status & EHCI_HC_PS_SPEED_MASK) != EHCI_HC_PS_SPEED_LOW || (hcd_ehci -> ux_hcd_ehci_embedded_tt == UX_TRUE))
172 {
173
174 for (i = 0; ; i ++)
175 {
176
177 /* Before reset, phy does not know the speed. */
178 UX_HCD_EHCI_EXT_USBPHY_HIGHSPEED_MODE_SET(hcd_ehci, UX_FALSE);
179
180 /* The device may be high speed or full speed, we try to reset the port for some time
181 and see if the port is enabled by the host controller. */
182 _ux_hcd_ehci_register_write(hcd_ehci, EHCI_HCOR_PORT_SC + port_index, (ehci_register_port_status | EHCI_HC_PS_PR));
183
184 /* Wait until the port has been reset. */
185 _ux_utility_delay_ms(EHCI_HC_RH_RESET_DELAY );
186
187 /* Now turn off the port reset. */
188 ehci_register_port_status = _ux_hcd_ehci_register_read(hcd_ehci, EHCI_HCOR_PORT_SC + port_index);
189 if (ehci_register_port_status & EHCI_HC_PS_PR)
190 {
191
192 ehci_register_port_status &= ~EHCI_HC_PS_PR;
193 _ux_hcd_ehci_register_write(hcd_ehci, EHCI_HCOR_PORT_SC + port_index, ehci_register_port_status);
194
195 /* According to the USB 2.0 spec, the controller may take 2ms to reset the port bit from 1 to 0 after
196 we write a 0. Wait until the port reset bit has been turned off completely. */
197 _ux_utility_delay_ms(EHCI_HC_RH_RESET_SETTLE_DELAY);
198 }
199
200 /* Now check port speed. */
201 ehci_register_port_status = _ux_hcd_ehci_register_read(hcd_ehci, EHCI_HCOR_PORT_SC + port_index);
202 if (hcd_ehci -> ux_hcd_ehci_embedded_tt &&
203 (ehci_register_port_status & EHCI_HC_PS_EMBEDDED_TT_SPEED_MASK) == EHCI_HC_PS_EMBEDDED_TT_SPEED_HIGH)
204 break;
205
206 /* Seems we need to set the Port to a Suspend state before forcing the reset. Otherwise some devices fail the
207 HS detection handshake. */
208 if (i == 0)
209 {
210 _ux_hcd_ehci_register_write(hcd_ehci, EHCI_HCOR_PORT_SC + port_index, (ehci_register_port_status | EHCI_HC_PS_SUSPEND));
211 _ux_utility_delay_ms(UX_HIGH_SPEED_DETECTION_HANDSHAKE_SUSPEND_WAIT);
212 _ux_hcd_ehci_register_write(hcd_ehci, EHCI_HCOR_PORT_SC + port_index, (ehci_register_port_status & ~EHCI_HC_PS_SUSPEND));
213 }
214 else
215 break;
216 }
217
218 /* Now we can read the port enable bit. */
219 ehci_register_port_status = _ux_hcd_ehci_register_read(hcd_ehci, EHCI_HCOR_PORT_SC + port_index);
220 if ((ehci_register_port_status & EHCI_HC_PS_PE) != 0)
221 {
222
223 /* After reset, adjust phy speed. */
224 UX_HCD_EHCI_EXT_USBPHY_HIGHSPEED_MODE_SET(hcd_ehci, UX_TRUE);
225 return(UX_SUCCESS);
226 }
227 }
228
229 /* We come here when the device is either low speed or full speed. In this case, we release
230 the ownership of the port to the companion chip. */
231 _ux_hcd_ehci_register_write(hcd_ehci, EHCI_HCOR_PORT_SC + port_index, (ehci_register_port_status | EHCI_HC_PS_PO));
232
233 /* Delay. */
234 _ux_utility_delay_ms(EHCI_HC_RH_RESET_DELAY);
235
236 /* If trace is enabled, insert this event into the trace buffer. */
237 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_PORT_RESET_FAILED, port_index, 0, 0, UX_TRACE_ERRORS, 0, 0)
238
239 /* Error trap. */
240 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_PORT_RESET_FAILED);
241
242 /* When the root HUB sees an error message, it will give up on this device and the companion chip root HUB
243 will pick up the insertion signal again and reawake the root HUB driver. */
244 return(UX_PORT_RESET_FAILED);
245 }
246
247