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 /**   OHCI 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_ohci.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_hcd_ohci_initialize                             PORTABLE C      */
38 /*                                                           6.1.12       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*     This function initializes the OHCI controller. It sets the dma     */
46 /*     areas, programs all the OHCI registers, setup the ED and TD        */
47 /*     containers, sets the control, and builds the periodic lists.       */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    HCD                                   Pointer to HCD                */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    Completion Status                                                   */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _ux_hcd_ohci_periodic_tree_create     Create OHCI periodic tree     */
60 /*    _ux_hcd_ohci_power_root_hubs          Power root HUBs               */
61 /*    _ux_hcd_ohci_register_read            Read OHCI register            */
62 /*    _ux_hcd_ohci_register_write           Write OHCI register           */
63 /*    _ux_utility_memory_allocate           Allocate memory block         */
64 /*    _ux_host_mutex_on                     Get mutex protection          */
65 /*    _ux_host_mutex_off                    Release mutex protection      */
66 /*    _ux_utility_physical_address          Get physical address          */
67 /*    _ux_utility_set_interrupt_handler     Setup interrupt handler       */
68 /*                                                                        */
69 /*  CALLED BY                                                             */
70 /*                                                                        */
71 /*    Host Stack                                                          */
72 /*                                                                        */
73 /*  RELEASE HISTORY                                                       */
74 /*                                                                        */
75 /*    DATE              NAME                      DESCRIPTION             */
76 /*                                                                        */
77 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
78 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            optimized based on compile  */
80 /*                                            definitions,                */
81 /*                                            resulting in version 6.1    */
82 /*  01-31-2022     Xiuwen Cai               Modified comment(s),          */
83 /*                                            fixed HcPeriodicStart value,*/
84 /*                                            resulting in version 6.1.10 */
85 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
86 /*                                            fixed standalone compile,   */
87 /*                                            resulting in version 6.1.11 */
88 /*  07-29-2022     Yajun Xia                Modified comment(s),          */
89 /*                                            fixed OHCI PRSC issue,      */
90 /*                                            resulting in version 6.1.12 */
91 /*                                                                        */
92 /**************************************************************************/
_ux_hcd_ohci_initialize(UX_HCD * hcd)93 UINT  _ux_hcd_ohci_initialize(UX_HCD *hcd)
94 {
95 
96 UX_HCD_OHCI     *hcd_ohci;
97 ULONG           ohci_register;
98 UINT            index_loop;
99 UINT            status;
100 
101 
102     /* The controller initialized here is of OHCI type.  */
103     hcd -> ux_hcd_controller_type =  UX_OHCI_CONTROLLER;
104 
105 #if UX_MAX_DEVICES > 1
106     /* Initialize the max bandwidth for periodic endpoints. On OHCI, the spec says no
107        more than 90% to be allocated for periodic.  */
108     hcd -> ux_hcd_available_bandwidth =  UX_OHCI_AVAILABLE_BANDWIDTH;
109 #endif
110 
111     /* Allocate memory for this OHCI HCD instance.  */
112     hcd_ohci =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HCD_OHCI));
113     if (hcd_ohci == UX_NULL)
114         return(UX_MEMORY_INSUFFICIENT);
115 
116     /* Set the pointer to the OHCI HCD.  */
117     hcd -> ux_hcd_controller_hardware =  (VOID *) hcd_ohci;
118 
119     /* Save the HCOR address.  */
120     hcd_ohci -> ux_hcd_ohci_hcor =  (ULONG *) hcd -> ux_hcd_io;
121 
122     /* Set the generic HCD owner for the OHCI HCD.  */
123     hcd_ohci -> ux_hcd_ohci_hcd_owner =  hcd;
124 
125     /* Initialize the function collector for this HCD.  */
126     hcd -> ux_hcd_entry_function =  _ux_hcd_ohci_entry;
127 
128     /* Set the state of the controller to HALTED first.  */
129     hcd -> ux_hcd_status =  UX_HCD_STATUS_HALTED;
130 
131     /* get an DMA safe address for the HCCA. This block of memory is to be aligned
132        on 256 bytes.  */
133     hcd_ohci -> ux_hcd_ohci_hcca =  _ux_utility_memory_allocate(UX_ALIGN_256, UX_CACHE_SAFE_MEMORY, sizeof(UX_HCD_OHCI_HCCA));
134     if (hcd_ohci -> ux_hcd_ohci_hcca == UX_NULL)
135         return(UX_MEMORY_INSUFFICIENT);
136 
137     /* Allocate the list of eds. All eds are allocated on 16 byte memory boundary.  */
138     hcd_ohci -> ux_hcd_ohci_ed_list =  _ux_utility_memory_allocate(UX_ALIGN_16, UX_CACHE_SAFE_MEMORY, sizeof(UX_OHCI_ED) * _ux_system_host -> ux_system_host_max_ed);
139     if (hcd_ohci -> ux_hcd_ohci_ed_list == UX_NULL)
140         return(UX_MEMORY_INSUFFICIENT);
141 
142     /* Allocate the list of tds. All tds are allocated on 32 byte memory boundary.  */
143     hcd_ohci -> ux_hcd_ohci_td_list =  _ux_utility_memory_allocate(UX_ALIGN_32, UX_CACHE_SAFE_MEMORY, sizeof(UX_OHCI_TD) * _ux_system_host -> ux_system_host_max_td);
144     if (hcd_ohci -> ux_hcd_ohci_td_list == UX_NULL)
145         return(UX_MEMORY_INSUFFICIENT);
146 
147     /* Allocate the list of isochronous tds. All tds are allocated on 32 byte memory boundary.  */
148     hcd_ohci -> ux_hcd_ohci_iso_td_list =  _ux_utility_memory_allocate(UX_ALIGN_32, UX_CACHE_SAFE_MEMORY, sizeof(UX_OHCI_ISO_TD) * _ux_system_host -> ux_system_host_max_iso_td);
149     if (hcd_ohci -> ux_hcd_ohci_td_list == UX_NULL)
150         return(UX_MEMORY_INSUFFICIENT);
151 
152     /* Initialize the periodic tree.  */
153     status =  _ux_hcd_ohci_periodic_tree_create(hcd_ohci);
154     if (status != UX_SUCCESS)
155         return(status);
156 
157 #if UX_MAX_DEVICES > 1
158 
159     /* Read the OHCI controller version, it is either USB 1.0 or 1.1. This is important for
160        filtering INT out endpoints on a 1.0 OHCI.  */
161     hcd -> ux_hcd_version =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_REVISION);
162 #endif
163 
164     /* Set the state of the OHCI controller to reset in the control register.
165        This is not compulsory but some controllers demand to start in this state.  */
166     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_CONTROL, 0);
167 
168     /* The following is time critical. If we get interrupted here, the controller will go in
169        suspend mode. Get the protection mutex.  */
170     _ux_host_mutex_on(&_ux_system -> ux_system_mutex);
171 
172     /* Send the reset command to the controller. The controller should ack
173        this command within 10us. We try this several time and check for timeout.  */
174     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_COMMAND_STATUS, OHCI_HC_CS_HCR);
175 
176     for (index_loop = 0; index_loop < UX_OHCI_RESET_RETRY; index_loop++)
177     {
178 
179         ohci_register =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_COMMAND_STATUS);
180         if ((ohci_register & OHCI_HC_CS_HCR) == 0)
181             break;
182     }
183 
184     /* Check if the controller is reset properly.  */
185     if ((ohci_register & OHCI_HC_CS_HCR) != 0)
186     {
187 
188         /* Release the thread protection.  */
189         _ux_host_mutex_off(&_ux_system -> ux_system_mutex);
190 
191         /* Error trap. */
192         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_CONTROLLER_INIT_FAILED);
193 
194         /* If trace is enabled, insert this event into the trace buffer.  */
195         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONTROLLER_INIT_FAILED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
196 
197         return(UX_CONTROLLER_INIT_FAILED);
198     }
199 
200     /* Set the HCCA pointer to the HCOR.  */
201     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_HCCA, (ULONG) _ux_utility_physical_address(hcd_ohci -> ux_hcd_ohci_hcca));
202 
203     /* For now and until we have control and bulk ED, reset the control and bulk head registers.  */
204     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_CONTROL_HEAD_ED, 0);
205     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_CONTROL_CURRENT_ED, 0);
206     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_BULK_HEAD_ED, 0);
207     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_BULK_CURRENT_ED, 0);
208 
209     /* Turn on the OHCI controller functional registers we will use after this operation,
210        the controller is operational.  */
211     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_CONTROL, OHCI_HC_CONTROL_VALUE);
212     hcd -> ux_hcd_status =  UX_HCD_STATUS_OPERATIONAL;
213 
214     /* We can safely release the mutex protection.  */
215     _ux_host_mutex_off(&_ux_system -> ux_system_mutex);
216 
217     /* Set the controller interval.  */
218     ohci_register =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_FM_INTERVAL) & OHCI_HC_FM_INTERVAL_CLEAR;
219     ohci_register |=  OHCI_HC_FM_INTERVAL_SET;
220     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_FM_INTERVAL, ohci_register);
221 
222     /* Set HcPeriodicStart to a value that is 90% of the value in FrameInterval field of the HcFmInterval register.  */
223     ohci_register =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_FM_INTERVAL) & OHCI_HC_FM_INTERVAL_FI_MASK;
224     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_PERIODIC_START, ohci_register * 9 / 10);
225 
226     /* Reset all the OHCI interrupts and re-enable only the ones we will use.  */
227     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_INTERRUPT_DISABLE, OHCI_HC_INTERRUPT_DISABLE_ALL);
228     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_INTERRUPT_ENABLE, OHCI_HC_INTERRUPT_ENABLE_NORMAL);
229 
230     /* Get the number of ports on the controller. The number of ports needs to be reflected both
231        for the generic HCD container and the local OHCI container.  */
232     ohci_register =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_RH_DESCRIPTOR_A);
233     hcd -> ux_hcd_nb_root_hubs =  (UINT) (ohci_register & 0xff);
234     if (hcd -> ux_hcd_nb_root_hubs > UX_MAX_ROOTHUB_PORT)
235         hcd -> ux_hcd_nb_root_hubs = UX_MAX_ROOTHUB_PORT;
236     hcd_ohci -> ux_hcd_ohci_nb_root_hubs =  hcd -> ux_hcd_nb_root_hubs;
237 
238     /* Create HCD event flags */
239     status = _ux_host_event_flags_create(&hcd_ohci -> ux_hcd_ohci_event_flags_group, "ux_hcd_ohci_event_flags_group");
240     if (status != UX_SUCCESS)
241         return(status);
242 
243     /* All ports must now be powered to pick up device insertion.  */
244     _ux_hcd_ohci_power_root_hubs(hcd_ohci);
245 
246     /* Return successful completion.  */
247     return(UX_SUCCESS);
248 }
249 
250