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