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