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