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 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_hcd_ehci_periodic_tree_create                   PORTABLE C      */
38 /*                                                           6.1.2        */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function creates the periodic static tree for the interrupt    */
46 /*    and isochronous eds.                                                */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    hcd_ehci                              Pointer to EHCI controller    */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    Completion Status                                                   */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    _ux_hcd_ehci_ed_obtain                Obtain an ED                  */
59 /*    _ux_utility_physical_address          Get physical address          */
60 /*                                                                        */
61 /*  CALLED BY                                                             */
62 /*                                                                        */
63 /*    EHCI Controller Driver                                              */
64 /*                                                                        */
65 /*  RELEASE HISTORY                                                       */
66 /*                                                                        */
67 /*    DATE              NAME                      DESCRIPTION             */
68 /*                                                                        */
69 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
70 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
71 /*                                            resulting in version 6.1    */
72 /*  11-09-2020     Chaoqiong Xiao           Modified comment(s),          */
73 /*                                            fixed compile warnings,     */
74 /*                                            resulting in version 6.1.2  */
75 /*                                                                        */
76 /**************************************************************************/
_ux_hcd_ehci_periodic_tree_create(UX_HCD_EHCI * hcd_ehci)77 UINT  _ux_hcd_ehci_periodic_tree_create(UX_HCD_EHCI *hcd_ehci)
78 {
79 
80 UX_EHCI_ED                      *ed;
81 UX_EHCI_ED                      *previous_ed;
82 UINT                            list_index;
83 UINT                            list_entries;
84 UINT                            current_list_entry;
85 UX_EHCI_ED                      *ed_list[32];
86 UX_EHCI_ED                      *ed_start_list[32];
87 UX_EHCI_PERIODIC_LINK_POINTER   lp;
88 
89     /* Start with the 1st list - it has 32 entries.  */
90     list_entries =  32;
91 
92     /* Create each list one by one starting from the 32ms list.  */
93     for (list_index = 0; list_index < 6; list_index++)
94     {
95 
96         for (current_list_entry = 0; current_list_entry < list_entries; current_list_entry++)
97         {
98 
99             /* In each list, insert an static QH as the anchor. There should not
100                be any errors when obtaining a new ED, still we do a sanity check.  */
101             ed =  _ux_hcd_ehci_ed_obtain(hcd_ehci);
102             if (ed == UX_NULL)
103                 return(UX_NO_ED_AVAILABLE);
104 
105             /* Mark the anchor as being a QH pointer and a terminator.  */
106             ed -> ux_ehci_ed_queue_head =  (UX_EHCI_ED *) (UX_EHCI_QH_TYP_QH | UX_EHCI_QH_T);
107 
108             /* The Queue element has the terminator bit on.  */
109             ed -> ux_ehci_ed_queue_element =  (UX_EHCI_TD *) UX_EHCI_TD_T;
110 
111             /* The Alternate TD has the terminator bit on.  */
112             ed -> ux_ehci_ed_alternate_td =  (UX_EHCI_TD *) UX_EHCI_TD_T;
113 
114             /* This endpoint is an anchor.  */
115             ed -> ux_ehci_ed_status |=  UX_EHCI_QH_STATIC;
116 
117             /* Either we hook this new ED to the start list for further processing
118                or we hook it to the 2 successive entries in the previous list.  */
119             if (list_index == 0)
120             {
121 
122                 ed_start_list[current_list_entry] =  ed;
123             }
124             else
125             {
126 
127                 /* We need to update the previous ED with the link to this new ED. Since
128                    this is a tree structure, this operation is done twice to the 2 previous
129                    eds in the previous list.  */
130                 lp.void_ptr =                           _ux_utility_physical_address(ed);
131                 lp.value |=                             UX_EHCI_QH_TYP_QH;
132                 previous_ed =                           ed_list[current_list_entry * 2];
133                 previous_ed -> ux_ehci_ed_queue_head =  lp.ed_ptr;
134                 previous_ed -> ux_ehci_ed_next_ed =     ed;
135                 previous_ed -> REF_AS.ANCHOR.ux_ehci_ed_next_anchor = ed;
136                 previous_ed =                           ed_list[(current_list_entry * 2) + 1];
137                 previous_ed -> ux_ehci_ed_queue_head =  lp.ed_ptr;
138                 previous_ed -> ux_ehci_ed_next_ed =     ed;
139                 previous_ed -> REF_AS.ANCHOR.ux_ehci_ed_next_anchor = ed;
140             }
141 
142             /* Memorize this ED in the local list. We do this operation now, otherwise
143                we would erase the previous list eds.  */
144             ed_list[current_list_entry] =  ed;
145         }
146 
147         /*  Shift the number of entries in the next list by 1 (i.e. divide by 2).  */
148         list_entries =  list_entries>>1;
149     }
150 
151     /* Check the value of the ehci frame list entries. If 0, it was not initialized by the controller init function.  */
152     if (hcd_ehci -> ux_hcd_ehci_frame_list_size == 0)
153 
154         /* Value not initialized. Use default.  */
155         hcd_ehci -> ux_hcd_ehci_frame_list_size = UX_EHCI_FRAME_LIST_ENTRIES;
156 
157     /* The tree has been completed but the entries in the EHCI frame list are in the wrong order.
158        We need to swap each entry according to the EHCI specified entry order list so that we
159        have a fair interval frequency for each periodic ED. The primary eds are fetched from the
160        start list, translated into physical addresses and stored into the frame List.  */
161     for (current_list_entry = 0; current_list_entry < 32; current_list_entry++)
162     {
163 
164         ed =  ed_start_list[_ux_system_host_hcd_periodic_tree_entries[current_list_entry]];
165         *(hcd_ehci -> ux_hcd_ehci_frame_list+current_list_entry) =  (UX_EHCI_ED *) _ux_utility_physical_address(ed);
166     }
167 
168     /* We still haven't set the type of each queue head in the list itself. Do that now. */
169     for (current_list_entry = 0; current_list_entry < 32; current_list_entry++)
170     {
171 
172         lp.ed_ptr = hcd_ehci -> ux_hcd_ehci_frame_list[current_list_entry];
173         lp.value |= UX_EHCI_QH_TYP_QH;
174         hcd_ehci -> ux_hcd_ehci_frame_list[current_list_entry] =  lp.ed_ptr;
175     }
176 
177     /* Now the first 32 entries in the frame list have to be duplicated to fill the other entries in the frame list.
178        If the list is set to 32 entries, nothing is done here.  */
179     for (current_list_entry = 32; current_list_entry < hcd_ehci -> ux_hcd_ehci_frame_list_size; current_list_entry++)
180         hcd_ehci -> ux_hcd_ehci_frame_list[current_list_entry] =  hcd_ehci -> ux_hcd_ehci_frame_list[current_list_entry & 0x1f];
181 
182     /* Now each traffic list from entry consumes 1/32 periodic bandwidth.
183      * The poll entry layers depth low to high:
184      * 32ms, 16ms, 8ms, 4ms, 2ms, 1ms -- micro-frames
185      */
186 
187     /* Return successful completion.  */
188     return(UX_SUCCESS);
189 }
190 
191