1 From c2eaacd30565604bbf776ca6e83c9889ea87ea74 Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Tue, 17 Jan 2012 19:14:08 +0000
4 Subject: [PATCH 1/7] Add dwc_otg driver
6 Signed-off-by: popcornmix <popcornmix@gmail.com>
8 drivers/usb/Makefile | 1 +
9 drivers/usb/core/generic.c | 1 +
10 drivers/usb/core/hub.c | 52 +-
11 drivers/usb/core/message.c | 79 +
12 drivers/usb/core/otg_whitelist.h | 172 +-
13 drivers/usb/gadget/Kconfig | 28 +
14 drivers/usb/gadget/file_storage.c | 70 +-
15 drivers/usb/host/Kconfig | 13 +
16 drivers/usb/host/Makefile | 2 +
17 drivers/usb/host/dwc_common_port/Makefile | 44 +
18 drivers/usb/host/dwc_common_port/Makefile.linux | 36 +
19 drivers/usb/host/dwc_common_port/doc/doxygen.cfg | 270 +
20 .../html/dir_c13d72e45af28cdc461a5f284d3d36fc.html | 81 +
21 .../usb/host/dwc_common_port/doc/html/dirs.html | 22 +
22 .../usb/host/dwc_common_port/doc/html/doxygen.css | 358 ++
23 .../host/dwc_common_port/doc/html/dwc__cc_8h.html | 709 +++
24 .../dwc_common_port/doc/html/dwc__crypto_8c.html | 435 ++
25 .../dwc_common_port/doc/html/dwc__crypto_8h.html | 618 +++
26 .../host/dwc_common_port/doc/html/dwc__dh_8h.html | 166 +
27 .../dwc_common_port/doc/html/dwc__list_8h.html | 1844 +++++++
28 .../dwc_common_port/doc/html/dwc__modpow_8h.html | 48 +
29 .../dwc_common_port/doc/html/dwc__notifier_8h.html | 306 ++
30 .../host/dwc_common_port/doc/html/dwc__os_8h.html | 3090 +++++++++++
31 .../usb/host/dwc_common_port/doc/html/files.html | 34 +
32 .../usb/host/dwc_common_port/doc/html/globals.html | 163 +
33 .../dwc_common_port/doc/html/globals_defs.html | 41 +
34 .../dwc_common_port/doc/html/globals_func.html | 153 +
35 .../dwc_common_port/doc/html/globals_type.html | 41 +
36 .../usb/host/dwc_common_port/doc/html/index.html | 8 +
37 .../usb/host/dwc_common_port/doc/html/main.html | 45 +
38 .../usb/host/dwc_common_port/doc/html/pages.html | 23 +
39 drivers/usb/host/dwc_common_port/doc/html/tabs.css | 102 +
40 .../usb/host/dwc_common_port/doc/html/todo.html | 23 +
41 .../usb/host/dwc_common_port/doc/html/tree.html | 90 +
42 drivers/usb/host/dwc_common_port/dwc_cc.c | 506 ++
43 drivers/usb/host/dwc_common_port/dwc_cc.h | 209 +
44 .../usb/host/dwc_common_port/dwc_common_linux.c | 1247 +++++
45 drivers/usb/host/dwc_common_port/dwc_crypto.c | 306 ++
46 drivers/usb/host/dwc_common_port/dwc_crypto.h | 103 +
47 drivers/usb/host/dwc_common_port/dwc_dh.c | 286 ++
48 drivers/usb/host/dwc_common_port/dwc_dh.h | 98 +
49 drivers/usb/host/dwc_common_port/dwc_list.h | 616 +++
50 drivers/usb/host/dwc_common_port/dwc_mem.c | 172 +
51 drivers/usb/host/dwc_common_port/dwc_modpow.c | 622 +++
52 drivers/usb/host/dwc_common_port/dwc_modpow.h | 26 +
53 drivers/usb/host/dwc_common_port/dwc_notifier.c | 256 +
54 drivers/usb/host/dwc_common_port/dwc_notifier.h | 112 +
55 drivers/usb/host/dwc_common_port/dwc_os.h | 924 ++++
56 drivers/usb/host/dwc_common_port/usb.h | 850 +++
57 drivers/usb/host/dwc_otg/Makefile | 78 +
58 drivers/usb/host/dwc_otg/doc/doxygen.cfg | 224 +
59 drivers/usb/host/dwc_otg/doc/html/annotated.html | 120 +
60 drivers/usb/host/dwc_otg/doc/html/doxygen.css | 358 ++
61 .../dwc_otg/doc/html/dummy__audio_8c-source.html | 1550 ++++++
62 .../doc/html/dwc__cfi__common_8h-source.html | 115 +
63 .../host/dwc_otg/doc/html/dwc__cfi__common_8h.html | 119 +
64 .../dwc_otg/doc/html/dwc__otg__attr_8c-source.html | 828 +++
65 .../host/dwc_otg/doc/html/dwc__otg__attr_8c.html | 485 ++
66 .../dwc_otg/doc/html/dwc__otg__attr_8h-source.html | 105 +
67 .../host/dwc_otg/doc/html/dwc__otg__attr_8h.html | 116 +
68 .../dwc_otg/doc/html/dwc__otg__cfi_8c-source.html | 1724 +++++++
69 .../host/dwc_otg/doc/html/dwc__otg__cfi_8c.html | 36 +
70 .../dwc_otg/doc/html/dwc__otg__cfi_8h-source.html | 299 ++
71 .../host/dwc_otg/doc/html/dwc__otg__cfi_8h.html | 302 ++
72 .../dwc_otg/doc/html/dwc__otg__cil_8c-source.html | 4922 ++++++++++++++++++
73 .../host/dwc_otg/doc/html/dwc__otg__cil_8c.html | 3103 +++++++++++
74 .../dwc_otg/doc/html/dwc__otg__cil_8h-source.html | 709 +++
75 .../host/dwc_otg/doc/html/dwc__otg__cil_8h.html | 1844 +++++++
76 .../doc/html/dwc__otg__cil__intr_8c-source.html | 742 +++
77 .../dwc_otg/doc/html/dwc__otg__cil__intr_8c.html | 645 +++
78 .../doc/html/dwc__otg__core__if_8h-source.html | 365 ++
79 .../dwc_otg/doc/html/dwc__otg__core__if_8h.html | 1730 +++++++
80 .../dwc_otg/doc/html/dwc__otg__dbg_8h-source.html | 100 +
81 .../host/dwc_otg/doc/html/dwc__otg__dbg_8h.html | 133 +
82 .../doc/html/dwc__otg__driver_8c-source.html | 1079 ++++
83 .../host/dwc_otg/doc/html/dwc__otg__driver_8c.html | 719 +++
84 .../doc/html/dwc__otg__driver_8h-source.html | 110 +
85 .../host/dwc_otg/doc/html/dwc__otg__driver_8h.html | 50 +
86 .../dwc_otg/doc/html/dwc__otg__hcd_8c-source.html | 2946 +++++++++++
87 .../host/dwc_otg/doc/html/dwc__otg__hcd_8c.html | 1837 +++++++
88 .../dwc_otg/doc/html/dwc__otg__hcd_8h-source.html | 517 ++
89 .../host/dwc_otg/doc/html/dwc__otg__hcd_8h.html | 1310 +++++
90 .../doc/html/dwc__otg__hcd__ddma_8c-source.html | 1070 ++++
91 .../dwc_otg/doc/html/dwc__otg__hcd__ddma_8c.html | 311 ++
92 .../doc/html/dwc__otg__hcd__if_8h-source.html | 191 +
93 .../dwc_otg/doc/html/dwc__otg__hcd__if_8h.html | 1381 +++++
94 .../doc/html/dwc__otg__hcd__intr_8c-source.html | 1873 +++++++
95 .../dwc_otg/doc/html/dwc__otg__hcd__intr_8c.html | 1252 +++++
96 .../doc/html/dwc__otg__hcd__linux_8c-source.html | 726 +++
97 .../dwc_otg/doc/html/dwc__otg__hcd__linux_8c.html | 514 ++
98 .../doc/html/dwc__otg__hcd__queue_8c-source.html | 633 +++
99 .../dwc_otg/doc/html/dwc__otg__hcd__queue_8c.html | 667 +++
100 .../dwc_otg/doc/html/dwc__otg__pcd_8c-source.html | 1851 +++++++
101 .../host/dwc_otg/doc/html/dwc__otg__pcd_8c.html | 1343 +++++
102 .../dwc_otg/doc/html/dwc__otg__pcd_8h-source.html | 171 +
103 .../host/dwc_otg/doc/html/dwc__otg__pcd_8h.html | 254 +
104 .../doc/html/dwc__otg__pcd__if_8h-source.html | 174 +
105 .../dwc_otg/doc/html/dwc__otg__pcd__if_8h.html | 976 ++++
106 .../doc/html/dwc__otg__pcd__intr_8c-source.html | 3629 +++++++++++++
107 .../dwc_otg/doc/html/dwc__otg__pcd__intr_8c.html | 1599 ++++++
108 .../doc/html/dwc__otg__pcd__linux_8c-source.html | 997 ++++
109 .../dwc_otg/doc/html/dwc__otg__pcd__linux_8c.html | 796 +++
110 .../dwc_otg/doc/html/dwc__otg__regs_8h-source.html | 1260 +++++
111 .../host/dwc_otg/doc/html/dwc__otg__regs_8h.html | 1468 ++++++
112 drivers/usb/host/dwc_otg/doc/html/files.html | 52 +
113 drivers/usb/host/dwc_otg/doc/html/functions.html | 82 +
114 .../usb/host/dwc_otg/doc/html/functions_0x62.html | 99 +
115 .../usb/host/dwc_otg/doc/html/functions_0x63.html | 110 +
116 .../usb/host/dwc_otg/doc/html/functions_0x64.html | 158 +
117 .../usb/host/dwc_otg/doc/html/functions_0x65.html | 109 +
118 .../usb/host/dwc_otg/doc/html/functions_0x66.html | 81 +
119 .../usb/host/dwc_otg/doc/html/functions_0x67.html | 95 +
120 .../usb/host/dwc_otg/doc/html/functions_0x68.html | 119 +
121 .../usb/host/dwc_otg/doc/html/functions_0x69.html | 121 +
122 .../usb/host/dwc_otg/doc/html/functions_0x6c.html | 74 +
123 .../usb/host/dwc_otg/doc/html/functions_0x6d.html | 79 +
124 .../usb/host/dwc_otg/doc/html/functions_0x6e.html | 99 +
125 .../usb/host/dwc_otg/doc/html/functions_0x6f.html | 101 +
126 .../usb/host/dwc_otg/doc/html/functions_0x70.html | 144 +
127 .../usb/host/dwc_otg/doc/html/functions_0x71.html | 71 +
128 .../usb/host/dwc_otg/doc/html/functions_0x72.html | 141 +
129 .../usb/host/dwc_otg/doc/html/functions_0x73.html | 128 +
130 .../usb/host/dwc_otg/doc/html/functions_0x74.html | 88 +
131 .../usb/host/dwc_otg/doc/html/functions_0x75.html | 78 +
132 .../usb/host/dwc_otg/doc/html/functions_0x76.html | 65 +
133 .../usb/host/dwc_otg/doc/html/functions_0x77.html | 79 +
134 .../usb/host/dwc_otg/doc/html/functions_0x78.html | 77 +
135 .../usb/host/dwc_otg/doc/html/functions_func.html | 36 +
136 .../usb/host/dwc_otg/doc/html/functions_vars.html | 82 +
137 .../host/dwc_otg/doc/html/functions_vars_0x62.html | 99 +
138 .../host/dwc_otg/doc/html/functions_vars_0x63.html | 110 +
139 .../host/dwc_otg/doc/html/functions_vars_0x64.html | 157 +
140 .../host/dwc_otg/doc/html/functions_vars_0x65.html | 109 +
141 .../host/dwc_otg/doc/html/functions_vars_0x66.html | 81 +
142 .../host/dwc_otg/doc/html/functions_vars_0x67.html | 95 +
143 .../host/dwc_otg/doc/html/functions_vars_0x68.html | 119 +
144 .../host/dwc_otg/doc/html/functions_vars_0x69.html | 121 +
145 .../host/dwc_otg/doc/html/functions_vars_0x6c.html | 74 +
146 .../host/dwc_otg/doc/html/functions_vars_0x6d.html | 79 +
147 .../host/dwc_otg/doc/html/functions_vars_0x6e.html | 99 +
148 .../host/dwc_otg/doc/html/functions_vars_0x6f.html | 101 +
149 .../host/dwc_otg/doc/html/functions_vars_0x70.html | 144 +
150 .../host/dwc_otg/doc/html/functions_vars_0x71.html | 71 +
151 .../host/dwc_otg/doc/html/functions_vars_0x72.html | 141 +
152 .../host/dwc_otg/doc/html/functions_vars_0x73.html | 128 +
153 .../host/dwc_otg/doc/html/functions_vars_0x74.html | 88 +
154 .../host/dwc_otg/doc/html/functions_vars_0x75.html | 78 +
155 .../host/dwc_otg/doc/html/functions_vars_0x76.html | 65 +
156 .../host/dwc_otg/doc/html/functions_vars_0x77.html | 79 +
157 .../host/dwc_otg/doc/html/functions_vars_0x78.html | 77 +
158 drivers/usb/host/dwc_otg/doc/html/globals.html | 87 +
159 .../usb/host/dwc_otg/doc/html/globals_0x61.html | 76 +
160 .../usb/host/dwc_otg/doc/html/globals_0x62.html | 83 +
161 .../usb/host/dwc_otg/doc/html/globals_0x63.html | 100 +
162 .../usb/host/dwc_otg/doc/html/globals_0x64.html | 686 +++
163 .../usb/host/dwc_otg/doc/html/globals_0x65.html | 78 +
164 .../usb/host/dwc_otg/doc/html/globals_0x66.html | 87 +
165 .../usb/host/dwc_otg/doc/html/globals_0x67.html | 93 +
166 .../usb/host/dwc_otg/doc/html/globals_0x68.html | 129 +
167 .../usb/host/dwc_otg/doc/html/globals_0x69.html | 76 +
168 .../usb/host/dwc_otg/doc/html/globals_0x6b.html | 69 +
169 .../usb/host/dwc_otg/doc/html/globals_0x6d.html | 84 +
170 .../usb/host/dwc_otg/doc/html/globals_0x6e.html | 68 +
171 .../usb/host/dwc_otg/doc/html/globals_0x6f.html | 73 +
172 .../usb/host/dwc_otg/doc/html/globals_0x70.html | 84 +
173 .../usb/host/dwc_otg/doc/html/globals_0x71.html | 70 +
174 .../usb/host/dwc_otg/doc/html/globals_0x72.html | 94 +
175 .../usb/host/dwc_otg/doc/html/globals_0x73.html | 85 +
176 .../usb/host/dwc_otg/doc/html/globals_0x74.html | 68 +
177 .../usb/host/dwc_otg/doc/html/globals_0x75.html | 80 +
178 .../usb/host/dwc_otg/doc/html/globals_0x76.html | 75 +
179 .../usb/host/dwc_otg/doc/html/globals_0x77.html | 74 +
180 .../usb/host/dwc_otg/doc/html/globals_defs.html | 68 +
181 .../host/dwc_otg/doc/html/globals_defs_0x61.html | 64 +
182 .../host/dwc_otg/doc/html/globals_defs_0x62.html | 71 +
183 .../host/dwc_otg/doc/html/globals_defs_0x63.html | 74 +
184 .../host/dwc_otg/doc/html/globals_defs_0x64.html | 241 +
185 .../host/dwc_otg/doc/html/globals_defs_0x66.html | 71 +
186 .../host/dwc_otg/doc/html/globals_defs_0x67.html | 62 +
187 .../host/dwc_otg/doc/html/globals_defs_0x68.html | 63 +
188 .../host/dwc_otg/doc/html/globals_defs_0x69.html | 62 +
189 .../host/dwc_otg/doc/html/globals_defs_0x6d.html | 76 +
190 .../host/dwc_otg/doc/html/globals_defs_0x6e.html | 62 +
191 .../host/dwc_otg/doc/html/globals_defs_0x6f.html | 67 +
192 .../host/dwc_otg/doc/html/globals_defs_0x72.html | 66 +
193 .../host/dwc_otg/doc/html/globals_defs_0x73.html | 63 +
194 .../host/dwc_otg/doc/html/globals_defs_0x75.html | 64 +
195 .../host/dwc_otg/doc/html/globals_defs_0x76.html | 68 +
196 .../usb/host/dwc_otg/doc/html/globals_enum.html | 44 +
197 .../usb/host/dwc_otg/doc/html/globals_eval.html | 43 +
198 .../usb/host/dwc_otg/doc/html/globals_func.html | 77 +
199 .../host/dwc_otg/doc/html/globals_func_0x61.html | 70 +
200 .../host/dwc_otg/doc/html/globals_func_0x62.html | 68 +
201 .../host/dwc_otg/doc/html/globals_func_0x63.html | 77 +
202 .../host/dwc_otg/doc/html/globals_func_0x64.html | 427 ++
203 .../host/dwc_otg/doc/html/globals_func_0x65.html | 73 +
204 .../host/dwc_otg/doc/html/globals_func_0x66.html | 72 +
205 .../host/dwc_otg/doc/html/globals_func_0x67.html | 78 +
206 .../host/dwc_otg/doc/html/globals_func_0x68.html | 101 +
207 .../host/dwc_otg/doc/html/globals_func_0x69.html | 71 +
208 .../host/dwc_otg/doc/html/globals_func_0x6b.html | 66 +
209 .../host/dwc_otg/doc/html/globals_func_0x6d.html | 66 +
210 .../host/dwc_otg/doc/html/globals_func_0x70.html | 78 +
211 .../host/dwc_otg/doc/html/globals_func_0x71.html | 67 +
212 .../host/dwc_otg/doc/html/globals_func_0x72.html | 80 +
213 .../host/dwc_otg/doc/html/globals_func_0x73.html | 77 +
214 .../host/dwc_otg/doc/html/globals_func_0x75.html | 73 +
215 .../host/dwc_otg/doc/html/globals_func_0x76.html | 65 +
216 .../host/dwc_otg/doc/html/globals_func_0x77.html | 70 +
217 .../usb/host/dwc_otg/doc/html/globals_type.html | 175 +
218 .../usb/host/dwc_otg/doc/html/globals_vars.html | 120 +
219 drivers/usb/host/dwc_otg/doc/html/index.html | 8 +
220 .../dwc_otg/doc/html/linux module attributes.html | 130 +
221 drivers/usb/host/dwc_otg/doc/html/main.html | 21 +
222 .../host/dwc_otg/doc/html/module parameters.html | 189 +
223 drivers/usb/host/dwc_otg/doc/html/pages.html | 27 +
224 .../html/struct__ddma__align__buffer__setup.html | 46 +
225 .../html/struct__ddma__concat__buffer__setup.html | 46 +
226 .../struct__ddma__concat__buffer__setup__hdr.html | 49 +
227 .../doc/html/struct__ddma__sg__buffer__setup.html | 57 +
228 .../doc/html/struct__rx__fifo__size__setup.html | 43 +
229 .../doc/html/struct__tx__fifo__size__setup.html | 46 +
230 .../doc/html/structcfi__all__features__header.html | 75 +
231 .../dwc_otg/doc/html/structcfi__dma__buff.html | 41 +
232 .../usb/host/dwc_otg/doc/html/structcfi__ep.html | 69 +
233 .../doc/html/structcfi__feature__desc__header.html | 60 +
234 .../usb/host/dwc_otg/doc/html/structcfi__ops.html | 64 +
235 .../host/dwc_otg/doc/html/structcfi__string.html | 48 +
236 .../doc/html/structcfi__usb__ctrlrequest.html | 58 +
237 .../usb/host/dwc_otg/doc/html/structcfiobject.html | 62 +
238 .../usb/host/dwc_otg/doc/html/structdwc__ep.html | 192 +
239 .../usb/host/dwc_otg/doc/html/structdwc__hc.html | 345 ++
240 .../doc/html/structdwc__otg__cil__callbacks.html | 70 +
241 .../html/structdwc__otg__core__global__regs.html | 557 ++
242 .../dwc_otg/doc/html/structdwc__otg__core__if.html | 190 +
243 .../doc/html/structdwc__otg__core__params.html | 606 +++
244 .../doc/html/structdwc__otg__dev__dma__desc.html | 50 +
245 .../html/structdwc__otg__dev__global__regs.html | 441 ++
246 .../dwc_otg/doc/html/structdwc__otg__dev__if.html | 142 +
247 .../html/structdwc__otg__dev__in__ep__regs.html | 221 +
248 .../html/structdwc__otg__dev__out__ep__regs.html | 221 +
249 .../dwc_otg/doc/html/structdwc__otg__device.html | 64 +
250 .../structdwc__otg__driver__module__params.html | 146 +
251 .../dwc_otg/doc/html/structdwc__otg__hc__regs.html | 200 +
252 .../host/dwc_otg/doc/html/structdwc__otg__hcd.html | 377 ++
253 .../html/structdwc__otg__hcd__function__ops.html | 53 +
254 .../structdwc__otg__hcd__iso__packet__desc.html | 47 +
255 .../doc/html/structdwc__otg__hcd__pipe__info.html | 50 +
256 .../dwc_otg/doc/html/structdwc__otg__hcd__urb.html | 80 +
257 .../doc/html/structdwc__otg__host__dma__desc.html | 50 +
258 .../html/structdwc__otg__host__global__regs.html | 219 +
259 .../dwc_otg/doc/html/structdwc__otg__host__if.html | 66 +
260 .../host/dwc_otg/doc/html/structdwc__otg__pcd.html | 152 +
261 .../dwc_otg/doc/html/structdwc__otg__pcd__ep.html | 77 +
262 .../html/structdwc__otg__pcd__function__ops.html | 73 +
263 .../doc/html/structdwc__otg__pcd__request.html | 64 +
264 .../host/dwc_otg/doc/html/structdwc__otg__qh.html | 228 +
265 .../host/dwc_otg/doc/html/structdwc__otg__qtd.html | 157 +
266 .../dwc_otg/doc/html/structgadget__wrapper.html | 53 +
267 .../dwc_otg/doc/html/structiso__pkt__info.html | 49 +
268 .../doc/html/structwrapper__priv__data.html | 38 +
269 .../usb/host/dwc_otg/doc/html/structzero__dev.html | 56 +
270 drivers/usb/host/dwc_otg/doc/html/tabs.css | 102 +
271 drivers/usb/host/dwc_otg/doc/html/todo.html | 262 +
272 drivers/usb/host/dwc_otg/doc/html/tree.html | 201 +
273 .../host/dwc_otg/doc/html/uniondaint__data.html | 131 +
274 .../usb/host/dwc_otg/doc/html/uniondcfg__data.html | 74 +
275 .../usb/host/dwc_otg/doc/html/uniondctl__data.html | 96 +
276 .../host/dwc_otg/doc/html/uniondepctl__data.html | 139 +
277 .../host/dwc_otg/doc/html/uniondeptsiz0__data.html | 69 +
278 .../host/dwc_otg/doc/html/uniondeptsiz__data.html | 63 +
279 .../dwc_otg/doc/html/uniondev__dma__desc__sts.html | 140 +
280 .../doc/html/uniondevice__grxsts__data.html | 62 +
281 .../host/dwc_otg/doc/html/uniondiepint__data.html | 90 +
282 .../host/dwc_otg/doc/html/uniondoepint__data.html | 98 +
283 .../usb/host/dwc_otg/doc/html/uniondsts__data.html | 68 +
284 .../host/dwc_otg/doc/html/uniondthrctl__data.html | 178 +
285 .../host/dwc_otg/doc/html/uniondtknq1__data.html | 86 +
286 .../host/dwc_otg/doc/html/uniondtxfsts__data.html | 56 +
287 ...otg__hcd_1_1dwc__otg__hcd__internal__flags.html | 66 +
288 .../host/dwc_otg/doc/html/unionfifosize__data.html | 56 +
289 .../host/dwc_otg/doc/html/uniongahbcfg__data.html | 66 +
290 .../host/dwc_otg/doc/html/uniongi2cctl__data.html | 72 +
291 .../host/dwc_otg/doc/html/uniongintmsk__data.html | 114 +
292 .../host/dwc_otg/doc/html/uniongintsts__data.html | 114 +
293 .../host/dwc_otg/doc/html/unionglpmctl__data.html | 178 +
294 .../host/dwc_otg/doc/html/uniongnptxsts__data.html | 69 +
295 .../host/dwc_otg/doc/html/uniongotgctl__data.html | 80 +
296 .../host/dwc_otg/doc/html/uniongotgint__data.html | 79 +
297 .../host/dwc_otg/doc/html/uniongrstctl__data.html | 249 +
298 .../host/dwc_otg/doc/html/uniongusbcfg__data.html | 98 +
299 .../host/dwc_otg/doc/html/unionhaint__data.html | 93 +
300 .../host/dwc_otg/doc/html/unionhaintmsk__data.html | 93 +
301 .../host/dwc_otg/doc/html/unionhcchar__data.html | 123 +
302 .../host/dwc_otg/doc/html/unionhcdma__data.html | 78 +
303 .../usb/host/dwc_otg/doc/html/unionhcfg__data.html | 72 +
304 .../host/dwc_otg/doc/html/unionhcint__data.html | 95 +
305 .../host/dwc_otg/doc/html/unionhcintmsk__data.html | 82 +
306 .../host/dwc_otg/doc/html/unionhcsplt__data.html | 63 +
307 .../host/dwc_otg/doc/html/unionhctsiz__data.html | 105 +
308 .../usb/host/dwc_otg/doc/html/unionhfir__data.html | 54 +
309 .../host/dwc_otg/doc/html/unionhfnum__data.html | 54 +
310 .../doc/html/unionhost__dma__desc__sts.html | 123 +
311 .../dwc_otg/doc/html/unionhost__grxsts__data.html | 60 +
312 .../host/dwc_otg/doc/html/unionhprt0__data.html | 82 +
313 .../host/dwc_otg/doc/html/unionhptxsts__data.html | 62 +
314 .../host/dwc_otg/doc/html/unionhwcfg1__data.html | 84 +
315 .../host/dwc_otg/doc/html/unionhwcfg2__data.html | 82 +
316 .../host/dwc_otg/doc/html/unionhwcfg3__data.html | 76 +
317 .../host/dwc_otg/doc/html/unionhwcfg4__data.html | 80 +
318 .../host/dwc_otg/doc/html/unionpcgcctl__data.html | 78 +
319 drivers/usb/host/dwc_otg/dummy_audio.c | 1575 ++++++
320 drivers/usb/host/dwc_otg/dwc_cfi_common.h | 142 +
321 drivers/usb/host/dwc_otg/dwc_otg_attr.c | 1316 +++++
322 drivers/usb/host/dwc_otg/dwc_otg_attr.h | 88 +
323 drivers/usb/host/dwc_otg/dwc_otg_cfi.c | 1876 +++++++
324 drivers/usb/host/dwc_otg/dwc_otg_cfi.h | 319 ++
325 drivers/usb/host/dwc_otg/dwc_otg_cil.c | 5410 ++++++++++++++++++++
326 drivers/usb/host/dwc_otg/dwc_otg_cil.h | 1143 +++++
327 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 846 +++
328 drivers/usb/host/dwc_otg/dwc_otg_core_if.h | 641 +++
329 drivers/usb/host/dwc_otg/dwc_otg_dbg.h | 113 +
330 drivers/usb/host/dwc_otg/dwc_otg_driver.c | 1577 ++++++
331 drivers/usb/host/dwc_otg/dwc_otg_driver.h | 101 +
332 drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 3330 ++++++++++++
333 drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 804 +++
334 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 1106 ++++
335 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 393 ++
336 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2065 ++++++++
337 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 840 +++
338 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 732 +++
339 drivers/usb/host/dwc_otg/dwc_otg_pcd.c | 2067 ++++++++
340 drivers/usb/host/dwc_otg/dwc_otg_pcd.h | 216 +
341 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h | 333 ++
342 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 4077 +++++++++++++++
343 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 1288 +++++
344 drivers/usb/host/dwc_otg/dwc_otg_regs.h | 2237 ++++++++
345 drivers/usb/host/dwc_otg/test/Makefile | 16 +
346 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm | 337 ++
347 drivers/usb/host/dwc_otg/test/test_mod_param.pl | 133 +
348 drivers/usb/host/dwc_otg/test/test_sysfs.pl | 193 +
349 341 files changed, 124762 insertions(+), 59 deletions(-)
350 create mode 100644 drivers/usb/host/dwc_common_port/Makefile
351 create mode 100644 drivers/usb/host/dwc_common_port/Makefile.linux
352 create mode 100644 drivers/usb/host/dwc_common_port/doc/doxygen.cfg
353 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dir_c13d72e45af28cdc461a5f284d3d36fc.html
354 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dirs.html
355 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/doxygen.css
356 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__cc_8h.html
357 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__crypto_8c.html
358 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__crypto_8h.html
359 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__dh_8h.html
360 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__list_8h.html
361 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__modpow_8h.html
362 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__notifier_8h.html
363 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__os_8h.html
364 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/files.html
365 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/globals.html
366 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/globals_defs.html
367 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/globals_func.html
368 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/globals_type.html
369 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/index.html
370 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/main.html
371 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/pages.html
372 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/tabs.css
373 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/todo.html
374 create mode 100644 drivers/usb/host/dwc_common_port/doc/html/tree.html
375 create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.c
376 create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.h
377 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_linux.c
378 create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.c
379 create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.h
380 create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.c
381 create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.h
382 create mode 100644 drivers/usb/host/dwc_common_port/dwc_list.h
383 create mode 100644 drivers/usb/host/dwc_common_port/dwc_mem.c
384 create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.c
385 create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.h
386 create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.c
387 create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.h
388 create mode 100644 drivers/usb/host/dwc_common_port/dwc_os.h
389 create mode 100644 drivers/usb/host/dwc_common_port/usb.h
390 create mode 100644 drivers/usb/host/dwc_otg/Makefile
391 create mode 100644 drivers/usb/host/dwc_otg/doc/doxygen.cfg
392 create mode 100644 drivers/usb/host/dwc_otg/doc/html/annotated.html
393 create mode 100644 drivers/usb/host/dwc_otg/doc/html/doxygen.css
394 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dummy__audio_8c-source.html
395 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__cfi__common_8h-source.html
396 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__cfi__common_8h.html
397 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8c-source.html
398 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8c.html
399 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8h-source.html
400 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8h.html
401 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8c-source.html
402 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8c.html
403 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8h-source.html
404 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8h.html
405 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8c-source.html
406 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8c.html
407 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8h-source.html
408 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8h.html
409 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil__intr_8c-source.html
410 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil__intr_8c.html
411 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__core__if_8h-source.html
412 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__core__if_8h.html
413 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__dbg_8h-source.html
414 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__dbg_8h.html
415 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8c-source.html
416 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8c.html
417 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8h-source.html
418 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8h.html
419 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8c-source.html
420 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8c.html
421 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8h-source.html
422 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8h.html
423 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__ddma_8c-source.html
424 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__ddma_8c.html
425 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__if_8h-source.html
426 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__if_8h.html
427 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__intr_8c-source.html
428 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__intr_8c.html
429 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__linux_8c-source.html
430 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__linux_8c.html
431 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__queue_8c-source.html
432 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__queue_8c.html
433 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8c-source.html
434 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8c.html
435 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8h-source.html
436 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8h.html
437 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__if_8h-source.html
438 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__if_8h.html
439 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__intr_8c-source.html
440 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__intr_8c.html
441 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__linux_8c-source.html
442 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__linux_8c.html
443 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__regs_8h-source.html
444 create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__regs_8h.html
445 create mode 100644 drivers/usb/host/dwc_otg/doc/html/files.html
446 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions.html
447 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x62.html
448 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x63.html
449 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x64.html
450 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x65.html
451 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x66.html
452 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x67.html
453 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x68.html
454 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x69.html
455 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x6c.html
456 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x6d.html
457 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x6e.html
458 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x6f.html
459 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x70.html
460 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x71.html
461 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x72.html
462 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x73.html
463 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x74.html
464 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x75.html
465 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x76.html
466 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x77.html
467 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x78.html
468 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_func.html
469 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars.html
470 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x62.html
471 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x63.html
472 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x64.html
473 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x65.html
474 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x66.html
475 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x67.html
476 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x68.html
477 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x69.html
478 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6c.html
479 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6d.html
480 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6e.html
481 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6f.html
482 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x70.html
483 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x71.html
484 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x72.html
485 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x73.html
486 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x74.html
487 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x75.html
488 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x76.html
489 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x77.html
490 create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x78.html
491 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals.html
492 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x61.html
493 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x62.html
494 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x63.html
495 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x64.html
496 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x65.html
497 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x66.html
498 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x67.html
499 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x68.html
500 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x69.html
501 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x6b.html
502 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x6d.html
503 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x6e.html
504 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x6f.html
505 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x70.html
506 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x71.html
507 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x72.html
508 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x73.html
509 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x74.html
510 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x75.html
511 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x76.html
512 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x77.html
513 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs.html
514 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x61.html
515 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x62.html
516 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x63.html
517 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x64.html
518 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x66.html
519 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x67.html
520 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x68.html
521 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x69.html
522 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6d.html
523 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6e.html
524 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6f.html
525 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x72.html
526 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x73.html
527 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x75.html
528 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x76.html
529 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_enum.html
530 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_eval.html
531 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func.html
532 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x61.html
533 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x62.html
534 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x63.html
535 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x64.html
536 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x65.html
537 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x66.html
538 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x67.html
539 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x68.html
540 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x69.html
541 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x6b.html
542 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x6d.html
543 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x70.html
544 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x71.html
545 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x72.html
546 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x73.html
547 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x75.html
548 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x76.html
549 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x77.html
550 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_type.html
551 create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_vars.html
552 create mode 100644 drivers/usb/host/dwc_otg/doc/html/index.html
553 create mode 100644 drivers/usb/host/dwc_otg/doc/html/linux module attributes.html
554 create mode 100644 drivers/usb/host/dwc_otg/doc/html/main.html
555 create mode 100644 drivers/usb/host/dwc_otg/doc/html/module parameters.html
556 create mode 100644 drivers/usb/host/dwc_otg/doc/html/pages.html
557 create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__ddma__align__buffer__setup.html
558 create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__ddma__concat__buffer__setup.html
559 create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__ddma__concat__buffer__setup__hdr.html
560 create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__ddma__sg__buffer__setup.html
561 create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__rx__fifo__size__setup.html
562 create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__tx__fifo__size__setup.html
563 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__all__features__header.html
564 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__dma__buff.html
565 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__ep.html
566 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__feature__desc__header.html
567 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__ops.html
568 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__string.html
569 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__usb__ctrlrequest.html
570 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfiobject.html
571 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__ep.html
572 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__hc.html
573 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__cil__callbacks.html
574 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__global__regs.html
575 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__if.html
576 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__params.html
577 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__dma__desc.html
578 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__global__regs.html
579 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__if.html
580 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__in__ep__regs.html
581 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__out__ep__regs.html
582 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__device.html
583 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__driver__module__params.html
584 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hc__regs.html
585 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd.html
586 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__function__ops.html
587 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__iso__packet__desc.html
588 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__pipe__info.html
589 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__urb.html
590 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__dma__desc.html
591 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__global__regs.html
592 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__if.html
593 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd.html
594 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__ep.html
595 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__function__ops.html
596 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__request.html
597 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__qh.html
598 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__qtd.html
599 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structgadget__wrapper.html
600 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structiso__pkt__info.html
601 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structwrapper__priv__data.html
602 create mode 100644 drivers/usb/host/dwc_otg/doc/html/structzero__dev.html
603 create mode 100644 drivers/usb/host/dwc_otg/doc/html/tabs.css
604 create mode 100644 drivers/usb/host/dwc_otg/doc/html/todo.html
605 create mode 100644 drivers/usb/host/dwc_otg/doc/html/tree.html
606 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondaint__data.html
607 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondcfg__data.html
608 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondctl__data.html
609 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondepctl__data.html
610 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondeptsiz0__data.html
611 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondeptsiz__data.html
612 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondev__dma__desc__sts.html
613 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondevice__grxsts__data.html
614 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondiepint__data.html
615 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondoepint__data.html
616 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondsts__data.html
617 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondthrctl__data.html
618 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondtknq1__data.html
619 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondtxfsts__data.html
620 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondwc__otg__hcd_1_1dwc__otg__hcd__internal__flags.html
621 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionfifosize__data.html
622 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongahbcfg__data.html
623 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongi2cctl__data.html
624 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongintmsk__data.html
625 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongintsts__data.html
626 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionglpmctl__data.html
627 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongnptxsts__data.html
628 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongotgctl__data.html
629 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongotgint__data.html
630 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongrstctl__data.html
631 create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongusbcfg__data.html
632 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhaint__data.html
633 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhaintmsk__data.html
634 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcchar__data.html
635 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcdma__data.html
636 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcfg__data.html
637 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcint__data.html
638 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcintmsk__data.html
639 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcsplt__data.html
640 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhctsiz__data.html
641 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhfir__data.html
642 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhfnum__data.html
643 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhost__dma__desc__sts.html
644 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhost__grxsts__data.html
645 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhprt0__data.html
646 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhptxsts__data.html
647 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhwcfg1__data.html
648 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhwcfg2__data.html
649 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhwcfg3__data.html
650 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhwcfg4__data.html
651 create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionpcgcctl__data.html
652 create mode 100644 drivers/usb/host/dwc_otg/dummy_audio.c
653 create mode 100644 drivers/usb/host/dwc_otg/dwc_cfi_common.h
654 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.c
655 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.h
656 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.c
657 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.h
658 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.c
659 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.h
660 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
661 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_core_if.h
662 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_dbg.h
663 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.c
664 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.h
665 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.c
666 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.h
667 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
668 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
669 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
670 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
671 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
672 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.c
673 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.h
674 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
675 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
676 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
677 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_regs.h
678 create mode 100644 drivers/usb/host/dwc_otg/test/Makefile
679 create mode 100644 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
680 create mode 100644 drivers/usb/host/dwc_otg/test/test_mod_param.pl
681 create mode 100644 drivers/usb/host/dwc_otg/test/test_sysfs.pl
683 --- a/drivers/usb/Makefile
684 +++ b/drivers/usb/Makefile
685 @@ -25,6 +25,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/
686 obj-$(CONFIG_USB_R8A66597_HCD) += host/
687 obj-$(CONFIG_USB_HWA_HCD) += host/
688 obj-$(CONFIG_USB_ISP1760_HCD) += host/
689 +obj-$(CONFIG_USB_DWCOTG) += host/
690 obj-$(CONFIG_USB_IMX21_HCD) += host/
691 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
693 --- a/drivers/usb/core/generic.c
694 +++ b/drivers/usb/core/generic.c
695 @@ -149,6 +149,7 @@ int usb_choose_configuration(struct usb_
697 "no configuration chosen from %d choice%s\n",
698 num_configs, plural(num_configs));
699 + dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA);
703 --- a/drivers/usb/core/hub.c
704 +++ b/drivers/usb/core/hub.c
705 @@ -1075,6 +1075,8 @@ static int hub_configure(struct usb_hub
706 INIT_WORK(&hub->tt.clear_work, hub_tt_work);
707 switch (hdev->descriptor.bDeviceProtocol) {
709 + dev_dbg(hub_dev, "TT with no hub-specific protocol - "
712 case USB_HUB_PR_HS_SINGLE_TT:
713 dev_dbg(hub_dev, "Single TT\n");
714 @@ -1091,6 +1093,7 @@ static int hub_configure(struct usb_hub
718 + dev_dbg(hub_dev, "USB 3.0 hub - no TT\n");
719 /* USB 3.0 hubs don't have a TT */
722 @@ -1719,6 +1722,12 @@ static inline void announce_device(struc
725 #ifdef CONFIG_USB_OTG
727 +static int enable_whitelist;
728 +module_param(enable_whitelist, bool, S_IRUGO | S_IWUSR);
729 +MODULE_PARM_DESC(enable_whitelist,
730 + "only recognize devices in OTG whitelist if true");
732 #include "otg_whitelist.h"
735 @@ -1773,9 +1782,15 @@ static int usb_enumerate_device_otg(stru
737 "can't set HNP mode: %d\n",
739 + dev_printk(KERN_CRIT, &udev->dev,
740 + "Not Connected/Responding\n");
742 bus->b_hnp_enable = 0;
744 + dev_info(&udev->dev,
745 + "HNP Not Supported\n");
752 @@ -1784,12 +1799,27 @@ static int usb_enumerate_device_otg(stru
753 /* Maybe it can talk to us, though we can't talk to it.
754 * (Includes HNP test device.)
756 - if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
757 + if (udev->bus->b_hnp_enable || udev->bus->is_b_host ||
758 + udev->descriptor.idVendor == 0x1a0a) {
759 err = usb_port_suspend(udev, PMSG_SUSPEND);
762 dev_dbg(&udev->dev, "HNP fail, %d\n", err);
764 + /* Return Connection Refused(ECONNREFUSED)
765 + * instead of No Device(ENODEV) so that the
766 + * retry loop in hub_port_connect_change() is
767 + * exited without disabling the port
769 + err = -ECONNREFUSED;
775 + /* Return Not Connected (ENOTCONN) instead of No
776 + * Device(ENODEV) so that the retry loop in
777 + * hub_port_connect_change() is exited
783 @@ -2980,7 +3010,9 @@ hub_port_init (struct usb_hub *hub, stru
784 buf->bMaxPacketSize0 = 0;
785 r = usb_control_msg(udev, usb_rcvaddr0pipe(),
786 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
787 - USB_DT_DEVICE << 8, 0,
788 + USB_DT_DEVICE << 8,
789 + //USB_DT_DEVICE << 64, // DWC patch suggestion!
791 buf, GET_DESCRIPTOR_BUFSIZE,
792 initial_descriptor_timeout);
793 switch (buf->bMaxPacketSize0) {
794 @@ -3426,8 +3458,10 @@ loop:
795 release_devnum(udev);
798 - if ((status == -ENOTCONN) || (status == -ENOTSUPP))
800 + if (status == -ENOTCONN || status == -ENOTSUPP ||
801 + status == -ECONNREFUSED)
802 + // break; //DWC patch
805 if (hub->hdev->parent ||
806 !hcd->driver->port_handed_over ||
807 --- a/drivers/usb/core/message.c
808 +++ b/drivers/usb/core/message.c
809 @@ -1837,6 +1837,85 @@ free_interfaces:
810 if (cp->string == NULL &&
811 !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
812 cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
813 +/* Uncomment this define to enable the HS Electrical Test support */
814 +#define DWC_HS_ELECT_TST 1
815 +#ifdef DWC_HS_ELECT_TST
816 + /* Here we implement the HS Electrical Test support. The
817 + * tester uses a vendor ID of 0x1A0A to indicate we should
818 + * run a special test sequence. The product ID tells us
819 + * which sequence to run. We invoke the test sequence by
820 + * sending a non-standard SetFeature command to our root
821 + * hub port. Our dwc_otg_hcd_hub_control() routine will
822 + * recognize the command and perform the desired test
825 + if (dev->descriptor.idVendor == 0x1A0A) {
826 + /* HSOTG Electrical Test */
827 + dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n");
829 + if (dev->bus && dev->bus->root_hub) {
830 + struct usb_device *hdev = dev->bus->root_hub;
831 + dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct);
833 + switch (dev->descriptor.idProduct) {
834 + case 0x0101: /* TEST_SE0_NAK */
835 + dev_warn(&dev->dev, "TEST_SE0_NAK\n");
836 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
837 + USB_REQ_SET_FEATURE, USB_RT_PORT,
838 + USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ);
841 + case 0x0102: /* TEST_J */
842 + dev_warn(&dev->dev, "TEST_J\n");
843 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
844 + USB_REQ_SET_FEATURE, USB_RT_PORT,
845 + USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ);
848 + case 0x0103: /* TEST_K */
849 + dev_warn(&dev->dev, "TEST_K\n");
850 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
851 + USB_REQ_SET_FEATURE, USB_RT_PORT,
852 + USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ);
855 + case 0x0104: /* TEST_PACKET */
856 + dev_warn(&dev->dev, "TEST_PACKET\n");
857 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
858 + USB_REQ_SET_FEATURE, USB_RT_PORT,
859 + USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ);
862 + case 0x0105: /* TEST_FORCE_ENABLE */
863 + dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n");
864 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
865 + USB_REQ_SET_FEATURE, USB_RT_PORT,
866 + USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ);
869 + case 0x0106: /* HS_HOST_PORT_SUSPEND_RESUME */
870 + dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n");
871 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
872 + USB_REQ_SET_FEATURE, USB_RT_PORT,
873 + USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ);
876 + case 0x0107: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
877 + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n");
878 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
879 + USB_REQ_SET_FEATURE, USB_RT_PORT,
880 + USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ);
883 + case 0x0108: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
884 + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n");
885 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
886 + USB_REQ_SET_FEATURE, USB_RT_PORT,
887 + USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ);
891 +#endif /* DWC_HS_ELECT_TST */
893 /* Now that all the interfaces are set up, register them
894 * to trigger binding of drivers to interfaces. probe()
895 --- a/drivers/usb/core/otg_whitelist.h
896 +++ b/drivers/usb/core/otg_whitelist.h
898 static struct usb_device_id whitelist_table [] = {
900 /* hubs are optional in OTG, but very handy ... */
901 +#define CERT_WITHOUT_HUBS
902 +#if defined(CERT_WITHOUT_HUBS)
903 +{ USB_DEVICE( 0x0000, 0x0000 ), }, /* Root HUB Only*/
905 { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
906 { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
907 +{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), },
910 #ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
911 /* FIXME actually, printers are NOT supposed to use device classes;
912 * they're supposed to use interface classes...
914 -{ USB_DEVICE_INFO(7, 1, 1) },
915 -{ USB_DEVICE_INFO(7, 1, 2) },
916 -{ USB_DEVICE_INFO(7, 1, 3) },
917 +//{ USB_DEVICE_INFO(7, 1, 1) },
918 +//{ USB_DEVICE_INFO(7, 1, 2) },
919 +//{ USB_DEVICE_INFO(7, 1, 3) },
922 #ifdef CONFIG_USB_NET_CDCETHER
923 /* Linux-USB CDC Ethernet gadget */
924 -{ USB_DEVICE(0x0525, 0xa4a1), },
925 +//{ USB_DEVICE(0x0525, 0xa4a1), },
926 /* Linux-USB CDC Ethernet + RNDIS gadget */
927 -{ USB_DEVICE(0x0525, 0xa4a2), },
928 +//{ USB_DEVICE(0x0525, 0xa4a2), },
931 #if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
932 /* gadget zero, for testing */
933 -{ USB_DEVICE(0x0525, 0xa4a0), },
934 +//{ USB_DEVICE(0x0525, 0xa4a0), },
938 +{ USB_DEVICE( 0x1a0a, 0x0101 ), }, /* TEST_SE0_NAK */
939 +{ USB_DEVICE( 0x1a0a, 0x0102 ), }, /* Test_J */
940 +{ USB_DEVICE( 0x1a0a, 0x0103 ), }, /* Test_K */
941 +{ USB_DEVICE( 0x1a0a, 0x0104 ), }, /* Test_PACKET */
942 +{ USB_DEVICE( 0x1a0a, 0x0105 ), }, /* Test_FORCE_ENABLE */
943 +{ USB_DEVICE( 0x1a0a, 0x0106 ), }, /* HS_PORT_SUSPEND_RESUME */
944 +{ USB_DEVICE( 0x1a0a, 0x0107 ), }, /* SINGLE_STEP_GET_DESCRIPTOR setup */
945 +{ USB_DEVICE( 0x1a0a, 0x0108 ), }, /* SINGLE_STEP_GET_DESCRIPTOR execute */
948 +{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), },
950 +/* Memory Devices */
951 +//{ USB_DEVICE( 0x0781, 0x5150 ), }, /* SanDisk */
952 +//{ USB_DEVICE( 0x05DC, 0x0080 ), }, /* Lexar */
953 +//{ USB_DEVICE( 0x4146, 0x9281 ), }, /* IOMEGA */
954 +//{ USB_DEVICE( 0x067b, 0x2507 ), }, /* Hammer 20GB External HD */
955 +{ USB_DEVICE( 0x0EA0, 0x2168 ), }, /* Ours Technology Inc. (BUFFALO ClipDrive)*/
956 +//{ USB_DEVICE( 0x0457, 0x0150 ), }, /* Silicon Integrated Systems Corp. */
959 +//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */
960 +//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */
963 +//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */
964 +//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */
966 { } /* Terminating entry */
969 +static inline void report_errors(struct usb_device *dev)
971 + /* OTG MESSAGE: report errors here, customize to match your product */
972 + dev_info(&dev->dev, "device Vendor:%04x Product:%04x is not supported\n",
973 + le16_to_cpu(dev->descriptor.idVendor),
974 + le16_to_cpu(dev->descriptor.idProduct));
975 + if (USB_CLASS_HUB == dev->descriptor.bDeviceClass){
976 + dev_printk(KERN_CRIT, &dev->dev, "Unsupported Hub Topology\n");
978 + dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n");
983 static int is_targeted(struct usb_device *dev)
985 struct usb_device_id *id = whitelist_table;
986 @@ -55,58 +104,83 @@ static int is_targeted(struct usb_device
989 /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
990 - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
991 - le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
993 + if (dev->descriptor.idVendor == 0x1a0a &&
994 + dev->descriptor.idProduct == 0xbadd) {
996 + } else if (!enable_whitelist) {
1000 - /* NOTE: can't use usb_match_id() since interface caches
1001 - * aren't set up yet. this is cut/paste from that code.
1003 - for (id = whitelist_table; id->match_flags; id++) {
1004 - if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
1005 - id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
1008 - if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
1009 - id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
1012 - /* No need to test id->bcdDevice_lo != 0, since 0 is never
1013 - greater than any unsigned number. */
1014 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
1015 - (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
1018 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
1019 - (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
1022 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
1023 - (id->bDeviceClass != dev->descriptor.bDeviceClass))
1026 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
1027 - (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
1030 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
1031 - (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
1034 + dev_dbg(&dev->dev, "device V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
1035 + dev->descriptor.idVendor,
1036 + dev->descriptor.idProduct,
1037 + dev->descriptor.bDeviceClass,
1038 + dev->descriptor.bDeviceSubClass,
1039 + dev->descriptor.bDeviceProtocol);
1043 + /* NOTE: can't use usb_match_id() since interface caches
1044 + * aren't set up yet. this is cut/paste from that code.
1046 + for (id = whitelist_table; id->match_flags; id++) {
1048 + dev_dbg(&dev->dev,
1049 + "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
1053 + id->bDeviceSubClass,
1054 + id->bDeviceProtocol);
1057 + if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
1058 + id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
1061 + if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
1062 + id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
1065 + /* No need to test id->bcdDevice_lo != 0, since 0 is never
1066 + greater than any unsigned number. */
1067 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
1068 + (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
1071 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
1072 + (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
1075 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
1076 + (id->bDeviceClass != dev->descriptor.bDeviceClass))
1079 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
1080 + (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
1083 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
1084 + (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
1091 /* add other match criteria here ... */
1094 - /* OTG MESSAGE: report errors here, customize to match your product */
1095 - dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
1096 - le16_to_cpu(dev->descriptor.idVendor),
1097 - le16_to_cpu(dev->descriptor.idProduct));
1098 #ifdef CONFIG_USB_OTG_WHITELIST
1099 + report_errors(dev);
1103 + if (enable_whitelist) {
1104 + report_errors(dev);
1112 --- a/drivers/usb/gadget/Kconfig
1113 +++ b/drivers/usb/gadget/Kconfig
1114 @@ -536,6 +536,34 @@ config USB_GADGET_SUPERSPEED
1116 depends on USB_GADGET_DUALSPEED
1118 +config USB_GADGET_SNPS_DWC_OTG
1119 + boolean "Synopsys Driver for DWC_otg Controller"
1120 + depends on USB && EXPERIMENTAL
1122 + select USB_GADGET_DUALSPEED
1124 + Selects the Synopsys Driver for the DWC_otg Controller.
1126 +config USB_DWC_OTG_LPM
1127 + boolean "Enable LPM support"
1128 + depends on USB && EXPERIMENTAL
1130 + Enables LPM support.
1132 +config USB_GADGET_SNPS_DWC_OTG
1133 + boolean "Synopsys Driver for DWC_otg Controller"
1134 + depends on USB && EXPERIMENTAL
1136 + select USB_GADGET_DUALSPEED
1138 + Selects the Synopsys Driver for the DWC_otg Controller.
1140 +config USB_DWC_OTG_LPM
1141 + boolean "Enable LPM support"
1142 + depends on USB && EXPERIMENTAL
1144 + Enables LPM support.
1147 # USB Gadget Drivers
1149 --- a/drivers/usb/gadget/file_storage.c
1150 +++ b/drivers/usb/gadget/file_storage.c
1151 @@ -573,8 +573,37 @@ config_desc = {
1152 .iConfiguration = FSG_STRING_CONFIG,
1153 .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
1154 .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
1155 + //.bMaxPower = 0, //unused suggestion by DWC patch
1158 +#ifdef CONFIG_USB_DWC_OTG_LPM
1159 +#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02
1160 +#define USB_20_EXT_LPM 0x02
1161 +typedef struct usb_dev_cap_20_ext_desc {
1163 + __u8 bDescriptorType;
1164 + __u8 bDevCapabilityType;
1165 + __le32 bmAttributes;
1166 +} __attribute__ ((__packed__)) usb_dev_cap_20_ext_desc_t;
1168 +static struct usb_bos_20_ext_desc {
1169 + struct usb_bos_descriptor bos_desc;
1170 + struct usb_dev_cap_20_ext_desc dev_cap_20_ext_desc;
1171 +} __attribute__ ((__packed__)) bos_20_ext_desc = {
1173 + .bLength = sizeof(struct usb_bos_descriptor),
1174 + .bDescriptorType = USB_DT_BOS,
1175 + .wTotalLength = sizeof(struct usb_bos_20_ext_desc),
1176 + .bNumDeviceCaps = 1,
1179 + .bLength = sizeof(struct usb_dev_cap_20_ext_desc),
1180 + .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
1181 + .bDevCapabilityType = USB_DEVICE_CAPABILITY_20_EXTENSION,
1182 + .bmAttributes = USB_20_EXT_LPM,
1187 static struct usb_qualifier_descriptor
1189 @@ -989,6 +1018,24 @@ get_config:
1190 if (gadget_is_superspeed(fsg->gadget))
1191 value = populate_bos(fsg, req->buf);
1193 +#ifdef CONFIG_USB_DWC_OTG_LPM
1195 + /* When the PCD has LPM enabled set the LPM
1196 + * Feature bit to 1 when not enabled set the
1198 + if (usb_gadget_test_lpm_support(fsg->gadget)) {
1199 + VDBG(fsg, "LPM support enabled in DWC UDC PCD\n");
1200 + bos_20_ext_desc.dev_cap_20_ext_desc.bmAttributes |= USB_20_EXT_LPM;
1202 + VDBG(fsg, "LPM support disabled in DWC UDC PCD\n");
1203 + bos_20_ext_desc.dev_cap_20_ext_desc.bmAttributes &= ~USB_20_EXT_LPM;
1205 + DBG(fsg, "sending BOS descriptor to host\n");
1206 + value = sizeof bos_20_ext_desc;
1207 + memcpy(req->buf, &bos_20_ext_desc, value);
1214 @@ -2650,6 +2697,9 @@ static int received_cbw(struct fsg_dev *
1215 fsg_set_halt(fsg, fsg->bulk_out);
1216 halt_bulk_in_endpoint(fsg);
1218 + fsg->bulk_in->ops->set_halt(fsg->bulk_in, 3);
1219 + fsg_set_halt(fsg, fsg->bulk_out);
1220 + fsg->bulk_out->ops->set_halt(fsg->bulk_out, 3);
1224 @@ -3011,7 +3061,8 @@ static void handle_exception(struct fsg_
1225 * bulk endpoint, clear the halt now. (The SuperH UDC
1226 * requires this.) */
1227 if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
1228 - usb_ep_clear_halt(fsg->bulk_in);
1229 + //usb_ep_clear_halt(fsg->bulk_in); //DWC patch:
1230 + fsg->bulk_in->ops->set_halt(fsg->bulk_in, 2);
1232 if (transport_is_bbb()) {
1233 if (fsg->ep0_req_tag == exception_req_tag)
1234 @@ -3085,6 +3136,9 @@ static int fsg_main_thread(void *fsg_)
1235 * that expects a __user pointer and it will work okay. */
1238 + /* Setting this thread high priority */
1239 + set_user_nice(current, -20);
1242 while (fsg->state != FSG_STATE_TERMINATED) {
1243 if (exception_in_progress(fsg) || signal_pending(current)) {
1244 @@ -3232,6 +3286,13 @@ static int __init check_parameters(struc
1245 gcnum = usb_gadget_controller_number(fsg->gadget);
1247 mod_data.release = 0x0300 + gcnum;
1248 + else if (gadget_is_dwc_otg(fsg->gadget)) {
1249 + mod_data.release = __constant_cpu_to_le16 (0x0200);
1250 + mod_data.vendor = __constant_cpu_to_le16 (0x053f);
1251 + if (mod_data.product == DRIVER_PRODUCT_ID) {
1252 + mod_data.product = __constant_cpu_to_le16 (0x0000);
1256 WARNING(fsg, "controller '%s' not recognized\n",
1258 @@ -3493,6 +3554,13 @@ static int __init fsg_bind(struct usb_ga
1262 +#ifdef CONFIG_USB_DWC_OTG_LPM
1263 + /* When LPM is enabled, Inform the host that the remote wake
1264 + * up capability is supported. */
1265 + if (usb_gadget_test_lpm_support(fsg->gadget))
1266 + config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
1269 /* Allocate the request and buffer for endpoint 0 */
1270 fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
1272 --- a/drivers/usb/host/Kconfig
1273 +++ b/drivers/usb/host/Kconfig
1274 @@ -571,6 +571,19 @@ config USB_HWA_HCD
1275 To compile this driver a module, choose M here: the module
1276 will be called "hwa-hc".
1279 + tristate "Synopsis DWC host support"
1282 + The Synopsis DWC controller is a dual-role
1283 + host/peripheral/OTG ("On The Go") USB controllers.
1285 + Enable this option to support this IP in host controller mode.
1288 + To compile this driver as a module, choose M here: the
1289 + modules built will be called dwc_otg and dwc_common_port.
1291 config USB_IMX21_HCD
1292 tristate "i.MX21 HCD support"
1293 depends on USB && ARM && ARCH_MXC
1294 --- a/drivers/usb/host/Makefile
1295 +++ b/drivers/usb/host/Makefile
1296 @@ -33,6 +33,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
1297 obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
1298 obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
1299 obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
1301 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/
1302 obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
1303 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
1304 obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
1306 +++ b/drivers/usb/host/dwc_common_port/Makefile
1309 +# Makefile for DWC_common library
1312 +ifneq ($(KERNELRELEASE),)
1314 +#CPPFLAGS += -DDEBUG_MEMORY
1316 +CPPFLAGS += -DDEBUG
1317 +CPPFLAGS += -DDWC_LINUX
1319 +obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o
1320 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
1321 + dwc_crypto.o dwc_notifier.o \
1322 + dwc_common_linux.o dwc_mem.o
1324 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
1325 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
1327 +ifneq ($(kernrel3),2.6.20)
1328 +# grayg - I only know that we use EXTRA_CFLAGS in 2.6.31 actually
1329 +EXTRA_CFLAGS += $(CPPFLAGS)
1335 +DOXYGEN := $(DOXYGEN)
1339 + $(MAKE) -C$(KDIR) M=$(PWD) modules
1341 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
1342 + $(DOXYGEN) doc/doxygen.cfg
1344 +tags: $(wildcard *.[hc])
1345 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
1350 + rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers
1353 +++ b/drivers/usb/host/dwc_common_port/Makefile.linux
1356 +# Makefile for DWC_common library
1358 +ifneq ($(KERNELRELEASE),)
1360 +#CPPFLAGS += -DDEBUG_MEMORY
1362 +#CPPFLAGS += -DDEBUG
1363 +CPPFLAGS += -DDWC_LINUX
1365 +obj-m := dwc_common_port_lib.o
1366 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
1367 + dwc_crypto.o dwc_notifier.o \
1368 + dwc_common_linux.o dwc_mem.o
1374 +DOXYGEN := $(DOXYGEN)
1378 + $(MAKE) -C$(KDIR) M=$(PWD) modules
1380 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
1381 + $(DOXYGEN) doc/doxygen.cfg
1383 +tags: $(wildcard *.[hc])
1384 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
1389 + rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers
1392 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.c
1394 +/* =========================================================================
1395 + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_cc.c $
1397 + * $Date: 2008/12/21 $
1398 + * $Change: 1156609 $
1400 + * Synopsys Portability Library Software and documentation
1401 + * (hereinafter, "Software") is an Unsupported proprietary work of
1402 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
1403 + * between Synopsys and you.
1405 + * The Software IS NOT an item of Licensed Software or Licensed Product
1406 + * under any End User Software License Agreement or Agreement for
1407 + * Licensed Product with Synopsys or any supplement thereto. You are
1408 + * permitted to use and redistribute this Software in source and binary
1409 + * forms, with or without modification, provided that redistributions
1410 + * of source code must retain this notice. You may not view, use,
1411 + * disclose, copy or distribute this file or any information contained
1412 + * herein except pursuant to this license grant from Synopsys. If you
1413 + * do not agree with this notice, including the disclaimer below, then
1414 + * you are not authorized to use the Software.
1416 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
1417 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1418 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
1419 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
1420 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
1421 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1422 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1423 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1424 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1425 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1426 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1428 + * ========================================================================= */
1429 +#include "dwc_cc.h"
1431 +typedef struct dwc_cc
1439 + DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
1442 +DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
1444 +/** The main structure for CC management. */
1447 + dwc_mutex_t *mutex;
1450 + unsigned is_host:1;
1452 + dwc_notifier_t *notifier;
1454 + struct context_list list;
1458 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
1461 + DWC_PRINTF("%s: ", name);
1462 + for (i=0; i<len; i++) {
1463 + DWC_PRINTF("%02x ", bytes[i]);
1468 +#define dump_bytes(x...)
1471 +static dwc_cc_t *alloc_cc(uint8_t *name, uint32_t length)
1473 + dwc_cc_t *cc = DWC_ALLOC(sizeof(dwc_cc_t));
1477 + DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
1480 + cc->length = length;
1481 + cc->name = DWC_ALLOC(length);
1482 + DWC_MEMCPY(cc->name, name, length);
1488 +static void free_cc(dwc_cc_t *cc)
1491 + DWC_FREE(cc->name);
1496 +static uint32_t next_uid(dwc_cc_if_t *cc_if)
1500 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
1501 + if (cc->uid > uid) {
1513 +static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
1516 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
1517 + if (cc->uid == uid) {
1524 +static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
1526 + unsigned int size = 0;
1528 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
1531 + size += cc->length;
1537 +static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
1542 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
1543 + if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
1550 +static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
1555 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
1556 + if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
1564 +/* Internal cc_add */
1565 +static int32_t cc_add(dwc_cc_if_t *cc_if, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
1570 + if (cc_if->is_host) {
1571 + uid = cc_match_cdid(cc_if, cdid);
1574 + uid = cc_match_chid(cc_if, chid);
1578 + DWC_DEBUG("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
1579 + cc = cc_find(cc_if, uid);
1582 + cc = alloc_cc(name, length);
1583 + cc->uid = next_uid(cc_if);
1584 + DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
1587 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
1588 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
1589 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
1591 + DWC_DEBUG("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
1592 + dump_bytes("CHID", cc->chid, 16);
1593 + dump_bytes("CDID", cc->cdid, 16);
1594 + dump_bytes("CK", cc->ck, 16);
1598 +/* Internal cc_clear */
1599 +static void cc_clear(dwc_cc_if_t *cc_if)
1601 + while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
1602 + dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
1603 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
1608 +dwc_cc_if_t *dwc_cc_if_alloc(dwc_notifier_t *notifier, unsigned is_host)
1610 + dwc_cc_if_t *cc_if = NULL;
1612 + /* Allocate a common_cc_if structure */
1613 + cc_if = DWC_ALLOC(sizeof(dwc_cc_if_t));
1618 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
1619 + DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
1621 + cc_if->mutex = DWC_MUTEX_ALLOC();
1623 + DWC_CIRCLEQ_INIT(&cc_if->list);
1624 + cc_if->is_host = is_host;
1625 + cc_if->notifier = notifier;
1629 +void dwc_cc_if_free(dwc_cc_if_t *cc_if)
1631 + DWC_MUTEX_FREE(cc_if->mutex);
1636 +static void cc_changed(dwc_cc_if_t *cc_if)
1638 + if (cc_if->notifier) {
1639 + dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
1643 +void dwc_cc_clear(dwc_cc_if_t *cc_if)
1645 + DWC_MUTEX_LOCK(cc_if->mutex);
1647 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1648 + cc_changed(cc_if);
1651 +int32_t dwc_cc_add(dwc_cc_if_t *cc_if, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
1655 + DWC_MUTEX_LOCK(cc_if->mutex);
1656 + uid = cc_add(cc_if, chid, cdid, ck, name, length);
1657 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1658 + cc_changed(cc_if);
1663 +void dwc_cc_change(dwc_cc_if_t *cc_if, int32_t id,
1664 + uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
1668 + DWC_DEBUG("Change connection context %d", id);
1670 + DWC_MUTEX_LOCK(cc_if->mutex);
1671 + cc = cc_find(cc_if, id);
1673 + DWC_ERROR("Uid %d not found in cc list", id);
1674 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1679 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
1682 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
1685 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
1690 + DWC_FREE(cc->name);
1692 + cc->name = DWC_ALLOC(length);
1693 + cc->length = length;
1694 + DWC_MEMCPY(cc->name, name, length);
1697 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1699 + cc_changed(cc_if);
1701 + DWC_DEBUG("Changed connection context id=%d\n", id);
1702 + dump_bytes("New CHID", cc->chid, 16);
1703 + dump_bytes("New CDID", cc->cdid, 16);
1704 + dump_bytes("New CK", cc->ck, 16);
1707 +void dwc_cc_remove(dwc_cc_if_t *cc_if, int32_t id)
1711 + DWC_DEBUG("Removing connection context %d", id);
1713 + DWC_MUTEX_LOCK(cc_if->mutex);
1714 + cc = cc_find(cc_if, id);
1716 + DWC_ERROR("Uid %d not found in cc list", id);
1717 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1721 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
1722 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1725 + cc_changed(cc_if);
1728 +uint8_t *dwc_cc_data_for_save(dwc_cc_if_t *cc_if, unsigned int *length)
1734 + DWC_MUTEX_LOCK(cc_if->mutex);
1735 + *length = cc_data_size(cc_if);
1737 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1741 + DWC_DEBUG("Creating data for saving (length=%d)", *length);
1743 + buf = DWC_ALLOC(*length);
1746 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1751 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
1752 + DWC_MEMCPY(x, cc->chid, 16);
1754 + DWC_MEMCPY(x, cc->cdid, 16);
1756 + DWC_MEMCPY(x, cc->ck, 16);
1759 + DWC_MEMCPY(x, &cc->length, 1);
1761 + DWC_MEMCPY(x, cc->name, cc->length);
1765 + DWC_MEMCPY(x, &zero, 1);
1769 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1774 +void dwc_cc_restore_from_data(dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
1776 + uint8_t name_length;
1783 + DWC_MUTEX_LOCK(cc_if->mutex);
1786 + while (i < length) {
1794 + name_length = data[i];
1797 + if (name_length) {
1805 + /* check to see if we haven't overflown the buffer */
1807 + DWC_ERROR("Data format error while attempting to load CCs "
1808 + "(nlen=%d, iter=%d, buflen=%d).", name_length, i, length);
1812 + cc_add(cc_if, chid, cdid, ck, name, name_length);
1814 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1816 + cc_changed(cc_if);
1819 +uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
1823 + DWC_MUTEX_LOCK(cc_if->mutex);
1824 + uid = cc_match_chid(cc_if, chid);
1825 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1828 +uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
1832 + DWC_MUTEX_LOCK(cc_if->mutex);
1833 + uid = cc_match_cdid(cc_if, cdid);
1834 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1838 +uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
1840 + uint8_t *ck = NULL;
1843 + DWC_MUTEX_LOCK(cc_if->mutex);
1844 + cc = cc_find(cc_if, id);
1848 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1854 +uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
1856 + uint8_t *retval = NULL;
1859 + DWC_MUTEX_LOCK(cc_if->mutex);
1860 + cc = cc_find(cc_if, id);
1862 + retval = cc->chid;
1864 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1869 +uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
1871 + uint8_t *retval = NULL;
1874 + DWC_MUTEX_LOCK(cc_if->mutex);
1875 + cc = cc_find(cc_if, id);
1877 + retval = cc->cdid;
1879 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1884 +uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
1886 + uint8_t *retval = NULL;
1889 + DWC_MUTEX_LOCK(cc_if->mutex);
1891 + cc = cc_find(cc_if, id);
1893 + *length = cc->length;
1894 + retval = cc->name;
1896 + DWC_MUTEX_UNLOCK(cc_if->mutex);
1901 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.h
1903 +/* =========================================================================
1904 + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_cc.h $
1906 + * $Date: 2008/12/21 $
1907 + * $Change: 1156609 $
1909 + * Synopsys Portability Library Software and documentation
1910 + * (hereinafter, "Software") is an Unsupported proprietary work of
1911 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
1912 + * between Synopsys and you.
1914 + * The Software IS NOT an item of Licensed Software or Licensed Product
1915 + * under any End User Software License Agreement or Agreement for
1916 + * Licensed Product with Synopsys or any supplement thereto. You are
1917 + * permitted to use and redistribute this Software in source and binary
1918 + * forms, with or without modification, provided that redistributions
1919 + * of source code must retain this notice. You may not view, use,
1920 + * disclose, copy or distribute this file or any information contained
1921 + * herein except pursuant to this license grant from Synopsys. If you
1922 + * do not agree with this notice, including the disclaimer below, then
1923 + * you are not authorized to use the Software.
1925 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
1926 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1927 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
1928 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
1929 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
1930 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1931 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1932 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1933 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1934 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1935 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1937 + * ========================================================================= */
1943 + * This file defines the Context Context library.
1945 + * The main data structure is dwc_cc_if_t which is returned by either the
1946 + * dwc_cc_if_alloc function or returned by the module to the user via a provided
1947 + * function. The data structure is opaque and should only be manipulated via the
1948 + * functions provied in this API.
1950 + * It manages a list of connection contexts and operations can be performed to
1951 + * add, remove, query, search, and change, those contexts. Additionally,
1952 + * a dwc_notifier_t object can be requested from the manager so that
1953 + * the user can be notified whenever the context list has changed.
1956 +#include "dwc_os.h"
1957 +#include "dwc_list.h"
1958 +#include "dwc_notifier.h"
1961 +/* Notifications */
1962 +#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
1965 +typedef struct dwc_cc_if dwc_cc_if_t;
1968 +/** @name Connection Context Operations */
1971 +/** This function allocates memory for a dwc_cc_if_t structure, initializes
1972 + * fields to default values, and returns a pointer to the structure or NULL on
1974 +extern dwc_cc_if_t *dwc_cc_if_alloc(dwc_notifier_t *notifier, unsigned is_host);
1976 +/** Frees the memory for the specified CC structure allocated from
1977 + * dwc_cc_if_alloc(). */
1978 +extern void dwc_cc_if_free(dwc_cc_if_t *cc_if);
1980 +/** Removes all contexts from the connection context list */
1981 +extern void dwc_cc_clear(dwc_cc_if_t *cc_if);
1983 +/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
1984 + * If a CHID already exists, the CK and name are overwritten. Statistics are
1985 + * not overwritten.
1987 + * @param cc_if The cc_if structure.
1988 + * @param chid A pointer to the 16-byte CHID. This value will be copied.
1989 + * @param ck A pointer to the 16-byte CK. This value will be copied.
1990 + * @param cdid A pointer to the 16-byte CDID. This value will be copied.
1991 + * @param name An optional host friendly name as defined in the association model
1992 + * spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name.
1993 + * @param length The length othe unicode string.
1994 + * @return A unique identifier used to refer to this context that is valid for
1995 + * as long as this context is still in the list. */
1996 +extern int32_t dwc_cc_add(dwc_cc_if_t *cc_if, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length);
1998 +/** Changes the CHID, CK, CDID, or Name values of a connection context in the
1999 + * list, preserving any accumulated statistics. This would typically be called
2000 + * if the host decideds to change the context with a SET_CONNECTION request.
2002 + * @param cc_if The cc_if structure.
2003 + * @param id The identifier of the connection context.
2004 + * @param chid A pointer to the 16-byte CHID. This value will be copied. NULL
2005 + * indicates no change.
2006 + * @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL
2007 + * indicates no change.
2008 + * @param ck A pointer to the 16-byte CK. This value will be copied. NULL
2009 + * indicates no change.
2010 + * @param name Host friendly name UTF16-LE. NULL indicates no change.
2011 + * @param length Length of name. */
2012 +extern void dwc_cc_change(dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length);
2014 +/** Remove the specified connection context.
2015 + * @param cc_if The cc_if structure.
2016 + * @param id The identifier of the connection context to remove. */
2017 +extern void dwc_cc_remove(dwc_cc_if_t *cc_if, int32_t id);
2019 +/** Get a binary block of data for the connection context list and attributes.
2020 + * This data can be used by the OS specific driver to save the connection
2021 + * context list into non-volatile memory.
2023 + * @param cc_if The cc_if structure.
2024 + * @param length Return the length of the data buffer.
2025 + * @return A pointer to the data buffer. The memory for this buffer should be freed with DWC_FREE() after use. */
2026 +extern uint8_t *dwc_cc_data_for_save(dwc_cc_if_t *cc_if, unsigned int *length);
2028 +/** Restore the connection context list from the binary data that was previously
2029 + * returned from a call to dwc_cc_data_for_save. This can be used by the OS specific
2030 + * driver to load a connection context list from non-volatile memory.
2032 + * @param cc_if The cc_if structure.
2033 + * @param data The data bytes as returned from dwc_cc_data_for_save.
2034 + * @param length The length of the data. */
2035 +extern void dwc_cc_restore_from_data(dwc_cc_if_t *cc_if, uint8_t *data, unsigned int length);
2037 +/** Find the connection context from the specified CHID.
2039 + * @param cc_if The cc_if structure.
2040 + * @param chid A pointer to the CHID data.
2041 + * @return A non-zero identifier of the connection context if the CHID matches.
2042 + * Otherwise returns 0. */
2043 +extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
2045 +/** Find the connection context from the specified CDID.
2047 + * @param cc_if The cc_if structure.
2048 + * @param cdid A pointer to the CDID data.
2049 + * @return A non-zero identifier of the connection context if the CHID matches.
2050 + * Otherwise returns 0. */
2051 +extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
2053 +/** Retrieve the CK from the specified connection context.
2055 + * @param cc_if The cc_if structure.
2056 + * @param id The identifier of the connection context.
2057 + * @return A pointer to the CK data. The memory does not need to be freed. */
2058 +extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
2060 +/** Retrieve the CHID from the specified connection context.
2062 + * @param cc_if The cc_if structure.
2063 + * @param id The identifier of the connection context.
2064 + * @return A pointer to the CHID data. The memory does not need to be freed. */
2065 +extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
2067 +/** Retrieve the CDID from the specified connection context.
2069 + * @param cc_if The cc_if structure.
2070 + * @param id The identifier of the connection context.
2071 + * @return A pointer to the CDID data. The memory does not need to be freed. */
2072 +extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
2074 +extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
2076 +/** Checks a buffer for non-zero.
2077 + * @param id A pointer to a 16 byte buffer.
2078 + * @return true if the 16 byte value is non-zero. */
2079 +static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
2081 + for (i=0; i<16; i++) {
2082 + if (id[i]) return 1;
2087 +/** Checks a buffer for zero.
2088 + * @param id A pointer to a 16 byte buffer.
2089 + * @return true if the 16 byte value is zero. */
2090 +static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
2091 + return !dwc_assoc_is_not_zero_id(id);
2094 +/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
2096 +static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
2097 + char *ptr = buffer;
2099 + for (i=0; i<16; i++) {
2100 + ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
2102 + ptr += DWC_SPRINTF(ptr, " ");
2105 + return ptr - buffer;
2110 +#endif /* _DWC_CC_H_ */
2113 +++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
2115 +#include "dwc_cc.h"
2116 +#include "dwc_modpow.h"
2117 +#include "dwc_dh.h"
2118 +#include "dwc_crypto.h"
2119 +#include "dwc_notifier.h"
2121 +#include <linux/kernel.h>
2122 +#include <linux/init.h>
2123 +#include <linux/module.h>
2124 +#include <linux/kthread.h>
2126 +MODULE_DESCRIPTION("DWC Common Library - Portable version");
2127 +MODULE_AUTHOR("Synopsys Inc.");
2128 +MODULE_LICENSE ("GPL");
2130 +static int dwc_common_port_init_module(void)
2132 + printk( KERN_DEBUG "Module dwc_common_port init\n" );
2133 +#ifdef DEBUG_MEMORY
2134 + dwc_memory_debug_start();
2136 + dwc_alloc_notification_manager();
2140 +static void dwc_common_port_exit_module(void)
2142 + printk( KERN_DEBUG "Module dwc_common_port exit\n" );
2143 + dwc_free_notification_manager();
2144 +#ifdef DEBUG_MEMORY
2145 + dwc_memory_debug_stop();
2149 +module_init(dwc_common_port_init_module);
2150 +module_exit(dwc_common_port_exit_module);
2153 +EXPORT_SYMBOL(dwc_cc_if_alloc);
2154 +EXPORT_SYMBOL(dwc_cc_if_free);
2155 +EXPORT_SYMBOL(dwc_cc_clear);
2156 +EXPORT_SYMBOL(dwc_cc_add);
2157 +EXPORT_SYMBOL(dwc_cc_remove);
2158 +EXPORT_SYMBOL(dwc_cc_change);
2159 +EXPORT_SYMBOL(dwc_cc_data_for_save);
2160 +EXPORT_SYMBOL(dwc_cc_restore_from_data);
2161 +EXPORT_SYMBOL(dwc_cc_match_chid);
2162 +EXPORT_SYMBOL(dwc_cc_match_cdid);
2163 +EXPORT_SYMBOL(dwc_cc_ck);
2164 +EXPORT_SYMBOL(dwc_cc_chid);
2165 +EXPORT_SYMBOL(dwc_cc_cdid);
2166 +EXPORT_SYMBOL(dwc_cc_name);
2168 +#ifndef CONFIG_MACH_IPMATE
2170 +EXPORT_SYMBOL(dwc_modpow);
2172 +EXPORT_SYMBOL(dwc_dh_modpow);
2173 +EXPORT_SYMBOL(dwc_dh_derive_keys);
2174 +EXPORT_SYMBOL(dwc_dh_pk);
2175 +#endif /* CONFIG_MACH_IPMATE */
2177 +EXPORT_SYMBOL(dwc_wusb_aes_encrypt);
2178 +EXPORT_SYMBOL(dwc_wusb_cmf);
2179 +EXPORT_SYMBOL(dwc_wusb_prf);
2180 +EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce);
2181 +EXPORT_SYMBOL(dwc_wusb_gen_nonce);
2182 +EXPORT_SYMBOL(dwc_wusb_gen_key);
2183 +EXPORT_SYMBOL(dwc_wusb_gen_mic);
2187 +EXPORT_SYMBOL(dwc_alloc_notification_manager);
2188 +EXPORT_SYMBOL(dwc_free_notification_manager);
2189 +EXPORT_SYMBOL(dwc_register_notifier);
2190 +EXPORT_SYMBOL(dwc_unregister_notifier);
2191 +EXPORT_SYMBOL(dwc_add_observer);
2192 +EXPORT_SYMBOL(dwc_remove_observer);
2193 +EXPORT_SYMBOL(dwc_notify);
2195 +/* Memory Debugging Routines */
2196 +#ifdef DEBUG_MEMORY
2197 +EXPORT_SYMBOL(dwc_alloc_debug);
2198 +EXPORT_SYMBOL(dwc_alloc_atomic_debug);
2199 +EXPORT_SYMBOL(dwc_free_debug);
2200 +EXPORT_SYMBOL(dwc_dma_alloc_debug);
2201 +EXPORT_SYMBOL(dwc_dma_alloc_atomic_debug);
2202 +EXPORT_SYMBOL(dwc_dma_free_debug);
2205 +/* OS-Level Implementations */
2207 +/* This is the Linux kernel implementation of the DWC platform library. */
2208 +#include <linux/kernel.h>
2209 +#include <linux/init.h>
2210 +#include <linux/module.h>
2211 +#include <linux/moduleparam.h>
2212 +#include <linux/ctype.h>
2213 +#include <linux/crypto.h>
2214 +#include <linux/delay.h>
2215 +#include <linux/device.h>
2216 +#include <linux/dma-mapping.h>
2217 +#include <linux/cdev.h>
2218 +#include <linux/errno.h>
2219 +#include <linux/interrupt.h>
2220 +#include <linux/jiffies.h>
2221 +#include <linux/list.h>
2222 +#include <linux/pci.h>
2223 +#include <linux/slab.h>
2224 +#include <linux/stat.h>
2225 +#include <linux/string.h>
2226 +#include <linux/timer.h>
2227 +#include <linux/version.h>
2228 +#include <linux/usb.h>
2229 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
2230 +#include <linux/usb_gadget.h>
2232 +#include <linux/usb/gadget.h>
2234 +#include <linux/random.h>
2235 +#include <asm/io.h>
2236 +#include <asm/page.h>
2237 +#include <asm/uaccess.h>
2238 +#include <asm/unaligned.h>
2239 +#include <asm/page.h>
2240 +#include <linux/scatterlist.h>
2244 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
2246 + return memset(dest, byte, size);
2248 +EXPORT_SYMBOL(DWC_MEMSET);
2250 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
2252 + return memcpy(dest, src, size);
2254 +EXPORT_SYMBOL(DWC_MEMCPY);
2256 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
2258 + return memmove(dest, src, size);
2260 +EXPORT_SYMBOL(DWC_MEMMOVE);
2262 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
2264 + return memcmp(m1, m2, size);
2266 +EXPORT_SYMBOL(DWC_MEMCMP);
2268 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
2270 + return strncmp(s1, s2, size);
2272 +EXPORT_SYMBOL(DWC_STRNCMP);
2274 +int DWC_STRCMP(void *s1, void *s2)
2276 + return strcmp(s1, s2);
2278 +EXPORT_SYMBOL(DWC_STRCMP);
2280 +int DWC_STRLEN(char const *str)
2282 + return strlen(str);
2284 +EXPORT_SYMBOL(DWC_STRLEN);
2286 +char *DWC_STRCPY(char *to, const char *from)
2288 + return strcpy(to, from);
2290 +EXPORT_SYMBOL(DWC_STRCPY);
2292 +char *DWC_STRDUP(char const *str)
2294 + int len = DWC_STRLEN(str) + 1;
2295 + char *new = DWC_ALLOC_ATOMIC(len);
2299 + DWC_MEMCPY(new, str, len);
2302 +EXPORT_SYMBOL(DWC_STRDUP);
2304 +int DWC_ATOI(char *str, int32_t *value)
2307 + *value = simple_strtol(str, &end, 0);
2308 + if (*end == '\0') {
2313 +EXPORT_SYMBOL(DWC_ATOI);
2315 +int DWC_ATOUI(char *str, uint32_t *value)
2318 + *value = simple_strtoul(str, &end, 0);
2319 + if (*end == '\0') {
2324 +EXPORT_SYMBOL(DWC_ATOUI);
2327 +/* From usbstring.c */
2328 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
2334 + /* this insists on correct encodings, though not minimal ones.
2335 + * BUT it currently rejects legit 4-byte UTF-8 code points,
2336 + * which need surrogate pairs. (Unicode 3.1 can use them.)
2338 + while (len != 0 && (c = (u8) *s++) != 0) {
2339 + if (unlikely(c & 0x80)) {
2340 + // 2-byte sequence:
2341 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
2342 + if ((c & 0xe0) == 0xc0) {
2343 + uchar = (c & 0x1f) << 6;
2346 + if ((c & 0xc0) != 0xc0)
2351 + // 3-byte sequence (most CJKV characters):
2352 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
2353 + } else if ((c & 0xf0) == 0xe0) {
2354 + uchar = (c & 0x0f) << 12;
2357 + if ((c & 0xc0) != 0xc0)
2363 + if ((c & 0xc0) != 0xc0)
2368 + /* no bogus surrogates */
2369 + if (0xd800 <= uchar && uchar <= 0xdfff)
2372 + // 4-byte sequence (surrogate pairs, currently rare):
2373 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
2374 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
2375 + // (uuuuu = wwww + 1)
2376 + // FIXME accept the surrogate code points (only)
2382 + put_unaligned (cpu_to_le16 (uchar), cp++);
2390 +EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE);
2394 +dwc_bool_t DWC_IN_IRQ(void)
2398 +EXPORT_SYMBOL(DWC_IN_IRQ);
2400 +int DWC_IN_BH(void)
2402 + return in_softirq();
2404 +EXPORT_SYMBOL(DWC_IN_BH);
2406 +void DWC_VPRINTF(char *format, va_list args)
2408 + vprintk(format, args);
2410 +EXPORT_SYMBOL(DWC_VPRINTF);
2412 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
2414 + return vsnprintf(str, size, format, args);
2417 +void DWC_PRINTF(char *format, ...)
2420 + va_start(args, format);
2421 + DWC_VPRINTF(format, args);
2424 +EXPORT_SYMBOL(DWC_PRINTF);
2426 +int DWC_SPRINTF(char *buffer, char *format, ...)
2430 + va_start(args, format);
2431 + retval = vsprintf(buffer, format, args);
2435 +EXPORT_SYMBOL(DWC_SPRINTF);
2437 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
2441 + va_start(args, format);
2442 + retval = vsnprintf(buffer, size, format, args);
2446 +EXPORT_SYMBOL(DWC_SNPRINTF);
2448 +void __DWC_WARN(char *format, ...)
2451 + va_start(args, format);
2452 + DWC_PRINTF(KERN_WARNING);
2453 + DWC_VPRINTF(format, args);
2456 +EXPORT_SYMBOL(__DWC_WARN);
2458 +void __DWC_ERROR(char *format, ...)
2461 + va_start(args, format);
2462 + DWC_PRINTF(KERN_ERR);
2463 + DWC_VPRINTF(format, args);
2466 +EXPORT_SYMBOL(__DWC_ERROR);
2468 +void DWC_EXCEPTION(char *format, ...)
2471 + va_start(args, format);
2472 + DWC_PRINTF(KERN_ERR);
2473 + DWC_VPRINTF(format, args);
2477 +EXPORT_SYMBOL(DWC_EXCEPTION);
2480 +void __DWC_DEBUG(char *format, ...)
2483 + va_start(args, format);
2484 + DWC_PRINTF(KERN_DEBUG);
2485 + DWC_VPRINTF(format, args);
2488 +EXPORT_SYMBOL(__DWC_DEBUG);
2496 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
2500 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
2501 + size, align, alloc);
2502 + return (dwc_pool_t *)pool;
2505 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
2507 + dma_pool_destroy((struct dma_pool *)pool);
2510 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, U64 *dma_addr)
2512 + return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
2515 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, U64 *dma_addr)
2517 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
2521 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
2523 + dma_pool_free(pool, vaddr, daddr);
2528 +void *__DWC_DMA_ALLOC(uint32_t size, dwc_dma_t *dma_addr)
2530 + void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_KERNEL);
2534 + memset(buf, 0, (size_t)size);
2537 +EXPORT_SYMBOL(__DWC_DMA_ALLOC);
2539 +void __DWC_DMA_FREE(uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
2541 + dma_free_coherent(NULL, size, virt_addr, dma_addr);
2543 +EXPORT_SYMBOL(__DWC_DMA_FREE);
2545 +void *__DWC_DMA_ALLOC_ATOMIC(uint32_t size, dwc_dma_t *dma_addr)
2547 + void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC);
2551 + memset(buf, 0, (size_t)size);
2554 +EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC);
2556 +void *__DWC_ALLOC(uint32_t size)
2558 + return kzalloc(size, GFP_KERNEL);
2560 +EXPORT_SYMBOL(__DWC_ALLOC);
2562 +void *__DWC_ALLOC_ATOMIC(uint32_t size)
2564 + return kzalloc(size, GFP_ATOMIC);
2566 +EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC);
2568 +void __DWC_FREE(void *addr)
2572 +EXPORT_SYMBOL(__DWC_FREE);
2576 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
2578 + get_random_bytes(buffer, length);
2580 +EXPORT_SYMBOL(DWC_RANDOM_BYTES);
2582 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
2584 + struct crypto_blkcipher *tfm;
2585 + struct blkcipher_desc desc;
2586 + struct scatterlist sgd;
2587 + struct scatterlist sgs;
2589 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
2590 + if (tfm == NULL) {
2591 + printk("failed to load transform for aes CBC\n");
2595 + crypto_blkcipher_setkey(tfm, key, keylen);
2596 + crypto_blkcipher_set_iv(tfm, iv, 16);
2598 + sg_init_one(&sgd, out, messagelen);
2599 + sg_init_one(&sgs, message, messagelen);
2604 + if(crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
2605 + crypto_free_blkcipher(tfm);
2606 + DWC_ERROR("AES CBC encryption failed");
2610 + crypto_free_blkcipher(tfm);
2613 +EXPORT_SYMBOL(DWC_AES_CBC);
2615 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
2617 + struct crypto_hash *tfm;
2618 + struct hash_desc desc;
2619 + struct scatterlist sg;
2621 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
2622 + if (IS_ERR(tfm)) {
2623 + DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm));
2629 + sg_init_one(&sg, message, len);
2630 + crypto_hash_digest(&desc, &sg, len, out);
2631 + crypto_free_hash(tfm);
2635 +EXPORT_SYMBOL(DWC_SHA256);
2637 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
2638 + uint8_t *key, uint32_t keylen, uint8_t *out)
2640 + struct crypto_hash *tfm;
2641 + struct hash_desc desc;
2642 + struct scatterlist sg;
2644 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
2645 + if (IS_ERR(tfm)) {
2646 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm));
2652 + sg_init_one(&sg, message, messagelen);
2653 + crypto_hash_setkey(tfm, key, keylen);
2654 + crypto_hash_digest(&desc, &sg, messagelen, out);
2655 + crypto_free_hash(tfm);
2659 +EXPORT_SYMBOL(DWC_HMAC_SHA256);
2661 +/* Byte Ordering Conversions. */
2662 +uint32_t DWC_CPU_TO_LE32(void *p)
2664 +#ifdef __LITTLE_ENDIAN
2665 + return *((uint32_t *)p);
2667 + uint8_t *u_p = (uint8_t *)p;
2669 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
2672 +EXPORT_SYMBOL(DWC_CPU_TO_LE32);
2674 +uint32_t DWC_CPU_TO_BE32(void *p)
2676 +#ifdef __BIG_ENDIAN
2677 + return *((uint32_t *)p);
2679 + uint8_t *u_p = (uint8_t *)p;
2681 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
2684 +EXPORT_SYMBOL(DWC_CPU_TO_BE32);
2686 +uint32_t DWC_LE32_TO_CPU(void *p)
2688 +#ifdef __LITTLE_ENDIAN
2689 + return *((uint32_t *)p);
2691 + uint8_t *u_p = (uint8_t *)p;
2693 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
2697 +EXPORT_SYMBOL(DWC_LE32_TO_CPU);
2699 +uint32_t DWC_BE32_TO_CPU(void *p)
2701 +#ifdef __BIG_ENDIAN
2702 + return *((uint32_t *)p);
2704 + uint8_t *u_p = (uint8_t *)p;
2706 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
2709 +EXPORT_SYMBOL(DWC_BE32_TO_CPU);
2711 +uint16_t DWC_CPU_TO_LE16(void *p)
2713 +#ifdef __LITTLE_ENDIAN
2714 + return *((uint16_t *)p);
2716 + uint8_t *u_p = (uint8_t *)p;
2717 + return (u_p[1] | (u_p[0] << 8));
2720 +EXPORT_SYMBOL(DWC_CPU_TO_LE16);
2722 +uint16_t DWC_CPU_TO_BE16(void *p)
2724 +#ifdef __BIG_ENDIAN
2725 + return *((uint16_t *)p);
2727 + uint8_t *u_p = (uint8_t *)p;
2728 + return (u_p[1] | (u_p[0] << 8));
2731 +EXPORT_SYMBOL(DWC_CPU_TO_BE16);
2733 +uint16_t DWC_LE16_TO_CPU(void *p)
2735 +#ifdef __LITTLE_ENDIAN
2736 + return *((uint16_t *)p);
2738 + uint8_t *u_p = (uint8_t *)p;
2739 + return (u_p[1] | (u_p[0] << 8));
2742 +EXPORT_SYMBOL(DWC_LE16_TO_CPU);
2744 +uint16_t DWC_BE16_TO_CPU(void *p)
2746 +#ifdef __BIG_ENDIAN
2747 + return *((uint16_t *p)p);
2749 + uint8_t *u_p = (uint8_t *)p;
2750 + return (u_p[1] | (u_p[0] << 8));
2753 +EXPORT_SYMBOL(DWC_BE16_TO_CPU);
2758 +uint32_t DWC_READ_REG32(uint32_t volatile *reg)
2760 + return readl(reg);
2762 +EXPORT_SYMBOL(DWC_READ_REG32);
2765 +uint64_t DWC_READ_REG64(uint64_t volatile *reg)
2770 +void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
2772 + writel(value, reg);
2774 +EXPORT_SYMBOL(DWC_WRITE_REG32);
2777 +void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
2782 +void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
2784 + writel( (readl(reg) & ~clear_mask) | set_mask, reg );
2786 +EXPORT_SYMBOL(DWC_MODIFY_REG32);
2789 +void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t value)
2798 +typedef struct work_container
2800 + dwc_work_callback_t cb;
2806 + DWC_CIRCLEQ_ENTRY(work_container) entry;
2809 + struct delayed_work work;
2810 +} work_container_t;
2813 +DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
2818 + struct workqueue_struct *wq;
2820 + dwc_spinlock_t *lock;
2821 + dwc_waitq_t *waitq;
2824 + struct work_container_queue entries;
2828 +static void do_work(struct work_struct *work)
2831 + struct delayed_work *dw = container_of(work, struct delayed_work, work);
2832 + work_container_t *container = container_of(dw, struct work_container, work);
2833 + dwc_workq_t *wq = container->wq;
2835 + container->cb(container->data);
2838 + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
2841 + if (container->name) {
2842 + DWC_DEBUG("Work done: %s, container=%p",
2843 + container->name, container); //GRAYG
2844 + DWC_FREE(container->name);
2846 + DWC_FREE(container);
2848 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
2850 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
2851 + DWC_WAITQ_TRIGGER(wq->waitq);
2854 +static int work_done(void *data)
2856 + dwc_workq_t *workq = (dwc_workq_t *)data;
2857 + return workq->pending == 0;
2860 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
2862 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
2864 +EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE);
2866 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
2868 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
2869 + wq->wq = create_singlethread_workqueue(name);
2871 + wq->lock = DWC_SPINLOCK_ALLOC();
2872 + wq->waitq = DWC_WAITQ_ALLOC();
2874 + DWC_CIRCLEQ_INIT(&wq->entries);
2878 +EXPORT_SYMBOL(DWC_WORKQ_ALLOC);
2880 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
2883 + if (wq->pending != 0) {
2884 + struct work_container *wc;
2885 + DWC_ERROR("Destroying work queue with pending work");
2886 + DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) {
2887 + DWC_ERROR("Work %s still pending", wc->name);
2891 + destroy_workqueue((struct workqueue_struct *)wq->wq);
2892 + DWC_SPINLOCK_FREE(wq->lock);
2893 + DWC_WAITQ_FREE(wq->waitq);
2896 +EXPORT_SYMBOL(DWC_WORKQ_FREE);
2898 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t work_cb, void *data, char *format, ...)
2901 + work_container_t *container;
2902 + static char name[128];
2905 + va_start(args, format);
2907 + DWC_VSNPRINTF(name, 128, format, args);
2910 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
2912 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
2913 + DWC_WAITQ_TRIGGER(wq->waitq);
2915 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
2917 + container->data = data;
2918 + container->cb = work_cb;
2919 + container->wq = wq;
2921 + container->name = DWC_STRDUP(name);
2922 + DWC_DEBUG("Queueing work: %s, contianer=%p",
2923 + container->name, container);
2925 + container->name = NULL;
2927 + INIT_WORK(&container->work.work, do_work);
2930 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
2933 + queue_work(wq->wq, &container->work.work);
2936 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE);
2938 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t work_cb, void *data, uint32_t time, char *format, ...)
2941 + work_container_t *container;
2942 + static char name[128];
2945 + va_start(args, format);
2947 + DWC_VSNPRINTF(name, 128, format, args);
2950 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
2952 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
2953 + DWC_WAITQ_TRIGGER(wq->waitq);
2955 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
2957 + container->data = data;
2958 + container->cb = work_cb;
2959 + container->wq = wq;
2960 + if (format) { //GRAYG
2961 + container->name = DWC_STRDUP(name);
2962 + DWC_DEBUG("Queueing work: %s, contianer=%p",
2963 + container->name, container);
2965 + container->name = NULL;
2966 + INIT_DELAYED_WORK(&container->work, do_work);
2969 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
2972 + queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time));
2975 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED);
2978 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
2980 + return wq->pending;
2982 +EXPORT_SYMBOL(DWC_WORKQ_PENDING);
2984 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
2986 + spinlock_t *sl = (spinlock_t *)1;
2987 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
2988 + sl = DWC_ALLOC(sizeof(*sl));
2989 + spin_lock_init(sl);
2991 + return (dwc_spinlock_t *)sl;
2993 +EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC);
2995 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
2997 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
3001 +EXPORT_SYMBOL(DWC_SPINLOCK_FREE);
3003 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
3005 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
3006 + spin_lock((spinlock_t *)lock);
3009 +EXPORT_SYMBOL(DWC_SPINLOCK);
3011 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
3013 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
3014 + spin_unlock((spinlock_t *)lock);
3017 +EXPORT_SYMBOL(DWC_SPINUNLOCK);
3019 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, uint64_t *flags)
3022 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
3023 + spin_lock_irqsave((spinlock_t *)lock, f);
3025 + local_irq_save(f);
3029 +EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE);
3031 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, uint64_t flags)
3033 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
3034 + spin_unlock_irqrestore((spinlock_t *)lock, flags);
3036 + // in kernel 2.6.31, at least, we check for unsigned long
3037 + local_irq_restore((unsigned long)flags);
3040 +EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE);
3042 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
3044 + dwc_mutex_t *mutex = (dwc_mutex_t*)DWC_ALLOC(sizeof(struct mutex));
3045 + struct mutex *m = (struct mutex *)mutex;
3049 +EXPORT_SYMBOL(DWC_MUTEX_ALLOC);
3051 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
3053 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
3055 + mutex_destroy((struct mutex *)mutex);
3058 +EXPORT_SYMBOL(DWC_MUTEX_FREE);
3061 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
3063 + struct mutex *m = (struct mutex *)mutex;
3066 +EXPORT_SYMBOL(DWC_MUTEX_LOCK);
3068 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
3070 + struct mutex *m = (struct mutex *)mutex;
3071 + return mutex_trylock(m);
3073 +EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK);
3075 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
3077 + struct mutex *m = (struct mutex *)mutex;
3080 +EXPORT_SYMBOL(DWC_MUTEX_UNLOCK);
3082 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t thread_function, char *name, void *data)
3084 + struct task_struct *thread = kthread_run(thread_function, data, name);
3085 + if (thread == ERR_PTR(-ENOMEM)) {
3088 + return (dwc_thread_t *)thread;
3090 +EXPORT_SYMBOL(DWC_THREAD_RUN);
3092 +int DWC_THREAD_STOP(dwc_thread_t *thread)
3094 + return kthread_stop((struct task_struct *)thread);
3096 +EXPORT_SYMBOL(DWC_THREAD_STOP);
3098 +dwc_bool_t DWC_THREAD_SHOULD_STOP()
3100 + return kthread_should_stop();
3102 +EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP);
3108 + struct timer_list *t;
3110 + dwc_timer_callback_t cb;
3112 + uint8_t scheduled;
3113 + dwc_spinlock_t *lock;
3116 +static void set_scheduled(dwc_timer_t *t, int s)
3119 + DWC_SPINLOCK_IRQSAVE(t->lock, &flags);
3121 + DWC_SPINUNLOCK_IRQRESTORE(t->lock, flags);
3124 +static int get_scheduled(dwc_timer_t *t)
3128 + DWC_SPINLOCK_IRQSAVE(t->lock, &flags);
3130 + DWC_SPINUNLOCK_IRQRESTORE(t->lock, flags);
3134 +static void timer_callback(unsigned long data)
3136 + dwc_timer_t *timer = (dwc_timer_t *)data;
3137 + set_scheduled(timer, 0);
3138 + DWC_DEBUG("Timer %s callback", timer->name);
3139 + timer->cb(timer->data);
3142 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
3144 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
3146 + DWC_ERROR("Cannot allocate memory for timer");
3149 + t->t = DWC_ALLOC(sizeof(*t->t));
3151 + DWC_ERROR("Cannot allocate memory for timer->t");
3155 + t->name = DWC_STRDUP(name);
3157 + DWC_ERROR("Cannot allocate memory for timer->name");
3161 + t->lock = DWC_SPINLOCK_ALLOC();
3163 + DWC_ERROR("Cannot allocate memory for lock");
3167 + t->t->base = &boot_tvec_bases;
3168 + t->t->expires = jiffies;
3169 + setup_timer(t->t, timer_callback, (unsigned long)t);
3177 + DWC_FREE(t->name);
3184 +EXPORT_SYMBOL(DWC_TIMER_ALLOC);
3186 +void DWC_TIMER_FREE(dwc_timer_t *timer)
3188 + if (get_scheduled(timer)) {
3189 + del_timer(timer->t);
3192 + DWC_SPINLOCK_FREE(timer->lock);
3193 + DWC_FREE(timer->t);
3194 + DWC_FREE(timer->name);
3197 +EXPORT_SYMBOL(DWC_TIMER_FREE);
3199 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
3201 + if (!get_scheduled(timer)) {
3202 + set_scheduled(timer, 1);
3203 + //cgg: DWC_DEBUG("Scheduling timer %s to expire in +%d msec", timer->name, time);
3204 + timer->t->expires = jiffies + msecs_to_jiffies(time);
3205 + add_timer(timer->t);
3208 + //cgg: DWC_DEBUG("Modifying timer %s to expire in +%d msec", timer->name, time);
3209 + mod_timer(timer->t, jiffies + msecs_to_jiffies(time));
3212 +EXPORT_SYMBOL(DWC_TIMER_SCHEDULE);
3214 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
3216 + del_timer(timer->t);
3218 +EXPORT_SYMBOL(DWC_TIMER_CANCEL);
3222 + struct tasklet_struct t;
3223 + dwc_tasklet_callback_t cb;
3227 +static void tasklet_callback(unsigned long data)
3229 + dwc_tasklet_t *t = (dwc_tasklet_t *)data;
3233 +dwc_tasklet_t *DWC_TASK_ALLOC(dwc_tasklet_callback_t cb, void *data)
3235 + dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t));
3240 + tasklet_init(&t->t, tasklet_callback, (unsigned long)t);
3242 + DWC_ERROR("Cannot allocate memory for tasklet\n");
3247 +EXPORT_SYMBOL(DWC_TASK_ALLOC);
3249 +void DWC_TASK_FREE(dwc_tasklet_t *t)
3253 +EXPORT_SYMBOL(DWC_TASK_FREE);
3255 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
3257 + tasklet_schedule(&task->t);
3259 +EXPORT_SYMBOL(DWC_TASK_SCHEDULE);
3263 +void DWC_UDELAY(uint32_t usecs)
3267 +EXPORT_SYMBOL(DWC_UDELAY);
3269 +void DWC_MDELAY(uint32_t msecs)
3273 +EXPORT_SYMBOL(DWC_MDELAY);
3275 +void DWC_MSLEEP(uint32_t msecs)
3279 +EXPORT_SYMBOL(DWC_MSLEEP);
3281 +uint32_t DWC_TIME(void)
3283 + return jiffies_to_msecs(jiffies);
3285 +EXPORT_SYMBOL(DWC_TIME);
3292 + wait_queue_head_t queue;
3296 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
3298 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
3299 + init_waitqueue_head(&wq->queue);
3303 +EXPORT_SYMBOL(DWC_WAITQ_ALLOC);
3305 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
3309 +EXPORT_SYMBOL(DWC_WAITQ_FREE);
3311 +static int32_t check_result(dwc_waitq_t *wq, int result)
3314 + msecs = jiffies_to_msecs(result);
3321 + if (result == 0) {
3322 + return -DWC_E_TIMEOUT;
3325 + if ((result == -ERESTARTSYS) || (wq->abort == 1)) {
3326 + return -DWC_E_ABORT;
3329 + return -DWC_E_UNKNOWN;
3332 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t condition, void *data)
3334 + int result = wait_event_interruptible(wq->queue,
3335 + condition(data) || wq->abort);
3336 + return check_result(wq, result);
3338 +EXPORT_SYMBOL(DWC_WAITQ_WAIT);
3340 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t condition,
3341 + void *data, int32_t msecs)
3343 + int result = wait_event_interruptible_timeout(wq->queue,
3344 + condition(data) || wq->abort,
3345 + msecs_to_jiffies(msecs));
3346 + return check_result(wq, result);
3348 +EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT);
3350 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
3352 + wake_up_interruptible(&wq->queue);
3354 +EXPORT_SYMBOL(DWC_WAITQ_TRIGGER);
3356 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
3359 + DWC_WAITQ_TRIGGER(wq);
3361 +EXPORT_SYMBOL(DWC_WAITQ_ABORT);
3363 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.c
3365 +/* =========================================================================
3366 + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_crypto.c $
3368 + * $Date: 2008/12/21 $
3369 + * $Change: 1156609 $
3371 + * Synopsys Portability Library Software and documentation
3372 + * (hereinafter, "Software") is an Unsupported proprietary work of
3373 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
3374 + * between Synopsys and you.
3376 + * The Software IS NOT an item of Licensed Software or Licensed Product
3377 + * under any End User Software License Agreement or Agreement for
3378 + * Licensed Product with Synopsys or any supplement thereto. You are
3379 + * permitted to use and redistribute this Software in source and binary
3380 + * forms, with or without modification, provided that redistributions
3381 + * of source code must retain this notice. You may not view, use,
3382 + * disclose, copy or distribute this file or any information contained
3383 + * herein except pursuant to this license grant from Synopsys. If you
3384 + * do not agree with this notice, including the disclaimer below, then
3385 + * you are not authorized to use the Software.
3387 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
3388 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3389 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
3390 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
3391 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
3392 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3393 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3394 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
3395 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3396 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3397 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3399 + * ========================================================================= */
3402 + * This file contains the WUSB cryptographic routines.
3405 +#include "dwc_crypto.h"
3409 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
3412 + DWC_PRINTF("%s: ", name);
3413 + for (i=0; i<len; i++) {
3414 + DWC_PRINTF("%02x ", bytes[i]);
3419 +#define dump_bytes(x...)
3422 +/* Display a block */
3423 +void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
3425 +#ifdef DEBUG_CRYPTO
3426 + int i, blksize = 16;
3428 + DWC_DEBUG("%s", prefix);
3430 + if (suffix == NULL) {
3435 + for (i = 0; i < blksize; i++)
3436 + DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? " " : " ");
3437 + DWC_PRINT(suffix);
3443 + * Encrypts an array of bytes using the AES encryption engine.
3444 + * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
3447 + * @return 0 on success, negative error code on error.
3449 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
3452 + DWC_MEMSET(block_t, 0, 16);
3454 + return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
3458 + * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
3459 + * This function takes a data string and returns the encrypted CBC
3460 + * Counter-mode MIC.
3462 + * @param key The 128-bit symmetric key.
3463 + * @param nonce The CCM nonce.
3464 + * @param label The unique 14-byte ASCII text label.
3465 + * @param bytes The byte array to be encrypted.
3466 + * @param len Length of the byte array.
3467 + * @param result Byte array to receive the 8-byte encrypted MIC.
3469 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
3470 + char *label, u8 *bytes, int len, u8 *result)
3476 + u16 la = (u16)(len + 14);
3478 + /* Set the AES-128 key */
3479 + //dwc_aes_setkey(tfm, key, 16);
3481 + /* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
3482 + block_m[0] = 0x59;
3483 + for (idx = 0; idx < 13; idx++)
3484 + block_m[idx + 1] = nonce[idx];
3488 + /* Produce the CBC IV */
3489 + dwc_wusb_aes_encrypt(block_m, key, block_x);
3490 + show_block(block_m, "CBC IV in: ", "\n", 0);
3491 + show_block(block_x, "CBC IV out:", "\n", 0);
3493 + /* Fill block B1 from l(a) = Blen + 14, and A */
3494 + block_x[0] ^= (u8)(la >> 8);
3495 + block_x[1] ^= (u8)la;
3496 + for (idx = 0; idx < 14; idx++)
3497 + block_x[idx + 2] ^= label[idx];
3498 + show_block(block_x, "After xor: ", "b1\n", 16);
3500 + dwc_wusb_aes_encrypt(block_x, key, block_x);
3501 + show_block(block_x, "After AES: ", "b1\n", 16);
3506 + /* Fill remaining blocks with B */
3507 + while (len-- > 0) {
3508 + block_x[idx] ^= *bytes++;
3509 + if (++idx >= 16) {
3511 + show_block(block_x, "After xor: ", "\n", blkNum);
3512 + dwc_wusb_aes_encrypt(block_x, key, block_x);
3513 + show_block(block_x, "After AES: ", "\n", blkNum);
3518 + /* Handle partial last block */
3520 + show_block(block_x, "After xor: ", "\n", blkNum);
3521 + dwc_wusb_aes_encrypt(block_x, key, block_x);
3522 + show_block(block_x, "After AES: ", "\n", blkNum);
3525 + /* Save the MIC tag */
3526 + DWC_MEMCPY(block_t, block_x, 8);
3527 + show_block(block_t, "MIC tag : ", NULL, 8);
3529 + /* Fill block A0 from flags = 0x01, N, and counter = 0 */
3530 + block_m[0] = 0x01;
3534 + /* Encrypt the counter */
3535 + dwc_wusb_aes_encrypt(block_m, key, block_x);
3536 + show_block(block_x, "CTR[MIC] : ", NULL, 8);
3538 + /* XOR with MIC tag */
3539 + for (idx = 0; idx < 8; idx++) {
3540 + block_t[idx] ^= block_x[idx];
3543 + /* Return result to caller */
3544 + DWC_MEMCPY(result, block_t, 8);
3545 + show_block(result, "CCM-MIC : ", NULL, 8);
3550 + * The PRF function described in section 6.5 of the WUSB spec. This function
3551 + * concatenates MIC values returned from dwc_cmf() to create a value of
3552 + * the requested length.
3554 + * @param prf_len Length of the PRF function in bits (64, 128, or 256).
3555 + * @param key, nonce, label, bytes, len Same as for dwc_cmf().
3556 + * @param result Byte array to receive the result.
3558 +void dwc_wusb_prf(int prf_len, u8 *key,
3559 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
3564 + for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
3565 + dwc_wusb_cmf(key, nonce, label, bytes, len, result);
3571 + * Fills in CCM Nonce per the WUSB spec.
3573 + * @param[in] haddr Host address.
3574 + * @param[in] daddr Device address.
3575 + * @param[in] tkid Session Key(PTK) identifier.
3576 + * @param[out] nonce Pointer to where the CCM Nonce output is to be written.
3578 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
3582 + DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
3584 + DWC_MEMSET(&nonce[0], 0, 16);
3586 + DWC_MEMCPY(&nonce[6], tkid, 3);
3587 + nonce[9] = daddr & 0xFF;
3588 + nonce[10] = (daddr >> 8) & 0xFF;
3589 + nonce[11] = haddr & 0xFF;
3590 + nonce[12] = (haddr >> 8) & 0xFF;
3592 + dump_bytes("CCM nonce", nonce, 16);
3596 + * Generates a 16-byte cryptographic-grade random number for the Host/Device
3599 +void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
3601 + uint8_t inonce[16];
3604 + /* Fill in the Nonce */
3605 + DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
3606 + inonce[9] = addr & 0xFF;
3607 + inonce[10] = (addr >> 8) & 0xFF;
3608 + inonce[11] = inonce[9];
3609 + inonce[12] = inonce[10];
3611 + /* Collect "randomness samples" */
3612 + DWC_RANDOM_BYTES((uint8_t *)temp, 16);
3614 + dwc_wusb_prf_128((uint8_t *)temp, nonce,
3615 + "Random Numbers", (uint8_t *)temp, sizeof(temp),
3620 + * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
3623 + * @param[in] ccm_nonce Pointer to CCM Nonce.
3624 + * @param[in] mk Master Key to derive the session from
3625 + * @param[in] hnonce Pointer to Host Nonce.
3626 + * @param[in] dnonce Pointer to Device Nonce.
3627 + * @param[out] kck Pointer to where the KCK output is to be written.
3628 + * @param[out] ptk Pointer to where the PTK output is to be written.
3630 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
3631 + uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
3633 + uint8_t idata[32];
3634 + uint8_t odata[32];
3636 + dump_bytes("ck", mk, 16);
3637 + dump_bytes("hnonce", hnonce, 16);
3638 + dump_bytes("dnonce", dnonce, 16);
3640 + /* The data is the HNonce and DNonce concatenated */
3641 + DWC_MEMCPY(&idata[0], hnonce, 16);
3642 + DWC_MEMCPY(&idata[16], dnonce, 16);
3644 + dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
3646 + /* Low 16 bytes of the result is the KCK, high 16 is the PTK */
3647 + DWC_MEMCPY(kck, &odata[0], 16);
3648 + DWC_MEMCPY(ptk, &odata[16], 16);
3650 + dump_bytes("kck", kck, 16);
3651 + dump_bytes("ptk", ptk, 16);
3655 + * Generates the Message Integrity Code over the Handshake data per the
3658 + * @param ccm_nonce Pointer to CCM Nonce.
3659 + * @param kck Pointer to Key Confirmation Key.
3660 + * @param data Pointer to Handshake data to be checked.
3661 + * @param mic Pointer to where the MIC output is to be written.
3663 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
3664 + uint8_t *data, uint8_t *mic)
3667 + dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
3668 + data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
3672 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.h
3674 +/* =========================================================================
3675 + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_crypto.h $
3677 + * $Date: 2008/12/21 $
3678 + * $Change: 1156609 $
3680 + * Synopsys Portability Library Software and documentation
3681 + * (hereinafter, "Software") is an Unsupported proprietary work of
3682 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
3683 + * between Synopsys and you.
3685 + * The Software IS NOT an item of Licensed Software or Licensed Product
3686 + * under any End User Software License Agreement or Agreement for
3687 + * Licensed Product with Synopsys or any supplement thereto. You are
3688 + * permitted to use and redistribute this Software in source and binary
3689 + * forms, with or without modification, provided that redistributions
3690 + * of source code must retain this notice. You may not view, use,
3691 + * disclose, copy or distribute this file or any information contained
3692 + * herein except pursuant to this license grant from Synopsys. If you
3693 + * do not agree with this notice, including the disclaimer below, then
3694 + * you are not authorized to use the Software.
3696 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
3697 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3698 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
3699 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
3700 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
3701 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3702 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3703 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
3704 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3705 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3706 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3708 + * ========================================================================= */
3710 +#ifndef _DWC_CRYPTO_H_
3711 +#define _DWC_CRYPTO_H_
3715 + * This file contains declarations for the WUSB Cryptographic routines as
3716 + * defined in the WUSB spec. They are only to be used internally by the DWC UWB
3720 +#include "dwc_os.h"
3722 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
3724 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
3725 + char *label, u8 *bytes, int len, u8 *result);
3726 +void dwc_wusb_prf(int prf_len, u8 *key,
3727 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
3730 + * The PRF-64 function described in section 6.5 of the WUSB spec.
3732 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
3734 +static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
3735 + char *label, u8 *bytes, int len, u8 *result)
3737 + dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
3741 + * The PRF-128 function described in section 6.5 of the WUSB spec.
3743 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
3745 +static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
3746 + char *label, u8 *bytes, int len, u8 *result)
3748 + dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
3752 + * The PRF-256 function described in section 6.5 of the WUSB spec.
3754 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
3756 +static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
3757 + char *label, u8 *bytes, int len, u8 *result)
3759 + dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
3763 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
3765 +void dwc_wusb_gen_nonce(uint16_t addr,
3768 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
3769 + uint8_t *hnonce, uint8_t *dnonce,
3770 + uint8_t *kck, uint8_t *ptk);
3773 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
3774 + *kck, uint8_t *data, uint8_t *mic);
3776 +#endif /* _DWC_CRYPTO_H_ */
3778 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.c
3780 +/* =========================================================================
3781 + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_dh.c $
3783 + * $Date: 2008/12/21 $
3784 + * $Change: 1156609 $
3786 + * Synopsys Portability Library Software and documentation
3787 + * (hereinafter, "Software") is an Unsupported proprietary work of
3788 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
3789 + * between Synopsys and you.
3791 + * The Software IS NOT an item of Licensed Software or Licensed Product
3792 + * under any End User Software License Agreement or Agreement for
3793 + * Licensed Product with Synopsys or any supplement thereto. You are
3794 + * permitted to use and redistribute this Software in source and binary
3795 + * forms, with or without modification, provided that redistributions
3796 + * of source code must retain this notice. You may not view, use,
3797 + * disclose, copy or distribute this file or any information contained
3798 + * herein except pursuant to this license grant from Synopsys. If you
3799 + * do not agree with this notice, including the disclaimer below, then
3800 + * you are not authorized to use the Software.
3802 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
3803 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3804 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
3805 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
3806 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
3807 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3808 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3809 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
3810 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3811 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3812 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3814 + * ========================================================================= */
3815 +#ifndef CONFIG_MACH_IPMATE
3816 +#include "dwc_dh.h"
3817 +#include "dwc_modpow.h"
3820 +/* This function prints out a buffer in the format described in the Association
3821 + * Model specification. */
3822 +static void dh_dump(char *str, void *_num, int len)
3824 + uint8_t *num = _num;
3826 + DWC_PRINTF("%s\n", str);
3827 + for (i = 0; i < len; i ++) {
3828 + DWC_PRINTF("%02x", num[i]);
3829 + if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
3830 + if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
3836 +#define dh_dump(_x...) do {; } while(0)
3839 +/* Constant g value */
3840 +static __u32 dh_g[] = {
3844 +/* Constant p value */
3845 +static __u32 dh_p[] = {
3846 + 0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
3847 + 0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
3848 + 0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
3849 + 0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
3850 + 0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
3851 + 0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
3852 + 0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
3853 + 0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
3854 + 0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
3855 + 0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
3856 + 0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
3857 + 0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
3860 +static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
3862 + uint8_t *in = _in;
3863 + uint8_t *out = _out;
3865 + for (i=0; i<len; i++) {
3866 + out[i] = in[len-1-i];
3870 +/* Computes the modular exponentiation (num^exp % mod). num, exp, and mod are
3871 + * big endian numbers of size len, in bytes. Each len value must be a multiple
3873 +int dwc_dh_modpow(void *num, uint32_t num_len,
3874 + void *exp, uint32_t exp_len,
3875 + void *mod, uint32_t mod_len,
3878 + /* modpow() takes little endian numbers. AM uses big-endian. This
3879 + * function swaps bytes of numbers before passing onto modpow. */
3884 + uint32_t *bignum_num = DWC_ALLOC(num_len + 4);
3885 + uint32_t *bignum_exp = DWC_ALLOC(exp_len + 4);
3886 + uint32_t *bignum_mod = DWC_ALLOC(mod_len + 4);
3888 + dh_swap_bytes(num, &bignum_num[1], num_len);
3889 + bignum_num[0] = num_len / 4;
3891 + dh_swap_bytes(exp, &bignum_exp[1], exp_len);
3892 + bignum_exp[0] = exp_len / 4;
3894 + dh_swap_bytes(mod, &bignum_mod[1], mod_len);
3895 + bignum_mod[0] = mod_len / 4;
3897 + result = dwc_modpow(bignum_num, bignum_exp, bignum_mod);
3900 + goto dh_modpow_nomem;
3903 + dh_swap_bytes(&result[1], out, result[0] * 4);
3907 + DWC_FREE(bignum_num);
3908 + DWC_FREE(bignum_exp);
3909 + DWC_FREE(bignum_mod);
3914 +int dwc_dh_pk(uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
3919 +#ifndef DH_TEST_VECTORS
3920 + DWC_RANDOM_BYTES(exp, 32);
3923 + /* Compute the pkd */
3924 + if ((retval = dwc_dh_modpow(dh_g, 4,
3926 + dh_p, 384, pk))) {
3931 + DWC_MEMCPY(&m3[0], pk, 384);
3932 + DWC_SHA256(m3, 385, hash);
3934 + dh_dump("PK", pk, 384);
3935 + dh_dump("SHA-256(M3)", hash, 32);
3939 +int dwc_dh_derive_keys(uint8_t nd, uint8_t *pkh, uint8_t *pkd,
3940 + uint8_t *exp, int is_host,
3941 + char *dd, uint8_t *ck, uint8_t *kdk)
3945 + uint8_t sha_result[32];
3946 + uint8_t dhkey[384];
3947 + uint8_t shared_secret[384];
3960 + if ((retval = dwc_dh_modpow(pk, 384,
3962 + dh_p, 384, shared_secret))) {
3965 + dh_dump("Shared Secret", shared_secret, 384);
3967 + DWC_SHA256(shared_secret, 384, dhkey);
3968 + dh_dump("DHKEY", dhkey, 384);
3970 + DWC_MEMCPY(&mv[0], pkd, 384);
3971 + DWC_MEMCPY(&mv[384], pkh, 384);
3972 + DWC_MEMCPY(&mv[768], "displayed digest", 16);
3973 + dh_dump("MV", mv, 784);
3975 + DWC_SHA256(mv, 784, sha_result);
3976 + dh_dump("SHA-256(MV)", sha_result, 32);
3977 + dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
3979 + dh_swap_bytes(sha_result, &vd, 4);
3981 + DWC_PRINTF("Vd (decimal) = %d\n", vd);
3987 + DWC_SPRINTF(dd, "%02d", vd);
3991 + DWC_SPRINTF(dd, "%03d", vd);
3995 + DWC_SPRINTF(dd, "%04d", vd);
3999 + DWC_PRINTF("Display Digits: %s\n", dd);
4002 + message = "connection key";
4003 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
4004 + dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
4005 + DWC_MEMCPY(ck, sha_result, 16);
4007 + message = "key derivation key";
4008 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
4009 + dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
4010 + DWC_MEMCPY(kdk, sha_result, 32);
4016 +#ifdef DH_TEST_VECTORS
4018 +static __u8 dh_a[] = {
4019 + 0x44, 0x00, 0x51, 0xd6,
4020 + 0xf0, 0xb5, 0x5e, 0xa9,
4021 + 0x67, 0xab, 0x31, 0xc6,
4022 + 0x8a, 0x8b, 0x5e, 0x37,
4023 + 0xd9, 0x10, 0xda, 0xe0,
4024 + 0xe2, 0xd4, 0x59, 0xa4,
4025 + 0x86, 0x45, 0x9c, 0xaa,
4026 + 0xdf, 0x36, 0x75, 0x16,
4029 +static __u8 dh_b[] = {
4030 + 0x5d, 0xae, 0xc7, 0x86,
4031 + 0x79, 0x80, 0xa3, 0x24,
4032 + 0x8c, 0xe3, 0x57, 0x8f,
4033 + 0xc7, 0x5f, 0x1b, 0x0f,
4034 + 0x2d, 0xf8, 0x9d, 0x30,
4035 + 0x6f, 0xa4, 0x52, 0xcd,
4036 + 0xe0, 0x7a, 0x04, 0x8a,
4037 + 0xde, 0xd9, 0x26, 0x56,
4040 +void dwc_run_dh_test_vectors(void)
4044 + uint8_t hashd[32];
4045 + uint8_t hashh[32];
4050 + DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
4052 + /* compute the PKd and SHA-256(PKd || Nd) */
4053 + DWC_PRINTF("Computing PKd\n");
4054 + dwc_dh_pk(2, dh_a, pkd, hashd);
4056 + /* compute the PKd and SHA-256(PKh || Nd) */
4057 + DWC_PRINTF("Computing PKh\n");
4058 + dwc_dh_pk(2, dh_b, pkh, hashh);
4060 + /* compute the dhkey */
4061 + dwc_dh_derive_keys(2, pkh, pkd, dh_a, 0, dd, ck, kdk);
4063 +#endif /* DH_TEST_VECTORS */
4065 +#endif /* CONFIG_IPMATE_MACH */
4067 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.h
4069 +/* =========================================================================
4070 + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_dh.h $
4072 + * $Date: 2008/12/21 $
4073 + * $Change: 1156609 $
4075 + * Synopsys Portability Library Software and documentation
4076 + * (hereinafter, "Software") is an Unsupported proprietary work of
4077 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
4078 + * between Synopsys and you.
4080 + * The Software IS NOT an item of Licensed Software or Licensed Product
4081 + * under any End User Software License Agreement or Agreement for
4082 + * Licensed Product with Synopsys or any supplement thereto. You are
4083 + * permitted to use and redistribute this Software in source and binary
4084 + * forms, with or without modification, provided that redistributions
4085 + * of source code must retain this notice. You may not view, use,
4086 + * disclose, copy or distribute this file or any information contained
4087 + * herein except pursuant to this license grant from Synopsys. If you
4088 + * do not agree with this notice, including the disclaimer below, then
4089 + * you are not authorized to use the Software.
4091 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
4092 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4093 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
4094 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
4095 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
4096 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
4097 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
4098 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
4099 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4100 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
4101 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
4103 + * ========================================================================= */
4107 +#include "dwc_os.h"
4111 + * This file defines the common functions on device and host for performing
4112 + * numeric association as defined in the WUSB spec. They are only to be
4113 + * used internally by the DWC UWB modules. */
4115 +extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
4116 +extern int dwc_dh_hmac_sha256(uint8_t *message, uint32_t messagelen,
4117 + uint8_t *key, uint32_t keylen,
4119 +extern int dwc_dh_modpow(void *num, uint32_t num_len,
4120 + void *exp, uint32_t exp_len,
4121 + void *mod, uint32_t mod_len,
4124 +/** Computes PKD or PKH, and SHA-256(PKd || Nd)
4126 + * PK = g^exp mod p.
4129 + * Nd = Number of digits on the device.
4132 + * exp = A 32-byte buffer to be filled with a randomly generated number.
4133 + * used as either A or B.
4134 + * pk = A 384-byte buffer to be filled with the PKH or PKD.
4135 + * hash = A 32-byte buffer to be filled with SHA-256(PK || ND).
4137 +extern int dwc_dh_pk(uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash);
4139 +/** Computes the DHKEY, and VD.
4141 + * If called from host, then it will comput DHKEY=PKD^exp % p.
4142 + * If called from device, then it will comput DHKEY=PKH^exp % p.
4145 + * pkd = The PKD value.
4146 + * pkh = The PKH value.
4147 + * exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk.
4148 + * is_host = Set to non zero if a WUSB host is calling this function.
4152 + * dd = A pointer to an buffer to be set to the displayed digits string to be shown
4153 + * to the user. This buffer should be at 5 bytes long to hold 4 digits plus a
4154 + * null termination character. This buffer can be used directly for display.
4155 + * ck = A 16-byte buffer to be filled with the CK.
4156 + * kdk = A 32-byte buffer to be filled with the KDK.
4158 +extern int dwc_dh_derive_keys(uint8_t nd, uint8_t *pkh, uint8_t *pkd,
4159 + uint8_t *exp, int is_host,
4160 + char *dd, uint8_t *ck, uint8_t *kdk);
4162 +#ifdef DH_TEST_VECTORS
4163 +extern void dwc_run_dh_test_vectors(void);
4166 +#endif /* _DWC_DH_H_ */
4168 +++ b/drivers/usb/host/dwc_common_port/dwc_list.h
4170 +/* $OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $ */
4171 +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
4174 + * Copyright (c) 1991, 1993
4175 + * The Regents of the University of California. All rights reserved.
4177 + * Redistribution and use in source and binary forms, with or without
4178 + * modification, are permitted provided that the following conditions
4180 + * 1. Redistributions of source code must retain the above copyright
4181 + * notice, this list of conditions and the following disclaimer.
4182 + * 2. Redistributions in binary form must reproduce the above copyright
4183 + * notice, this list of conditions and the following disclaimer in the
4184 + * documentation and/or other materials provided with the distribution.
4185 + * 3. Neither the name of the University nor the names of its contributors
4186 + * may be used to endorse or promote products derived from this software
4187 + * without specific prior written permission.
4189 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
4190 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4191 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4192 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
4193 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4194 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4195 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4196 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4197 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4198 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4201 + * @(#)queue.h 8.5 (Berkeley) 8/20/94
4204 +#ifndef _SYS_QUEUE_H_
4205 +#define _SYS_QUEUE_H_
4210 + * This file defines linked list operations. It is derived from BSD with
4211 + * only the MACRO names being prefixed with DWC_. This is because a few of
4212 + * these names conflict with those on Linux. For documentation on use, see the
4213 + * inline comments in the source code. The original license for this source
4214 + * code applies and is preserved in the dwc_list.h source file.
4218 + * This file defines five types of data structures: singly-linked lists,
4219 + * lists, simple queues, tail queues, and circular queues.
4222 + * A singly-linked list is headed by a single forward pointer. The elements
4223 + * are singly linked for minimum space and pointer manipulation overhead at
4224 + * the expense of O(n) removal for arbitrary elements. New elements can be
4225 + * added to the list after an existing element or at the head of the list.
4226 + * Elements being removed from the head of the list should use the explicit
4227 + * macro for this purpose for optimum efficiency. A singly-linked list may
4228 + * only be traversed in the forward direction. Singly-linked lists are ideal
4229 + * for applications with large datasets and few or no removals or for
4230 + * implementing a LIFO queue.
4232 + * A list is headed by a single forward pointer (or an array of forward
4233 + * pointers for a hash table header). The elements are doubly linked
4234 + * so that an arbitrary element can be removed without a need to
4235 + * traverse the list. New elements can be added to the list before
4236 + * or after an existing element or at the head of the list. A list
4237 + * may only be traversed in the forward direction.
4239 + * A simple queue is headed by a pair of pointers, one the head of the
4240 + * list and the other to the tail of the list. The elements are singly
4241 + * linked to save space, so elements can only be removed from the
4242 + * head of the list. New elements can be added to the list before or after
4243 + * an existing element, at the head of the list, or at the end of the
4244 + * list. A simple queue may only be traversed in the forward direction.
4246 + * A tail queue is headed by a pair of pointers, one to the head of the
4247 + * list and the other to the tail of the list. The elements are doubly
4248 + * linked so that an arbitrary element can be removed without a need to
4249 + * traverse the list. New elements can be added to the list before or
4250 + * after an existing element, at the head of the list, or at the end of
4251 + * the list. A tail queue may be traversed in either direction.
4253 + * A circle queue is headed by a pair of pointers, one to the head of the
4254 + * list and the other to the tail of the list. The elements are doubly
4255 + * linked so that an arbitrary element can be removed without a need to
4256 + * traverse the list. New elements can be added to the list before or after
4257 + * an existing element, at the head of the list, or at the end of the list.
4258 + * A circle queue may be traversed in either direction, but has a more
4259 + * complex end of list detection.
4261 + * For details on the use of these macros, see the queue(3) manual page.
4265 + * Double-linked List.
4268 +typedef struct dwc_list_link {
4269 + struct dwc_list_link *next;
4270 + struct dwc_list_link *prev;
4273 +#define DWC_LIST_INIT(link) do{ \
4274 + (link)->next = (link); \
4275 + (link)->prev = (link); \
4278 +#define DWC_LIST_FIRST(link) ((link)->next)
4279 +#define DWC_LIST_LAST(link) ((link)->prev)
4280 +#define DWC_LIST_END(link) (link)
4281 +#define DWC_LIST_NEXT(link) ((link)->next)
4282 +#define DWC_LIST_PREV(link) ((link)->prev)
4283 +#define DWC_LIST_EMPTY(link) \
4284 + (DWC_LIST_FIRST(link) == DWC_LIST_END(link))
4285 +#define DWC_LIST_ENTRY(link, type, field) (type *) \
4286 + ((uint8_t *)(link) - (size_t)(&((type *)0)->field))
4288 +#define DWC_LIST_INSERT_HEAD(list, link) do { \
4289 + (link)->next = (list)->next; \
4290 + (link)->prev = (list); \
4291 + (list)->next->prev = link; \
4292 + (list)->next = link; \
4295 +#define DWC_LIST_INSERT_TAIL(list, link) do { \
4296 + (link)->next = list; \
4297 + (link)->prev = (list)->prev; \
4298 + (list)->prev->next = link; \
4299 + (list)->prev = link; \
4302 +#define DWC_LIST_REMOVE(link) do { \
4303 + (link)->next->prev = (link)->prev; \
4304 + (link)->prev->next = (link)->next; \
4307 +#define DWC_LIST_REMOVE_INIT(link) do { \
4308 + DWC_LIST_REMOVE(link); \
4309 + DWC_LIST_INIT(link); \
4312 +#define DWC_LIST_MOVE_HEAD(list, link) do { \
4313 + DWC_LIST_REMOVE(link); \
4314 + DWC_LIST_INSERT_HEAD(list, link); \
4317 +#define DWC_LIST_MOVE_TAIL(list, link) do { \
4318 + DWC_LIST_REMOVE(link); \
4319 + DWC_LIST_INSERT_TAIL(list, link); \
4322 +#define DWC_LIST_FOREACH(var, list) \
4323 + for((var) = DWC_LIST_FIRST(list); \
4324 + (var) != DWC_LIST_END(list); \
4325 + (var) = DWC_LIST_NEXT(var))
4327 +#define DWC_LIST_FOREACH_SAFE(var, var2, list) \
4328 + for((var) = DWC_LIST_FIRST(list), var2 = DWC_LIST_NEXT(var); \
4329 + (var) != DWC_LIST_END(list); \
4330 + (var) = (var2), var2 = DWC_LIST_NEXT(var2))
4332 +#define DWC_LIST_FOREACH_REVERSE(var, list) \
4333 + for((var) = DWC_LIST_LAST(list); \
4334 + (var) != DWC_LIST_END(list); \
4335 + (var) = DWC_LIST_PREV(var))
4338 + * Singly-linked List definitions.
4340 +#define DWC_SLIST_HEAD(name, type) \
4342 + struct type *slh_first; /* first element */ \
4345 +#define DWC_SLIST_HEAD_INITIALIZER(head) \
4348 +#define DWC_SLIST_ENTRY(type) \
4350 + struct type *sle_next; /* next element */ \
4354 + * Singly-linked List access methods.
4356 +#define DWC_SLIST_FIRST(head) ((head)->slh_first)
4357 +#define DWC_SLIST_END(head) NULL
4358 +#define DWC_SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
4359 +#define DWC_SLIST_NEXT(elm, field) ((elm)->field.sle_next)
4361 +#define DWC_SLIST_FOREACH(var, head, field) \
4362 + for((var) = SLIST_FIRST(head); \
4363 + (var) != SLIST_END(head); \
4364 + (var) = SLIST_NEXT(var, field))
4366 +#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field) \
4367 + for ((varp) = &SLIST_FIRST((head)); \
4368 + ((var) = *(varp)) != SLIST_END(head); \
4369 + (varp) = &SLIST_NEXT((var), field))
4372 + * Singly-linked List functions.
4374 +#define DWC_SLIST_INIT(head) { \
4375 + SLIST_FIRST(head) = SLIST_END(head); \
4378 +#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do { \
4379 + (elm)->field.sle_next = (slistelm)->field.sle_next; \
4380 + (slistelm)->field.sle_next = (elm); \
4383 +#define DWC_SLIST_INSERT_HEAD(head, elm, field) do { \
4384 + (elm)->field.sle_next = (head)->slh_first; \
4385 + (head)->slh_first = (elm); \
4388 +#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do { \
4389 + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
4392 +#define DWC_SLIST_REMOVE_HEAD(head, field) do { \
4393 + (head)->slh_first = (head)->slh_first->field.sle_next; \
4396 +#define DWC_SLIST_REMOVE(head, elm, type, field) do { \
4397 + if ((head)->slh_first == (elm)) { \
4398 + SLIST_REMOVE_HEAD((head), field); \
4401 + struct type *curelm = (head)->slh_first; \
4402 + while( curelm->field.sle_next != (elm) ) \
4403 + curelm = curelm->field.sle_next; \
4404 + curelm->field.sle_next = \
4405 + curelm->field.sle_next->field.sle_next; \
4412 + * List definitions.
4414 +#define DWC_LIST_HEAD(name, type) \
4416 + struct type *lh_first; /* first element */ \
4419 +#define DWC_LIST_HEAD_INITIALIZER(head) \
4422 +#define DWC_LIST_ENTRY(type) \
4424 + struct type *le_next; /* next element */ \
4425 + struct type **le_prev; /* address of previous next element */ \
4429 + * List access methods
4431 +#define DWC_LIST_FIRST(head) ((head)->lh_first)
4432 +#define DWC_LIST_END(head) NULL
4433 +#define DWC_LIST_EMPTY(head) (DWC_LIST_FIRST(head) == DWC_LIST_END(head))
4434 +#define DWC_LIST_NEXT(elm, field) ((elm)->field.le_next)
4436 +#define DWC_LIST_FOREACH(var, head, field) \
4437 + for((var) = DWC_LIST_FIRST(head); \
4438 + (var)!= DWC_LIST_END(head); \
4439 + (var) = DWC_LIST_NEXT(var, field))
4440 +#define DWC_LIST_FOREACH_SAFE(var, var2, head, field) \
4441 + for((var) = DWC_LIST_FIRST(head), var2 = DWC_LIST_NEXT(var, field); \
4442 + (var) != DWC_LIST_END(head); \
4443 + (var) = var2, var2 = DWC_LIST_NEXT(var, field))
4448 +#define DWC_LIST_INIT(head) do { \
4449 + DWC_LIST_FIRST(head) = DWC_LIST_END(head); \
4452 +#define DWC_LIST_INSERT_AFTER(listelm, elm, field) do { \
4453 + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
4454 + (listelm)->field.le_next->field.le_prev = \
4455 + &(elm)->field.le_next; \
4456 + (listelm)->field.le_next = (elm); \
4457 + (elm)->field.le_prev = &(listelm)->field.le_next; \
4460 +#define DWC_LIST_INSERT_BEFORE(listelm, elm, field) do { \
4461 + (elm)->field.le_prev = (listelm)->field.le_prev; \
4462 + (elm)->field.le_next = (listelm); \
4463 + *(listelm)->field.le_prev = (elm); \
4464 + (listelm)->field.le_prev = &(elm)->field.le_next; \
4467 +#define DWC_LIST_INSERT_HEAD(head, elm, field) do { \
4468 + if (((elm)->field.le_next = (head)->lh_first) != NULL) \
4469 + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
4470 + (head)->lh_first = (elm); \
4471 + (elm)->field.le_prev = &(head)->lh_first; \
4474 +#define DWC_LIST_REMOVE(elm, field) do { \
4475 + if ((elm)->field.le_next != NULL) \
4476 + (elm)->field.le_next->field.le_prev = \
4477 + (elm)->field.le_prev; \
4478 + *(elm)->field.le_prev = (elm)->field.le_next; \
4481 +#define DWC_LIST_REPLACE(elm, elm2, field) do { \
4482 + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
4483 + (elm2)->field.le_next->field.le_prev = \
4484 + &(elm2)->field.le_next; \
4485 + (elm2)->field.le_prev = (elm)->field.le_prev; \
4486 + *(elm2)->field.le_prev = (elm2); \
4492 + * Simple queue definitions.
4494 +#define DWC_SIMPLEQ_HEAD(name, type) \
4496 + struct type *sqh_first; /* first element */ \
4497 + struct type **sqh_last; /* addr of last next element */ \
4500 +#define DWC_SIMPLEQ_HEAD_INITIALIZER(head) \
4501 + { NULL, &(head).sqh_first }
4503 +#define DWC_SIMPLEQ_ENTRY(type) \
4505 + struct type *sqe_next; /* next element */ \
4509 + * Simple queue access methods.
4511 +#define DWC_SIMPLEQ_FIRST(head) ((head)->sqh_first)
4512 +#define DWC_SIMPLEQ_END(head) NULL
4513 +#define DWC_SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
4514 +#define DWC_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
4516 +#define DWC_SIMPLEQ_FOREACH(var, head, field) \
4517 + for((var) = SIMPLEQ_FIRST(head); \
4518 + (var) != SIMPLEQ_END(head); \
4519 + (var) = SIMPLEQ_NEXT(var, field))
4522 + * Simple queue functions.
4524 +#define DWC_SIMPLEQ_INIT(head) do { \
4525 + (head)->sqh_first = NULL; \
4526 + (head)->sqh_last = &(head)->sqh_first; \
4529 +#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
4530 + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
4531 + (head)->sqh_last = &(elm)->field.sqe_next; \
4532 + (head)->sqh_first = (elm); \
4535 +#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
4536 + (elm)->field.sqe_next = NULL; \
4537 + *(head)->sqh_last = (elm); \
4538 + (head)->sqh_last = &(elm)->field.sqe_next; \
4541 +#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
4542 + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
4543 + (head)->sqh_last = &(elm)->field.sqe_next; \
4544 + (listelm)->field.sqe_next = (elm); \
4547 +#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do { \
4548 + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
4549 + (head)->sqh_last = &(head)->sqh_first; \
4553 + * Tail queue definitions.
4555 +#define DWC_TAILQ_HEAD(name, type) \
4557 + struct type *tqh_first; /* first element */ \
4558 + struct type **tqh_last; /* addr of last next element */ \
4561 +#define DWC_TAILQ_HEAD_INITIALIZER(head) \
4562 + { NULL, &(head).tqh_first }
4564 +#define DWC_TAILQ_ENTRY(type) \
4566 + struct type *tqe_next; /* next element */ \
4567 + struct type **tqe_prev; /* address of previous next element */ \
4571 + * tail queue access methods
4573 +#define DWC_TAILQ_FIRST(head) ((head)->tqh_first)
4574 +#define DWC_TAILQ_END(head) NULL
4575 +#define DWC_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
4576 +#define DWC_TAILQ_LAST(head, headname) \
4577 + (*(((struct headname *)((head)->tqh_last))->tqh_last))
4579 +#define DWC_TAILQ_PREV(elm, headname, field) \
4580 + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
4581 +#define DWC_TAILQ_EMPTY(head) \
4582 + (TAILQ_FIRST(head) == TAILQ_END(head))
4584 +#define DWC_TAILQ_FOREACH(var, head, field) \
4585 + for((var) = TAILQ_FIRST(head); \
4586 + (var) != TAILQ_END(head); \
4587 + (var) = TAILQ_NEXT(var, field))
4589 +#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
4590 + for((var) = TAILQ_LAST(head, headname); \
4591 + (var) != TAILQ_END(head); \
4592 + (var) = TAILQ_PREV(var, headname, field))
4595 + * Tail queue functions.
4597 +#define DWC_TAILQ_INIT(head) do { \
4598 + (head)->tqh_first = NULL; \
4599 + (head)->tqh_last = &(head)->tqh_first; \
4602 +#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do { \
4603 + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
4604 + (head)->tqh_first->field.tqe_prev = \
4605 + &(elm)->field.tqe_next; \
4607 + (head)->tqh_last = &(elm)->field.tqe_next; \
4608 + (head)->tqh_first = (elm); \
4609 + (elm)->field.tqe_prev = &(head)->tqh_first; \
4612 +#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do { \
4613 + (elm)->field.tqe_next = NULL; \
4614 + (elm)->field.tqe_prev = (head)->tqh_last; \
4615 + *(head)->tqh_last = (elm); \
4616 + (head)->tqh_last = &(elm)->field.tqe_next; \
4619 +#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
4620 + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
4621 + (elm)->field.tqe_next->field.tqe_prev = \
4622 + &(elm)->field.tqe_next; \
4624 + (head)->tqh_last = &(elm)->field.tqe_next; \
4625 + (listelm)->field.tqe_next = (elm); \
4626 + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
4629 +#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
4630 + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
4631 + (elm)->field.tqe_next = (listelm); \
4632 + *(listelm)->field.tqe_prev = (elm); \
4633 + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
4636 +#define DWC_TAILQ_REMOVE(head, elm, field) do { \
4637 + if (((elm)->field.tqe_next) != NULL) \
4638 + (elm)->field.tqe_next->field.tqe_prev = \
4639 + (elm)->field.tqe_prev; \
4641 + (head)->tqh_last = (elm)->field.tqe_prev; \
4642 + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
4645 +#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do { \
4646 + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
4647 + (elm2)->field.tqe_next->field.tqe_prev = \
4648 + &(elm2)->field.tqe_next; \
4650 + (head)->tqh_last = &(elm2)->field.tqe_next; \
4651 + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
4652 + *(elm2)->field.tqe_prev = (elm2); \
4656 + * Circular queue definitions.
4658 +#define DWC_CIRCLEQ_HEAD(name, type) \
4660 + struct type *cqh_first; /* first element */ \
4661 + struct type *cqh_last; /* last element */ \
4664 +#define DWC_CIRCLEQ_HEAD_INITIALIZER(head) \
4665 + { DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
4667 +#define DWC_CIRCLEQ_ENTRY(type) \
4669 + struct type *cqe_next; /* next element */ \
4670 + struct type *cqe_prev; /* previous element */ \
4674 + * Circular queue access methods
4676 +#define DWC_CIRCLEQ_FIRST(head) ((head)->cqh_first)
4677 +#define DWC_CIRCLEQ_LAST(head) ((head)->cqh_last)
4678 +#define DWC_CIRCLEQ_END(head) ((void *)(head))
4679 +#define DWC_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
4680 +#define DWC_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
4681 +#define DWC_CIRCLEQ_EMPTY(head) \
4682 + (DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
4684 +#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
4686 +#define DWC_CIRCLEQ_FOREACH(var, head, field) \
4687 + for((var) = DWC_CIRCLEQ_FIRST(head); \
4688 + (var) != DWC_CIRCLEQ_END(head); \
4689 + (var) = DWC_CIRCLEQ_NEXT(var, field))
4691 +#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field) \
4692 + for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
4693 + (var) != DWC_CIRCLEQ_END(head); \
4694 + (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
4696 +#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field) \
4697 + for((var) = DWC_CIRCLEQ_LAST(head); \
4698 + (var) != DWC_CIRCLEQ_END(head); \
4699 + (var) = DWC_CIRCLEQ_PREV(var, field))
4702 + * Circular queue functions.
4704 +#define DWC_CIRCLEQ_INIT(head) do { \
4705 + (head)->cqh_first = DWC_CIRCLEQ_END(head); \
4706 + (head)->cqh_last = DWC_CIRCLEQ_END(head); \
4709 +#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do { \
4710 + (elm)->field.cqe_next = NULL; \
4711 + (elm)->field.cqe_prev = NULL; \
4714 +#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
4715 + (elm)->field.cqe_next = (listelm)->field.cqe_next; \
4716 + (elm)->field.cqe_prev = (listelm); \
4717 + if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
4718 + (head)->cqh_last = (elm); \
4720 + (listelm)->field.cqe_next->field.cqe_prev = (elm); \
4721 + (listelm)->field.cqe_next = (elm); \
4724 +#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
4725 + (elm)->field.cqe_next = (listelm); \
4726 + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
4727 + if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
4728 + (head)->cqh_first = (elm); \
4730 + (listelm)->field.cqe_prev->field.cqe_next = (elm); \
4731 + (listelm)->field.cqe_prev = (elm); \
4734 +#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
4735 + (elm)->field.cqe_next = (head)->cqh_first; \
4736 + (elm)->field.cqe_prev = DWC_CIRCLEQ_END(head); \
4737 + if ((head)->cqh_last == DWC_CIRCLEQ_END(head)) \
4738 + (head)->cqh_last = (elm); \
4740 + (head)->cqh_first->field.cqe_prev = (elm); \
4741 + (head)->cqh_first = (elm); \
4744 +#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
4745 + (elm)->field.cqe_next = DWC_CIRCLEQ_END(head); \
4746 + (elm)->field.cqe_prev = (head)->cqh_last; \
4747 + if ((head)->cqh_first == DWC_CIRCLEQ_END(head)) \
4748 + (head)->cqh_first = (elm); \
4750 + (head)->cqh_last->field.cqe_next = (elm); \
4751 + (head)->cqh_last = (elm); \
4754 +#define DWC_CIRCLEQ_REMOVE(head, elm, field) do { \
4755 + if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
4756 + (head)->cqh_last = (elm)->field.cqe_prev; \
4758 + (elm)->field.cqe_next->field.cqe_prev = \
4759 + (elm)->field.cqe_prev; \
4760 + if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
4761 + (head)->cqh_first = (elm)->field.cqe_next; \
4763 + (elm)->field.cqe_prev->field.cqe_next = \
4764 + (elm)->field.cqe_next; \
4767 +#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do { \
4768 + DWC_CIRCLEQ_REMOVE(head, elm, field); \
4769 + DWC_CIRCLEQ_INIT_ENTRY(elm, field); \
4772 +#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
4773 + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
4774 + DWC_CIRCLEQ_END(head)) \
4775 + (head).cqh_last = (elm2); \
4777 + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
4778 + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
4779 + DWC_CIRCLEQ_END(head)) \
4780 + (head).cqh_first = (elm2); \
4782 + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
4785 +#endif /* !_SYS_QUEUE_H_ */
4787 +++ b/drivers/usb/host/dwc_common_port/dwc_mem.c
4789 +#include "dwc_os.h"
4790 +#include "dwc_list.h"
4792 +/* Memory Debugging */
4793 +#ifdef DEBUG_MEMORY
4802 + DWC_CIRCLEQ_ENTRY(allocation) entry;
4805 +DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
4807 +struct allocation_manager
4809 + struct allocation_queue allocations;
4821 +static struct allocation_manager *manager = NULL;
4823 +static void add_allocation(uint32_t size, char const* func, int line, void *addr, int dma)
4825 + struct allocation *a = __DWC_ALLOC_ATOMIC(sizeof(*a));
4826 + a->func = __DWC_ALLOC_ATOMIC(DWC_STRLEN(func)+1);
4827 + DWC_MEMCPY(a->func, func, DWC_STRLEN(func)+1);
4832 + DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
4834 + /* Update stats */
4836 + manager->num_active ++;
4837 + manager->total += size;
4838 + manager->current += size;
4839 + if (manager->max < manager->current) {
4840 + manager->max = manager->current;
4844 +static struct allocation *find_allocation(void *addr)
4846 + struct allocation *a;
4847 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
4848 + if (a->addr == addr) {
4855 +static void free_allocation(void *addr, char const* func, int line)
4857 + struct allocation *a = find_allocation(addr);
4858 + if (!a && func && (line >= 0)) {
4859 + DWC_ASSERT(0, "Free of address %p that was never allocated or already freed %s:%d", addr, func, line);
4862 + DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
4864 + manager->num_active --;
4865 + manager->num_freed ++;
4866 + manager->current -= a->size;
4867 + __DWC_FREE(a->func);
4871 +void dwc_memory_debug_start(void)
4873 + DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
4874 + if (manager == NULL) {
4875 + manager = __DWC_ALLOC(sizeof(*manager));
4878 + DWC_CIRCLEQ_INIT(&manager->allocations);
4880 + manager->num_freed = 0;
4881 + manager->num_active = 0;
4882 + manager->total = 0;
4883 + manager->current = 0;
4887 +void dwc_memory_debug_stop(void)
4889 + struct allocation *a;
4890 + dwc_memory_debug_report();
4892 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
4893 + DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
4894 + free_allocation(a->addr, NULL, -1);
4897 + __DWC_FREE(manager);
4900 +void dwc_memory_debug_report(void)
4902 + struct allocation *a;
4903 + DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
4904 + DWC_PRINTF("Num Allocations = %d\n", manager->num);
4905 + DWC_PRINTF("Freed = %d\n", manager->num_freed);
4906 + DWC_PRINTF("Active = %d\n", manager->num_active);
4907 + DWC_PRINTF("Current Memory Used = %d\n", manager->current);
4908 + DWC_PRINTF("Total Memory Used = %d\n", manager->total);
4909 + DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
4910 + DWC_PRINTF("Unfreed allocations:\n");
4912 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
4913 + DWC_PRINTF(" addr=%p, size=%d from %s:%d, DMA=%d\n", a->addr, a->size, a->func, a->line, a->dma);
4919 +/* The replacement functions */
4920 +void *dwc_alloc_debug(uint32_t size, char const* func, int line)
4922 + void *addr = __DWC_ALLOC(size);
4923 + add_allocation(size, func, line, addr, 0);
4927 +void *dwc_alloc_atomic_debug(uint32_t size, char const* func, int line)
4929 + void *addr = __DWC_ALLOC_ATOMIC(size);
4930 + add_allocation(size, func, line, addr, 0);
4934 +void dwc_free_debug(void *addr, char const* func, int line)
4936 + free_allocation(addr, func, line);
4940 +void *dwc_dma_alloc_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line)
4942 + void *addr = __DWC_DMA_ALLOC(size, dma_addr);
4943 + add_allocation(size, func, line, addr, 1);
4947 +void *dwc_dma_alloc_atomic_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line)
4949 + void *addr = __DWC_DMA_ALLOC_ATOMIC(size, dma_addr);
4950 + add_allocation(size, func, line, addr, 1);
4954 +void dwc_dma_free_debug(uint32_t size, void *virt_addr, dwc_dma_t dma_addr, char const *func, int line)
4956 + free_allocation(virt_addr, func, line);
4957 + __DWC_DMA_FREE(size, virt_addr, dma_addr);
4960 +#endif /* DEBUG_MEMORY */
4962 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.c
4964 +/* Bignum routines adapted from PUTTY sources. PuTTY copyright notice follows.
4966 + * PuTTY is copyright 1997-2007 Simon Tatham.
4968 + * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
4969 + * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
4970 + * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
4971 + * Kuhn, and CORE SDI S.A.
4973 + * Permission is hereby granted, free of charge, to any person
4974 + * obtaining a copy of this software and associated documentation files
4975 + * (the "Software"), to deal in the Software without restriction,
4976 + * including without limitation the rights to use, copy, modify, merge,
4977 + * publish, distribute, sublicense, and/or sell copies of the Software,
4978 + * and to permit persons to whom the Software is furnished to do so,
4979 + * subject to the following conditions:
4981 + * The above copyright notice and this permission notice shall be
4982 + * included in all copies or substantial portions of the Software.
4984 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4985 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4986 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
4987 + * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
4988 + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
4989 + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4990 + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4994 +#ifndef CONFIG_MACH_IPMATE
4997 +#include "dwc_modpow.h"
4999 +#define BIGNUM_INT_MASK 0xFFFFFFFFUL
5000 +#define BIGNUM_TOP_BIT 0x80000000UL
5001 +#define BIGNUM_INT_BITS 32
5004 +static void *snmalloc(size_t n, size_t size)
5008 + if (size == 0) size = 1;
5009 + p = DWC_ALLOC(size);
5013 +#define snewn(n, type) ((type *)snmalloc((n), sizeof(type)))
5014 +#define sfree DWC_FREE
5018 + * * Do not call the DIVMOD_WORD macro with expressions such as array
5019 + * subscripts, as some implementations object to this (see below).
5020 + * * Note that none of the division methods below will cope if the
5021 + * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
5022 + * to avoid this case.
5023 + * If this condition occurs, in the case of the x86 DIV instruction,
5024 + * an overflow exception will occur, which (according to a correspondent)
5025 + * will manifest on Windows as something like
5026 + * 0xC0000095: Integer overflow
5027 + * The C variant won't give the right answer, either.
5030 +#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
5032 +#if defined __GNUC__ && defined __i386__
5033 +#define DIVMOD_WORD(q, r, hi, lo, w) \
5034 + __asm__("div %2" : \
5035 + "=d" (r), "=a" (q) : \
5036 + "r" (w), "d" (hi), "a" (lo))
5038 +#define DIVMOD_WORD(q, r, hi, lo, w) do { \
5039 + BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
5048 +#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
5050 +#define BIGNUM_INTERNAL
5052 +static Bignum newbn(int length)
5054 + Bignum b = snewn(length + 1, BignumInt);
5056 + //abort(); /* FIXME */
5057 + DWC_MEMSET(b, 0, (length + 1) * sizeof(*b));
5062 +void freebn(Bignum b)
5065 + * Burn the evidence, just in case.
5067 + DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1));
5072 + * Compute c = a * b.
5073 + * Input is in the first len words of a and b.
5074 + * Result is returned in the first 2*len words of c.
5076 +static void internal_mul(BignumInt *a, BignumInt *b,
5077 + BignumInt *c, int len)
5082 + for (j = 0; j < 2 * len; j++)
5085 + for (i = len - 1; i >= 0; i--) {
5087 + for (j = len - 1; j >= 0; j--) {
5088 + t += MUL_WORD(a[i], (BignumDblInt) b[j]);
5089 + t += (BignumDblInt) c[i + j + 1];
5090 + c[i + j + 1] = (BignumInt) t;
5091 + t = t >> BIGNUM_INT_BITS;
5093 + c[i] = (BignumInt) t;
5097 +static void internal_add_shifted(BignumInt *number,
5098 + unsigned n, int shift)
5100 + int word = 1 + (shift / BIGNUM_INT_BITS);
5101 + int bshift = shift % BIGNUM_INT_BITS;
5102 + BignumDblInt addend;
5104 + addend = (BignumDblInt)n << bshift;
5107 + addend += number[word];
5108 + number[word] = (BignumInt) addend & BIGNUM_INT_MASK;
5109 + addend >>= BIGNUM_INT_BITS;
5115 + * Compute a = a % m.
5116 + * Input in first alen words of a and first mlen words of m.
5117 + * Output in first alen words of a
5118 + * (of which first alen-mlen words will be zero).
5119 + * The MSW of m MUST have its high bit set.
5120 + * Quotient is accumulated in the `quotient' array, which is a Bignum
5121 + * rather than the internal bigendian format. Quotient parts are shifted
5122 + * left by `qshift' before adding into quot.
5124 +static void internal_mod(BignumInt *a, int alen,
5125 + BignumInt *m, int mlen,
5126 + BignumInt *quot, int qshift)
5138 + for (i = 0; i <= alen - mlen; i++) {
5140 + unsigned int q, r, c, ai1;
5149 + if (i == alen - 1)
5154 + /* Find q = h:a[i] / m0 */
5159 + * To illustrate it, suppose a BignumInt is 8 bits, and
5160 + * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then
5161 + * our initial division will be 0xA123 / 0xA1, which
5162 + * will give a quotient of 0x100 and a divide overflow.
5163 + * However, the invariants in this division algorithm
5164 + * are not violated, since the full number A1:23:... is
5165 + * _less_ than the quotient prefix A1:B2:... and so the
5166 + * following correction loop would have sorted it out.
5168 + * In this situation we set q to be the largest
5169 + * quotient we _can_ stomach (0xFF, of course).
5171 + q = BIGNUM_INT_MASK;
5173 + /* Macro doesn't want an array subscript expression passed
5174 + * into it (see definition), so use a temporary. */
5175 + BignumInt tmplo = a[i];
5176 + DIVMOD_WORD(q, r, h, tmplo, m0);
5178 + /* Refine our estimate of q by looking at
5179 + h:a[i]:a[i+1] / m0:m1 */
5180 + t = MUL_WORD(m1, q);
5181 + if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
5184 + r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */
5185 + if (r >= (BignumDblInt) m0 &&
5186 + t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
5190 + /* Subtract q * m from a[i...] */
5192 + for (k = mlen - 1; k >= 0; k--) {
5193 + t = MUL_WORD(q, m[k]);
5195 + c = (unsigned)(t >> BIGNUM_INT_BITS);
5196 + if ((BignumInt) t > a[i + k])
5198 + a[i + k] -= (BignumInt) t;
5201 + /* Add back m in case of borrow */
5204 + for (k = mlen - 1; k >= 0; k--) {
5207 + a[i + k] = (BignumInt) t;
5208 + t = t >> BIGNUM_INT_BITS;
5213 + internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
5218 + * Compute p % mod.
5219 + * The most significant word of mod MUST be non-zero.
5220 + * We assume that the result array is the same size as the mod array.
5221 + * We optionally write out a quotient if `quotient' is non-NULL.
5222 + * We can avoid writing out the result if `result' is NULL.
5224 +void bigdivmod(Bignum p, Bignum mod, Bignum result, Bignum quotient)
5228 + int plen, mlen, i, j;
5230 + /* Allocate m of size mlen, copy mod to m */
5231 + /* We use big endian internally */
5233 + m = snewn(mlen, BignumInt);
5234 + for (j = 0; j < mlen; j++)
5235 + m[j] = mod[mod[0] - j];
5237 + /* Shift m left to make msb bit set */
5238 + for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
5239 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
5242 + for (i = 0; i < mlen - 1; i++)
5243 + m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift));
5244 + m[mlen - 1] = m[mlen - 1] << mshift;
5248 + /* Ensure plen > mlen */
5252 + /* Allocate n of size plen, copy p to n */
5253 + n = snewn(plen, BignumInt);
5254 + for (j = 0; j < plen; j++)
5256 + for (j = 1; j <= (int)p[0]; j++)
5257 + n[plen - j] = p[j];
5259 + /* Main computation */
5260 + internal_mod(n, plen, m, mlen, quotient, mshift);
5262 + /* Fixup result in case the modulus was shifted */
5264 + for (i = plen - mlen - 1; i < plen - 1; i++)
5265 + n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift));
5266 + n[plen - 1] = n[plen - 1] << mshift;
5267 + internal_mod(n, plen, m, mlen, quotient, 0);
5268 + for (i = plen - 1; i >= plen - mlen; i--)
5269 + n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift));
5272 + /* Copy result to buffer */
5274 + for (i = 1; i <= (int)result[0]; i++) {
5276 + result[i] = j >= 0 ? n[j] : 0;
5280 + /* Free temporary arrays */
5281 + for (i = 0; i < mlen; i++)
5284 + for (i = 0; i < plen; i++)
5290 + * Simple remainder.
5292 +Bignum bigmod(Bignum a, Bignum b)
5294 + Bignum r = newbn(b[0]);
5295 + bigdivmod(a, b, r, NULL);
5300 + * Compute (base ^ exp) % mod.
5302 +Bignum dwc_modpow(Bignum base_in, Bignum exp, Bignum mod)
5304 + BignumInt *a, *b, *n, *m;
5307 + Bignum base, result;
5310 + * The most significant word of mod needs to be non-zero. It
5311 + * should already be, but let's make sure.
5313 + //assert(mod[mod[0]] != 0);
5316 + * Make sure the base is smaller than the modulus, by reducing
5317 + * it modulo the modulus if not.
5319 + base = bigmod(base_in, mod);
5321 + /* Allocate m of size mlen, copy mod to m */
5322 + /* We use big endian internally */
5324 + m = snewn(mlen, BignumInt);
5325 + for (j = 0; j < mlen; j++)
5326 + m[j] = mod[mod[0] - j];
5328 + /* Shift m left to make msb bit set */
5329 + for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
5330 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
5333 + for (i = 0; i < mlen - 1; i++)
5335 + (m[i] << mshift) | (m[i + 1] >>
5336 + (BIGNUM_INT_BITS - mshift));
5337 + m[mlen - 1] = m[mlen - 1] << mshift;
5340 + /* Allocate n of size mlen, copy base to n */
5341 + n = snewn(mlen, BignumInt);
5342 + i = mlen - base[0];
5343 + for (j = 0; j < i; j++)
5345 + for (j = 0; j < base[0]; j++)
5346 + n[i + j] = base[base[0] - j];
5348 + /* Allocate a and b of size 2*mlen. Set a = 1 */
5349 + a = snewn(2 * mlen, BignumInt);
5350 + b = snewn(2 * mlen, BignumInt);
5351 + for (i = 0; i < 2 * mlen; i++)
5353 + a[2 * mlen - 1] = 1;
5355 + /* Skip leading zero bits of exp. */
5357 + j = BIGNUM_INT_BITS - 1;
5358 + while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
5362 + j = BIGNUM_INT_BITS - 1;
5366 + /* Main computation */
5367 + while (i < exp[0]) {
5369 + internal_mul(a + mlen, a + mlen, b, mlen);
5370 + internal_mod(b, mlen * 2, m, mlen, NULL, 0);
5371 + if ((exp[exp[0] - i] & (1 << j)) != 0) {
5372 + internal_mul(b + mlen, n, a, mlen);
5373 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
5383 + j = BIGNUM_INT_BITS - 1;
5386 + /* Fixup result in case the modulus was shifted */
5388 + for (i = mlen - 1; i < 2 * mlen - 1; i++)
5390 + (a[i] << mshift) | (a[i + 1] >>
5391 + (BIGNUM_INT_BITS - mshift));
5392 + a[2 * mlen - 1] = a[2 * mlen - 1] << mshift;
5393 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
5394 + for (i = 2 * mlen - 1; i >= mlen; i--)
5396 + (a[i] >> mshift) | (a[i - 1] <<
5397 + (BIGNUM_INT_BITS - mshift));
5400 + /* Copy result to buffer */
5401 + result = newbn(mod[0]);
5402 + for (i = 0; i < mlen; i++)
5403 + result[result[0] - i] = a[i + mlen];
5404 + while (result[0] > 1 && result[result[0]] == 0)
5407 + /* Free temporary arrays */
5408 + for (i = 0; i < 2 * mlen; i++)
5411 + for (i = 0; i < 2 * mlen; i++)
5414 + for (i = 0; i < mlen; i++)
5417 + for (i = 0; i < mlen; i++)
5429 +static __u32 dh_p[] = {
5529 +static __u32 dh_a[] = {
5541 +static __u32 dh_b[] = {
5553 +static __u32 dh_g[] = {
5562 + k = modpow(dh_g, dh_a, dh_p);
5565 + for (i=0; i<k[0]; i++) {
5566 + __u32 word32 = k[k[0] - i];
5567 + __u16 l = word32 & 0xffff;
5568 + __u16 m = (word32 & 0xffff0000) >> 16;
5569 + printf("%04x %04x ", m, l);
5570 + if (!((i + 1)%13)) printf("\n");
5574 + if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) {
5575 + printf("PASS\n\n");
5578 + printf("FAIL\n\n");
5583 +#endif /* UNITTEST */
5585 +#endif /* CONFIG_MACH_IPMATE */
5587 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.h
5591 + * See dwc_modpow.c for license and changes
5593 +#ifndef _DWC_MODPOW_H
5594 +#define _DWC_MODPOW_H
5596 +#include "dwc_os.h"
5600 + * This file defines the module exponentiation function which is only used
5601 + * internally by the DWC UWB modules for calculation of PKs during numeric
5602 + * association. The routine is taken from the PUTTY, an open source terminal
5603 + * emulator. The PUTTY License is preserved in the dwc_modpow.c file.
5607 +typedef uint32_t BignumInt;
5608 +typedef uint64_t BignumDblInt;
5609 +typedef BignumInt *Bignum;
5611 +/* Compute modular exponentiaion */
5612 +extern Bignum dwc_modpow(Bignum base_in, Bignum exp, Bignum mod);
5614 +#endif /* _LINUX_BIGNUM_H */
5616 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.c
5618 +#include "dwc_notifier.h"
5619 +#include "dwc_list.h"
5621 +typedef struct dwc_observer
5624 + dwc_notifier_callback_t callback;
5626 + char *notification;
5627 + DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
5630 +DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
5632 +typedef struct dwc_notifier
5635 + struct observer_queue observers;
5636 + DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
5639 +DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
5641 +typedef struct manager
5644 + dwc_mutex_t *mutex;
5645 + struct notifier_queue notifiers;
5648 +static manager_t *manager = NULL;
5650 +static void create_manager(void)
5652 + manager = DWC_ALLOC(sizeof(manager_t));
5653 + DWC_CIRCLEQ_INIT(&manager->notifiers);
5654 + manager->wq = DWC_WORKQ_ALLOC("DWC Notification WorkQ");
5657 +static void free_manager(void)
5659 + DWC_WORKQ_FREE(manager->wq);
5660 + /* All notifiers must have unregistered themselves before this module
5661 + * can be removed. Hitting this assertion indicates a programmer
5663 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers), "Notification manager being freed before all notifiers have been removed");
5664 + DWC_FREE(manager);
5668 +static void dump_manager(void)
5672 + DWC_ASSERT(manager, "Notification manager not found");
5673 + DWC_DEBUG("List of all notifiers and observers:");
5674 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
5675 + DWC_DEBUG("Notifier %p has observers:", n->object);
5676 + DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
5677 + DWC_DEBUG(" %p watching %s", o->observer, o->notification);
5682 +#define dump_manager(...)
5685 +static observer_t *alloc_observer(void *observer, char *notification, dwc_notifier_callback_t callback, void *data)
5687 + observer_t *new_observer = DWC_ALLOC(sizeof(observer_t));
5688 + DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
5689 + new_observer->observer = observer;
5690 + new_observer->notification = notification;
5691 + new_observer->callback = callback;
5692 + new_observer->data = data;
5693 + return new_observer;
5696 +static void free_observer(observer_t *observer)
5698 + DWC_FREE(observer);
5701 +static notifier_t *alloc_notifier(void *object)
5703 + notifier_t *notifier;
5709 + notifier = DWC_ALLOC(sizeof(notifier_t));
5710 + DWC_CIRCLEQ_INIT(¬ifier->observers);
5711 + DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
5713 + notifier->object = object;
5717 +static void free_notifier(notifier_t *notifier)
5719 + observer_t *observer;
5720 + DWC_CIRCLEQ_FOREACH(observer, ¬ifier->observers, list_entry) {
5721 + free_observer(observer);
5723 + DWC_FREE(notifier);
5726 +static notifier_t *find_notifier(void *object)
5728 + notifier_t *notifier;
5732 + DWC_ASSERT(manager, "Notification manager not found");
5733 + DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
5734 + if (notifier->object == object) {
5741 +void dwc_alloc_notification_manager(void)
5746 +void dwc_free_notification_manager(void)
5751 +dwc_notifier_t *dwc_register_notifier(void *object)
5753 + notifier_t *notifier = find_notifier(object);
5754 + DWC_ASSERT(manager, "Notification manager not found");
5756 + DWC_ERROR("Notifier %p is already registered", object);
5760 + notifier = alloc_notifier(object);
5761 + DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
5764 + DWC_INFO("Notifier %p registered", object);
5770 +void dwc_unregister_notifier(dwc_notifier_t *notifier)
5772 + DWC_ASSERT(manager, "Notification manager not found");
5773 + if (!DWC_CIRCLEQ_EMPTY(¬ifier->observers)) {
5775 + DWC_ERROR("Notifier %p has active observers when removing", notifier->object);
5776 + DWC_CIRCLEQ_FOREACH(o, ¬ifier->observers, list_entry) {
5777 + DWC_DEBUG(" %p watching %s", o->observer, o->notification);
5779 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(¬ifier->observers), "Notifier %p has active observers when removing", notifier);
5782 + DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
5783 + free_notifier(notifier);
5785 + DWC_INFO("Notifier unregistered");
5789 +/* Add an observer to observe the notifier for a particular state, event, or notification. */
5790 +int dwc_add_observer(void *observer, void *object, char *notification, dwc_notifier_callback_t callback, void *data)
5792 + notifier_t *notifier = find_notifier(object);
5793 + observer_t *new_observer;
5795 + DWC_ERROR("Notifier %p is not found when adding observer", object);
5799 + new_observer = alloc_observer(observer, notification, callback, data);
5801 + DWC_CIRCLEQ_INSERT_TAIL(¬ifier->observers, new_observer, list_entry);
5803 + DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
5804 + observer, object, notification, callback, data);
5810 +int dwc_remove_observer(void *observer)
5813 + DWC_ASSERT(manager, "Notification manager not found");
5814 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
5817 + DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
5818 + if (o->observer == observer) {
5819 + DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
5820 + DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
5821 + o->observer, n->object, o->notification);
5831 +typedef struct callback_data
5833 + dwc_notifier_callback_t cb;
5837 + void *notification;
5838 + void *notification_data;
5841 +static void cb_task(void *data)
5843 + cb_data_t *cb = (cb_data_t *)data;
5844 + cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
5848 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
5851 + DWC_ASSERT(manager, "Notification manager not found");
5852 + DWC_CIRCLEQ_FOREACH(o, ¬ifier->observers, list_entry) {
5853 + int len = DWC_STRLEN(notification);
5854 + if (DWC_STRLEN(o->notification) != len) {
5858 + if (DWC_STRNCMP(o->notification, notification, len) == 0) {
5859 + cb_data_t *cb_data = DWC_ALLOC(sizeof(cb_data_t));
5860 + cb_data->cb = o->callback;
5861 + cb_data->observer = o->observer;
5862 + cb_data->data = o->data;
5863 + cb_data->object = notifier->object;
5864 + cb_data->notification = notification;
5865 + cb_data->notification_data = notification_data;
5866 + DWC_DEBUG("Observer found %p for notification %s", o->observer, notification);
5867 + DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
5868 + "Notify callback from %p for Notification %s, to observer %p",
5869 + cb_data->object, notification, cb_data->observer);
5875 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.h
5878 +#ifndef __DWC_NOTIFIER_H__
5879 +#define __DWC_NOTIFIER_H__
5881 +#include "dwc_os.h"
5885 + * A simple implementation of the Observer pattern. Any "module" can
5886 + * register as an observer or notifier. The notion of "module" is abstract and
5887 + * can mean anything used to identify either an observer or notifier. Usually
5888 + * it will be a pointer to a data structure which contains some state, ie an
5891 + * Before any notifiers can be added, the global notification manager must be
5892 + * brought up with dwc_alloc_notification_manager().
5893 + * dwc_free_notification_manager() will bring it down and free all resources.
5894 + * These would typically be called upon module load and unload. The
5895 + * notification manager is a single global instance that handles all registered
5896 + * observable modules and observers so this should be done only once.
5898 + * A module can be observable by using Notifications to publicize some general
5899 + * information about it's state or operation. It does not care who listens, or
5900 + * even if anyone listens, or what they do with the information. The observable
5901 + * modules do not need to know any information about it's observers or their
5902 + * interface, or their state or data.
5904 + * Any module can register to emit Notifications. It should publish a list of
5905 + * notifications that it can emit and their behavior, such as when they will get
5906 + * triggered, and what information will be provided to the observer. Then it
5907 + * should register itself as an observable module. See dwc_register_notifier().
5909 + * Any module can observe any observable, registered module, provided it has a
5910 + * handle to the other module and knows what notifications to observe. See
5911 + * dwc_add_observer().
5913 + * A function of type dwc_notifier_callback_t is called whenever a notification
5914 + * is triggered with one or more observers observing it. This function is
5915 + * called in it's own process so it may sleep or block if needed. It is
5916 + * guaranteed to be called sometime after the notification has occurred and will
5917 + * be called once per each time the notification is triggered. It will NOT be
5918 + * called in the same process context used to trigger the notification.
5920 + * @section Limitiations
5922 + * Keep in mind that Notifications that can be triggered in rapid sucession may
5923 + * schedule too many processes too handle. Be aware of this limitation when
5924 + * designing to use notifications, and only add notifications for appropriate
5925 + * observable information.
5927 + * Also Notification callbacks are not synchronous. If you need to synchronize
5928 + * the behavior between module/observer you must use other means. And perhaps
5929 + * that will mean Notifications are not the proper solution.
5932 +struct dwc_notifier;
5933 +typedef struct dwc_notifier dwc_notifier_t;
5935 +/** The callback function must be of this type.
5937 + * @param object This is the object that is being observed.
5938 + * @param notification This is the notification that was triggered.
5939 + * @param observer This is the observer
5940 + * @param notification_data This is notification-specific data that the notifier
5941 + * has included in this notification. The value of this should be published in
5942 + * the documentation of the observable module with the notifications.
5943 + * @param user_data This is any custom data that the observer provided when
5944 + * adding itself as an observer to the notification. */
5945 +typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer, void *notification_data, void *user_data);
5947 +/** Brings up the notification manager. */
5948 +extern void dwc_alloc_notification_manager(void);
5949 +/** Brings down the notification manager. */
5950 +extern void dwc_free_notification_manager(void);
5952 +/** This function register an observable module. A dwc_notifier_t object is
5953 + * returned to the observable module. This is an opaque object that is used by
5954 + * the observable module to trigger notifications. This object should only be
5955 + * accessible to functions that are authorized to trigger notifications for this
5956 + * module. Observers do not need this object. */
5957 +extern dwc_notifier_t *dwc_register_notifier(void *object);
5959 +/** This function unregister an observable module. All observers have to be
5960 + * removed prior to unregistration. */
5961 +extern void dwc_unregister_notifier(dwc_notifier_t *notifier);
5963 +/** Add a module as an observer to the observable module. The observable module
5964 + * needs to have previously registered with the notification manager.
5966 + * @param observer The observer module
5967 + * @param object The module to observe
5968 + * @param notification The notification to observe
5969 + * @param callback The callback function to call
5970 + * @param user_data Any additional user data to pass into the callback function */
5971 +extern int dwc_add_observer(void *observer, void *object, char *notification, dwc_notifier_callback_t callback, void *user_data);
5973 +/** Removes the specified observer from all notifications that it is currently
5975 +extern int dwc_remove_observer(void *observer);
5977 +/** This function triggers a Notification. It should be called by the
5978 + * observable module, or any module or library which the observable module
5979 + * allows to trigger notification on it's behalf. Such as the dwc_cc_t.
5981 + * dwc_notify is a non-blocking function. Callbacks are scheduled called in
5982 + * their own process context for each trigger. Callbacks can be blocking.
5983 + * dwc_notify can be called from interrupt context if needed.
5986 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data);
5988 +#endif /* __DWC_NOTIFIER_H__ */
5990 +++ b/drivers/usb/host/dwc_common_port/dwc_os.h
5992 +/* =========================================================================
5993 + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_os.h $
5995 + * $Date: 2009/04/02 $
5996 + * $Change: 1224130 $
5998 + * Synopsys Portability Library Software and documentation
5999 + * (hereinafter, "Software") is an Unsupported proprietary work of
6000 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
6001 + * between Synopsys and you.
6003 + * The Software IS NOT an item of Licensed Software or Licensed Product
6004 + * under any End User Software License Agreement or Agreement for
6005 + * Licensed Product with Synopsys or any supplement thereto. You are
6006 + * permitted to use and redistribute this Software in source and binary
6007 + * forms, with or without modification, provided that redistributions
6008 + * of source code must retain this notice. You may not view, use,
6009 + * disclose, copy or distribute this file or any information contained
6010 + * herein except pursuant to this license grant from Synopsys. If you
6011 + * do not agree with this notice, including the disclaimer below, then
6012 + * you are not authorized to use the Software.
6014 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
6015 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6016 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
6017 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
6018 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
6019 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
6020 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
6021 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
6022 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6023 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
6024 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
6026 + * ========================================================================= */
6032 + * DWC portability library, low level os-wrapper functions
6036 +/* These basic types need to be defined by some OS header file or custom header
6037 + * file for your specific target architecture.
6039 + * uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
6041 + * Any custom or alternate header file must be added and enabled here.
6045 +# include <linux/types.h>
6046 +# ifdef CONFIG_DEBUG_MUTEXES
6047 +# include <linux/mutex.h>
6050 +# include <stdint.h>
6054 +/** @name Primitive Types and Values */
6056 +/** We define a boolean type for consistency. Can be either YES or NO */
6057 +typedef uint8_t dwc_bool_t;
6061 +/** @todo make them positive and return the negative error code */
6062 +/** @name Error Codes */
6063 +#define DWC_E_INVALID 1001
6064 +#define DWC_E_NO_MEMORY 1002
6065 +#define DWC_E_NO_DEVICE 1003
6066 +#define DWC_E_NOT_SUPPORTED 1004
6067 +#define DWC_E_TIMEOUT 1005
6068 +#define DWC_E_BUSY 1006
6069 +#define DWC_E_AGAIN 1007
6070 +#define DWC_E_RESTART 1008
6071 +#define DWC_E_ABORT 1009
6072 +#define DWC_E_SHUTDOWN 1010
6073 +#define DWC_E_NO_DATA 1011
6074 +#define DWC_E_DISCONNECT 2000
6075 +#define DWC_E_UNKNOWN 3000
6076 +#define DWC_E_NO_STREAM_RES 4001
6077 +#define DWC_E_COMMUNICATION 4002
6078 +#define DWC_E_OVERFLOW 4003
6079 +#define DWC_E_PROTOCOL 4004
6080 +#define DWC_E_IN_PROGRESS 4005
6081 +#define DWC_E_PIPE 4006
6082 +#define DWC_E_IO 4007
6083 +#define DWC_E_NO_SPACE 4008
6085 +/** @name Tracing/Logging Functions
6087 + * These function provide the capability to add tracing, debugging, and error
6088 + * messages, as well exceptions as assertions. The WUDEV uses these
6089 + * extensively. These could be logged to the main console, the serial port, an
6090 + * internal buffer, etc. These functions could also be no-op if they are too
6091 + * expensive on your system. By default undefining the DEBUG macro already
6092 + * no-ops some of these functions. */
6094 +#include <stdarg.h>
6096 +/** Returns non-zero if in interrupt context. */
6097 +extern dwc_bool_t DWC_IN_IRQ(void);
6098 +#define dwc_in_irq DWC_IN_IRQ
6100 +/** Returns "IRQ" if DWC_IN_IRQ is true. */
6101 +static inline char *dwc_irq(void) {
6102 + return DWC_IN_IRQ() ? "IRQ" : "";
6106 + * A vprintf() clone. Just call vprintf if you've got it.
6108 +extern void DWC_VPRINTF(char *format, va_list args);
6109 +#define dwc_vprintf DWC_VPRINTF
6112 + * A vsnprintf() clone. Just call vprintf if you've got it.
6114 +extern int DWC_VSNPRINTF(char *str, int size, char *format, va_list args);
6115 +#define dwc_vsnprintf DWC_VSNPRINTF
6118 + * printf() clone. Just call printf if you've go it.
6120 +extern void DWC_PRINTF(char *format, ...)
6121 +/* This provides compiler level static checking of the parameters if you're
6124 + __attribute__ ((format(printf, 1, 2)));
6128 +#define dwc_printf DWC_PRINTF
6131 + * sprintf() clone. Just call sprintf if you've got it.
6133 +extern int DWC_SPRINTF(char *string, char *format, ...)
6135 + __attribute__ ((format(printf, 2, 3)));
6139 +#define dwc_sprintf DWC_SPRINTF
6142 + * snprintf() clone. Just call snprintf if you've got it.
6144 +extern int DWC_SNPRINTF(char *string, int size, char *format, ...)
6146 + __attribute__ ((format(printf, 3, 4)));
6150 +#define dwc_snprintf DWC_SNPRINTF
6153 + * Prints a WARNING message. On systems that don't differentiate between
6154 + * warnings and regular log messages, just print it. Indicates that something
6155 + * may be wrong with the driver. Works like printf().
6157 + * Use the DWC_WARN macro to call this function.
6159 +extern void __DWC_WARN(char *format, ...)
6161 + __attribute__ ((format(printf, 1, 2)));
6167 + * Prints an error message. On systems that don't differentiate between errors
6168 + * and regular log messages, just print it. Indicates that something went wrong
6169 + * with the driver, but it can be recovered from. Works like printf().
6171 + * Use the DWC_ERROR macro to call this function.
6173 +extern void __DWC_ERROR(char *format, ...)
6175 + __attribute__ ((format(printf, 1, 2)));
6181 + * Prints an exception error message and takes some user-defined action such as
6182 + * print out a backtrace or trigger a breakpoint. Indicates that something went
6183 + * abnormally wrong with the driver such as programmer error, or other
6184 + * exceptional condition. It should not be ignored so even on systems without
6185 + * printing capability, some action should be taken to notify the developer of
6186 + * it. Works like printf().
6188 +extern void DWC_EXCEPTION(char *format, ...)
6190 + __attribute__ ((format(printf, 1, 2)));
6194 +#define dwc_exception DWC_EXCEPTION
6198 + * Prints out a debug message. Used for logging/trace messages.
6200 + * Use the DWC_DEBUG macro to call this function
6202 +extern void __DWC_DEBUG(char *format, ...)
6204 + __attribute__ ((format(printf, 1, 2)));
6209 +#define __DWC_DEBUG printk
6213 + * Prints out a Debug message.
6215 +#define DWC_DEBUG(_format, _args...) __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", __func__, dwc_irq(), ## _args)
6216 +#define dwc_debug DWC_DEBUG
6218 + * Prints out an informative message.
6220 +#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", dwc_irq(), ## _args)
6221 +#define dwc_info DWC_INFO
6223 + * Prints out a warning message.
6225 +#define DWC_WARN(_format, _args...) __DWC_WARN("WARN:%s:%s:%d: " _format "\n", dwc_irq(), __func__, __LINE__, ## _args)
6226 +#define dwc_warn DWC_WARN
6228 + * Prints out an error message.
6230 +#define DWC_ERROR(_format, _args...) __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", dwc_irq(), __func__, __LINE__, ## _args)
6231 +#define dwc_error DWC_ERROR
6233 +#define DWC_PROTO_ERROR(_format, _args...) __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", dwc_irq(), __func__, __LINE__, ## _args)
6234 +#define dwc_proto_error DWC_PROTO_ERROR
6237 +/** Prints out a exception error message if the _expr expression fails. Disabled
6238 + * if DEBUG is not enabled. */
6239 +#define DWC_ASSERT(_expr, _format, _args...) if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), __FILE__, __LINE__, ## _args); }
6241 +#define DWC_ASSERT(_x...)
6243 +#define dwc_assert DWC_ASSERT
6245 +/** @name Byter Ordering
6246 + * The following functions are for conversions between processor's byte ordering
6247 + * and specific ordering you want.
6250 +/** Converts 32 bit data in CPU byte ordering to little endian. */
6251 +extern uint32_t DWC_CPU_TO_LE32(void *p);
6252 +#define dwc_cpu_to_le32 DWC_CPU_TO_LE32
6253 +/** Converts 32 bit data in CPU byte orderint to big endian. */
6254 +extern uint32_t DWC_CPU_TO_BE32(void *p);
6255 +#define dwc_cpu_to_be32 DWC_CPU_TO_BE32
6257 +/** Converts 32 bit little endian data to CPU byte ordering. */
6258 +extern uint32_t DWC_LE32_TO_CPU(void *p);
6259 +#define dwc_le32_to_cpu DWC_LE32_TO_CPU
6260 +/** Converts 32 bit big endian data to CPU byte ordering. */
6261 +extern uint32_t DWC_BE32_TO_CPU(void *p);
6262 +#define dwc_be32_to_cpu DWC_BE32_TO_CPU
6264 +/** Converts 16 bit data in CPU byte ordering to little endian. */
6265 +extern uint16_t DWC_CPU_TO_LE16(void *p);
6266 +#define dwc_cpu_to_le16 DWC_CPU_TO_LE16
6267 +/** Converts 16 bit data in CPU byte orderint to big endian. */
6268 +extern uint16_t DWC_CPU_TO_BE16(void *p);
6269 +#define dwc_cpu_to_be16 DWC_CPU_TO_BE16
6271 +/** Converts 16 bit little endian data to CPU byte ordering. */
6272 +extern uint16_t DWC_LE16_TO_CPU(void *p);
6273 +#define dwc_le16_to_cpu DWC_LE16_TO_CPU
6274 +/** Converts 16 bit bi endian data to CPU byte ordering. */
6275 +extern uint16_t DWC_BE16_TO_CPU(void *p);
6276 +#define dwc_be16_to_cpu DWC_BE16_TO_CPU
6278 +/** @name Register Read/Write
6280 + * The following five functions should be implemented to read/write registers of
6281 + * 32-bit and 64-bit sizes. All modules use this to read/write register values.
6282 + * The reg value is a pointer to the register calculated from the void *base
6283 + * variable passed into the driver when it is started. */
6285 +/** Reads the content of a 32-bit register. */
6286 +extern uint32_t DWC_READ_REG32(uint32_t volatile *reg);
6287 +#define dwc_read_reg32 DWC_READ_REG32
6288 +/** Reads the content of a 64-bit register. */
6289 +extern uint64_t DWC_READ_REG64(uint64_t volatile *reg);
6290 +#define dwc_read_reg64 DWC_READ_REG64
6291 +/** Writes to a 32-bit register. */
6292 +extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value);
6293 +#define dwc_write_reg32 DWC_WRITE_REG32
6294 +/** Writes to a 64-bit register. */
6295 +extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value);
6296 +#define dwc_write_reg64 DWC_WRITE_REG64
6298 + * Modify bit values in a register. Using the
6299 + * algorithm: (reg_contents & ~clear_mask) | set_mask.
6301 +extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
6302 +#define dwc_modify_reg32 DWC_MODIFY_REG32
6306 +/** @name Some convenience MACROS used internally. Define DEBUG_REGS to log the
6307 + * register writes. */
6311 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
6312 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
6313 + return DWC_READ_REG32(&container->regs->_reg[num]); \
6315 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
6316 + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, &(((uint32_t*)container->regs->_reg)[num]), data); \
6317 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
6320 +#define dwc_define_read_write_reg(_reg,_container_type) \
6321 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
6322 + return DWC_READ_REG32(&container->regs->_reg); \
6324 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
6325 + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
6326 + DWC_WRITE_REG32(&container->regs->_reg, data); \
6331 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
6332 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
6333 + return DWC_READ_REG32(&container->regs->_reg[num]); \
6335 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
6336 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
6339 +#define dwc_define_read_write_reg(_reg,_container_type) \
6340 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
6341 + return DWC_READ_REG32(&container->regs->_reg); \
6343 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
6344 + DWC_WRITE_REG32(&container->regs->_reg, data); \
6352 +/** @name Crypto Functions
6354 + * These are the low-level cryptographic functions used by the driver. */
6356 +/** Perform AES CBC */
6357 +extern int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out);
6358 +#define dwc_aes_cbc DWC_AES_CBC
6359 +/** Fill the provided buffer with random bytes. These should be cryptographic grade random numbers. */
6360 +extern void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length);
6361 +#define dwc_random_bytes DWC_RANDOM_BYTES
6362 +/** Perform the SHA-256 hash function */
6363 +extern int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out);
6364 +#define dwc_sha256 DWC_SHA256
6365 +/** Calculated the HMAC-SHA256 */
6366 +extern int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out);
6367 +#define dwc_hmac_sha256 DWC_HMAC_SHA256
6370 +/** @name Memory Allocation
6372 + * These function provide access to memory allocation. There are only 2 DMA
6373 + * functions and 3 Regular memory functions that need to be implemented. None
6374 + * of the memory debugging routines need to be implemented. The allocation
6375 + * routines all ZERO the contents of the memory.
6377 + * Defining DEBUG_MEMORY turns on memory debugging and statistic gathering.
6378 + * This checks for memory leaks, keeping track of alloc/free pairs. It also
6379 + * keeps track of how much memory the driver is using at any given time. */
6381 +#define DWC_PAGE_SIZE 4096
6382 +#define DWC_PAGE_OFFSET(addr) (((uint32_t)addr) & 0xfff)
6383 +#define DWC_PAGE_ALIGNED(addr) ((((uint32_t)addr) & 0xfff) == 0)
6385 +#define DWC_INVALID_DMA_ADDR 0x0
6387 +typedef uint32_t dwc_dma_t;
6389 +/** @todo these functions will be added in the future */
6392 + * Creates a DMA pool from which you can allocate DMA buffers. Buffers
6393 + * allocated from this pool will be guaranteed to meet the size, alignment, and
6394 + * boundary requirements specified.
6396 + * @param[in] size Specifies the size of the buffers that will be allocated from
6398 + * @param[in] align Specifies the byte alignment requirements of the buffers
6399 + * allocated from this pool. Must be a power of 2.
6400 + * @param[in] boundary Specifies the N-byte boundary that buffers allocated from
6401 + * this pool must not cross.
6403 + * @returns A pointer to an internal opaque structure which is not to be
6404 + * accessed outside of these library functions. Use this handle to specify
6405 + * which pools to allocate/free DMA buffers from and also to destroy the pool,
6406 + * when you are done with it.
6408 +extern dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t boundary);
6410 + * Destroy a DMA pool. All buffers allocated from that pool must be freed first.
6412 +extern void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool);
6414 + * Allocate a buffer from the specified DMA pool and zeros its contents.
6416 +extern void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr);
6418 + * Free a previously allocated buffer from the DMA pool.
6420 +extern void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr);
6424 +/** Allocates a DMA capable buffer and zeroes its contents. */
6425 +extern void *__DWC_DMA_ALLOC(uint32_t size, dwc_dma_t *dma_addr);
6427 +/** Allocates a DMA capable buffer and zeroes its contents in atomic contest */
6428 +extern void *__DWC_DMA_ALLOC_ATOMIC(uint32_t size, dwc_dma_t *dma_addr);
6430 +/** Frees a previosly allocated buffer. */
6431 +extern void __DWC_DMA_FREE(uint32_t size, void *virt_addr, dwc_dma_t dma_addr);
6433 +/** Allocates a block of memory and zeroes its contents. */
6434 +extern void *__DWC_ALLOC(uint32_t size);
6436 +/** Allocates a block of memory and zeroes its contents, in an atomic manner
6437 + * which can be used inside interrupt context. The size should be sufficiently
6438 + * small, a few KB at most, such that failures are not likely to occur. Can just call
6439 + * __DWC_ALLOC if it is atomic. */
6440 +extern void *__DWC_ALLOC_ATOMIC(uint32_t size);
6442 +/** Frees a previously allocated buffer. */
6443 +extern void __DWC_FREE(void *addr);
6445 +#ifndef DEBUG_MEMORY
6447 +#define DWC_ALLOC(_size_) __DWC_ALLOC(_size_)
6448 +#define DWC_ALLOC_ATOMIC(_size_) __DWC_ALLOC_ATOMIC(_size_)
6449 +#define DWC_FREE(_addr_) __DWC_FREE(_addr_)
6450 +#define DWC_DMA_ALLOC(_size_,_dma_) __DWC_DMA_ALLOC(_size_,_dma_)
6451 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) __DWC_DMA_ALLOC_ATOMIC(_size_,_dma_)
6452 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) __DWC_DMA_FREE(_size_,_virt_,_dma_)
6456 +extern void *dwc_alloc_debug(uint32_t size, char const *func, int line);
6457 +extern void *dwc_alloc_atomic_debug(uint32_t size, char const *func, int line);
6458 +extern void dwc_free_debug(void *addr, char const *func, int line);
6459 +extern void *dwc_dma_alloc_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line);
6460 +extern void *dwc_dma_alloc_atomic_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line);
6461 +extern void dwc_dma_free_debug(uint32_t size, void *virt_addr, dwc_dma_t dma_addr, char const *func, int line);
6463 +extern void dwc_memory_debug_start(void);
6464 +extern void dwc_memory_debug_stop(void);
6465 +extern void dwc_memory_debug_report(void);
6467 +#define DWC_ALLOC(_size_) (dwc_alloc_debug(_size_, __func__, __LINE__))
6468 +#define DWC_ALLOC_ATOMIC(_size_) (dwc_alloc_atomic_debug(_size_, __func__, __LINE__))
6469 +#define DWC_FREE(_addr_) (dwc_free_debug(_addr_, __func__, __LINE__))
6470 +#define DWC_DMA_ALLOC(_size_,_dma_) dwc_dma_alloc_debug(_size_, _dma_, __func__, __LINE__)
6471 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) dwc_dma_alloc_atomic_debug(_size_, _dma_, __func__, __LINE__)
6472 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) dwc_dma_free_debug(_size_, _virt_, _dma_, __func__, __LINE__)
6474 +#endif /* DEBUG_MEMORY */
6476 +#define dwc_alloc DWC_ALLOC
6477 +#define dwc_alloc_atomic DWC_ALLOC_ATOMIC
6478 +#define dwc_free DWC_FREE
6479 +#define dwc_dma_alloc DWC_DMA_ALLOC
6480 +#define dwc_dma_alloc_atomic DWC_DMA_ALLOC_ATOMIC
6481 +#define dwc_dma_free DWC_DMA_FREE
6484 +/** @name Memory and String Processing */
6486 +/** memset() clone */
6487 +extern void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size);
6488 +#define dwc_memset DWC_MEMSET
6489 +/** memcpy() clone */
6490 +extern void *DWC_MEMCPY(void *dest, void const *src, uint32_t size);
6491 +#define dwc_memcpy DWC_MEMCPY
6492 +/** memmove() clone */
6493 +extern void *DWC_MEMMOVE(void *dest, void *src, uint32_t size);
6494 +#define dwc_memmove DWC_MEMMOVE
6495 +/** memcmp() clone */
6496 +extern int DWC_MEMCMP(void *m1, void *m2, uint32_t size);
6497 +#define dwc_memcmp DWC_MEMCMP
6498 +/** strcmp() clone */
6499 +extern int DWC_STRCMP(void *s1, void *s2);
6500 +#define dwc_strcmp DWC_STRCMP
6501 +/** strncmp() clone */
6502 +extern int DWC_STRNCMP(void *s1, void *s2, uint32_t size);
6503 +#define dwc_strncmp DWC_STRNCMP
6504 +/** strlen() clone, for NULL terminated ASCII strings */
6505 +extern int DWC_STRLEN(char const *str);
6506 +#define dwc_strlen DWC_STRLEN
6507 +/** strcpy() clone, for NULL terminated ASCII strings */
6508 +extern char *DWC_STRCPY(char *to, const char *from);
6509 +#define dwc_strcpy DWC_STRCPY
6511 +/** strdup() clone. If you wish to use memory allocation debugging, this
6512 + * implementation of strdup should use the DWC_* memory routines instead of
6513 + * calling a predefined strdup. Otherwise the memory allocated by this routine
6514 + * will not be seen by the debugging routines. */
6515 +extern char *DWC_STRDUP(char const *str);
6516 +#define dwc_strdup DWC_STRDUP
6518 +/** NOT an atoi() clone. Read the description carefully. Returns an integer
6519 + * converted from the string str in base 10 unless the string begins with a "0x"
6520 + * in which case it is base 16. String must be a NULL terminated sequence of
6521 + * ASCII characters and may optionally begin with whitespace, a + or -, and a
6522 + * "0x" prefix if base 16. The remaining characters must be valid digits for
6523 + * the number and end with a NULL character. If any invalid characters are
6524 + * encountered or it returns with a negative error code and the results of the
6525 + * conversion are undefined. On sucess it returns 0. Overflow conditions are
6526 + * undefined. An example implementation using atoi() can be referenced from the
6527 + * Linux implementation. */
6528 +extern int DWC_ATOI(char *str, int32_t *value);
6529 +#define dwc_atoi DWC_ATOI
6530 +/** Same as above but for unsigned. */
6531 +extern int DWC_ATOUI(char *str, uint32_t *value);
6532 +#define dwc_atoui DWC_ATOUI
6533 +/** This routine returns a UTF16LE unicode encoded string from a UTF8 string. */
6534 +extern int DWC_UTF8_TO_UTF16LE(uint8_t const *utf8string, uint16_t *utf16string, unsigned len);
6535 +#define dwc_utf8_to_utf16le DWC_UTF8_TO_UTF16LE
6537 +/** @name Wait queues
6539 + * Wait queues provide a means of synchronizing between threads or processes. A
6540 + * process can block on a waitq if some condition is not true, waiting for it to
6541 + * become true. When the waitq is triggered all waiting process will get
6542 + * unblocked and the condition will be check again. Waitqs should be triggered
6543 + * every time a condition can potentially change.*/
6545 +typedef struct dwc_waitq dwc_waitq_t;
6547 +/** The type of waitq condition callback function. This is called every time
6548 + * condition is evaluated. */
6549 +typedef int (*dwc_waitq_condition_t)(void *data);
6551 +/** Allocate a waitq */
6552 +extern dwc_waitq_t *DWC_WAITQ_ALLOC(void);
6553 +#define dwc_waitq_alloc DWC_WAITQ_ALLOC
6554 +/** Free a waitq */
6555 +extern void DWC_WAITQ_FREE(dwc_waitq_t *wq);
6556 +#define dwc_waitq_free DWC_WAITQ_FREE
6558 +/** Check the condition and if it is false, block on the waitq. When unblocked, check the
6559 + * condition again. The function returns when the condition becomes true. The return value
6560 + * is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. */
6561 +extern int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t condition, void *data);
6562 +#define dwc_waitq_wait DWC_WAITQ_WAIT;
6563 +/** Check the condition and if it is false, block on the waitq. When unblocked,
6564 + * check the condition again. The function returns when the condition become
6565 + * true or the timeout has passed. The return value is 0 on condition true or
6566 + * DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on
6568 +extern int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t condition, void *data, int32_t msecs);
6569 +#define dwc_waitq_wait_timeout DWC_WAITQ_WAIT_TIMEOUT
6570 +/** Trigger a waitq, unblocking all processes. This should be called whenever a condition
6571 + * has potentially changed. */
6572 +extern void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq);
6573 +#define dwc_waitq_trigger DWC_WAITQ_TRIGGER
6574 +/** Unblock all processes waiting on the waitq with an ABORTED result. */
6575 +extern void DWC_WAITQ_ABORT(dwc_waitq_t *wq);
6576 +#define dwc_waitq_abort DWC_WAITQ_ABORT
6580 + * A thread must be explicitly stopped. It must check DWC_THREAD_SHOULD_STOP
6581 + * whenever it is woken up, and then return. The DWC_THREAD_STOP function
6582 + * returns the value from the thread.
6586 +typedef struct dwc_thread dwc_thread_t;
6588 +/** The thread function */
6589 +typedef int (*dwc_thread_function_t)(void *data);
6591 +/** Create a thread and start it running the thread_function. Returns a handle
6592 + * to the thread */
6593 +extern dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t thread_function, char *name, void *data);
6594 +#define dwc_thread_run DWC_THREAD_RUN
6595 +/** Stops a thread. Return the value returned by the thread. Or will return
6596 + * DWC_ABORT if the thread never started. */
6597 +extern int DWC_THREAD_STOP(dwc_thread_t *thread);
6598 +#define dwc_thread_stop DWC_THREAD_STOP
6599 +/** Signifies to the thread that it must stop. */
6600 +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(void);
6601 +#define dwc_thread_should_stop DWC_THREAD_SHOULD_STOP
6603 +/** @name Work queues
6605 + * Workqs are used to queue a callback function to be called at some later time,
6606 + * in another thread. */
6608 +typedef struct dwc_workq dwc_workq_t;
6610 +/** The type of the callback function to be called. */
6611 +typedef void (*dwc_work_callback_t)(void *data);
6613 +/** Allocate a workq */
6614 +extern dwc_workq_t *DWC_WORKQ_ALLOC(char *name);
6615 +#define dwc_workq_alloc DWC_WORKQ_ALLOC
6616 +/** Free a workq. All work must be completed before being freed. */
6617 +extern void DWC_WORKQ_FREE(dwc_workq_t *workq);
6618 +#define dwc_workq_free DWC_WORKQ_FREE
6619 +/** Schedule a callback on the workq, passing in data. The function will be
6620 + * scheduled at some later time. */
6621 +extern void DWC_WORKQ_SCHEDULE(dwc_workq_t *workq, dwc_work_callback_t work_cb, void *data, char *format, ...)
6623 + __attribute__ ((format(printf, 4, 5)));
6627 +#define dwc_workq_schedule DWC_WORKQ_SCHEDULE
6629 +/** Schedule a callback on the workq, that will be called until at least
6630 + * given number miliseconds have passed. */
6631 +extern void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *workq, dwc_work_callback_t work_cb, void *data, uint32_t time, char *format, ...)
6633 + __attribute__ ((format(printf, 5, 6)));
6637 +#define dwc_workq_schedule_delayed DWC_WORKQ_SCHEDULE_DELAYED
6639 +/** The number of processes in the workq */
6640 +extern int DWC_WORKQ_PENDING(dwc_workq_t *workq);
6641 +#define dwc_workq_pending DWC_WORKQ_PENDING
6642 +/** Blocks until all the work in the workq is complete or timed out. Returns <
6643 + * 0 on timeout. */
6644 +extern int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout);
6645 +#define dwc_workq_wait_work_done DWC_WORKQ_WAIT_WORK_DONE
6651 +struct dwc_tasklet;
6652 +typedef struct dwc_tasklet dwc_tasklet_t;
6654 +typedef void (*dwc_tasklet_callback_t)(void *data);
6656 +extern dwc_tasklet_t *DWC_TASK_ALLOC(dwc_tasklet_callback_t cb, void *data);
6657 +#define dwc_task_alloc DWC_TASK_ALLOC
6658 +extern void DWC_TASK_FREE(dwc_tasklet_t *t);
6659 +#define dwc_task_free DWC_TASK_FREE
6660 +extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
6661 +#define dwc_task_schedule DWC_TASK_SCHEDULE
6666 + * Callbacks must be small and atomic.
6669 +typedef struct dwc_timer dwc_timer_t;
6671 +typedef void (*dwc_timer_callback_t)(void *data);
6673 +extern dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data);
6674 +#define dwc_timer_alloc DWC_TIMER_ALLOC
6675 +extern void DWC_TIMER_FREE(dwc_timer_t *timer);
6676 +#define dwc_timer_free DWC_TIMER_FREE
6678 +/** Schedules the timer to run at time ms from now. And will repeat at every
6679 + * repeat_interval msec therafter
6681 + * Modifies a timer that is still awaiting execution to a new expiration time.
6682 + * The mod_time is added to the old time. */
6683 +extern void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time);
6684 +#define dwc_timer_schedule DWC_TIMER_SCHEDULE
6686 +/** Disables the timer from execution. */
6687 +extern void DWC_TIMER_CANCEL(dwc_timer_t *timer);
6688 +#define dwc_timer_cancel DWC_TIMER_CANCEL
6692 +/** @name Spinlocks
6694 + * These locks are used when the work between the lock/unlock is atomic and
6695 + * short. Interrupts are also disabled during the lock/unlock and thus they are
6696 + * suitable to lock between interrupt/non-interrupt context. They also lock
6697 + * between processes if you have multiple CPUs or Preemption. If you don't have
6698 + * multiple CPUS or Preemption, then the you can simply implement the
6699 + * DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts. Because
6700 + * the work between the lock/unlock is atomic, the process context will never
6701 + * change, and so you never have to lock between processes. */
6703 +struct dwc_spinlock;
6704 +typedef struct dwc_spinlock dwc_spinlock_t;
6706 +/** Returns an initialized lock variable. This function should allocate and
6707 + * initialize the OS-specific data structure used for locking. This data
6708 + * structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should
6709 + * be freed by the DWC_FREE_LOCK when it is no longer used. */
6710 +extern dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void);
6711 +#define dwc_spinlock_alloc DWC_SPINLOCK_ALLOC
6713 +/** Frees an initialized lock variable. */
6714 +extern void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock);
6715 +#define dwc_spinlock_free DWC_SPINLOCK_FREE
6717 +/** Disables interrupts and blocks until it acquires the lock.
6719 + * @param lock Pointer to the spinlock.
6720 + * @param flags Unsigned long for irq flags storage.
6722 +extern void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, uint64_t *flags);
6723 +#define dwc_spinlock_irqsave DWC_SPINLOCK_IRQSAVE
6725 +/** Re-enables the interrupt and releases the lock.
6727 + * @param lock Pointer to the spinlock.
6728 + * @param flags Unsigned long for irq flags storage. Must be the same as was
6729 + * passed into DWC_LOCK.
6731 +extern void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, uint64_t flags);
6732 +#define dwc_spinunlock_irqrestore DWC_SPINUNLOCK_IRQRESTORE
6734 +/** Blocks until it acquires the lock.
6736 + * @param lock Pointer to the spinlock.
6738 +extern void DWC_SPINLOCK(dwc_spinlock_t *lock);
6739 +#define dwc_spinlock DWC_SPINLOCK
6741 +/** Releases the lock.
6743 + * @param lock Pointer to the spinlock.
6745 +extern void DWC_SPINUNLOCK(dwc_spinlock_t *lock);
6746 +#define dwc_spinunlock DWC_SPINUNLOCK
6750 + * Unlike spinlocks Mutexes lock only between processes and the work between the
6751 + * lock/unlock CAN block, therefore it CANNOT be called from interrupt context.
6755 +typedef struct dwc_mutex dwc_mutex_t;
6758 +/* For Linux Mutex Debugging make it inline because the debugging routines use
6759 + * the symbol to determine recursive locking. This makes it falsely think
6760 + * recursive locking occurs. */
6761 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
6762 +#define DWC_MUTEX_ALLOC_LINUX_DEBUG(__mutexp) ({ \
6763 + __mutexp = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); \
6764 + mutex_init((struct mutex *)__mutexp); \
6767 +extern dwc_mutex_t *DWC_MUTEX_ALLOC(void);
6768 +#define dwc_mutex_alloc DWC_MUTEX_ALLOC
6770 +/* For memory leak debugging when using Linux Mutex Debugging */
6771 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
6772 +#define DWC_MUTEX_FREE(__mutexp) do { \
6773 + mutex_destroy((struct mutex *)__mutexp); \
6774 + DWC_FREE(__mutexp); \
6777 +extern void DWC_MUTEX_FREE(dwc_mutex_t *mutex);
6778 +#define dwc_mutex_free DWC_MUTEX_FREE
6781 +extern void DWC_MUTEX_LOCK(dwc_mutex_t *mutex);
6782 +#define dwc_mutex_lock DWC_MUTEX_LOCK
6783 +/** Non-blocking lock returns 1 on successful lock. */
6784 +extern int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex);
6785 +#define dwc_mutex_trylock DWC_MUTEX_TRYLOCK
6786 +extern void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex);
6787 +#define dwc_mutex_unlock DWC_MUTEX_UNLOCK
6794 +/** Microsecond delay.
6796 + * @param usecs Microseconds to delay.
6798 +extern void DWC_UDELAY(uint32_t usecs);
6799 +#define dwc_udelay DWC_UDELAY
6801 +/** Millisecond delay.
6803 + * @param msecs Milliseconds to delay.
6805 +extern void DWC_MDELAY(uint32_t msecs);
6806 +#define dwc_mdelay DWC_MDELAY
6808 +/** Non-busy waiting.
6809 + * Sleeps for specified number of milliseconds.
6811 + * @param msecs Milliseconds to sleep.
6813 +extern void DWC_MSLEEP(uint32_t msecs);
6814 +#define dwc_msleep DWC_MSLEEP
6816 +extern uint32_t DWC_TIME(void);
6817 +#define dwc_time DWC_TIME
6819 +#endif // _DWC_OS_H_
6824 +/** @mainpage DWC Portability and Common Library
6826 + * This is the documentation for the DWC Portability and Common Library.
6828 + * @section intro Introduction
6830 + * The DWC Portability library consists of wrapper calls and data structures to
6831 + * all low-level functions which are typically provided by the OS. The WUDEV
6832 + * driver uses only these functions. In order to port the WUDEV driver, only
6833 + * the functions in this library need to be re-implemented, with the same
6834 + * behavior as documented here.
6836 + * The Common library consists of higher level functions, which rely only on
6837 + * calling the functions from the DWC Portability library. These common
6838 + * routines are shared across modules. Some of the common libraries need to be
6839 + * used directly by the driver programmer when porting WUDEV. Such as the
6840 + * parameter and notification libraries.
6842 + * @section low Portability Library OS Wrapper Functions
6844 + * Any function starting with DWC and in all CAPS is a low-level OS-wrapper that
6845 + * needs to be implemented when porting, for example DWC_MUTEX_ALLOC(). All of
6846 + * these functions are included in the dwc_os.h file.
6848 + * There are many functions here covering a wide array of OS services. Please
6849 + * see dwc_os.h for details, and implementation notes for each function.
6851 + * @section common Common Library Functions
6853 + * Any function starting with dwc and in all lowercase is a common library
6854 + * routine. These functions have a portable implementation and do not need to
6855 + * be reimplemented when porting. The common routines can be used by any
6856 + * driver, and some must be used by the end user to control the drivers. For
6857 + * example, you must use the Parameter common library in order to set the
6858 + * parameters in the WUDEV module.
6860 + * The common libraries consist of the following:
6862 + * - Connection Contexts - Used internally and can be used by end-user. See dwc_cc.h
6863 + * - Parameters - Used internally and can be used by end-user. See dwc_params.h
6864 + * - Notifications - Used internally and can be used by end-user. See dwc_notifier.h
6865 + * - Lists - Used internally and can be used by end-user. See dwc_list.h
6866 + * - Memory Debugging - Used internally and can be used by end-user. See dwc_os.h
6867 + * - Modpow - Used internally only. See dwc_modpow.h
6868 + * - DH - Used internally only. See dwc_dh.h
6869 + * - Crypto - Used internally only. See dwc_crypto.h
6872 + * @section prereq Prerequistes For dwc_os.h
6873 + * @subsection types Data Types
6875 + * The dwc_os.h file assumes that several low-level data types are pre defined for the
6876 + * compilation environment. These data types are:
6878 + * - uint8_t - unsigned 8-bit data type
6879 + * - int8_t - signed 8-bit data type
6880 + * - uint16_t - unsigned 16-bit data type
6881 + * - int16_t - signed 16-bit data type
6882 + * - uint32_t - unsigned 32-bit data type
6883 + * - int32_t - signed 32-bit data type
6884 + * - uint64_t - unsigned 64-bit data type
6885 + * - int64_t - signed 64-bit data type
6887 + * Ensure that these are defined before using dwc_os.h. The easiest way to do
6888 + * that is to modify the top of the file to include the appropriate header.
6889 + * This is already done for the Linux environment. If the DWC_LINUX macro is
6890 + * defined, the correct header will be added. A standard header <stdint.h> is
6891 + * also used for environments where standard C headers are available.
6893 + * @subsection stdarg Variable Arguments
6895 + * Variable arguments are provided by a standard C header <stdarg.h>. it is
6896 + * available in Both the Linux and ANSI C enviornment. An equivalent must be
6897 + * provided in your enviornment in order to use dwc_os.h with the debug and
6898 + * tracing message functionality.
6900 + * @subsection thread Threading
6902 + * WUDEV Core must be run on an operating system that provides for multiple
6903 + * threads/processes. Threading can be implemented in many ways, even in
6904 + * embedded systems without an operating system. At the bare minimum, the
6905 + * system should be able to start any number of processes at any time to handle
6906 + * special work. It need not be a pre-emptive system. Process context can
6907 + * change upon a call to a blocking function. The hardware interrupt context
6908 + * that calls the module's ISR() function must be differentiable from process
6909 + * context, even if your processes are impemented via a hardware interrupt.
6910 + * Further locking mechanism between process must exist (or be implemented), and
6911 + * process context must have a way to disable interrupts for a period of time to
6912 + * lock them out. If all of this exists, the functions in dwc_os.h related to
6913 + * threading should be able to be implemented with the defined behavior.
6917 +++ b/drivers/usb/host/dwc_common_port/usb.h
6920 + * Copyright (c) 1998 The NetBSD Foundation, Inc.
6921 + * All rights reserved.
6923 + * This code is derived from software contributed to The NetBSD Foundation
6924 + * by Lennart Augustsson (lennart@augustsson.net) at
6925 + * Carlstedt Research & Technology.
6927 + * Redistribution and use in source and binary forms, with or without
6928 + * modification, are permitted provided that the following conditions
6930 + * 1. Redistributions of source code must retain the above copyright
6931 + * notice, this list of conditions and the following disclaimer.
6932 + * 2. Redistributions in binary form must reproduce the above copyright
6933 + * notice, this list of conditions and the following disclaimer in the
6934 + * documentation and/or other materials provided with the distribution.
6935 + * 3. All advertising materials mentioning features or use of this software
6936 + * must display the following acknowledgement:
6937 + * This product includes software developed by the NetBSD
6938 + * Foundation, Inc. and its contributors.
6939 + * 4. Neither the name of The NetBSD Foundation nor the names of its
6940 + * contributors may be used to endorse or promote products derived
6941 + * from this software without specific prior written permission.
6943 + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
6944 + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
6945 + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
6946 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
6947 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
6948 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
6949 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
6950 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
6951 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
6952 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
6953 + * POSSIBILITY OF SUCH DAMAGE.
6956 +/* Modified by Synopsys, Inc, 12/12/2007 */
6962 +#include "dwc_os.h"
6965 + * The USB records contain some unaligned little-endian word
6966 + * components. The U[SG]ETW macros take care of both the alignment
6967 + * and endian problem and should always be used to access non-byte
6970 +typedef u_int8_t uByte;
6971 +typedef u_int8_t uWord[2];
6972 +typedef u_int8_t uDWord[4];
6974 +#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
6977 +#define UGETW(w) ((w)[0] | ((w)[1] << 8))
6978 +#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
6979 +#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
6980 +#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
6981 + (w)[1] = (u_int8_t)((v) >> 8), \
6982 + (w)[2] = (u_int8_t)((v) >> 16), \
6983 + (w)[3] = (u_int8_t)((v) >> 24))
6986 + * On little-endian machines that can handle unanliged accesses
6987 + * (e.g. i386) these macros can be replaced by the following.
6989 +#define UGETW(w) (*(u_int16_t *)(w))
6990 +#define USETW(w,v) (*(u_int16_t *)(w) = (v))
6991 +#define UGETDW(w) (*(u_int32_t *)(w))
6992 +#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
6995 +#define UPACKED __attribute__((__packed__))
6998 + uByte bmRequestType;
7003 +} UPACKED usb_device_request_t;
7005 +#define UT_GET_DIR(a) ((a) & 0x80)
7006 +#define UT_WRITE 0x00
7007 +#define UT_READ 0x80
7009 +#define UT_GET_TYPE(a) ((a) & 0x60)
7010 +#define UT_STANDARD 0x00
7011 +#define UT_CLASS 0x20
7012 +#define UT_VENDOR 0x40
7014 +#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
7015 +#define UT_DEVICE 0x00
7016 +#define UT_INTERFACE 0x01
7017 +#define UT_ENDPOINT 0x02
7018 +#define UT_OTHER 0x03
7020 +#define UT_READ_DEVICE (UT_READ | UT_STANDARD | UT_DEVICE)
7021 +#define UT_READ_INTERFACE (UT_READ | UT_STANDARD | UT_INTERFACE)
7022 +#define UT_READ_ENDPOINT (UT_READ | UT_STANDARD | UT_ENDPOINT)
7023 +#define UT_WRITE_DEVICE (UT_WRITE | UT_STANDARD | UT_DEVICE)
7024 +#define UT_WRITE_INTERFACE (UT_WRITE | UT_STANDARD | UT_INTERFACE)
7025 +#define UT_WRITE_ENDPOINT (UT_WRITE | UT_STANDARD | UT_ENDPOINT)
7026 +#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE)
7027 +#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE)
7028 +#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER)
7029 +#define UT_READ_CLASS_ENDPOINT (UT_READ | UT_CLASS | UT_ENDPOINT)
7030 +#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE)
7031 +#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
7032 +#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER)
7033 +#define UT_WRITE_CLASS_ENDPOINT (UT_WRITE | UT_CLASS | UT_ENDPOINT)
7034 +#define UT_READ_VENDOR_DEVICE (UT_READ | UT_VENDOR | UT_DEVICE)
7035 +#define UT_READ_VENDOR_INTERFACE (UT_READ | UT_VENDOR | UT_INTERFACE)
7036 +#define UT_READ_VENDOR_OTHER (UT_READ | UT_VENDOR | UT_OTHER)
7037 +#define UT_READ_VENDOR_ENDPOINT (UT_READ | UT_VENDOR | UT_ENDPOINT)
7038 +#define UT_WRITE_VENDOR_DEVICE (UT_WRITE | UT_VENDOR | UT_DEVICE)
7039 +#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
7040 +#define UT_WRITE_VENDOR_OTHER (UT_WRITE | UT_VENDOR | UT_OTHER)
7041 +#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
7044 +#define UR_GET_STATUS 0x00
7045 +#define USTAT_STANDARD_STATUS 0x00
7046 +#define WUSTAT_WUSB_FEATURE 0x01
7047 +#define WUSTAT_CHANNEL_INFO 0x02
7048 +#define WUSTAT_RECEIVED_DATA 0x03
7049 +#define WUSTAT_MAS_AVAILABILITY 0x04
7050 +#define WUSTAT_CURRENT_TRANSMIT_POWER 0x05
7051 +#define UR_CLEAR_FEATURE 0x01
7052 +#define UR_SET_FEATURE 0x03
7053 +#define UR_SET_AND_TEST_FEATURE 0x0c
7054 +#define UR_SET_ADDRESS 0x05
7055 +#define UR_GET_DESCRIPTOR 0x06
7056 +#define UDESC_DEVICE 0x01
7057 +#define UDESC_CONFIG 0x02
7058 +#define UDESC_STRING 0x03
7059 +#define UDESC_INTERFACE 0x04
7060 +#define UDESC_ENDPOINT 0x05
7061 +#define UDESC_DEVICE_QUALIFIER 0x06
7062 +#define UDESC_OTHER_SPEED_CONFIGURATION 0x07
7063 +#define UDESC_INTERFACE_POWER 0x08
7064 +#define UDESC_OTG 0x09
7065 +#define WUDESC_SECURITY 0x0c
7066 +#define WUDESC_KEY 0x0d
7067 +#define WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
7068 +#define WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
7069 +#define WUD_KEY_TYPE_ASSOC 0x01
7070 +#define WUD_KEY_TYPE_GTK 0x02
7071 +#define WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
7072 +#define WUD_KEY_ORIGIN_HOST 0x00
7073 +#define WUD_KEY_ORIGIN_DEVICE 0x01
7074 +#define WUDESC_ENCRYPTION_TYPE 0x0e
7075 +#define WUDESC_BOS 0x0f
7076 +#define WUDESC_DEVICE_CAPABILITY 0x10
7077 +#define WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
7078 +#define UDESC_CS_DEVICE 0x21 /* class specific */
7079 +#define UDESC_CS_CONFIG 0x22
7080 +#define UDESC_CS_STRING 0x23
7081 +#define UDESC_CS_INTERFACE 0x24
7082 +#define UDESC_CS_ENDPOINT 0x25
7083 +#define UDESC_HUB 0x29
7084 +#define UR_SET_DESCRIPTOR 0x07
7085 +#define UR_GET_CONFIG 0x08
7086 +#define UR_SET_CONFIG 0x09
7087 +#define UR_GET_INTERFACE 0x0a
7088 +#define UR_SET_INTERFACE 0x0b
7089 +#define UR_SYNCH_FRAME 0x0c
7090 +#define WUR_SET_ENCRYPTION 0x0d
7091 +#define WUR_GET_ENCRYPTION 0x0e
7092 +#define WUR_SET_HANDSHAKE 0x0f
7093 +#define WUR_GET_HANDSHAKE 0x10
7094 +#define WUR_SET_CONNECTION 0x11
7095 +#define WUR_SET_SECURITY_DATA 0x12
7096 +#define WUR_GET_SECURITY_DATA 0x13
7097 +#define WUR_SET_WUSB_DATA 0x14
7098 +#define WUDATA_DRPIE_INFO 0x01
7099 +#define WUDATA_TRANSMIT_DATA 0x02
7100 +#define WUDATA_TRANSMIT_PARAMS 0x03
7101 +#define WUDATA_RECEIVE_PARAMS 0x04
7102 +#define WUDATA_TRANSMIT_POWER 0x05
7103 +#define WUR_LOOPBACK_DATA_WRITE 0x15
7104 +#define WUR_LOOPBACK_DATA_READ 0x16
7105 +#define WUR_SET_INTERFACE_DS 0x17
7107 +/* Feature numbers */
7108 +#define UF_ENDPOINT_HALT 0
7109 +#define UF_DEVICE_REMOTE_WAKEUP 1
7110 +#define UF_TEST_MODE 2
7111 +#define UF_DEVICE_B_HNP_ENABLE 3
7112 +#define UF_DEVICE_A_HNP_SUPPORT 4
7113 +#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
7115 +#define WUF_TX_DRPIE 0x0
7116 +#define WUF_DEV_XMIT_PACKET 0x1
7117 +#define WUF_COUNT_PACKETS 0x2
7118 +#define WUF_CAPTURE_PACKETS 0x3
7120 +/* Class requests from the USB 2.0 hub spec, table 11-15 */
7121 +#define UCR_CLEAR_HUB_FEATURE (0x2000 | UR_CLEAR_FEATURE)
7122 +#define UCR_CLEAR_PORT_FEATURE (0x2300 | UR_CLEAR_FEATURE)
7123 +#define UCR_GET_HUB_DESCRIPTOR (0xa000 | UR_GET_DESCRIPTOR)
7124 +#define UCR_GET_HUB_STATUS (0xa000 | UR_GET_STATUS)
7125 +#define UCR_GET_PORT_STATUS (0xa300 | UR_GET_STATUS)
7126 +#define UCR_SET_HUB_FEATURE (0x2000 | UR_SET_FEATURE)
7127 +#define UCR_SET_PORT_FEATURE (0x2300 | UR_SET_FEATURE)
7128 +#define UCR_SET_AND_TEST_PORT_FEATURE (0xa300 | UR_SET_AND_TEST_FEATURE)
7132 + uByte bDescriptorType;
7133 + uByte bDescriptorSubtype;
7134 +} UPACKED usb_descriptor_t;
7138 + uByte bDescriptorType;
7140 +#define UD_USB_2_0 0x0200
7141 +#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
7142 + uByte bDeviceClass;
7143 + uByte bDeviceSubClass;
7144 + uByte bDeviceProtocol;
7145 + uByte bMaxPacketSize;
7146 + /* The fields below are not part of the initial descriptor. */
7150 + uByte iManufacturer;
7152 + uByte iSerialNumber;
7153 + uByte bNumConfigurations;
7154 +} UPACKED usb_device_descriptor_t;
7155 +#define USB_DEVICE_DESCRIPTOR_SIZE 18
7159 + uByte bDescriptorType;
7160 + uWord wTotalLength;
7161 + uByte bNumInterface;
7162 + uByte bConfigurationValue;
7163 + uByte iConfiguration;
7164 + uByte bmAttributes;
7165 +#define UC_BUS_POWERED 0x80
7166 +#define UC_SELF_POWERED 0x40
7167 +#define UC_REMOTE_WAKEUP 0x20
7168 + uByte bMaxPower; /* max current in 2 mA units */
7169 +#define UC_POWER_FACTOR 2
7170 +} UPACKED usb_config_descriptor_t;
7171 +#define USB_CONFIG_DESCRIPTOR_SIZE 9
7175 + uByte bDescriptorType;
7176 + uByte bInterfaceNumber;
7177 + uByte bAlternateSetting;
7178 + uByte bNumEndpoints;
7179 + uByte bInterfaceClass;
7180 + uByte bInterfaceSubClass;
7181 + uByte bInterfaceProtocol;
7183 +} UPACKED usb_interface_descriptor_t;
7184 +#define USB_INTERFACE_DESCRIPTOR_SIZE 9
7188 + uByte bDescriptorType;
7189 + uByte bEndpointAddress;
7190 +#define UE_GET_DIR(a) ((a) & 0x80)
7191 +#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7))
7192 +#define UE_DIR_IN 0x80
7193 +#define UE_DIR_OUT 0x00
7194 +#define UE_ADDR 0x0f
7195 +#define UE_GET_ADDR(a) ((a) & UE_ADDR)
7196 + uByte bmAttributes;
7197 +#define UE_XFERTYPE 0x03
7198 +#define UE_CONTROL 0x00
7199 +#define UE_ISOCHRONOUS 0x01
7200 +#define UE_BULK 0x02
7201 +#define UE_INTERRUPT 0x03
7202 +#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE)
7203 +#define UE_ISO_TYPE 0x0c
7204 +#define UE_ISO_ASYNC 0x04
7205 +#define UE_ISO_ADAPT 0x08
7206 +#define UE_ISO_SYNC 0x0c
7207 +#define UE_GET_ISO_TYPE(a) ((a) & UE_ISO_TYPE)
7208 + uWord wMaxPacketSize;
7210 +} UPACKED usb_endpoint_descriptor_t;
7211 +#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
7215 + uByte bDescriptorType;
7216 + uWord bString[127];
7217 +} UPACKED usb_string_descriptor_t;
7218 +#define USB_MAX_STRING_LEN 128
7219 +#define USB_LANGUAGE_TABLE 0 /* # of the string language id table */
7221 +/* Hub specific request */
7222 +#define UR_GET_BUS_STATE 0x02
7223 +#define UR_CLEAR_TT_BUFFER 0x08
7224 +#define UR_RESET_TT 0x09
7225 +#define UR_GET_TT_STATE 0x0a
7226 +#define UR_STOP_TT 0x0b
7229 +#define UHF_C_HUB_LOCAL_POWER 0
7230 +#define UHF_C_HUB_OVER_CURRENT 1
7231 +#define UHF_PORT_CONNECTION 0
7232 +#define UHF_PORT_ENABLE 1
7233 +#define UHF_PORT_SUSPEND 2
7234 +#define UHF_PORT_OVER_CURRENT 3
7235 +#define UHF_PORT_RESET 4
7236 +#define UHF_PORT_L1 5
7237 +#define UHF_PORT_POWER 8
7238 +#define UHF_PORT_LOW_SPEED 9
7239 +#define UHF_PORT_HIGH_SPEED 10
7240 +#define UHF_C_PORT_CONNECTION 16
7241 +#define UHF_C_PORT_ENABLE 17
7242 +#define UHF_C_PORT_SUSPEND 18
7243 +#define UHF_C_PORT_OVER_CURRENT 19
7244 +#define UHF_C_PORT_RESET 20
7245 +#define UHF_C_PORT_L1 23
7246 +#define UHF_PORT_TEST 21
7247 +#define UHF_PORT_INDICATOR 22
7250 + uByte bDescLength;
7251 + uByte bDescriptorType;
7253 + uWord wHubCharacteristics;
7254 +#define UHD_PWR 0x0003
7255 +#define UHD_PWR_GANGED 0x0000
7256 +#define UHD_PWR_INDIVIDUAL 0x0001
7257 +#define UHD_PWR_NO_SWITCH 0x0002
7258 +#define UHD_COMPOUND 0x0004
7259 +#define UHD_OC 0x0018
7260 +#define UHD_OC_GLOBAL 0x0000
7261 +#define UHD_OC_INDIVIDUAL 0x0008
7262 +#define UHD_OC_NONE 0x0010
7263 +#define UHD_TT_THINK 0x0060
7264 +#define UHD_TT_THINK_8 0x0000
7265 +#define UHD_TT_THINK_16 0x0020
7266 +#define UHD_TT_THINK_24 0x0040
7267 +#define UHD_TT_THINK_32 0x0060
7268 +#define UHD_PORT_IND 0x0080
7269 + uByte bPwrOn2PwrGood; /* delay in 2 ms units */
7270 +#define UHD_PWRON_FACTOR 2
7271 + uByte bHubContrCurrent;
7272 + uByte DeviceRemovable[32]; /* max 255 ports */
7273 +#define UHD_NOT_REMOV(desc, i) \
7274 + (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
7275 + /* deprecated */ uByte PortPowerCtrlMask[1];
7276 +} UPACKED usb_hub_descriptor_t;
7277 +#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
7281 + uByte bDescriptorType;
7283 + uByte bDeviceClass;
7284 + uByte bDeviceSubClass;
7285 + uByte bDeviceProtocol;
7286 + uByte bMaxPacketSize0;
7287 + uByte bNumConfigurations;
7289 +} UPACKED usb_device_qualifier_t;
7290 +#define USB_DEVICE_QUALIFIER_SIZE 10
7294 + uByte bDescriptorType;
7295 + uByte bmAttributes;
7296 +#define UOTG_SRP 0x01
7297 +#define UOTG_HNP 0x02
7298 +} UPACKED usb_otg_descriptor_t;
7300 +/* OTG feature selectors */
7301 +#define UOTG_B_HNP_ENABLE 3
7302 +#define UOTG_A_HNP_SUPPORT 4
7303 +#define UOTG_A_ALT_HNP_SUPPORT 5
7307 +/* Device status flags */
7308 +#define UDS_SELF_POWERED 0x0001
7309 +#define UDS_REMOTE_WAKEUP 0x0002
7310 +/* Endpoint status flags */
7311 +#define UES_HALT 0x0001
7312 +} UPACKED usb_status_t;
7316 +#define UHS_LOCAL_POWER 0x0001
7317 +#define UHS_OVER_CURRENT 0x0002
7319 +} UPACKED usb_hub_status_t;
7322 + uWord wPortStatus;
7323 +#define UPS_CURRENT_CONNECT_STATUS 0x0001
7324 +#define UPS_PORT_ENABLED 0x0002
7325 +#define UPS_SUSPEND 0x0004
7326 +#define UPS_OVERCURRENT_INDICATOR 0x0008
7327 +#define UPS_RESET 0x0010
7328 +#define UPS_PORT_POWER 0x0100
7329 +#define UPS_LOW_SPEED 0x0200
7330 +#define UPS_HIGH_SPEED 0x0400
7331 +#define UPS_PORT_TEST 0x0800
7332 +#define UPS_PORT_INDICATOR 0x1000
7333 + uWord wPortChange;
7334 +#define UPS_C_CONNECT_STATUS 0x0001
7335 +#define UPS_C_PORT_ENABLED 0x0002
7336 +#define UPS_C_SUSPEND 0x0004
7337 +#define UPS_C_OVERCURRENT_INDICATOR 0x0008
7338 +#define UPS_C_PORT_RESET 0x0010
7339 +} UPACKED usb_port_status_t;
7341 +/* Device class codes */
7342 +#define UDCLASS_IN_INTERFACE 0x00
7343 +#define UDCLASS_COMM 0x02
7344 +#define UDCLASS_HUB 0x09
7345 +#define UDSUBCLASS_HUB 0x00
7346 +#define UDPROTO_FSHUB 0x00
7347 +#define UDPROTO_HSHUBSTT 0x01
7348 +#define UDPROTO_HSHUBMTT 0x02
7349 +#define UDCLASS_DIAGNOSTIC 0xdc
7350 +#define UDCLASS_WIRELESS 0xe0
7351 +#define UDSUBCLASS_RF 0x01
7352 +#define UDPROTO_BLUETOOTH 0x01
7353 +#define UDCLASS_VENDOR 0xff
7355 +/* Interface class codes */
7356 +#define UICLASS_UNSPEC 0x00
7358 +#define UICLASS_AUDIO 0x01
7359 +#define UISUBCLASS_AUDIOCONTROL 1
7360 +#define UISUBCLASS_AUDIOSTREAM 2
7361 +#define UISUBCLASS_MIDISTREAM 3
7363 +#define UICLASS_CDC 0x02 /* communication */
7364 +#define UISUBCLASS_DIRECT_LINE_CONTROL_MODEL 1
7365 +#define UISUBCLASS_ABSTRACT_CONTROL_MODEL 2
7366 +#define UISUBCLASS_TELEPHONE_CONTROL_MODEL 3
7367 +#define UISUBCLASS_MULTICHANNEL_CONTROL_MODEL 4
7368 +#define UISUBCLASS_CAPI_CONTROLMODEL 5
7369 +#define UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
7370 +#define UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
7371 +#define UIPROTO_CDC_AT 1
7373 +#define UICLASS_HID 0x03
7374 +#define UISUBCLASS_BOOT 1
7375 +#define UIPROTO_BOOT_KEYBOARD 1
7377 +#define UICLASS_PHYSICAL 0x05
7379 +#define UICLASS_IMAGE 0x06
7381 +#define UICLASS_PRINTER 0x07
7382 +#define UISUBCLASS_PRINTER 1
7383 +#define UIPROTO_PRINTER_UNI 1
7384 +#define UIPROTO_PRINTER_BI 2
7385 +#define UIPROTO_PRINTER_1284 3
7387 +#define UICLASS_MASS 0x08
7388 +#define UISUBCLASS_RBC 1
7389 +#define UISUBCLASS_SFF8020I 2
7390 +#define UISUBCLASS_QIC157 3
7391 +#define UISUBCLASS_UFI 4
7392 +#define UISUBCLASS_SFF8070I 5
7393 +#define UISUBCLASS_SCSI 6
7394 +#define UIPROTO_MASS_CBI_I 0
7395 +#define UIPROTO_MASS_CBI 1
7396 +#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */
7397 +#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */
7399 +#define UICLASS_HUB 0x09
7400 +#define UISUBCLASS_HUB 0
7401 +#define UIPROTO_FSHUB 0
7402 +#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */
7403 +#define UIPROTO_HSHUBMTT 1
7405 +#define UICLASS_CDC_DATA 0x0a
7406 +#define UISUBCLASS_DATA 0
7407 +#define UIPROTO_DATA_ISDNBRI 0x30 /* Physical iface */
7408 +#define UIPROTO_DATA_HDLC 0x31 /* HDLC */
7409 +#define UIPROTO_DATA_TRANSPARENT 0x32 /* Transparent */
7410 +#define UIPROTO_DATA_Q921M 0x50 /* Management for Q921 */
7411 +#define UIPROTO_DATA_Q921 0x51 /* Data for Q921 */
7412 +#define UIPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */
7413 +#define UIPROTO_DATA_V42BIS 0x90 /* Data compression */
7414 +#define UIPROTO_DATA_Q931 0x91 /* Euro-ISDN */
7415 +#define UIPROTO_DATA_V120 0x92 /* V.24 rate adaption */
7416 +#define UIPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */
7417 +#define UIPROTO_DATA_HOST_BASED 0xfd /* Host based driver */
7418 +#define UIPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc.*/
7419 +#define UIPROTO_DATA_VENDOR 0xff /* Vendor specific */
7421 +#define UICLASS_SMARTCARD 0x0b
7423 +/*#define UICLASS_FIRM_UPD 0x0c*/
7425 +#define UICLASS_SECURITY 0x0d
7427 +#define UICLASS_DIAGNOSTIC 0xdc
7429 +#define UICLASS_WIRELESS 0xe0
7430 +#define UISUBCLASS_RF 0x01
7431 +#define UIPROTO_BLUETOOTH 0x01
7433 +#define UICLASS_APPL_SPEC 0xfe
7434 +#define UISUBCLASS_FIRMWARE_DOWNLOAD 1
7435 +#define UISUBCLASS_IRDA 2
7436 +#define UIPROTO_IRDA 0
7438 +#define UICLASS_VENDOR 0xff
7441 +#define USB_HUB_MAX_DEPTH 5
7444 + * Minimum time a device needs to be powered down to go through
7445 + * a power cycle. XXX Are these time in the spec?
7447 +#define USB_POWER_DOWN_TIME 200 /* ms */
7448 +#define USB_PORT_POWER_DOWN_TIME 100 /* ms */
7451 +/* These are the values from the spec. */
7452 +#define USB_PORT_RESET_DELAY 10 /* ms */
7453 +#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
7454 +#define USB_PORT_RESET_RECOVERY 10 /* ms */
7455 +#define USB_PORT_POWERUP_DELAY 100 /* ms */
7456 +#define USB_SET_ADDRESS_SETTLE 2 /* ms */
7457 +#define USB_RESUME_DELAY (20*5) /* ms */
7458 +#define USB_RESUME_WAIT 10 /* ms */
7459 +#define USB_RESUME_RECOVERY 10 /* ms */
7460 +#define USB_EXTRA_POWER_UP_TIME 0 /* ms */
7462 +/* Allow for marginal (i.e. non-conforming) devices. */
7463 +#define USB_PORT_RESET_DELAY 50 /* ms */
7464 +#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
7465 +#define USB_PORT_RESET_RECOVERY 250 /* ms */
7466 +#define USB_PORT_POWERUP_DELAY 300 /* ms */
7467 +#define USB_SET_ADDRESS_SETTLE 10 /* ms */
7468 +#define USB_RESUME_DELAY (50*5) /* ms */
7469 +#define USB_RESUME_WAIT 50 /* ms */
7470 +#define USB_RESUME_RECOVERY 50 /* ms */
7471 +#define USB_EXTRA_POWER_UP_TIME 20 /* ms */
7474 +#define USB_MIN_POWER 100 /* mA */
7475 +#define USB_MAX_POWER 500 /* mA */
7477 +#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/
7480 +#define USB_UNCONFIG_NO 0
7481 +#define USB_UNCONFIG_INDEX (-1)
7483 +/*** ioctl() related stuff ***/
7485 +struct usb_ctl_request {
7487 + usb_device_request_t ucr_request;
7490 +#define USBD_SHORT_XFER_OK 0x04 /* allow short reads */
7491 + int ucr_actlen; /* actual length transferred */
7494 +struct usb_alt_interface {
7495 + int uai_config_index;
7496 + int uai_interface_index;
7500 +#define USB_CURRENT_CONFIG_INDEX (-1)
7501 +#define USB_CURRENT_ALT_INDEX (-1)
7503 +struct usb_config_desc {
7504 + int ucd_config_index;
7505 + usb_config_descriptor_t ucd_desc;
7508 +struct usb_interface_desc {
7509 + int uid_config_index;
7510 + int uid_interface_index;
7511 + int uid_alt_index;
7512 + usb_interface_descriptor_t uid_desc;
7515 +struct usb_endpoint_desc {
7516 + int ued_config_index;
7517 + int ued_interface_index;
7518 + int ued_alt_index;
7519 + int ued_endpoint_index;
7520 + usb_endpoint_descriptor_t ued_desc;
7523 +struct usb_full_desc {
7524 + int ufd_config_index;
7529 +struct usb_string_desc {
7530 + int usd_string_index;
7531 + int usd_language_id;
7532 + usb_string_descriptor_t usd_desc;
7535 +struct usb_ctl_report_desc {
7537 + u_char ucrd_data[1024]; /* filled data size will vary */
7540 +typedef struct { u_int32_t cookie; } usb_event_cookie_t;
7542 +#define USB_MAX_DEVNAMES 4
7543 +#define USB_MAX_DEVNAMELEN 16
7544 +struct usb_device_info {
7546 + u_int8_t udi_addr; /* device address */
7547 + usb_event_cookie_t udi_cookie;
7548 + char udi_product[USB_MAX_STRING_LEN];
7549 + char udi_vendor[USB_MAX_STRING_LEN];
7550 + char udi_release[8];
7551 + u_int16_t udi_productNo;
7552 + u_int16_t udi_vendorNo;
7553 + u_int16_t udi_releaseNo;
7554 + u_int8_t udi_class;
7555 + u_int8_t udi_subclass;
7556 + u_int8_t udi_protocol;
7557 + u_int8_t udi_config;
7558 + u_int8_t udi_speed;
7559 +#define USB_SPEED_LOW 1
7560 +#define USB_SPEED_FULL 2
7561 +#define USB_SPEED_HIGH 3
7562 + int udi_power; /* power consumption in mA, 0 if selfpowered */
7564 + char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
7565 + u_int8_t udi_ports[16];/* hub only: addresses of devices on ports */
7566 +#define USB_PORT_ENABLED 0xff
7567 +#define USB_PORT_SUSPENDED 0xfe
7568 +#define USB_PORT_POWERED 0xfd
7569 +#define USB_PORT_DISABLED 0xfc
7572 +struct usb_ctl_report {
7574 + u_char ucr_data[1024]; /* filled data size will vary */
7577 +struct usb_device_stats {
7578 + u_long uds_requests[4]; /* indexed by transfer type UE_* */
7584 +#define WUSB_MIN_IE 0x80
7585 +#define WUSB_WCTA_IE 0x80
7586 +#define WUSB_WCONNECTACK_IE 0x81
7587 +#define WUSB_WHOSTINFO_IE 0x82
7588 +#define WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
7589 +#define WUHI_CA_RECONN 0x00
7590 +#define WUHI_CA_LIMITED 0x01
7591 +#define WUHI_CA_ALL 0x03
7592 +#define WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
7593 +#define WUSB_WCHCHANGEANNOUNCE_IE 0x83
7594 +#define WUSB_WDEV_DISCONNECT_IE 0x84
7595 +#define WUSB_WHOST_DISCONNECT_IE 0x85
7596 +#define WUSB_WRELEASE_CHANNEL_IE 0x86
7597 +#define WUSB_WWORK_IE 0x87
7598 +#define WUSB_WCHANNEL_STOP_IE 0x88
7599 +#define WUSB_WDEV_KEEPALIVE_IE 0x89
7600 +#define WUSB_WISOCH_DISCARD_IE 0x8A
7601 +#define WUSB_WRESETDEVICE_IE 0x8B
7602 +#define WUSB_WXMIT_PACKET_ADJUST_IE 0x8C
7603 +#define WUSB_MAX_IE 0x8C
7605 +/* Device Notification Types */
7607 +#define WUSB_DN_MIN 0x01
7608 +#define WUSB_DN_CONNECT 0x01
7609 +# define WUSB_DA_OLDCONN 0x00
7610 +# define WUSB_DA_NEWCONN 0x01
7611 +# define WUSB_DA_SELF_BEACON 0x02
7612 +# define WUSB_DA_DIR_BEACON 0x04
7613 +# define WUSB_DA_NO_BEACON 0x06
7614 +#define WUSB_DN_DISCONNECT 0x02
7615 +#define WUSB_DN_EPRDY 0x03
7616 +#define WUSB_DN_MASAVAILCHANGED 0x04
7617 +#define WUSB_DN_REMOTEWAKEUP 0x05
7618 +#define WUSB_DN_SLEEP 0x06
7619 +#define WUSB_DN_ALIVE 0x07
7620 +#define WUSB_DN_MAX 0x07
7623 +/* WUSB Handshake Data. Used during the SET/GET HANDSHAKE requests */
7624 +typedef struct wusb_hndshk_data {
7625 + uint8_t bMessageNumber;
7628 + uint8_t bReserved;
7630 + uint8_t Nonce[16];
7632 +} UPACKED wusb_hndshk_data_t;
7633 +#define WUSB_HANDSHAKE_LEN_FOR_MIC 38
7635 +/* WUSB Connection Context */
7636 +typedef struct wusb_conn_context {
7637 + uint8_t CHID [16];
7638 + uint8_t CDID [16];
7640 +} UPACKED wusb_conn_context_t;
7642 +/* WUSB Security Descriptor */
7643 +typedef struct wusb_security_desc {
7645 + uint8_t bDescriptorType;
7646 + uint16_t wTotalLength;
7647 + uint8_t bNumEncryptionTypes;
7648 +} UPACKED wusb_security_desc_t;
7650 +/* WUSB Encryption Type Descriptor */
7651 +typedef struct wusb_encrypt_type_desc {
7653 + uint8_t bDescriptorType;
7655 + uint8_t bEncryptionType;
7656 +#define WUETD_UNSECURE 0
7657 +#define WUETD_WIRED 1
7658 +#define WUETD_CCM_1 2
7659 +#define WUETD_RSA_1 3
7661 + uint8_t bEncryptionValue;
7662 + uint8_t bAuthKeyIndex;
7663 +} UPACKED wusb_encrypt_type_desc_t;
7665 +/* WUSB Key Descriptor */
7666 +typedef struct wusb_key_desc {
7668 + uint8_t bDescriptorType;
7670 + uint8_t bReserved;
7671 + uint8_t KeyData[1]; /* variable length */
7672 +} UPACKED wusb_key_desc_t;
7674 +/* WUSB BOS Descriptor (Binary device Object Store) */
7675 +typedef struct wusb_bos_desc {
7677 + uint8_t bDescriptorType;
7678 + uint16_t wTotalLength;
7679 + uint8_t bNumDeviceCaps;
7680 +} UPACKED wusb_bos_desc_t;
7683 +/* Device Capability Type Codes */
7684 +#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
7686 +/* Device Capability Descriptor */
7687 +typedef struct wusb_dev_cap_desc {
7689 + uint8_t bDescriptorType;
7690 + uint8_t bDevCapabilityType;
7691 + uint8_t caps[1]; /* Variable length */
7692 +} UPACKED wusb_dev_cap_desc_t;
7694 +/* Device Capability Descriptor */
7695 +typedef struct wusb_dev_cap_uwb_desc {
7697 + uint8_t bDescriptorType;
7698 + uint8_t bDevCapabilityType;
7699 + uint8_t bmAttributes;
7700 + uint16_t wPHYRates; /* Bitmap */
7701 + uint8_t bmTFITXPowerInfo;
7702 + uint8_t bmFFITXPowerInfo;
7703 + uint16_t bmBandGroup;
7704 + uint8_t bReserved;
7705 +} UPACKED wusb_dev_cap_uwb_desc_t;
7707 +/* Wireless USB Endpoint Companion Descriptor */
7708 +typedef struct wusb_endpoint_companion_desc {
7710 + uint8_t bDescriptorType;
7711 + uint8_t bMaxBurst;
7712 + uint8_t bMaxSequence;
7713 + uint16_t wMaxStreamDelay;
7714 + uint16_t wOverTheAirPacketSize;
7715 + uint8_t bOverTheAirInterval;
7716 + uint8_t bmCompAttributes;
7717 +} UPACKED wusb_endpoint_companion_desc_t;
7720 +/* Wireless USB Numeric Association M1 Data Structure */
7721 +typedef struct wusb_m1_data {
7724 + uint8_t deviceFriendlyNameLength;
7725 + uint8_t sha_256_m3[32];
7726 + uint8_t deviceFriendlyName[256];
7727 +} UPACKED wusb_m1_data_t;
7729 +typedef struct wusb_m2_data {
7732 + uint8_t hostFriendlyNameLength;
7734 + uint8_t hostFriendlyName[256];
7735 +} UPACKED wusb_m2_data_t;
7737 +typedef struct wusb_m3_data {
7740 +} UPACKED wusb_m3_data_t;
7742 +typedef struct wusb_m4_data {
7743 + uint32_t _attributeTypeIdAndLength_1;
7744 + uint16_t associationTypeId;
7746 + uint32_t _attributeTypeIdAndLength_2;
7747 + uint16_t associationSubTypeId;
7749 + uint32_t _attributeTypeIdAndLength_3;
7752 + uint32_t _attributeTypeIdAndLength_4;
7753 + uint32_t associationStatus;
7755 + uint32_t _attributeTypeIdAndLength_5;
7758 + uint32_t _attributeTypeIdAndLength_6;
7761 + uint32_t _attributeTypeIdAndLength_7;
7762 + uint8_t bandGroups[2];
7763 +} UPACKED wusb_m4_data_t;
7768 +#endif /* _USB_H_ */
7770 +++ b/drivers/usb/host/dwc_otg/Makefile
7773 +# Makefile for DWC_otg Highspeed USB controller driver
7776 +ifneq ($(KERNELRELEASE),)
7778 +ifeq ($(BUS_INTERFACE),)
7779 + # BUS_INTERFACE = -DLM_INTERFACE
7780 + BUS_INTERFACE = -DPLATFORM_INTERFACE=1
7783 +CPPFLAGS += -DDEBUG
7785 +# Use one of the following flags to compile the software in host-only or
7786 +# device-only mode.
7787 +#CPPFLAGS += -DDWC_HOST_ONLY
7788 +#CPPFLAGS += -DDWC_DEVICE_ONLY
7790 +CPPFLAGS += -Dlinux -DDWC_HS_ELECT_TST
7791 +#CGG: CPPFLAGS += -DDWC_EN_ISOC
7792 +CPPFLAGS += -I$(obj)/../dwc_common_port
7793 +#CPPFLAGS += -I$(PORTLIB)
7794 +CPPFLAGS += -DDWC_LINUX
7796 +CPPFLAGS += $(BUS_INTERFACE)
7798 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o
7800 +dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o
7801 +dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
7802 +dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o
7803 +dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o
7805 +dwc_otg-objs += dwc_otg_cfi.o
7808 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
7809 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
7811 +ifneq ($(kernrel3),2.6.20)
7812 +EXTRA_CFLAGS += $(CPPFLAGS)
7817 +PWD := $(shell pwd)
7818 +PORTLIB := $(PWD)/../dwc_common_port
7822 +DOXYGEN := $(DOXYGEN)
7825 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
7828 +ifneq ($(INSTALL_MOD_PATH),)
7829 + $(MAKE) -C$(KDIR) M=$(PORTLIB) modules_install
7830 + $(MAKE) -C$(KDIR) M=$(PWD) modules_install
7832 + @echo "No install path defined"
7836 + $(MAKE) -C$(KDIR) M=$(PORTLIB) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
7837 + cp $(PORTLIB)/Module.symvers $(PWD)/
7839 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
7840 + $(DOXYGEN) doc/doxygen.cfg
7842 +tags: $(wildcard *.[hc])
7843 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
7847 + rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions
7851 +++ b/drivers/usb/host/dwc_otg/dummy_audio.c
7854 + * zero.c -- Gadget Zero, for USB development
7856 + * Copyright (C) 2003-2004 David Brownell
7857 + * All rights reserved.
7859 + * Redistribution and use in source and binary forms, with or without
7860 + * modification, are permitted provided that the following conditions
7862 + * 1. Redistributions of source code must retain the above copyright
7863 + * notice, this list of conditions, and the following disclaimer,
7864 + * without modification.
7865 + * 2. Redistributions in binary form must reproduce the above copyright
7866 + * notice, this list of conditions and the following disclaimer in the
7867 + * documentation and/or other materials provided with the distribution.
7868 + * 3. The names of the above-listed copyright holders may not be used
7869 + * to endorse or promote products derived from this software without
7870 + * specific prior written permission.
7872 + * ALTERNATIVELY, this software may be distributed under the terms of the
7873 + * GNU General Public License ("GPL") as published by the Free Software
7874 + * Foundation, either version 2 of that License or (at your option) any
7877 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
7878 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
7879 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
7880 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
7881 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
7882 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
7883 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
7884 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
7885 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
7886 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
7887 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7892 + * Gadget Zero only needs two bulk endpoints, and is an example of how you
7893 + * can write a hardware-agnostic gadget driver running inside a USB device.
7895 + * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
7896 + * affect most of the driver.
7898 + * Use it with the Linux host/master side "usbtest" driver to get a basic
7899 + * functional test of your device-side usb stack, or with "usb-skeleton".
7901 + * It supports two similar configurations. One sinks whatever the usb host
7902 + * writes, and in return sources zeroes. The other loops whatever the host
7903 + * writes back, so the host can read it. Module options include:
7905 + * buflen=N default N=4096, buffer size used
7906 + * qlen=N default N=32, how many buffers in the loopback queue
7907 + * loopdefault default false, list loopback config first
7909 + * Many drivers will only have one configuration, letting them be much
7910 + * simpler if they also don't support high speed operation (like this
7914 +#include <linux/config.h>
7915 +#include <linux/module.h>
7916 +#include <linux/kernel.h>
7917 +#include <linux/delay.h>
7918 +#include <linux/ioport.h>
7919 +#include <linux/sched.h>
7920 +#include <linux/slab.h>
7921 +#include <linux/smp_lock.h>
7922 +#include <linux/errno.h>
7923 +#include <linux/init.h>
7924 +#include <linux/timer.h>
7925 +#include <linux/list.h>
7926 +#include <linux/interrupt.h>
7927 +#include <linux/uts.h>
7928 +#include <linux/version.h>
7929 +#include <linux/device.h>
7930 +#include <linux/moduleparam.h>
7931 +#include <linux/proc_fs.h>
7933 +#include <asm/byteorder.h>
7934 +#include <asm/io.h>
7935 +#include <asm/irq.h>
7936 +#include <asm/system.h>
7937 +#include <asm/unaligned.h>
7939 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
7940 +# include <linux/usb/ch9.h>
7942 +# include <linux/usb_ch9.h>
7945 +#include <linux/usb_gadget.h>
7948 +/*-------------------------------------------------------------------------*/
7949 +/*-------------------------------------------------------------------------*/
7952 +static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
7958 + /* this insists on correct encodings, though not minimal ones.
7959 + * BUT it currently rejects legit 4-byte UTF-8 code points,
7960 + * which need surrogate pairs. (Unicode 3.1 can use them.)
7962 + while (len != 0 && (c = (u8) *s++) != 0) {
7963 + if (unlikely(c & 0x80)) {
7964 + // 2-byte sequence:
7965 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
7966 + if ((c & 0xe0) == 0xc0) {
7967 + uchar = (c & 0x1f) << 6;
7970 + if ((c & 0xc0) != 0xc0)
7975 + // 3-byte sequence (most CJKV characters):
7976 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
7977 + } else if ((c & 0xf0) == 0xe0) {
7978 + uchar = (c & 0x0f) << 12;
7981 + if ((c & 0xc0) != 0xc0)
7987 + if ((c & 0xc0) != 0xc0)
7992 + /* no bogus surrogates */
7993 + if (0xd800 <= uchar && uchar <= 0xdfff)
7996 + // 4-byte sequence (surrogate pairs, currently rare):
7997 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
7998 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
7999 + // (uuuuu = wwww + 1)
8000 + // FIXME accept the surrogate code points (only)
8006 + put_unaligned (cpu_to_le16 (uchar), cp++);
8017 + * usb_gadget_get_string - fill out a string descriptor
8018 + * @table: of c strings encoded using UTF-8
8019 + * @id: string id, from low byte of wValue in get string descriptor
8020 + * @buf: at least 256 bytes
8022 + * Finds the UTF-8 string matching the ID, and converts it into a
8023 + * string descriptor in utf16-le.
8024 + * Returns length of descriptor (always even) or negative errno
8026 + * If your driver needs stings in multiple languages, you'll probably
8027 + * "switch (wIndex) { ... }" in your ep0 string descriptor logic,
8028 + * using this routine after choosing which set of UTF-8 strings to use.
8029 + * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
8030 + * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
8031 + * characters (which are also widely used in C strings).
8034 +usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
8036 + struct usb_string *s;
8039 + /* descriptor 0 has the language id */
8042 + buf [1] = USB_DT_STRING;
8043 + buf [2] = (u8) table->language;
8044 + buf [3] = (u8) (table->language >> 8);
8047 + for (s = table->strings; s && s->s; s++)
8051 + /* unrecognized: stall. */
8055 + /* string descriptors have length, tag, then UTF16-LE text */
8056 + len = min ((size_t) 126, strlen (s->s));
8057 + memset (buf + 2, 0, 2 * len); /* zero all the bytes */
8058 + len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
8061 + buf [0] = (len + 1) * 2;
8062 + buf [1] = USB_DT_STRING;
8067 +/*-------------------------------------------------------------------------*/
8068 +/*-------------------------------------------------------------------------*/
8072 + * usb_descriptor_fillbuf - fill buffer with descriptors
8073 + * @buf: Buffer to be filled
8074 + * @buflen: Size of buf
8075 + * @src: Array of descriptor pointers, terminated by null pointer.
8077 + * Copies descriptors into the buffer, returning the length or a
8078 + * negative error code if they can't all be copied. Useful when
8079 + * assembling descriptors for an associated set of interfaces used
8080 + * as part of configuring a composite device; or in other cases where
8081 + * sets of descriptors need to be marshaled.
8084 +usb_descriptor_fillbuf(void *buf, unsigned buflen,
8085 + const struct usb_descriptor_header **src)
8092 + /* fill buffer from src[] until null descriptor ptr */
8093 + for (; 0 != *src; src++) {
8094 + unsigned len = (*src)->bLength;
8098 + memcpy(dest, *src, len);
8102 + return dest - (u8 *)buf;
8107 + * usb_gadget_config_buf - builts a complete configuration descriptor
8108 + * @config: Header for the descriptor, including characteristics such
8109 + * as power requirements and number of interfaces.
8110 + * @desc: Null-terminated vector of pointers to the descriptors (interface,
8111 + * endpoint, etc) defining all functions in this device configuration.
8112 + * @buf: Buffer for the resulting configuration descriptor.
8113 + * @length: Length of buffer. If this is not big enough to hold the
8114 + * entire configuration descriptor, an error code will be returned.
8116 + * This copies descriptors into the response buffer, building a descriptor
8117 + * for that configuration. It returns the buffer length or a negative
8118 + * status code. The config.wTotalLength field is set to match the length
8119 + * of the result, but other descriptor fields (including power usage and
8120 + * interface count) must be set by the caller.
8122 + * Gadget drivers could use this when constructing a config descriptor
8123 + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
8124 + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
8126 +int usb_gadget_config_buf(
8127 + const struct usb_config_descriptor *config,
8130 + const struct usb_descriptor_header **desc
8133 + struct usb_config_descriptor *cp = buf;
8136 + /* config descriptor first */
8137 + if (length < USB_DT_CONFIG_SIZE || !desc)
8141 + /* then interface/endpoint/class/vendor/... */
8142 + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
8143 + length - USB_DT_CONFIG_SIZE, desc);
8146 + len += USB_DT_CONFIG_SIZE;
8150 + /* patch up the config descriptor */
8151 + cp->bLength = USB_DT_CONFIG_SIZE;
8152 + cp->bDescriptorType = USB_DT_CONFIG;
8153 + cp->wTotalLength = cpu_to_le16(len);
8154 + cp->bmAttributes |= USB_CONFIG_ATT_ONE;
8158 +/*-------------------------------------------------------------------------*/
8159 +/*-------------------------------------------------------------------------*/
8162 +#define RBUF_LEN (1024*1024)
8163 +static int rbuf_start;
8164 +static int rbuf_len;
8165 +static __u8 rbuf[RBUF_LEN];
8167 +/*-------------------------------------------------------------------------*/
8169 +#define DRIVER_VERSION "St Patrick's Day 2004"
8171 +static const char shortname [] = "zero";
8172 +static const char longname [] = "YAMAHA YST-MS35D USB Speaker ";
8174 +static const char source_sink [] = "source and sink data";
8175 +static const char loopback [] = "loop input to output";
8177 +/*-------------------------------------------------------------------------*/
8180 + * driver assumes self-powered hardware, and
8181 + * has no way for users to trigger remote wakeup.
8183 + * this version autoconfigures as much as possible,
8184 + * which is reasonable for most "bulk-only" drivers.
8186 +static const char *EP_IN_NAME; /* source */
8187 +static const char *EP_OUT_NAME; /* sink */
8189 +/*-------------------------------------------------------------------------*/
8191 +/* big enough to hold our biggest descriptor */
8192 +#define USB_BUFSIZ 512
8196 + struct usb_gadget *gadget;
8197 + struct usb_request *req; /* for control responses */
8199 + /* when configured, we have one of two configs:
8200 + * - source data (in to host) and sink it (out from host)
8201 + * - or loop it back (out from host back in to host)
8204 + struct usb_ep *in_ep, *out_ep;
8206 + /* autoresume timer */
8207 + struct timer_list resume;
8210 +#define xprintk(d,level,fmt,args...) \
8211 + dev_printk(level , &(d)->gadget->dev , fmt , ## args)
8214 +#define DBG(dev,fmt,args...) \
8215 + xprintk(dev , KERN_DEBUG , fmt , ## args)
8217 +#define DBG(dev,fmt,args...) \
8224 +#define VDBG(dev,fmt,args...) \
8226 +#endif /* VERBOSE */
8228 +#define ERROR(dev,fmt,args...) \
8229 + xprintk(dev , KERN_ERR , fmt , ## args)
8230 +#define WARN(dev,fmt,args...) \
8231 + xprintk(dev , KERN_WARNING , fmt , ## args)
8232 +#define INFO(dev,fmt,args...) \
8233 + xprintk(dev , KERN_INFO , fmt , ## args)
8235 +/*-------------------------------------------------------------------------*/
8237 +static unsigned buflen = 4096;
8238 +static unsigned qlen = 32;
8239 +static unsigned pattern = 0;
8241 +module_param (buflen, uint, S_IRUGO|S_IWUSR);
8242 +module_param (qlen, uint, S_IRUGO|S_IWUSR);
8243 +module_param (pattern, uint, S_IRUGO|S_IWUSR);
8246 + * if it's nonzero, autoresume says how many seconds to wait
8247 + * before trying to wake up the host after suspend.
8249 +static unsigned autoresume = 0;
8250 +module_param (autoresume, uint, 0);
8253 + * Normally the "loopback" configuration is second (index 1) so
8254 + * it's not the default. Here's where to change that order, to
8255 + * work better with hosts where config changes are problematic.
8256 + * Or controllers (like superh) that only support one config.
8258 +static int loopdefault = 0;
8260 +module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
8262 +/*-------------------------------------------------------------------------*/
8264 +/* Thanks to NetChip Technologies for donating this product ID.
8266 + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
8267 + * Instead: allocate your own, using normal USB-IF procedures.
8269 +#ifndef CONFIG_USB_ZERO_HNPTEST
8270 +#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
8271 +#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
8273 +#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
8274 +#define DRIVER_PRODUCT_NUM 0xbadd
8277 +/*-------------------------------------------------------------------------*/
8280 + * DESCRIPTORS ... most are static, but strings and (full)
8281 + * configuration descriptors are built on demand.
8285 +#define STRING_MANUFACTURER 25
8286 +#define STRING_PRODUCT 42
8287 +#define STRING_SERIAL 101
8289 +#define STRING_MANUFACTURER 1
8290 +#define STRING_PRODUCT 2
8291 +#define STRING_SERIAL 3
8293 +#define STRING_SOURCE_SINK 250
8294 +#define STRING_LOOPBACK 251
8297 + * This device advertises two configurations; these numbers work
8298 + * on a pxa250 as well as more flexible hardware.
8300 +#define CONFIG_SOURCE_SINK 3
8301 +#define CONFIG_LOOPBACK 2
8304 +static struct usb_device_descriptor
8306 + .bLength = sizeof device_desc,
8307 + .bDescriptorType = USB_DT_DEVICE,
8309 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
8310 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
8312 + .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
8313 + .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
8314 + .iManufacturer = STRING_MANUFACTURER,
8315 + .iProduct = STRING_PRODUCT,
8316 + .iSerialNumber = STRING_SERIAL,
8317 + .bNumConfigurations = 2,
8320 +static struct usb_device_descriptor
8322 + .bLength = sizeof device_desc,
8323 + .bDescriptorType = USB_DT_DEVICE,
8324 + .bcdUSB = __constant_cpu_to_le16 (0x0100),
8325 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
8326 + .bDeviceSubClass = 0,
8327 + .bDeviceProtocol = 0,
8328 + .bMaxPacketSize0 = 64,
8329 + .bcdDevice = __constant_cpu_to_le16 (0x0100),
8330 + .idVendor = __constant_cpu_to_le16 (0x0499),
8331 + .idProduct = __constant_cpu_to_le16 (0x3002),
8332 + .iManufacturer = STRING_MANUFACTURER,
8333 + .iProduct = STRING_PRODUCT,
8334 + .iSerialNumber = STRING_SERIAL,
8335 + .bNumConfigurations = 1,
8338 +static struct usb_config_descriptor
8340 + .bLength = sizeof z_config,
8341 + .bDescriptorType = USB_DT_CONFIG,
8343 + /* compute wTotalLength on the fly */
8344 + .bNumInterfaces = 2,
8345 + .bConfigurationValue = 1,
8346 + .iConfiguration = 0,
8347 + .bmAttributes = 0x40,
8348 + .bMaxPower = 0, /* self-powered */
8352 +static struct usb_otg_descriptor
8354 + .bLength = sizeof otg_descriptor,
8355 + .bDescriptorType = USB_DT_OTG,
8357 + .bmAttributes = USB_OTG_SRP,
8360 +/* one interface in each configuration */
8361 +#ifdef CONFIG_USB_GADGET_DUALSPEED
8364 + * usb 2.0 devices need to expose both high speed and full speed
8365 + * descriptors, unless they only run at full speed.
8367 + * that means alternate endpoint descriptors (bigger packets)
8368 + * and a "device qualifier" ... plus more construction options
8369 + * for the config descriptor.
8372 +static struct usb_qualifier_descriptor
8374 + .bLength = sizeof dev_qualifier,
8375 + .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
8377 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
8378 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
8380 + .bNumConfigurations = 2,
8384 +struct usb_cs_as_general_descriptor {
8386 + __u8 bDescriptorType;
8388 + __u8 bDescriptorSubType;
8389 + __u8 bTerminalLink;
8392 +} __attribute__ ((packed));
8394 +struct usb_cs_as_format_descriptor {
8396 + __u8 bDescriptorType;
8398 + __u8 bDescriptorSubType;
8401 + __u8 bSubframeSize;
8402 + __u8 bBitResolution;
8403 + __u8 bSamfreqType;
8404 + __u8 tLowerSamFreq[3];
8405 + __u8 tUpperSamFreq[3];
8406 +} __attribute__ ((packed));
8408 +static const struct usb_interface_descriptor
8409 +z_audio_control_if_desc = {
8410 + .bLength = sizeof z_audio_control_if_desc,
8411 + .bDescriptorType = USB_DT_INTERFACE,
8412 + .bInterfaceNumber = 0,
8413 + .bAlternateSetting = 0,
8414 + .bNumEndpoints = 0,
8415 + .bInterfaceClass = USB_CLASS_AUDIO,
8416 + .bInterfaceSubClass = 0x1,
8417 + .bInterfaceProtocol = 0,
8421 +static const struct usb_interface_descriptor
8422 +z_audio_if_desc = {
8423 + .bLength = sizeof z_audio_if_desc,
8424 + .bDescriptorType = USB_DT_INTERFACE,
8425 + .bInterfaceNumber = 1,
8426 + .bAlternateSetting = 0,
8427 + .bNumEndpoints = 0,
8428 + .bInterfaceClass = USB_CLASS_AUDIO,
8429 + .bInterfaceSubClass = 0x2,
8430 + .bInterfaceProtocol = 0,
8434 +static const struct usb_interface_descriptor
8435 +z_audio_if_desc2 = {
8436 + .bLength = sizeof z_audio_if_desc,
8437 + .bDescriptorType = USB_DT_INTERFACE,
8438 + .bInterfaceNumber = 1,
8439 + .bAlternateSetting = 1,
8440 + .bNumEndpoints = 1,
8441 + .bInterfaceClass = USB_CLASS_AUDIO,
8442 + .bInterfaceSubClass = 0x2,
8443 + .bInterfaceProtocol = 0,
8447 +static const struct usb_cs_as_general_descriptor
8448 +z_audio_cs_as_if_desc = {
8450 + .bDescriptorType = 0x24,
8452 + .bDescriptorSubType = 0x01,
8453 + .bTerminalLink = 0x01,
8455 + .wFormatTag = __constant_cpu_to_le16 (0x0001)
8459 +static const struct usb_cs_as_format_descriptor
8460 +z_audio_cs_as_format_desc = {
8462 + .bDescriptorType = 0x24,
8464 + .bDescriptorSubType = 2,
8467 + .bSubframeSize = 1,
8468 + .bBitResolution = 8,
8469 + .bSamfreqType = 0,
8470 + .tLowerSamFreq = {0x7e, 0x13, 0x00},
8471 + .tUpperSamFreq = {0xe2, 0xd6, 0x00},
8474 +static const struct usb_endpoint_descriptor
8477 + .bDescriptorType = 0x05,
8478 + .bEndpointAddress = 0x04,
8479 + .bmAttributes = 0x09,
8480 + .wMaxPacketSize = 0x0038,
8481 + .bInterval = 0x01,
8483 + .bSynchAddress = 0x00,
8486 +static char z_iso_ep2[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
8489 +static char z_ac_interface_header_desc[] =
8490 +{ 0x09, 0x24, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x01, 0x01 };
8493 +static char z_0[] = {0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
8494 + 0x03, 0x00, 0x00, 0x00};
8496 +static char z_1[] = {0x0d, 0x24, 0x06, 0x02, 0x01, 0x02, 0x15, 0x00,
8497 + 0x02, 0x00, 0x02, 0x00, 0x00};
8499 +static char z_2[] = {0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x02,
8502 +static char za_0[] = {0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00,
8505 +static char za_1[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
8507 +static char za_2[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x01, 0x08, 0x00,
8508 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
8510 +static char za_3[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
8513 +static char za_4[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
8515 +static char za_5[] = {0x09, 0x04, 0x01, 0x03, 0x01, 0x01, 0x02, 0x00,
8518 +static char za_6[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
8520 +static char za_7[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x00,
8521 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
8523 +static char za_8[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
8526 +static char za_9[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
8528 +static char za_10[] = {0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00,
8531 +static char za_11[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
8533 +static char za_12[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00,
8534 + 0x73, 0x13, 0x00, 0xe2, 0xd6, 0x00};
8536 +static char za_13[] = {0x09, 0x05, 0x04, 0x09, 0xe0, 0x00, 0x01, 0x00,
8539 +static char za_14[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
8541 +static char za_15[] = {0x09, 0x04, 0x01, 0x05, 0x01, 0x01, 0x02, 0x00,
8544 +static char za_16[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
8546 +static char za_17[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x03, 0x14, 0x00,
8547 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
8549 +static char za_18[] = {0x09, 0x05, 0x04, 0x09, 0xa8, 0x00, 0x01, 0x00,
8552 +static char za_19[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
8554 +static char za_20[] = {0x09, 0x04, 0x01, 0x06, 0x01, 0x01, 0x02, 0x00,
8557 +static char za_21[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
8559 +static char za_22[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x03, 0x14, 0x00,
8560 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
8562 +static char za_23[] = {0x09, 0x05, 0x04, 0x09, 0x50, 0x01, 0x01, 0x00,
8565 +static char za_24[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
8569 +static const struct usb_descriptor_header *z_function [] = {
8570 + (struct usb_descriptor_header *) &z_audio_control_if_desc,
8571 + (struct usb_descriptor_header *) &z_ac_interface_header_desc,
8572 + (struct usb_descriptor_header *) &z_0,
8573 + (struct usb_descriptor_header *) &z_1,
8574 + (struct usb_descriptor_header *) &z_2,
8575 + (struct usb_descriptor_header *) &z_audio_if_desc,
8576 + (struct usb_descriptor_header *) &z_audio_if_desc2,
8577 + (struct usb_descriptor_header *) &z_audio_cs_as_if_desc,
8578 + (struct usb_descriptor_header *) &z_audio_cs_as_format_desc,
8579 + (struct usb_descriptor_header *) &z_iso_ep,
8580 + (struct usb_descriptor_header *) &z_iso_ep2,
8581 + (struct usb_descriptor_header *) &za_0,
8582 + (struct usb_descriptor_header *) &za_1,
8583 + (struct usb_descriptor_header *) &za_2,
8584 + (struct usb_descriptor_header *) &za_3,
8585 + (struct usb_descriptor_header *) &za_4,
8586 + (struct usb_descriptor_header *) &za_5,
8587 + (struct usb_descriptor_header *) &za_6,
8588 + (struct usb_descriptor_header *) &za_7,
8589 + (struct usb_descriptor_header *) &za_8,
8590 + (struct usb_descriptor_header *) &za_9,
8591 + (struct usb_descriptor_header *) &za_10,
8592 + (struct usb_descriptor_header *) &za_11,
8593 + (struct usb_descriptor_header *) &za_12,
8594 + (struct usb_descriptor_header *) &za_13,
8595 + (struct usb_descriptor_header *) &za_14,
8596 + (struct usb_descriptor_header *) &za_15,
8597 + (struct usb_descriptor_header *) &za_16,
8598 + (struct usb_descriptor_header *) &za_17,
8599 + (struct usb_descriptor_header *) &za_18,
8600 + (struct usb_descriptor_header *) &za_19,
8601 + (struct usb_descriptor_header *) &za_20,
8602 + (struct usb_descriptor_header *) &za_21,
8603 + (struct usb_descriptor_header *) &za_22,
8604 + (struct usb_descriptor_header *) &za_23,
8605 + (struct usb_descriptor_header *) &za_24,
8609 +/* maxpacket and other transfer characteristics vary by speed. */
8610 +#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
8614 +/* if there's no high speed support, maxpacket doesn't change. */
8615 +#define ep_desc(g,hs,fs) fs
8617 +#endif /* !CONFIG_USB_GADGET_DUALSPEED */
8619 +static char manufacturer [40];
8620 +//static char serial [40];
8621 +static char serial [] = "Ser 00 em";
8623 +/* static strings, in UTF-8 */
8624 +static struct usb_string strings [] = {
8625 + { STRING_MANUFACTURER, manufacturer, },
8626 + { STRING_PRODUCT, longname, },
8627 + { STRING_SERIAL, serial, },
8628 + { STRING_LOOPBACK, loopback, },
8629 + { STRING_SOURCE_SINK, source_sink, },
8630 + { } /* end of list */
8633 +static struct usb_gadget_strings stringtab = {
8634 + .language = 0x0409, /* en-us */
8635 + .strings = strings,
8639 + * config descriptors are also handcrafted. these must agree with code
8640 + * that sets configurations, and with code managing interfaces and their
8641 + * altsettings. other complexity may come from:
8643 + * - high speed support, including "other speed config" rules
8644 + * - multiple configurations
8645 + * - interfaces with alternate settings
8646 + * - embedded class or vendor-specific descriptors
8648 + * this handles high speed, and has a second config that could as easily
8649 + * have been an alternate interface setting (on most hardware).
8651 + * NOTE: to demonstrate (and test) more USB capabilities, this driver
8652 + * should include an altsetting to test interrupt transfers, including
8653 + * high bandwidth modes at high speed. (Maybe work like Intel's test
8657 +config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index)
8660 + const struct usb_descriptor_header **function;
8662 + function = z_function;
8663 + len = usb_gadget_config_buf (&z_config, buf, USB_BUFSIZ, function);
8666 + ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
8670 +/*-------------------------------------------------------------------------*/
8672 +static struct usb_request *
8673 +alloc_ep_req (struct usb_ep *ep, unsigned length)
8675 + struct usb_request *req;
8677 + req = usb_ep_alloc_request (ep, GFP_ATOMIC);
8679 + req->length = length;
8680 + req->buf = usb_ep_alloc_buffer (ep, length,
8681 + &req->dma, GFP_ATOMIC);
8683 + usb_ep_free_request (ep, req);
8690 +static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
8693 + usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
8694 + usb_ep_free_request (ep, req);
8697 +/*-------------------------------------------------------------------------*/
8699 +/* optionally require specific source/sink data patterns */
8703 + struct zero_dev *dev,
8704 + struct usb_ep *ep,
8705 + struct usb_request *req
8709 + u8 *buf = req->buf;
8711 + for (i = 0; i < req->actual; i++, buf++) {
8712 + switch (pattern) {
8713 + /* all-zeroes has no synchronization issues */
8718 + /* mod63 stays in sync with short-terminated transfers,
8719 + * or otherwise when host and gadget agree on how large
8720 + * each usb transfer request should be. resync is done
8721 + * with set_interface or set_config.
8724 + if (*buf == (u8)(i % 63))
8728 + ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
8729 + usb_ep_set_halt (ep);
8735 +/*-------------------------------------------------------------------------*/
8737 +static void zero_reset_config (struct zero_dev *dev)
8739 + if (dev->config == 0)
8742 + DBG (dev, "reset config\n");
8744 + /* just disable endpoints, forcing completion of pending i/o.
8745 + * all our completion handlers free their requests in this case.
8748 + usb_ep_disable (dev->in_ep);
8749 + dev->in_ep = NULL;
8751 + if (dev->out_ep) {
8752 + usb_ep_disable (dev->out_ep);
8753 + dev->out_ep = NULL;
8756 + del_timer (&dev->resume);
8759 +#define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
8762 +zero_isoc_complete (struct usb_ep *ep, struct usb_request *req)
8764 + struct zero_dev *dev = ep->driver_data;
8765 + int status = req->status;
8770 + case 0: /* normal completion? */
8771 + //printk ("\nzero ---------------> isoc normal completion %d bytes\n", req->actual);
8772 + for (i=0, j=rbuf_start; i<req->actual; i++) {
8773 + //printk ("%02x ", ((__u8*)req->buf)[i]);
8774 + rbuf[j] = ((__u8*)req->buf)[i];
8776 + if (j >= RBUF_LEN) j=0;
8779 + //printk ("\n\n");
8781 + if (rbuf_len < RBUF_LEN) {
8782 + rbuf_len += req->actual;
8783 + if (rbuf_len > RBUF_LEN) {
8784 + rbuf_len = RBUF_LEN;
8790 + /* this endpoint is normally active while we're configured */
8791 + case -ECONNABORTED: /* hardware forced ep reset */
8792 + case -ECONNRESET: /* request dequeued */
8793 + case -ESHUTDOWN: /* disconnect from host */
8794 + VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
8795 + req->actual, req->length);
8796 + if (ep == dev->out_ep)
8797 + check_read_data (dev, ep, req);
8798 + free_ep_req (ep, req);
8801 + case -EOVERFLOW: /* buffer overrun on read means that
8802 + * we didn't provide a big enough
8807 + DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
8808 + status, req->actual, req->length);
8810 + case -EREMOTEIO: /* short read */
8814 + status = usb_ep_queue (ep, req, GFP_ATOMIC);
8816 + ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
8817 + ep->name, req->length, status);
8818 + usb_ep_set_halt (ep);
8819 + /* FIXME recover later ... somehow */
8823 +static struct usb_request *
8824 +zero_start_isoc_ep (struct usb_ep *ep, int gfp_flags)
8826 + struct usb_request *req;
8829 + req = alloc_ep_req (ep, 512);
8833 + req->complete = zero_isoc_complete;
8835 + status = usb_ep_queue (ep, req, gfp_flags);
8837 + struct zero_dev *dev = ep->driver_data;
8839 + ERROR (dev, "start %s --> %d\n", ep->name, status);
8840 + free_ep_req (ep, req);
8847 +/* change our operational config. this code must agree with the code
8848 + * that returns config descriptors, and altsetting code.
8850 + * it's also responsible for power management interactions. some
8851 + * configurations might not work with our current power sources.
8853 + * note that some device controller hardware will constrain what this
8854 + * code can do, perhaps by disallowing more than one configuration or
8855 + * by limiting configuration choices (like the pxa2xx).
8858 +zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
8861 + struct usb_gadget *gadget = dev->gadget;
8862 + const struct usb_endpoint_descriptor *d;
8863 + struct usb_ep *ep;
8865 + if (number == dev->config)
8868 + zero_reset_config (dev);
8870 + gadget_for_each_ep (ep, gadget) {
8872 + if (strcmp (ep->name, "ep4") == 0) {
8874 + d = (struct usb_endpoint_descripter *)&za_23; // isoc ep desc for audio i/f alt setting 6
8875 + result = usb_ep_enable (ep, d);
8877 + if (result == 0) {
8878 + ep->driver_data = dev;
8881 + if (zero_start_isoc_ep (ep, gfp_flags) != 0) {
8887 + usb_ep_disable (ep);
8894 + dev->config = number;
8898 +/*-------------------------------------------------------------------------*/
8900 +static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
8902 + if (req->status || req->actual != req->length)
8903 + DBG ((struct zero_dev *) ep->driver_data,
8904 + "setup complete --> %d, %d/%d\n",
8905 + req->status, req->actual, req->length);
8909 + * The setup() callback implements all the ep0 functionality that's
8910 + * not handled lower down, in hardware or the hardware driver (like
8911 + * device and endpoint feature flags, and their status). It's all
8912 + * housekeeping for the gadget function we're implementing. Most of
8913 + * the work is in config-specific setup.
8916 +zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
8918 + struct zero_dev *dev = get_gadget_data (gadget);
8919 + struct usb_request *req = dev->req;
8920 + int value = -EOPNOTSUPP;
8922 + /* usually this stores reply data in the pre-allocated ep0 buffer,
8923 + * but config change events will reconfigure hardware.
8926 + switch (ctrl->bRequest) {
8928 + case USB_REQ_GET_DESCRIPTOR:
8930 + switch (ctrl->wValue >> 8) {
8932 + case USB_DT_DEVICE:
8933 + value = min (ctrl->wLength, (u16) sizeof device_desc);
8934 + memcpy (req->buf, &device_desc, value);
8936 +#ifdef CONFIG_USB_GADGET_DUALSPEED
8937 + case USB_DT_DEVICE_QUALIFIER:
8938 + if (!gadget->is_dualspeed)
8940 + value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
8941 + memcpy (req->buf, &dev_qualifier, value);
8944 + case USB_DT_OTHER_SPEED_CONFIG:
8945 + if (!gadget->is_dualspeed)
8948 +#endif /* CONFIG_USB_GADGET_DUALSPEED */
8949 + case USB_DT_CONFIG:
8950 + value = config_buf (gadget, req->buf,
8951 + ctrl->wValue >> 8,
8952 + ctrl->wValue & 0xff);
8954 + value = min (ctrl->wLength, (u16) value);
8957 + case USB_DT_STRING:
8958 + /* wIndex == language code.
8959 + * this driver only handles one language, you can
8960 + * add string tables for other languages, using
8961 + * any UTF-8 characters
8963 + value = usb_gadget_get_string (&stringtab,
8964 + ctrl->wValue & 0xff, req->buf);
8966 + value = min (ctrl->wLength, (u16) value);
8972 + /* currently two configs, two speeds */
8973 + case USB_REQ_SET_CONFIGURATION:
8974 + if (ctrl->bRequestType != 0)
8977 + spin_lock (&dev->lock);
8978 + value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
8979 + spin_unlock (&dev->lock);
8981 + case USB_REQ_GET_CONFIGURATION:
8982 + if (ctrl->bRequestType != USB_DIR_IN)
8984 + *(u8 *)req->buf = dev->config;
8985 + value = min (ctrl->wLength, (u16) 1);
8988 + /* until we add altsetting support, or other interfaces,
8989 + * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
8990 + * and already killed pending endpoint I/O.
8992 + case USB_REQ_SET_INTERFACE:
8994 + if (ctrl->bRequestType != USB_RECIP_INTERFACE)
8996 + spin_lock (&dev->lock);
8997 + if (dev->config) {
8998 + u8 config = dev->config;
9000 + /* resets interface configuration, forgets about
9001 + * previous transaction state (queued bufs, etc)
9002 + * and re-inits endpoint state (toggle etc)
9003 + * no response queued, just zero status == success.
9004 + * if we had more than one interface we couldn't
9005 + * use this "reset the config" shortcut.
9007 + zero_reset_config (dev);
9008 + zero_set_config (dev, config, GFP_ATOMIC);
9011 + spin_unlock (&dev->lock);
9013 + case USB_REQ_GET_INTERFACE:
9014 + if ((ctrl->bRequestType == 0x21) && (ctrl->wIndex == 0x02)) {
9015 + value = ctrl->wLength;
9019 + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
9023 + if (ctrl->wIndex != 0) {
9027 + *(u8 *)req->buf = 0;
9028 + value = min (ctrl->wLength, (u16) 1);
9033 + * These are the same vendor-specific requests supported by
9034 + * Intel's USB 2.0 compliance test devices. We exceed that
9035 + * device spec by allowing multiple-packet requests.
9037 + case 0x5b: /* control WRITE test -- fill the buffer */
9038 + if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
9040 + if (ctrl->wValue || ctrl->wIndex)
9042 + /* just read that many bytes into the buffer */
9043 + if (ctrl->wLength > USB_BUFSIZ)
9045 + value = ctrl->wLength;
9047 + case 0x5c: /* control READ test -- return the buffer */
9048 + if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
9050 + if (ctrl->wValue || ctrl->wIndex)
9052 + /* expect those bytes are still in the buffer; send back */
9053 + if (ctrl->wLength > USB_BUFSIZ
9054 + || ctrl->wLength != req->length)
9056 + value = ctrl->wLength;
9059 + case 0x01: // SET_CUR
9064 + value = ctrl->wLength;
9067 + switch (ctrl->wValue) {
9070 + ((u8*)req->buf)[0] = 0x00;
9071 + ((u8*)req->buf)[1] = 0xe3;
9075 + ((u8*)req->buf)[0] = 0x00;
9078 + //((u8*)req->buf)[0] = 0x81;
9079 + //((u8*)req->buf)[1] = 0x81;
9080 + value = ctrl->wLength;
9083 + switch (ctrl->wValue) {
9086 + ((u8*)req->buf)[0] = 0x00;
9087 + ((u8*)req->buf)[1] = 0xc3;
9091 + ((u8*)req->buf)[0] = 0x00;
9094 + //((u8*)req->buf)[0] = 0x82;
9095 + //((u8*)req->buf)[1] = 0x82;
9096 + value = ctrl->wLength;
9099 + switch (ctrl->wValue) {
9102 + ((u8*)req->buf)[0] = 0x00;
9103 + ((u8*)req->buf)[1] = 0x00;
9106 + ((u8*)req->buf)[0] = 0x60;
9109 + ((u8*)req->buf)[0] = 0x18;
9112 + //((u8*)req->buf)[0] = 0x83;
9113 + //((u8*)req->buf)[1] = 0x83;
9114 + value = ctrl->wLength;
9117 + switch (ctrl->wValue) {
9120 + ((u8*)req->buf)[0] = 0x00;
9121 + ((u8*)req->buf)[1] = 0x01;
9125 + ((u8*)req->buf)[0] = 0x08;
9128 + //((u8*)req->buf)[0] = 0x84;
9129 + //((u8*)req->buf)[1] = 0x84;
9130 + value = ctrl->wLength;
9133 + ((u8*)req->buf)[0] = 0x85;
9134 + ((u8*)req->buf)[1] = 0x85;
9135 + value = ctrl->wLength;
9141 + printk("unknown control req%02x.%02x v%04x i%04x l%d\n",
9142 + ctrl->bRequestType, ctrl->bRequest,
9143 + ctrl->wValue, ctrl->wIndex, ctrl->wLength);
9146 + /* respond with data transfer before status phase? */
9148 + req->length = value;
9149 + req->zero = value < ctrl->wLength
9150 + && (value % gadget->ep0->maxpacket) == 0;
9151 + value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
9153 + DBG (dev, "ep_queue < 0 --> %d\n", value);
9155 + zero_setup_complete (gadget->ep0, req);
9159 + /* device either stalls (value < 0) or reports success */
9164 +zero_disconnect (struct usb_gadget *gadget)
9166 + struct zero_dev *dev = get_gadget_data (gadget);
9167 + unsigned long flags;
9169 + spin_lock_irqsave (&dev->lock, flags);
9170 + zero_reset_config (dev);
9172 + /* a more significant application might have some non-usb
9173 + * activities to quiesce here, saving resources like power
9174 + * or pushing the notification up a network stack.
9176 + spin_unlock_irqrestore (&dev->lock, flags);
9178 + /* next we may get setup() calls to enumerate new connections;
9179 + * or an unbind() during shutdown (including removing module).
9184 +zero_autoresume (unsigned long _dev)
9186 + struct zero_dev *dev = (struct zero_dev *) _dev;
9189 + /* normally the host would be woken up for something
9190 + * more significant than just a timer firing...
9192 + if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
9193 + status = usb_gadget_wakeup (dev->gadget);
9194 + DBG (dev, "wakeup --> %d\n", status);
9198 +/*-------------------------------------------------------------------------*/
9201 +zero_unbind (struct usb_gadget *gadget)
9203 + struct zero_dev *dev = get_gadget_data (gadget);
9205 + DBG (dev, "unbind\n");
9207 + /* we've already been disconnected ... no i/o is active */
9209 + free_ep_req (gadget->ep0, dev->req);
9210 + del_timer_sync (&dev->resume);
9212 + set_gadget_data (gadget, NULL);
9216 +zero_bind (struct usb_gadget *gadget)
9218 + struct zero_dev *dev;
9219 + //struct usb_ep *ep;
9221 + printk("binding\n");
9223 + * DRIVER POLICY CHOICE: you may want to do this differently.
9224 + * One thing to avoid is reusing a bcdDevice revision code
9225 + * with different host-visible configurations or behavior
9226 + * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
9228 + //device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
9231 + /* ok, we made sense of the hardware ... */
9232 + dev = kmalloc (sizeof *dev, SLAB_KERNEL);
9235 + memset (dev, 0, sizeof *dev);
9236 + spin_lock_init (&dev->lock);
9237 + dev->gadget = gadget;
9238 + set_gadget_data (gadget, dev);
9240 + /* preallocate control response and buffer */
9241 + dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
9244 + dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
9245 + &dev->req->dma, GFP_KERNEL);
9246 + if (!dev->req->buf)
9249 + dev->req->complete = zero_setup_complete;
9251 + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
9253 +#ifdef CONFIG_USB_GADGET_DUALSPEED
9254 + /* assume ep0 uses the same value for both speeds ... */
9255 + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
9257 + /* and that all endpoints are dual-speed */
9258 + //hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
9259 + //hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
9262 + usb_gadget_set_selfpowered (gadget);
9264 + init_timer (&dev->resume);
9265 + dev->resume.function = zero_autoresume;
9266 + dev->resume.data = (unsigned long) dev;
9268 + gadget->ep0->driver_data = dev;
9270 + INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
9271 + INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
9272 + EP_OUT_NAME, EP_IN_NAME);
9274 + snprintf (manufacturer, sizeof manufacturer,
9275 + UTS_SYSNAME " " UTS_RELEASE " with %s",
9281 + zero_unbind (gadget);
9285 +/*-------------------------------------------------------------------------*/
9288 +zero_suspend (struct usb_gadget *gadget)
9290 + struct zero_dev *dev = get_gadget_data (gadget);
9292 + if (gadget->speed == USB_SPEED_UNKNOWN)
9296 + mod_timer (&dev->resume, jiffies + (HZ * autoresume));
9297 + DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
9299 + DBG (dev, "suspend\n");
9303 +zero_resume (struct usb_gadget *gadget)
9305 + struct zero_dev *dev = get_gadget_data (gadget);
9307 + DBG (dev, "resume\n");
9308 + del_timer (&dev->resume);
9312 +/*-------------------------------------------------------------------------*/
9314 +static struct usb_gadget_driver zero_driver = {
9315 +#ifdef CONFIG_USB_GADGET_DUALSPEED
9316 + .speed = USB_SPEED_HIGH,
9318 + .speed = USB_SPEED_FULL,
9320 + .function = (char *) longname,
9321 + .bind = zero_bind,
9322 + .unbind = zero_unbind,
9324 + .setup = zero_setup,
9325 + .disconnect = zero_disconnect,
9327 + .suspend = zero_suspend,
9328 + .resume = zero_resume,
9331 + .name = (char *) shortname,
9332 + // .shutdown = ...
9338 +MODULE_AUTHOR ("David Brownell");
9339 +MODULE_LICENSE ("Dual BSD/GPL");
9341 +static struct proc_dir_entry *pdir, *pfile;
9343 +static int isoc_read_data (char *page, char **start,
9344 + off_t off, int count,
9345 + int *eof, void *data)
9349 + static int done = 0;
9353 + printk ("\ncount: %d\n", count);
9354 + printk ("rbuf_start: %d\n", rbuf_start);
9355 + printk ("rbuf_len: %d\n", rbuf_len);
9356 + printk ("off: %d\n", off);
9357 + printk ("start: %p\n\n", *start);
9367 + if (rbuf_len == RBUF_LEN)
9372 + for (i=0; i<count && c<rbuf_len; i++, c++) {
9373 + page[i] = rbuf[(c+s) % RBUF_LEN];
9377 + if (c >= rbuf_len) {
9386 +static int __init init (void)
9391 + pdir = proc_mkdir("isoc_test", NULL);
9392 + if(pdir == NULL) {
9394 + printk("Error creating dir\n");
9397 + pdir->owner = THIS_MODULE;
9399 + pfile = create_proc_read_entry("isoc_data",
9403 + if (pfile == NULL) {
9405 + printk("Error creating file\n");
9408 + pfile->owner = THIS_MODULE;
9410 + return usb_gadget_register_driver (&zero_driver);
9413 + remove_proc_entry("isoc_data", NULL);
9417 +module_init (init);
9419 +static void __exit cleanup (void)
9422 + usb_gadget_unregister_driver (&zero_driver);
9424 + remove_proc_entry("isoc_data", pdir);
9425 + remove_proc_entry("isoc_test", NULL);
9427 +module_exit (cleanup);
9429 +++ b/drivers/usb/host/dwc_otg/dwc_cfi_common.h
9431 +/* ==========================================================================
9432 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
9433 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
9434 + * otherwise expressly agreed to in writing between Synopsys and you.
9436 + * The Software IS NOT an item of Licensed Software or Licensed Product under
9437 + * any End User Software License Agreement or Agreement for Licensed Product
9438 + * with Synopsys or any supplement thereto. You are permitted to use and
9439 + * redistribute this Software in source and binary forms, with or without
9440 + * modification, provided that redistributions of source code must retain this
9441 + * notice. You may not view, use, disclose, copy or distribute this file or
9442 + * any information contained herein except pursuant to this license grant from
9443 + * Synopsys. If you do not agree with this notice, including the disclaimer
9444 + * below, then you are not authorized to use the Software.
9446 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
9447 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9448 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9449 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
9450 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
9451 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
9452 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
9453 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9454 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9455 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9457 + * ========================================================================== */
9459 +#if !defined(__DWC_CFI_COMMON_H__)
9460 +#define __DWC_CFI_COMMON_H__
9462 +//#include <linux/types.h>
9467 + * This file contains the CFI specific common constants, interfaces
9468 + * (functions and macros) and structures for Linux. No PCD specific
9469 + * data structure or definition is to be included in this file.
9473 +/** This is a request for all Core Features */
9474 +#define VEN_CORE_GET_FEATURES 0xB1
9476 +/** This is a request to get the value of a specific Core Feature */
9477 +#define VEN_CORE_GET_FEATURE 0xB2
9479 +/** This command allows the host to set the value of a specific Core Feature */
9480 +#define VEN_CORE_SET_FEATURE 0xB3
9482 +/** This command allows the host to set the default values of
9483 + * either all or any specific Core Feature
9485 +#define VEN_CORE_RESET_FEATURES 0xB4
9487 +/** This command forces the PCD to write the deferred values of a Core Features */
9488 +#define VEN_CORE_ACTIVATE_FEATURES 0xB5
9490 +/** This request reads a DWORD value from a register at the specified offset */
9491 +#define VEN_CORE_READ_REGISTER 0xB6
9493 +/** This request writes a DWORD value into a register at the specified offset */
9494 +#define VEN_CORE_WRITE_REGISTER 0xB7
9496 +/** This structure is the header of the Core Features dataset returned to
9499 +struct cfi_all_features_header {
9500 +/** The features header structure length is */
9501 +#define CFI_ALL_FEATURES_HDR_LEN 8
9503 + * The total length of the features dataset returned to the Host
9505 + uint16_t wTotalLen;
9508 + * CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H).
9509 + * This field identifies the version of the CFI Specification with which
9510 + * the device is compliant.
9512 + uint16_t wVersion;
9514 + /** The ID of the Core */
9516 +#define CFI_CORE_ID_UDC 1
9517 +#define CFI_CORE_ID_OTG 2
9518 +#define CFI_CORE_ID_WUDEV 3
9520 + /** Number of features returned by VEN_CORE_GET_FEATURES request */
9521 + uint16_t wNumFeatures;
9524 +typedef struct cfi_all_features_header cfi_all_features_header_t;
9526 +/** This structure is a header of the Core Feature descriptor dataset returned to
9527 + * the Host after the VEN_CORE_GET_FEATURES request
9529 +struct cfi_feature_desc_header {
9530 +#define CFI_FEATURE_DESC_HDR_LEN 8
9532 + /** The feature ID */
9533 + uint16_t wFeatureID;
9535 + /** Length of this feature descriptor in bytes - including the
9536 + * length of the feature name string
9540 + /** The data length of this feature in bytes */
9541 + uint16_t wDataLength;
9544 + * Attributes of this features
9545 + * D0: Access rights
9549 + uint8_t bmAttributes;
9550 +#define CFI_FEATURE_ATTR_RO 1
9551 +#define CFI_FEATURE_ATTR_RW 0
9553 + /** Length of the feature name in bytes */
9556 + /** The feature name buffer */
9560 +typedef struct cfi_feature_desc_header cfi_feature_desc_header_t;
9563 + * This structure describes a NULL terminated string referenced by its id field.
9564 + * It is very similar to usb_string structure but has the id field type set to 16-bit.
9566 +struct cfi_string {
9570 +typedef struct cfi_string cfi_string_t;
9574 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
9576 +/* ==========================================================================
9577 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $
9578 + * $Revision: #35 $
9579 + * $Date: 2009/04/03 $
9580 + * $Change: 1225160 $
9582 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
9583 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
9584 + * otherwise expressly agreed to in writing between Synopsys and you.
9586 + * The Software IS NOT an item of Licensed Software or Licensed Product under
9587 + * any End User Software License Agreement or Agreement for Licensed Product
9588 + * with Synopsys or any supplement thereto. You are permitted to use and
9589 + * redistribute this Software in source and binary forms, with or without
9590 + * modification, provided that redistributions of source code must retain this
9591 + * notice. You may not view, use, disclose, copy or distribute this file or
9592 + * any information contained herein except pursuant to this license grant from
9593 + * Synopsys. If you do not agree with this notice, including the disclaimer
9594 + * below, then you are not authorized to use the Software.
9596 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
9597 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9598 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9599 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
9600 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
9601 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
9602 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
9603 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9604 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9605 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9607 + * ========================================================================== */
9611 + * The diagnostic interface will provide access to the controller for
9612 + * bringing up the hardware and testing. The Linux driver attributes
9613 + * feature will be used to provide the Linux Diagnostic
9614 + * Interface. These attributes are accessed through sysfs.
9617 +/** @page "Linux Module Attributes"
9619 + * The Linux module attributes feature is used to provide the Linux
9620 + * Diagnostic Interface. These attributes are accessed through sysfs.
9621 + * The diagnostic interface will provide access to the controller for
9622 + * bringing up the hardware and testing.
9624 + The following table shows the attributes.
9627 + <td><b> Name</b></td>
9628 + <td><b> Description</b></td>
9629 + <td><b> Access</b></td>
9634 + <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
9639 + <td> hnpcapable </td>
9640 + <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
9641 + Read returns the current value.</td>
9642 + <td> Read/Write</td>
9646 + <td> srpcapable </td>
9647 + <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
9648 + Read returns the current value.</td>
9649 + <td> Read/Write</td>
9653 + <td> hsic_connect </td>
9654 + <td> Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register.
9655 + Read returns the current value.</td>
9656 + <td> Read/Write</td>
9660 + <td> inv_sel_hsic </td>
9661 + <td> Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register.
9662 + Read returns the current value.</td>
9663 + <td> Read/Write</td>
9668 + <td> Initiates the Host Negotiation Protocol. Read returns the status.</td>
9669 + <td> Read/Write</td>
9674 + <td> Initiates the Session Request Protocol. Read returns the status.</td>
9675 + <td> Read/Write</td>
9679 + <td> buspower </td>
9680 + <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
9681 + <td> Read/Write</td>
9685 + <td> bussuspend </td>
9686 + <td> Suspends the USB bus.</td>
9687 + <td> Read/Write</td>
9691 + <td> busconnected </td>
9692 + <td> Gets the connection status of the bus</td>
9697 + <td> gotgctl </td>
9698 + <td> Gets or sets the Core Control Status Register.</td>
9699 + <td> Read/Write</td>
9703 + <td> gusbcfg </td>
9704 + <td> Gets or sets the Core USB Configuration Register</td>
9705 + <td> Read/Write</td>
9709 + <td> grxfsiz </td>
9710 + <td> Gets or sets the Receive FIFO Size Register</td>
9711 + <td> Read/Write</td>
9715 + <td> gnptxfsiz </td>
9716 + <td> Gets or sets the non-periodic Transmit Size Register</td>
9717 + <td> Read/Write</td>
9721 + <td> gpvndctl </td>
9722 + <td> Gets or sets the PHY Vendor Control Register</td>
9723 + <td> Read/Write</td>
9728 + <td> Gets the value in the lower 16-bits of the General Purpose IO Register
9729 + or sets the upper 16 bits.</td>
9730 + <td> Read/Write</td>
9735 + <td> Gets or sets the value of the User ID Register</td>
9736 + <td> Read/Write</td>
9740 + <td> gsnpsid </td>
9741 + <td> Gets the value of the Synopsys ID Regester</td>
9746 + <td> devspeed </td>
9747 + <td> Gets or sets the device speed setting in the DCFG register</td>
9748 + <td> Read/Write</td>
9752 + <td> enumspeed </td>
9753 + <td> Gets the device enumeration Speed.</td>
9758 + <td> hptxfsiz </td>
9759 + <td> Gets the value of the Host Periodic Transmit FIFO</td>
9765 + <td> Gets or sets the value in the Host Port Control and Status Register</td>
9766 + <td> Read/Write</td>
9770 + <td> regoffset </td>
9771 + <td> Sets the register offset for the next Register Access</td>
9772 + <td> Read/Write</td>
9776 + <td> regvalue </td>
9777 + <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
9778 + <td> Read/Write</td>
9782 + <td> remote_wakeup </td>
9783 + <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
9784 + wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
9785 + Wakeup signalling bit in the Device Control Register is set for 1
9786 + milli-second.</td>
9787 + <td> Read/Write</td>
9791 + <td> regdump </td>
9792 + <td> Dumps the contents of core registers.</td>
9797 + <td> spramdump </td>
9798 + <td> Dumps the contents of core registers.</td>
9803 + <td> hcddump </td>
9804 + <td> Dumps the current HCD state.</td>
9809 + <td> hcd_frrem </td>
9810 + <td> Shows the average value of the Frame Remaining
9811 + field in the Host Frame Number/Frame Remaining register when an SOF interrupt
9812 + occurs. This can be used to determine the average interrupt latency. Also
9813 + shows the average Frame Remaining value for start_transfer and the "a" and
9814 + "b" sample points. The "a" and "b" sample points may be used during debugging
9815 + bto determine how long it takes to execute a section of the HCD code.</td>
9820 + <td> rd_reg_test </td>
9821 + <td> Displays the time required to read the GNPTXFSIZ register many times
9822 + (the output shows the number of times the register is read).
9827 + <td> wr_reg_test </td>
9828 + <td> Displays the time required to write the GNPTXFSIZ register many times
9829 + (the output shows the number of times the register is written).
9834 + <td> lpm_response </td>
9835 + <td> Gets or sets lpm_response mode. Applicable only in device mode.
9840 + <td> sleep_local_dev </td>
9841 + <td> Generetates sleep signaling. Applicable only in host mode.
9846 + <td> sleep_status </td>
9847 + <td> Shows sleep status of device.
9854 + To get the current mode:
9855 + cat /sys/devices/lm0/mode
9857 + To power down the USB:
9858 + echo 0 > /sys/devices/lm0/buspower
9861 +#include <linux/kernel.h>
9862 +#include <linux/module.h>
9863 +#include <linux/moduleparam.h>
9864 +#include <linux/init.h>
9865 +#include <linux/device.h>
9866 +#include <linux/errno.h>
9867 +#include <linux/types.h>
9868 +#include <linux/stat.h> /* permission constants */
9869 +#include <linux/version.h>
9870 +#include <linux/param.h>
9871 +#include <linux/delay.h>
9872 +#include <linux/jiffies.h>
9875 +#ifdef LM_INTERFACE
9876 +#include <asm/sizes.h>
9877 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
9878 +#include <asm/arch/lm.h>
9880 +/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure -
9881 + here we use definitions stolen from arm-integrator headers
9883 +#include <mach/lm.h>
9885 +#elif defined(PLATFORM_INTERFACE)
9886 +#include <linux/platform_device.h>
9889 +#include <asm/io.h>
9891 +#include "dwc_os.h"
9892 +#include "dwc_otg_driver.h"
9893 +#include "dwc_otg_attr.h"
9894 +#include "dwc_otg_core_if.h"
9895 +#include "dwc_otg_pcd_if.h"
9896 +#include "dwc_otg_hcd_if.h"
9899 + * MACROs for defining sysfs attribute
9901 +#ifdef LM_INTERFACE
9903 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
9904 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
9906 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
9907 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
9909 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
9910 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
9912 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
9913 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
9914 + const char *buf, size_t count) \
9916 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
9917 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
9918 + uint32_t set = simple_strtoul(buf, NULL, 16); \
9919 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
9923 +#elif defined(PCI_INTERFACE)
9925 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
9926 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
9928 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
9930 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
9931 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
9933 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
9934 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
9935 + const char *buf, size_t count) \
9937 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
9938 + uint32_t set = simple_strtoul(buf, NULL, 16); \
9939 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
9943 +#elif defined(PLATFORM_INTERFACE)
9945 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
9946 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
9948 + struct platform_device *platform_dev = \
9949 + container_of(_dev, struct platform_device, dev); \
9950 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
9952 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
9953 + __func__, _dev, platform_dev, otg_dev); \
9954 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
9955 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
9957 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
9958 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
9959 + const char *buf, size_t count) \
9961 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
9962 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
9963 + uint32_t set = simple_strtoul(buf, NULL, 16); \
9964 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
9970 + * MACROs for defining sysfs attribute for 32-bit registers
9972 +#ifdef LM_INTERFACE
9973 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
9974 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
9976 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
9977 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
9979 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
9980 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
9982 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
9983 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
9984 + const char *buf, size_t count) \
9986 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
9987 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
9988 + uint32_t val = simple_strtoul(buf, NULL, 16); \
9989 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
9992 +#elif defined(PCI_INTERFACE)
9993 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
9994 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
9996 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
9998 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
9999 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
10001 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
10002 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
10003 + const char *buf, size_t count) \
10005 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
10006 + uint32_t val = simple_strtoul(buf, NULL, 16); \
10007 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
10011 +#elif defined(PLATFORM_INTERFACE)
10012 +#include "dwc_otg_dbg.h"
10013 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
10014 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
10016 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
10017 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
10019 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
10020 + __func__, _dev, platform_dev, otg_dev); \
10021 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
10022 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
10024 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
10025 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
10026 + const char *buf, size_t count) \
10028 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
10029 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
10030 + uint32_t val = simple_strtoul(buf, NULL, 16); \
10031 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
10037 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \
10038 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
10039 +DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
10040 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
10042 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \
10043 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
10044 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
10046 +#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
10047 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
10048 +DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
10049 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
10051 +#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
10052 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
10053 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
10055 +/** @name Functions for Show/Store of Attributes */
10059 + * Show the register offset of the Register Access.
10061 +static ssize_t regoffset_show(struct device *_dev,
10062 + struct device_attribute *attr, char *buf)
10064 +#ifdef LM_INTERFACE
10065 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10066 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10067 +#elif defined(PCI_INTERFACE)
10068 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10069 +#elif defined(PLATFORM_INTERFACE)
10070 + struct platform_device *platform_dev = container_of(_dev,
10071 + struct platform_device, dev);
10072 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10075 + return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
10076 + otg_dev->reg_offset);
10080 + * Set the register offset for the next Register Access Read/Write
10082 +static ssize_t regoffset_store(struct device *_dev,
10083 + struct device_attribute *attr,
10084 + const char *buf, size_t count)
10086 +#ifdef LM_INTERFACE
10087 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10088 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10089 +#elif defined(PCI_INTERFACE)
10090 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10091 +#elif defined(PLATFORM_INTERFACE)
10092 + struct platform_device *platform_dev = container_of(_dev,
10093 + struct platform_device, dev);
10094 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10097 + uint32_t offset = simple_strtoul(buf, NULL, 16);
10098 + if (offset < SZ_256K) {
10099 + otg_dev->reg_offset = offset;
10101 + dev_err(_dev, "invalid offset\n");
10107 +DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
10110 + * Show the value of the register at the offset in the reg_offset
10113 +static ssize_t regvalue_show(struct device *_dev,
10114 + struct device_attribute *attr, char *buf)
10116 +#ifdef LM_INTERFACE
10117 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10118 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10119 +#elif defined(PCI_INTERFACE)
10120 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10121 +#elif defined(PLATFORM_INTERFACE)
10122 + struct platform_device *platform_dev =
10123 + container_of(_dev, struct platform_device, dev);
10124 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10128 + volatile uint32_t *addr;
10130 + if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
10131 + /* Calculate the address */
10132 + addr = (uint32_t *) (otg_dev->reg_offset +
10133 + (uint8_t *) otg_dev->base);
10134 + val = dwc_read_reg32(addr);
10135 + return snprintf(buf,
10136 + sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
10137 + "Reg@0x%06x = 0x%08x\n", otg_dev->reg_offset,
10140 + dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->reg_offset);
10141 + return sprintf(buf, "invalid offset\n");
10146 + * Store the value in the register at the offset in the reg_offset
10150 +static ssize_t regvalue_store(struct device *_dev,
10151 + struct device_attribute *attr,
10152 + const char *buf, size_t count)
10154 +#ifdef LM_INTERFACE
10155 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10156 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10157 +#elif defined(PCI_INTERFACE)
10158 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10159 +#elif defined(PLATFORM_INTERFACE)
10160 + struct platform_device *platform_dev =
10161 + container_of(_dev, struct platform_device, dev);
10162 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10165 + volatile uint32_t *addr;
10166 + uint32_t val = simple_strtoul(buf, NULL, 16);
10167 + //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
10168 + if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
10169 + /* Calculate the address */
10170 + addr = (uint32_t *) (otg_dev->reg_offset +
10171 + (uint8_t *) otg_dev->base);
10172 + dwc_write_reg32(addr, val);
10174 + dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
10175 + otg_dev->reg_offset);
10180 +DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
10185 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
10186 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
10187 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "Mode");
10188 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
10189 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");
10191 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
10192 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
10193 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");
10195 +DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
10196 +DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
10197 + &(otg_dev->core_if->core_global_regs->gusbcfg),
10199 +DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
10200 + &(otg_dev->core_if->core_global_regs->grxfsiz),
10202 +DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
10203 + &(otg_dev->core_if->core_global_regs->gnptxfsiz),
10205 +DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
10206 + &(otg_dev->core_if->core_global_regs->gpvndctl),
10208 +DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
10209 + &(otg_dev->core_if->core_global_regs->ggpio),
10211 +DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
10213 +DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
10214 + &(otg_dev->core_if->core_global_regs->gsnpsid),
10216 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
10217 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");
10219 +DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
10220 + &(otg_dev->core_if->core_global_regs->hptxfsiz),
10222 +DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
10225 + * @todo Add code to initiate the HNP.
10228 + * Show the HNP status bit
10230 +static ssize_t hnp_show(struct device *_dev,
10231 + struct device_attribute *attr, char *buf)
10233 +#ifdef LM_INTERFACE
10234 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10235 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10236 +#elif defined(PCI_INTERFACE)
10237 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10238 +#elif defined(PLATFORM_INTERFACE)
10239 + struct platform_device *platform_dev =
10240 + container_of(_dev, struct platform_device, dev);
10241 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10243 + return sprintf(buf, "HstNegScs = 0x%x\n",
10244 + dwc_otg_get_hnpstatus(otg_dev->core_if));
10248 + * Set the HNP Request bit
10250 +static ssize_t hnp_store(struct device *_dev,
10251 + struct device_attribute *attr,
10252 + const char *buf, size_t count)
10254 +#ifdef LM_INTERFACE
10255 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10256 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10257 +#elif defined(PCI_INTERFACE)
10258 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10259 +#elif defined(PLATFORM_INTERFACE)
10260 + struct platform_device *platform_dev =
10261 + container_of(_dev, struct platform_device, dev);
10262 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10264 + uint32_t in = simple_strtoul(buf, NULL, 16);
10265 + dwc_otg_set_hnpreq(otg_dev->core_if, in);
10269 +DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
10272 + * @todo Add code to initiate the SRP.
10275 + * Show the SRP status bit
10277 +static ssize_t srp_show(struct device *_dev,
10278 + struct device_attribute *attr, char *buf)
10280 +#ifndef DWC_HOST_ONLY
10281 +#ifdef LM_INTERFACE
10282 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10283 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10284 +#elif defined(PCI_INTERFACE)
10285 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10286 +#elif defined(PLATFORM_INTERFACE)
10287 + struct platform_device *platform_dev =
10288 + container_of(_dev, struct platform_device, dev);
10289 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10291 + return sprintf(buf, "SesReqScs = 0x%x\n",
10292 + dwc_otg_get_srpstatus(otg_dev->core_if));
10294 + return sprintf(buf, "Host Only Mode!\n");
10299 + * Set the SRP Request bit
10301 +static ssize_t srp_store(struct device *_dev,
10302 + struct device_attribute *attr,
10303 + const char *buf, size_t count)
10305 +#ifndef DWC_HOST_ONLY
10306 +#ifdef LM_INTERFACE
10307 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10308 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10309 +#elif defined(PCI_INTERFACE)
10310 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10311 +#elif defined(PLATFORM_INTERFACE)
10312 + struct platform_device *platform_dev =
10313 + container_of(_dev, struct platform_device, dev);
10314 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10316 + dwc_otg_pcd_initiate_srp(otg_dev->pcd);
10321 +DEVICE_ATTR(srp, 0644, srp_show, srp_store);
10324 + * @todo Need to do more for power on/off?
10327 + * Show the Bus Power status
10329 +static ssize_t buspower_show(struct device *_dev,
10330 + struct device_attribute *attr, char *buf)
10332 +#ifdef LM_INTERFACE
10333 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10334 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10335 +#elif defined(PCI_INTERFACE)
10336 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10337 +#elif defined(PLATFORM_INTERFACE)
10338 + struct platform_device *platform_dev =
10339 + container_of(_dev, struct platform_device, dev);
10340 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10342 + return sprintf(buf, "Bus Power = 0x%x\n",
10343 + dwc_otg_get_prtpower(otg_dev->core_if));
10347 + * Set the Bus Power status
10349 +static ssize_t buspower_store(struct device *_dev,
10350 + struct device_attribute *attr,
10351 + const char *buf, size_t count)
10353 +#ifdef LM_INTERFACE
10354 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10355 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10356 +#elif defined(PCI_INTERFACE)
10357 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10358 +#elif defined(PLATFORM_INTERFACE)
10359 + struct platform_device *platform_dev =
10360 + container_of(_dev, struct platform_device, dev);
10361 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10363 + uint32_t on = simple_strtoul(buf, NULL, 16);
10364 + dwc_otg_set_prtpower(otg_dev->core_if, on);
10368 +DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
10371 + * @todo Need to do more for suspend?
10374 + * Show the Bus Suspend status
10376 +static ssize_t bussuspend_show(struct device *_dev,
10377 + struct device_attribute *attr, char *buf)
10379 +#ifdef LM_INTERFACE
10380 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10381 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10382 +#elif defined(PCI_INTERFACE)
10383 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10384 +#elif defined(PLATFORM_INTERFACE)
10385 + struct platform_device *platform_dev =
10386 + container_of(_dev, struct platform_device, dev);
10387 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10390 + return sprintf(buf, "Bus Suspend = 0x%x\n",
10391 + dwc_otg_get_prtsuspend(otg_dev->core_if));
10395 + * Set the Bus Suspend status
10397 +static ssize_t bussuspend_store(struct device *_dev,
10398 + struct device_attribute *attr,
10399 + const char *buf, size_t count)
10401 +#ifdef LM_INTERFACE
10402 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10403 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10404 +#elif defined(PCI_INTERFACE)
10405 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10406 +#elif defined(PLATFORM_INTERFACE)
10407 + struct platform_device *platform_dev =
10408 + container_of(_dev, struct platform_device, dev);
10409 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10412 + uint32_t in = simple_strtoul(buf, NULL, 16);
10413 + dwc_otg_set_prtsuspend(otg_dev->core_if, in);
10417 +DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
10420 + * Show the status of Remote Wakeup.
10422 +static ssize_t remote_wakeup_show(struct device *_dev,
10423 + struct device_attribute *attr, char *buf)
10425 +#ifndef DWC_HOST_ONLY
10426 +#ifdef LM_INTERFACE
10427 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10428 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10429 +#elif defined(PCI_INTERFACE)
10430 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10431 +#elif defined(PLATFORM_INTERFACE)
10432 + struct platform_device *platform_dev =
10433 + container_of(_dev, struct platform_device, dev);
10434 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10437 + return sprintf(buf,
10438 + "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
10439 + dwc_otg_get_remotewakesig(otg_dev->core_if),
10440 + dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
10441 + dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
10443 + return sprintf(buf, "Host Only Mode!\n");
10444 +#endif /* DWC_HOST_ONLY */
10448 + * Initiate a remote wakeup of the host. The Device control register
10449 + * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
10453 +static ssize_t remote_wakeup_store(struct device *_dev,
10454 + struct device_attribute *attr,
10455 + const char *buf, size_t count)
10457 +#ifndef DWC_HOST_ONLY
10458 +#ifdef LM_INTERFACE
10459 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10460 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10461 +#elif defined(PCI_INTERFACE)
10462 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10463 +#elif defined(PLATFORM_INTERFACE)
10464 + struct platform_device *platform_dev =
10465 + container_of(_dev, struct platform_device, dev);
10466 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10469 + uint32_t val = simple_strtoul(buf, NULL, 16);
10472 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
10474 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
10476 +#endif /* DWC_HOST_ONLY */
10480 +DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
10481 + remote_wakeup_store);
10484 + * Dump global registers and either host or device registers (depending on the
10485 + * current mode of the core).
10487 +static ssize_t regdump_show(struct device *_dev,
10488 + struct device_attribute *attr, char *buf)
10490 +#ifdef LM_INTERFACE
10491 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10492 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10493 +#elif defined(PCI_INTERFACE)
10494 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10495 +#elif defined(PLATFORM_INTERFACE)
10496 + struct platform_device *platform_dev =
10497 + container_of(_dev, struct platform_device, dev);
10498 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10501 + dwc_otg_dump_global_registers(otg_dev->core_if);
10502 + if (dwc_otg_is_host_mode(otg_dev->core_if)) {
10503 + dwc_otg_dump_host_registers(otg_dev->core_if);
10505 + dwc_otg_dump_dev_registers(otg_dev->core_if);
10508 + return sprintf(buf, "Register Dump\n");
10511 +DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);
10514 + * Dump global registers and either host or device registers (depending on the
10515 + * current mode of the core).
10517 +static ssize_t spramdump_show(struct device *_dev,
10518 + struct device_attribute *attr, char *buf)
10520 +#ifdef LM_INTERFACE
10521 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10522 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10523 +#elif defined(PCI_INTERFACE)
10524 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10525 +#elif defined(PLATFORM_INTERFACE)
10526 + struct platform_device *platform_dev =
10527 + container_of(_dev, struct platform_device, dev);
10528 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10531 + dwc_otg_dump_spram(otg_dev->core_if);
10533 + return sprintf(buf, "SPRAM Dump\n");
10536 +DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);
10539 + * Dump the current hcd state.
10541 +static ssize_t hcddump_show(struct device *_dev,
10542 + struct device_attribute *attr, char *buf)
10544 +#ifndef DWC_DEVICE_ONLY
10545 +#ifdef LM_INTERFACE
10546 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10547 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10548 +#elif defined(PCI_INTERFACE)
10549 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10550 +#elif defined(PLATFORM_INTERFACE)
10551 + struct platform_device *platform_dev =
10552 + container_of(_dev, struct platform_device, dev);
10553 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10556 + dwc_otg_hcd_dump_state(otg_dev->hcd);
10557 +#endif /* DWC_DEVICE_ONLY */
10558 + return sprintf(buf, "HCD Dump\n");
10561 +DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);
10564 + * Dump the average frame remaining at SOF. This can be used to
10565 + * determine average interrupt latency. Frame remaining is also shown for
10566 + * start transfer and two additional sample points.
10568 +static ssize_t hcd_frrem_show(struct device *_dev,
10569 + struct device_attribute *attr, char *buf)
10571 +#ifndef DWC_DEVICE_ONLY
10572 +#ifdef LM_INTERFACE
10573 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10574 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10575 +#elif defined(PCI_INTERFACE)
10576 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10577 +#elif defined(PLATFORM_INTERFACE)
10578 + struct platform_device *platform_dev =
10579 + container_of(_dev, struct platform_device, dev);
10580 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10583 + dwc_otg_hcd_dump_frrem(otg_dev->hcd);
10584 +#endif /* DWC_DEVICE_ONLY */
10585 + return sprintf(buf, "HCD Dump Frame Remaining\n");
10588 +DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);
10591 + * Displays the time required to read the GNPTXFSIZ register many times (the
10592 + * output shows the number of times the register is read).
10594 +#define RW_REG_COUNT 10000000
10595 +#define MSEC_PER_JIFFIE 1000/HZ
10596 +static ssize_t rd_reg_test_show(struct device *_dev,
10597 + struct device_attribute *attr, char *buf)
10599 +#ifdef LM_INTERFACE
10600 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10601 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10602 +#elif defined(PCI_INTERFACE)
10603 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10604 +#elif defined(PLATFORM_INTERFACE)
10605 + struct platform_device *platform_dev =
10606 + container_of(_dev, struct platform_device, dev);
10607 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10612 + int start_jiffies;
10614 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
10615 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
10616 + start_jiffies = jiffies;
10617 + for (i = 0; i < RW_REG_COUNT; i++) {
10618 + dwc_otg_get_gnptxfsiz(otg_dev->core_if);
10620 + time = jiffies - start_jiffies;
10621 + return sprintf(buf,
10622 + "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
10623 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
10626 +DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);
10629 + * Displays the time required to write the GNPTXFSIZ register many times (the
10630 + * output shows the number of times the register is written).
10632 +static ssize_t wr_reg_test_show(struct device *_dev,
10633 + struct device_attribute *attr, char *buf)
10635 +#ifdef LM_INTERFACE
10636 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10637 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10638 +#elif defined(PCI_INTERFACE)
10639 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10640 +#elif defined(PLATFORM_INTERFACE)
10641 + struct platform_device *platform_dev =
10642 + container_of(_dev, struct platform_device, dev);
10643 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10646 + uint32_t reg_val;
10649 + int start_jiffies;
10651 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
10652 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
10653 + reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
10654 + start_jiffies = jiffies;
10655 + for (i = 0; i < RW_REG_COUNT; i++) {
10656 + dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);
10658 + time = jiffies - start_jiffies;
10659 + return sprintf(buf,
10660 + "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
10661 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
10664 +DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);
10666 +#ifdef CONFIG_USB_DWC_OTG_LPM
10669 +* Show the lpm_response attribute.
10671 +static ssize_t lpmresp_show(struct device *_dev,
10672 + struct device_attribute *attr, char *buf)
10674 +#ifdef LM_INTERFACE
10675 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10676 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10677 +#elif defined(PCI_INTERFACE)
10678 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10679 +#elif defined(PLATFORM_INTERFACE)
10680 + struct platform_device *platform_dev =
10681 + container_of(_dev, struct platform_device, dev);
10682 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10685 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
10686 + return sprintf(buf, "** LPM is DISABLED **\n");
10688 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
10689 + return sprintf(buf, "** Current mode is not device mode\n");
10691 + return sprintf(buf, "lpm_response = %d\n",
10692 + dwc_otg_get_lpmresponse(otg_dev->core_if));
10696 +* Store the lpm_response attribute.
10698 +static ssize_t lpmresp_store(struct device *_dev,
10699 + struct device_attribute *attr,
10700 + const char *buf, size_t count)
10702 +#ifdef LM_INTERFACE
10703 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10704 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10705 +#elif defined(PCI_INTERFACE)
10706 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10707 +#elif defined(PLATFORM_INTERFACE)
10708 + struct platform_device *platform_dev =
10709 + container_of(_dev, struct platform_device, dev);
10710 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10713 + uint32_t val = simple_strtoul(buf, NULL, 16);
10715 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
10719 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
10723 + dwc_otg_set_lpmresponse(otg_dev->core_if, val);
10727 +DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);
10730 +* Show the sleep_status attribute.
10732 +static ssize_t sleepstatus_show(struct device *_dev,
10733 + struct device_attribute *attr, char *buf)
10735 +#ifdef LM_INTERFACE
10736 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10737 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10738 +#elif defined(PCI_INTERFACE)
10739 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10740 +#elif defined(PLATFORM_INTERFACE)
10741 + struct platform_device *platform_dev =
10742 + container_of(_dev, struct platform_device, dev);
10743 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10747 + return sprintf(buf, "Sleep Status = %d\n",
10748 + dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
10752 + * Store the sleep_status attribure.
10754 +static ssize_t sleepstatus_store(struct device *_dev,
10755 + struct device_attribute *attr,
10756 + const char *buf, size_t count)
10758 +#ifdef LM_INTERFACE
10759 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
10760 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
10761 +#elif defined(PCI_INTERFACE)
10762 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
10763 +#elif defined(PLATFORM_INTERFACE)
10764 + struct platform_device *platform_dev =
10765 + container_of(_dev, struct platform_device, dev);
10766 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
10769 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
10771 + if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
10772 + if (dwc_otg_is_host_mode(core_if)) {
10774 + DWC_PRINTF("Host initiated resume\n");
10775 + dwc_otg_set_prtresume(otg_dev->core_if, 1);
10782 +DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
10783 + sleepstatus_store);
10785 +#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */
10790 + * Create the device files
10792 +void dwc_otg_attr_create (
10793 +#ifdef LM_INTERFACE
10794 + struct lm_device *dev
10795 +#elif defined(PCI_INTERFACE)
10796 + struct pci_dev *dev
10797 +#elif defined(PLATFORM_INTERFACE)
10798 + struct platform_device *dev
10805 + error = device_create_file(&dev->dev, &dev_attr_regoffset);
10806 + error = device_create_file(&dev->dev, &dev_attr_regvalue);
10807 + error = device_create_file(&dev->dev, &dev_attr_mode);
10808 + error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
10809 + error = device_create_file(&dev->dev, &dev_attr_srpcapable);
10810 + error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
10811 + error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
10812 + error = device_create_file(&dev->dev, &dev_attr_hnp);
10813 + error = device_create_file(&dev->dev, &dev_attr_srp);
10814 + error = device_create_file(&dev->dev, &dev_attr_buspower);
10815 + error = device_create_file(&dev->dev, &dev_attr_bussuspend);
10816 + error = device_create_file(&dev->dev, &dev_attr_busconnected);
10817 + error = device_create_file(&dev->dev, &dev_attr_gotgctl);
10818 + error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
10819 + error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
10820 + error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
10821 + error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
10822 + error = device_create_file(&dev->dev, &dev_attr_ggpio);
10823 + error = device_create_file(&dev->dev, &dev_attr_guid);
10824 + error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
10825 + error = device_create_file(&dev->dev, &dev_attr_devspeed);
10826 + error = device_create_file(&dev->dev, &dev_attr_enumspeed);
10827 + error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
10828 + error = device_create_file(&dev->dev, &dev_attr_hprt0);
10829 + error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
10830 + error = device_create_file(&dev->dev, &dev_attr_regdump);
10831 + error = device_create_file(&dev->dev, &dev_attr_spramdump);
10832 + error = device_create_file(&dev->dev, &dev_attr_hcddump);
10833 + error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
10834 + error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
10835 + error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
10836 +#ifdef CONFIG_USB_DWC_OTG_LPM
10837 + error = device_create_file(&dev->dev, &dev_attr_lpm_response);
10838 + error = device_create_file(&dev->dev, &dev_attr_sleep_status);
10843 + * Remove the device files
10845 +void dwc_otg_attr_remove (
10846 +#ifdef LM_INTERFACE
10847 + struct lm_device *dev
10848 +#elif defined(PCI_INTERFACE)
10849 + struct pci_dev *dev
10850 +#elif defined(PLATFORM_INTERFACE)
10851 + struct platform_device *dev
10856 + device_remove_file(&dev->dev, &dev_attr_regoffset);
10857 + device_remove_file(&dev->dev, &dev_attr_regvalue);
10858 + device_remove_file(&dev->dev, &dev_attr_mode);
10859 + device_remove_file(&dev->dev, &dev_attr_hnpcapable);
10860 + device_remove_file(&dev->dev, &dev_attr_srpcapable);
10861 + device_remove_file(&dev->dev, &dev_attr_hsic_connect);
10862 + device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
10863 + device_remove_file(&dev->dev, &dev_attr_hnp);
10864 + device_remove_file(&dev->dev, &dev_attr_srp);
10865 + device_remove_file(&dev->dev, &dev_attr_buspower);
10866 + device_remove_file(&dev->dev, &dev_attr_bussuspend);
10867 + device_remove_file(&dev->dev, &dev_attr_busconnected);
10868 + device_remove_file(&dev->dev, &dev_attr_gotgctl);
10869 + device_remove_file(&dev->dev, &dev_attr_gusbcfg);
10870 + device_remove_file(&dev->dev, &dev_attr_grxfsiz);
10871 + device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
10872 + device_remove_file(&dev->dev, &dev_attr_gpvndctl);
10873 + device_remove_file(&dev->dev, &dev_attr_ggpio);
10874 + device_remove_file(&dev->dev, &dev_attr_guid);
10875 + device_remove_file(&dev->dev, &dev_attr_gsnpsid);
10876 + device_remove_file(&dev->dev, &dev_attr_devspeed);
10877 + device_remove_file(&dev->dev, &dev_attr_enumspeed);
10878 + device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
10879 + device_remove_file(&dev->dev, &dev_attr_hprt0);
10880 + device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
10881 + device_remove_file(&dev->dev, &dev_attr_regdump);
10882 + device_remove_file(&dev->dev, &dev_attr_spramdump);
10883 + device_remove_file(&dev->dev, &dev_attr_hcddump);
10884 + device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
10885 + device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
10886 + device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
10887 +#ifdef CONFIG_USB_DWC_OTG_LPM
10888 + device_remove_file(&dev->dev, &dev_attr_lpm_response);
10889 + device_remove_file(&dev->dev, &dev_attr_sleep_status);
10893 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
10895 +/* ==========================================================================
10896 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
10897 + * $Revision: #11 $
10898 + * $Date: 2009/04/03 $
10899 + * $Change: 1225160 $
10901 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
10902 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
10903 + * otherwise expressly agreed to in writing between Synopsys and you.
10905 + * The Software IS NOT an item of Licensed Software or Licensed Product under
10906 + * any End User Software License Agreement or Agreement for Licensed Product
10907 + * with Synopsys or any supplement thereto. You are permitted to use and
10908 + * redistribute this Software in source and binary forms, with or without
10909 + * modification, provided that redistributions of source code must retain this
10910 + * notice. You may not view, use, disclose, copy or distribute this file or
10911 + * any information contained herein except pursuant to this license grant from
10912 + * Synopsys. If you do not agree with this notice, including the disclaimer
10913 + * below, then you are not authorized to use the Software.
10915 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
10916 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10917 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10918 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
10919 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
10920 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
10921 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
10922 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10923 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10924 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
10926 + * ========================================================================== */
10928 +#if !defined(__DWC_OTG_ATTR_H__)
10929 +#define __DWC_OTG_ATTR_H__
10932 + * This file contains the interface to the Linux device attributes.
10934 +extern struct device_attribute dev_attr_regoffset;
10935 +extern struct device_attribute dev_attr_regvalue;
10937 +extern struct device_attribute dev_attr_mode;
10938 +extern struct device_attribute dev_attr_hnpcapable;
10939 +extern struct device_attribute dev_attr_srpcapable;
10940 +extern struct device_attribute dev_attr_hnp;
10941 +extern struct device_attribute dev_attr_srp;
10942 +extern struct device_attribute dev_attr_buspower;
10943 +extern struct device_attribute dev_attr_bussuspend;
10944 +extern struct device_attribute dev_attr_busconnected;
10945 +extern struct device_attribute dev_attr_gotgctl;
10946 +extern struct device_attribute dev_attr_gusbcfg;
10947 +extern struct device_attribute dev_attr_grxfsiz;
10948 +extern struct device_attribute dev_attr_gnptxfsiz;
10949 +extern struct device_attribute dev_attr_gpvndctl;
10950 +extern struct device_attribute dev_attr_ggpio;
10951 +extern struct device_attribute dev_attr_guid;
10952 +extern struct device_attribute dev_attr_gsnpsid;
10953 +extern struct device_attribute dev_attr_devspeed;
10954 +extern struct device_attribute dev_attr_enumspeed;
10955 +extern struct device_attribute dev_attr_hptxfsiz;
10956 +extern struct device_attribute dev_attr_hprt0;
10957 +#ifdef CONFIG_USB_DWC_OTG_LPM
10958 +extern struct device_attribute dev_attr_lpm_response;
10959 +extern struct device_attribute dev_attr_sleep_local_dev;
10960 +extern struct device_attribute devi_attr_sleep_status;
10963 +void dwc_otg_attr_create (
10964 +#ifdef LM_INTERFACE
10965 + struct lm_device *dev
10966 +#elif defined(PCI_INTERFACE)
10967 + struct pci_dev *dev
10968 +#elif defined(PLATFORM_INTERFACE)
10969 + struct platform_device *dev
10973 +void dwc_otg_attr_remove (
10974 +#ifdef LM_INTERFACE
10975 + struct lm_device *dev
10976 +#elif defined(PCI_INTERFACE)
10977 + struct pci_dev *dev
10978 +#elif defined(PLATFORM_INTERFACE)
10979 + struct platform_device *dev
10984 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.c
10986 +/* ==========================================================================
10987 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
10988 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
10989 + * otherwise expressly agreed to in writing between Synopsys and you.
10991 + * The Software IS NOT an item of Licensed Software or Licensed Product under
10992 + * any End User Software License Agreement or Agreement for Licensed Product
10993 + * with Synopsys or any supplement thereto. You are permitted to use and
10994 + * redistribute this Software in source and binary forms, with or without
10995 + * modification, provided that redistributions of source code must retain this
10996 + * notice. You may not view, use, disclose, copy or distribute this file or
10997 + * any information contained herein except pursuant to this license grant from
10998 + * Synopsys. If you do not agree with this notice, including the disclaimer
10999 + * below, then you are not authorized to use the Software.
11001 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
11002 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
11003 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
11004 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
11005 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11006 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
11007 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
11008 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
11009 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
11010 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
11012 + * ========================================================================== */
11016 + * This file contains the most of the CFI implementation for the OTG.
11019 +#ifdef DWC_UTE_CFI
11021 +#include "dwc_otg_pcd.h"
11022 +#include "dwc_otg_cfi.h"
11024 +/** This definition should actually migrate to the Portability Library */
11025 +#define DWC_CONSTANT_CPU_TO_LE16(x) (x)
11027 +extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex);
11029 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen);
11030 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
11031 + struct dwc_otg_pcd *pcd,
11032 + struct cfi_usb_ctrlrequest *ctrl_req);
11033 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd);
11034 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
11035 + struct cfi_usb_ctrlrequest *req);
11036 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
11037 + struct cfi_usb_ctrlrequest *req);
11038 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
11039 + struct cfi_usb_ctrlrequest *req);
11040 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
11041 + struct cfi_usb_ctrlrequest *req);
11042 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep);
11044 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if);
11045 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue);
11046 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue);
11048 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if);
11050 +/** This is the header of the all features descriptor */
11051 +static cfi_all_features_header_t all_props_desc_header = {
11052 + .wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100),
11053 + .wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG),
11054 + .wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9),
11057 +/** This is an array of statically allocated feature descriptors */
11058 +static cfi_feature_desc_header_t prop_descs[] = {
11060 + /* FT_ID_DMA_MODE */
11062 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE),
11063 + .bmAttributes = CFI_FEATURE_ATTR_RW,
11064 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1),
11067 + /* FT_ID_DMA_BUFFER_SETUP */
11069 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP),
11070 + .bmAttributes = CFI_FEATURE_ATTR_RW,
11071 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
11074 + /* FT_ID_DMA_BUFF_ALIGN */
11076 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN),
11077 + .bmAttributes = CFI_FEATURE_ATTR_RW,
11078 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
11081 + /* FT_ID_DMA_CONCAT_SETUP */
11083 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP),
11084 + .bmAttributes = CFI_FEATURE_ATTR_RW,
11085 + //.wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
11088 + /* FT_ID_DMA_CIRCULAR */
11090 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR),
11091 + .bmAttributes = CFI_FEATURE_ATTR_RW,
11092 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
11095 + /* FT_ID_THRESHOLD_SETUP */
11097 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP),
11098 + .bmAttributes = CFI_FEATURE_ATTR_RW,
11099 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
11102 + /* FT_ID_DFIFO_DEPTH */
11104 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH),
11105 + .bmAttributes = CFI_FEATURE_ATTR_RO,
11106 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
11109 + /* FT_ID_TX_FIFO_DEPTH */
11111 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH),
11112 + .bmAttributes = CFI_FEATURE_ATTR_RW,
11113 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
11116 + /* FT_ID_RX_FIFO_DEPTH */
11118 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH),
11119 + .bmAttributes = CFI_FEATURE_ATTR_RW,
11120 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
11124 +/** The table of feature names */
11125 +cfi_string_t prop_name_table[] = {
11126 + {FT_ID_DMA_MODE, "dma_mode"},
11127 + {FT_ID_DMA_BUFFER_SETUP, "buffer_setup"},
11128 + {FT_ID_DMA_BUFF_ALIGN, "buffer_align"},
11129 + {FT_ID_DMA_CONCAT_SETUP, "concat_setup"},
11130 + {FT_ID_DMA_CIRCULAR, "buffer_circular"},
11131 + {FT_ID_THRESHOLD_SETUP, "threshold_setup"},
11132 + {FT_ID_DFIFO_DEPTH, "dfifo_depth"},
11133 + {FT_ID_TX_FIFO_DEPTH, "txfifo_depth"},
11134 + {FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"},
11138 +/************************************************************************/
11141 + * Returns the name of the feature by its ID
11142 + * or NULL if no featute ID matches.
11145 +const uint8_t *get_prop_name(uint16_t prop_id, int *len)
11147 + cfi_string_t *pstr;
11150 + for (pstr = prop_name_table; pstr && pstr->s; pstr++) {
11151 + if (pstr->id == prop_id) {
11152 + *len = DWC_STRLEN(pstr->s);
11160 + * This function handles all CFI specific control requests.
11162 + * Return a negative value to stall the DCE.
11164 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)
11167 + dwc_otg_pcd_ep_t *ep = NULL;
11168 + cfiobject_t *cfi = pcd->cfi;
11169 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
11170 + uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength);
11171 + uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue);
11172 + uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex);
11173 + uint32_t regaddr = 0;
11174 + uint32_t regval = 0;
11176 + /* Save this Control Request in the CFI object.
11177 + * The data field will be assigned in the data stage completion CB function.
11179 + cfi->ctrl_req = *ctrl;
11180 + cfi->ctrl_req.data = NULL;
11182 + cfi->need_gadget_att = 0;
11183 + cfi->need_status_in_complete = 0;
11185 + switch (ctrl->bRequest) {
11186 + case VEN_CORE_GET_FEATURES:
11187 + retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN);
11188 + if (retval >= 0) {
11189 + //dump_msg(cfi->buf_in.buf, retval);
11192 + retval = min((uint16_t) retval, wLen);
11193 + /* Transfer this buffer to the host through the EP0-IN EP */
11194 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
11195 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
11196 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
11197 + ep->dwc_ep.xfer_len = retval;
11198 + ep->dwc_ep.xfer_count = 0;
11199 + ep->dwc_ep.sent_zlp = 0;
11200 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
11202 + pcd->ep0_pending = 1;
11203 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
11208 + case VEN_CORE_GET_FEATURE:
11209 + CFI_INFO("VEN_CORE_GET_FEATURE\n");
11210 + retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN,
11212 + if (retval >= 0) {
11215 + retval = min((uint16_t) retval, wLen);
11216 + /* Transfer this buffer to the host through the EP0-IN EP */
11217 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
11218 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
11219 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
11220 + ep->dwc_ep.xfer_len = retval;
11221 + ep->dwc_ep.xfer_count = 0;
11222 + ep->dwc_ep.sent_zlp = 0;
11223 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
11225 + pcd->ep0_pending = 1;
11226 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
11228 + CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval);
11229 + dump_msg(cfi->buf_in.buf, retval);
11232 + case VEN_CORE_SET_FEATURE:
11233 + CFI_INFO("VEN_CORE_SET_FEATURE\n");
11234 + /* Set up an XFER to get the data stage of the control request,
11235 + * which is the new value of the feature to be modified.
11238 + ep->dwc_ep.is_in = 0;
11239 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
11240 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
11241 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
11242 + ep->dwc_ep.xfer_len = wLen;
11243 + ep->dwc_ep.xfer_count = 0;
11244 + ep->dwc_ep.sent_zlp = 0;
11245 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
11247 + pcd->ep0_pending = 1;
11248 + /* Read the control write's data stage */
11249 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
11253 + case VEN_CORE_RESET_FEATURES:
11254 + CFI_INFO("VEN_CORE_RESET_FEATURES\n");
11255 + cfi->need_gadget_att = 1;
11256 + cfi->need_status_in_complete = 1;
11257 + retval = cfi_preproc_reset(pcd, ctrl);
11258 + CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval);
11261 + case VEN_CORE_ACTIVATE_FEATURES:
11262 + CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n");
11265 + case VEN_CORE_READ_REGISTER:
11266 + CFI_INFO("VEN_CORE_READ_REGISTER\n");
11267 + /* wValue optionally contains the HI WORD of the register offset and
11268 + * wIndex contains the LOW WORD of the register offset
11270 + if (wValue == 0) {
11271 + /* @TODO - MAS - fix the access to the base field */
11273 + //regaddr = (uint32_t) pcd->otg_dev->base;
11274 + //GET_CORE_IF(pcd)->co
11275 + regaddr |= wIndex;
11277 + regaddr = (wValue << 16) | wIndex;
11280 + /* Read a 32-bit value of the memory at the regaddr */
11281 + regval = dwc_read_reg32((uint32_t *) regaddr);
11284 + dwc_memcpy(cfi->buf_in.buf, ®val, sizeof(uint32_t));
11285 + ep->dwc_ep.is_in = 1;
11286 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
11287 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
11288 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
11289 + ep->dwc_ep.xfer_len = wLen;
11290 + ep->dwc_ep.xfer_count = 0;
11291 + ep->dwc_ep.sent_zlp = 0;
11292 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
11294 + pcd->ep0_pending = 1;
11295 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
11296 + cfi->need_gadget_att = 0;
11300 + case VEN_CORE_WRITE_REGISTER:
11301 + CFI_INFO("VEN_CORE_WRITE_REGISTER\n");
11302 + /* Set up an XFER to get the data stage of the control request,
11303 + * which is the new value of the register to be modified.
11306 + ep->dwc_ep.is_in = 0;
11307 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
11308 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
11309 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
11310 + ep->dwc_ep.xfer_len = wLen;
11311 + ep->dwc_ep.xfer_count = 0;
11312 + ep->dwc_ep.sent_zlp = 0;
11313 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
11315 + pcd->ep0_pending = 1;
11316 + /* Read the control write's data stage */
11317 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
11322 + retval = -DWC_E_NOT_SUPPORTED;
11330 + * This function prepares the core features descriptors and copies its
11331 + * raw representation into the buffer <buf>.
11333 + * The buffer structure is as follows:
11334 + * all_features_header (8 bytes)
11335 + * features_#1 (8 bytes + feature name string length)
11336 + * features_#2 (8 bytes + feature name string length)
11338 + * features_#n - where n=the total count of feature descriptors
11340 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen)
11342 + cfi_feature_desc_header_t *prop_hdr = prop_descs;
11343 + cfi_feature_desc_header_t *prop;
11344 + cfi_all_features_header_t *all_props_hdr = &all_props_desc_header;
11345 + cfi_all_features_header_t *tmp;
11346 + uint8_t *tmpbuf = buf;
11347 + const uint8_t *pname = NULL;
11348 + int i, j, namelen = 0, totlen;
11350 + /* Prepare and copy the core features into the buffer */
11351 + CFI_INFO("%s:\n", __func__);
11353 + tmp = (cfi_all_features_header_t *) tmpbuf;
11354 + *tmp = *all_props_hdr;
11355 + tmpbuf += CFI_ALL_FEATURES_HDR_LEN;
11357 + j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t);
11358 + for (i = 0; i < j; i++, prop_hdr++) {
11359 + pname = get_prop_name(prop_hdr->wFeatureID, &namelen);
11360 + prop = (cfi_feature_desc_header_t *) tmpbuf;
11361 + *prop = *prop_hdr;
11363 + prop->bNameLen = namelen;
11365 + DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN +
11368 + tmpbuf += CFI_FEATURE_DESC_HDR_LEN;
11369 + dwc_memcpy(tmpbuf, pname, namelen);
11370 + tmpbuf += namelen;
11373 + totlen = tmpbuf - buf;
11375 + if (totlen > 0) {
11376 + tmp = (cfi_all_features_header_t *) buf;
11377 + tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen);
11384 + * This function releases all the dynamic memory in the CFI object.
11386 +static void cfi_release(cfiobject_t * cfiobj)
11389 + dwc_list_link_t *tmp;
11391 + CFI_INFO("%s\n", __func__);
11393 + if (cfiobj->buf_in.buf) {
11394 + dwc_dma_free(CFI_IN_BUF_LEN, cfiobj->buf_in.buf,
11395 + cfiobj->buf_in.addr);
11396 + cfiobj->buf_in.buf = NULL;
11399 + if (cfiobj->buf_out.buf) {
11400 + dwc_dma_free(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf,
11401 + cfiobj->buf_out.addr);
11402 + cfiobj->buf_out.buf = NULL;
11405 + /* Free the Buffer Setup values for each EP */
11406 + //list_for_each_entry(cfiep, &cfiobj->active_eps, lh) {
11407 + DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) {
11408 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
11409 + cfi_free_ep_bs_dyn_data(cfiep);
11414 + * This function frees the dynamically allocated EP buffer setup data.
11416 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep)
11418 + if (cfiep->bm_sg) {
11419 + dwc_free(cfiep->bm_sg);
11420 + cfiep->bm_sg = NULL;
11423 + if (cfiep->bm_align) {
11424 + dwc_free(cfiep->bm_align);
11425 + cfiep->bm_align = NULL;
11428 + if (cfiep->bm_concat) {
11429 + if (NULL != cfiep->bm_concat->wTxBytes) {
11430 + dwc_free(cfiep->bm_concat->wTxBytes);
11431 + cfiep->bm_concat->wTxBytes = NULL;
11433 + dwc_free(cfiep->bm_concat);
11434 + cfiep->bm_concat = NULL;
11439 + * This function initializes the default values of the features
11440 + * for a specific endpoint and should be called only once when
11441 + * the EP is enabled first time.
11443 +static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep)
11447 + cfiep->bm_sg = dwc_alloc(sizeof(ddma_sg_buffer_setup_t));
11448 + if (NULL == cfiep->bm_sg) {
11449 + CFI_INFO("Failed to allocate memory for SG feature value\n");
11450 + return -DWC_E_NO_MEMORY;
11452 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
11454 + /* For the Concatenation feature's default value we do not allocate
11455 + * memory for the wTxBytes field - it will be done in the set_feature_value
11456 + * request handler.
11458 + cfiep->bm_concat = dwc_alloc(sizeof(ddma_concat_buffer_setup_t));
11459 + if (NULL == cfiep->bm_concat) {
11461 + ("Failed to allocate memory for CONCATENATION feature value\n");
11462 + dwc_free(cfiep->bm_sg);
11463 + return -DWC_E_NO_MEMORY;
11465 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
11467 + cfiep->bm_align = dwc_alloc(sizeof(ddma_align_buffer_setup_t));
11468 + if (NULL == cfiep->bm_align) {
11470 + ("Failed to allocate memory for Alignment feature value\n");
11471 + dwc_free(cfiep->bm_sg);
11472 + dwc_free(cfiep->bm_concat);
11473 + return -DWC_E_NO_MEMORY;
11475 + dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t));
11481 + * The callback function that notifies the CFI on the activation of
11482 + * an endpoint in the PCD. The following steps are done in this function:
11484 + * Create a dynamically allocated cfi_ep_t object (a CFI wrapper to the PCD's
11485 + * active endpoint)
11486 + * Create MAX_DMA_DESCS_PER_EP count DMA Descriptors for the EP
11487 + * Set the Buffer Mode to standard
11488 + * Initialize the default values for all EP modes (SG, Circular, Concat, Align)
11489 + * Add the cfi_ep_t object to the list of active endpoints in the CFI object
11491 +static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
11492 + struct dwc_otg_pcd_ep *ep)
11495 + int retval = -DWC_E_NOT_SUPPORTED;
11497 + CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__,
11498 + "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress);
11499 + /* MAS - Check whether this endpoint already is in the list */
11500 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
11502 + if (NULL == cfiep) {
11503 + /* Allocate a cfi_ep_t object */
11504 + cfiep = dwc_alloc(sizeof(cfi_ep_t));
11505 + if (NULL == cfiep) {
11507 + ("Unable to allocate memory for <cfiep> in function %s\n",
11509 + return -DWC_E_NO_MEMORY;
11511 + dwc_memset(cfiep, 0, sizeof(cfi_ep_t));
11513 + /* Save the dwc_otg_pcd_ep pointer in the cfiep object */
11516 + /* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */
11517 + ep->dwc_ep.descs =
11518 + dwc_dma_alloc(MAX_DMA_DESCS_PER_EP *
11519 + sizeof(dwc_otg_dma_desc_t),
11520 + &ep->dwc_ep.descs_dma_addr);
11522 + if (NULL == ep->dwc_ep.descs) {
11524 + return -DWC_E_NO_MEMORY;
11527 + DWC_LIST_INIT(&cfiep->lh);
11529 + /* Set the buffer mode to BM_STANDARD. It will be modified
11530 + * when building descriptors for a specific buffer mode */
11531 + ep->dwc_ep.buff_mode = BM_STANDARD;
11533 + /* Create and initialize the default values for this EP's Buffer modes */
11534 + if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0)
11537 + /* Add the cfi_ep_t object to the CFI object's list of active endpoints */
11538 + DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh);
11540 + } else { /* The sought EP already is in the list */
11541 + CFI_INFO("%s: The sought EP already is in the list\n",
11549 + * This function is called when the data stage of a 3-stage Control Write request
11553 +static int cfi_ctrl_write_complete(struct cfiobject *cfi,
11554 + struct dwc_otg_pcd *pcd)
11556 + uint32_t addr, reg_value;
11557 + uint16_t wIndex, wValue;
11558 + uint8_t bRequest;
11559 + uint8_t *buf = cfi->buf_out.buf;
11560 + //struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved;
11561 + struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req;
11562 + int retval = -DWC_E_NOT_SUPPORTED;
11564 + CFI_INFO("%s\n", __func__);
11566 + bRequest = ctrl_req->bRequest;
11567 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
11568 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
11571 + * Save the pointer to the data stage in the ctrl_req's <data> field.
11572 + * The request should be already saved in the command stage by now.
11574 + ctrl_req->data = cfi->buf_out.buf;
11575 + cfi->need_status_in_complete = 0;
11576 + cfi->need_gadget_att = 0;
11578 + switch (bRequest) {
11579 + case VEN_CORE_WRITE_REGISTER:
11580 + /* The buffer contains raw data of the new value for the register */
11581 + reg_value = *((uint32_t *) buf);
11582 + if (wValue == 0) {
11584 + //addr = (uint32_t) pcd->otg_dev->base;
11587 + addr = (wValue << 16) | wIndex;
11590 + //writel(reg_value, addr);
11593 + cfi->need_status_in_complete = 1;
11596 + case VEN_CORE_SET_FEATURE:
11597 + /* The buffer contains raw data of the new value of the feature */
11598 + retval = cfi_set_feature_value(pcd);
11602 + cfi->need_status_in_complete = 1;
11613 + * This function builds the DMA descriptors for the SG buffer mode.
11615 +static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
11616 + dwc_otg_pcd_request_t * req)
11618 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
11619 + ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg;
11620 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
11621 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
11622 + dma_addr_t buff_addr = req->dma;
11624 + uint32_t txsize, off;
11626 + txsize = sgval->wSize;
11627 + off = sgval->bOffset;
11629 +// CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n",
11630 +// __func__, cfiep->ep->ep.name, txsize, off);
11632 + for (i = 0; i < sgval->bCount; i++) {
11633 + desc->status.b.bs = BS_HOST_BUSY;
11634 + desc->buf = buff_addr;
11635 + desc->status.b.l = 0;
11636 + desc->status.b.ioc = 0;
11637 + desc->status.b.sp = 0;
11638 + desc->status.b.bytes = txsize;
11639 + desc->status.b.bs = BS_HOST_READY;
11641 + /* Set the next address of the buffer */
11642 + buff_addr += txsize + off;
11643 + desc_last = desc;
11647 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
11648 + desc_last->status.b.l = 1;
11649 + desc_last->status.b.ioc = 1;
11650 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
11651 + /* Save the last DMA descriptor pointer */
11652 + cfiep->dma_desc_last = desc_last;
11653 + cfiep->desc_count = sgval->bCount;
11657 + * This function builds the DMA descriptors for the Concatenation buffer mode.
11659 +static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
11660 + dwc_otg_pcd_request_t * req)
11662 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
11663 + ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat;
11664 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
11665 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
11666 + dma_addr_t buff_addr = req->dma;
11668 + uint16_t *txsize;
11670 + txsize = concatval->wTxBytes;
11672 + for (i = 0; i < concatval->hdr.bDescCount; i++) {
11673 + desc->buf = buff_addr;
11674 + desc->status.b.bs = BS_HOST_BUSY;
11675 + desc->status.b.l = 0;
11676 + desc->status.b.ioc = 0;
11677 + desc->status.b.sp = 0;
11678 + desc->status.b.bytes = *txsize;
11679 + desc->status.b.bs = BS_HOST_READY;
11682 + /* Set the next address of the buffer */
11683 + buff_addr += UGETW(ep->desc->wMaxPacketSize);
11684 + desc_last = desc;
11688 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
11689 + desc_last->status.b.l = 1;
11690 + desc_last->status.b.ioc = 1;
11691 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
11692 + cfiep->dma_desc_last = desc_last;
11693 + cfiep->desc_count = concatval->hdr.bDescCount;
11697 + * This function builds the DMA descriptors for the Circular buffer mode
11699 +static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
11700 + dwc_otg_pcd_request_t * req)
11702 + /* @todo: MAS - add implementation when this feature needs to be tested */
11706 + * This function builds the DMA descriptors for the Alignment buffer mode
11708 +static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
11709 + dwc_otg_pcd_request_t * req)
11711 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
11712 + ddma_align_buffer_setup_t *alignval = cfiep->bm_align;
11713 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
11714 + dma_addr_t buff_addr = req->dma;
11716 + desc->status.b.bs = BS_HOST_BUSY;
11717 + desc->status.b.l = 1;
11718 + desc->status.b.ioc = 1;
11719 + desc->status.b.sp = ep->dwc_ep.sent_zlp;
11720 + desc->status.b.bytes = req->length;
11721 + /* Adjust the buffer alignment */
11722 + desc->buf = (buff_addr + alignval->bAlign);
11723 + desc->status.b.bs = BS_HOST_READY;
11724 + cfiep->dma_desc_last = desc;
11725 + cfiep->desc_count = 1;
11729 + * This function builds the DMA descriptors chain for different modes of the
11730 + * buffer setup of an endpoint.
11732 +static void cfi_build_descriptors(struct cfiobject *cfi,
11733 + struct dwc_otg_pcd *pcd,
11734 + struct dwc_otg_pcd_ep *ep,
11735 + dwc_otg_pcd_request_t * req)
11739 + /* Get the cfiep by the dwc_otg_pcd_ep */
11740 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
11741 + if (NULL == cfiep) {
11742 + CFI_INFO("%s: Unable to find a matching active endpoint\n",
11747 + cfiep->xfer_len = req->length;
11749 + /* Iterate through all the DMA descriptors */
11750 + switch (cfiep->ep->dwc_ep.buff_mode) {
11752 + cfi_build_sg_descs(cfi, cfiep, req);
11756 + cfi_build_concat_descs(cfi, cfiep, req);
11759 + case BM_CIRCULAR:
11760 + cfi_build_circ_descs(cfi, cfiep, req);
11764 + cfi_build_align_descs(cfi, cfiep, req);
11773 + * Allocate DMA buffer for different Buffer modes.
11775 +static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
11776 + struct dwc_otg_pcd_ep *ep, dma_addr_t * dma,
11777 + unsigned size, gfp_t flags)
11779 + return dwc_dma_alloc(size, dma);
11783 + * This function initializes the CFI object.
11785 +int init_cfi(cfiobject_t * cfiobj)
11787 + CFI_INFO("%s\n", __func__);
11789 + /* Allocate a buffer for IN XFERs */
11790 + cfiobj->buf_in.buf =
11791 + dwc_dma_alloc(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr);
11792 + if (NULL == cfiobj->buf_in.buf) {
11793 + CFI_INFO("Unable to allocate buffer for INs\n");
11794 + return -DWC_E_NO_MEMORY;
11797 + /* Allocate a buffer for OUT XFERs */
11798 + cfiobj->buf_out.buf =
11799 + dwc_dma_alloc(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr);
11800 + if (NULL == cfiobj->buf_out.buf) {
11801 + CFI_INFO("Unable to allocate buffer for OUT\n");
11802 + return -DWC_E_NO_MEMORY;
11805 + /* Initialize the callback function pointers */
11806 + cfiobj->ops.release = cfi_release;
11807 + cfiobj->ops.ep_enable = cfi_ep_enable;
11808 + cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete;
11809 + cfiobj->ops.build_descriptors = cfi_build_descriptors;
11810 + cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf;
11812 + /* Initialize the list of active endpoints in the CFI object */
11813 + DWC_LIST_INIT(&cfiobj->active_eps);
11819 + * This function reads the required feature's current value into the buffer
11821 + * @retval: Returns negative as error, or the data length of the feature
11823 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
11824 + struct dwc_otg_pcd *pcd,
11825 + struct cfi_usb_ctrlrequest *ctrl_req)
11827 + int retval = -DWC_E_NOT_SUPPORTED;
11828 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
11829 + uint16_t dfifo, rxfifo, txfifo;
11831 + switch (ctrl_req->wIndex) {
11832 + /* Whether the DDMA is enabled or not */
11833 + case FT_ID_DMA_MODE:
11834 + *buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0;
11838 + case FT_ID_DMA_BUFFER_SETUP:
11839 + retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req);
11842 + case FT_ID_DMA_BUFF_ALIGN:
11843 + retval = cfi_ep_get_align_val(buf, pcd, ctrl_req);
11846 + case FT_ID_DMA_CONCAT_SETUP:
11847 + retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req);
11850 + case FT_ID_DMA_CIRCULAR:
11851 + CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n");
11854 + case FT_ID_THRESHOLD_SETUP:
11855 + CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n");
11858 + case FT_ID_DFIFO_DEPTH:
11859 + dfifo = get_dfifo_size(coreif);
11860 + *((uint16_t *) buf) = dfifo;
11861 + retval = sizeof(uint16_t);
11864 + case FT_ID_TX_FIFO_DEPTH:
11865 + retval = get_txfifo_size(pcd, ctrl_req->wValue);
11866 + if (retval >= 0) {
11868 + *((uint16_t *) buf) = txfifo;
11869 + retval = sizeof(uint16_t);
11873 + case FT_ID_RX_FIFO_DEPTH:
11874 + retval = get_rxfifo_size(coreif, ctrl_req->wValue);
11875 + if (retval >= 0) {
11877 + *((uint16_t *) buf) = rxfifo;
11878 + retval = sizeof(uint16_t);
11887 + * This function resets the SG for the specified EP to its default value
11889 +static int cfi_reset_sg_val(cfi_ep_t * cfiep)
11891 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
11896 + * This function resets the Alignment for the specified EP to its default value
11898 +static int cfi_reset_align_val(cfi_ep_t * cfiep)
11900 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
11905 + * This function resets the Concatenation for the specified EP to its default value
11906 + * This function will also set the value of the wTxBytes field to NULL after
11907 + * freeing the memory previously allocated for this field.
11909 +static int cfi_reset_concat_val(cfi_ep_t * cfiep)
11911 + /* First we need to free the wTxBytes field */
11912 + if (cfiep->bm_concat->wTxBytes) {
11913 + dwc_free(cfiep->bm_concat->wTxBytes);
11914 + cfiep->bm_concat->wTxBytes = NULL;
11917 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
11922 + * This function resets all the buffer setups of the specified endpoint
11924 +static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep)
11926 + cfi_reset_sg_val(cfiep);
11927 + cfi_reset_align_val(cfiep);
11928 + cfi_reset_concat_val(cfiep);
11932 +static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr,
11933 + uint8_t rx_rst, uint8_t tx_rst)
11935 + int retval = -DWC_E_INVALID;
11936 + uint16_t tx_siz[15];
11937 + uint16_t rx_siz = 0;
11938 + dwc_otg_pcd_ep_t *ep = NULL;
11939 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
11940 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
11943 + rx_siz = params->dev_rx_fifo_size;
11944 + params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz;
11948 + if (ep_addr == 0) {
11951 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
11953 + core_if->core_params->dev_tx_fifo_size[i];
11954 + core_if->core_params->dev_tx_fifo_size[i] =
11955 + core_if->init_txfsiz[i];
11959 + ep = get_ep_by_addr(pcd, ep_addr);
11961 + if (NULL == ep) {
11963 + ("%s: Unable to get the endpoint addr=0x%02x\n",
11964 + __func__, ep_addr);
11965 + return -DWC_E_INVALID;
11969 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num -
11971 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] =
11972 + GET_CORE_IF(pcd)->init_txfsiz[ep->dwc_ep.
11973 + tx_fifo_num - 1];
11977 + if (resize_fifos(GET_CORE_IF(pcd))) {
11981 + ("%s: Error resetting the feature Reset All(FIFO size)\n",
11984 + params->dev_rx_fifo_size = rx_siz;
11988 + if (ep_addr == 0) {
11990 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps;
11992 + core_if->core_params->
11993 + dev_tx_fifo_size[i] = tx_siz[i];
11996 + params->dev_tx_fifo_size[ep->dwc_ep.
11997 + tx_fifo_num - 1] =
12001 + retval = -DWC_E_INVALID;
12006 +static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr)
12010 + cfiobject_t *cfi = pcd->cfi;
12011 + dwc_list_link_t *tmp;
12013 + retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1);
12014 + if (retval < 0) {
12018 + /* If the EP address is known then reset the features for only that EP */
12020 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
12021 + if (NULL == cfiep) {
12022 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
12024 + return -DWC_E_INVALID;
12026 + retval = cfi_ep_reset_all_setup_vals(cfiep);
12027 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
12029 + /* Otherwise (wValue == 0), reset all features of all EP's */
12031 + /* Traverse all the active EP's and reset the feature(s) value(s) */
12032 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
12033 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
12034 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
12035 + retval = cfi_ep_reset_all_setup_vals(cfiep);
12036 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
12037 + if (retval < 0) {
12039 + ("%s: Error resetting the feature Reset All\n",
12048 +static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd,
12053 + cfiobject_t *cfi = pcd->cfi;
12054 + dwc_list_link_t *tmp;
12056 + /* If the EP address is known then reset the features for only that EP */
12058 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
12059 + if (NULL == cfiep) {
12060 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
12062 + return -DWC_E_INVALID;
12064 + retval = cfi_reset_sg_val(cfiep);
12066 + /* Otherwise (wValue == 0), reset all features of all EP's */
12068 + /* Traverse all the active EP's and reset the feature(s) value(s) */
12069 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
12070 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
12071 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
12072 + retval = cfi_reset_sg_val(cfiep);
12073 + if (retval < 0) {
12075 + ("%s: Error resetting the feature Buffer Setup\n",
12084 +static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr)
12088 + cfiobject_t *cfi = pcd->cfi;
12089 + dwc_list_link_t *tmp;
12091 + /* If the EP address is known then reset the features for only that EP */
12093 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
12094 + if (NULL == cfiep) {
12095 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
12097 + return -DWC_E_INVALID;
12099 + retval = cfi_reset_concat_val(cfiep);
12101 + /* Otherwise (wValue == 0), reset all features of all EP's */
12103 + /* Traverse all the active EP's and reset the feature(s) value(s) */
12104 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
12105 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
12106 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
12107 + retval = cfi_reset_concat_val(cfiep);
12108 + if (retval < 0) {
12110 + ("%s: Error resetting the feature Concatenation Value\n",
12119 +static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr)
12123 + cfiobject_t *cfi = pcd->cfi;
12124 + dwc_list_link_t *tmp;
12126 + /* If the EP address is known then reset the features for only that EP */
12128 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
12129 + if (NULL == cfiep) {
12130 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
12132 + return -DWC_E_INVALID;
12134 + retval = cfi_reset_align_val(cfiep);
12136 + /* Otherwise (wValue == 0), reset all features of all EP's */
12138 + /* Traverse all the active EP's and reset the feature(s) value(s) */
12139 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
12140 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
12141 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
12142 + retval = cfi_reset_align_val(cfiep);
12143 + if (retval < 0) {
12145 + ("%s: Error resetting the feature Aliignment Value\n",
12155 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
12156 + struct cfi_usb_ctrlrequest *req)
12160 + switch (req->wIndex) {
12162 + /* Reset all features */
12163 + retval = cfi_handle_reset_all(pcd, req->wValue & 0xff);
12166 + case FT_ID_DMA_BUFFER_SETUP:
12167 + /* Reset the SG buffer setup */
12169 + cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff);
12172 + case FT_ID_DMA_CONCAT_SETUP:
12173 + /* Reset the Concatenation buffer setup */
12174 + retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff);
12177 + case FT_ID_DMA_BUFF_ALIGN:
12178 + /* Reset the Alignment buffer setup */
12179 + retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff);
12182 + case FT_ID_TX_FIFO_DEPTH:
12184 + cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1);
12185 + pcd->cfi->need_gadget_att = 0;
12188 + case FT_ID_RX_FIFO_DEPTH:
12189 + retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0);
12190 + pcd->cfi->need_gadget_att = 0;
12199 + * This function sets a new value for the SG buffer setup.
12201 +static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
12203 + uint8_t inaddr, outaddr;
12204 + cfi_ep_t *epin, *epout;
12205 + ddma_sg_buffer_setup_t *psgval;
12206 + uint32_t desccount, size;
12208 + CFI_INFO("%s\n", __func__);
12210 + psgval = (ddma_sg_buffer_setup_t *) buf;
12211 + desccount = (uint32_t) psgval->bCount;
12212 + size = (uint32_t) psgval->wSize;
12214 + /* Check the DMA descriptor count */
12215 + if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) {
12217 + ("%s: The count of DMA Descriptors should be between 1 and %d\n",
12218 + __func__, MAX_DMA_DESCS_PER_EP);
12219 + return -DWC_E_INVALID;
12222 + /* Check the DMA descriptor count */
12226 + CFI_INFO("%s: The transfer size should be at least 1 byte\n",
12229 + return -DWC_E_INVALID;
12233 + inaddr = psgval->bInEndpointAddress;
12234 + outaddr = psgval->bOutEndpointAddress;
12236 + epin = get_cfi_ep_by_addr(pcd->cfi, inaddr);
12237 + epout = get_cfi_ep_by_addr(pcd->cfi, outaddr);
12239 + if (NULL == epin || NULL == epout) {
12241 + ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n",
12242 + __func__, inaddr, outaddr);
12243 + return -DWC_E_INVALID;
12246 + epin->ep->dwc_ep.buff_mode = BM_SG;
12247 + dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
12249 + epout->ep->dwc_ep.buff_mode = BM_SG;
12250 + dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
12256 + * This function sets a new value for the buffer Alignment setup.
12258 +static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
12262 + ddma_align_buffer_setup_t *palignval;
12264 + palignval = (ddma_align_buffer_setup_t *) buf;
12265 + addr = palignval->bEndpointAddress;
12267 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
12269 + if (NULL == ep) {
12270 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
12272 + return -DWC_E_INVALID;
12275 + ep->ep->dwc_ep.buff_mode = BM_ALIGN;
12276 + dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t));
12282 + * This function sets a new value for the Concatenation buffer setup.
12284 +static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
12288 + struct _ddma_concat_buffer_setup_hdr *pConcatValHdr;
12290 + uint32_t desccount;
12294 + pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf;
12295 + desccount = (uint32_t) pConcatValHdr->bDescCount;
12296 + pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN);
12298 + /* Check the DMA descriptor count */
12299 + if (desccount > MAX_DMA_DESCS_PER_EP) {
12300 + CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n",
12301 + __func__, MAX_DMA_DESCS_PER_EP);
12302 + return -DWC_E_INVALID;
12305 + addr = pConcatValHdr->bEndpointAddress;
12306 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
12307 + if (NULL == ep) {
12308 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
12310 + return -DWC_E_INVALID;
12313 + mps = UGETW(ep->ep->desc->wMaxPacketSize);
12316 + for (i = 0; i < desccount; i++) {
12317 + CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]);
12319 + CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps);
12322 + /* Check the wTxSizes to be less than or equal to the mps */
12323 + for (i = 0; i < desccount; i++) {
12324 + if (pVals[i] > mps) {
12326 + ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n",
12327 + __func__, i, pVals[i]);
12328 + return -DWC_E_INVALID;
12332 + ep->ep->dwc_ep.buff_mode = BM_CONCAT;
12333 + dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN);
12335 + /* Free the previously allocated storage for the wTxBytes */
12336 + if (ep->bm_concat->wTxBytes) {
12337 + dwc_free(ep->bm_concat->wTxBytes);
12340 + /* Allocate a new storage for the wTxBytes field */
12341 + ep->bm_concat->wTxBytes =
12342 + dwc_alloc(sizeof(uint16_t) * pConcatValHdr->bDescCount);
12343 + if (NULL == ep->bm_concat->wTxBytes) {
12344 + CFI_INFO("%s: Unable to allocate memory\n", __func__);
12345 + return -DWC_E_NO_MEMORY;
12348 + /* Copy the new values into the wTxBytes filed */
12349 + dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN,
12350 + sizeof(uint16_t) * pConcatValHdr->bDescCount);
12356 + * This function calculates the total of all FIFO sizes
12358 + * @param core_if Programming view of DWC_otg controller
12360 + * @return The total of data FIFO sizes.
12363 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if)
12365 + dwc_otg_core_params_t *params = core_if->core_params;
12366 + uint16_t dfifo_total = 0;
12369 + /* The shared RxFIFO size */
12371 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
12373 + /* Add up each TxFIFO size to the total */
12374 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
12375 + dfifo_total += params->dev_tx_fifo_size[i];
12378 + return dfifo_total;
12382 + * This function returns Rx FIFO size
12384 + * @param core_if Programming view of DWC_otg controller
12386 + * @return The total of data FIFO sizes.
12389 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue)
12391 + switch (wValue >> 8) {
12393 + return (core_if->pwron_rxfsiz <
12394 + 32768) ? core_if->pwron_rxfsiz : 32768;
12397 + return core_if->core_params->dev_rx_fifo_size;
12400 + return -DWC_E_INVALID;
12406 + * This function returns Tx FIFO size for IN EP
12408 + * @param core_if Programming view of DWC_otg controller
12410 + * @return The total of data FIFO sizes.
12413 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue)
12415 + dwc_otg_pcd_ep_t *ep;
12417 + ep = get_ep_by_addr(pcd, wValue & 0xff);
12419 + if (NULL == ep) {
12420 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
12421 + __func__, wValue & 0xff);
12422 + return -DWC_E_INVALID;
12425 + if (!ep->dwc_ep.is_in) {
12427 + ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n",
12428 + __func__, wValue & 0xff);
12429 + return -DWC_E_INVALID;
12432 + switch (wValue >> 8) {
12434 + return (GET_CORE_IF(pcd)->
12435 + pwron_txfsiz[ep->dwc_ep.tx_fifo_num - 1] <
12436 + 768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->dwc_ep.
12441 + return GET_CORE_IF(pcd)->core_params->dev_tx_fifo_size[ep->
12446 + return -DWC_E_INVALID;
12452 + * This function checks if the submitted combination of
12453 + * device mode FIFO sizes is possible or not.
12455 + * @param core_if Programming view of DWC_otg controller
12457 + * @return 1 if possible, 0 otherwise.
12460 +static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if)
12462 + uint16_t dfifo_actual = 0;
12463 + dwc_otg_core_params_t *params = core_if->core_params;
12464 + uint16_t start_addr = 0;
12468 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
12470 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
12471 + dfifo_actual += params->dev_tx_fifo_size[i];
12474 + if (dfifo_actual > core_if->total_fifo_size) {
12478 + if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16)
12481 + if (params->dev_nperio_tx_fifo_size > 32768
12482 + || params->dev_nperio_tx_fifo_size < 16)
12485 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
12487 + if (params->dev_tx_fifo_size[i] > 768
12488 + || params->dev_tx_fifo_size[i] < 4)
12492 + if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz)
12494 + start_addr = params->dev_rx_fifo_size;
12496 + if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz)
12498 + start_addr += params->dev_nperio_tx_fifo_size;
12500 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
12502 + if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i])
12504 + start_addr += params->dev_tx_fifo_size[i];
12511 + * This function resizes Device mode FIFOs
12513 + * @param core_if Programming view of DWC_otg controller
12515 + * @return 1 if successful, 0 otherwise
12518 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if)
12521 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
12522 + dwc_otg_core_params_t *params = core_if->core_params;
12523 + uint32_t rx_fifo_size;
12524 + fifosize_data_t nptxfifosize;
12525 + fifosize_data_t txfifosize[15];
12527 + uint32_t rx_fsz_bak;
12528 + uint32_t nptxfsz_bak;
12529 + uint32_t txfsz_bak[15];
12531 + uint16_t start_address;
12532 + uint8_t retval = 1;
12534 + if (!check_fifo_sizes(core_if)) {
12538 + /* Configure data FIFO sizes */
12539 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
12540 + rx_fsz_bak = dwc_read_reg32(&global_regs->grxfsiz);
12541 + rx_fifo_size = params->dev_rx_fifo_size;
12542 + dwc_write_reg32(&global_regs->grxfsiz, rx_fifo_size);
12545 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
12546 + * Indexes of the FIFO size module parameters in the
12547 + * dev_tx_fifo_size array and the FIFO size registers in
12548 + * the dptxfsiz_dieptxf array run from 0 to 14.
12551 + /* Non-periodic Tx FIFO */
12552 + nptxfsz_bak = dwc_read_reg32(&global_regs->gnptxfsiz);
12553 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
12554 + start_address = params->dev_rx_fifo_size;
12555 + nptxfifosize.b.startaddr = start_address;
12557 + dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32);
12559 + start_address += nptxfifosize.b.depth;
12561 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
12563 + dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]);
12565 + txfifosize[i].b.depth = params->dev_tx_fifo_size[i];
12566 + txfifosize[i].b.startaddr = start_address;
12567 + dwc_write_reg32(&global_regs->dptxfsiz_dieptxf[i],
12568 + txfifosize[i].d32);
12570 + start_address += txfifosize[i].b.depth;
12573 + /** Check if register values are set correctly */
12574 + if (rx_fifo_size != dwc_read_reg32(&global_regs->grxfsiz)) {
12578 + if (nptxfifosize.d32 != dwc_read_reg32(&global_regs->gnptxfsiz)) {
12582 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
12583 + if (txfifosize[i].d32 !=
12584 + dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])) {
12589 + /** If register values are not set correctly, reset old values */
12590 + if (retval == 0) {
12591 + dwc_write_reg32(&global_regs->grxfsiz, rx_fsz_bak);
12593 + /* Non-periodic Tx FIFO */
12594 + dwc_write_reg32(&global_regs->gnptxfsiz, nptxfsz_bak);
12596 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
12597 + dwc_write_reg32(&global_regs->
12598 + dptxfsiz_dieptxf[i],
12606 + /* Flush the FIFOs */
12607 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
12608 + dwc_otg_flush_rx_fifo(core_if);
12614 + * This function sets a new value for the buffer Alignment setup.
12616 +static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
12621 + uint16_t ep_addr;
12622 + dwc_otg_pcd_ep_t *ep;
12623 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
12624 + tx_fifo_size_setup_t *ptxfifoval;
12626 + ptxfifoval = (tx_fifo_size_setup_t *) buf;
12627 + ep_addr = ptxfifoval->bEndpointAddress;
12628 + size = ptxfifoval->wDepth;
12630 + ep = get_ep_by_addr(pcd, ep_addr);
12633 + ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n",
12634 + __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num);
12636 + if (NULL == ep) {
12637 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
12638 + __func__, ep_addr);
12639 + return -DWC_E_INVALID;
12642 + fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1];
12643 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size;
12645 + if (resize_fifos(GET_CORE_IF(pcd))) {
12649 + ("%s: Error setting the feature Tx FIFO Size for EP%d\n",
12650 + __func__, ep_addr);
12651 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz;
12652 + retval = -DWC_E_INVALID;
12659 + * This function sets a new value for the buffer Alignment setup.
12661 +static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
12666 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
12667 + rx_fifo_size_setup_t *prxfifoval;
12669 + prxfifoval = (rx_fifo_size_setup_t *) buf;
12670 + size = prxfifoval->wDepth;
12672 + fsiz = params->dev_rx_fifo_size;
12673 + params->dev_rx_fifo_size = size;
12675 + if (resize_fifos(GET_CORE_IF(pcd))) {
12678 + CFI_INFO("%s: Error setting the feature Rx FIFO Size\n",
12680 + params->dev_rx_fifo_size = fsiz;
12681 + retval = -DWC_E_INVALID;
12688 + * This function reads the SG of an EP's buffer setup into the buffer buf
12690 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
12691 + struct cfi_usb_ctrlrequest *req)
12693 + int retval = -DWC_E_INVALID;
12697 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
12698 + addr = req->wValue & 0xFF;
12699 + if (addr == 0) /* The address should be non-zero */
12702 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
12703 + if (NULL == ep) {
12704 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
12709 + dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN);
12710 + retval = BS_SG_VAL_DESC_LEN;
12715 + * This function reads the Concatenation value of an EP's buffer mode into
12718 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
12719 + struct cfi_usb_ctrlrequest *req)
12721 + int retval = -DWC_E_INVALID;
12724 + uint8_t desc_count;
12726 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
12727 + addr = req->wValue & 0xFF;
12728 + if (addr == 0) /* The address should be non-zero */
12731 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
12732 + if (NULL == ep) {
12733 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
12738 + /* Copy the header to the buffer */
12739 + dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN);
12740 + /* Advance the buffer pointer by the header size */
12741 + buf += BS_CONCAT_VAL_HDR_LEN;
12743 + desc_count = ep->bm_concat->hdr.bDescCount;
12744 + /* Copy alll the wTxBytes to the buffer */
12745 + dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count);
12747 + retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count;
12752 + * This function reads the buffer Alignment value of an EP's buffer mode into
12755 + * @return The total number of bytes copied to the buffer or negative error code.
12757 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
12758 + struct cfi_usb_ctrlrequest *req)
12760 + int retval = -DWC_E_INVALID;
12764 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
12765 + addr = req->wValue & 0xFF;
12766 + if (addr == 0) /* The address should be non-zero */
12769 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
12770 + if (NULL == ep) {
12771 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
12776 + dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN);
12777 + retval = BS_ALIGN_VAL_HDR_LEN;
12783 + * This function sets a new value for the specified feature
12785 + * @param pcd A pointer to the PCD object
12787 + * @return 0 if successful, negative error code otherwise to stall the DCE.
12789 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd)
12791 + int retval = -DWC_E_NOT_SUPPORTED;
12792 + uint16_t wIndex, wValue;
12793 + uint8_t bRequest;
12794 + struct dwc_otg_core_if *coreif;
12795 + cfiobject_t *cfi = pcd->cfi;
12796 + struct cfi_usb_ctrlrequest *ctrl_req;
12798 + ctrl_req = &cfi->ctrl_req;
12800 + buf = pcd->cfi->ctrl_req.data;
12802 + coreif = GET_CORE_IF(pcd);
12803 + bRequest = ctrl_req->bRequest;
12804 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
12805 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
12807 + /* See which feature is to be modified */
12808 + switch (wIndex) {
12809 + case FT_ID_DMA_BUFFER_SETUP:
12810 + /* Modify the feature */
12811 + if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0)
12814 + /* And send this request to the gadget */
12815 + cfi->need_gadget_att = 1;
12818 + case FT_ID_DMA_BUFF_ALIGN:
12819 + if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0)
12821 + cfi->need_gadget_att = 1;
12824 + case FT_ID_DMA_CONCAT_SETUP:
12825 + /* Modify the feature */
12826 + if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0)
12828 + cfi->need_gadget_att = 1;
12831 + case FT_ID_DMA_CIRCULAR:
12832 + CFI_INFO("FT_ID_DMA_CIRCULAR\n");
12835 + case FT_ID_THRESHOLD_SETUP:
12836 + CFI_INFO("FT_ID_THRESHOLD_SETUP\n");
12839 + case FT_ID_DFIFO_DEPTH:
12840 + CFI_INFO("FT_ID_DFIFO_DEPTH\n");
12843 + case FT_ID_TX_FIFO_DEPTH:
12844 + CFI_INFO("FT_ID_TX_FIFO_DEPTH\n");
12845 + if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0)
12847 + cfi->need_gadget_att = 0;
12850 + case FT_ID_RX_FIFO_DEPTH:
12851 + CFI_INFO("FT_ID_RX_FIFO_DEPTH\n");
12852 + if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0)
12854 + cfi->need_gadget_att = 0;
12861 +#endif //DWC_UTE_CFI
12863 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h
12865 +/* ==========================================================================
12866 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
12867 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
12868 + * otherwise expressly agreed to in writing between Synopsys and you.
12870 + * The Software IS NOT an item of Licensed Software or Licensed Product under
12871 + * any End User Software License Agreement or Agreement for Licensed Product
12872 + * with Synopsys or any supplement thereto. You are permitted to use and
12873 + * redistribute this Software in source and binary forms, with or without
12874 + * modification, provided that redistributions of source code must retain this
12875 + * notice. You may not view, use, disclose, copy or distribute this file or
12876 + * any information contained herein except pursuant to this license grant from
12877 + * Synopsys. If you do not agree with this notice, including the disclaimer
12878 + * below, then you are not authorized to use the Software.
12880 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
12881 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12882 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12883 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
12884 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
12885 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
12886 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
12887 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12888 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12889 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
12891 + * ========================================================================== */
12893 +#if !defined(__DWC_OTG_CFI_H__)
12894 +#define __DWC_OTG_CFI_H__
12896 +#include "dwc_otg_pcd.h"
12897 +#include "dwc_cfi_common.h"
12902 + * This file contains the CFI related OTG PCD specific common constants, interfaces
12903 + * (functions and macros) and data structures.
12907 +struct dwc_otg_pcd;
12908 +struct dwc_otg_pcd_ep;
12910 +/** OTG CFI Features (properties) ID constants */
12911 +/** This is a request for all Core Features */
12912 +#define FT_ID_DMA_MODE 0x0001
12913 +#define FT_ID_DMA_BUFFER_SETUP 0x0002
12914 +#define FT_ID_DMA_BUFF_ALIGN 0x0003
12915 +#define FT_ID_DMA_CONCAT_SETUP 0x0004
12916 +#define FT_ID_DMA_CIRCULAR 0x0005
12917 +#define FT_ID_THRESHOLD_SETUP 0x0006
12918 +#define FT_ID_DFIFO_DEPTH 0x0007
12919 +#define FT_ID_TX_FIFO_DEPTH 0x0008
12920 +#define FT_ID_RX_FIFO_DEPTH 0x0009
12922 +/**********************************************************/
12923 +#define CFI_INFO_DEF
12925 +#ifdef CFI_INFO_DEF
12926 +#define CFI_INFO(fmt...) DWC_PRINTF("CFI: " fmt);
12928 +#define CFI_INFO(fmt...)
12931 +#define min(x,y) ({ \
12932 + x < y ? x : y; })
12934 +#define max(x,y) ({ \
12935 + x > y ? x : y; })
12938 + * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is
12939 + * also used for setting up a buffer for Circular DDMA.
12941 +struct _ddma_sg_buffer_setup {
12942 +#define BS_SG_VAL_DESC_LEN 6
12943 + /* The OUT EP address */
12944 + uint8_t bOutEndpointAddress;
12945 + /* The IN EP address */
12946 + uint8_t bInEndpointAddress;
12947 + /* Number of bytes to put between transfer segments (must be DWORD boundaries) */
12949 + /* The number of transfer segments (a DMA descriptors per each segment) */
12951 + /* Size (in byte) of each transfer segment */
12953 +} __attribute__ ((packed));
12954 +typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
12956 +/** Descriptor DMA Concatenation Buffer setup structure */
12957 +struct _ddma_concat_buffer_setup_hdr {
12958 +#define BS_CONCAT_VAL_HDR_LEN 4
12959 + /* The endpoint for which the buffer is to be set up */
12960 + uint8_t bEndpointAddress;
12961 + /* The count of descriptors to be used */
12962 + uint8_t bDescCount;
12963 + /* The total size of the transfer */
12965 +} __attribute__ ((packed));
12966 +typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
12968 +/** Descriptor DMA Concatenation Buffer setup structure */
12969 +struct _ddma_concat_buffer_setup {
12970 + /* The SG header */
12971 + ddma_concat_buffer_setup_hdr_t hdr;
12973 + /* The XFER sizes pointer (allocated dynamically) */
12974 + uint16_t *wTxBytes;
12975 +} __attribute__ ((packed));
12976 +typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
12978 +/** Descriptor DMA Alignment Buffer setup structure */
12979 +struct _ddma_align_buffer_setup {
12980 +#define BS_ALIGN_VAL_HDR_LEN 2
12981 + uint8_t bEndpointAddress;
12983 +} __attribute__ ((packed));
12984 +typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
12986 +/** Transmit FIFO Size setup structure */
12987 +struct _tx_fifo_size_setup {
12988 + uint8_t bEndpointAddress;
12990 +} __attribute__ ((packed));
12991 +typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
12993 +/** Transmit FIFO Size setup structure */
12994 +struct _rx_fifo_size_setup {
12996 +} __attribute__ ((packed));
12997 +typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
13000 + * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest
13001 + * This structure encapsulates the standard usb_ctrlrequest and adds a pointer
13002 + * to the data returned in the data stage of a 3-stage Control Write requests.
13004 +struct cfi_usb_ctrlrequest {
13005 + uint8_t bRequestType;
13006 + uint8_t bRequest;
13009 + uint16_t wLength;
13013 +/*---------------------------------------------------------------------------*/
13016 + * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures.
13017 + * This structure is used to store the buffer setup data for any
13018 + * enabled endpoint in the PCD.
13021 + /* Entry for the list container */
13022 + dwc_list_link_t lh;
13023 + /* Pointer to the active PCD endpoint structure */
13024 + struct dwc_otg_pcd_ep *ep;
13025 + /* The last descriptor in the chain of DMA descriptors of the endpoint */
13026 + struct dwc_otg_dma_desc *dma_desc_last;
13027 + /* The SG feature value */
13028 + ddma_sg_buffer_setup_t *bm_sg;
13029 + /* The Circular feature value */
13030 + ddma_sg_buffer_setup_t *bm_circ;
13031 + /* The Concatenation feature value */
13032 + ddma_concat_buffer_setup_t *bm_concat;
13033 + /* The Alignment feature value */
13034 + ddma_align_buffer_setup_t *bm_align;
13035 + /* XFER length */
13036 + uint32_t xfer_len;
13038 + * Count of DMA descriptors currently used.
13039 + * The total should not exceed the MAX_DMA_DESCS_PER_EP value
13040 + * defined in the dwc_otg_cil.h
13042 + uint32_t desc_count;
13044 +typedef struct cfi_ep cfi_ep_t;
13046 +typedef struct cfi_dma_buff {
13047 +#define CFI_IN_BUF_LEN 1024
13048 +#define CFI_OUT_BUF_LEN 1024
13056 + * This is the interface for the CFI operations.
13058 + * @param ep_enable Called when any endpoint is enabled and activated.
13059 + * @param release Called when the CFI object is released and it needs to correctly
13060 + * deallocate the dynamic memory
13061 + * @param ctrl_write_complete Called when the data stage of the request is complete
13063 +typedef struct cfi_ops {
13064 + int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
13065 + struct dwc_otg_pcd_ep * ep);
13066 + void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
13067 + struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
13068 + unsigned size, gfp_t flags);
13069 + void (*release) (struct cfiobject * cfi);
13070 + int (*ctrl_write_complete) (struct cfiobject * cfi,
13071 + struct dwc_otg_pcd * pcd);
13072 + void (*build_descriptors) (struct cfiobject * cfi,
13073 + struct dwc_otg_pcd * pcd,
13074 + struct dwc_otg_pcd_ep * ep,
13075 + dwc_otg_pcd_request_t * req);
13078 +struct cfiobject {
13080 + struct dwc_otg_pcd *pcd;
13081 + struct usb_gadget *gadget;
13083 + /* Buffers used to send/receive CFI-related request data */
13084 + cfi_dma_buff_t buf_in;
13085 + cfi_dma_buff_t buf_out;
13087 + /* CFI specific Control request wrapper */
13088 + struct cfi_usb_ctrlrequest ctrl_req;
13090 + /* The list of active EP's in the PCD of type cfi_ep_t */
13091 + dwc_list_link_t active_eps;
13093 + /* This flag shall control the propagation of a specific request
13094 + * to the gadget's processing routines.
13095 + * 0 - no gadget handling
13096 + * 1 - the gadget needs to know about this request (w/o completing a status
13097 + * phase - just return a 0 to the _setup callback)
13099 + uint8_t need_gadget_att;
13101 + /* Flag indicating whether the status IN phase needs to be
13102 + * completed by the PCD
13104 + uint8_t need_status_in_complete;
13106 +typedef struct cfiobject cfiobject_t;
13110 +#if defined(DUMP_MSG)
13111 +static inline void dump_msg(const u8 * buf, unsigned int length)
13113 + unsigned int start, num, i;
13114 + char line[52], *p;
13116 + if (length >= 512)
13120 + while (length > 0) {
13121 + num = min(length, 16u);
13123 + for (i = 0; i < num; ++i) {
13126 + DWC_SPRINTF(p, " %02x", buf[i]);
13130 + DWC_DEBUG("%6x: %s\n", start, line);
13137 +static inline void dump_msg(const u8 * buf, unsigned int length)
13143 + * This function returns a pointer to cfi_ep_t object with the addr address.
13145 +static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
13148 + struct cfi_ep *pcfiep;
13149 + dwc_list_link_t *tmp;
13151 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
13152 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
13154 + if (pcfiep->ep->desc->bEndpointAddress == addr) {
13163 + * This function returns a pointer to cfi_ep_t object that matches
13164 + * the dwc_otg_pcd_ep object.
13166 +static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
13167 + struct dwc_otg_pcd_ep *ep)
13169 + struct cfi_ep *pcfiep = NULL;
13170 + dwc_list_link_t *tmp;
13172 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
13173 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
13174 + if (pcfiep->ep == ep) {
13181 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
13183 +#endif /* (__DWC_OTG_CFI_H__) */
13185 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
13187 +/* ==========================================================================
13188 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $
13189 + * $Revision: #159 $
13190 + * $Date: 2009/04/21 $
13191 + * $Change: 1237465 $
13193 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
13194 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
13195 + * otherwise expressly agreed to in writing between Synopsys and you.
13197 + * The Software IS NOT an item of Licensed Software or Licensed Product under
13198 + * any End User Software License Agreement or Agreement for Licensed Product
13199 + * with Synopsys or any supplement thereto. You are permitted to use and
13200 + * redistribute this Software in source and binary forms, with or without
13201 + * modification, provided that redistributions of source code must retain this
13202 + * notice. You may not view, use, disclose, copy or distribute this file or
13203 + * any information contained herein except pursuant to this license grant from
13204 + * Synopsys. If you do not agree with this notice, including the disclaimer
13205 + * below, then you are not authorized to use the Software.
13207 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
13208 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13209 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13210 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
13211 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13212 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
13213 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
13214 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13215 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13216 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
13218 + * ========================================================================== */
13222 + * The Core Interface Layer provides basic services for accessing and
13223 + * managing the DWC_otg hardware. These services are used by both the
13224 + * Host Controller Driver and the Peripheral Controller Driver.
13226 + * The CIL manages the memory map for the core so that the HCD and PCD
13227 + * don't have to do this separately. It also handles basic tasks like
13228 + * reading/writing the registers and data FIFOs in the controller.
13229 + * Some of the data access functions provide encapsulation of several
13230 + * operations required to perform a task, such as writing multiple
13231 + * registers to start a transfer. Finally, the CIL performs basic
13232 + * services that are not specific to either the host or device modes
13233 + * of operation. These services include management of the OTG Host
13234 + * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
13235 + * Diagnostic API is also provided to allow testing of the controller
13238 + * The Core Interface Layer has the following requirements:
13239 + * - Provides basic controller operations.
13240 + * - Minimal use of OS services.
13241 + * - The OS services used will be abstracted by using inline functions
13246 +#include "dwc_os.h"
13247 +#include "dwc_otg_regs.h"
13248 +#include "dwc_otg_cil.h"
13250 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if);
13253 + * This function is called to initialize the DWC_otg CSR data
13254 + * structures. The register addresses in the device and host
13255 + * structures are initialized from the base address supplied by the
13256 + * caller. The calling function must make the OS calls to get the
13257 + * base address of the DWC_otg controller registers. The core_params
13258 + * argument holds the parameters that specify how the core should be
13261 + * @param reg_base_addr Base address of DWC_otg core registers
13264 +dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr)
13266 + dwc_otg_core_if_t *core_if = 0;
13267 + dwc_otg_dev_if_t *dev_if = 0;
13268 + dwc_otg_host_if_t *host_if = 0;
13269 + uint8_t *reg_base = (uint8_t *) reg_base_addr;
13272 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr);
13274 + core_if = dwc_alloc(sizeof(dwc_otg_core_if_t));
13276 + if (core_if == 0) {
13277 + DWC_DEBUGPL(DBG_CIL,
13278 + "Allocation of dwc_otg_core_if_t failed\n");
13281 + core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base;
13284 + * Allocate the Device Mode structures.
13286 + dev_if = dwc_alloc(sizeof(dwc_otg_dev_if_t));
13288 + if (dev_if == 0) {
13289 + DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
13290 + dwc_free(core_if);
13294 + dev_if->dev_global_regs =
13295 + (dwc_otg_device_global_regs_t *) (reg_base +
13296 + DWC_DEV_GLOBAL_REG_OFFSET);
13298 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
13299 + dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
13300 + (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
13301 + (i * DWC_EP_REG_OFFSET));
13303 + dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
13304 + (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
13305 + (i * DWC_EP_REG_OFFSET));
13306 + DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
13307 + i, &dev_if->in_ep_regs[i]->diepctl);
13308 + DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
13309 + i, &dev_if->out_ep_regs[i]->doepctl);
13312 + dev_if->speed = 0; // unknown
13314 + core_if->dev_if = dev_if;
13317 + * Allocate the Host Mode structures.
13319 + host_if = dwc_alloc(sizeof(dwc_otg_host_if_t));
13321 + if (host_if == 0) {
13322 + DWC_DEBUGPL(DBG_CIL,
13323 + "Allocation of dwc_otg_host_if_t failed\n");
13324 + dwc_free(dev_if);
13325 + dwc_free(core_if);
13329 + host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
13330 + (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
13333 + (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
13335 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
13336 + host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
13337 + (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
13338 + (i * DWC_OTG_CHAN_REGS_OFFSET));
13339 + DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
13340 + i, &host_if->hc_regs[i]->hcchar);
13343 + host_if->num_host_channels = MAX_EPS_CHANNELS;
13344 + core_if->host_if = host_if;
13346 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
13347 + core_if->data_fifo[i] =
13348 + (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
13349 + (i * DWC_OTG_DATA_FIFO_SIZE));
13350 + DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08x\n",
13351 + i, (unsigned)core_if->data_fifo[i]);
13354 + core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
13356 + /* Initiate lx_state to L3 disconnected state */
13357 + core_if->lx_state = DWC_OTG_L3;
13359 + * Store the contents of the hardware configuration registers here for
13360 + * easy access later.
13362 + core_if->hwcfg1.d32 =
13363 + dwc_read_reg32(&core_if->core_global_regs->ghwcfg1);
13364 + core_if->hwcfg2.d32 =
13365 + dwc_read_reg32(&core_if->core_global_regs->ghwcfg2);
13366 + core_if->hwcfg3.d32 =
13367 + dwc_read_reg32(&core_if->core_global_regs->ghwcfg3);
13368 + core_if->hwcfg4.d32 =
13369 + dwc_read_reg32(&core_if->core_global_regs->ghwcfg4);
13371 + DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
13372 + DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
13373 + DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
13374 + DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
13376 + core_if->hcfg.d32 =
13377 + dwc_read_reg32(&core_if->host_if->host_global_regs->hcfg);
13378 + core_if->dcfg.d32 =
13379 + dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg);
13381 + DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32);
13382 + DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32);
13384 + DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
13385 + DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
13386 + DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
13387 + DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
13388 + core_if->hwcfg2.b.num_host_chan);
13389 + DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
13390 + core_if->hwcfg2.b.nonperio_tx_q_depth);
13391 + DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
13392 + core_if->hwcfg2.b.host_perio_tx_q_depth);
13393 + DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
13394 + core_if->hwcfg2.b.dev_token_q_depth);
13396 + DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
13397 + core_if->hwcfg3.b.dfifo_depth);
13398 + DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
13399 + core_if->hwcfg3.b.xfer_size_cntr_width);
13402 + * Set the SRP sucess bit for FS-I2c
13404 + core_if->srp_success = 0;
13405 + core_if->srp_timer_started = 0;
13408 + * Create new workqueue and init works
13410 + core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg");
13411 + if (core_if->wq_otg == 0) {
13412 + DWC_WARN("DWC_WORKQ_ALLOC failed\n");
13413 + dwc_free(host_if);
13414 + dwc_free(dev_if);
13415 + dwc_free(core_if);
13419 + core_if->snpsid = dwc_read_reg32(&core_if->core_global_regs->gsnpsid);
13421 + DWC_PRINTF("Core Release: %x.%x%x%x\n",
13422 + (core_if->snpsid >> 12 & 0xF),
13423 + (core_if->snpsid >> 8 & 0xF),
13424 + (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF));
13426 + core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer",
13427 + w_wakeup_detected, core_if);
13428 + if (core_if->wkp_timer == 0) {
13429 + DWC_WARN("DWC_TIMER_ALLOC failed\n");
13430 + dwc_free(host_if);
13431 + dwc_free(dev_if);
13432 + DWC_WORKQ_FREE(core_if->wq_otg);
13433 + dwc_free(core_if);
13437 + if (dwc_otg_setup_params(core_if)) {
13438 + DWC_WARN("Error while setting core params\n");
13445 + * This function frees the structures allocated by dwc_otg_cil_init().
13447 + * @param core_if The core interface pointer returned from
13448 + * dwc_otg_cil_init().
13451 +void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if)
13453 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
13455 + /* Disable all interrupts */
13456 + dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, 1, 0);
13457 + dwc_write_reg32(&core_if->core_global_regs->gintmsk, 0);
13459 + if (core_if->wq_otg) {
13460 + DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500);
13461 + DWC_WORKQ_FREE(core_if->wq_otg);
13463 + if (core_if->dev_if) {
13464 + dwc_free(core_if->dev_if);
13466 + if (core_if->host_if) {
13467 + dwc_free(core_if->host_if);
13469 + dwc_free(core_if);
13470 + DWC_TIMER_FREE(core_if->wkp_timer);
13471 + DWC_FREE(core_if->core_params);
13475 + * This function enables the controller's Global Interrupt in the AHB Config
13478 + * @param core_if Programming view of DWC_otg controller.
13480 +void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if)
13482 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
13483 + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */
13484 + dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
13488 + * This function disables the controller's Global Interrupt in the AHB Config
13491 + * @param core_if Programming view of DWC_otg controller.
13493 +void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if)
13495 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
13496 + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */
13497 + DWC_PRINTF("%x -> %x\n", (unsigned int)&core_if->core_global_regs->gahbcfg, ahbcfg.d32);
13498 + dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
13502 + * This function initializes the commmon interrupts, used in both
13503 + * device and host modes.
13505 + * @param core_if Programming view of the DWC_otg controller
13508 +static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if)
13510 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
13511 + gintmsk_data_t intr_mask = {.d32 = 0 };
13513 + /* Clear any pending OTG Interrupts */
13514 + dwc_write_reg32(&global_regs->gotgint, 0xFFFFFFFF);
13516 + /* Clear any pending interrupts */
13517 + dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF);
13520 + * Enable the interrupts in the GINTMSK.
13522 + intr_mask.b.modemismatch = 1;
13523 + intr_mask.b.otgintr = 1;
13525 + if (!core_if->dma_enable) {
13526 + intr_mask.b.rxstsqlvl = 1;
13529 + intr_mask.b.conidstschng = 1;
13530 + intr_mask.b.wkupintr = 1;
13531 + intr_mask.b.disconnect = 1;
13532 + intr_mask.b.usbsuspend = 1;
13533 + intr_mask.b.sessreqintr = 1;
13534 +#ifdef CONFIG_USB_DWC_OTG_LPM
13535 + if (core_if->core_params->lpm_enable) {
13536 + intr_mask.b.lpmtranrcvd = 1;
13539 + dwc_write_reg32(&global_regs->gintmsk, intr_mask.d32);
13543 + * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
13546 +static void init_fslspclksel(dwc_otg_core_if_t * core_if)
13549 + hcfg_data_t hcfg;
13551 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
13552 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
13553 + (core_if->core_params->ulpi_fs_ls)) ||
13554 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
13555 + /* Full speed PHY */
13556 + val = DWC_HCFG_48_MHZ;
13558 + /* High speed PHY running at full speed or high speed */
13559 + val = DWC_HCFG_30_60_MHZ;
13562 + DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
13563 + hcfg.d32 = dwc_read_reg32(&core_if->host_if->host_global_regs->hcfg);
13564 + hcfg.b.fslspclksel = val;
13565 + dwc_write_reg32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
13569 + * Initializes the DevSpd field of the DCFG register depending on the PHY type
13570 + * and the enumeration speed of the device.
13572 +static void init_devspd(dwc_otg_core_if_t * core_if)
13575 + dcfg_data_t dcfg;
13577 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
13578 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
13579 + (core_if->core_params->ulpi_fs_ls)) ||
13580 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
13581 + /* Full speed PHY */
13583 + } else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
13584 + /* High speed PHY running at full speed */
13587 + /* High speed PHY running at high speed */
13591 + DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
13593 + dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg);
13594 + dcfg.b.devspd = val;
13595 + dwc_write_reg32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
13599 + * This function calculates the number of IN EPS
13600 + * using GHWCFG1 and GHWCFG2 registers values
13602 + * @param core_if Programming view of the DWC_otg controller
13604 +static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if)
13606 + uint32_t num_in_eps = 0;
13607 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
13608 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3;
13609 + uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps;
13612 + for (i = 0; i < num_eps; ++i) {
13613 + if (!(hwcfg1 & 0x1))
13619 + if (core_if->hwcfg4.b.ded_fifo_en) {
13621 + (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
13624 + return num_in_eps;
13628 + * This function calculates the number of OUT EPS
13629 + * using GHWCFG1 and GHWCFG2 registers values
13631 + * @param core_if Programming view of the DWC_otg controller
13633 +static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if)
13635 + uint32_t num_out_eps = 0;
13636 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
13637 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2;
13640 + for (i = 0; i < num_eps; ++i) {
13641 + if (!(hwcfg1 & 0x1))
13646 + return num_out_eps;
13650 + * This function initializes the DWC_otg controller registers and
13651 + * prepares the core for device mode or host mode operation.
13653 + * @param core_if Programming view of the DWC_otg controller
13656 +void dwc_otg_core_init(dwc_otg_core_if_t * core_if)
13659 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
13660 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
13661 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
13662 + gusbcfg_data_t usbcfg = {.d32 = 0 };
13663 + gi2cctl_data_t i2cctl = {.d32 = 0 };
13665 + DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p) regs at %p\n",
13666 + core_if, global_regs);
13668 + /* Common Initialization */
13670 + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
13672 + /* Program the ULPI External VBUS bit if needed */
13673 + usbcfg.b.ulpi_ext_vbus_drv =
13674 + (core_if->core_params->phy_ulpi_ext_vbus ==
13675 + DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
13677 + /* Set external TS Dline pulsing */
13678 + usbcfg.b.term_sel_dl_pulse =
13679 + (core_if->core_params->ts_dline == 1) ? 1 : 0;
13680 + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
13682 + /* Reset the Controller */
13683 + dwc_otg_core_reset(core_if);
13685 + /* Initialize parameters from Hardware configuration registers. */
13686 + dev_if->num_in_eps = calc_num_in_eps(core_if);
13687 + dev_if->num_out_eps = calc_num_out_eps(core_if);
13689 + DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
13690 + core_if->hwcfg4.b.num_dev_perio_in_ep);
13692 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
13693 + dev_if->perio_tx_fifo_size[i] =
13694 + dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16;
13695 + DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
13696 + i, dev_if->perio_tx_fifo_size[i]);
13699 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
13700 + dev_if->tx_fifo_size[i] =
13701 + dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16;
13702 + DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
13703 + i, dev_if->perio_tx_fifo_size[i]);
13706 + core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
13707 + core_if->rx_fifo_size = dwc_read_reg32(&global_regs->grxfsiz);
13708 + core_if->nperio_tx_fifo_size =
13709 + dwc_read_reg32(&global_regs->gnptxfsiz) >> 16;
13711 + DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
13712 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
13713 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
13714 + core_if->nperio_tx_fifo_size);
13716 + /* This programming sequence needs to happen in FS mode before any other
13717 + * programming occurs */
13718 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
13719 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
13720 + /* If FS mode with FS PHY */
13722 + /* core_init() is now called on every switch so only call the
13723 + * following for the first time through. */
13724 + if (!core_if->phy_init_done) {
13725 + core_if->phy_init_done = 1;
13726 + DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
13727 + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
13728 + usbcfg.b.physel = 1;
13729 + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
13731 + /* Reset after a PHY select */
13732 + dwc_otg_core_reset(core_if);
13735 + /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
13736 + * do this on HNP Dev/Host mode switches (done in dev_init and
13738 + if (dwc_otg_is_host_mode(core_if)) {
13739 + init_fslspclksel(core_if);
13741 + init_devspd(core_if);
13744 + if (core_if->core_params->i2c_enable) {
13745 + DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
13746 + /* Program GUSBCFG.OtgUtmifsSel to I2C */
13747 + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
13748 + usbcfg.b.otgutmifssel = 1;
13749 + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
13751 + /* Program GI2CCTL.I2CEn */
13752 + i2cctl.d32 = dwc_read_reg32(&global_regs->gi2cctl);
13753 + i2cctl.b.i2cdevaddr = 1;
13754 + i2cctl.b.i2cen = 0;
13755 + dwc_write_reg32(&global_regs->gi2cctl, i2cctl.d32);
13756 + i2cctl.b.i2cen = 1;
13757 + dwc_write_reg32(&global_regs->gi2cctl, i2cctl.d32);
13760 + } /* endif speed == DWC_SPEED_PARAM_FULL */
13762 + /* High speed PHY. */
13763 + if (!core_if->phy_init_done) {
13764 + core_if->phy_init_done = 1;
13765 + /* HS PHY parameters. These parameters are preserved
13766 + * during soft reset so only program the first time. Do
13767 + * a soft reset immediately after setting phyif. */
13768 + usbcfg.b.ulpi_utmi_sel = core_if->core_params->phy_type;
13769 + if (usbcfg.b.ulpi_utmi_sel == 1) {
13770 + /* ULPI interface */
13771 + usbcfg.b.phyif = 0;
13772 + usbcfg.b.ddrsel =
13773 + core_if->core_params->phy_ulpi_ddr;
13775 + /* UTMI+ interface */
13776 + if (core_if->core_params->phy_utmi_width == 16) {
13777 + usbcfg.b.phyif = 1;
13780 + usbcfg.b.phyif = 0;
13785 + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
13786 + /* Reset after setting the PHY parameters */
13787 + dwc_otg_core_reset(core_if);
13791 + if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
13792 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
13793 + (core_if->core_params->ulpi_fs_ls)) {
13794 + DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
13795 + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
13796 + usbcfg.b.ulpi_fsls = 1;
13797 + usbcfg.b.ulpi_clk_sus_m = 1;
13798 + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
13800 + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
13801 + usbcfg.b.ulpi_fsls = 0;
13802 + usbcfg.b.ulpi_clk_sus_m = 0;
13803 + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
13806 + /* Program the GAHBCFG Register. */
13807 + switch (core_if->hwcfg2.b.architecture) {
13809 + case DWC_SLAVE_ONLY_ARCH:
13810 + DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
13811 + ahbcfg.b.nptxfemplvl_txfemplvl =
13812 + DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
13813 + ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
13814 + core_if->dma_enable = 0;
13815 + core_if->dma_desc_enable = 0;
13818 + case DWC_EXT_DMA_ARCH:
13819 + DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
13821 + uint8_t brst_sz = core_if->core_params->dma_burst_size;
13822 + ahbcfg.b.hburstlen = 0;
13823 + while (brst_sz > 1) {
13824 + ahbcfg.b.hburstlen++;
13828 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
13829 + core_if->dma_desc_enable =
13830 + (core_if->core_params->dma_desc_enable != 0);
13833 + case DWC_INT_DMA_ARCH:
13834 + DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
13835 + /*ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR; */
13836 + ahbcfg.b.hburstlen = (1<<3)|(0<<0); /* WRESP=1, max 4 beats */
13837 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
13838 + core_if->dma_desc_enable =
13839 + (core_if->core_params->dma_desc_enable != 0);
13843 + if (core_if->dma_enable) {
13844 + if (core_if->dma_desc_enable) {
13845 + DWC_PRINTF("Using Descriptor DMA mode\n");
13847 + DWC_PRINTF("Using Buffer DMA mode\n");
13851 + DWC_PRINTF("Using Slave mode\n");
13852 + core_if->dma_desc_enable = 0;
13855 + ahbcfg.b.dmaenable = core_if->dma_enable;
13856 + dwc_write_reg32(&global_regs->gahbcfg, ahbcfg.d32);
13858 + core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en;
13860 + core_if->pti_enh_enable = core_if->core_params->pti_enable != 0;
13861 + core_if->multiproc_int_enable = core_if->core_params->mpi_enable;
13862 + DWC_PRINTF("Periodic Transfer Interrupt Enhancement - %s\n",
13863 + ((core_if->pti_enh_enable) ? "enabled" : "disabled"));
13864 + DWC_PRINTF("Multiprocessor Interrupt Enhancement - %s\n",
13865 + ((core_if->multiproc_int_enable) ? "enabled" : "disabled"));
13868 + * Program the GUSBCFG register.
13870 + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
13872 + switch (core_if->hwcfg2.b.op_mode) {
13873 + case DWC_MODE_HNP_SRP_CAPABLE:
13874 + usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
13875 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
13876 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
13877 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
13880 + case DWC_MODE_SRP_ONLY_CAPABLE:
13881 + usbcfg.b.hnpcap = 0;
13882 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
13883 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
13886 + case DWC_MODE_NO_HNP_SRP_CAPABLE:
13887 + usbcfg.b.hnpcap = 0;
13888 + usbcfg.b.srpcap = 0;
13891 + case DWC_MODE_SRP_CAPABLE_DEVICE:
13892 + usbcfg.b.hnpcap = 0;
13893 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
13894 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
13897 + case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
13898 + usbcfg.b.hnpcap = 0;
13899 + usbcfg.b.srpcap = 0;
13902 + case DWC_MODE_SRP_CAPABLE_HOST:
13903 + usbcfg.b.hnpcap = 0;
13904 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
13905 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
13908 + case DWC_MODE_NO_SRP_CAPABLE_HOST:
13909 + usbcfg.b.hnpcap = 0;
13910 + usbcfg.b.srpcap = 0;
13914 + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
13916 +#ifdef CONFIG_USB_DWC_OTG_LPM
13917 + if (core_if->core_params->lpm_enable) {
13918 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
13920 + /* To enable LPM support set lpm_cap_en bit */
13921 + lpmcfg.b.lpm_cap_en = 1;
13923 + /* Make AppL1Res ACK */
13924 + lpmcfg.b.appl_resp = 1;
13926 + /* Retry 3 times */
13927 + lpmcfg.b.retry_count = 3;
13929 + dwc_modify_reg32(&core_if->core_global_regs->glpmcfg,
13934 + if (core_if->core_params->ic_usb_cap) {
13935 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
13936 + gusbcfg.b.ic_usb_cap = 1;
13937 + dwc_modify_reg32(&core_if->core_global_regs->gusbcfg,
13941 + /* Enable common interrupts */
13942 + dwc_otg_enable_common_interrupts(core_if);
13944 + /* Do device or host intialization based on mode during PCD
13945 + * and HCD initialization */
13946 + if (dwc_otg_is_host_mode(core_if)) {
13947 + DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
13948 + core_if->op_state = A_HOST;
13950 + DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
13951 + core_if->op_state = B_PERIPHERAL;
13952 +#ifdef DWC_DEVICE_ONLY
13953 + dwc_otg_core_dev_init(core_if);
13959 + * This function enables the Device mode interrupts.
13961 + * @param core_if Programming view of DWC_otg controller
13963 +void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if)
13965 + gintmsk_data_t intr_mask = {.d32 = 0 };
13966 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
13968 + DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
13970 + /* Disable all interrupts. */
13971 + dwc_write_reg32(&global_regs->gintmsk, 0);
13973 + /* Clear any pending interrupts */
13974 + dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF);
13976 + /* Enable the common interrupts */
13977 + dwc_otg_enable_common_interrupts(core_if);
13979 + /* Enable interrupts */
13980 + intr_mask.b.usbreset = 1;
13981 + intr_mask.b.enumdone = 1;
13983 + if (!core_if->multiproc_int_enable) {
13984 + intr_mask.b.inepintr = 1;
13985 + intr_mask.b.outepintr = 1;
13988 + intr_mask.b.erlysuspend = 1;
13990 + if (core_if->en_multiple_tx_fifo == 0) {
13991 + intr_mask.b.epmismatch = 1;
13993 +#ifdef DWC_EN_ISOC
13994 + if (core_if->dma_enable) {
13995 + if (core_if->dma_desc_enable == 0) {
13996 + if (core_if->pti_enh_enable) {
13997 + dctl_data_t dctl = {.d32 = 0 };
13998 + dctl.b.ifrmnum = 1;
13999 + dwc_modify_reg32(&core_if->dev_if->
14000 + dev_global_regs->dctl, 0,
14003 + intr_mask.b.incomplisoin = 1;
14004 + intr_mask.b.incomplisoout = 1;
14008 + intr_mask.b.incomplisoin = 1;
14009 + intr_mask.b.incomplisoout = 1;
14011 +#endif /* DWC_EN_ISOC */
14013 + /** @todo NGS: Should this be a module parameter? */
14014 +#ifdef USE_PERIODIC_EP
14015 + intr_mask.b.isooutdrop = 1;
14016 + intr_mask.b.eopframe = 1;
14017 + intr_mask.b.incomplisoin = 1;
14018 + intr_mask.b.incomplisoout = 1;
14021 + dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
14023 + DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
14024 + dwc_read_reg32(&global_regs->gintmsk));
14028 + * This function initializes the DWC_otg controller registers for
14031 + * @param core_if Programming view of DWC_otg controller
14034 +void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if)
14037 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
14038 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
14039 + dwc_otg_core_params_t *params = core_if->core_params;
14040 + dcfg_data_t dcfg = {.d32 = 0 };
14041 + grstctl_t resetctl = {.d32 = 0 };
14042 + uint32_t rx_fifo_size;
14043 + fifosize_data_t nptxfifosize;
14044 + fifosize_data_t txfifosize;
14045 + dthrctl_data_t dthrctl;
14046 + fifosize_data_t ptxfifosize;
14048 + /* Restart the Phy Clock */
14049 + dwc_write_reg32(core_if->pcgcctl, 0);
14051 + /* Device configuration register */
14052 + init_devspd(core_if);
14053 + dcfg.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dcfg);
14054 + dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0;
14055 + dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
14057 + dwc_write_reg32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
14059 + /* Configure data FIFO sizes */
14060 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
14061 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
14062 + core_if->total_fifo_size);
14063 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
14064 + params->dev_rx_fifo_size);
14065 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
14066 + params->dev_nperio_tx_fifo_size);
14069 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
14070 + dwc_read_reg32(&global_regs->grxfsiz));
14072 +#ifdef DWC_UTE_CFI
14073 + core_if->pwron_rxfsiz = dwc_read_reg32(&global_regs->grxfsiz);
14074 + core_if->init_rxfsiz = params->dev_rx_fifo_size;
14076 + rx_fifo_size = params->dev_rx_fifo_size;
14077 + dwc_write_reg32(&global_regs->grxfsiz, rx_fifo_size);
14079 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
14080 + dwc_read_reg32(&global_regs->grxfsiz));
14082 + /** Set Periodic Tx FIFO Mask all bits 0 */
14083 + core_if->p_tx_msk = 0;
14085 + /** Set Tx FIFO Mask all bits 0 */
14086 + core_if->tx_msk = 0;
14088 + if (core_if->en_multiple_tx_fifo == 0) {
14089 + /* Non-periodic Tx FIFO */
14090 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
14091 + dwc_read_reg32(&global_regs->gnptxfsiz));
14093 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
14094 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
14096 + dwc_write_reg32(&global_regs->gnptxfsiz,
14097 + nptxfifosize.d32);
14099 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
14100 + dwc_read_reg32(&global_regs->gnptxfsiz));
14102 + /**@todo NGS: Fix Periodic FIFO Sizing! */
14104 + * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
14105 + * Indexes of the FIFO size module parameters in the
14106 + * dev_perio_tx_fifo_size array and the FIFO size registers in
14107 + * the dptxfsiz array run from 0 to 14.
14109 + /** @todo Finish debug of this */
14110 + ptxfifosize.b.startaddr =
14111 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
14112 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep;
14114 + ptxfifosize.b.depth =
14115 + params->dev_perio_tx_fifo_size[i];
14116 + DWC_DEBUGPL(DBG_CIL,
14117 + "initial dptxfsiz_dieptxf[%d]=%08x\n",
14119 + dwc_read_reg32(&global_regs->
14122 + dwc_write_reg32(&global_regs->
14123 + dptxfsiz_dieptxf[i],
14124 + ptxfifosize.d32);
14125 + DWC_DEBUGPL(DBG_CIL,
14126 + "new dptxfsiz_dieptxf[%d]=%08x\n",
14128 + dwc_read_reg32(&global_regs->
14131 + ptxfifosize.b.startaddr += ptxfifosize.b.depth;
14135 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
14136 + * Indexes of the FIFO size module parameters in the
14137 + * dev_tx_fifo_size array and the FIFO size registers in
14138 + * the dptxfsiz_dieptxf array run from 0 to 14.
14141 + /* Non-periodic Tx FIFO */
14142 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
14143 + dwc_read_reg32(&global_regs->gnptxfsiz));
14145 +#ifdef DWC_UTE_CFI
14146 + core_if->pwron_gnptxfsiz =
14147 + (dwc_read_reg32(&global_regs->gnptxfsiz) >> 16);
14148 + core_if->init_gnptxfsiz =
14149 + params->dev_nperio_tx_fifo_size;
14151 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
14152 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
14154 + dwc_write_reg32(&global_regs->gnptxfsiz,
14155 + nptxfifosize.d32);
14157 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
14158 + dwc_read_reg32(&global_regs->gnptxfsiz));
14160 + txfifosize.b.startaddr =
14161 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
14163 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
14165 + txfifosize.b.depth =
14166 + params->dev_tx_fifo_size[i];
14168 + DWC_DEBUGPL(DBG_CIL,
14169 + "initial dptxfsiz_dieptxf[%d]=%08x\n",
14171 + dwc_read_reg32(&global_regs->
14175 +#ifdef DWC_UTE_CFI
14176 + core_if->pwron_txfsiz[i] =
14178 + (&global_regs->dptxfsiz_dieptxf[i]) >> 16);
14179 + core_if->init_txfsiz[i] =
14180 + params->dev_tx_fifo_size[i];
14182 + dwc_write_reg32(&global_regs->
14183 + dptxfsiz_dieptxf[i],
14186 + DWC_DEBUGPL(DBG_CIL,
14187 + "new dptxfsiz_dieptxf[%d]=%08x\n",
14189 + dwc_read_reg32(&global_regs->
14193 + txfifosize.b.startaddr += txfifosize.b.depth;
14197 + /* Flush the FIFOs */
14198 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
14199 + dwc_otg_flush_rx_fifo(core_if);
14201 + /* Flush the Learning Queue. */
14202 + resetctl.b.intknqflsh = 1;
14203 + dwc_write_reg32(&core_if->core_global_regs->grstctl, resetctl.d32);
14205 + /* Clear all pending Device Interrupts */
14206 + /** @todo - if the condition needed to be checked
14207 + * or in any case all pending interrutps should be cleared?
14209 + if (core_if->multiproc_int_enable) {
14210 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
14211 + dwc_write_reg32(&dev_if->dev_global_regs->
14212 + diepeachintmsk[i], 0);
14215 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
14216 + dwc_write_reg32(&dev_if->dev_global_regs->
14217 + doepeachintmsk[i], 0);
14220 + dwc_write_reg32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF);
14221 + dwc_write_reg32(&dev_if->dev_global_regs->deachintmsk, 0);
14223 + dwc_write_reg32(&dev_if->dev_global_regs->diepmsk, 0);
14224 + dwc_write_reg32(&dev_if->dev_global_regs->doepmsk, 0);
14225 + dwc_write_reg32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
14226 + dwc_write_reg32(&dev_if->dev_global_regs->daintmsk, 0);
14229 + for (i = 0; i <= dev_if->num_in_eps; i++) {
14230 + depctl_data_t depctl;
14231 + depctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl);
14232 + if (depctl.b.epena) {
14234 + depctl.b.epdis = 1;
14235 + depctl.b.snak = 1;
14240 + dwc_write_reg32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
14242 + dwc_write_reg32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
14243 + dwc_write_reg32(&dev_if->in_ep_regs[i]->diepdma, 0);
14244 + dwc_write_reg32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
14247 + for (i = 0; i <= dev_if->num_out_eps; i++) {
14248 + depctl_data_t depctl;
14249 + depctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[i]->doepctl);
14250 + if (depctl.b.epena) {
14252 + depctl.b.epdis = 1;
14253 + depctl.b.snak = 1;
14258 + dwc_write_reg32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
14260 + dwc_write_reg32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
14261 + dwc_write_reg32(&dev_if->out_ep_regs[i]->doepdma, 0);
14262 + dwc_write_reg32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
14265 + if (core_if->en_multiple_tx_fifo && core_if->dma_enable) {
14266 + dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1;
14267 + dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1;
14268 + dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1;
14270 + dev_if->rx_thr_length = params->rx_thr_length;
14271 + dev_if->tx_thr_length = params->tx_thr_length;
14273 + dev_if->setup_desc_index = 0;
14276 + dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
14277 + dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
14278 + dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
14279 + dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
14280 + dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
14281 + dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio;
14283 + dwc_write_reg32(&dev_if->dev_global_regs->dtknqr3_dthrctl,
14286 + DWC_DEBUGPL(DBG_CIL,
14287 + "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
14288 + dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en,
14289 + dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len,
14290 + dthrctl.b.rx_thr_len);
14294 + dwc_otg_enable_device_interrupts(core_if);
14297 + diepmsk_data_t msk = {.d32 = 0 };
14298 + msk.b.txfifoundrn = 1;
14299 + if (core_if->multiproc_int_enable) {
14300 + dwc_modify_reg32(&dev_if->dev_global_regs->
14301 + diepeachintmsk[0], msk.d32, msk.d32);
14303 + dwc_modify_reg32(&dev_if->dev_global_regs->diepmsk,
14304 + msk.d32, msk.d32);
14308 + if (core_if->multiproc_int_enable) {
14309 + /* Set NAK on Babble */
14310 + dctl_data_t dctl = {.d32 = 0 };
14311 + dctl.b.nakonbble = 1;
14312 + dwc_modify_reg32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
14317 + * This function enables the Host mode interrupts.
14319 + * @param core_if Programming view of DWC_otg controller
14321 +void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if)
14323 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
14324 + gintmsk_data_t intr_mask = {.d32 = 0 };
14326 + DWC_DEBUGPL(DBG_CIL, "%s(%p)\n", __func__, core_if);
14328 + /* Disable all interrupts. */
14329 + dwc_write_reg32(&global_regs->gintmsk, 0);
14331 + /* Clear any pending interrupts. */
14332 + dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF);
14334 + /* Enable the common interrupts */
14335 + dwc_otg_enable_common_interrupts(core_if);
14338 + * Enable host mode interrupts without disturbing common
14342 + /* Do not need sof interrupt for Descriptor DMA*/
14343 + if (!core_if->dma_desc_enable)
14344 + intr_mask.b.sofintr = 1;
14345 + intr_mask.b.portintr = 1;
14346 + intr_mask.b.hcintr = 1;
14348 + dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
14352 + * This function disables the Host Mode interrupts.
14354 + * @param core_if Programming view of DWC_otg controller
14356 +void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if)
14358 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
14359 + gintmsk_data_t intr_mask = {.d32 = 0 };
14361 + DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
14364 + * Disable host mode interrupts without disturbing common
14367 + intr_mask.b.sofintr = 1;
14368 + intr_mask.b.portintr = 1;
14369 + intr_mask.b.hcintr = 1;
14370 + intr_mask.b.ptxfempty = 1;
14371 + intr_mask.b.nptxfempty = 1;
14373 + dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0);
14377 + * This function initializes the DWC_otg controller registers for
14380 + * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
14381 + * request queues. Host channels are reset to ensure that they are ready for
14382 + * performing transfers.
14384 + * @param core_if Programming view of DWC_otg controller
14387 +void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
14389 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
14390 + dwc_otg_host_if_t *host_if = core_if->host_if;
14391 + dwc_otg_core_params_t *params = core_if->core_params;
14392 + hprt0_data_t hprt0 = {.d32 = 0 };
14393 + fifosize_data_t nptxfifosize;
14394 + fifosize_data_t ptxfifosize;
14396 + hcchar_data_t hcchar;
14397 + hcfg_data_t hcfg;
14398 + dwc_otg_hc_regs_t *hc_regs;
14399 + int num_channels;
14400 + gotgctl_data_t gotgctl = {.d32 = 0 };
14402 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
14404 + /* Restart the Phy Clock */
14405 + dwc_write_reg32(core_if->pcgcctl, 0);
14407 + /* Initialize Host Configuration Register */
14408 + init_fslspclksel(core_if);
14409 + if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
14410 + hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg);
14411 + hcfg.b.fslssupp = 1;
14412 + dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32);
14416 + if (core_if->core_params->dma_desc_enable) {
14417 + uint8_t op_mode = core_if->hwcfg2.b.op_mode;
14418 + if (!(core_if->hwcfg4.b.desc_dma && (core_if->snpsid >= OTG_CORE_REV_2_90a) &&
14419 + ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) ||
14420 + (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) ||
14421 + (op_mode == DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG) ||
14422 + (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST) ||
14423 + (op_mode == DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) {
14425 + DWC_ERROR("Host can't operate in Descriptor DMA mode.\n"
14426 + "Either core version is below 2.90a or "
14427 + "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n"
14428 + "To run the driver in Buffer DMA host mode set dma_desc_enable "
14429 + "module parameter to 0.\n");
14432 + hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg);
14433 + hcfg.b.descdma = 1;
14434 + dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32);
14437 + /* Configure data FIFO sizes */
14438 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
14439 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
14440 + core_if->total_fifo_size);
14441 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
14442 + params->host_rx_fifo_size);
14443 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
14444 + params->host_nperio_tx_fifo_size);
14445 + DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
14446 + params->host_perio_tx_fifo_size);
14449 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
14450 + dwc_read_reg32(&global_regs->grxfsiz));
14451 + dwc_write_reg32(&global_regs->grxfsiz,
14452 + params->host_rx_fifo_size);
14453 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
14454 + dwc_read_reg32(&global_regs->grxfsiz));
14456 + /* Non-periodic Tx FIFO */
14457 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
14458 + dwc_read_reg32(&global_regs->gnptxfsiz));
14459 + nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
14460 + nptxfifosize.b.startaddr = params->host_rx_fifo_size;
14461 + dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32);
14462 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
14463 + dwc_read_reg32(&global_regs->gnptxfsiz));
14465 + /* Periodic Tx FIFO */
14466 + DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
14467 + dwc_read_reg32(&global_regs->hptxfsiz));
14468 + ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
14469 + ptxfifosize.b.startaddr =
14470 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
14471 + dwc_write_reg32(&global_regs->hptxfsiz, ptxfifosize.d32);
14472 + DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
14473 + dwc_read_reg32(&global_regs->hptxfsiz));
14476 + /* Clear Host Set HNP Enable in the OTG Control Register */
14477 + gotgctl.b.hstsethnpen = 1;
14478 + dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
14480 + /* Make sure the FIFOs are flushed. */
14481 + dwc_otg_flush_tx_fifo(core_if, 0x10 /* all Tx FIFOs */ );
14482 + dwc_otg_flush_rx_fifo(core_if);
14484 + if(!core_if->core_params->dma_desc_enable) {
14485 + /* Flush out any leftover queued requests. */
14486 + num_channels = core_if->core_params->host_channels;
14488 + for (i = 0; i < num_channels; i++) {
14489 + hc_regs = core_if->host_if->hc_regs[i];
14490 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
14491 + hcchar.b.chen = 0;
14492 + hcchar.b.chdis = 1;
14493 + hcchar.b.epdir = 0;
14494 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
14497 + /* Halt all channels to put them into a known state. */
14498 + for (i = 0; i < num_channels; i++) {
14500 + hc_regs = core_if->host_if->hc_regs[i];
14501 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
14502 + hcchar.b.chen = 1;
14503 + hcchar.b.chdis = 1;
14504 + hcchar.b.epdir = 0;
14505 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
14506 + DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d regs %p\n", __func__, i, hc_regs);
14508 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
14509 + if (++count > 1000) {
14511 + ("%s: Unable to clear halt on channel %d (timeout HCCHAR 0x%X @%p)\n",
14512 + __func__, i, hcchar.d32, &hc_regs->hcchar);
14516 + } while (hcchar.b.chen);
14520 + /* Turn on the vbus power. */
14521 + DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state);
14522 + if (core_if->op_state == A_HOST) {
14523 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
14524 + DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
14525 + if (hprt0.b.prtpwr == 0) {
14526 + hprt0.b.prtpwr = 1;
14527 + dwc_write_reg32(host_if->hprt0, hprt0.d32);
14531 + dwc_otg_enable_host_interrupts(core_if);
14535 + * Prepares a host channel for transferring packets to/from a specific
14536 + * endpoint. The HCCHARn register is set up with the characteristics specified
14537 + * in _hc. Host channel interrupts that may need to be serviced while this
14538 + * transfer is in progress are enabled.
14540 + * @param core_if Programming view of DWC_otg controller
14541 + * @param hc Information needed to initialize the host channel
14543 +void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
14545 + uint32_t intr_enable;
14546 + hcintmsk_data_t hc_intr_mask;
14547 + gintmsk_data_t gintmsk = {.d32 = 0 };
14548 + hcchar_data_t hcchar;
14549 + hcsplt_data_t hcsplt;
14551 + uint8_t hc_num = hc->hc_num;
14552 + dwc_otg_host_if_t *host_if = core_if->host_if;
14553 + dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
14555 + /* Clear old interrupt conditions for this host channel. */
14556 + hc_intr_mask.d32 = 0xFFFFFFFF;
14557 + hc_intr_mask.b.reserved14_31 = 0;
14558 + dwc_write_reg32(&hc_regs->hcint, hc_intr_mask.d32);
14560 + /* Enable channel interrupts required for this transfer. */
14561 + hc_intr_mask.d32 = 0;
14562 + hc_intr_mask.b.chhltd = 1;
14563 + if (core_if->dma_enable) {
14564 + /* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */
14565 + if (!core_if->dma_desc_enable)
14566 + hc_intr_mask.b.ahberr = 1;
14568 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
14569 + hc_intr_mask.b.xfercompl = 1;
14572 + if (hc->error_state && !hc->do_split &&
14573 + hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
14574 + hc_intr_mask.b.ack = 1;
14575 + if (hc->ep_is_in) {
14576 + hc_intr_mask.b.datatglerr = 1;
14577 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
14578 + hc_intr_mask.b.nak = 1;
14583 + switch (hc->ep_type) {
14584 + case DWC_OTG_EP_TYPE_CONTROL:
14585 + case DWC_OTG_EP_TYPE_BULK:
14586 + hc_intr_mask.b.xfercompl = 1;
14587 + hc_intr_mask.b.stall = 1;
14588 + hc_intr_mask.b.xacterr = 1;
14589 + hc_intr_mask.b.datatglerr = 1;
14590 + if (hc->ep_is_in) {
14591 + hc_intr_mask.b.bblerr = 1;
14593 + hc_intr_mask.b.nak = 1;
14594 + hc_intr_mask.b.nyet = 1;
14595 + if (hc->do_ping) {
14596 + hc_intr_mask.b.ack = 1;
14600 + if (hc->do_split) {
14601 + hc_intr_mask.b.nak = 1;
14602 + if (hc->complete_split) {
14603 + hc_intr_mask.b.nyet = 1;
14605 + hc_intr_mask.b.ack = 1;
14609 + if (hc->error_state) {
14610 + hc_intr_mask.b.ack = 1;
14613 + case DWC_OTG_EP_TYPE_INTR:
14614 + hc_intr_mask.b.xfercompl = 1;
14615 + hc_intr_mask.b.nak = 1;
14616 + hc_intr_mask.b.stall = 1;
14617 + hc_intr_mask.b.xacterr = 1;
14618 + hc_intr_mask.b.datatglerr = 1;
14619 + hc_intr_mask.b.frmovrun = 1;
14621 + if (hc->ep_is_in) {
14622 + hc_intr_mask.b.bblerr = 1;
14624 + if (hc->error_state) {
14625 + hc_intr_mask.b.ack = 1;
14627 + if (hc->do_split) {
14628 + if (hc->complete_split) {
14629 + hc_intr_mask.b.nyet = 1;
14631 + hc_intr_mask.b.ack = 1;
14635 + case DWC_OTG_EP_TYPE_ISOC:
14636 + hc_intr_mask.b.xfercompl = 1;
14637 + hc_intr_mask.b.frmovrun = 1;
14638 + hc_intr_mask.b.ack = 1;
14640 + if (hc->ep_is_in) {
14641 + hc_intr_mask.b.xacterr = 1;
14642 + hc_intr_mask.b.bblerr = 1;
14647 + dwc_write_reg32(&hc_regs->hcintmsk, hc_intr_mask.d32);
14649 + /* Enable the top level host channel interrupt. */
14650 + intr_enable = (1 << hc_num);
14651 + dwc_modify_reg32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
14653 + /* Make sure host channel interrupts are enabled. */
14654 + gintmsk.b.hcintr = 1;
14655 + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
14658 + * Program the HCCHARn register with the endpoint characteristics for
14659 + * the current transfer.
14662 + hcchar.b.devaddr = hc->dev_addr;
14663 + hcchar.b.epnum = hc->ep_num;
14664 + hcchar.b.epdir = hc->ep_is_in;
14665 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
14666 + hcchar.b.eptype = hc->ep_type;
14667 + hcchar.b.mps = hc->max_packet;
14669 + dwc_write_reg32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
14671 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
14672 + DWC_DEBUGPL(DBG_HCDV, " Dev Addr: %d\n", hcchar.b.devaddr);
14673 + DWC_DEBUGPL(DBG_HCDV, " Ep Num: %d\n", hcchar.b.epnum);
14674 + DWC_DEBUGPL(DBG_HCDV, " Is In: %d\n", hcchar.b.epdir);
14675 + DWC_DEBUGPL(DBG_HCDV, " Is Low Speed: %d\n", hcchar.b.lspddev);
14676 + DWC_DEBUGPL(DBG_HCDV, " Ep Type: %d\n", hcchar.b.eptype);
14677 + DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps);
14678 + DWC_DEBUGPL(DBG_HCDV, " Multi Cnt: %d\n", hcchar.b.multicnt);
14681 + * Program the HCSPLIT register for SPLITs
14684 + if (hc->do_split) {
14685 + DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
14687 + hc->complete_split ? "CSPLIT" : "SSPLIT");
14688 + hcsplt.b.compsplt = hc->complete_split;
14689 + hcsplt.b.xactpos = hc->xact_pos;
14690 + hcsplt.b.hubaddr = hc->hub_addr;
14691 + hcsplt.b.prtaddr = hc->port_addr;
14692 + DWC_DEBUGPL(DBG_HCDV, " comp split %d\n", hc->complete_split);
14693 + DWC_DEBUGPL(DBG_HCDV, " xact pos %d\n", hc->xact_pos);
14694 + DWC_DEBUGPL(DBG_HCDV, " hub addr %d\n", hc->hub_addr);
14695 + DWC_DEBUGPL(DBG_HCDV, " port addr %d\n", hc->port_addr);
14696 + DWC_DEBUGPL(DBG_HCDV, " is_in %d\n", hc->ep_is_in);
14697 + DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps);
14698 + DWC_DEBUGPL(DBG_HCDV, " xferlen: %d\n", hc->xfer_len);
14700 + dwc_write_reg32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
14705 + * Attempts to halt a host channel. This function should only be called in
14706 + * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
14707 + * normal circumstances in DMA mode, the controller halts the channel when the
14708 + * transfer is complete or a condition occurs that requires application
14711 + * In slave mode, checks for a free request queue entry, then sets the Channel
14712 + * Enable and Channel Disable bits of the Host Channel Characteristics
14713 + * register of the specified channel to intiate the halt. If there is no free
14714 + * request queue entry, sets only the Channel Disable bit of the HCCHARn
14715 + * register to flush requests for this channel. In the latter case, sets a
14716 + * flag to indicate that the host channel needs to be halted when a request
14717 + * queue slot is open.
14719 + * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
14720 + * HCCHARn register. The controller ensures there is space in the request
14721 + * queue before submitting the halt request.
14723 + * Some time may elapse before the core flushes any posted requests for this
14724 + * host channel and halts. The Channel Halted interrupt handler completes the
14725 + * deactivation of the host channel.
14727 + * @param core_if Controller register interface.
14728 + * @param hc Host channel to halt.
14729 + * @param halt_status Reason for halting the channel.
14731 +void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if,
14732 + dwc_hc_t * hc, dwc_otg_halt_status_e halt_status)
14734 + gnptxsts_data_t nptxsts;
14735 + hptxsts_data_t hptxsts;
14736 + hcchar_data_t hcchar;
14737 + dwc_otg_hc_regs_t *hc_regs;
14738 + dwc_otg_core_global_regs_t *global_regs;
14739 + dwc_otg_host_global_regs_t *host_global_regs;
14741 + DWC_DEBUGPL(DBG_HW2937, " dwc_otg_hc_halt(%d)\n", hc->hc_num);
14742 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
14743 + global_regs = core_if->core_global_regs;
14744 + host_global_regs = core_if->host_if->host_global_regs;
14746 + DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS),
14747 + "halt_status = %d\n", halt_status);
14749 + if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
14750 + halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
14752 + * Disable all channel interrupts except Ch Halted. The QTD
14753 + * and QH state associated with this transfer has been cleared
14754 + * (in the case of URB_DEQUEUE), so the channel needs to be
14755 + * shut down carefully to prevent crashes.
14757 + hcintmsk_data_t hcintmsk;
14758 + hcintmsk.d32 = 0;
14759 + hcintmsk.b.chhltd = 1;
14760 + dwc_write_reg32(&hc_regs->hcintmsk, hcintmsk.d32);
14763 + * Make sure no other interrupts besides halt are currently
14764 + * pending. Handling another interrupt could cause a crash due
14765 + * to the QTD and QH state.
14767 + dwc_write_reg32(&hc_regs->hcint, ~hcintmsk.d32);
14770 + * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
14771 + * even if the channel was already halted for some other
14774 + hc->halt_status = halt_status;
14776 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
14777 + if (hcchar.b.chen == 0) {
14779 + * The channel is either already halted or it hasn't
14780 + * started yet. In DMA mode, the transfer may halt if
14781 + * it finishes normally or a condition occurs that
14782 + * requires driver intervention. Don't want to halt
14783 + * the channel again. In either Slave or DMA mode,
14784 + * it's possible that the transfer has been assigned
14785 + * to a channel, but not started yet when an URB is
14786 + * dequeued. Don't want to halt a channel that hasn't
14792 + if (hc->halt_pending) {
14794 + * A halt has already been issued for this channel. This might
14795 + * happen when a transfer is aborted by a higher level in
14800 + ("*** %s: Channel %d, _hc->halt_pending already set ***\n",
14801 + __func__, hc->hc_num);
14807 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
14809 + /* No need to set the bit in DDMA for disabling the channel */
14810 + //TODO check it everywhere channel is disabled
14811 + if(!core_if->core_params->dma_desc_enable)
14812 + hcchar.b.chen = 1;
14813 + hcchar.b.chdis = 1;
14815 + if (!core_if->dma_enable) {
14816 + /* Check for space in the request queue to issue the halt. */
14817 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
14818 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
14819 + nptxsts.d32 = dwc_read_reg32(&global_regs->gnptxsts);
14820 + if (nptxsts.b.nptxqspcavail == 0) {
14821 + hcchar.b.chen = 0;
14825 + dwc_read_reg32(&host_global_regs->hptxsts);
14826 + if ((hptxsts.b.ptxqspcavail == 0)
14827 + || (core_if->queuing_high_bandwidth)) {
14828 + hcchar.b.chen = 0;
14832 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
14834 + hc->halt_status = halt_status;
14836 + if (hcchar.b.chen) {
14837 + hc->halt_pending = 1;
14838 + hc->halt_on_queue = 0;
14840 + hc->halt_on_queue = 1;
14843 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
14844 + DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32);
14845 + DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", hc->halt_pending);
14846 + DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", hc->halt_on_queue);
14847 + DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", hc->halt_status);
14853 + * Clears the transfer state for a host channel. This function is normally
14854 + * called after a transfer is done and the host channel is being released.
14856 + * @param core_if Programming view of DWC_otg controller.
14857 + * @param hc Identifies the host channel to clean up.
14859 +void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
14861 + dwc_otg_hc_regs_t *hc_regs;
14863 + hc->xfer_started = 0;
14866 + * Clear channel interrupt enables and any unhandled channel interrupt
14869 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
14870 + dwc_write_reg32(&hc_regs->hcintmsk, 0);
14871 + dwc_write_reg32(&hc_regs->hcint, 0xFFFFFFFF);
14873 + DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]);
14878 + * Sets the channel property that indicates in which frame a periodic transfer
14879 + * should occur. This is always set to the _next_ frame. This function has no
14880 + * effect on non-periodic transfers.
14882 + * @param core_if Programming view of DWC_otg controller.
14883 + * @param hc Identifies the host channel to set up and its properties.
14884 + * @param hcchar Current value of the HCCHAR register for the specified host
14887 +static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if,
14888 + dwc_hc_t * hc, hcchar_data_t * hcchar)
14890 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
14891 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
14892 + hfnum_data_t hfnum;
14894 + dwc_read_reg32(&core_if->host_if->host_global_regs->hfnum);
14896 + /* 1 if _next_ frame is odd, 0 if it's even */
14897 + hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
14899 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
14900 + && !hc->complete_split) {
14901 + switch (hfnum.b.frnum & 0x7) {
14903 + core_if->hfnum_7_samples++;
14904 + core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
14907 + core_if->hfnum_0_samples++;
14908 + core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
14911 + core_if->hfnum_other_samples++;
14912 + core_if->hfnum_other_frrem_accum +=
14922 +void hc_xfer_timeout(void *ptr)
14924 + hc_xfer_info_t *xfer_info = (hc_xfer_info_t *) ptr;
14925 + int hc_num = xfer_info->hc->hc_num;
14926 + DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
14927 + DWC_WARN(" start_hcchar_val 0x%08x\n",
14928 + xfer_info->core_if->start_hcchar_val[hc_num]);
14932 +void set_pid_isoc(dwc_hc_t * hc)
14934 + /* Set up the initial PID for the transfer. */
14935 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
14936 + if (hc->ep_is_in) {
14937 + if (hc->multi_count == 1) {
14938 + hc->data_pid_start =
14939 + DWC_OTG_HC_PID_DATA0;
14940 + } else if (hc->multi_count == 2) {
14941 + hc->data_pid_start =
14942 + DWC_OTG_HC_PID_DATA1;
14944 + hc->data_pid_start =
14945 + DWC_OTG_HC_PID_DATA2;
14948 + if (hc->multi_count == 1) {
14949 + hc->data_pid_start =
14950 + DWC_OTG_HC_PID_DATA0;
14952 + hc->data_pid_start =
14953 + DWC_OTG_HC_PID_MDATA;
14957 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
14962 + * This function does the setup for a data transfer for a host channel and
14963 + * starts the transfer. May be called in either Slave mode or DMA mode. In
14964 + * Slave mode, the caller must ensure that there is sufficient space in the
14965 + * request queue and Tx Data FIFO.
14967 + * For an OUT transfer in Slave mode, it loads a data packet into the
14968 + * appropriate FIFO. If necessary, additional data packets will be loaded in
14971 + * For an IN transfer in Slave mode, a data packet is requested. The data
14972 + * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
14973 + * additional data packets are requested in the Host ISR.
14975 + * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
14976 + * register along with a packet count of 1 and the channel is enabled. This
14977 + * causes a single PING transaction to occur. Other fields in HCTSIZ are
14978 + * simply set to 0 since no data transfer occurs in this case.
14980 + * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
14981 + * all the information required to perform the subsequent data transfer. In
14982 + * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
14983 + * controller performs the entire PING protocol, then starts the data
14986 + * @param core_if Programming view of DWC_otg controller.
14987 + * @param hc Information needed to initialize the host channel. The xfer_len
14988 + * value may be reduced to accommodate the max widths of the XferSize and
14989 + * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
14990 + * to reflect the final xfer_len value.
14992 +void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
14994 + hcchar_data_t hcchar;
14995 + hctsiz_data_t hctsiz;
14996 + uint16_t num_packets;
14997 + uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
14998 + uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
14999 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
15003 + if (hc->do_ping) {
15004 + if (!core_if->dma_enable) {
15005 + dwc_otg_hc_do_ping(core_if, hc);
15006 + hc->xfer_started = 1;
15009 + hctsiz.b.dopng = 1;
15013 + if (hc->do_split) {
15016 + if (hc->complete_split && !hc->ep_is_in) {
15017 + /* For CSPLIT OUT Transfer, set the size to 0 so the
15018 + * core doesn't expect any data written to the FIFO */
15019 + hc->xfer_len = 0;
15020 + } else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
15021 + hc->xfer_len = hc->max_packet;
15022 + } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
15023 + hc->xfer_len = 188;
15026 + hctsiz.b.xfersize = hc->xfer_len;
15029 + * Ensure that the transfer length and packet count will fit
15030 + * in the widths allocated for them in the HCTSIZn register.
15032 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
15033 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
15035 + * Make sure the transfer size is no larger than one
15036 + * (micro)frame's worth of data. (A check was done
15037 + * when the periodic transfer was accepted to ensure
15038 + * that a (micro)frame's worth of data can be
15039 + * programmed into a channel.)
15041 + uint32_t max_periodic_len =
15042 + hc->multi_count * hc->max_packet;
15043 + if (hc->xfer_len > max_periodic_len) {
15044 + hc->xfer_len = max_periodic_len;
15047 + } else if (hc->xfer_len > max_hc_xfer_size) {
15048 + /* Make sure that xfer_len is a multiple of max packet size. */
15049 + hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
15052 + if (hc->xfer_len > 0) {
15054 + (hc->xfer_len + hc->max_packet -
15055 + 1) / hc->max_packet;
15056 + if (num_packets > max_hc_pkt_count) {
15057 + num_packets = max_hc_pkt_count;
15058 + hc->xfer_len = num_packets * hc->max_packet;
15061 + /* Need 1 packet for transfer length of 0. */
15065 + if (hc->ep_is_in) {
15066 + /* Always program an integral # of max packets for IN transfers. */
15067 + hc->xfer_len = num_packets * hc->max_packet;
15070 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
15071 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
15073 + * Make sure that the multi_count field matches the
15074 + * actual transfer length.
15076 + hc->multi_count = num_packets;
15079 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
15080 + set_pid_isoc(hc);
15082 + hctsiz.b.xfersize = hc->xfer_len;
15085 + hc->start_pkt_count = num_packets;
15086 + hctsiz.b.pktcnt = num_packets;
15087 + hctsiz.b.pid = hc->data_pid_start;
15088 + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
15090 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
15091 + DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize);
15092 + DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt);
15093 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
15095 + if (core_if->dma_enable) {
15096 + dwc_dma_t dma_addr;
15097 + if (hc->align_buff) {
15098 + dma_addr = hc->align_buff;
15100 + dma_addr = (uint32_t)hc->xfer_buff;
15102 + dwc_write_reg32(&hc_regs->hcdma, dma_addr);
15105 + /* Start the split */
15106 + if (hc->do_split) {
15107 + hcsplt_data_t hcsplt;
15108 + hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
15109 + hcsplt.b.spltena = 1;
15110 + dwc_write_reg32(&hc_regs->hcsplt, hcsplt.d32);
15113 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
15114 + hcchar.b.multicnt = hc->multi_count;
15115 + hc_set_even_odd_frame(core_if, hc, &hcchar);
15117 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
15118 + if (hcchar.b.chdis) {
15119 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
15120 + __func__, hc->hc_num, hcchar.d32);
15124 + /* Set host channel enable after all other setup is complete. */
15125 + hcchar.b.chen = 1;
15126 + hcchar.b.chdis = 0;
15127 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
15129 + hc->xfer_started = 1;
15132 + if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
15133 + /* Load OUT packet into the appropriate Tx FIFO. */
15134 + dwc_otg_hc_write_packet(core_if, hc);
15137 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
15138 + DWC_DEBUGPL(DBG_HCDV, "transfer %d from core_if %p\n",
15139 + hc->hc_num, core_if);//GRAYG
15140 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
15141 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
15142 + /* Start a timer for this transfer. */
15143 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
15149 + * This function does the setup for a data transfer for a host channel
15150 + * and starts the transfer in Descriptor DMA mode.
15152 + * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
15153 + * Sets PID and NTD values. For periodic transfers
15154 + * initializes SCHED_INFO field with micro-frame bitmap.
15156 + * Initializes HCDMA register with descriptor list address and CTD value
15157 + * then starts the transfer via enabling the channel.
15159 + * @param core_if Programming view of DWC_otg controller.
15160 + * @param hc Information needed to initialize the host channel.
15162 +void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
15164 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
15165 + hcchar_data_t hcchar;
15166 + hctsiz_data_t hctsiz;
15167 + hcdma_data_t hcdma;
15171 + if (hc->do_ping && !hc->ep_is_in)
15172 + hctsiz.b_ddma.dopng = 1;
15174 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
15175 + set_pid_isoc(hc);
15177 + /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
15178 + hctsiz.b_ddma.pid = hc->data_pid_start;
15179 + hctsiz.b_ddma.ntd = hc->ntd - 1; /* 0 - 1 descriptor, 1 - 2 descriptors, etc. */
15180 + hctsiz.b_ddma.schinfo = hc->schinfo; /* Non-zero only for high-speed interrupt endpoints */
15182 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
15183 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
15184 + DWC_DEBUGPL(DBG_HCDV, " NTD: %d\n", hctsiz.b_ddma.ntd);
15186 + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
15189 + hcdma.b.dma_addr = ((uint32_t)hc->desc_list_addr) >> 11;
15191 + /* Always start from first descriptor. */
15193 + dwc_write_reg32(&hc_regs->hcdma, hcdma.d32);
15195 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
15196 + hcchar.b.multicnt = hc->multi_count;
15199 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
15200 + if (hcchar.b.chdis) {
15201 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
15202 + __func__, hc->hc_num, hcchar.d32);
15206 + /* Set host channel enable after all other setup is complete. */
15207 + hcchar.b.chen = 1;
15208 + hcchar.b.chdis = 0;
15210 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
15212 + hc->xfer_started = 1;
15216 + if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR) && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) {
15217 + DWC_DEBUGPL(DBG_HCDV, "DMA transfer %d from core_if %p\n",
15218 + hc->hc_num, core_if);//GRAYG
15219 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
15220 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
15221 + /* Start a timer for this transfer. */
15222 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
15230 + * This function continues a data transfer that was started by previous call
15231 + * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
15232 + * sufficient space in the request queue and Tx Data FIFO. This function
15233 + * should only be called in Slave mode. In DMA mode, the controller acts
15234 + * autonomously to complete transfers programmed to a host channel.
15236 + * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
15237 + * if there is any data remaining to be queued. For an IN transfer, another
15238 + * data packet is always requested. For the SETUP phase of a control transfer,
15239 + * this function does nothing.
15241 + * @return 1 if a new request is queued, 0 if no more requests are required
15242 + * for this transfer.
15244 +int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
15246 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
15248 + if (hc->do_split) {
15249 + /* SPLITs always queue just once per channel */
15251 + } else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
15252 + /* SETUPs are queued only once since they can't be NAKed. */
15254 + } else if (hc->ep_is_in) {
15256 + * Always queue another request for other IN transfers. If
15257 + * back-to-back INs are issued and NAKs are received for both,
15258 + * the driver may still be processing the first NAK when the
15259 + * second NAK is received. When the interrupt handler clears
15260 + * the NAK interrupt for the first NAK, the second NAK will
15261 + * not be seen. So we can't depend on the NAK interrupt
15262 + * handler to requeue a NAKed request. Instead, IN requests
15263 + * are issued each time this function is called. When the
15264 + * transfer completes, the extra requests for the channel will
15267 + hcchar_data_t hcchar;
15268 + dwc_otg_hc_regs_t *hc_regs =
15269 + core_if->host_if->hc_regs[hc->hc_num];
15271 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
15272 + hc_set_even_odd_frame(core_if, hc, &hcchar);
15273 + hcchar.b.chen = 1;
15274 + hcchar.b.chdis = 0;
15275 + DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n",
15277 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
15281 + /* OUT transfers. */
15282 + if (hc->xfer_count < hc->xfer_len) {
15283 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
15284 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
15285 + hcchar_data_t hcchar;
15286 + dwc_otg_hc_regs_t *hc_regs;
15287 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
15288 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
15289 + hc_set_even_odd_frame(core_if, hc, &hcchar);
15292 + /* Load OUT packet into the appropriate Tx FIFO. */
15293 + dwc_otg_hc_write_packet(core_if, hc);
15303 + * Starts a PING transfer. This function should only be called in Slave mode.
15304 + * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
15306 +void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
15308 + hcchar_data_t hcchar;
15309 + hctsiz_data_t hctsiz;
15310 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
15312 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
15315 + hctsiz.b.dopng = 1;
15316 + hctsiz.b.pktcnt = 1;
15317 + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
15319 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
15320 + hcchar.b.chen = 1;
15321 + hcchar.b.chdis = 0;
15322 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
15326 + * This function writes a packet into the Tx FIFO associated with the Host
15327 + * Channel. For a channel associated with a non-periodic EP, the non-periodic
15328 + * Tx FIFO is written. For a channel associated with a periodic EP, the
15329 + * periodic Tx FIFO is written. This function should only be called in Slave
15332 + * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
15333 + * then number of bytes written to the Tx FIFO.
15335 +void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
15338 + uint32_t remaining_count;
15339 + uint32_t byte_count;
15340 + uint32_t dword_count;
15342 + uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
15343 + uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
15345 + remaining_count = hc->xfer_len - hc->xfer_count;
15346 + if (remaining_count > hc->max_packet) {
15347 + byte_count = hc->max_packet;
15349 + byte_count = remaining_count;
15352 + dword_count = (byte_count + 3) / 4;
15354 + if ((((unsigned long)data_buff) & 0x3) == 0) {
15355 + /* xfer_buff is DWORD aligned. */
15356 + for (i = 0; i < dword_count; i++, data_buff++) {
15357 + dwc_write_reg32(data_fifo, *data_buff);
15360 + /* xfer_buff is not DWORD aligned. */
15361 + for (i = 0; i < dword_count; i++, data_buff++) {
15364 + (data_buff[0] | data_buff[1] << 8 | data_buff[2] <<
15365 + 16 | data_buff[3] << 24);
15366 + dwc_write_reg32(data_fifo, data);
15370 + hc->xfer_count += byte_count;
15371 + hc->xfer_buff += byte_count;
15375 + * Gets the current USB frame number. This is the frame number from the last
15378 +uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if)
15380 + dsts_data_t dsts;
15381 + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
15383 + /* read current frame/microframe number from DSTS register */
15384 + return dsts.b.soffn;
15388 + * This function reads a setup packet from the Rx FIFO into the destination
15389 + * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl)
15390 + * Interrupt routine when a SETUP packet has been received in Slave mode.
15392 + * @param core_if Programming view of DWC_otg controller.
15393 + * @param dest Destination buffer for packet data.
15395 +void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest)
15397 + /* Get the 8 bytes of a setup transaction data */
15399 + /* Pop 2 DWORDS off the receive data FIFO into memory */
15400 + dest[0] = dwc_read_reg32(core_if->data_fifo[0]);
15401 + dest[1] = dwc_read_reg32(core_if->data_fifo[0]);
15405 + * This function enables EP0 OUT to receive SETUP packets and configures EP0
15406 + * IN for transmitting packets. It is normally called when the
15407 + * "Enumeration Done" interrupt occurs.
15409 + * @param core_if Programming view of DWC_otg controller.
15410 + * @param ep The EP0 data.
15412 +void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
15414 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
15415 + dsts_data_t dsts;
15416 + depctl_data_t diepctl;
15417 + depctl_data_t doepctl;
15418 + dctl_data_t dctl = {.d32 = 0 };
15420 + /* Read the Device Status and Endpoint 0 Control registers */
15421 + dsts.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dsts);
15422 + diepctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl);
15423 + doepctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl);
15425 + /* Set the MPS of the IN EP based on the enumeration speed */
15426 + switch (dsts.b.enumspd) {
15427 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
15428 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
15429 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
15430 + diepctl.b.mps = DWC_DEP0CTL_MPS_64;
15432 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
15433 + diepctl.b.mps = DWC_DEP0CTL_MPS_8;
15437 + dwc_write_reg32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
15439 + /* Enable OUT EP for receive */
15440 + doepctl.b.epena = 1;
15441 + dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
15444 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
15445 + dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
15446 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
15447 + dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl));
15449 + dctl.b.cgnpinnak = 1;
15451 + dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
15452 + DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
15453 + dwc_read_reg32(&dev_if->dev_global_regs->dctl));
15457 + * This function activates an EP. The Device EP control register for
15458 + * the EP is configured as defined in the ep structure. Note: This
15459 + * function is not used for EP0.
15461 + * @param core_if Programming view of DWC_otg controller.
15462 + * @param ep The EP to activate.
15464 +void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
15466 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
15467 + depctl_data_t depctl;
15468 + volatile uint32_t *addr;
15469 + daint_data_t daintmsk = {.d32 = 0 };
15471 + DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
15472 + (ep->is_in ? "IN" : "OUT"));
15474 + /* Read DEPCTLn register */
15475 + if (ep->is_in == 1) {
15476 + addr = &dev_if->in_ep_regs[ep->num]->diepctl;
15477 + daintmsk.ep.in = 1 << ep->num;
15479 + addr = &dev_if->out_ep_regs[ep->num]->doepctl;
15480 + daintmsk.ep.out = 1 << ep->num;
15483 + /* If the EP is already active don't change the EP Control
15485 + depctl.d32 = dwc_read_reg32(addr);
15486 + if (!depctl.b.usbactep) {
15487 + depctl.b.mps = ep->maxpacket;
15488 + depctl.b.eptype = ep->type;
15489 + depctl.b.txfnum = ep->tx_fifo_num;
15491 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
15492 + depctl.b.setd0pid = 1; // ???
15494 + depctl.b.setd0pid = 1;
15496 + depctl.b.usbactep = 1;
15498 + dwc_write_reg32(addr, depctl.d32);
15499 + DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", dwc_read_reg32(addr));
15502 + /* Enable the Interrupt for this EP */
15503 + if (core_if->multiproc_int_enable) {
15504 + if (ep->is_in == 1) {
15505 + diepmsk_data_t diepmsk = {.d32 = 0 };
15506 + diepmsk.b.xfercompl = 1;
15507 + diepmsk.b.timeout = 1;
15508 + diepmsk.b.epdisabled = 1;
15509 + diepmsk.b.ahberr = 1;
15510 + diepmsk.b.intknepmis = 1;
15511 + diepmsk.b.txfifoundrn = 1; //?????
15513 + if (core_if->dma_desc_enable) {
15514 + diepmsk.b.bna = 1;
15517 + if(core_if->dma_enable) {
15518 + doepmsk.b.nak = 1;
15521 + dwc_write_reg32(&dev_if->dev_global_regs->
15522 + diepeachintmsk[ep->num], diepmsk.d32);
15525 + doepmsk_data_t doepmsk = {.d32 = 0 };
15526 + doepmsk.b.xfercompl = 1;
15527 + doepmsk.b.ahberr = 1;
15528 + doepmsk.b.epdisabled = 1;
15530 + if (core_if->dma_desc_enable) {
15531 + doepmsk.b.bna = 1;
15534 + doepmsk.b.babble = 1;
15535 + doepmsk.b.nyet = 1;
15536 + doepmsk.b.nak = 1;
15538 + dwc_write_reg32(&dev_if->dev_global_regs->
15539 + doepeachintmsk[ep->num], doepmsk.d32);
15541 + dwc_modify_reg32(&dev_if->dev_global_regs->deachintmsk,
15542 + 0, daintmsk.d32);
15544 + dwc_modify_reg32(&dev_if->dev_global_regs->daintmsk,
15545 + 0, daintmsk.d32);
15548 + DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
15549 + dwc_read_reg32(&dev_if->dev_global_regs->daintmsk));
15551 + ep->stall_clear_flag = 0;
15556 + * This function deactivates an EP. This is done by clearing the USB Active
15557 + * EP bit in the Device EP control register. Note: This function is not used
15558 + * for EP0. EP0 cannot be deactivated.
15560 + * @param core_if Programming view of DWC_otg controller.
15561 + * @param ep The EP to deactivate.
15563 +void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
15565 + depctl_data_t depctl = {.d32 = 0 };
15566 + volatile uint32_t *addr;
15567 + daint_data_t daintmsk = {.d32 = 0 };
15569 + /* Read DEPCTLn register */
15570 + if (ep->is_in == 1) {
15571 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
15572 + daintmsk.ep.in = 1 << ep->num;
15574 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
15575 + daintmsk.ep.out = 1 << ep->num;
15578 + depctl.d32 = dwc_read_reg32(addr);
15580 + depctl.b.usbactep = 0;
15582 + if (core_if->dma_desc_enable)
15583 + depctl.b.epdis = 1;
15585 + dwc_write_reg32(addr, depctl.d32);
15587 + /* Disable the Interrupt for this EP */
15588 + if (core_if->multiproc_int_enable) {
15589 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->deachintmsk,
15590 + daintmsk.d32, 0);
15592 + if (ep->is_in == 1) {
15593 + dwc_write_reg32(&core_if->dev_if->dev_global_regs->
15594 + diepeachintmsk[ep->num], 0);
15596 + dwc_write_reg32(&core_if->dev_if->dev_global_regs->
15597 + doepeachintmsk[ep->num], 0);
15600 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->daintmsk,
15601 + daintmsk.d32, 0);
15606 + * This function initializes dma descriptor chain.
15608 + * @param core_if Programming view of DWC_otg controller.
15609 + * @param ep The EP to start the transfer on.
15611 +static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
15613 + dwc_otg_dev_dma_desc_t *dma_desc;
15615 + uint32_t xfer_est;
15618 + ep->desc_cnt = (ep->total_len / ep->maxxfer) +
15619 + ((ep->total_len % ep->maxxfer) ? 1 : 0);
15620 + if (!ep->desc_cnt)
15621 + ep->desc_cnt = 1;
15623 + dma_desc = ep->desc_addr;
15624 + xfer_est = ep->total_len;
15626 + for (i = 0; i < ep->desc_cnt; ++i) {
15627 + /** DMA Descriptor Setup */
15628 + if (xfer_est > ep->maxxfer) {
15629 + dma_desc->status.b.bs = BS_HOST_BUSY;
15630 + dma_desc->status.b.l = 0;
15631 + dma_desc->status.b.ioc = 0;
15632 + dma_desc->status.b.sp = 0;
15633 + dma_desc->status.b.bytes = ep->maxxfer;
15634 + dma_desc->buf = ep->dma_addr + offset;
15635 + dma_desc->status.b.bs = BS_HOST_READY;
15637 + xfer_est -= ep->maxxfer;
15638 + offset += ep->maxxfer;
15640 + dma_desc->status.b.bs = BS_HOST_BUSY;
15641 + dma_desc->status.b.l = 1;
15642 + dma_desc->status.b.ioc = 1;
15644 + dma_desc->status.b.sp =
15646 + ep->maxpacket) ? 1 : ((ep->
15647 + sent_zlp) ? 1 : 0);
15648 + dma_desc->status.b.bytes = xfer_est;
15650 + dma_desc->status.b.bytes =
15651 + xfer_est + ((4 - (xfer_est & 0x3)) & 0x3);
15654 + dma_desc->buf = ep->dma_addr + offset;
15655 + dma_desc->status.b.bs = BS_HOST_READY;
15662 + * This function does the setup for a data transfer for an EP and
15663 + * starts the transfer. For an IN transfer, the packets will be
15664 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
15665 + * the packets are unloaded from the Rx FIFO in the ISR. the ISR.
15667 + * @param core_if Programming view of DWC_otg controller.
15668 + * @param ep The EP to start the transfer on.
15671 +void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
15673 + depctl_data_t depctl;
15674 + deptsiz_data_t deptsiz;
15675 + gintmsk_data_t intr_mask = {.d32 = 0 };
15677 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
15678 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
15679 + "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n",
15680 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
15681 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
15683 + /* IN endpoint */
15684 + if (ep->is_in == 1) {
15685 + dwc_otg_dev_in_ep_regs_t *in_regs =
15686 + core_if->dev_if->in_ep_regs[ep->num];
15688 + gnptxsts_data_t gtxstatus;
15691 + dwc_read_reg32(&core_if->core_global_regs->gnptxsts);
15693 + if (core_if->en_multiple_tx_fifo == 0
15694 + && gtxstatus.b.nptxqspcavail == 0) {
15696 + DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32);
15701 + depctl.d32 = dwc_read_reg32(&(in_regs->diepctl));
15702 + deptsiz.d32 = dwc_read_reg32(&(in_regs->dieptsiz));
15704 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
15705 + ep->maxxfer : (ep->total_len - ep->xfer_len);
15707 + /* Zero Length Packet? */
15708 + if ((ep->xfer_len - ep->xfer_count) == 0) {
15709 + deptsiz.b.xfersize = 0;
15710 + deptsiz.b.pktcnt = 1;
15712 + /* Program the transfer size and packet count
15713 + * as follows: xfersize = N * maxpacket +
15714 + * short_packet pktcnt = N + (short_packet
15717 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
15718 + deptsiz.b.pktcnt =
15719 + (ep->xfer_len - ep->xfer_count - 1 +
15720 + ep->maxpacket) / ep->maxpacket;
15723 + /* Write the DMA register */
15724 + if (core_if->dma_enable) {
15725 + if (core_if->dma_desc_enable == 0) {
15726 + dwc_write_reg32(&in_regs->dieptsiz,
15728 + dwc_write_reg32(&(in_regs->diepdma),
15729 + (uint32_t) ep->dma_addr);
15731 +#ifdef DWC_UTE_CFI
15732 + /* The descriptor chain should be already initialized by now */
15733 + if (ep->buff_mode != BM_STANDARD) {
15734 + dwc_write_reg32(&in_regs->diepdma,
15735 + ep->descs_dma_addr);
15738 + init_dma_desc_chain(core_if, ep);
15739 + /** DIEPDMAn Register write */
15740 + dwc_write_reg32(&in_regs->diepdma,
15741 + ep->dma_desc_addr);
15742 +#ifdef DWC_UTE_CFI
15747 + dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
15748 + if (ep->type != DWC_OTG_EP_TYPE_ISOC) {
15750 + * Enable the Non-Periodic Tx FIFO empty interrupt,
15751 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
15752 + * the data will be written into the fifo by the ISR.
15754 + if (core_if->en_multiple_tx_fifo == 0) {
15755 + intr_mask.b.nptxfempty = 1;
15756 + dwc_modify_reg32(&core_if->
15757 + core_global_regs->
15758 + gintmsk, intr_mask.d32,
15761 + /* Enable the Tx FIFO Empty Interrupt for this EP */
15762 + if (ep->xfer_len > 0) {
15763 + uint32_t fifoemptymsk = 0;
15764 + fifoemptymsk = 1 << ep->num;
15765 + dwc_modify_reg32(&core_if->
15767 + dev_global_regs->
15768 + dtknqr4_fifoemptymsk,
15777 + /* EP enable, IN data in FIFO */
15778 + depctl.b.cnak = 1;
15779 + depctl.b.epena = 1;
15780 + dwc_write_reg32(&in_regs->diepctl, depctl.d32);
15783 + dwc_read_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl);
15784 + depctl.b.nextep = ep->num;
15785 + dwc_write_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl,
15789 + /* OUT endpoint */
15790 + dwc_otg_dev_out_ep_regs_t *out_regs =
15791 + core_if->dev_if->out_ep_regs[ep->num];
15793 + depctl.d32 = dwc_read_reg32(&(out_regs->doepctl));
15794 + deptsiz.d32 = dwc_read_reg32(&(out_regs->doeptsiz));
15796 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
15797 + ep->maxxfer : (ep->total_len - ep->xfer_len);
15799 + /* Program the transfer size and packet count as follows:
15802 + * xfersize = N * maxpacket
15804 + if ((ep->xfer_len - ep->xfer_count) == 0) {
15805 + /* Zero Length Packet */
15806 + deptsiz.b.xfersize = ep->maxpacket;
15807 + deptsiz.b.pktcnt = 1;
15809 + deptsiz.b.pktcnt =
15810 + (ep->xfer_len - ep->xfer_count +
15811 + (ep->maxpacket - 1)) / ep->maxpacket;
15813 + deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count;
15814 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
15817 + DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
15818 + ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
15820 + if (core_if->dma_enable) {
15821 + if (!core_if->dma_desc_enable) {
15822 + dwc_write_reg32(&out_regs->doeptsiz,
15825 + dwc_write_reg32(&(out_regs->doepdma),
15826 + (uint32_t) ep->dma_addr);
15828 +#ifdef DWC_UTE_CFI
15829 + /* The descriptor chain should be already initialized by now */
15830 + if (ep->buff_mode != BM_STANDARD) {
15831 + dwc_write_reg32(&out_regs->doepdma,
15832 + ep->descs_dma_addr);
15836 + init_dma_desc_chain(core_if, ep);
15838 + /** DOEPDMAn Register write */
15839 + dwc_write_reg32(&out_regs->doepdma,
15840 + ep->dma_desc_addr);
15841 +#ifdef DWC_UTE_CFI
15846 + dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
15850 + depctl.b.cnak = 1;
15851 + depctl.b.epena = 1;
15853 + dwc_write_reg32(&out_regs->doepctl, depctl.d32);
15855 + DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
15856 + dwc_read_reg32(&out_regs->doepctl),
15857 + dwc_read_reg32(&out_regs->doeptsiz));
15858 + DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
15859 + dwc_read_reg32(&core_if->dev_if->dev_global_regs->
15861 + dwc_read_reg32(&core_if->core_global_regs->
15867 + * This function setup a zero length transfer in Buffer DMA and
15868 + * Slave modes for usb requests with zero field set
15870 + * @param core_if Programming view of DWC_otg controller.
15871 + * @param ep The EP to start the transfer on.
15874 +void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
15877 + depctl_data_t depctl;
15878 + deptsiz_data_t deptsiz;
15879 + gintmsk_data_t intr_mask = {.d32 = 0 };
15881 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
15882 + DWC_PRINTF("zero length transfer is called\n");
15884 + /* IN endpoint */
15885 + if (ep->is_in == 1) {
15886 + dwc_otg_dev_in_ep_regs_t *in_regs =
15887 + core_if->dev_if->in_ep_regs[ep->num];
15889 + depctl.d32 = dwc_read_reg32(&(in_regs->diepctl));
15890 + deptsiz.d32 = dwc_read_reg32(&(in_regs->dieptsiz));
15892 + deptsiz.b.xfersize = 0;
15893 + deptsiz.b.pktcnt = 1;
15895 + /* Write the DMA register */
15896 + if (core_if->dma_enable) {
15897 + if (core_if->dma_desc_enable == 0) {
15898 + dwc_write_reg32(&in_regs->dieptsiz,
15900 + dwc_write_reg32(&(in_regs->diepdma),
15901 + (uint32_t) ep->dma_addr);
15904 + dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
15906 + * Enable the Non-Periodic Tx FIFO empty interrupt,
15907 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
15908 + * the data will be written into the fifo by the ISR.
15910 + if (core_if->en_multiple_tx_fifo == 0) {
15911 + intr_mask.b.nptxfempty = 1;
15912 + dwc_modify_reg32(&core_if->core_global_regs->
15913 + gintmsk, intr_mask.d32,
15916 + /* Enable the Tx FIFO Empty Interrupt for this EP */
15917 + if (ep->xfer_len > 0) {
15918 + uint32_t fifoemptymsk = 0;
15919 + fifoemptymsk = 1 << ep->num;
15920 + dwc_modify_reg32(&core_if->dev_if->
15921 + dev_global_regs->
15922 + dtknqr4_fifoemptymsk,
15923 + 0, fifoemptymsk);
15928 + /* EP enable, IN data in FIFO */
15929 + depctl.b.cnak = 1;
15930 + depctl.b.epena = 1;
15931 + dwc_write_reg32(&in_regs->diepctl, depctl.d32);
15934 + dwc_read_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl);
15935 + depctl.b.nextep = ep->num;
15936 + dwc_write_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl,
15940 + /* OUT endpoint */
15941 + dwc_otg_dev_out_ep_regs_t *out_regs =
15942 + core_if->dev_if->out_ep_regs[ep->num];
15944 + depctl.d32 = dwc_read_reg32(&(out_regs->doepctl));
15945 + deptsiz.d32 = dwc_read_reg32(&(out_regs->doeptsiz));
15947 + /* Zero Length Packet */
15948 + deptsiz.b.xfersize = ep->maxpacket;
15949 + deptsiz.b.pktcnt = 1;
15951 + if (core_if->dma_enable) {
15952 + if (!core_if->dma_desc_enable) {
15953 + dwc_write_reg32(&out_regs->doeptsiz,
15956 + dwc_write_reg32(&(out_regs->doepdma),
15957 + (uint32_t) ep->dma_addr);
15960 + dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
15964 + depctl.b.cnak = 1;
15965 + depctl.b.epena = 1;
15967 + dwc_write_reg32(&out_regs->doepctl, depctl.d32);
15973 + * This function does the setup for a data transfer for EP0 and starts
15974 + * the transfer. For an IN transfer, the packets will be loaded into
15975 + * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
15976 + * unloaded from the Rx FIFO in the ISR.
15978 + * @param core_if Programming view of DWC_otg controller.
15979 + * @param ep The EP0 data.
15981 +void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
15983 + depctl_data_t depctl;
15984 + deptsiz0_data_t deptsiz;
15985 + gintmsk_data_t intr_mask = {.d32 = 0 };
15986 + dwc_otg_dev_dma_desc_t *dma_desc;
15988 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
15989 + "xfer_buff=%p start_xfer_buff=%p \n",
15990 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
15991 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
15993 + ep->total_len = ep->xfer_len;
15995 + /* IN endpoint */
15996 + if (ep->is_in == 1) {
15997 + dwc_otg_dev_in_ep_regs_t *in_regs =
15998 + core_if->dev_if->in_ep_regs[0];
16000 + gnptxsts_data_t gtxstatus;
16003 + dwc_read_reg32(&core_if->core_global_regs->gnptxsts);
16005 + if (core_if->en_multiple_tx_fifo == 0
16006 + && gtxstatus.b.nptxqspcavail == 0) {
16008 + deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
16009 + DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
16010 + dwc_read_reg32(&in_regs->diepctl));
16011 + DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
16013 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
16014 + DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n",
16020 + depctl.d32 = dwc_read_reg32(&in_regs->diepctl);
16021 + deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
16023 + /* Zero Length Packet? */
16024 + if (ep->xfer_len == 0) {
16025 + deptsiz.b.xfersize = 0;
16026 + deptsiz.b.pktcnt = 1;
16028 + /* Program the transfer size and packet count
16029 + * as follows: xfersize = N * maxpacket +
16030 + * short_packet pktcnt = N + (short_packet
16033 + if (ep->xfer_len > ep->maxpacket) {
16034 + ep->xfer_len = ep->maxpacket;
16035 + deptsiz.b.xfersize = ep->maxpacket;
16037 + deptsiz.b.xfersize = ep->xfer_len;
16039 + deptsiz.b.pktcnt = 1;
16042 + DWC_DEBUGPL(DBG_PCDV,
16043 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
16044 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
16047 + /* Write the DMA register */
16048 + if (core_if->dma_enable) {
16049 + if (core_if->dma_desc_enable == 0) {
16050 + dwc_write_reg32(&in_regs->dieptsiz,
16053 + dwc_write_reg32(&(in_regs->diepdma),
16054 + (uint32_t) ep->dma_addr);
16056 + dma_desc = core_if->dev_if->in_desc_addr;
16058 + /** DMA Descriptor Setup */
16059 + dma_desc->status.b.bs = BS_HOST_BUSY;
16060 + dma_desc->status.b.l = 1;
16061 + dma_desc->status.b.ioc = 1;
16062 + dma_desc->status.b.sp =
16063 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
16064 + dma_desc->status.b.bytes = ep->xfer_len;
16065 + dma_desc->buf = ep->dma_addr;
16066 + dma_desc->status.b.bs = BS_HOST_READY;
16068 + /** DIEPDMA0 Register write */
16069 + dwc_write_reg32(&in_regs->diepdma,
16070 + core_if->dev_if->
16071 + dma_in_desc_addr);
16074 + dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
16077 + /* EP enable, IN data in FIFO */
16078 + depctl.b.cnak = 1;
16079 + depctl.b.epena = 1;
16080 + dwc_write_reg32(&in_regs->diepctl, depctl.d32);
16083 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
16084 + * data will be written into the fifo by the ISR.
16086 + if (!core_if->dma_enable) {
16087 + if (core_if->en_multiple_tx_fifo == 0) {
16088 + intr_mask.b.nptxfempty = 1;
16089 + dwc_modify_reg32(&core_if->core_global_regs->
16090 + gintmsk, intr_mask.d32,
16093 + /* Enable the Tx FIFO Empty Interrupt for this EP */
16094 + if (ep->xfer_len > 0) {
16095 + uint32_t fifoemptymsk = 0;
16096 + fifoemptymsk |= 1 << ep->num;
16097 + dwc_modify_reg32(&core_if->dev_if->
16098 + dev_global_regs->
16099 + dtknqr4_fifoemptymsk,
16100 + 0, fifoemptymsk);
16105 + /* OUT endpoint */
16106 + dwc_otg_dev_out_ep_regs_t *out_regs =
16107 + core_if->dev_if->out_ep_regs[0];
16109 + depctl.d32 = dwc_read_reg32(&out_regs->doepctl);
16110 + deptsiz.d32 = dwc_read_reg32(&out_regs->doeptsiz);
16112 + /* Program the transfer size and packet count as follows:
16113 + * xfersize = N * (maxpacket + 4 - (maxpacket % 4))
16115 + /* Zero Length Packet */
16116 + deptsiz.b.xfersize = ep->maxpacket;
16117 + deptsiz.b.pktcnt = 1;
16119 + DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n",
16120 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);
16122 + if (core_if->dma_enable) {
16123 + if (!core_if->dma_desc_enable) {
16124 + dwc_write_reg32(&out_regs->doeptsiz,
16127 + dwc_write_reg32(&(out_regs->doepdma),
16128 + (uint32_t) ep->dma_addr);
16130 + dma_desc = core_if->dev_if->out_desc_addr;
16132 + /** DMA Descriptor Setup */
16133 + dma_desc->status.b.bs = BS_HOST_BUSY;
16134 + dma_desc->status.b.l = 1;
16135 + dma_desc->status.b.ioc = 1;
16136 + dma_desc->status.b.bytes = ep->maxpacket;
16137 + dma_desc->buf = ep->dma_addr;
16138 + dma_desc->status.b.bs = BS_HOST_READY;
16140 + /** DOEPDMA0 Register write */
16141 + dwc_write_reg32(&out_regs->doepdma,
16142 + core_if->dev_if->
16143 + dma_out_desc_addr);
16146 + dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
16150 + depctl.b.cnak = 1;
16151 + depctl.b.epena = 1;
16152 + dwc_write_reg32(&(out_regs->doepctl), depctl.d32);
16157 + * This function continues control IN transfers started by
16158 + * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
16159 + * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
16160 + * bit for the packet count.
16162 + * @param core_if Programming view of DWC_otg controller.
16163 + * @param ep The EP0 data.
16165 +void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
16167 + depctl_data_t depctl;
16168 + deptsiz0_data_t deptsiz;
16169 + gintmsk_data_t intr_mask = {.d32 = 0 };
16170 + dwc_otg_dev_dma_desc_t *dma_desc;
16172 + if (ep->is_in == 1) {
16173 + dwc_otg_dev_in_ep_regs_t *in_regs =
16174 + core_if->dev_if->in_ep_regs[0];
16175 + gnptxsts_data_t tx_status = {.d32 = 0 };
16178 + dwc_read_reg32(&core_if->core_global_regs->gnptxsts);
16179 + /** @todo Should there be check for room in the Tx
16180 + * Status Queue. If not remove the code above this comment. */
16182 + depctl.d32 = dwc_read_reg32(&in_regs->diepctl);
16183 + deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
16185 + /* Program the transfer size and packet count
16186 + * as follows: xfersize = N * maxpacket +
16187 + * short_packet pktcnt = N + (short_packet
16191 + if (core_if->dma_desc_enable == 0) {
16192 + deptsiz.b.xfersize =
16193 + (ep->total_len - ep->xfer_count) >
16194 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
16196 + deptsiz.b.pktcnt = 1;
16197 + if (core_if->dma_enable == 0) {
16198 + ep->xfer_len += deptsiz.b.xfersize;
16200 + ep->xfer_len = deptsiz.b.xfersize;
16202 + dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
16205 + (ep->total_len - ep->xfer_count) >
16206 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
16209 + dma_desc = core_if->dev_if->in_desc_addr;
16211 + /** DMA Descriptor Setup */
16212 + dma_desc->status.b.bs = BS_HOST_BUSY;
16213 + dma_desc->status.b.l = 1;
16214 + dma_desc->status.b.ioc = 1;
16215 + dma_desc->status.b.sp =
16216 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
16217 + dma_desc->status.b.bytes = ep->xfer_len;
16218 + dma_desc->buf = ep->dma_addr;
16219 + dma_desc->status.b.bs = BS_HOST_READY;
16221 + /** DIEPDMA0 Register write */
16222 + dwc_write_reg32(&in_regs->diepdma,
16223 + core_if->dev_if->dma_in_desc_addr);
16226 + DWC_DEBUGPL(DBG_PCDV,
16227 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
16228 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
16231 + /* Write the DMA register */
16232 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
16233 + if (core_if->dma_desc_enable == 0)
16234 + dwc_write_reg32(&(in_regs->diepdma),
16235 + (uint32_t) ep->dma_addr);
16238 + /* EP enable, IN data in FIFO */
16239 + depctl.b.cnak = 1;
16240 + depctl.b.epena = 1;
16241 + dwc_write_reg32(&in_regs->diepctl, depctl.d32);
16244 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
16245 + * data will be written into the fifo by the ISR.
16247 + if (!core_if->dma_enable) {
16248 + if (core_if->en_multiple_tx_fifo == 0) {
16249 + /* First clear it from GINTSTS */
16250 + intr_mask.b.nptxfempty = 1;
16251 + dwc_modify_reg32(&core_if->core_global_regs->
16252 + gintmsk, intr_mask.d32,
16256 + /* Enable the Tx FIFO Empty Interrupt for this EP */
16257 + if (ep->xfer_len > 0) {
16258 + uint32_t fifoemptymsk = 0;
16259 + fifoemptymsk |= 1 << ep->num;
16260 + dwc_modify_reg32(&core_if->dev_if->
16261 + dev_global_regs->
16262 + dtknqr4_fifoemptymsk,
16263 + 0, fifoemptymsk);
16268 + dwc_otg_dev_out_ep_regs_t *out_regs =
16269 + core_if->dev_if->out_ep_regs[0];
16271 + depctl.d32 = dwc_read_reg32(&out_regs->doepctl);
16272 + deptsiz.d32 = dwc_read_reg32(&out_regs->doeptsiz);
16274 + /* Program the transfer size and packet count
16275 + * as follows: xfersize = N * maxpacket +
16276 + * short_packet pktcnt = N + (short_packet
16279 + deptsiz.b.xfersize = ep->maxpacket;
16280 + deptsiz.b.pktcnt = 1;
16282 + if (core_if->dma_desc_enable == 0) {
16283 + dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
16285 + dma_desc = core_if->dev_if->out_desc_addr;
16287 + /** DMA Descriptor Setup */
16288 + dma_desc->status.b.bs = BS_HOST_BUSY;
16289 + dma_desc->status.b.l = 1;
16290 + dma_desc->status.b.ioc = 1;
16291 + dma_desc->status.b.bytes = ep->maxpacket;
16292 + dma_desc->buf = ep->dma_addr;
16293 + dma_desc->status.b.bs = BS_HOST_READY;
16295 + /** DOEPDMA0 Register write */
16296 + dwc_write_reg32(&out_regs->doepdma,
16297 + core_if->dev_if->dma_out_desc_addr);
16300 + DWC_DEBUGPL(DBG_PCDV,
16301 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
16302 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
16305 + /* Write the DMA register */
16306 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
16307 + if (core_if->dma_desc_enable == 0)
16308 + dwc_write_reg32(&(out_regs->doepdma),
16309 + (uint32_t) ep->dma_addr);
16312 + /* EP enable, IN data in FIFO */
16313 + depctl.b.cnak = 1;
16314 + depctl.b.epena = 1;
16315 + dwc_write_reg32(&out_regs->doepctl, depctl.d32);
16321 +void dump_msg(const u8 * buf, unsigned int length)
16323 + unsigned int start, num, i;
16324 + char line[52], *p;
16326 + if (length >= 512)
16329 + while (length > 0) {
16330 + num = length < 16u ? length : 16u;
16332 + for (i = 0; i < num; ++i) {
16335 + DWC_SPRINTF(p, " %02x", buf[i]);
16339 + DWC_PRINTF("%6x: %s\n", start, line);
16346 +static inline void dump_msg(const u8 * buf, unsigned int length)
16352 + * This function writes a packet into the Tx FIFO associated with the
16353 + * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For
16354 + * periodic EPs the periodic Tx FIFO associated with the EP is written
16355 + * with all packets for the next micro-frame.
16357 + * @param core_if Programming view of DWC_otg controller.
16358 + * @param ep The EP to write packet for.
16359 + * @param dma Indicates if DMA is being used.
16361 +void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep,
16365 + * The buffer is padded to DWORD on a per packet basis in
16366 + * slave/dma mode if the MPS is not DWORD aligned. The last
16367 + * packet, if short, is also padded to a multiple of DWORD.
16369 + * ep->xfer_buff always starts DWORD aligned in memory and is a
16370 + * multiple of DWORD in length
16372 + * ep->xfer_len can be any number of bytes
16374 + * ep->xfer_count is a multiple of ep->maxpacket until the last
16377 + * FIFO access is DWORD */
16380 + uint32_t byte_count;
16381 + uint32_t dword_count;
16383 + uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
16385 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if,
16387 + if (ep->xfer_count >= ep->xfer_len) {
16388 + DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
16392 + /* Find the byte length of the packet either short packet or MPS */
16393 + if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) {
16394 + byte_count = ep->xfer_len - ep->xfer_count;
16396 + byte_count = ep->maxpacket;
16399 + /* Find the DWORD length, padded by extra bytes as neccessary if MPS
16400 + * is not a multiple of DWORD */
16401 + dword_count = (byte_count + 3) / 4;
16404 + dump_msg(ep->xfer_buff, byte_count);
16407 + /**@todo NGS Where are the Periodic Tx FIFO addresses
16408 + * intialized? What should this be? */
16410 + fifo = core_if->data_fifo[ep->num];
16412 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
16413 + fifo, data_buff, *data_buff, byte_count);
16416 + for (i = 0; i < dword_count; i++, data_buff++) {
16417 + dwc_write_reg32(fifo, *data_buff);
16421 + ep->xfer_count += byte_count;
16422 + ep->xfer_buff += byte_count;
16423 + ep->dma_addr += byte_count;
16427 + * Set the EP STALL.
16429 + * @param core_if Programming view of DWC_otg controller.
16430 + * @param ep The EP to set the stall on.
16432 +void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
16434 + depctl_data_t depctl;
16435 + volatile uint32_t *depctl_addr;
16437 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
16438 + (ep->is_in ? "IN" : "OUT"));
16440 + if (ep->is_in == 1) {
16441 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
16442 + depctl.d32 = dwc_read_reg32(depctl_addr);
16444 + /* set the disable and stall bits */
16445 + if (depctl.b.epena) {
16446 + depctl.b.epdis = 1;
16448 + depctl.b.stall = 1;
16449 + dwc_write_reg32(depctl_addr, depctl.d32);
16451 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
16452 + depctl.d32 = dwc_read_reg32(depctl_addr);
16454 + /* set the stall bit */
16455 + depctl.b.stall = 1;
16456 + dwc_write_reg32(depctl_addr, depctl.d32);
16459 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", dwc_read_reg32(depctl_addr));
16465 + * Clear the EP STALL.
16467 + * @param core_if Programming view of DWC_otg controller.
16468 + * @param ep The EP to clear stall from.
16470 +void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
16472 + depctl_data_t depctl;
16473 + volatile uint32_t *depctl_addr;
16475 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
16476 + (ep->is_in ? "IN" : "OUT"));
16478 + if (ep->is_in == 1) {
16479 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
16481 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
16484 + depctl.d32 = dwc_read_reg32(depctl_addr);
16486 + /* clear the stall bits */
16487 + depctl.b.stall = 0;
16490 + * USB Spec 9.4.5: For endpoints using data toggle, regardless
16491 + * of whether an endpoint has the Halt feature set, a
16492 + * ClearFeature(ENDPOINT_HALT) request always results in the
16493 + * data toggle being reinitialized to DATA0.
16495 + if (ep->type == DWC_OTG_EP_TYPE_INTR ||
16496 + ep->type == DWC_OTG_EP_TYPE_BULK) {
16497 + depctl.b.setd0pid = 1; /* DATA0 */
16500 + dwc_write_reg32(depctl_addr, depctl.d32);
16501 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", dwc_read_reg32(depctl_addr));
16506 + * This function reads a packet from the Rx FIFO into the destination
16507 + * buffer. To read SETUP data use dwc_otg_read_setup_packet.
16509 + * @param core_if Programming view of DWC_otg controller.
16510 + * @param dest Destination buffer for the packet.
16511 + * @param bytes Number of bytes to copy to the destination.
16513 +void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
16514 + uint8_t * dest, uint16_t bytes)
16517 + int word_count = (bytes + 3) / 4;
16519 + volatile uint32_t *fifo = core_if->data_fifo[0];
16520 + uint32_t *data_buff = (uint32_t *) dest;
16523 + * @todo Account for the case where _dest is not dword aligned. This
16524 + * requires reading data from the FIFO into a uint32_t temp buffer,
16525 + * then moving it into the data buffer.
16528 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
16529 + core_if, dest, bytes);
16531 + for (i = 0; i < word_count; i++, data_buff++) {
16532 + *data_buff = dwc_read_reg32(fifo);
16539 + * This functions reads the device registers and prints them
16541 + * @param core_if Programming view of DWC_otg controller.
16543 +void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if)
16546 + volatile uint32_t *addr;
16548 + DWC_PRINTF("Device Global Registers\n");
16549 + addr = &core_if->dev_if->dev_global_regs->dcfg;
16550 + DWC_PRINTF("DCFG @0x%08X : 0x%08X\n", (uint32_t) addr,
16551 + dwc_read_reg32(addr));
16552 + addr = &core_if->dev_if->dev_global_regs->dctl;
16553 + DWC_PRINTF("DCTL @0x%08X : 0x%08X\n", (uint32_t) addr,
16554 + dwc_read_reg32(addr));
16555 + addr = &core_if->dev_if->dev_global_regs->dsts;
16556 + DWC_PRINTF("DSTS @0x%08X : 0x%08X\n", (uint32_t) addr,
16557 + dwc_read_reg32(addr));
16558 + addr = &core_if->dev_if->dev_global_regs->diepmsk;
16559 + DWC_PRINTF("DIEPMSK @0x%08X : 0x%08X\n", (uint32_t) addr,
16560 + dwc_read_reg32(addr));
16561 + addr = &core_if->dev_if->dev_global_regs->doepmsk;
16562 + DWC_PRINTF("DOEPMSK @0x%08X : 0x%08X\n", (uint32_t) addr,
16563 + dwc_read_reg32(addr));
16564 + addr = &core_if->dev_if->dev_global_regs->daint;
16565 + DWC_PRINTF("DAINT @0x%08X : 0x%08X\n", (uint32_t) addr,
16566 + dwc_read_reg32(addr));
16567 + addr = &core_if->dev_if->dev_global_regs->daintmsk;
16568 + DWC_PRINTF("DAINTMSK @0x%08X : 0x%08X\n", (uint32_t) addr,
16569 + dwc_read_reg32(addr));
16570 + addr = &core_if->dev_if->dev_global_regs->dtknqr1;
16571 + DWC_PRINTF("DTKNQR1 @0x%08X : 0x%08X\n", (uint32_t) addr,
16572 + dwc_read_reg32(addr));
16573 + if (core_if->hwcfg2.b.dev_token_q_depth > 6) {
16574 + addr = &core_if->dev_if->dev_global_regs->dtknqr2;
16575 + DWC_PRINTF("DTKNQR2 @0x%08X : 0x%08X\n",
16576 + (uint32_t) addr, dwc_read_reg32(addr));
16579 + addr = &core_if->dev_if->dev_global_regs->dvbusdis;
16580 + DWC_PRINTF("DVBUSID @0x%08X : 0x%08X\n", (uint32_t) addr,
16581 + dwc_read_reg32(addr));
16583 + addr = &core_if->dev_if->dev_global_regs->dvbuspulse;
16584 + DWC_PRINTF("DVBUSPULSE @0x%08X : 0x%08X\n",
16585 + (uint32_t) addr, dwc_read_reg32(addr));
16587 + addr = &core_if->dev_if->dev_global_regs->dtknqr3_dthrctl;
16588 + DWC_PRINTF("DTKNQR3_DTHRCTL @0x%08X : 0x%08X\n",
16589 + (uint32_t) addr, dwc_read_reg32(addr));
16591 + if (core_if->hwcfg2.b.dev_token_q_depth > 22) {
16592 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
16593 + DWC_PRINTF("DTKNQR4 @0x%08X : 0x%08X\n",
16594 + (uint32_t) addr, dwc_read_reg32(addr));
16597 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
16598 + DWC_PRINTF("FIFOEMPMSK @0x%08X : 0x%08X\n", (uint32_t) addr,
16599 + dwc_read_reg32(addr));
16601 + addr = &core_if->dev_if->dev_global_regs->deachint;
16602 + DWC_PRINTF("DEACHINT @0x%08X : 0x%08X\n", (uint32_t) addr,
16603 + dwc_read_reg32(addr));
16604 + addr = &core_if->dev_if->dev_global_regs->deachintmsk;
16605 + DWC_PRINTF("DEACHINTMSK @0x%08X : 0x%08X\n", (uint32_t) addr,
16606 + dwc_read_reg32(addr));
16608 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
16609 + addr = &core_if->dev_if->dev_global_regs->diepeachintmsk[i];
16610 + DWC_PRINTF("DIEPEACHINTMSK[%d] @0x%08X : 0x%08X\n", i,
16611 + (uint32_t) addr, dwc_read_reg32(addr));
16614 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
16615 + addr = &core_if->dev_if->dev_global_regs->doepeachintmsk[i];
16616 + DWC_PRINTF("DOEPEACHINTMSK[%d] @0x%08X : 0x%08X\n", i,
16617 + (uint32_t) addr, dwc_read_reg32(addr));
16620 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
16621 + DWC_PRINTF("Device IN EP %d Registers\n", i);
16622 + addr = &core_if->dev_if->in_ep_regs[i]->diepctl;
16623 + DWC_PRINTF("DIEPCTL @0x%08X : 0x%08X\n", (uint32_t) addr,
16624 + dwc_read_reg32(addr));
16625 + addr = &core_if->dev_if->in_ep_regs[i]->diepint;
16626 + DWC_PRINTF("DIEPINT @0x%08X : 0x%08X\n", (uint32_t) addr,
16627 + dwc_read_reg32(addr));
16628 + addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz;
16629 + DWC_PRINTF("DIETSIZ @0x%08X : 0x%08X\n", (uint32_t) addr,
16630 + dwc_read_reg32(addr));
16631 + addr = &core_if->dev_if->in_ep_regs[i]->diepdma;
16632 + DWC_PRINTF("DIEPDMA @0x%08X : 0x%08X\n", (uint32_t) addr,
16633 + dwc_read_reg32(addr));
16634 + addr = &core_if->dev_if->in_ep_regs[i]->dtxfsts;
16635 + DWC_PRINTF("DTXFSTS @0x%08X : 0x%08X\n", (uint32_t) addr,
16636 + dwc_read_reg32(addr));
16637 + addr = &core_if->dev_if->in_ep_regs[i]->diepdmab;
16638 + DWC_PRINTF("DIEPDMAB @0x%08X : 0x%08X\n", (uint32_t) addr,
16639 + 0 /*dwc_read_reg32(addr) */ );
16642 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
16643 + DWC_PRINTF("Device OUT EP %d Registers\n", i);
16644 + addr = &core_if->dev_if->out_ep_regs[i]->doepctl;
16645 + DWC_PRINTF("DOEPCTL @0x%08X : 0x%08X\n", (uint32_t) addr,
16646 + dwc_read_reg32(addr));
16647 + addr = &core_if->dev_if->out_ep_regs[i]->doepfn;
16648 + DWC_PRINTF("DOEPFN @0x%08X : 0x%08X\n", (uint32_t) addr,
16649 + dwc_read_reg32(addr));
16650 + addr = &core_if->dev_if->out_ep_regs[i]->doepint;
16651 + DWC_PRINTF("DOEPINT @0x%08X : 0x%08X\n", (uint32_t) addr,
16652 + dwc_read_reg32(addr));
16653 + addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz;
16654 + DWC_PRINTF("DOETSIZ @0x%08X : 0x%08X\n", (uint32_t) addr,
16655 + dwc_read_reg32(addr));
16656 + addr = &core_if->dev_if->out_ep_regs[i]->doepdma;
16657 + DWC_PRINTF("DOEPDMA @0x%08X : 0x%08X\n", (uint32_t) addr,
16658 + dwc_read_reg32(addr));
16659 + if (core_if->dma_enable) { /* Don't access this register in SLAVE mode */
16660 + addr = &core_if->dev_if->out_ep_regs[i]->doepdmab;
16661 + DWC_PRINTF("DOEPDMAB @0x%08X : 0x%08X\n",
16662 + (uint32_t) addr, dwc_read_reg32(addr));
16669 + * This functions reads the SPRAM and prints its content
16671 + * @param core_if Programming view of DWC_otg controller.
16673 +void dwc_otg_dump_spram(dwc_otg_core_if_t * core_if)
16675 + volatile uint8_t *addr, *start_addr, *end_addr;
16677 + DWC_PRINTF("SPRAM Data:\n");
16678 + start_addr = (void *)core_if->core_global_regs;
16679 + DWC_PRINTF("Base Address: 0x%8X\n", (uint32_t) start_addr);
16680 + start_addr += 0x00028000;
16681 + end_addr = (void *)core_if->core_global_regs;
16682 + end_addr += 0x000280e0;
16684 + for (addr = start_addr; addr < end_addr; addr += 16) {
16686 + ("0x%8X:\t%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n",
16687 + (uint32_t) addr, addr[0], addr[1], addr[2], addr[3],
16688 + addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
16689 + addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]
16697 + * This function reads the host registers and prints them
16699 + * @param core_if Programming view of DWC_otg controller.
16701 +void dwc_otg_dump_host_registers(dwc_otg_core_if_t * core_if)
16704 + volatile uint32_t *addr;
16706 + DWC_PRINTF("Host Global Registers\n");
16707 + addr = &core_if->host_if->host_global_regs->hcfg;
16708 + DWC_PRINTF("HCFG @0x%08X : 0x%08X\n", (uint32_t) addr,
16709 + dwc_read_reg32(addr));
16710 + addr = &core_if->host_if->host_global_regs->hfir;
16711 + DWC_PRINTF("HFIR @0x%08X : 0x%08X\n", (uint32_t) addr,
16712 + dwc_read_reg32(addr));
16713 + addr = &core_if->host_if->host_global_regs->hfnum;
16714 + DWC_PRINTF("HFNUM @0x%08X : 0x%08X\n", (uint32_t) addr,
16715 + dwc_read_reg32(addr));
16716 + addr = &core_if->host_if->host_global_regs->hptxsts;
16717 + DWC_PRINTF("HPTXSTS @0x%08X : 0x%08X\n", (uint32_t) addr,
16718 + dwc_read_reg32(addr));
16719 + addr = &core_if->host_if->host_global_regs->haint;
16720 + DWC_PRINTF("HAINT @0x%08X : 0x%08X\n", (uint32_t) addr,
16721 + dwc_read_reg32(addr));
16722 + addr = &core_if->host_if->host_global_regs->haintmsk;
16723 + DWC_PRINTF("HAINTMSK @0x%08X : 0x%08X\n", (uint32_t) addr,
16724 + dwc_read_reg32(addr));
16725 + if (core_if->dma_desc_enable) {
16726 + addr = &core_if->host_if->host_global_regs->hflbaddr;
16727 + DWC_PRINTF("HFLBADDR @0x%08X : 0x%08X\n",(uint32_t) addr,
16728 + dwc_read_reg32(addr));
16731 + addr = core_if->host_if->hprt0;
16732 + DWC_PRINTF("HPRT0 @0x%08X : 0x%08X\n", (uint32_t) addr,
16733 + dwc_read_reg32(addr));
16735 + for (i = 0; i < core_if->core_params->host_channels; i++) {
16736 + DWC_PRINTF("Host Channel %d Specific Registers\n", i);
16737 + addr = &core_if->host_if->hc_regs[i]->hcchar;
16738 + DWC_PRINTF("HCCHAR @0x%08X : 0x%08X\n", (uint32_t) addr,
16739 + dwc_read_reg32(addr));
16740 + addr = &core_if->host_if->hc_regs[i]->hcsplt;
16741 + DWC_PRINTF("HCSPLT @0x%08X : 0x%08X\n", (uint32_t) addr,
16742 + dwc_read_reg32(addr));
16743 + addr = &core_if->host_if->hc_regs[i]->hcint;
16744 + DWC_PRINTF("HCINT @0x%08X : 0x%08X\n", (uint32_t) addr,
16745 + dwc_read_reg32(addr));
16746 + addr = &core_if->host_if->hc_regs[i]->hcintmsk;
16747 + DWC_PRINTF("HCINTMSK @0x%08X : 0x%08X\n", (uint32_t) addr,
16748 + dwc_read_reg32(addr));
16749 + addr = &core_if->host_if->hc_regs[i]->hctsiz;
16750 + DWC_PRINTF("HCTSIZ @0x%08X : 0x%08X\n", (uint32_t) addr,
16751 + dwc_read_reg32(addr));
16752 + addr = &core_if->host_if->hc_regs[i]->hcdma;
16753 + DWC_PRINTF("HCDMA @0x%08X : 0x%08X\n", (uint32_t) addr,
16754 + dwc_read_reg32(addr));
16755 + if (core_if->dma_desc_enable) {
16756 + addr=&core_if->host_if->hc_regs[i]->hcdmab;
16757 + DWC_PRINTF("HCDMAB @0x%08X : 0x%08X\n",(uint32_t) addr, dwc_read_reg32(addr));
16765 + * This function reads the core global registers and prints them
16767 + * @param core_if Programming view of DWC_otg controller.
16769 +void dwc_otg_dump_global_registers(dwc_otg_core_if_t * core_if)
16772 + volatile uint32_t *addr;
16774 + DWC_PRINTF("Core Global Registers\n");
16775 + addr = &core_if->core_global_regs->gotgctl;
16776 + DWC_PRINTF("GOTGCTL @0x%08X : 0x%08X\n", (uint32_t) addr,
16777 + dwc_read_reg32(addr));
16778 + addr = &core_if->core_global_regs->gotgint;
16779 + DWC_PRINTF("GOTGINT @0x%08X : 0x%08X\n", (uint32_t) addr,
16780 + dwc_read_reg32(addr));
16781 + addr = &core_if->core_global_regs->gahbcfg;
16782 + DWC_PRINTF("GAHBCFG @0x%08X : 0x%08X\n", (uint32_t) addr,
16783 + dwc_read_reg32(addr));
16784 + addr = &core_if->core_global_regs->gusbcfg;
16785 + DWC_PRINTF("GUSBCFG @0x%08X : 0x%08X\n", (uint32_t) addr,
16786 + dwc_read_reg32(addr));
16787 + addr = &core_if->core_global_regs->grstctl;
16788 + DWC_PRINTF("GRSTCTL @0x%08X : 0x%08X\n", (uint32_t) addr,
16789 + dwc_read_reg32(addr));
16790 + addr = &core_if->core_global_regs->gintsts;
16791 + DWC_PRINTF("GINTSTS @0x%08X : 0x%08X\n", (uint32_t) addr,
16792 + dwc_read_reg32(addr));
16793 + addr = &core_if->core_global_regs->gintmsk;
16794 + DWC_PRINTF("GINTMSK @0x%08X : 0x%08X\n", (uint32_t) addr,
16795 + dwc_read_reg32(addr));
16796 + addr = &core_if->core_global_regs->grxstsr;
16797 + DWC_PRINTF("GRXSTSR @0x%08X : 0x%08X\n", (uint32_t) addr,
16798 + dwc_read_reg32(addr));
16799 + addr = &core_if->core_global_regs->grxfsiz;
16800 + DWC_PRINTF("GRXFSIZ @0x%08X : 0x%08X\n", (uint32_t) addr,
16801 + dwc_read_reg32(addr));
16802 + addr = &core_if->core_global_regs->gnptxfsiz;
16803 + DWC_PRINTF("GNPTXFSIZ @0x%08X : 0x%08X\n", (uint32_t) addr,
16804 + dwc_read_reg32(addr));
16805 + addr = &core_if->core_global_regs->gnptxsts;
16806 + DWC_PRINTF("GNPTXSTS @0x%08X : 0x%08X\n", (uint32_t) addr,
16807 + dwc_read_reg32(addr));
16808 + addr = &core_if->core_global_regs->gi2cctl;
16809 + DWC_PRINTF("GI2CCTL @0x%08X : 0x%08X\n", (uint32_t) addr,
16810 + dwc_read_reg32(addr));
16811 + addr = &core_if->core_global_regs->gpvndctl;
16812 + DWC_PRINTF("GPVNDCTL @0x%08X : 0x%08X\n", (uint32_t) addr,
16813 + dwc_read_reg32(addr));
16814 + addr = &core_if->core_global_regs->ggpio;
16815 + DWC_PRINTF("GGPIO @0x%08X : 0x%08X\n", (uint32_t) addr,
16816 + dwc_read_reg32(addr));
16817 + addr = &core_if->core_global_regs->guid;
16818 + DWC_PRINTF("GUID @0x%08X : 0x%08X\n", (uint32_t) addr,
16819 + dwc_read_reg32(addr));
16820 + addr = &core_if->core_global_regs->gsnpsid;
16821 + DWC_PRINTF("GSNPSID @0x%08X : 0x%08X\n", (uint32_t) addr,
16822 + dwc_read_reg32(addr));
16823 + addr = &core_if->core_global_regs->ghwcfg1;
16824 + DWC_PRINTF("GHWCFG1 @0x%08X : 0x%08X\n", (uint32_t) addr,
16825 + dwc_read_reg32(addr));
16826 + addr = &core_if->core_global_regs->ghwcfg2;
16827 + DWC_PRINTF("GHWCFG2 @0x%08X : 0x%08X\n", (uint32_t) addr,
16828 + dwc_read_reg32(addr));
16829 + addr = &core_if->core_global_regs->ghwcfg3;
16830 + DWC_PRINTF("GHWCFG3 @0x%08X : 0x%08X\n", (uint32_t) addr,
16831 + dwc_read_reg32(addr));
16832 + addr = &core_if->core_global_regs->ghwcfg4;
16833 + DWC_PRINTF("GHWCFG4 @0x%08X : 0x%08X\n", (uint32_t) addr,
16834 + dwc_read_reg32(addr));
16835 + addr = &core_if->core_global_regs->glpmcfg;
16836 + DWC_PRINTF("GLPMCFG @0x%08X : 0x%08X\n", (uint32_t) addr,
16837 + dwc_read_reg32(addr));
16838 + addr = &core_if->core_global_regs->hptxfsiz;
16839 + DWC_PRINTF("HPTXFSIZ @0x%08X : 0x%08X\n", (uint32_t) addr,
16840 + dwc_read_reg32(addr));
16842 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
16843 + addr = &core_if->core_global_regs->dptxfsiz_dieptxf[i];
16844 + DWC_PRINTF("DPTXFSIZ[%d] @0x%08X : 0x%08X\n", i,
16845 + (uint32_t) addr, dwc_read_reg32(addr));
16847 + addr = core_if->pcgcctl;
16848 + DWC_PRINTF("PCGCCTL @0x%08X : 0x%08X\n", (uint32_t) addr,
16849 + dwc_read_reg32(addr));
16853 + * Flush a Tx FIFO.
16855 + * @param core_if Programming view of DWC_otg controller.
16856 + * @param num Tx FIFO to flush.
16858 +void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * core_if, const int num)
16860 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
16861 + volatile grstctl_t greset = {.d32 = 0 };
16864 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", num);
16866 + greset.b.txfflsh = 1;
16867 + greset.b.txfnum = num;
16868 + dwc_write_reg32(&global_regs->grstctl, greset.d32);
16871 + greset.d32 = dwc_read_reg32(&global_regs->grstctl);
16872 + if (++count > 10000) {
16873 + DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
16874 + __func__, greset.d32,
16875 + dwc_read_reg32(&global_regs->gnptxsts));
16879 + } while (greset.b.txfflsh == 1);
16881 + /* Wait for 3 PHY Clocks */
16888 + * @param core_if Programming view of DWC_otg controller.
16890 +void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * core_if)
16892 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
16893 + volatile grstctl_t greset = {.d32 = 0 };
16896 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__);
16900 + greset.b.rxfflsh = 1;
16901 + dwc_write_reg32(&global_regs->grstctl, greset.d32);
16904 + greset.d32 = dwc_read_reg32(&global_regs->grstctl);
16905 + if (++count > 10000) {
16906 + DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
16911 + } while (greset.b.rxfflsh == 1);
16913 + /* Wait for 3 PHY Clocks */
16918 + * Do core a soft reset of the core. Be careful with this because it
16919 + * resets all the internal state machines of the core.
16921 +void dwc_otg_core_reset(dwc_otg_core_if_t * core_if)
16923 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
16924 + volatile grstctl_t greset = {.d32 = 0 };
16927 + DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
16928 + /* Wait for AHB master IDLE state. */
16931 + greset.d32 = dwc_read_reg32(&global_regs->grstctl);
16932 + if (++count > 100000) {
16933 + DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
16938 + while (greset.b.ahbidle == 0);
16940 + /* Core Soft Reset */
16942 + greset.b.csftrst = 1;
16943 + dwc_write_reg32(&global_regs->grstctl, greset.d32);
16945 + greset.d32 = dwc_read_reg32(&global_regs->grstctl);
16946 + if (++count > 10000) {
16947 + DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n",
16948 + __func__, greset.d32);
16953 + while (greset.b.csftrst == 1);
16955 + /* Wait for 3 PHY Clocks */
16959 +uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if)
16961 + return (dwc_otg_mode(_core_if) != DWC_HOST_MODE);
16964 +uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if)
16966 + return (dwc_otg_mode(_core_if) == DWC_HOST_MODE);
16970 + * Register HCD callbacks. The callbacks are used to start and stop
16971 + * the HCD for interrupt processing.
16973 + * @param core_if Programming view of DWC_otg controller.
16974 + * @param cb the HCD callback structure.
16975 + * @param p pointer to be passed to callback function (usb_hcd*).
16977 +void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * core_if,
16978 + dwc_otg_cil_callbacks_t * cb, void *p)
16980 + core_if->hcd_cb = cb;
16985 + * Register PCD callbacks. The callbacks are used to start and stop
16986 + * the PCD for interrupt processing.
16988 + * @param core_if Programming view of DWC_otg controller.
16989 + * @param cb the PCD callback structure.
16990 + * @param p pointer to be passed to callback function (pcd*).
16992 +void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * core_if,
16993 + dwc_otg_cil_callbacks_t * cb, void *p)
16995 + core_if->pcd_cb = cb;
16999 +#ifdef DWC_EN_ISOC
17002 + * This function writes isoc data per 1 (micro)frame into tx fifo
17004 + * @param core_if Programming view of DWC_otg controller.
17005 + * @param ep The EP to start the transfer on.
17008 +void write_isoc_frame_data(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
17010 + dwc_otg_dev_in_ep_regs_t *ep_regs;
17011 + dtxfsts_data_t txstatus = {.d32 = 0 };
17012 + uint32_t len = 0;
17015 + ep->xfer_len = ep->data_per_frame;
17016 + ep->xfer_count = 0;
17018 + ep_regs = core_if->dev_if->in_ep_regs[ep->num];
17020 + len = ep->xfer_len - ep->xfer_count;
17022 + if (len > ep->maxpacket) {
17023 + len = ep->maxpacket;
17026 + dwords = (len + 3) / 4;
17028 + /* While there is space in the queue and space in the FIFO and
17029 + * More data to tranfer, Write packets to the Tx FIFO */
17031 + dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]->dtxfsts);
17032 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", ep->num, txstatus.d32);
17034 + while (txstatus.b.txfspcavail > dwords &&
17035 + ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) {
17036 + /* Write the FIFO */
17037 + dwc_otg_ep_write_packet(core_if, ep, 0);
17039 + len = ep->xfer_len - ep->xfer_count;
17040 + if (len > ep->maxpacket) {
17041 + len = ep->maxpacket;
17044 + dwords = (len + 3) / 4;
17046 + dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]->
17048 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", ep->num,
17054 + * This function initializes a descriptor chain for Isochronous transfer
17056 + * @param core_if Programming view of DWC_otg controller.
17057 + * @param ep The EP to start the transfer on.
17060 +void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
17063 + deptsiz_data_t deptsiz = {.d32 = 0 };
17064 + depctl_data_t depctl = {.d32 = 0 };
17065 + dsts_data_t dsts = {.d32 = 0 };
17066 + volatile uint32_t *addr;
17069 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
17071 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
17074 + ep->xfer_len = ep->data_per_frame;
17075 + ep->xfer_count = 0;
17076 + ep->xfer_buff = ep->cur_pkt_addr;
17077 + ep->dma_addr = ep->cur_pkt_dma_addr;
17080 + /* Program the transfer size and packet count
17081 + * as follows: xfersize = N * maxpacket +
17082 + * short_packet pktcnt = N + (short_packet
17085 + deptsiz.b.xfersize = ep->xfer_len;
17086 + deptsiz.b.pktcnt =
17087 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
17088 + deptsiz.b.mc = deptsiz.b.pktcnt;
17089 + dwc_write_reg32(&core_if->dev_if->in_ep_regs[ep->num]->dieptsiz,
17092 + /* Write the DMA register */
17093 + if (core_if->dma_enable) {
17094 + dwc_write_reg32(&
17095 + (core_if->dev_if->in_ep_regs[ep->num]->
17096 + diepdma), (uint32_t) ep->dma_addr);
17099 + deptsiz.b.pktcnt =
17100 + (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket;
17101 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
17103 + dwc_write_reg32(&core_if->dev_if->out_ep_regs[ep->num]->
17104 + doeptsiz, deptsiz.d32);
17106 + if (core_if->dma_enable) {
17107 + dwc_write_reg32(&
17108 + (core_if->dev_if->out_ep_regs[ep->num]->
17109 + doepdma), (uint32_t) ep->dma_addr);
17113 + /** Enable endpoint, clear nak */
17116 + if (ep->bInterval == 1) {
17118 + dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
17119 + ep->next_frame = dsts.b.soffn + ep->bInterval;
17121 + if (ep->next_frame & 0x1) {
17122 + depctl.b.setd1pid = 1;
17124 + depctl.b.setd0pid = 1;
17127 + ep->next_frame += ep->bInterval;
17129 + if (ep->next_frame & 0x1) {
17130 + depctl.b.setd1pid = 1;
17132 + depctl.b.setd0pid = 1;
17135 + depctl.b.epena = 1;
17136 + depctl.b.cnak = 1;
17138 + dwc_modify_reg32(addr, 0, depctl.d32);
17139 + depctl.d32 = dwc_read_reg32(addr);
17141 + if (ep->is_in && core_if->dma_enable == 0) {
17142 + write_isoc_frame_data(core_if, ep);
17146 +#endif /* DWC_EN_ISOC */
17148 +static void dwc_otg_set_uninitialized(int32_t * p, int size)
17151 + for (i = 0; i < size; i++) {
17156 +static int dwc_otg_param_initialized(int32_t val)
17158 + return val != -1;
17161 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if)
17164 + core_if->core_params = DWC_ALLOC(sizeof(*core_if->core_params));
17165 + if (!core_if->core_params) {
17166 + return -DWC_E_NO_MEMORY;
17168 + dwc_otg_set_uninitialized((int32_t *) core_if->core_params,
17169 + sizeof(*core_if->core_params) /
17170 + sizeof(int32_t));
17171 + DWC_PRINTF("Setting default values for core params\n");
17172 + dwc_otg_set_param_otg_cap(core_if, dwc_param_otg_cap_default);
17173 + dwc_otg_set_param_dma_enable(core_if, dwc_param_dma_enable_default);
17174 + dwc_otg_set_param_dma_desc_enable(core_if,
17175 + dwc_param_dma_desc_enable_default);
17176 + dwc_otg_set_param_opt(core_if, dwc_param_opt_default);
17177 + dwc_otg_set_param_dma_burst_size(core_if,
17178 + dwc_param_dma_burst_size_default);
17179 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
17180 + dwc_param_host_support_fs_ls_low_power_default);
17181 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
17182 + dwc_param_enable_dynamic_fifo_default);
17183 + dwc_otg_set_param_data_fifo_size(core_if,
17184 + dwc_param_data_fifo_size_default);
17185 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
17186 + dwc_param_dev_rx_fifo_size_default);
17187 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
17188 + dwc_param_dev_nperio_tx_fifo_size_default);
17189 + dwc_otg_set_param_host_rx_fifo_size(core_if,
17190 + dwc_param_host_rx_fifo_size_default);
17191 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
17192 + dwc_param_host_nperio_tx_fifo_size_default);
17193 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
17194 + dwc_param_host_perio_tx_fifo_size_default);
17195 + dwc_otg_set_param_max_transfer_size(core_if,
17196 + dwc_param_max_transfer_size_default);
17197 + dwc_otg_set_param_max_packet_count(core_if,
17198 + dwc_param_max_packet_count_default);
17199 + dwc_otg_set_param_host_channels(core_if,
17200 + dwc_param_host_channels_default);
17201 + dwc_otg_set_param_dev_endpoints(core_if,
17202 + dwc_param_dev_endpoints_default);
17203 + dwc_otg_set_param_phy_type(core_if, dwc_param_phy_type_default);
17204 + dwc_otg_set_param_speed(core_if, dwc_param_speed_default);
17205 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
17206 + dwc_param_host_ls_low_power_phy_clk_default);
17207 + dwc_otg_set_param_phy_ulpi_ddr(core_if, dwc_param_phy_ulpi_ddr_default);
17208 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
17209 + dwc_param_phy_ulpi_ext_vbus_default);
17210 + dwc_otg_set_param_phy_utmi_width(core_if,
17211 + dwc_param_phy_utmi_width_default);
17212 + dwc_otg_set_param_ts_dline(core_if, dwc_param_ts_dline_default);
17213 + dwc_otg_set_param_i2c_enable(core_if, dwc_param_i2c_enable_default);
17214 + dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_param_ulpi_fs_ls_default);
17215 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
17216 + dwc_param_en_multiple_tx_fifo_default);
17217 + for (i = 0; i < 15; i++) {
17218 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
17219 + dwc_param_dev_perio_tx_fifo_size_default,
17223 + for (i = 0; i < 15; i++) {
17224 + dwc_otg_set_param_dev_tx_fifo_size(core_if,
17225 + dwc_param_dev_tx_fifo_size_default,
17228 + dwc_otg_set_param_thr_ctl(core_if, dwc_param_thr_ctl_default);
17229 + dwc_otg_set_param_mpi_enable(core_if, dwc_param_mpi_enable_default);
17230 + dwc_otg_set_param_pti_enable(core_if, dwc_param_pti_enable_default);
17231 + dwc_otg_set_param_lpm_enable(core_if, dwc_param_lpm_enable_default);
17232 + dwc_otg_set_param_ic_usb_cap(core_if, dwc_param_ic_usb_cap_default);
17233 + dwc_otg_set_param_tx_thr_length(core_if,
17234 + dwc_param_tx_thr_length_default);
17235 + dwc_otg_set_param_rx_thr_length(core_if,
17236 + dwc_param_rx_thr_length_default);
17237 + dwc_otg_set_param_ahb_thr_ratio(core_if, dwc_param_ahb_thr_ratio_default);
17238 + DWC_PRINTF("Finished setting default values for core params\n");
17242 +uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if)
17244 + return core_if->dma_enable;
17247 +/* Checks if the parameter is outside of its valid range of values */
17248 +#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \
17249 + (((_param_) < (_low_)) || \
17250 + ((_param_) > (_high_)))
17252 +/* Parameter access functions */
17253 +int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val)
17257 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
17258 + DWC_WARN("Wrong value for otg_cap parameter\n");
17259 + DWC_WARN("otg_cap parameter must be 0,1 or 2\n");
17260 + retval = -DWC_E_INVALID;
17266 + case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
17267 + if (core_if->hwcfg2.b.op_mode !=
17268 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
17271 + case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
17272 + if ((core_if->hwcfg2.b.op_mode !=
17273 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
17274 + && (core_if->hwcfg2.b.op_mode !=
17275 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
17276 + && (core_if->hwcfg2.b.op_mode !=
17277 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
17278 + && (core_if->hwcfg2.b.op_mode !=
17279 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) {
17283 + case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
17284 + /* always valid */
17288 + if (dwc_otg_param_initialized(core_if->core_params->otg_cap)) {
17290 + ("%d invalid for otg_cap paremter. Check HW configuration.\n",
17294 + (((core_if->hwcfg2.b.op_mode ==
17295 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
17296 + || (core_if->hwcfg2.b.op_mode ==
17297 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
17298 + || (core_if->hwcfg2.b.op_mode ==
17299 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
17300 + || (core_if->hwcfg2.b.op_mode ==
17301 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ?
17302 + DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE :
17303 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
17304 + retval = -DWC_E_INVALID;
17307 + core_if->core_params->otg_cap = val;
17312 +int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if)
17314 + return core_if->core_params->otg_cap;
17317 +int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val)
17319 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17320 + DWC_WARN("Wrong value for opt parameter\n");
17321 + return -DWC_E_INVALID;
17323 + core_if->core_params->opt = val;
17327 +int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if)
17329 + return core_if->core_params->opt;
17332 +int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, int32_t val)
17335 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17336 + DWC_WARN("Wrong value for dma enable\n");
17337 + return -DWC_E_INVALID;
17340 + if ((val == 1) && (core_if->hwcfg2.b.architecture == 0)) {
17341 + if (dwc_otg_param_initialized(core_if->core_params->dma_enable)) {
17343 + ("%d invalid for dma_enable paremter. Check HW configuration.\n",
17347 + retval = -DWC_E_INVALID;
17350 + core_if->core_params->dma_enable = val;
17352 + dwc_otg_set_param_dma_desc_enable(core_if, 0);
17357 +int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if)
17359 + return core_if->core_params->dma_enable;
17362 +int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, int32_t val)
17365 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17366 + DWC_WARN("Wrong value for dma_enable\n");
17367 + DWC_WARN("dma_desc_enable must be 0 or 1\n");
17368 + return -DWC_E_INVALID;
17372 + && ((dwc_otg_get_param_dma_enable(core_if) == 0)
17373 + || (core_if->hwcfg4.b.desc_dma == 0))) {
17374 + if (dwc_otg_param_initialized
17375 + (core_if->core_params->dma_desc_enable)) {
17377 + ("%d invalid for dma_desc_enable paremter. Check HW configuration.\n",
17381 + retval = -DWC_E_INVALID;
17383 + core_if->core_params->dma_desc_enable = val;
17387 +int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if)
17389 + return core_if->core_params->dma_desc_enable;
17392 +int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * core_if,
17395 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17396 + DWC_WARN("Wrong value for host_support_fs_low_power\n");
17397 + DWC_WARN("host_support_fs_low_power must be 0 or 1\n");
17398 + return -DWC_E_INVALID;
17400 + core_if->core_params->host_support_fs_ls_low_power = val;
17404 +int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
17407 + return core_if->core_params->host_support_fs_ls_low_power;
17410 +int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
17414 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17415 + DWC_WARN("Wrong value for enable_dynamic_fifo\n");
17416 + DWC_WARN("enable_dynamic_fifo must be 0 or 1\n");
17417 + return -DWC_E_INVALID;
17420 + if ((val == 1) && (core_if->hwcfg2.b.dynamic_fifo == 0)) {
17421 + if (dwc_otg_param_initialized
17422 + (core_if->core_params->enable_dynamic_fifo)) {
17424 + ("%d invalid for enable_dynamic_fifo paremter. Check HW configuration.\n",
17428 + retval = -DWC_E_INVALID;
17430 + core_if->core_params->enable_dynamic_fifo = val;
17434 +int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if)
17436 + return core_if->core_params->enable_dynamic_fifo;
17439 +int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
17442 + if (DWC_OTG_PARAM_TEST(val, 32, 32768)) {
17443 + DWC_WARN("Wrong value for data_fifo_size\n");
17444 + DWC_WARN("data_fifo_size must be 32-32768\n");
17445 + return -DWC_E_INVALID;
17448 + if (val > core_if->hwcfg3.b.dfifo_depth) {
17449 + if (dwc_otg_param_initialized
17450 + (core_if->core_params->data_fifo_size)) {
17452 + ("%d invalid for data_fifo_size parameter. Check HW configuration.\n",
17455 + val = core_if->hwcfg3.b.dfifo_depth;
17456 + retval = -DWC_E_INVALID;
17459 + core_if->core_params->data_fifo_size = val;
17463 +int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if)
17465 + return core_if->core_params->data_fifo_size;
17468 +int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
17471 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
17472 + DWC_WARN("Wrong value for dev_rx_fifo_size\n");
17473 + DWC_WARN("dev_rx_fifo_size must be 16-32768\n");
17474 + return -DWC_E_INVALID;
17477 + if (val > dwc_read_reg32(&core_if->core_global_regs->grxfsiz)) {
17478 + if(dwc_otg_param_initialized(core_if->core_params->dev_rx_fifo_size)) {
17479 + DWC_WARN("%d invalid for dev_rx_fifo_size parameter\n", val);
17481 + val = dwc_read_reg32(&core_if->core_global_regs->grxfsiz);
17482 + retval = -DWC_E_INVALID;
17485 + core_if->core_params->dev_rx_fifo_size = val;
17489 +int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if)
17491 + return core_if->core_params->dev_rx_fifo_size;
17494 +int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
17499 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
17500 + DWC_WARN("Wrong value for dev_nperio_tx_fifo\n");
17501 + DWC_WARN("dev_nperio_tx_fifo must be 16-32768\n");
17502 + return -DWC_E_INVALID;
17505 + if (val > (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
17506 + if (dwc_otg_param_initialized
17507 + (core_if->core_params->dev_nperio_tx_fifo_size)) {
17509 + ("%d invalid for dev_nperio_tx_fifo_size. Check HW configuration.\n",
17513 + (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >>
17515 + retval = -DWC_E_INVALID;
17518 + core_if->core_params->dev_nperio_tx_fifo_size = val;
17522 +int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
17524 + return core_if->core_params->dev_nperio_tx_fifo_size;
17527 +int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
17532 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
17533 + DWC_WARN("Wrong value for host_rx_fifo_size\n");
17534 + DWC_WARN("host_rx_fifo_size must be 16-32768\n");
17535 + return -DWC_E_INVALID;
17538 + if (val > dwc_read_reg32(&core_if->core_global_regs->grxfsiz)) {
17539 + if (dwc_otg_param_initialized
17540 + (core_if->core_params->host_rx_fifo_size)) {
17542 + ("%d invalid for host_rx_fifo_size. Check HW configuration.\n",
17545 + val = dwc_read_reg32(&core_if->core_global_regs->grxfsiz);
17546 + retval = -DWC_E_INVALID;
17549 + core_if->core_params->host_rx_fifo_size = val;
17554 +int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if)
17556 + return core_if->core_params->host_rx_fifo_size;
17559 +int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
17564 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
17565 + DWC_WARN("Wrong value for host_nperio_tx_fifo_size\n");
17566 + DWC_WARN("host_nperio_tx_fifo_size must be 16-32768\n");
17567 + return -DWC_E_INVALID;
17570 + if (val > (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
17571 + if (dwc_otg_param_initialized
17572 + (core_if->core_params->host_nperio_tx_fifo_size)) {
17574 + ("%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
17578 + (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >>
17580 + retval = -DWC_E_INVALID;
17583 + core_if->core_params->host_nperio_tx_fifo_size = val;
17587 +int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
17589 + return core_if->core_params->host_nperio_tx_fifo_size;
17592 +int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
17596 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
17597 + DWC_WARN("Wrong value for host_perio_tx_fifo_size\n");
17598 + DWC_WARN("host_perio_tx_fifo_size must be 16-32768\n");
17599 + return -DWC_E_INVALID;
17603 + ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))) {
17604 + if (dwc_otg_param_initialized
17605 + (core_if->core_params->host_perio_tx_fifo_size)) {
17607 + ("%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
17611 + (dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >>
17613 + retval = -DWC_E_INVALID;
17616 + core_if->core_params->host_perio_tx_fifo_size = val;
17620 +int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if)
17622 + return core_if->core_params->host_perio_tx_fifo_size;
17625 +int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
17630 + if (DWC_OTG_PARAM_TEST(val, 2047, 524288)) {
17631 + DWC_WARN("Wrong value for max_transfer_size\n");
17632 + DWC_WARN("max_transfer_size must be 2047-524288\n");
17633 + return -DWC_E_INVALID;
17636 + if (val >= (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))) {
17637 + if (dwc_otg_param_initialized
17638 + (core_if->core_params->max_transfer_size)) {
17640 + ("%d invalid for max_transfer_size. Check HW configuration.\n",
17644 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 11)) -
17646 + retval = -DWC_E_INVALID;
17649 + core_if->core_params->max_transfer_size = val;
17653 +int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if)
17655 + return core_if->core_params->max_transfer_size;
17658 +int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, int32_t val)
17662 + if (DWC_OTG_PARAM_TEST(val, 15, 511)) {
17663 + DWC_WARN("Wrong value for max_packet_count\n");
17664 + DWC_WARN("max_packet_count must be 15-511\n");
17665 + return -DWC_E_INVALID;
17668 + if (val > (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))) {
17669 + if (dwc_otg_param_initialized
17670 + (core_if->core_params->max_packet_count)) {
17672 + ("%d invalid for max_packet_count. Check HW configuration.\n",
17676 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1);
17677 + retval = -DWC_E_INVALID;
17680 + core_if->core_params->max_packet_count = val;
17684 +int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if)
17686 + return core_if->core_params->max_packet_count;
17689 +int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, int32_t val)
17693 + if (DWC_OTG_PARAM_TEST(val, 1, 16)) {
17694 + DWC_WARN("Wrong value for host_channels\n");
17695 + DWC_WARN("host_channels must be 1-16\n");
17696 + return -DWC_E_INVALID;
17699 + if (val > (core_if->hwcfg2.b.num_host_chan + 1)) {
17700 + if (dwc_otg_param_initialized
17701 + (core_if->core_params->host_channels)) {
17703 + ("%d invalid for host_channels. Check HW configurations.\n",
17706 + val = (core_if->hwcfg2.b.num_host_chan + 1);
17707 + retval = -DWC_E_INVALID;
17710 + core_if->core_params->host_channels = val;
17714 +int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if)
17716 + return core_if->core_params->host_channels;
17719 +int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, int32_t val)
17723 + if (DWC_OTG_PARAM_TEST(val, 1, 15)) {
17724 + DWC_WARN("Wrong value for dev_endpoints\n");
17725 + DWC_WARN("dev_endpoints must be 1-15\n");
17726 + return -DWC_E_INVALID;
17729 + if (val > (core_if->hwcfg2.b.num_dev_ep)) {
17730 + if (dwc_otg_param_initialized
17731 + (core_if->core_params->dev_endpoints)) {
17733 + ("%d invalid for dev_endpoints. Check HW configurations.\n",
17736 + val = core_if->hwcfg2.b.num_dev_ep;
17737 + retval = -DWC_E_INVALID;
17740 + core_if->core_params->dev_endpoints = val;
17744 +int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if)
17746 + return core_if->core_params->dev_endpoints;
17749 +int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val)
17754 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
17755 + DWC_WARN("Wrong value for phy_type\n");
17756 + DWC_WARN("phy_type must be 0,1 or 2\n");
17757 + return -DWC_E_INVALID;
17759 +#ifndef NO_FS_PHY_HW_CHECKS
17760 + if ((val == DWC_PHY_TYPE_PARAM_UTMI) &&
17761 + ((core_if->hwcfg2.b.hs_phy_type == 1) ||
17762 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
17764 + } else if ((val == DWC_PHY_TYPE_PARAM_ULPI) &&
17765 + ((core_if->hwcfg2.b.hs_phy_type == 2) ||
17766 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
17768 + } else if ((val == DWC_PHY_TYPE_PARAM_FS) &&
17769 + (core_if->hwcfg2.b.fs_phy_type == 1)) {
17773 + if (dwc_otg_param_initialized(core_if->core_params->phy_type)) {
17775 + ("%d invalid for phy_type. Check HW configurations.\n",
17778 + if (core_if->hwcfg2.b.hs_phy_type) {
17779 + if ((core_if->hwcfg2.b.hs_phy_type == 3) ||
17780 + (core_if->hwcfg2.b.hs_phy_type == 1)) {
17781 + val = DWC_PHY_TYPE_PARAM_UTMI;
17783 + val = DWC_PHY_TYPE_PARAM_ULPI;
17786 + retval = -DWC_E_INVALID;
17789 + core_if->core_params->phy_type = val;
17793 +int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if)
17795 + return core_if->core_params->phy_type;
17798 +int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val)
17801 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17802 + DWC_WARN("Wrong value for speed parameter\n");
17803 + DWC_WARN("max_speed parameter must be 0 or 1\n");
17804 + return -DWC_E_INVALID;
17807 + && dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS) {
17808 + if (dwc_otg_param_initialized(core_if->core_params->speed)) {
17810 + ("%d invalid for speed paremter. Check HW configuration.\n",
17814 + (dwc_otg_get_param_phy_type(core_if) ==
17815 + DWC_PHY_TYPE_PARAM_FS ? 1 : 0);
17816 + retval = -DWC_E_INVALID;
17818 + core_if->core_params->speed = val;
17822 +int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if)
17824 + return core_if->core_params->speed;
17827 +int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if,
17832 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17834 + ("Wrong value for host_ls_low_power_phy_clk parameter\n");
17835 + DWC_WARN("host_ls_low_power_phy_clk must be 0 or 1\n");
17836 + return -DWC_E_INVALID;
17839 + if ((val == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)
17840 + && (dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS)) {
17841 + if(dwc_otg_param_initialized(core_if->core_params->host_ls_low_power_phy_clk)) {
17842 + DWC_ERROR("%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
17846 + (dwc_otg_get_param_phy_type(core_if) ==
17847 + DWC_PHY_TYPE_PARAM_FS) ?
17848 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ :
17849 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
17850 + retval = -DWC_E_INVALID;
17853 + core_if->core_params->host_ls_low_power_phy_clk = val;
17857 +int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if)
17859 + return core_if->core_params->host_ls_low_power_phy_clk;
17862 +int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, int32_t val)
17864 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17865 + DWC_WARN("Wrong value for phy_ulpi_ddr\n");
17866 + DWC_WARN("phy_upli_ddr must be 0 or 1\n");
17867 + return -DWC_E_INVALID;
17870 + core_if->core_params->phy_ulpi_ddr = val;
17874 +int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if)
17876 + return core_if->core_params->phy_ulpi_ddr;
17879 +int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
17882 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17883 + DWC_WARN("Wrong valaue for phy_ulpi_ext_vbus\n");
17884 + DWC_WARN("phy_ulpi_ext_vbus must be 0 or 1\n");
17885 + return -DWC_E_INVALID;
17888 + core_if->core_params->phy_ulpi_ext_vbus = val;
17892 +int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if)
17894 + return core_if->core_params->phy_ulpi_ext_vbus;
17897 +int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, int32_t val)
17899 + if (DWC_OTG_PARAM_TEST(val, 8, 8) && DWC_OTG_PARAM_TEST(val, 16, 16)) {
17900 + DWC_WARN("Wrong valaue for phy_utmi_width\n");
17901 + DWC_WARN("phy_utmi_width must be 8 or 16\n");
17902 + return -DWC_E_INVALID;
17905 + core_if->core_params->phy_utmi_width = val;
17909 +int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if)
17911 + return core_if->core_params->phy_utmi_width;
17914 +int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, int32_t val)
17916 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17917 + DWC_WARN("Wrong valaue for ulpi_fs_ls\n");
17918 + DWC_WARN("ulpi_fs_ls must be 0 or 1\n");
17919 + return -DWC_E_INVALID;
17922 + core_if->core_params->ulpi_fs_ls = val;
17926 +int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if)
17928 + return core_if->core_params->ulpi_fs_ls;
17931 +int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val)
17933 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17934 + DWC_WARN("Wrong valaue for ts_dline\n");
17935 + DWC_WARN("ts_dline must be 0 or 1\n");
17936 + return -DWC_E_INVALID;
17939 + core_if->core_params->ts_dline = val;
17943 +int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if)
17945 + return core_if->core_params->ts_dline;
17948 +int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, int32_t val)
17951 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
17952 + DWC_WARN("Wrong valaue for i2c_enable\n");
17953 + DWC_WARN("i2c_enable must be 0 or 1\n");
17954 + return -DWC_E_INVALID;
17956 +#ifndef NO_FS_PHY_HW_CHECK
17957 + if (val == 1 && core_if->hwcfg3.b.i2c == 0) {
17958 + if(dwc_otg_param_initialized(core_if->core_params->i2c_enable)) {
17959 + DWC_ERROR("%d invalid for i2c_enable. Check HW configuration.\n",
17963 + retval = -DWC_E_INVALID;
17967 + core_if->core_params->i2c_enable = val;
17971 +int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if)
17973 + return core_if->core_params->i2c_enable;
17976 +int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
17977 + int32_t val, int fifo_num)
17981 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
17982 + DWC_WARN("Wrong value for dev_perio_tx_fifo_size\n");
17983 + DWC_WARN("dev_perio_tx_fifo_size must be 4-768\n");
17984 + return -DWC_E_INVALID;
17987 + if (val > (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num]))) {
17988 + if(dwc_otg_param_initialized(core_if->core_params->dev_perio_tx_fifo_size[fifo_num])) {
17989 + DWC_ERROR("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n",
17992 + val = (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num]));
17993 + retval = -DWC_E_INVALID;
17996 + core_if->core_params->dev_perio_tx_fifo_size[fifo_num] = val;
18000 +int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
18003 + return core_if->core_params->dev_perio_tx_fifo_size[fifo_num];
18006 +int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
18010 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
18011 + DWC_WARN("Wrong valaue for en_multiple_tx_fifo,\n");
18012 + DWC_WARN("en_multiple_tx_fifo must be 0 or 1\n");
18013 + return -DWC_E_INVALID;
18016 + if (val == 1 && core_if->hwcfg4.b.ded_fifo_en == 0) {
18017 + if(dwc_otg_param_initialized(core_if->core_params->en_multiple_tx_fifo)) {
18018 + DWC_ERROR("%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
18022 + retval = -DWC_E_INVALID;
18025 + core_if->core_params->en_multiple_tx_fifo = val;
18029 +int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if)
18031 + return core_if->core_params->en_multiple_tx_fifo;
18034 +int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val,
18039 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
18040 + DWC_WARN("Wrong value for dev_tx_fifo_size\n");
18041 + DWC_WARN("dev_tx_fifo_size must be 4-768\n");
18042 + return -DWC_E_INVALID;
18045 + if (val > (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num]))) {
18046 + if(dwc_otg_param_initialized(core_if->core_params->dev_tx_fifo_size[fifo_num])) {
18047 + DWC_ERROR("`%d' invalid for parameter `dev_tx_fifo_size_%d'. Check HW configuration.\n",
18050 + val = (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num]));
18051 + retval = -DWC_E_INVALID;
18054 + core_if->core_params->dev_tx_fifo_size[fifo_num] = val;
18058 +int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
18061 + return core_if->core_params->dev_tx_fifo_size[fifo_num];
18064 +int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val)
18068 + if (DWC_OTG_PARAM_TEST(val, 0, 7)) {
18069 + DWC_WARN("Wrong value for thr_ctl\n");
18070 + DWC_WARN("thr_ctl must be 0-7\n");
18071 + return -DWC_E_INVALID;
18074 + if ((val != 0) &&
18075 + (!dwc_otg_get_param_dma_enable(core_if) ||
18076 + !core_if->hwcfg4.b.ded_fifo_en)) {
18077 + if(dwc_otg_param_initialized(core_if->core_params->thr_ctl)) {
18078 + DWC_ERROR("%d invalid for parameter thr_ctl. Check HW configuration.\n",
18082 + retval = -DWC_E_INVALID;
18085 + core_if->core_params->thr_ctl = val;
18089 +int32_t dwc_otg_get_param_thr_ctl(dwc_otg_core_if_t * core_if)
18091 + return core_if->core_params->thr_ctl;
18094 +int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, int32_t val)
18098 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
18099 + DWC_WARN("Wrong value for lpm_enable\n");
18100 + DWC_WARN("lpm_enable must be 0 or 1\n");
18101 + return -DWC_E_INVALID;
18104 + if (val && !core_if->hwcfg3.b.otg_lpm_en) {
18105 + if(dwc_otg_param_initialized(core_if->core_params->lpm_enable)) {
18106 + DWC_ERROR("%d invalid for parameter lpm_enable. Check HW configuration.\n",
18110 + retval = -DWC_E_INVALID;
18113 + core_if->core_params->lpm_enable = val;
18117 +int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if)
18119 + return core_if->core_params->lpm_enable;
18122 +int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
18124 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
18125 + DWC_WARN("Wrong valaue for tx_thr_length\n");
18126 + DWC_WARN("tx_thr_length must be 8 - 128\n");
18127 + return -DWC_E_INVALID;
18130 + core_if->core_params->tx_thr_length = val;
18134 +int32_t dwc_otg_get_param_tx_thr_length(dwc_otg_core_if_t * core_if)
18136 + return core_if->core_params->tx_thr_length;
18139 +int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
18141 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
18142 + DWC_WARN("Wrong valaue for rx_thr_length\n");
18143 + DWC_WARN("rx_thr_length must be 8 - 128\n");
18144 + return -DWC_E_INVALID;
18147 + core_if->core_params->rx_thr_length = val;
18151 +int32_t dwc_otg_get_param_rx_thr_length(dwc_otg_core_if_t * core_if)
18153 + return core_if->core_params->rx_thr_length;
18156 +int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, int32_t val)
18158 + if (DWC_OTG_PARAM_TEST(val, 1, 1) &&
18159 + DWC_OTG_PARAM_TEST(val, 4, 4) &&
18160 + DWC_OTG_PARAM_TEST(val, 8, 8) &&
18161 + DWC_OTG_PARAM_TEST(val, 16, 16) &&
18162 + DWC_OTG_PARAM_TEST(val, 32, 32) &&
18163 + DWC_OTG_PARAM_TEST(val, 64, 64) &&
18164 + DWC_OTG_PARAM_TEST(val, 128, 128) &&
18165 + DWC_OTG_PARAM_TEST(val, 256, 256)) {
18166 + DWC_WARN("`%d' invalid for parameter `dma_burst_size'\n", val);
18167 + return -DWC_E_INVALID;
18169 + core_if->core_params->dma_burst_size = val;
18173 +int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if)
18175 + return core_if->core_params->dma_burst_size;
18178 +int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, int32_t val)
18181 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
18182 + DWC_WARN("`%d' invalid for parameter `pti_enable'\n", val);
18183 + return -DWC_E_INVALID;
18185 + if (val && (core_if->snpsid < OTG_CORE_REV_2_72a)) {
18186 + if (dwc_otg_param_initialized(core_if->core_params->pti_enable)) {
18187 + DWC_ERROR("%d invalid for parameter pti_enable. Check HW configuration.\n",
18190 + retval = -DWC_E_INVALID;
18193 + core_if->core_params->pti_enable = val;
18197 +int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if)
18199 + return core_if->core_params->pti_enable;
18202 +int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, int32_t val)
18205 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
18206 + DWC_WARN("`%d' invalid for parameter `mpi_enable'\n", val);
18207 + return -DWC_E_INVALID;
18209 + if (val && (core_if->hwcfg2.b.multi_proc_int == 0)) {
18210 + if (dwc_otg_param_initialized(core_if->core_params->mpi_enable)) {
18211 + DWC_ERROR("%d invalid for parameter mpi_enable. Check HW configuration.\n",
18214 + retval = -DWC_E_INVALID;
18217 + core_if->core_params->mpi_enable = val;
18221 +int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if)
18223 + return core_if->core_params->mpi_enable;
18226 +int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
18230 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
18231 + DWC_WARN("`%d' invalid for parameter `ic_usb_cap'\n", val);
18232 + DWC_WARN("ic_usb_cap must be 0 or 1\n");
18233 + return -DWC_E_INVALID;
18236 + if (val && (core_if->hwcfg3.b.otg_enable_ic_usb == 0)) {
18237 + if (dwc_otg_param_initialized(core_if->core_params->ic_usb_cap)) {
18238 + DWC_ERROR("%d invalid for parameter ic_usb_cap. Check HW configuration.\n",
18241 + retval = -DWC_E_INVALID;
18244 + core_if->core_params->ic_usb_cap = val;
18247 +int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if)
18249 + return core_if->core_params->ic_usb_cap;
18252 +int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val)
18257 + if(DWC_OTG_PARAM_TEST(val, 0, 3)) {
18258 + DWC_WARN("`%d' invalid for parameter `ahb_thr_ratio'\n", val);
18259 + DWC_WARN("ahb_thr_ratio must be 0 - 3\n");
18260 + return -DWC_E_INVALID;
18263 + if(val && (core_if->snpsid < OTG_CORE_REV_2_81a || !dwc_otg_get_param_thr_ctl(core_if))) {
18265 + } else if(val && ((dwc_otg_get_param_tx_thr_length(core_if) / (1 << val)) < 4)) {
18269 + if(dwc_otg_param_initialized(core_if->core_params->ahb_thr_ratio)) {
18270 + DWC_ERROR("%d invalid for parameter ahb_thr_ratio. Chack HW configuration.\n", val);
18272 + retval = -DWC_E_INVALID;
18276 + core_if->core_params->ahb_thr_ratio = val;
18279 +int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if)
18281 + return core_if->core_params->ahb_thr_ratio;
18285 +uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if)
18287 + gotgctl_data_t otgctl;
18288 + otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
18289 + return otgctl.b.hstnegscs;
18292 +uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if)
18294 + gotgctl_data_t otgctl;
18295 + otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
18296 + return otgctl.b.sesreqscs;
18299 +void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val)
18301 + gotgctl_data_t otgctl;
18302 + otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
18303 + otgctl.b.hnpreq = val;
18304 + dwc_write_reg32(&core_if->core_global_regs->gotgctl, otgctl.d32);
18307 +uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if)
18309 + return core_if->snpsid;
18312 +uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if)
18314 + gotgctl_data_t otgctl;
18315 + otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
18316 + return otgctl.b.currmod;
18319 +uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if)
18321 + gusbcfg_data_t usbcfg;
18322 + usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
18323 + return usbcfg.b.hnpcap;
18326 +void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
18328 + gusbcfg_data_t usbcfg;
18329 + usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
18330 + usbcfg.b.hnpcap = val;
18331 + dwc_write_reg32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
18334 +uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if)
18336 + gusbcfg_data_t usbcfg;
18337 + usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
18338 + return usbcfg.b.srpcap;
18341 +void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
18343 + gusbcfg_data_t usbcfg;
18344 + usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
18345 + usbcfg.b.srpcap = val;
18346 + dwc_write_reg32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
18349 +uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if)
18351 + dcfg_data_t dcfg;
18352 + dcfg.d32 = -1; //GRAYG
18353 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)\n", __func__, core_if);
18354 + if (NULL == core_if)
18355 + DWC_ERROR("reg request with NULL core_if\n");
18356 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)\n", __func__,
18357 + core_if, core_if->dev_if);
18358 + if (NULL == core_if->dev_if)
18359 + DWC_ERROR("reg request with NULL dev_if\n");
18360 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)->"
18361 + "dev_global_regs(%p)\n", __func__,
18362 + core_if, core_if->dev_if,
18363 + core_if->dev_if->dev_global_regs);
18364 + if (NULL == core_if->dev_if->dev_global_regs)
18365 + DWC_ERROR("reg request with NULL dev_global_regs\n");
18367 + DWC_DEBUGPL(DBG_CILV, "%s - &core_if(%p)->dev_if(%p)->"
18368 + "dev_global_regs(%p)->dcfg = %p\n", __func__,
18369 + core_if, core_if->dev_if,
18370 + core_if->dev_if->dev_global_regs,
18371 + &core_if->dev_if->dev_global_regs->dcfg);
18372 + dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg);
18374 + return dcfg.b.devspd;
18377 +void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val)
18379 + dcfg_data_t dcfg;
18380 + dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg);
18381 + dcfg.b.devspd = val;
18382 + dwc_write_reg32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
18385 +uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if)
18387 + hprt0_data_t hprt0;
18388 + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
18389 + return hprt0.b.prtconnsts;
18392 +uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if)
18394 + dsts_data_t dsts;
18395 + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
18396 + return dsts.b.enumspd;
18399 +uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if)
18401 + hprt0_data_t hprt0;
18402 + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
18403 + return hprt0.b.prtpwr;
18407 +void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val)
18409 + hprt0_data_t hprt0;
18410 + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
18411 + hprt0.b.prtpwr = val;
18412 + dwc_write_reg32(core_if->host_if->hprt0, val);
18415 +uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if)
18417 + hprt0_data_t hprt0;
18418 + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
18419 + return hprt0.b.prtsusp;
18423 +void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val)
18425 + hprt0_data_t hprt0;
18426 + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
18427 + hprt0.b.prtsusp = val;
18428 + dwc_write_reg32(core_if->host_if->hprt0, val);
18431 +void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val)
18433 + hprt0_data_t hprt0;
18434 + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
18435 + hprt0.b.prtres = val;
18436 + dwc_write_reg32(core_if->host_if->hprt0, val);
18439 +uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if)
18441 + dctl_data_t dctl;
18442 + dctl.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dctl);
18443 + return dctl.b.rmtwkupsig;
18446 +uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if)
18448 + glpmcfg_data_t lpmcfg;
18449 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
18452 + ((core_if->lx_state == DWC_OTG_L1) ^ lpmcfg.b.prt_sleep_sts),
18453 + "lx_state = %d, lmpcfg.prt_sleep_sts = %d\n",
18454 + core_if->lx_state, lpmcfg.b.prt_sleep_sts);
18456 + return lpmcfg.b.prt_sleep_sts;
18459 +uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if)
18461 + glpmcfg_data_t lpmcfg;
18462 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
18463 + return lpmcfg.b.rem_wkup_en;
18466 +uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if)
18468 + glpmcfg_data_t lpmcfg;
18469 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
18470 + return lpmcfg.b.appl_resp;
18473 +void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val)
18475 + glpmcfg_data_t lpmcfg;
18476 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
18477 + lpmcfg.b.appl_resp = val;
18478 + dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
18481 +uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if)
18483 + glpmcfg_data_t lpmcfg;
18484 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
18485 + return lpmcfg.b.hsic_connect;
18488 +void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val)
18490 + glpmcfg_data_t lpmcfg;
18491 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
18492 + lpmcfg.b.hsic_connect = val;
18493 + dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
18496 +uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if)
18498 + glpmcfg_data_t lpmcfg;
18499 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
18500 + return lpmcfg.b.inv_sel_hsic;
18504 +void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val)
18506 + glpmcfg_data_t lpmcfg;
18507 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
18508 + lpmcfg.b.inv_sel_hsic = val;
18509 + dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
18512 +uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if)
18514 + return dwc_read_reg32(&core_if->core_global_regs->gotgctl);
18517 +void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val)
18519 + dwc_write_reg32(&core_if->core_global_regs->gotgctl, val);
18522 +uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if)
18524 + return dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
18527 +void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val)
18529 + dwc_write_reg32(&core_if->core_global_regs->gusbcfg, val);
18532 +uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if)
18534 + return dwc_read_reg32(&core_if->core_global_regs->grxfsiz);
18537 +void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
18539 + dwc_write_reg32(&core_if->core_global_regs->grxfsiz, val);
18542 +uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if)
18544 + return dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz);
18547 +void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
18549 + dwc_write_reg32(&core_if->core_global_regs->gnptxfsiz, val);
18552 +uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if)
18554 + return dwc_read_reg32(&core_if->core_global_regs->gpvndctl);
18557 +void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val)
18559 + dwc_write_reg32(&core_if->core_global_regs->gpvndctl, val);
18562 +uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if)
18564 + return dwc_read_reg32(&core_if->core_global_regs->ggpio);
18567 +void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val)
18569 + dwc_write_reg32(&core_if->core_global_regs->ggpio, val);
18572 +uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if)
18574 + return dwc_read_reg32(core_if->host_if->hprt0);
18578 +void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val)
18580 + dwc_write_reg32(core_if->host_if->hprt0, val);
18583 +uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if)
18585 + return dwc_read_reg32(&core_if->core_global_regs->guid);
18588 +void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val)
18590 + dwc_write_reg32(&core_if->core_global_regs->guid, val);
18593 +uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if)
18595 + return dwc_read_reg32(&core_if->core_global_regs->hptxfsiz);
18598 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.h
18600 +/* ==========================================================================
18601 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.h $
18602 + * $Revision: #99 $
18603 + * $Date: 2009/04/21 $
18604 + * $Change: 1237466 $
18606 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
18607 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
18608 + * otherwise expressly agreed to in writing between Synopsys and you.
18610 + * The Software IS NOT an item of Licensed Software or Licensed Product under
18611 + * any End User Software License Agreement or Agreement for Licensed Product
18612 + * with Synopsys or any supplement thereto. You are permitted to use and
18613 + * redistribute this Software in source and binary forms, with or without
18614 + * modification, provided that redistributions of source code must retain this
18615 + * notice. You may not view, use, disclose, copy or distribute this file or
18616 + * any information contained herein except pursuant to this license grant from
18617 + * Synopsys. If you do not agree with this notice, including the disclaimer
18618 + * below, then you are not authorized to use the Software.
18620 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
18621 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18622 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18623 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
18624 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18625 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18626 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18627 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18628 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18629 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
18631 + * ========================================================================== */
18633 +#if !defined(__DWC_CIL_H__)
18634 +#define __DWC_CIL_H__
18636 +//#define HW2937_WORKAROUND
18637 +#define DBG_HW2937 0x400
18639 +#include "dwc_os.h"
18640 +#include "dwc_list.h"
18641 +#include "dwc_otg_dbg.h"
18642 +#include "dwc_otg_regs.h"
18644 +#include "dwc_otg_core_if.h"
18648 + * This file contains the interface to the Core Interface Layer.
18651 +#ifdef DWC_UTE_CFI
18653 +#define MAX_DMA_DESCS_PER_EP 256
18656 + * Enumeration for the data buffer mode
18658 +typedef enum _data_buffer_mode {
18659 + BM_STANDARD = 0, /* data buffer is in normal mode */
18660 + BM_SG = 1, /* data buffer uses the scatter/gather mode */
18661 + BM_CONCAT = 2, /* data buffer uses the concatenation mode */
18662 + BM_CIRCULAR = 3, /* data buffer uses the circular DMA mode */
18663 + BM_ALIGN = 4 /* data buffer is in buffer alignment mode */
18664 +} data_buffer_mode_e;
18665 +#endif //DWC_UTE_CFI
18667 +/** Macros defined for DWC OTG HW Release verison */
18669 +#define OTG_CORE_REV_2_60a 0x4F54260A
18670 +#define OTG_CORE_REV_2_71a 0x4F54271A
18671 +#define OTG_CORE_REV_2_72a 0x4F54272A
18672 +#define OTG_CORE_REV_2_80a 0x4F54280A
18673 +#define OTG_CORE_REV_2_81a 0x4F54281A
18674 +#define OTG_CORE_REV_2_90a 0x4F54290A
18677 + * Information for each ISOC packet.
18679 +typedef struct iso_pkt_info {
18686 + * The <code>dwc_ep</code> structure represents the state of a single
18687 + * endpoint when acting in device mode. It contains the data items
18688 + * needed for an endpoint to be activated and transfer packets.
18690 +typedef struct dwc_ep {
18691 + /** EP number used for register address lookup */
18693 + /** EP direction 0 = OUT */
18694 + unsigned is_in:1;
18695 + /** EP active. */
18696 + unsigned active:1;
18698 + /** Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic Tx FIFO
18699 + If dedicated Tx FIFOs are enabled for all IN Eps - Tx FIFO # FOR IN EPs*/
18700 + unsigned tx_fifo_num:4;
18701 + /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */
18703 +#define DWC_OTG_EP_TYPE_CONTROL 0
18704 +#define DWC_OTG_EP_TYPE_ISOC 1
18705 +#define DWC_OTG_EP_TYPE_BULK 2
18706 +#define DWC_OTG_EP_TYPE_INTR 3
18708 + /** DATA start PID for INTR and BULK EP */
18709 + unsigned data_pid_start:1;
18710 + /** Frame (even/odd) for ISOC EP */
18711 + unsigned even_odd_frame:1;
18712 + /** Max Packet bytes */
18713 + unsigned maxpacket:11;
18715 + /** Max Transfer size */
18716 + uint32_t maxxfer;
18718 + /** @name Transfer state */
18722 + * Pointer to the beginning of the transfer buffer -- do not modify
18723 + * during transfer.
18726 + dwc_dma_t dma_addr;
18728 + dwc_dma_t dma_desc_addr;
18729 + dwc_otg_dev_dma_desc_t *desc_addr;
18731 + uint8_t *start_xfer_buff;
18732 + /** pointer to the transfer buffer */
18733 + uint8_t *xfer_buff;
18734 + /** Number of bytes to transfer */
18735 + unsigned xfer_len:19;
18736 + /** Number of bytes transferred. */
18737 + unsigned xfer_count:19;
18739 + unsigned sent_zlp:1;
18740 + /** Total len for control transfer */
18741 + unsigned total_len:19;
18743 + /** stall clear flag */
18744 + unsigned stall_clear_flag:1;
18746 +#ifdef DWC_UTE_CFI
18747 + /* The buffer mode */
18748 + data_buffer_mode_e buff_mode;
18750 + /* The chain of DMA descriptors.
18751 + * MAX_DMA_DESCS_PER_EP will be allocated for each active EP.
18753 + dwc_otg_dma_desc_t *descs;
18755 + /* The DMA address of the descriptors chain start */
18756 + dma_addr_t descs_dma_addr;
18757 + /** This variable stores the length of the last enqueued request */
18758 + uint32_t cfi_req_len;
18759 +#endif //DWC_UTE_CFI
18761 + /** Allocated DMA Desc count */
18762 + uint32_t desc_cnt;
18764 +#ifdef DWC_EN_ISOC
18766 + * Variables specific for ISOC EPs
18769 + /** DMA addresses of ISOC buffers */
18770 + dwc_dma_t dma_addr0;
18771 + dwc_dma_t dma_addr1;
18773 + dwc_dma_t iso_dma_desc_addr;
18774 + dwc_otg_dev_dma_desc_t *iso_desc_addr;
18776 + /** pointer to the transfer buffers */
18777 + uint8_t *xfer_buff0;
18778 + uint8_t *xfer_buff1;
18780 + /** number of ISOC Buffer is processing */
18781 + uint32_t proc_buf_num;
18782 + /** Interval of ISOC Buffer processing */
18783 + uint32_t buf_proc_intrvl;
18784 + /** Data size for regular frame */
18785 + uint32_t data_per_frame;
18787 + /* todo - pattern data support is to be implemented in the future */
18788 + /** Data size for pattern frame */
18789 + uint32_t data_pattern_frame;
18790 + /** Frame number of pattern data */
18791 + uint32_t sync_frame;
18794 + uint32_t bInterval;
18795 + /** ISO Packet number per frame */
18796 + uint32_t pkt_per_frm;
18797 + /** Next frame num for which will be setup DMA Desc */
18798 + uint32_t next_frame;
18799 + /** Number of packets per buffer processing */
18800 + uint32_t pkt_cnt;
18801 + /** Info for all isoc packets */
18802 + iso_pkt_info_t *pkt_info;
18803 + /** current pkt number */
18804 + uint32_t cur_pkt;
18805 + /** current pkt number */
18806 + uint8_t *cur_pkt_addr;
18807 + /** current pkt number */
18808 + uint32_t cur_pkt_dma_addr;
18809 +#endif /* DWC_EN_ISOC */
18815 + * Reasons for halting a host channel.
18817 +typedef enum dwc_otg_halt_status {
18818 + DWC_OTG_HC_XFER_NO_HALT_STATUS,
18819 + DWC_OTG_HC_XFER_COMPLETE,
18820 + DWC_OTG_HC_XFER_URB_COMPLETE,
18821 + DWC_OTG_HC_XFER_ACK,
18822 + DWC_OTG_HC_XFER_NAK,
18823 + DWC_OTG_HC_XFER_NYET,
18824 + DWC_OTG_HC_XFER_STALL,
18825 + DWC_OTG_HC_XFER_XACT_ERR,
18826 + DWC_OTG_HC_XFER_FRAME_OVERRUN,
18827 + DWC_OTG_HC_XFER_BABBLE_ERR,
18828 + DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
18829 + DWC_OTG_HC_XFER_AHB_ERR,
18830 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
18831 + DWC_OTG_HC_XFER_URB_DEQUEUE
18832 +#ifdef HW2937_WORKAROUND
18833 + , DWC_OTG_HC_XFER_PAUSE_IN
18835 +} dwc_otg_halt_status_e;
18838 + * Host channel descriptor. This structure represents the state of a single
18839 + * host channel when acting in host mode. It contains the data items needed to
18840 + * transfer packets to an endpoint via a host channel.
18842 +typedef struct dwc_hc {
18843 + /** Host channel number used for register address lookup */
18846 + /** Device to access */
18847 + unsigned dev_addr:7;
18849 + /** EP to access */
18850 + unsigned ep_num:4;
18852 + /** EP direction. 0: OUT, 1: IN */
18853 + unsigned ep_is_in:1;
18857 + * One of the following values:
18858 + * - DWC_OTG_EP_SPEED_LOW
18859 + * - DWC_OTG_EP_SPEED_FULL
18860 + * - DWC_OTG_EP_SPEED_HIGH
18862 + unsigned speed:2;
18863 +#define DWC_OTG_EP_SPEED_LOW 0
18864 +#define DWC_OTG_EP_SPEED_FULL 1
18865 +#define DWC_OTG_EP_SPEED_HIGH 2
18869 + * One of the following values:
18870 + * - DWC_OTG_EP_TYPE_CONTROL: 0
18871 + * - DWC_OTG_EP_TYPE_ISOC: 1
18872 + * - DWC_OTG_EP_TYPE_BULK: 2
18873 + * - DWC_OTG_EP_TYPE_INTR: 3
18875 + unsigned ep_type:2;
18877 + /** Max packet size in bytes */
18878 + unsigned max_packet:11;
18881 + * PID for initial transaction.
18885 + * 3: MDATA (non-Control EP),
18886 + * SETUP (Control EP)
18888 + unsigned data_pid_start:2;
18889 +#define DWC_OTG_HC_PID_DATA0 0
18890 +#define DWC_OTG_HC_PID_DATA2 1
18891 +#define DWC_OTG_HC_PID_DATA1 2
18892 +#define DWC_OTG_HC_PID_MDATA 3
18893 +#define DWC_OTG_HC_PID_SETUP 3
18895 + /** Number of periodic transactions per (micro)frame */
18896 + unsigned multi_count:2;
18898 + /** @name Transfer State */
18901 + /** Pointer to the current transfer buffer position. */
18902 + uint8_t *xfer_buff;
18904 + * In Buffer DMA mode this buffer will be used
18905 + * if xfer_buff is not DWORD aligned.
18907 + dwc_dma_t align_buff;
18908 + /** Total number of bytes to transfer. */
18909 + uint32_t xfer_len;
18910 + /** Number of bytes transferred so far. */
18911 + uint32_t xfer_count;
18912 + /** Packet count at start of transfer.*/
18913 + uint16_t start_pkt_count;
18916 + * Flag to indicate whether the transfer has been started. Set to 1 if
18917 + * it has been started, 0 otherwise.
18919 + uint8_t xfer_started;
18922 + * Set to 1 to indicate that a PING request should be issued on this
18923 + * channel. If 0, process normally.
18928 + * Set to 1 to indicate that the error count for this transaction is
18929 + * non-zero. Set to 0 if the error count is 0.
18931 + uint8_t error_state;
18934 + * Set to 1 to indicate that this channel should be halted the next
18935 + * time a request is queued for the channel. This is necessary in
18936 + * slave mode if no request queue space is available when an attempt
18937 + * is made to halt the channel.
18939 + uint8_t halt_on_queue;
18942 + * Set to 1 if the host channel has been halted, but the core is not
18943 + * finished flushing queued requests. Otherwise 0.
18945 + uint8_t halt_pending;
18948 + * Reason for halting the host channel.
18950 + dwc_otg_halt_status_e halt_status;
18953 + * Split settings for the host channel
18955 + uint8_t do_split; /**< Enable split for the channel */
18956 + uint8_t complete_split; /**< Enable complete split */
18957 + uint8_t hub_addr; /**< Address of high speed hub */
18959 + uint8_t port_addr; /**< Port of the low/full speed device */
18960 + /** Split transaction position
18961 + * One of the following values:
18962 + * - DWC_HCSPLIT_XACTPOS_MID
18963 + * - DWC_HCSPLIT_XACTPOS_BEGIN
18964 + * - DWC_HCSPLIT_XACTPOS_END
18965 + * - DWC_HCSPLIT_XACTPOS_ALL */
18966 + uint8_t xact_pos;
18968 + /** Set when the host channel does a short read. */
18969 + uint8_t short_read;
18972 + * Number of requests issued for this channel since it was assigned to
18973 + * the current transfer (not counting PINGs).
18975 + uint8_t requests;
18978 + * Queue Head for the transfer being processed by this channel.
18980 + struct dwc_otg_qh *qh;
18984 + /** Entry in list of host channels. */
18985 + DWC_CIRCLEQ_ENTRY(dwc_hc) hc_list_entry;
18987 + /** @name Descriptor DMA support */
18990 + /** Number of Transfer Descriptors */
18993 + /** Descriptor List DMA address */
18994 + dwc_dma_t desc_list_addr;
18996 + /** Scheduling micro-frame bitmap. */
19003 + * The following parameters may be specified when starting the module. These
19004 + * parameters define how the DWC_otg controller should be configured.
19006 +typedef struct dwc_otg_core_params {
19010 + * Specifies the OTG capabilities. The driver will automatically
19011 + * detect the value for this parameter if none is specified.
19012 + * 0 - HNP and SRP capable (default)
19013 + * 1 - SRP Only capable
19014 + * 2 - No HNP/SRP capable
19019 + * Specifies whether to use slave or DMA mode for accessing the data
19020 + * FIFOs. The driver will automatically detect the value for this
19021 + * parameter if none is specified.
19023 + * 1 - DMA (default, if available)
19025 + int32_t dma_enable;
19028 + * When DMA mode is enabled specifies whether to use address DMA or DMA Descritor mode for accessing the data
19029 + * FIFOs in device mode. The driver will automatically detect the value for this
19030 + * parameter if none is specified.
19031 + * 0 - address DMA
19032 + * 1 - DMA Descriptor(default, if available)
19034 + int32_t dma_desc_enable;
19035 + /** The DMA Burst size (applicable only for External DMA
19036 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
19038 + int32_t dma_burst_size; /* Translate this to GAHBCFG values */
19041 + * Specifies the maximum speed of operation in host and device mode.
19042 + * The actual speed depends on the speed of the attached device and
19043 + * the value of phy_type. The actual speed depends on the speed of the
19044 + * attached device.
19045 + * 0 - High Speed (default)
19049 + /** Specifies whether low power mode is supported when attached
19050 + * to a Full Speed or Low Speed device in host mode.
19051 + * 0 - Don't support low power mode (default)
19052 + * 1 - Support low power mode
19054 + int32_t host_support_fs_ls_low_power;
19056 + /** Specifies the PHY clock rate in low power mode when connected to a
19057 + * Low Speed device in host mode. This parameter is applicable only if
19058 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
19059 + * then defaults to 6 MHZ otherwise 48 MHZ.
19064 + int32_t host_ls_low_power_phy_clk;
19067 + * 0 - Use cC FIFO size parameters
19068 + * 1 - Allow dynamic FIFO sizing (default)
19070 + int32_t enable_dynamic_fifo;
19072 + /** Total number of 4-byte words in the data FIFO memory. This
19073 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
19075 + * 32 to 32768 (default 8192)
19076 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
19078 + int32_t data_fifo_size;
19080 + /** Number of 4-byte words in the Rx FIFO in device mode when dynamic
19081 + * FIFO sizing is enabled.
19082 + * 16 to 32768 (default 1064)
19084 + int32_t dev_rx_fifo_size;
19086 + /** Number of 4-byte words in the non-periodic Tx FIFO in device mode
19087 + * when dynamic FIFO sizing is enabled.
19088 + * 16 to 32768 (default 1024)
19090 + int32_t dev_nperio_tx_fifo_size;
19092 + /** Number of 4-byte words in each of the periodic Tx FIFOs in device
19093 + * mode when dynamic FIFO sizing is enabled.
19094 + * 4 to 768 (default 256)
19096 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
19098 + /** Number of 4-byte words in the Rx FIFO in host mode when dynamic
19099 + * FIFO sizing is enabled.
19100 + * 16 to 32768 (default 1024)
19102 + int32_t host_rx_fifo_size;
19104 + /** Number of 4-byte words in the non-periodic Tx FIFO in host mode
19105 + * when Dynamic FIFO sizing is enabled in the core.
19106 + * 16 to 32768 (default 1024)
19108 + int32_t host_nperio_tx_fifo_size;
19110 + /** Number of 4-byte words in the host periodic Tx FIFO when dynamic
19111 + * FIFO sizing is enabled.
19112 + * 16 to 32768 (default 1024)
19114 + int32_t host_perio_tx_fifo_size;
19116 + /** The maximum transfer size supported in bytes.
19117 + * 2047 to 65,535 (default 65,535)
19119 + int32_t max_transfer_size;
19121 + /** The maximum number of packets in a transfer.
19122 + * 15 to 511 (default 511)
19124 + int32_t max_packet_count;
19126 + /** The number of host channel registers to use.
19127 + * 1 to 16 (default 12)
19128 + * Note: The FPGA configuration supports a maximum of 12 host channels.
19130 + int32_t host_channels;
19132 + /** The number of endpoints in addition to EP0 available for device
19133 + * mode operations.
19134 + * 1 to 15 (default 6 IN and OUT)
19135 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
19136 + * endpoints in addition to EP0.
19138 + int32_t dev_endpoints;
19141 + * Specifies the type of PHY interface to use. By default, the driver
19142 + * will automatically detect the phy_type.
19144 + * 0 - Full Speed PHY
19145 + * 1 - UTMI+ (default)
19148 + int32_t phy_type;
19151 + * Specifies the UTMI+ Data Width. This parameter is
19152 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
19153 + * PHY_TYPE, this parameter indicates the data width between
19154 + * the MAC and the ULPI Wrapper.) Also, this parameter is
19155 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
19156 + * to "8 and 16 bits", meaning that the core has been
19157 + * configured to work at either data path width.
19159 + * 8 or 16 bits (default 16)
19161 + int32_t phy_utmi_width;
19164 + * Specifies whether the ULPI operates at double or single
19165 + * data rate. This parameter is only applicable if PHY_TYPE is
19168 + * 0 - single data rate ULPI interface with 8 bit wide data
19170 + * 1 - double data rate ULPI interface with 4 bit wide data
19173 + int32_t phy_ulpi_ddr;
19176 + * Specifies whether to use the internal or external supply to
19177 + * drive the vbus with a ULPI phy.
19179 + int32_t phy_ulpi_ext_vbus;
19182 + * Specifies whether to use the I2Cinterface for full speed PHY. This
19183 + * parameter is only applicable if PHY_TYPE is FS.
19184 + * 0 - No (default)
19187 + int32_t i2c_enable;
19189 + int32_t ulpi_fs_ls;
19191 + int32_t ts_dline;
19194 + * Specifies whether dedicated transmit FIFOs are
19195 + * enabled for non periodic IN endpoints in device mode
19199 + int32_t en_multiple_tx_fifo;
19201 + /** Number of 4-byte words in each of the Tx FIFOs in device
19202 + * mode when dynamic FIFO sizing is enabled.
19203 + * 4 to 768 (default 256)
19205 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
19207 + /** Thresholding enable flag-
19208 + * bit 0 - enable non-ISO Tx thresholding
19209 + * bit 1 - enable ISO Tx thresholding
19210 + * bit 2 - enable Rx thresholding
19212 + uint32_t thr_ctl;
19214 + /** Thresholding length for Tx
19215 + * FIFOs in 32 bit DWORDs
19217 + uint32_t tx_thr_length;
19219 + /** Thresholding length for Rx
19220 + * FIFOs in 32 bit DWORDs
19222 + uint32_t rx_thr_length;
19225 + * Specifies whether LPM (Link Power Management) support is enabled
19227 + int32_t lpm_enable;
19229 + /** Per Transfer Interrupt
19230 + * mode enable flag
19234 + int32_t pti_enable;
19236 + /** Multi Processor Interrupt
19237 + * mode enable flag
19241 + int32_t mpi_enable;
19243 + /** IS_USB Capability
19247 + int32_t ic_usb_cap;
19249 + /** AHB Threshold Ratio
19250 + * 2'b00 AHB Threshold = MAC Threshold
19251 + * 2'b01 AHB Threshold = 1/2 MAC Threshold
19252 + * 2'b10 AHB Threshold = 1/4 MAC Threshold
19253 + * 2'b11 AHB Threshold = 1/8 MAC Threshold
19255 + int32_t ahb_thr_ratio;
19257 +} dwc_otg_core_params_t;
19260 +struct dwc_otg_core_if;
19261 +typedef struct hc_xfer_info {
19262 + struct dwc_otg_core_if *core_if;
19269 +typedef enum dwc_otg_lx_state {
19272 + /** LPM sleep state*/
19274 + /** USB suspend state*/
19278 +} dwc_otg_lx_state_e;
19281 + * The <code>dwc_otg_core_if</code> structure contains information needed to manage
19282 + * the DWC_otg controller acting in either host or device mode. It
19283 + * represents the programming view of the controller as a whole.
19285 +struct dwc_otg_core_if {
19286 + /** Parameters that define how the core should be configured.*/
19287 + dwc_otg_core_params_t *core_params;
19289 + /** Core Global registers starting at offset 000h. */
19290 + dwc_otg_core_global_regs_t *core_global_regs;
19292 + /** Device-specific information */
19293 + dwc_otg_dev_if_t *dev_if;
19294 + /** Host-specific information */
19295 + dwc_otg_host_if_t *host_if;
19297 + /** Value from SNPSID register */
19301 + * Set to 1 if the core PHY interface bits in USBCFG have been
19304 + uint8_t phy_init_done;
19307 + * SRP Success flag, set by srp success interrupt in FS I2C mode
19309 + uint8_t srp_success;
19310 + uint8_t srp_timer_started;
19312 + /* Common configuration information */
19313 + /** Power and Clock Gating Control Register */
19314 + volatile uint32_t *pcgcctl;
19315 +#define DWC_OTG_PCGCCTL_OFFSET 0xE00
19317 + /** Push/pop addresses for endpoints or host channels.*/
19318 + uint32_t *data_fifo[MAX_EPS_CHANNELS];
19319 +#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
19320 +#define DWC_OTG_DATA_FIFO_SIZE 0x1000
19322 + /** Total RAM for FIFOs (Bytes) */
19323 + uint16_t total_fifo_size;
19324 + /** Size of Rx FIFO (Bytes) */
19325 + uint16_t rx_fifo_size;
19326 + /** Size of Non-periodic Tx FIFO (Bytes) */
19327 + uint16_t nperio_tx_fifo_size;
19329 + /** 1 if DMA is enabled, 0 otherwise. */
19330 + uint8_t dma_enable;
19332 + /** 1 if DMA descriptor is enabled, 0 otherwise. */
19333 + uint8_t dma_desc_enable;
19335 + /** 1 if PTI Enhancement mode is enabled, 0 otherwise. */
19336 + uint8_t pti_enh_enable;
19338 + /** 1 if MPI Enhancement mode is enabled, 0 otherwise. */
19339 + uint8_t multiproc_int_enable;
19341 + /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */
19342 + uint8_t en_multiple_tx_fifo;
19344 + /** Set to 1 if multiple packets of a high-bandwidth transfer is in
19345 + * process of being queued */
19346 + uint8_t queuing_high_bandwidth;
19348 + /** Hardware Configuration -- stored here for convenience.*/
19349 + hwcfg1_data_t hwcfg1;
19350 + hwcfg2_data_t hwcfg2;
19351 + hwcfg3_data_t hwcfg3;
19352 + hwcfg4_data_t hwcfg4;
19354 + /** Host and Device Configuration -- stored here for convenience.*/
19355 + hcfg_data_t hcfg;
19356 + dcfg_data_t dcfg;
19358 + /** The operational State, during transations
19359 + * (a_host>>a_peripherial and b_device=>b_host) this may not
19360 + * match the core but allows the software to determine
19363 + uint8_t op_state;
19366 + * Set to 1 if the HCD needs to be restarted on a session request
19367 + * interrupt. This is required if no connector ID status change has
19368 + * occurred since the HCD was last disconnected.
19370 + uint8_t restart_hcd_on_session_req;
19372 + /** HCD callbacks */
19373 + /** A-Device is a_host */
19374 +#define A_HOST (1)
19375 + /** A-Device is a_suspend */
19376 +#define A_SUSPEND (2)
19377 + /** A-Device is a_peripherial */
19378 +#define A_PERIPHERAL (3)
19379 + /** B-Device is operating as a Peripheral. */
19380 +#define B_PERIPHERAL (4)
19381 + /** B-Device is operating as a Host. */
19382 +#define B_HOST (5)
19384 + /** HCD callbacks */
19385 + struct dwc_otg_cil_callbacks *hcd_cb;
19386 + /** PCD callbacks */
19387 + struct dwc_otg_cil_callbacks *pcd_cb;
19389 + /** Device mode Periodic Tx FIFO Mask */
19390 + uint32_t p_tx_msk;
19391 + /** Device mode Periodic Tx FIFO Mask */
19394 + /** Workqueue object used for handling several interrupts */
19395 + dwc_workq_t *wq_otg;
19397 + /** Timer object used for handling "Wakeup Detected" Interrupt */
19398 + dwc_timer_t *wkp_timer;
19401 + uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
19403 + hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS];
19404 + dwc_timer_t *hc_xfer_timer[MAX_EPS_CHANNELS];
19406 + uint32_t hfnum_7_samples;
19407 + uint64_t hfnum_7_frrem_accum;
19408 + uint32_t hfnum_0_samples;
19409 + uint64_t hfnum_0_frrem_accum;
19410 + uint32_t hfnum_other_samples;
19411 + uint64_t hfnum_other_frrem_accum;
19414 +#ifdef DWC_UTE_CFI
19415 + uint16_t pwron_rxfsiz;
19416 + uint16_t pwron_gnptxfsiz;
19417 + uint16_t pwron_txfsiz[15];
19419 + uint16_t init_rxfsiz;
19420 + uint16_t init_gnptxfsiz;
19421 + uint16_t init_txfsiz[15];
19424 + /** Lx state of device */
19425 + dwc_otg_lx_state_e lx_state;
19431 + * This function is called when transfer is timed out.
19433 +extern void hc_xfer_timeout(void *ptr);
19437 + * The following functions are functions for works
19438 + * using during handling some interrupts
19440 +extern void w_conn_id_status_change(void *p);
19442 +extern void w_wakeup_detected(void *p);
19445 + * The following functions support initialization of the CIL driver component
19446 + * and the DWC_otg controller.
19448 +extern void dwc_otg_core_host_init(dwc_otg_core_if_t * _core_if);
19449 +extern void dwc_otg_core_dev_init(dwc_otg_core_if_t * _core_if);
19451 +/** @name Device CIL Functions
19452 + * The following functions support managing the DWC_otg controller in device
19456 +extern void dwc_otg_wakeup(dwc_otg_core_if_t * _core_if);
19457 +extern void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if,
19458 + uint32_t * _dest);
19459 +extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if);
19460 +extern void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
19461 +extern void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
19462 +extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
19463 +extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if,
19465 +extern void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * _core_if,
19467 +extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * _core_if,
19469 +extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * _core_if,
19471 +extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t * _core_if,
19472 + dwc_ep_t * _ep, int _dma);
19473 +extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
19474 +extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * _core_if,
19476 +extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * _core_if);
19478 +#ifdef DWC_EN_ISOC
19479 +extern void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
19481 +extern void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
19483 +#endif /* DWC_EN_ISOC */
19486 +/** @name Host CIL Functions
19487 + * The following functions support managing the DWC_otg controller in host
19491 +extern void dwc_otg_hc_init(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
19492 +extern void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if,
19493 + dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status);
19494 +extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
19495 +extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if,
19497 +extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if,
19499 +extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
19500 +extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if,
19502 +extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * _core_if);
19503 +extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * _core_if);
19505 +extern void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc);
19507 +/* Macro used to clear one channel interrupt */
19508 +#define clear_hc_int(_hc_regs_, _intr_) \
19510 + hcint_data_t hcint_clear = {.d32 = 0}; \
19511 + hcint_clear.b._intr_ = 1; \
19512 + dwc_write_reg32(&(_hc_regs_)->hcint, hcint_clear.d32); \
19516 + * Macro used to disable one channel interrupt. Channel interrupts are
19517 + * disabled when the channel is halted or released by the interrupt handler.
19518 + * There is no need to handle further interrupts of that type until the
19519 + * channel is re-assigned. In fact, subsequent handling may cause crashes
19520 + * because the channel structures are cleaned up when the channel is released.
19522 +#define disable_hc_int(_hc_regs_, _intr_) \
19524 + hcintmsk_data_t hcintmsk = {.d32 = 0}; \
19525 + hcintmsk.b._intr_ = 1; \
19526 + dwc_modify_reg32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \
19530 + * This function Reads HPRT0 in preparation to modify. It keeps the
19531 + * WC bits 0 so that if they are read as 1, they won't clear when you
19534 +static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t * _core_if)
19536 + hprt0_data_t hprt0;
19537 + hprt0.d32 = dwc_read_reg32(_core_if->host_if->hprt0);
19538 + hprt0.b.prtena = 0;
19539 + hprt0.b.prtconndet = 0;
19540 + hprt0.b.prtenchng = 0;
19541 + hprt0.b.prtovrcurrchng = 0;
19542 + return hprt0.d32;
19547 +/** @name Common CIL Functions
19548 + * The following functions support managing the DWC_otg controller in either
19549 + * device or host mode.
19553 +extern void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
19554 + uint8_t * dest, uint16_t bytes);
19556 +extern void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * _core_if, const int _num);
19557 +extern void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * _core_if);
19558 +extern void dwc_otg_core_reset(dwc_otg_core_if_t * _core_if);
19561 + * This function returns the Core Interrupt register.
19563 +static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t * core_if)
19565 + return (dwc_read_reg32(&core_if->core_global_regs->gintsts) &
19566 + dwc_read_reg32(&core_if->core_global_regs->gintmsk));
19570 + * This function returns the OTG Interrupt register.
19572 +static inline uint32_t dwc_otg_read_otg_intr(dwc_otg_core_if_t * core_if)
19574 + return (dwc_read_reg32(&core_if->core_global_regs->gotgint));
19578 + * This function reads the Device All Endpoints Interrupt register and
19579 + * returns the IN endpoint interrupt bits.
19581 +static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *
19587 + if (core_if->multiproc_int_enable) {
19588 + v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->
19589 + deachint) & dwc_read_reg32(&core_if->dev_if->
19590 + dev_global_regs->
19593 + v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->daint) &
19594 + dwc_read_reg32(&core_if->dev_if->dev_global_regs->daintmsk);
19596 + return (v & 0xffff);
19600 + * This function reads the Device All Endpoints Interrupt register and
19601 + * returns the OUT endpoint interrupt bits.
19603 +static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *
19608 + if (core_if->multiproc_int_enable) {
19609 + v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->
19610 + deachint) & dwc_read_reg32(&core_if->dev_if->
19611 + dev_global_regs->
19614 + v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->daint) &
19615 + dwc_read_reg32(&core_if->dev_if->dev_global_regs->daintmsk);
19618 + return ((v & 0xffff0000) >> 16);
19622 + * This function returns the Device IN EP Interrupt register
19624 +static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t * core_if,
19627 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
19628 + uint32_t v, msk, emp;
19630 + if (core_if->multiproc_int_enable) {
19632 + dwc_read_reg32(&dev_if->dev_global_regs->
19633 + diepeachintmsk[ep->num]);
19635 + dwc_read_reg32(&dev_if->dev_global_regs->
19636 + dtknqr4_fifoemptymsk);
19637 + msk |= ((emp >> ep->num) & 0x1) << 7;
19638 + v = dwc_read_reg32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
19640 + msk = dwc_read_reg32(&dev_if->dev_global_regs->diepmsk);
19642 + dwc_read_reg32(&dev_if->dev_global_regs->
19643 + dtknqr4_fifoemptymsk);
19644 + msk |= ((emp >> ep->num) & 0x1) << 7;
19645 + v = dwc_read_reg32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
19652 + * This function returns the Device OUT EP Interrupt register
19654 +static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *
19655 + _core_if, dwc_ep_t * _ep)
19657 + dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
19659 + doepmsk_data_t msk = {.d32 = 0 };
19661 + if (_core_if->multiproc_int_enable) {
19663 + dwc_read_reg32(&dev_if->dev_global_regs->
19664 + doepeachintmsk[_ep->num]);
19665 + if (_core_if->pti_enh_enable) {
19666 + msk.b.pktdrpsts = 1;
19668 + v = dwc_read_reg32(&dev_if->out_ep_regs[_ep->num]->
19669 + doepint) & msk.d32;
19671 + msk.d32 = dwc_read_reg32(&dev_if->dev_global_regs->doepmsk);
19672 + if (_core_if->pti_enh_enable) {
19673 + msk.b.pktdrpsts = 1;
19675 + v = dwc_read_reg32(&dev_if->out_ep_regs[_ep->num]->
19676 + doepint) & msk.d32;
19682 + * This function returns the Host All Channel Interrupt register
19684 +static inline uint32_t dwc_otg_read_host_all_channels_intr(dwc_otg_core_if_t *
19687 + return (dwc_read_reg32(&_core_if->host_if->host_global_regs->haint));
19690 +static inline uint32_t dwc_otg_read_host_channel_intr(dwc_otg_core_if_t *
19691 + _core_if, dwc_hc_t * _hc)
19693 + return (dwc_read_reg32
19694 + (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint));
19698 + * This function returns the mode of the operation, host or device.
19700 + * @return 0 - Device Mode, 1 - Host Mode
19702 +static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t * _core_if)
19704 + return (dwc_read_reg32(&_core_if->core_global_regs->gintsts) & 0x1);
19710 + * DWC_otg CIL callback structure. This structure allows the HCD and
19711 + * PCD to register functions used for starting and stopping the PCD
19712 + * and HCD for role change on for a DRD.
19714 +typedef struct dwc_otg_cil_callbacks {
19715 + /** Start function for role change */
19716 + int (*start) (void *_p);
19717 + /** Stop Function for role change */
19718 + int (*stop) (void *_p);
19719 + /** Disconnect Function for role change */
19720 + int (*disconnect) (void *_p);
19721 + /** Resume/Remote wakeup Function */
19722 + int (*resume_wakeup) (void *_p);
19723 + /** Suspend function */
19724 + int (*suspend) (void *_p);
19725 + /** Session Start (SRP) */
19726 + int (*session_start) (void *_p);
19727 +#ifdef CONFIG_USB_DWC_OTG_LPM
19728 + /** Sleep (switch to L0 state) */
19729 + int (*sleep) (void *_p);
19731 + /** Pointer passed to start() and stop() */
19733 +} dwc_otg_cil_callbacks_t;
19735 +extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if,
19736 + dwc_otg_cil_callbacks_t * _cb,
19738 +extern void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * _core_if,
19739 + dwc_otg_cil_callbacks_t * _cb,
19744 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
19746 +/* ==========================================================================
19747 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
19748 + * $Revision: #15 $
19749 + * $Date: 2009/04/15 $
19750 + * $Change: 1234129 $
19752 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
19753 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
19754 + * otherwise expressly agreed to in writing between Synopsys and you.
19756 + * The Software IS NOT an item of Licensed Software or Licensed Product under
19757 + * any End User Software License Agreement or Agreement for Licensed Product
19758 + * with Synopsys or any supplement thereto. You are permitted to use and
19759 + * redistribute this Software in source and binary forms, with or without
19760 + * modification, provided that redistributions of source code must retain this
19761 + * notice. You may not view, use, disclose, copy or distribute this file or
19762 + * any information contained herein except pursuant to this license grant from
19763 + * Synopsys. If you do not agree with this notice, including the disclaimer
19764 + * below, then you are not authorized to use the Software.
19766 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
19767 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19768 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19769 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
19770 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19771 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19772 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19773 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
19774 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
19775 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
19777 + * ========================================================================== */
19781 + * The Core Interface Layer provides basic services for accessing and
19782 + * managing the DWC_otg hardware. These services are used by both the
19783 + * Host Controller Driver and the Peripheral Controller Driver.
19785 + * This file contains the Common Interrupt handlers.
19787 +#include "dwc_os.h"
19788 +#include "dwc_otg_regs.h"
19789 +#include "dwc_otg_cil.h"
19792 +inline const char *op_state_str(dwc_otg_core_if_t * core_if)
19794 + return (core_if->op_state == A_HOST ? "a_host" :
19795 + (core_if->op_state == A_SUSPEND ? "a_suspend" :
19796 + (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
19797 + (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
19798 + (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
19802 +/** This function will log a debug message
19804 + * @param core_if Programming view of DWC_otg controller.
19806 +int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if)
19808 + gintsts_data_t gintsts;
19809 + DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
19810 + dwc_otg_mode(core_if) ? "Host" : "Device");
19812 + /* Clear interrupt */
19814 + gintsts.b.modemismatch = 1;
19815 + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
19819 +/** Start the HCD. Helper function for using the HCD callbacks.
19821 + * @param core_if Programming view of DWC_otg controller.
19823 +static inline void hcd_start(dwc_otg_core_if_t * core_if)
19825 + if (core_if->hcd_cb && core_if->hcd_cb->start) {
19826 + core_if->hcd_cb->start(core_if->hcd_cb->p);
19830 +/** Stop the HCD. Helper function for using the HCD callbacks.
19832 + * @param core_if Programming view of DWC_otg controller.
19834 +static inline void hcd_stop(dwc_otg_core_if_t * core_if)
19836 + if (core_if->hcd_cb && core_if->hcd_cb->stop) {
19837 + core_if->hcd_cb->stop(core_if->hcd_cb->p);
19841 +/** Disconnect the HCD. Helper function for using the HCD callbacks.
19843 + * @param core_if Programming view of DWC_otg controller.
19845 +static inline void hcd_disconnect(dwc_otg_core_if_t * core_if)
19847 + if (core_if->hcd_cb && core_if->hcd_cb->disconnect) {
19848 + core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
19852 +/** Inform the HCD the a New Session has begun. Helper function for
19853 + * using the HCD callbacks.
19855 + * @param core_if Programming view of DWC_otg controller.
19857 +static inline void hcd_session_start(dwc_otg_core_if_t * core_if)
19859 + if (core_if->hcd_cb && core_if->hcd_cb->session_start) {
19860 + core_if->hcd_cb->session_start(core_if->hcd_cb->p);
19864 +#ifdef CONFIG_USB_DWC_OTG_LPM
19866 + * Inform the HCD about LPM sleep.
19867 + * Helper function for using the HCD callbacks.
19869 + * @param core_if Programming view of DWC_otg controller.
19871 +static inline void hcd_sleep(dwc_otg_core_if_t * core_if)
19873 + if (core_if->hcd_cb && core_if->hcd_cb->sleep) {
19874 + core_if->hcd_cb->sleep(core_if->hcd_cb->p);
19879 +/** Resume the HCD. Helper function for using the HCD callbacks.
19881 + * @param core_if Programming view of DWC_otg controller.
19883 +static inline void hcd_resume(dwc_otg_core_if_t * core_if)
19885 + if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) {
19886 + core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p);
19890 +/** Start the PCD. Helper function for using the PCD callbacks.
19892 + * @param core_if Programming view of DWC_otg controller.
19894 +static inline void pcd_start(dwc_otg_core_if_t * core_if)
19896 + if (core_if->pcd_cb && core_if->pcd_cb->start) {
19897 + core_if->pcd_cb->start(core_if->pcd_cb->p);
19901 +/** Stop the PCD. Helper function for using the PCD callbacks.
19903 + * @param core_if Programming view of DWC_otg controller.
19905 +static inline void pcd_stop(dwc_otg_core_if_t * core_if)
19907 + if (core_if->pcd_cb && core_if->pcd_cb->stop) {
19908 + core_if->pcd_cb->stop(core_if->pcd_cb->p);
19912 +/** Suspend the PCD. Helper function for using the PCD callbacks.
19914 + * @param core_if Programming view of DWC_otg controller.
19916 +static inline void pcd_suspend(dwc_otg_core_if_t * core_if)
19918 + if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
19919 + core_if->pcd_cb->suspend(core_if->pcd_cb->p);
19923 +/** Resume the PCD. Helper function for using the PCD callbacks.
19925 + * @param core_if Programming view of DWC_otg controller.
19927 +static inline void pcd_resume(dwc_otg_core_if_t * core_if)
19929 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
19930 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
19935 + * This function handles the OTG Interrupts. It reads the OTG
19936 + * Interrupt Register (GOTGINT) to determine what interrupt has
19939 + * @param core_if Programming view of DWC_otg controller.
19941 +int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if)
19943 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
19944 + gotgint_data_t gotgint;
19945 + gotgctl_data_t gotgctl;
19946 + gintmsk_data_t gintmsk;
19948 + gotgint.d32 = dwc_read_reg32(&global_regs->gotgint);
19949 + gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
19950 + DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
19951 + op_state_str(core_if));
19953 + if (gotgint.b.sesenddet) {
19954 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
19955 + "Session End Detected++ (%s)\n",
19956 + op_state_str(core_if));
19957 + gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
19959 + if (core_if->op_state == B_HOST) {
19960 + pcd_start(core_if);
19961 + core_if->op_state = B_PERIPHERAL;
19963 + /* If not B_HOST and Device HNP still set. HNP
19964 + * Did not succeed!*/
19965 + if (gotgctl.b.devhnpen) {
19966 + DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
19967 + __DWC_ERROR("Device Not Connected/Responding!\n");
19970 + /* If Session End Detected the B-Cable has
19971 + * been disconnected. */
19972 + /* Reset PCD and Gadget driver to a
19973 + * clean state. */
19974 + core_if->lx_state = DWC_OTG_L0;
19975 + pcd_stop(core_if);
19978 + gotgctl.b.devhnpen = 1;
19979 + dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
19981 + if (gotgint.b.sesreqsucstschng) {
19982 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
19983 + "Session Reqeust Success Status Change++\n");
19984 + gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
19985 + if (gotgctl.b.sesreqscs) {
19986 + if ((core_if->core_params->phy_type ==
19987 + DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) {
19988 + core_if->srp_success = 1;
19990 + pcd_resume(core_if);
19991 + /* Clear Session Request */
19993 + gotgctl.b.sesreq = 1;
19994 + dwc_modify_reg32(&global_regs->gotgctl,
19999 + if (gotgint.b.hstnegsucstschng) {
20000 + /* Print statements during the HNP interrupt handling
20001 + * can cause it to fail.*/
20002 + gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
20003 + if (gotgctl.b.hstnegscs) {
20004 + if (dwc_otg_is_host_mode(core_if)) {
20005 + core_if->op_state = B_HOST;
20007 + * Need to disable SOF interrupt immediately.
20008 + * When switching from device to host, the PCD
20009 + * interrupt handler won't handle the
20010 + * interrupt if host mode is already set. The
20011 + * HCD interrupt handler won't get called if
20012 + * the HCD state is HALT. This means that the
20013 + * interrupt does not get handled and Linux
20014 + * complains loudly.
20017 + gintmsk.b.sofintr = 1;
20018 + dwc_modify_reg32(&global_regs->gintmsk,
20020 + pcd_stop(core_if);
20022 + * Initialize the Core for Host mode.
20024 + hcd_start(core_if);
20025 + core_if->op_state = B_HOST;
20029 + gotgctl.b.hnpreq = 1;
20030 + gotgctl.b.devhnpen = 1;
20031 + dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
20032 + DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
20033 + __DWC_ERROR("Device Not Connected/Responding\n");
20036 + if (gotgint.b.hstnegdet) {
20037 + /* The disconnect interrupt is set at the same time as
20038 + * Host Negotiation Detected. During the mode
20039 + * switch all interrupts are cleared so the disconnect
20040 + * interrupt handler will not get executed.
20042 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
20043 + "Host Negotiation Detected++ (%s)\n",
20044 + (dwc_otg_is_host_mode(core_if) ? "Host" :
20046 + if (dwc_otg_is_device_mode(core_if)) {
20047 + DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
20048 + core_if->op_state);
20049 + hcd_disconnect(core_if);
20050 + pcd_start(core_if);
20051 + core_if->op_state = A_PERIPHERAL;
20054 + * Need to disable SOF interrupt immediately. When
20055 + * switching from device to host, the PCD interrupt
20056 + * handler won't handle the interrupt if host mode is
20057 + * already set. The HCD interrupt handler won't get
20058 + * called if the HCD state is HALT. This means that
20059 + * the interrupt does not get handled and Linux
20060 + * complains loudly.
20063 + gintmsk.b.sofintr = 1;
20064 + dwc_modify_reg32(&global_regs->gintmsk, gintmsk.d32, 0);
20065 + pcd_stop(core_if);
20066 + hcd_start(core_if);
20067 + core_if->op_state = A_HOST;
20070 + if (gotgint.b.adevtoutchng) {
20071 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
20072 + "A-Device Timeout Change++\n");
20074 + if (gotgint.b.debdone) {
20075 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
20078 + /* Clear GOTGINT */
20079 + dwc_write_reg32(&core_if->core_global_regs->gotgint, gotgint.d32);
20084 +void w_conn_id_status_change(void *p)
20086 + dwc_otg_core_if_t *core_if = p;
20087 + uint32_t count = 0;
20088 + gotgctl_data_t gotgctl = {.d32 = 0 };
20090 + gotgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
20091 + DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
20092 + DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
20094 + /* B-Device connector (Device Mode) */
20095 + if (gotgctl.b.conidsts) {
20096 + /* Wait for switch to device mode. */
20097 + while (!dwc_otg_is_device_mode(core_if)) {
20098 + DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
20099 + (dwc_otg_is_host_mode(core_if) ? "Host" :
20102 + if (++count > 10000)
20105 + DWC_ASSERT(++count < 10000,
20106 + "Connection id status change timed out");
20107 + core_if->op_state = B_PERIPHERAL;
20108 + dwc_otg_core_init(core_if);
20109 + dwc_otg_enable_global_interrupts(core_if);
20110 + pcd_start(core_if);
20112 + /* A-Device connector (Host Mode) */
20113 + while (!dwc_otg_is_host_mode(core_if)) {
20114 + DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
20115 + (dwc_otg_is_host_mode(core_if) ? "Host" :
20118 + if (++count > 10000)
20121 + DWC_ASSERT(++count < 10000,
20122 + "Connection id status change timed out");
20123 + core_if->op_state = A_HOST;
20125 + * Initialize the Core for Host mode.
20127 + dwc_otg_core_init(core_if);
20128 + dwc_otg_enable_global_interrupts(core_if);
20129 + hcd_start(core_if);
20134 + * This function handles the Connector ID Status Change Interrupt. It
20135 + * reads the OTG Interrupt Register (GOTCTL) to determine whether this
20136 + * is a Device to Host Mode transition or a Host Mode to Device
20139 + * This only occurs when the cable is connected/removed from the PHY
20142 + * @param core_if Programming view of DWC_otg controller.
20144 +int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
20148 + * Need to disable SOF interrupt immediately. If switching from device
20149 + * to host, the PCD interrupt handler won't handle the interrupt if
20150 + * host mode is already set. The HCD interrupt handler won't get
20151 + * called if the HCD state is HALT. This means that the interrupt does
20152 + * not get handled and Linux complains loudly.
20154 + gintmsk_data_t gintmsk = {.d32 = 0 };
20155 + gintsts_data_t gintsts = {.d32 = 0 };
20157 + gintmsk.b.sofintr = 1;
20158 + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
20160 + DWC_DEBUGPL(DBG_CIL,
20161 + " ++Connector ID Status Change Interrupt++ (%s)\n",
20162 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
20165 + * Need to schedule a work, as there are possible DELAY function calls
20167 + DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
20168 + core_if, "connection id status change");
20170 + /* Set flag and clear interrupt */
20171 + gintsts.b.conidstschng = 1;
20172 + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
20178 + * This interrupt indicates that a device is initiating the Session
20179 + * Request Protocol to request the host to turn on bus power so a new
20180 + * session can begin. The handler responds by turning on bus power. If
20181 + * the DWC_otg controller is in low power mode, the handler brings the
20182 + * controller out of low power mode before turning on bus power.
20184 + * @param core_if Programming view of DWC_otg controller.
20186 +int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
20188 + hprt0_data_t hprt0;
20189 + gintsts_data_t gintsts;
20191 +#ifndef DWC_HOST_ONLY
20192 + DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
20194 + if (dwc_otg_is_device_mode(core_if)) {
20195 + DWC_PRINTF("SRP: Device mode\n");
20197 + DWC_PRINTF("SRP: Host mode\n");
20199 + /* Turn on the port power bit. */
20200 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
20201 + hprt0.b.prtpwr = 1;
20202 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
20204 + /* Start the Connection timer. So a message can be displayed
20205 + * if connect does not occur within 10 seconds. */
20206 + hcd_session_start(core_if);
20210 + /* Clear interrupt */
20212 + gintsts.b.sessreqintr = 1;
20213 + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
20218 +void w_wakeup_detected(void *p)
20220 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
20222 + * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
20223 + * so that OPT tests pass with all PHYs).
20225 + hprt0_data_t hprt0 = {.d32 = 0 };
20227 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
20228 + /* Restart the Phy Clock */
20229 + pcgcctl.b.stoppclk = 1;
20230 + dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0);
20233 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
20234 + DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
20235 +// dwc_mdelay(70);
20236 + hprt0.b.prtres = 0; /* Resume */
20237 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
20238 + DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
20239 + dwc_read_reg32(core_if->host_if->hprt0));
20241 + hcd_resume(core_if);
20243 + /** Change to L0 state*/
20244 + core_if->lx_state = DWC_OTG_L0;
20249 + * This interrupt indicates that the DWC_otg controller has detected a
20250 + * resume or remote wakeup sequence. If the DWC_otg controller is in
20251 + * low power mode, the handler must brings the controller out of low
20252 + * power mode. The controller automatically begins resume
20253 + * signaling. The handler schedules a time to stop resume signaling.
20255 +int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
20257 + gintsts_data_t gintsts;
20259 + DWC_DEBUGPL(DBG_ANY,
20260 + "++Resume and Remote Wakeup Detected Interrupt++\n");
20262 + DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
20264 + if (dwc_otg_is_device_mode(core_if)) {
20265 + dctl_data_t dctl = {.d32 = 0 };
20266 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
20267 + dwc_read_reg32(&core_if->dev_if->dev_global_regs->
20269 + if (core_if->lx_state == DWC_OTG_L2) {
20270 +#ifdef PARTIAL_POWER_DOWN
20271 + if (core_if->hwcfg4.b.power_optimiz) {
20272 + pcgcctl_data_t power = {.d32 = 0 };
20274 + power.d32 = dwc_read_reg32(core_if->pcgcctl);
20275 + DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
20278 + power.b.stoppclk = 0;
20279 + dwc_write_reg32(core_if->pcgcctl, power.d32);
20281 + power.b.pwrclmp = 0;
20282 + dwc_write_reg32(core_if->pcgcctl, power.d32);
20284 + power.b.rstpdwnmodule = 0;
20285 + dwc_write_reg32(core_if->pcgcctl, power.d32);
20288 + /* Clear the Remote Wakeup Signalling */
20289 + dctl.b.rmtwkupsig = 1;
20290 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
20291 + dctl, dctl.d32, 0);
20293 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
20294 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->
20298 + glpmcfg_data_t lpmcfg;
20300 + dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
20301 + lpmcfg.b.hird_thres &= (~(1 << 4));
20302 + dwc_write_reg32(&core_if->core_global_regs->glpmcfg,
20305 + /** Change to L0 state*/
20306 + core_if->lx_state = DWC_OTG_L0;
20308 + if (core_if->lx_state != DWC_OTG_L1) {
20309 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
20311 + /* Restart the Phy Clock */
20312 + pcgcctl.b.stoppclk = 1;
20313 + dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0);
20315 + DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
20317 + /** Change to L0 state*/
20318 + core_if->lx_state = DWC_OTG_L0;
20322 + /* Clear interrupt */
20324 + gintsts.b.wkupintr = 1;
20325 + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
20331 + * This interrupt indicates that a device has been disconnected from
20334 +int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if)
20336 + gintsts_data_t gintsts;
20338 + DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
20339 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
20340 + op_state_str(core_if));
20342 +/** @todo Consolidate this if statement. */
20343 +#ifndef DWC_HOST_ONLY
20344 + if (core_if->op_state == B_HOST) {
20345 + /* If in device mode Disconnect and stop the HCD, then
20346 + * start the PCD. */
20347 + hcd_disconnect(core_if);
20348 + pcd_start(core_if);
20349 + core_if->op_state = B_PERIPHERAL;
20350 + } else if (dwc_otg_is_device_mode(core_if)) {
20351 + gotgctl_data_t gotgctl = {.d32 = 0 };
20353 + dwc_read_reg32(&core_if->core_global_regs->gotgctl);
20354 + if (gotgctl.b.hstsethnpen == 1) {
20355 + /* Do nothing, if HNP in process the OTG
20356 + * interrupt "Host Negotiation Detected"
20357 + * interrupt will do the mode switch.
20359 + } else if (gotgctl.b.devhnpen == 0) {
20360 + /* If in device mode Disconnect and stop the HCD, then
20361 + * start the PCD. */
20362 + hcd_disconnect(core_if);
20363 + pcd_start(core_if);
20364 + core_if->op_state = B_PERIPHERAL;
20366 + DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
20369 + if (core_if->op_state == A_HOST) {
20370 + /* A-Cable still connected but device disconnected. */
20371 + hcd_disconnect(core_if);
20375 + /* Change to L3(OFF) state */
20376 + core_if->lx_state = DWC_OTG_L3;
20379 + gintsts.b.disconnect = 1;
20380 + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
20385 + * This interrupt indicates that SUSPEND state has been detected on
20388 + * For HNP the USB Suspend interrupt signals the change from
20389 + * "a_peripheral" to "a_host".
20391 + * When power management is enabled the core will be put in low power
20394 +int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if)
20396 + dsts_data_t dsts;
20397 + gintsts_data_t gintsts;
20399 + DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
20401 + if (dwc_otg_is_device_mode(core_if)) {
20402 + /* Check the Device status register to determine if the Suspend
20403 + * state is active. */
20405 + dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
20406 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
20407 + DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
20408 + "HWCFG4.power Optimize=%d\n",
20409 + dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
20411 +#ifdef PARTIAL_POWER_DOWN
20412 +/** @todo Add a module parameter for power management. */
20414 + if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
20415 + pcgcctl_data_t power = {.d32 = 0 };
20416 + DWC_DEBUGPL(DBG_CIL, "suspend\n");
20418 + power.b.pwrclmp = 1;
20419 + dwc_write_reg32(core_if->pcgcctl, power.d32);
20421 + power.b.rstpdwnmodule = 1;
20422 + dwc_modify_reg32(core_if->pcgcctl, 0, power.d32);
20424 + power.b.stoppclk = 1;
20425 + dwc_modify_reg32(core_if->pcgcctl, 0, power.d32);
20428 + DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
20431 + /* PCD callback for suspend. */
20432 + pcd_suspend(core_if);
20434 + if (core_if->op_state == A_PERIPHERAL) {
20435 + DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
20436 + /* Clear the a_peripheral flag, back to a_host. */
20437 + pcd_stop(core_if);
20438 + hcd_start(core_if);
20439 + core_if->op_state = A_HOST;
20443 + /* Change to L2(suspend) state */
20444 + core_if->lx_state = DWC_OTG_L2;
20446 + /* Clear interrupt */
20448 + gintsts.b.usbsuspend = 1;
20449 + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
20454 +#ifdef CONFIG_USB_DWC_OTG_LPM
20456 + * This function hadles LPM transaction received interrupt.
20458 +static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
20460 + glpmcfg_data_t lpmcfg;
20461 + gintsts_data_t gintsts;
20463 + if (!core_if->core_params->lpm_enable) {
20464 + DWC_PRINTF("Unexpected LPM interrupt\n");
20467 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
20468 + DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
20470 + if (dwc_otg_is_host_mode(core_if)) {
20471 + hcd_sleep(core_if);
20473 + lpmcfg.b.hird_thres |= (1 << 4);
20474 + dwc_write_reg32(&core_if->core_global_regs->glpmcfg,
20478 + /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
20480 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
20481 + if (lpmcfg.b.prt_sleep_sts) {
20482 + /* Save the current state */
20483 + core_if->lx_state = DWC_OTG_L1;
20486 + /* Clear interrupt */
20488 + gintsts.b.lpmtranrcvd = 1;
20489 + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
20492 +#endif /* CONFIG_USB_DWC_OTG_LPM */
20495 + * This function returns the Core Interrupt register.
20497 +static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
20499 + gintsts_data_t gintsts;
20500 + gintmsk_data_t gintmsk;
20501 + gintmsk_data_t gintmsk_common = {.d32 = 0 };
20502 + gintmsk_common.b.wkupintr = 1;
20503 + gintmsk_common.b.sessreqintr = 1;
20504 + gintmsk_common.b.conidstschng = 1;
20505 + gintmsk_common.b.otgintr = 1;
20506 + gintmsk_common.b.modemismatch = 1;
20507 + gintmsk_common.b.disconnect = 1;
20508 + gintmsk_common.b.usbsuspend = 1;
20509 +#ifdef CONFIG_USB_DWC_OTG_LPM
20510 + gintmsk_common.b.lpmtranrcvd = 1;
20512 + /** @todo: The port interrupt occurs while in device
20513 + * mode. Added code to CIL to clear the interrupt for now!
20515 + gintmsk_common.b.portintr = 1;
20517 + gintsts.d32 = dwc_read_reg32(&core_if->core_global_regs->gintsts);
20518 + gintmsk.d32 = dwc_read_reg32(&core_if->core_global_regs->gintmsk);
20520 + /* if any common interrupts set */
20521 + if (gintsts.d32 & gintmsk_common.d32) {
20522 + DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
20523 + gintsts.d32, gintmsk.d32);
20527 + return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
20532 + * Common interrupt handler.
20534 + * The common interrupts are those that occur in both Host and Device mode.
20535 + * This handler handles the following interrupts:
20536 + * - Mode Mismatch Interrupt
20537 + * - Disconnect Interrupt
20538 + * - OTG Interrupt
20539 + * - Connector ID Status Change Interrupt
20540 + * - Session Request Interrupt.
20541 + * - Resume / Remote Wakeup Detected Interrupt.
20542 + * - LPM Transaction Received Interrutp
20545 +int32_t dwc_otg_handle_common_intr(dwc_otg_core_if_t * core_if)
20548 + gintsts_data_t gintsts;
20550 + gintsts.d32 = dwc_otg_read_common_intr(core_if);
20552 + if (gintsts.b.modemismatch) {
20553 + retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
20555 + if (gintsts.b.otgintr) {
20556 + retval |= dwc_otg_handle_otg_intr(core_if);
20558 + if (gintsts.b.conidstschng) {
20559 + retval |= dwc_otg_handle_conn_id_status_change_intr(core_if);
20561 + if (gintsts.b.disconnect) {
20562 + retval |= dwc_otg_handle_disconnect_intr(core_if);
20564 + if (gintsts.b.sessreqintr) {
20565 + retval |= dwc_otg_handle_session_req_intr(core_if);
20567 + if (gintsts.b.wkupintr) {
20568 + retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
20570 + if (gintsts.b.usbsuspend) {
20571 + retval |= dwc_otg_handle_usb_suspend_intr(core_if);
20573 +#ifdef CONFIG_USB_DWC_OTG_LPM
20574 + if (gintsts.b.lpmtranrcvd) {
20575 + retval |= dwc_otg_handle_lpm_intr(core_if);
20579 + if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
20580 + /* The port interrupt occurs while in device mode with HPRT0
20581 + * Port Enable/Disable.
20584 + gintsts.b.portintr = 1;
20585 + dwc_write_reg32(&core_if->core_global_regs->gintsts,
20593 +++ b/drivers/usb/host/dwc_otg/dwc_otg_core_if.h
20595 +/* ==========================================================================
20596 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $
20597 + * $Revision: #4 $
20598 + * $Date: 2008/12/18 $
20599 + * $Change: 1155299 $
20601 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
20602 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
20603 + * otherwise expressly agreed to in writing between Synopsys and you.
20605 + * The Software IS NOT an item of Licensed Software or Licensed Product under
20606 + * any End User Software License Agreement or Agreement for Licensed Product
20607 + * with Synopsys or any supplement thereto. You are permitted to use and
20608 + * redistribute this Software in source and binary forms, with or without
20609 + * modification, provided that redistributions of source code must retain this
20610 + * notice. You may not view, use, disclose, copy or distribute this file or
20611 + * any information contained herein except pursuant to this license grant from
20612 + * Synopsys. If you do not agree with this notice, including the disclaimer
20613 + * below, then you are not authorized to use the Software.
20615 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
20616 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20617 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20618 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
20619 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20620 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20621 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20622 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20623 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20624 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
20626 + * ========================================================================== */
20627 +#if !defined(__DWC_CORE_IF_H__)
20628 +#define __DWC_CORE_IF_H__
20630 +#include "dwc_os.h"
20633 + * This file defines DWC_OTG Core API
20636 +struct dwc_otg_core_if;
20637 +typedef struct dwc_otg_core_if dwc_otg_core_if_t;
20639 +/** Maximum number of Periodic FIFOs */
20640 +#define MAX_PERIO_FIFOS 15
20641 +/** Maximum number of Periodic FIFOs */
20642 +#define MAX_TX_FIFOS 15
20644 +/** Maximum number of Endpoints/HostChannels */
20645 +#define MAX_EPS_CHANNELS 16
20647 +extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr);
20648 +extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if);
20649 +extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if);
20651 +extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if);
20652 +extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if);
20654 +extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if);
20655 +extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if);
20657 +extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if);
20659 +/** This function should be called on every hardware interrupt. */
20660 +extern int32_t dwc_otg_handle_common_intr(dwc_otg_core_if_t * _core_if);
20662 +/** @name OTG Core Parameters */
20666 + * Specifies the OTG capabilities. The driver will automatically
20667 + * detect the value for this parameter if none is specified.
20668 + * 0 - HNP and SRP capable (default)
20669 + * 1 - SRP Only capable
20670 + * 2 - No HNP/SRP capable
20672 +extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val);
20673 +extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if);
20674 +#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
20675 +#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
20676 +#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
20677 +#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
20679 +extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val);
20680 +extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if);
20681 +#define dwc_param_opt_default 1
20684 + * Specifies whether to use slave or DMA mode for accessing the data
20685 + * FIFOs. The driver will automatically detect the value for this
20686 + * parameter if none is specified.
20688 + * 1 - DMA (default, if available)
20690 +extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if,
20692 +extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if);
20693 +#define dwc_param_dma_enable_default 1
20696 + * When DMA mode is enabled specifies whether to use
20697 + * address DMA or DMA Descritor mode for accessing the data
20698 + * FIFOs in device mode. The driver will automatically detect
20699 + * the value for this parameter if none is specified.
20700 + * 0 - address DMA
20701 + * 1 - DMA Descriptor(default, if available)
20703 +extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if,
20705 +extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if);
20706 +//#define dwc_param_dma_desc_enable_default 1
20707 +#define dwc_param_dma_desc_enable_default 0 // Broadcom BCM2708
20709 +/** The DMA Burst size (applicable only for External DMA
20710 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
20712 +extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if,
20714 +extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if);
20715 +#define dwc_param_dma_burst_size_default 32
20718 + * Specifies the maximum speed of operation in host and device mode.
20719 + * The actual speed depends on the speed of the attached device and
20720 + * the value of phy_type. The actual speed depends on the speed of the
20721 + * attached device.
20722 + * 0 - High Speed (default)
20725 +extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val);
20726 +extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if);
20727 +#define dwc_param_speed_default 0
20728 +#define DWC_SPEED_PARAM_HIGH 0
20729 +#define DWC_SPEED_PARAM_FULL 1
20731 +/** Specifies whether low power mode is supported when attached
20732 + * to a Full Speed or Low Speed device in host mode.
20733 + * 0 - Don't support low power mode (default)
20734 + * 1 - Support low power mode
20736 +extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
20737 + core_if, int32_t val);
20738 +extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t
20740 +#define dwc_param_host_support_fs_ls_low_power_default 0
20742 +/** Specifies the PHY clock rate in low power mode when connected to a
20743 + * Low Speed device in host mode. This parameter is applicable only if
20744 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
20745 + * then defaults to 6 MHZ otherwise 48 MHZ.
20750 +extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
20751 + core_if, int32_t val);
20752 +extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
20754 +#define dwc_param_host_ls_low_power_phy_clk_default 0
20755 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
20756 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
20759 + * 0 - Use cC FIFO size parameters
20760 + * 1 - Allow dynamic FIFO sizing (default)
20762 +extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
20764 +extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t *
20766 +#define dwc_param_enable_dynamic_fifo_default 1
20768 +/** Total number of 4-byte words in the data FIFO memory. This
20769 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
20771 + * 32 to 32768 (default 8192)
20772 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
20774 +extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if,
20776 +extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if);
20777 +//#define dwc_param_data_fifo_size_default 8192
20778 +#define dwc_param_data_fifo_size_default 0xFF0 // Broadcom BCM2708
20780 +/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
20781 + * FIFO sizing is enabled.
20782 + * 16 to 32768 (default 1064)
20784 +extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if,
20786 +extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if);
20787 +#define dwc_param_dev_rx_fifo_size_default 1064
20789 +/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
20790 + * when dynamic FIFO sizing is enabled.
20791 + * 16 to 32768 (default 1024)
20793 +extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
20794 + core_if, int32_t val);
20795 +extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
20797 +#define dwc_param_dev_nperio_tx_fifo_size_default 1024
20799 +/** Number of 4-byte words in each of the periodic Tx FIFOs in device
20800 + * mode when dynamic FIFO sizing is enabled.
20801 + * 4 to 768 (default 256)
20803 +extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
20804 + int32_t val, int fifo_num);
20805 +extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t *
20806 + core_if, int fifo_num);
20807 +#define dwc_param_dev_perio_tx_fifo_size_default 256
20809 +/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
20810 + * FIFO sizing is enabled.
20811 + * 16 to 32768 (default 1024)
20813 +extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
20815 +extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if);
20816 +//#define dwc_param_host_rx_fifo_size_default 1024
20817 +#define dwc_param_host_rx_fifo_size_default 774 // Broadcom BCM2708
20819 +/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
20820 + * when Dynamic FIFO sizing is enabled in the core.
20821 + * 16 to 32768 (default 1024)
20823 +extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
20824 + core_if, int32_t val);
20825 +extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
20827 +//#define dwc_param_host_nperio_tx_fifo_size_default 1024
20828 +#define dwc_param_host_nperio_tx_fifo_size_default 0x100 // Broadcom BCM2708
20830 +/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
20831 + * FIFO sizing is enabled.
20832 + * 16 to 32768 (default 1024)
20834 +extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
20835 + core_if, int32_t val);
20836 +extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
20838 +//#define dwc_param_host_perio_tx_fifo_size_default 1024
20839 +#define dwc_param_host_perio_tx_fifo_size_default 0x200 // Broadcom BCM2708
20841 +/** The maximum transfer size supported in bytes.
20842 + * 2047 to 65,535 (default 65,535)
20844 +extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
20846 +extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if);
20847 +#define dwc_param_max_transfer_size_default 65535
20849 +/** The maximum number of packets in a transfer.
20850 + * 15 to 511 (default 511)
20852 +extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if,
20854 +extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if);
20855 +#define dwc_param_max_packet_count_default 511
20857 +/** The number of host channel registers to use.
20858 + * 1 to 16 (default 12)
20859 + * Note: The FPGA configuration supports a maximum of 12 host channels.
20861 +extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if,
20863 +extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if);
20864 +#define dwc_param_host_channels_default 12
20866 +/** The number of endpoints in addition to EP0 available for device
20867 + * mode operations.
20868 + * 1 to 15 (default 6 IN and OUT)
20869 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
20870 + * endpoints in addition to EP0.
20872 +extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if,
20874 +extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if);
20875 +#define dwc_param_dev_endpoints_default 6
20878 + * Specifies the type of PHY interface to use. By default, the driver
20879 + * will automatically detect the phy_type.
20881 + * 0 - Full Speed PHY
20882 + * 1 - UTMI+ (default)
20885 +extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val);
20886 +extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if);
20887 +#define DWC_PHY_TYPE_PARAM_FS 0
20888 +#define DWC_PHY_TYPE_PARAM_UTMI 1
20889 +#define DWC_PHY_TYPE_PARAM_ULPI 2
20890 +#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
20893 + * Specifies the UTMI+ Data Width. This parameter is
20894 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
20895 + * PHY_TYPE, this parameter indicates the data width between
20896 + * the MAC and the ULPI Wrapper.) Also, this parameter is
20897 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
20898 + * to "8 and 16 bits", meaning that the core has been
20899 + * configured to work at either data path width.
20901 + * 8 or 16 bits (default 16)
20903 +extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if,
20905 +extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if);
20906 +//#define dwc_param_phy_utmi_width_default 16
20907 +#define dwc_param_phy_utmi_width_default 8 // Broadcom BCM2708
20910 + * Specifies whether the ULPI operates at double or single
20911 + * data rate. This parameter is only applicable if PHY_TYPE is
20914 + * 0 - single data rate ULPI interface with 8 bit wide data
20916 + * 1 - double data rate ULPI interface with 4 bit wide data
20919 +extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if,
20921 +extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if);
20922 +#define dwc_param_phy_ulpi_ddr_default 0
20925 + * Specifies whether to use the internal or external supply to
20926 + * drive the vbus with a ULPI phy.
20928 +extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
20930 +extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if);
20931 +#define DWC_PHY_ULPI_INTERNAL_VBUS 0
20932 +#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
20933 +#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
20936 + * Specifies whether to use the I2Cinterface for full speed PHY. This
20937 + * parameter is only applicable if PHY_TYPE is FS.
20938 + * 0 - No (default)
20941 +extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if,
20943 +extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if);
20944 +#define dwc_param_i2c_enable_default 0
20946 +extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if,
20948 +extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if);
20949 +#define dwc_param_ulpi_fs_ls_default 0
20951 +extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val);
20952 +extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if);
20953 +#define dwc_param_ts_dline_default 0
20956 + * Specifies whether dedicated transmit FIFOs are
20957 + * enabled for non periodic IN endpoints in device mode
20961 +extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
20963 +extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t *
20965 +#define dwc_param_en_multiple_tx_fifo_default 1
20967 +/** Number of 4-byte words in each of the Tx FIFOs in device
20968 + * mode when dynamic FIFO sizing is enabled.
20969 + * 4 to 768 (default 256)
20971 +extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
20972 + int fifo_num, int32_t val);
20973 +extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
20975 +#define dwc_param_dev_tx_fifo_size_default 256
20977 +/** Thresholding enable flag-
20978 + * bit 0 - enable non-ISO Tx thresholding
20979 + * bit 1 - enable ISO Tx thresholding
20980 + * bit 2 - enable Rx thresholding
20982 +extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val);
20983 +extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num);
20984 +#define dwc_param_thr_ctl_default 0
20986 +/** Thresholding length for Tx
20987 + * FIFOs in 32 bit DWORDs
20989 +extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if,
20991 +extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if);
20992 +#define dwc_param_tx_thr_length_default 64
20994 +/** Thresholding length for Rx
20995 + * FIFOs in 32 bit DWORDs
20997 +extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if,
20999 +extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if);
21000 +#define dwc_param_rx_thr_length_default 64
21003 + * Specifies whether LPM (Link Power Management) support is enabled
21005 +extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if,
21007 +extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if);
21008 +#define dwc_param_lpm_enable_default 1
21011 + * Specifies whether PTI enhancement is enabled
21013 +extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if,
21015 +extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if);
21016 +#define dwc_param_pti_enable_default 0
21019 + * Specifies whether MPI enhancement is enabled
21021 +extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if,
21023 +extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if);
21024 +#define dwc_param_mpi_enable_default 0
21027 + * Specifies whether IC_USB capability is enabled
21029 +extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
21031 +extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if);
21032 +#define dwc_param_ic_usb_cap_default 0
21034 +extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val);
21035 +extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if);
21036 +#define dwc_param_ahb_thr_ratio_default 0
21040 +/** @name Access to registers and bit-fields */
21043 + * Dump core registers and SPRAM
21045 +extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if);
21046 +extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if);
21047 +extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if);
21048 +extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if);
21051 + * Get host negotiation status.
21053 +extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if);
21058 +extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if);
21061 + * Set hnpreq bit in the GOTGCTL register.
21063 +extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val);
21066 + * Get Content of SNPSID register.
21068 +extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if);
21071 + * Get current mode.
21072 + * Returns 0 if in device mode, and 1 if in host mode.
21074 +extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if);
21077 + * Get value of hnpcapable field in the GUSBCFG register
21079 +extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if);
21081 + * Set value of hnpcapable field in the GUSBCFG register
21083 +extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
21086 + * Get value of srpcapable field in the GUSBCFG register
21088 +extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if);
21090 + * Set value of srpcapable field in the GUSBCFG register
21092 +extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
21095 + * Get value of devspeed field in the DCFG register
21097 +extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if);
21099 + * Set value of devspeed field in the DCFG register
21101 +extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val);
21104 + * Get the value of busconnected field from the HPRT0 register
21106 +extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if);
21109 + * Gets the device enumeration Speed.
21111 +extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if);
21114 + * Get value of prtpwr field from the HPRT0 register
21116 +extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if);
21118 + * Set value of prtpwr field from the HPRT0 register
21120 +extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val);
21123 + * Get value of prtsusp field from the HPRT0 regsiter
21125 +extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if);
21127 + * Set value of prtpwr field from the HPRT0 register
21129 +extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val);
21132 + * Set value of prtres field from the HPRT0 register
21135 +extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val);
21138 + * Get value of rmtwkupsig bit in DCTL register
21140 +extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if);
21143 + * Get value of prt_sleep_sts field from the GLPMCFG register
21145 +extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if);
21148 + * Get value of rem_wkup_en field from the GLPMCFG register
21150 +extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if);
21153 + * Get value of appl_resp field from the GLPMCFG register
21155 +extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if);
21157 + * Set value of appl_resp field from the GLPMCFG register
21159 +extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val);
21162 + * Get value of hsic_connect field from the GLPMCFG register
21164 +extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if);
21166 + * Set value of hsic_connect field from the GLPMCFG register
21168 +extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val);
21171 + * Get value of inv_sel_hsic field from the GLPMCFG register.
21173 +extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if);
21175 + * Set value of inv_sel_hsic field from the GLPMFG register.
21177 +extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val);
21180 + * Some functions for accessing registers
21184 + * GOTGCTL register
21186 +extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if);
21187 +extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val);
21190 + * GUSBCFG register
21192 +extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if);
21193 +extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val);
21196 + * GRXFSIZ register
21198 +extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if);
21199 +extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
21202 + * GNPTXFSIZ register
21204 +extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if);
21205 +extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
21207 +extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if);
21208 +extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val);
21213 +extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if);
21214 +extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val);
21219 +extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if);
21220 +extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val);
21225 +extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if);
21226 +extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val);
21231 +extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if);
21235 +#endif /* __DWC_CORE_IF_H__ */
21237 +++ b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h
21239 +/* ==========================================================================
21241 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
21242 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
21243 + * otherwise expressly agreed to in writing between Synopsys and you.
21245 + * The Software IS NOT an item of Licensed Software or Licensed Product under
21246 + * any End User Software License Agreement or Agreement for Licensed Product
21247 + * with Synopsys or any supplement thereto. You are permitted to use and
21248 + * redistribute this Software in source and binary forms, with or without
21249 + * modification, provided that redistributions of source code must retain this
21250 + * notice. You may not view, use, disclose, copy or distribute this file or
21251 + * any information contained herein except pursuant to this license grant from
21252 + * Synopsys. If you do not agree with this notice, including the disclaimer
21253 + * below, then you are not authorized to use the Software.
21255 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
21256 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21257 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21258 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
21259 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21260 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21261 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21262 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21263 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21264 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
21266 + * ========================================================================== */
21268 +#ifndef __DWC_OTG_DBG_H__
21269 +#define __DWC_OTG_DBG_H__
21272 + * This file defines debug levels.
21273 + * Debugging support vanishes in non-debug builds.
21277 + * The Debug Level bit-mask variable.
21279 +extern uint32_t g_dbg_lvl;
21281 + * Set the Debug Level variable.
21283 +static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new)
21285 + uint32_t old = g_dbg_lvl;
21290 +/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
21291 +#define DBG_CIL (0x2)
21292 +/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
21294 +#define DBG_CILV (0x20)
21295 +/** When debug level has the DBG_PCD bit set, display PCD (Device) debug
21297 +#define DBG_PCD (0x4)
21298 +/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
21300 +#define DBG_PCDV (0x40)
21301 +/** When debug level has the DBG_HCD bit set, display Host debug messages */
21302 +#define DBG_HCD (0x8)
21303 +/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
21305 +#define DBG_HCDV (0x80)
21306 +/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
21308 +#define DBG_HCD_URB (0x800)
21310 +/** When debug level has any bit set, display debug messages */
21311 +#define DBG_ANY (0xFF)
21313 +/** All debug messages off */
21316 +/** Prefix string for DWC_DEBUG print macros. */
21317 +#define USB_DWC "DWC_otg: "
21320 + * Print a debug message when the Global debug level variable contains
21321 + * the bit defined in <code>lvl</code>.
21323 + * @param[in] lvl - Debug level, use one of the DBG_ constants above.
21324 + * @param[in] x - like printf
21328 + * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
21331 + * results in:<br>
21333 + * usb-DWC_otg: dwc_otg_cil_init(ca867000)
21338 +# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0)
21339 +# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x )
21341 +# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
21345 +# define DWC_DEBUGPL(lvl, x...) do{}while(0)
21346 +# define DWC_DEBUGP(x...)
21348 +# define CHK_DEBUG_LEVEL(level) (0)
21353 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
21355 +/* ==========================================================================
21356 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $
21357 + * $Revision: #76 $
21358 + * $Date: 2009/05/03 $
21359 + * $Change: 1245589 $
21361 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
21362 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
21363 + * otherwise expressly agreed to in writing between Synopsys and you.
21365 + * The Software IS NOT an item of Licensed Software or Licensed Product under
21366 + * any End User Software License Agreement or Agreement for Licensed Product
21367 + * with Synopsys or any supplement thereto. You are permitted to use and
21368 + * redistribute this Software in source and binary forms, with or without
21369 + * modification, provided that redistributions of source code must retain this
21370 + * notice. You may not view, use, disclose, copy or distribute this file or
21371 + * any information contained herein except pursuant to this license grant from
21372 + * Synopsys. If you do not agree with this notice, including the disclaimer
21373 + * below, then you are not authorized to use the Software.
21375 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
21376 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21377 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21378 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
21379 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21380 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21381 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21382 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21383 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21384 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
21386 + * ========================================================================== */
21389 + * The dwc_otg_driver module provides the initialization and cleanup entry
21390 + * points for the DWC_otg driver. This module will be dynamically installed
21391 + * after Linux is booted using the insmod command. When the module is
21392 + * installed, the dwc_otg_driver_init function is called. When the module is
21393 + * removed (using rmmod), the dwc_otg_driver_cleanup function is called.
21395 + * This module also defines a data structure for the dwc_otg_driver, which is
21396 + * used in conjunction with the standard ARM lm_device structure. These
21397 + * structures allow the OTG driver to comply with the standard Linux driver
21398 + * model in which devices and drivers are registered with a bus driver. This
21399 + * has the benefit that Linux can expose attributes of the driver and device
21400 + * in its special sysfs file system. Users can then read or write files in
21401 + * this file system to perform diagnostics on the driver components or the
21405 +#include <linux/kernel.h>
21406 +#include <linux/module.h>
21407 +#include <linux/moduleparam.h>
21408 +#include <linux/init.h>
21409 +#include <linux/device.h>
21410 +#include <linux/errno.h>
21411 +#include <linux/types.h>
21412 +#include <linux/stat.h> /* permission constants */
21413 +#include <linux/version.h>
21414 +#include <linux/interrupt.h>
21416 +#ifdef LM_INTERFACE
21417 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
21418 +#include <asm/arch/lm.h>
21419 +#include <asm/arch/hardware.h>
21421 +/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure -
21422 + here we use definitions stolen from arm-integrator headers
21424 +#include <mach/lm.h>
21425 +#include <mach/hardware.h>
21427 +#include <asm/sizes.h>
21428 +#include <asm/mach/map.h>
21430 +#elif defined(PLATFORM_INTERFACE)
21432 +#include <linux/platform_device.h>
21433 +#include <asm/mach/map.h>
21437 +# include <linux/irq.h>
21439 +#include <asm/io.h>
21442 +#include "dwc_os.h"
21443 +#include "dwc_otg_dbg.h"
21444 +#include "dwc_otg_driver.h"
21445 +#include "dwc_otg_attr.h"
21446 +#include "dwc_otg_core_if.h"
21447 +#include "dwc_otg_pcd_if.h"
21448 +#include "dwc_otg_hcd_if.h"
21450 +#define DWC_DRIVER_VERSION "2.90b 6-MAY-2010"
21451 +#define DWC_DRIVER_DESC "HS OTG USB Controller driver"
21453 +static const char dwc_driver_name[] = "dwc_otg";
21455 +extern int pcd_init(
21456 +#ifdef LM_INTERFACE
21457 + struct lm_device *_dev
21458 +#elif defined(PCI_INTERFACE)
21459 + struct pci_dev *_dev
21460 +#elif defined(PLATFORM_INTERFACE)
21461 + struct platform_device *dev
21464 +extern int hcd_init(
21465 +#ifdef LM_INTERFACE
21466 + struct lm_device *_dev
21467 +#elif defined(PCI_INTERFACE)
21468 + struct pci_dev *_dev
21469 +#elif defined(PLATFORM_INTERFACE)
21470 + struct platform_device *dev
21474 +extern int pcd_remove(
21475 +#ifdef LM_INTERFACE
21476 + struct lm_device *_dev
21477 +#elif defined(PCI_INTERFACE)
21478 + struct pci_dev *_dev
21479 +#elif defined(PLATFORM_INTERFACE)
21480 + struct platform_device *_dev
21484 +extern void hcd_remove(
21485 +#ifdef LM_INTERFACE
21486 + struct lm_device *_dev
21487 +#elif defined(PCI_INTERFACE)
21488 + struct pci_dev *_dev
21489 +#elif defined(PLATFORM_INTERFACE)
21490 + struct platform_device *_dev
21494 +/*-------------------------------------------------------------------------*/
21495 +/* Encapsulate the module parameter settings */
21497 +struct dwc_otg_driver_module_params {
21500 + int32_t dma_enable;
21501 + int32_t dma_desc_enable;
21502 + int32_t dma_burst_size;
21504 + int32_t host_support_fs_ls_low_power;
21505 + int32_t host_ls_low_power_phy_clk;
21506 + int32_t enable_dynamic_fifo;
21507 + int32_t data_fifo_size;
21508 + int32_t dev_rx_fifo_size;
21509 + int32_t dev_nperio_tx_fifo_size;
21510 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
21511 + int32_t host_rx_fifo_size;
21512 + int32_t host_nperio_tx_fifo_size;
21513 + int32_t host_perio_tx_fifo_size;
21514 + int32_t max_transfer_size;
21515 + int32_t max_packet_count;
21516 + int32_t host_channels;
21517 + int32_t dev_endpoints;
21518 + int32_t phy_type;
21519 + int32_t phy_utmi_width;
21520 + int32_t phy_ulpi_ddr;
21521 + int32_t phy_ulpi_ext_vbus;
21522 + int32_t i2c_enable;
21523 + int32_t ulpi_fs_ls;
21524 + int32_t ts_dline;
21525 + int32_t en_multiple_tx_fifo;
21526 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
21527 + uint32_t thr_ctl;
21528 + uint32_t tx_thr_length;
21529 + uint32_t rx_thr_length;
21530 + int32_t pti_enable;
21531 + int32_t mpi_enable;
21532 + int32_t lpm_enable;
21533 + int32_t ic_usb_cap;
21534 + int32_t ahb_thr_ratio;
21537 +static struct dwc_otg_driver_module_params dwc_otg_module_params = {
21540 + .dma_enable = -1,
21541 + .dma_desc_enable = -1,
21542 + .dma_burst_size = -1,
21544 + .host_support_fs_ls_low_power = -1,
21545 + .host_ls_low_power_phy_clk = -1,
21546 + .enable_dynamic_fifo = -1,
21547 + .data_fifo_size = -1,
21548 + .dev_rx_fifo_size = -1,
21549 + .dev_nperio_tx_fifo_size = -1,
21550 + .dev_perio_tx_fifo_size = {
21551 + /* dev_perio_tx_fifo_size_1 */
21569 + .host_rx_fifo_size = -1,
21570 + .host_nperio_tx_fifo_size = -1,
21571 + .host_perio_tx_fifo_size = -1,
21572 + .max_transfer_size = -1,
21573 + .max_packet_count = -1,
21574 + .host_channels = -1,
21575 + .dev_endpoints = -1,
21577 + .phy_utmi_width = -1,
21578 + .phy_ulpi_ddr = -1,
21579 + .phy_ulpi_ext_vbus = -1,
21580 + .i2c_enable = -1,
21581 + .ulpi_fs_ls = -1,
21583 + .en_multiple_tx_fifo = -1,
21584 + .dev_tx_fifo_size = {
21585 + /* dev_tx_fifo_size */
21604 + .tx_thr_length = -1,
21605 + .rx_thr_length = -1,
21606 + .pti_enable = -1,
21607 + .mpi_enable = -1,
21608 + .lpm_enable = -1,
21609 + .ic_usb_cap = -1,
21610 + .ahb_thr_ratio = -1,
21614 + * This function shows the Driver Version.
21616 +static ssize_t version_show(struct device_driver *dev, char *buf)
21618 + return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n",
21619 + DWC_DRIVER_VERSION);
21622 +static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
21625 + * Global Debug Level Mask.
21627 +uint32_t g_dbg_lvl = 0; /* OFF */
21630 + * This function shows the driver Debug Level.
21632 +static ssize_t dbg_level_show(struct device_driver *drv, char *buf)
21634 + return sprintf(buf, "0x%0x\n", g_dbg_lvl);
21638 + * This function stores the driver Debug Level.
21640 +static ssize_t dbg_level_store(struct device_driver *drv, const char *buf,
21643 + g_dbg_lvl = simple_strtoul(buf, NULL, 16);
21647 +static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show,
21648 + dbg_level_store);
21651 + * This function is called during module intialization
21652 + * to pass module parameters to the DWC_OTG CORE.
21654 +static int set_parameters(dwc_otg_core_if_t * core_if)
21659 + if (dwc_otg_module_params.otg_cap != -1) {
21661 + dwc_otg_set_param_otg_cap(core_if,
21662 + dwc_otg_module_params.otg_cap);
21664 + if (dwc_otg_module_params.dma_enable != -1) {
21666 + dwc_otg_set_param_dma_enable(core_if,
21667 + dwc_otg_module_params.
21670 + if (dwc_otg_module_params.dma_desc_enable != -1) {
21672 + dwc_otg_set_param_dma_desc_enable(core_if,
21673 + dwc_otg_module_params.
21674 + dma_desc_enable);
21676 + if (dwc_otg_module_params.opt != -1) {
21678 + dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt);
21680 + if (dwc_otg_module_params.dma_burst_size != -1) {
21682 + dwc_otg_set_param_dma_burst_size(core_if,
21683 + dwc_otg_module_params.
21686 + if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) {
21688 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
21689 + dwc_otg_module_params.
21690 + host_support_fs_ls_low_power);
21692 + if (dwc_otg_module_params.enable_dynamic_fifo != -1) {
21694 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
21695 + dwc_otg_module_params.
21696 + enable_dynamic_fifo);
21698 + if (dwc_otg_module_params.data_fifo_size != -1) {
21700 + dwc_otg_set_param_data_fifo_size(core_if,
21701 + dwc_otg_module_params.
21704 + if (dwc_otg_module_params.dev_rx_fifo_size != -1) {
21706 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
21707 + dwc_otg_module_params.
21708 + dev_rx_fifo_size);
21710 + if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) {
21712 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
21713 + dwc_otg_module_params.
21714 + dev_nperio_tx_fifo_size);
21716 + if (dwc_otg_module_params.host_rx_fifo_size != -1) {
21718 + dwc_otg_set_param_host_rx_fifo_size(core_if,
21719 + dwc_otg_module_params.host_rx_fifo_size);
21721 + if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) {
21723 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
21724 + dwc_otg_module_params.
21725 + host_nperio_tx_fifo_size);
21727 + if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) {
21729 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
21730 + dwc_otg_module_params.
21731 + host_perio_tx_fifo_size);
21733 + if (dwc_otg_module_params.max_transfer_size != -1) {
21735 + dwc_otg_set_param_max_transfer_size(core_if,
21736 + dwc_otg_module_params.
21737 + max_transfer_size);
21739 + if (dwc_otg_module_params.max_packet_count != -1) {
21741 + dwc_otg_set_param_max_packet_count(core_if,
21742 + dwc_otg_module_params.
21743 + max_packet_count);
21745 + if (dwc_otg_module_params.host_channels != -1) {
21747 + dwc_otg_set_param_host_channels(core_if,
21748 + dwc_otg_module_params.
21751 + if (dwc_otg_module_params.dev_endpoints != -1) {
21753 + dwc_otg_set_param_dev_endpoints(core_if,
21754 + dwc_otg_module_params.
21757 + if (dwc_otg_module_params.phy_type != -1) {
21759 + dwc_otg_set_param_phy_type(core_if,
21760 + dwc_otg_module_params.phy_type);
21762 + if (dwc_otg_module_params.speed != -1) {
21764 + dwc_otg_set_param_speed(core_if,
21765 + dwc_otg_module_params.speed);
21767 + if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) {
21769 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
21770 + dwc_otg_module_params.
21771 + host_ls_low_power_phy_clk);
21773 + if (dwc_otg_module_params.phy_ulpi_ddr != -1) {
21775 + dwc_otg_set_param_phy_ulpi_ddr(core_if,
21776 + dwc_otg_module_params.
21779 + if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) {
21781 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
21782 + dwc_otg_module_params.
21783 + phy_ulpi_ext_vbus);
21785 + if (dwc_otg_module_params.phy_utmi_width != -1) {
21787 + dwc_otg_set_param_phy_utmi_width(core_if,
21788 + dwc_otg_module_params.
21791 + if (dwc_otg_module_params.ulpi_fs_ls != -1) {
21793 + dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_otg_module_params.ulpi_fs_ls);
21795 + if (dwc_otg_module_params.ts_dline != -1) {
21797 + dwc_otg_set_param_ts_dline(core_if,
21798 + dwc_otg_module_params.ts_dline);
21800 + if (dwc_otg_module_params.i2c_enable != -1) {
21802 + dwc_otg_set_param_i2c_enable(core_if,
21803 + dwc_otg_module_params.
21806 + if (dwc_otg_module_params.en_multiple_tx_fifo != -1) {
21808 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
21809 + dwc_otg_module_params.
21810 + en_multiple_tx_fifo);
21812 + for (i = 0; i < 15; i++) {
21813 + if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) {
21815 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
21816 + dwc_otg_module_params.
21817 + dev_perio_tx_fifo_size
21822 + for (i = 0; i < 15; i++) {
21823 + if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) {
21824 + retval += dwc_otg_set_param_dev_tx_fifo_size(core_if,
21825 + dwc_otg_module_params.
21830 + if (dwc_otg_module_params.thr_ctl != -1) {
21832 + dwc_otg_set_param_thr_ctl(core_if,
21833 + dwc_otg_module_params.thr_ctl);
21835 + if (dwc_otg_module_params.mpi_enable != -1) {
21837 + dwc_otg_set_param_mpi_enable(core_if,
21838 + dwc_otg_module_params.
21841 + if (dwc_otg_module_params.pti_enable != -1) {
21843 + dwc_otg_set_param_pti_enable(core_if,
21844 + dwc_otg_module_params.
21847 + if (dwc_otg_module_params.lpm_enable != -1) {
21849 + dwc_otg_set_param_lpm_enable(core_if,
21850 + dwc_otg_module_params.
21853 + if (dwc_otg_module_params.ic_usb_cap != -1) {
21855 + dwc_otg_set_param_ic_usb_cap(core_if,
21856 + dwc_otg_module_params.
21859 + if (dwc_otg_module_params.tx_thr_length != -1) {
21861 + dwc_otg_set_param_tx_thr_length(core_if,
21862 + dwc_otg_module_params.tx_thr_length);
21864 + if (dwc_otg_module_params.rx_thr_length != -1) {
21866 + dwc_otg_set_param_rx_thr_length(core_if,
21867 + dwc_otg_module_params.
21870 + if(dwc_otg_module_params.ahb_thr_ratio != -1) {
21872 + dwc_otg_set_param_ahb_thr_ratio(core_if, dwc_otg_module_params.ahb_thr_ratio);
21878 + * This function is the top level interrupt handler for the Common
21879 + * (Device and host modes) interrupts.
21881 +static irqreturn_t dwc_otg_common_irq(int irq, void *dev)
21883 + dwc_otg_device_t *otg_dev = dev;
21884 + int32_t retval = IRQ_NONE;
21886 + retval = dwc_otg_handle_common_intr(otg_dev->core_if);
21887 + if (retval != 0) {
21888 + S3C2410X_CLEAR_EINTPEND();
21890 + return IRQ_RETVAL(retval);
21894 + * This function is called when a lm_device is unregistered with the
21895 + * dwc_otg_driver. This happens, for example, when the rmmod command is
21896 + * executed. The device may or may not be electrically present. If it is
21897 + * present, the driver stops device processing. Any resources used on behalf
21898 + * of this device are freed.
21902 +#ifdef LM_INTERFACE
21903 +static void dwc_otg_driver_remove(
21904 + struct lm_device *_dev
21905 +#elif defined(PCI_INTERFACE)
21906 +static void dwc_otg_driver_remove(
21907 + struct pci_dev *_dev
21908 +#elif defined(PLATFORM_INTERFACE)
21909 +static int dwc_otg_driver_remove(
21910 + struct platform_device *_dev
21915 +#ifdef LM_INTERFACE
21916 + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
21917 +#elif defined(PCI_INTERFACE)
21918 + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
21919 +#elif defined(PLATFORM_INTERFACE)
21920 + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
21924 + DWC_DEBUGPL(DBG_ANY, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
21927 + /* Memory allocation for the dwc_otg_device failed. */
21928 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
21929 +#ifdef PLATFORM_INTERFACE
21935 +#ifndef DWC_DEVICE_ONLY
21936 + if (otg_dev->hcd) {
21937 + hcd_remove(_dev);
21939 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
21940 +#ifdef PLATFORM_INTERFACE
21948 +#ifndef DWC_HOST_ONLY
21949 + if (otg_dev->pcd) {
21950 + pcd_remove(_dev);
21956 + if (otg_dev->common_irq_installed) {
21957 +#ifdef PLATFORM_INTERFACE
21958 + free_irq(platform_get_irq(_dev, 0), otg_dev);
21960 + free_irq(_dev->irq, otg_dev);
21964 + if (otg_dev->core_if) {
21965 + dwc_otg_cil_remove(otg_dev->core_if);
21969 + * Remove the device attributes
21971 + dwc_otg_attr_remove(_dev);
21974 + * Return the memory.
21976 + if (otg_dev->base) {
21977 + iounmap(otg_dev->base);
21979 + dwc_free(otg_dev);
21982 + * Clear the drvdata pointer.
21984 +#ifdef LM_INTERFACE
21985 + lm_set_drvdata(_dev, 0);
21986 +#elif defined(PCI_INTERFACE)
21987 + release_mem_region(otg_dev->rsrc_start, otg_dev->rsrc_len);
21988 + pci_set_drvdata(_dev, 0);
21989 +#elif defined(PLATFORM_INTERFACE)
21990 + platform_set_drvdata(_dev, 0);
21996 + * This function is called when an lm_device is bound to a
21997 + * dwc_otg_driver. It creates the driver components required to
21998 + * control the device (CIL, HCD, and PCD) and it initializes the
21999 + * device. The driver components are stored in a dwc_otg_device
22000 + * structure. A reference to the dwc_otg_device is saved in the
22001 + * lm_device. This allows the driver to access the dwc_otg_device
22002 + * structure on subsequent calls to driver methods for this device.
22004 + * @param _dev Bus device
22006 +static int dwc_otg_driver_probe(
22007 +#ifdef LM_INTERFACE
22008 +struct lm_device *_dev
22009 +#elif defined(PCI_INTERFACE)
22010 +struct pci_dev *_dev, const struct pci_device_id *id
22011 +#elif defined(PLATFORM_INTERFACE)
22012 +struct platform_device *_dev
22017 + dwc_otg_device_t *dwc_otg_device;
22020 + dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev);
22021 +#ifdef LM_INTERFACE
22022 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource.start);
22023 +#elif defined(PCI_INTERFACE)
22025 + DWC_ERROR("Invalid pci_device_id %p", id);
22029 + if (!_dev || (pci_enable_device(_dev) < 0)) {
22030 + DWC_ERROR("Invalid pci_device %p", _dev);
22033 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(_dev,0));
22034 + /* other stuff needed as well? */
22036 +#elif defined(PLATFORM_INTERFACE)
22037 + dev_dbg(&_dev->dev, "start=0x%08x (len 0x%x)\n",
22038 + (unsigned)_dev->resource->start,
22039 + (unsigned)(_dev->resource->end - _dev->resource->start));
22043 + dwc_otg_device = dwc_alloc(sizeof(dwc_otg_device_t));
22045 + if (!dwc_otg_device) {
22046 + dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n");
22047 + retval = -ENOMEM;
22051 + memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
22052 + dwc_otg_device->reg_offset = 0xFFFFFFFF;
22055 + * Map the DWC_otg Core memory into virtual address space.
22057 +#ifdef LM_INTERFACE
22059 + dwc_otg_device->base = ioremap(_dev->resource.start, SZ_256K);
22061 + struct map_desc desc = {
22062 + .virtual = IO_ADDRESS((unsigned)_dev->resource.start),
22063 + .pfn = __phys_to_pfn((unsigned)_dev->resource.start),
22064 + .length = SZ_128K,
22065 + .type = MT_DEVICE
22067 + iotable_init(&desc, 1);
22068 + dwc_otg_device->base = (void *)desc.virtual;
22071 + if (!dwc_otg_device->base) {
22072 + dev_err(&_dev->dev, "ioremap() failed\n");
22073 + retval = -ENOMEM;
22076 + dev_dbg(&_dev->dev, "base=0x%08x\n", (unsigned)dwc_otg_device->base);
22077 +#elif defined(PCI_INTERFACE)
22078 + _dev->current_state = PCI_D0;
22079 + _dev->dev.power.power_state = PMSG_ON;
22081 + if (!_dev->irq) {
22082 + DWC_ERROR("Found HC with no IRQ. Check BIOS/PCI %s setup!", pci_name(_dev));
22083 + retval = -ENODEV;
22087 + dwc_otg_device->rsrc_start = pci_resource_start(_dev,0);
22088 + dwc_otg_device->rsrc_len = pci_resource_len(_dev,0);
22089 + DWC_DEBUGPL(DBG_ANY,"PCI resource: start=%08x, len=%08x\n",
22090 + dwc_otg_device->rsrc_start,
22091 + dwc_otg_device->rsrc_len);
22092 + if (!request_mem_region(dwc_otg_device->rsrc_start, dwc_otg_device->rsrc_len, "dwc_otg")) {
22093 + dev_dbg(&_dev->dev, "error mapping memory\n");
22094 + retval = -EFAULT;
22098 + dwc_otg_device->base = ioremap_nocache(dwc_otg_device->rsrc_start, dwc_otg_device->rsrc_len);
22099 + if (dwc_otg_device->base == NULL) {
22100 + dev_dbg(&_dev->dev, "error mapping memory\n");
22101 + retval = -EFAULT;
22104 + dev_dbg(&_dev->dev, "base=0x%p (before adjust) \n", dwc_otg_device->base);
22105 + dwc_otg_device->base = (char *)dwc_otg_device->base;
22106 + dev_dbg(&_dev->dev, "base=0x%p (after adjust) \n", dwc_otg_device->base);
22107 + dev_dbg(&_dev->dev, "%s: mapped PA 0x%x to VA 0x%p\n", __func__,
22108 + (unsigned)dwc_otg_device->rsrc_start, dwc_otg_device->base);
22110 + pci_set_drvdata(_dev, dwc_otg_device);
22111 + pci_set_master(_dev);
22112 +#elif defined(PLATFORM_INTERFACE)
22113 + DWC_DEBUGPL(DBG_ANY,"Platform resource: start=%08x, len=%08x\n",
22114 + _dev->resource->start,
22115 + _dev->resource->end - _dev->resource->start + 1);
22117 + if (!request_mem_region(_dev->resource->start,
22118 + _dev->resource->end - _dev->resource->start + 1,
22120 + dev_dbg(&_dev->dev, "error reserving mapped memory\n");
22121 + retval = -EFAULT;
22125 + dwc_otg_device->base = ioremap_nocache(_dev->resource->start,
22126 + _dev->resource->end -
22127 + _dev->resource->start + 1);
22130 + struct map_desc desc = {
22131 + .virtual = IO_ADDRESS((unsigned)_dev->resource->start),
22132 + .pfn = __phys_to_pfn((unsigned)_dev->resource->start),
22133 + .length = SZ_128K,
22134 + .type = MT_DEVICE
22136 + iotable_init(&desc, 1);
22137 + dwc_otg_device->base = (void *)desc.virtual;
22140 + if (!dwc_otg_device->base) {
22141 + dev_err(&_dev->dev, "ioremap() failed\n");
22142 + retval = -ENOMEM;
22145 + dev_dbg(&_dev->dev, "base=0x%08x\n", (unsigned)dwc_otg_device->base);
22149 + * Initialize driver data to point to the global DWC_otg
22150 + * Device structure.
22152 +#ifdef LM_INTERFACE
22153 + lm_set_drvdata(_dev, dwc_otg_device);
22154 +#elif defined(PLATFORM_INTERFACE)
22155 + platform_set_drvdata(_dev, dwc_otg_device);
22157 + dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device);
22159 + dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->base);
22160 + DWC_DEBUGPL(DBG_HCDV, "probe of device %p given core_if %p\n",
22161 + dwc_otg_device, dwc_otg_device->core_if);//GRAYG
22163 + if (!dwc_otg_device->core_if) {
22164 + dev_err(&_dev->dev, "CIL initialization failed!\n");
22165 + retval = -ENOMEM;
22169 + dev_dbg(&_dev->dev, "Calling get_gsnpsid\n");
22171 + * Attempt to ensure this device is really a DWC_otg Controller.
22172 + * Read and verify the SNPSID register contents. The value should be
22173 + * 0x45F42XXX, which corresponds to "OT2", as in "OTG version 2.XX".
22176 + if ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) !=
22178 + dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n",
22179 + dwc_otg_get_gsnpsid(dwc_otg_device->core_if));
22180 + dwc_otg_cil_remove(dwc_otg_device->core_if);
22181 + dwc_free(dwc_otg_device);
22182 + retval = -EINVAL;
22187 + * Validate parameter values.
22189 + dev_dbg(&_dev->dev, "Calling set_parameters\n");
22190 + if (set_parameters(dwc_otg_device->core_if)) {
22191 + dwc_otg_cil_remove(dwc_otg_device->core_if);
22192 + retval = -EINVAL;
22197 + * Create Device Attributes in sysfs
22199 + dev_dbg(&_dev->dev, "Calling attr_create\n");
22200 + dwc_otg_attr_create(_dev);
22203 + * Disable the global interrupt until all the interrupt
22204 + * handlers are installed.
22206 + dev_dbg(&_dev->dev, "Calling disable_global_interrupts\n");
22207 + dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
22210 + * Install the interrupt handler for the common interrupts before
22211 + * enabling common interrupts in core_init below.
22213 +#if defined(PLATFORM_INTERFACE)
22214 + devirq = platform_get_irq(_dev, 0);
22216 + devirq = _dev->irq;
22218 + DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n",
22220 + dev_dbg(&_dev->dev, "Calling request_irq(%d)\n", devirq);
22221 + retval = request_irq(devirq, dwc_otg_common_irq,
22223 + "dwc_otg", dwc_otg_device);
22225 + DWC_ERROR("request of irq%d failed\n", devirq);
22229 + dwc_otg_device->common_irq_installed = 1;
22232 +#ifndef IRQF_TRIGGER_LOW
22233 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
22234 + dev_dbg(&_dev->dev, "Calling set_irq_type\n");
22235 + set_irq_type(devirq,
22236 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
22239 + IRQ_TYPE_LEVEL_LOW
22243 +#endif /*IRQF_TRIGGER_LOW*/
22246 + * Initialize the DWC_otg core.
22248 + dev_dbg(&_dev->dev, "Calling dwc_otg_core_init\n");
22249 + dwc_otg_core_init(dwc_otg_device->core_if);
22251 +#ifndef DWC_HOST_ONLY
22253 + * Initialize the PCD
22255 + dev_dbg(&_dev->dev, "Calling pcd_init\n");
22256 + retval = pcd_init(_dev);
22257 + if (retval != 0) {
22258 + DWC_ERROR("pcd_init failed\n");
22259 + dwc_otg_device->pcd = NULL;
22263 +#ifndef DWC_DEVICE_ONLY
22265 + * Initialize the HCD
22267 + dev_dbg(&_dev->dev, "Calling hcd_init\n");
22268 + retval = hcd_init(_dev);
22269 + if (retval != 0) {
22270 + DWC_ERROR("hcd_init failed\n");
22271 + dwc_otg_device->hcd = NULL;
22275 + /* Recover from drvdata having been overwritten by hcd_init() */
22276 +#ifdef LM_INTERFACE
22277 + lm_set_drvdata(_dev, dwc_otg_device);
22278 +#elif defined(PLATFORM_INTERFACE)
22279 + platform_set_drvdata(_dev, dwc_otg_device);
22280 +#elif defined(PCI_INTERFACE)
22281 + pci_set_drvdata(_dev, dwc_otg_device);
22285 + * Enable the global interrupt after all the interrupt
22286 + * handlers are installed.
22288 + dev_dbg(&_dev->dev, "Calling enable_global_interrupts\n");
22289 + dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);
22290 + dev_dbg(&_dev->dev, "Done\n");
22295 + dwc_otg_driver_remove(_dev);
22300 + * This structure defines the methods to be called by a bus driver
22301 + * during the lifecycle of a device on that bus. Both drivers and
22302 + * devices are registered with a bus driver. The bus driver matches
22303 + * devices to drivers based on information in the device and driver
22306 + * The probe function is called when the bus driver matches a device
22307 + * to this driver. The remove function is called when a device is
22308 + * unregistered with the bus driver.
22310 +#ifdef LM_INTERFACE
22311 +static struct lm_driver dwc_otg_driver = {
22313 + .name = (char *)dwc_driver_name,
22315 + .probe = dwc_otg_driver_probe,
22316 + .remove = dwc_otg_driver_remove,
22317 + // 'suspend' and 'resume' absent
22319 +#elif defined(PCI_INTERFACE)
22320 +static const struct pci_device_id pci_ids[] = { {
22321 + PCI_DEVICE(0x16c3, 0xabcd),
22322 + .driver_data = (unsigned long) 0xdeadbeef,
22323 + }, { /* end: all zeroes */ }
22325 +MODULE_DEVICE_TABLE(pci, pci_ids);
22327 +/* pci driver glue; this is a "new style" PCI driver module */
22328 +static struct pci_driver dwc_otg_driver = {
22329 + .name = "dwc_otg",
22330 + .id_table = pci_ids,
22332 + .probe = dwc_otg_driver_probe,
22333 + .remove = dwc_otg_driver_remove,
22336 + .name = (char*)dwc_driver_name,
22339 +#elif defined(PLATFORM_INTERFACE)
22340 +static struct platform_device_id platform_ids[] = {
22342 + .name = "bcm2708_usb",
22343 + .driver_data = (kernel_ulong_t) 0xdeadbeef,
22345 + { /* end: all zeroes */ }
22347 +MODULE_DEVICE_TABLE(platform, platform_ids);
22349 +static struct platform_driver dwc_otg_driver = {
22351 + .name = (char *)dwc_driver_name,
22353 + .id_table = platform_ids,
22355 + .probe = dwc_otg_driver_probe,
22356 + .remove = dwc_otg_driver_remove,
22357 + // no 'shutdown', 'suspend', 'resume', 'suspend_late' or 'resume_early'
22363 + * This function is called when the dwc_otg_driver is installed with the
22364 + * insmod command. It registers the dwc_otg_driver structure with the
22365 + * appropriate bus driver. This will cause the dwc_otg_driver_probe function
22366 + * to be called. In addition, the bus driver will automatically expose
22367 + * attributes defined for the device and driver in the special sysfs file
22372 +static int __init dwc_otg_driver_init(void)
22376 + printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name,
22377 + DWC_DRIVER_VERSION,
22378 +#ifdef LM_INTERFACE
22380 + retval = lm_driver_register(&dwc_otg_driver);
22381 +#elif defined(PCI_INTERFACE)
22383 + retval = pci_register_driver(&dwc_otg_driver);
22384 +#elif defined(PLATFORM_INTERFACE)
22386 + retval = platform_driver_register(&dwc_otg_driver);
22388 + if (retval < 0) {
22389 + printk(KERN_ERR "%s retval=%d\n", __func__, retval);
22392 +#ifdef LM_INTERFACE
22393 + error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_version);
22394 + error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
22395 +#elif defined(PCI_INTERFACE)
22396 + error = driver_create_file(&dwc_otg_driver.driver,
22397 + &driver_attr_version);
22398 + error = driver_create_file(&dwc_otg_driver.driver,
22399 + &driver_attr_debuglevel);
22400 +#elif defined(PLATFORM_INTERFACE)
22401 + error = driver_create_file(&dwc_otg_driver.driver,
22402 + &driver_attr_version);
22403 + error = driver_create_file(&dwc_otg_driver.driver,
22404 + &driver_attr_debuglevel);
22409 +module_init(dwc_otg_driver_init);
22412 + * This function is called when the driver is removed from the kernel
22413 + * with the rmmod command. The driver unregisters itself with its bus
22417 +static void __exit dwc_otg_driver_cleanup(void)
22419 + printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n");
22421 +#ifdef LM_INTERFACE
22422 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
22423 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_version);
22424 + lm_driver_unregister(&dwc_otg_driver);
22425 +#elif defined(PCI_INTERFACE)
22426 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
22427 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
22428 + pci_unregister_driver(&dwc_otg_driver);
22429 +#elif defined(PLATFORM_INTERFACE)
22430 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
22431 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
22432 + platform_driver_unregister(&dwc_otg_driver);
22435 + printk(KERN_INFO "%s module removed\n", dwc_driver_name);
22437 +module_exit(dwc_otg_driver_cleanup);
22439 +MODULE_DESCRIPTION(DWC_DRIVER_DESC);
22440 +MODULE_AUTHOR("Synopsys Inc.");
22441 +MODULE_LICENSE("GPL");
22443 +module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444);
22444 +MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None");
22445 +module_param_named(opt, dwc_otg_module_params.opt, int, 0444);
22446 +MODULE_PARM_DESC(opt, "OPT Mode");
22447 +module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444);
22448 +MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled");
22450 +module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int,
22452 +MODULE_PARM_DESC(dma_desc_enable,
22453 + "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled");
22455 +module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int,
22457 +MODULE_PARM_DESC(dma_burst_size,
22458 + "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256");
22459 +module_param_named(speed, dwc_otg_module_params.speed, int, 0444);
22460 +MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed");
22461 +module_param_named(host_support_fs_ls_low_power,
22462 + dwc_otg_module_params.host_support_fs_ls_low_power, int,
22464 +MODULE_PARM_DESC(host_support_fs_ls_low_power,
22465 + "Support Low Power w/FS or LS 0=Support 1=Don't Support");
22466 +module_param_named(host_ls_low_power_phy_clk,
22467 + dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444);
22468 +MODULE_PARM_DESC(host_ls_low_power_phy_clk,
22469 + "Low Speed Low Power Clock 0=48Mhz 1=6Mhz");
22470 +module_param_named(enable_dynamic_fifo,
22471 + dwc_otg_module_params.enable_dynamic_fifo, int, 0444);
22472 +MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing");
22473 +module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int,
22475 +MODULE_PARM_DESC(data_fifo_size,
22476 + "Total number of words in the data FIFO memory 32-32768");
22477 +module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size,
22479 +MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
22480 +module_param_named(dev_nperio_tx_fifo_size,
22481 + dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444);
22482 +MODULE_PARM_DESC(dev_nperio_tx_fifo_size,
22483 + "Number of words in the non-periodic Tx FIFO 16-32768");
22484 +module_param_named(dev_perio_tx_fifo_size_1,
22485 + dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444);
22486 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_1,
22487 + "Number of words in the periodic Tx FIFO 4-768");
22488 +module_param_named(dev_perio_tx_fifo_size_2,
22489 + dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444);
22490 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_2,
22491 + "Number of words in the periodic Tx FIFO 4-768");
22492 +module_param_named(dev_perio_tx_fifo_size_3,
22493 + dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444);
22494 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_3,
22495 + "Number of words in the periodic Tx FIFO 4-768");
22496 +module_param_named(dev_perio_tx_fifo_size_4,
22497 + dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444);
22498 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_4,
22499 + "Number of words in the periodic Tx FIFO 4-768");
22500 +module_param_named(dev_perio_tx_fifo_size_5,
22501 + dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444);
22502 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_5,
22503 + "Number of words in the periodic Tx FIFO 4-768");
22504 +module_param_named(dev_perio_tx_fifo_size_6,
22505 + dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444);
22506 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_6,
22507 + "Number of words in the periodic Tx FIFO 4-768");
22508 +module_param_named(dev_perio_tx_fifo_size_7,
22509 + dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444);
22510 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_7,
22511 + "Number of words in the periodic Tx FIFO 4-768");
22512 +module_param_named(dev_perio_tx_fifo_size_8,
22513 + dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444);
22514 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_8,
22515 + "Number of words in the periodic Tx FIFO 4-768");
22516 +module_param_named(dev_perio_tx_fifo_size_9,
22517 + dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444);
22518 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_9,
22519 + "Number of words in the periodic Tx FIFO 4-768");
22520 +module_param_named(dev_perio_tx_fifo_size_10,
22521 + dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444);
22522 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_10,
22523 + "Number of words in the periodic Tx FIFO 4-768");
22524 +module_param_named(dev_perio_tx_fifo_size_11,
22525 + dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444);
22526 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_11,
22527 + "Number of words in the periodic Tx FIFO 4-768");
22528 +module_param_named(dev_perio_tx_fifo_size_12,
22529 + dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444);
22530 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_12,
22531 + "Number of words in the periodic Tx FIFO 4-768");
22532 +module_param_named(dev_perio_tx_fifo_size_13,
22533 + dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444);
22534 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_13,
22535 + "Number of words in the periodic Tx FIFO 4-768");
22536 +module_param_named(dev_perio_tx_fifo_size_14,
22537 + dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444);
22538 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_14,
22539 + "Number of words in the periodic Tx FIFO 4-768");
22540 +module_param_named(dev_perio_tx_fifo_size_15,
22541 + dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444);
22542 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_15,
22543 + "Number of words in the periodic Tx FIFO 4-768");
22544 +module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size,
22546 +MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
22547 +module_param_named(host_nperio_tx_fifo_size,
22548 + dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444);
22549 +MODULE_PARM_DESC(host_nperio_tx_fifo_size,
22550 + "Number of words in the non-periodic Tx FIFO 16-32768");
22551 +module_param_named(host_perio_tx_fifo_size,
22552 + dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444);
22553 +MODULE_PARM_DESC(host_perio_tx_fifo_size,
22554 + "Number of words in the host periodic Tx FIFO 16-32768");
22555 +module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size,
22557 +/** @todo Set the max to 512K, modify checks */
22558 +MODULE_PARM_DESC(max_transfer_size,
22559 + "The maximum transfer size supported in bytes 2047-65535");
22560 +module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count,
22562 +MODULE_PARM_DESC(max_packet_count,
22563 + "The maximum number of packets in a transfer 15-511");
22564 +module_param_named(host_channels, dwc_otg_module_params.host_channels, int,
22566 +MODULE_PARM_DESC(host_channels,
22567 + "The number of host channel registers to use 1-16");
22568 +module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int,
22570 +MODULE_PARM_DESC(dev_endpoints,
22571 + "The number of endpoints in addition to EP0 available for device mode 1-15");
22572 +module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444);
22573 +MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI");
22574 +module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int,
22576 +MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits");
22577 +module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444);
22578 +MODULE_PARM_DESC(phy_ulpi_ddr,
22579 + "ULPI at double or single data rate 0=Single 1=Double");
22580 +module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus,
22582 +MODULE_PARM_DESC(phy_ulpi_ext_vbus,
22583 + "ULPI PHY using internal or external vbus 0=Internal");
22584 +module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444);
22585 +MODULE_PARM_DESC(i2c_enable, "FS PHY Interface");
22586 +module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444);
22587 +MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only");
22588 +module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444);
22589 +MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs");
22590 +module_param_named(debug, g_dbg_lvl, int, 0444);
22591 +MODULE_PARM_DESC(debug, "");
22593 +module_param_named(en_multiple_tx_fifo,
22594 + dwc_otg_module_params.en_multiple_tx_fifo, int, 0444);
22595 +MODULE_PARM_DESC(en_multiple_tx_fifo,
22596 + "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled");
22597 +module_param_named(dev_tx_fifo_size_1,
22598 + dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444);
22599 +MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768");
22600 +module_param_named(dev_tx_fifo_size_2,
22601 + dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444);
22602 +MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768");
22603 +module_param_named(dev_tx_fifo_size_3,
22604 + dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444);
22605 +MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768");
22606 +module_param_named(dev_tx_fifo_size_4,
22607 + dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444);
22608 +MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768");
22609 +module_param_named(dev_tx_fifo_size_5,
22610 + dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444);
22611 +MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768");
22612 +module_param_named(dev_tx_fifo_size_6,
22613 + dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444);
22614 +MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768");
22615 +module_param_named(dev_tx_fifo_size_7,
22616 + dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444);
22617 +MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768");
22618 +module_param_named(dev_tx_fifo_size_8,
22619 + dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444);
22620 +MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768");
22621 +module_param_named(dev_tx_fifo_size_9,
22622 + dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444);
22623 +MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768");
22624 +module_param_named(dev_tx_fifo_size_10,
22625 + dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444);
22626 +MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768");
22627 +module_param_named(dev_tx_fifo_size_11,
22628 + dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444);
22629 +MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768");
22630 +module_param_named(dev_tx_fifo_size_12,
22631 + dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444);
22632 +MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768");
22633 +module_param_named(dev_tx_fifo_size_13,
22634 + dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444);
22635 +MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768");
22636 +module_param_named(dev_tx_fifo_size_14,
22637 + dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444);
22638 +MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768");
22639 +module_param_named(dev_tx_fifo_size_15,
22640 + dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444);
22641 +MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768");
22643 +module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444);
22644 +MODULE_PARM_DESC(thr_ctl,
22645 + "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled");
22646 +module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int,
22648 +MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs");
22649 +module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int,
22651 +MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs");
22653 +module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444);
22654 +module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444);
22655 +module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444);
22656 +MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled");
22657 +module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444);
22658 +MODULE_PARM_DESC(ic_usb_cap,
22659 + "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled");
22660 +module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int, 0444);
22661 +MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio");
22663 +/** @page "Module Parameters"
22665 + * The following parameters may be specified when starting the module.
22666 + * These parameters define how the DWC_otg controller should be
22667 + * configured. Parameter values are passed to the CIL initialization
22668 + * function dwc_otg_cil_init
22670 + * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code>
22674 + <tr><td>Parameter Name</td><td>Meaning</td></tr>
22678 + <td>Specifies the OTG capabilities. The driver will automatically detect the
22679 + value for this parameter if none is specified.
22680 + - 0: HNP and SRP capable (default, if available)
22681 + - 1: SRP Only capable
22682 + - 2: No HNP/SRP capable
22686 + <td>dma_enable</td>
22687 + <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs.
22688 + The driver will automatically detect the value for this parameter if none is
22691 + - 1: DMA (default, if available)
22695 + <td>dma_burst_size</td>
22696 + <td>The DMA Burst size (applicable only for External DMA Mode).
22697 + - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32)
22702 + <td>Specifies the maximum speed of operation in host and device mode. The
22703 + actual speed depends on the speed of the attached device and the value of
22705 + - 0: High Speed (default)
22710 + <td>host_support_fs_ls_low_power</td>
22711 + <td>Specifies whether low power mode is supported when attached to a Full
22712 + Speed or Low Speed device in host mode.
22713 + - 0: Don't support low power mode (default)
22714 + - 1: Support low power mode
22718 + <td>host_ls_low_power_phy_clk</td>
22719 + <td>Specifies the PHY clock rate in low power mode when connected to a Low
22720 + Speed device in host mode. This parameter is applicable only if
22721 + HOST_SUPPORT_FS_LS_LOW_POWER is enabled.
22722 + - 0: 48 MHz (default)
22727 + <td>enable_dynamic_fifo</td>
22728 + <td> Specifies whether FIFOs may be resized by the driver software.
22729 + - 0: Use cC FIFO size parameters
22730 + - 1: Allow dynamic FIFO sizing (default)
22734 + <td>data_fifo_size</td>
22735 + <td>Total number of 4-byte words in the data FIFO memory. This memory
22736 + includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs.
22737 + - Values: 32 to 32768 (default 8192)
22739 + Note: The total FIFO memory depth in the FPGA configuration is 8192.
22743 + <td>dev_rx_fifo_size</td>
22744 + <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic
22745 + FIFO sizing is enabled.
22746 + - Values: 16 to 32768 (default 1064)
22750 + <td>dev_nperio_tx_fifo_size</td>
22751 + <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when
22752 + dynamic FIFO sizing is enabled.
22753 + - Values: 16 to 32768 (default 1024)
22757 + <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td>
22758 + <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode
22759 + when dynamic FIFO sizing is enabled.
22760 + - Values: 4 to 768 (default 256)
22764 + <td>host_rx_fifo_size</td>
22765 + <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO
22766 + sizing is enabled.
22767 + - Values: 16 to 32768 (default 1024)
22771 + <td>host_nperio_tx_fifo_size</td>
22772 + <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when
22773 + dynamic FIFO sizing is enabled in the core.
22774 + - Values: 16 to 32768 (default 1024)
22778 + <td>host_perio_tx_fifo_size</td>
22779 + <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO
22780 + sizing is enabled.
22781 + - Values: 16 to 32768 (default 1024)
22785 + <td>max_transfer_size</td>
22786 + <td>The maximum transfer size supported in bytes.
22787 + - Values: 2047 to 65,535 (default 65,535)
22791 + <td>max_packet_count</td>
22792 + <td>The maximum number of packets in a transfer.
22793 + - Values: 15 to 511 (default 511)
22797 + <td>host_channels</td>
22798 + <td>The number of host channel registers to use.
22799 + - Values: 1 to 16 (default 12)
22801 + Note: The FPGA configuration supports a maximum of 12 host channels.
22805 + <td>dev_endpoints</td>
22806 + <td>The number of endpoints in addition to EP0 available for device mode
22808 + - Values: 1 to 15 (default 6 IN and OUT)
22810 + Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in
22815 + <td>phy_type</td>
22816 + <td>Specifies the type of PHY interface to use. By default, the driver will
22817 + automatically detect the phy_type.
22819 + - 1: UTMI+ (default, if available)
22824 + <td>phy_utmi_width</td>
22825 + <td>Specifies the UTMI+ Data Width. This parameter is applicable for a
22826 + phy_type of UTMI+. Also, this parameter is applicable only if the
22827 + OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the
22828 + core has been configured to work at either data path width.
22829 + - Values: 8 or 16 bits (default 16)
22833 + <td>phy_ulpi_ddr</td>
22834 + <td>Specifies whether the ULPI operates at double or single data rate. This
22835 + parameter is only applicable if phy_type is ULPI.
22836 + - 0: single data rate ULPI interface with 8 bit wide data bus (default)
22837 + - 1: double data rate ULPI interface with 4 bit wide data bus
22841 + <td>i2c_enable</td>
22842 + <td>Specifies whether to use the I2C interface for full speed PHY. This
22843 + parameter is only applicable if PHY_TYPE is FS.
22844 + - 0: Disabled (default)
22849 + <td>otg_en_multiple_tx_fifo</td>
22850 + <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs.
22851 + The driver will automatically detect the value for this parameter if none is
22854 + - 1: Enabled (default, if available)
22858 + <td>dev_tx_fifo_size_n (n = 1 to 15)</td>
22859 + <td>Number of 4-byte words in each of the Tx FIFOs in device mode
22860 + when dynamic FIFO sizing is enabled.
22861 + - Values: 4 to 768 (default 256)
22865 + <td>tx_thr_length</td>
22866 + <td>Transmit Threshold length in 32 bit double words
22867 + - Values: 8 to 128 (default 64)
22871 + <td>rx_thr_length</td>
22872 + <td>Receive Threshold length in 32 bit double words
22873 + - Values: 8 to 128 (default 64)
22878 + <td>Specifies whether to enable Thresholding for Device mode. Bits 0, 1, 2 of this
22879 + parmater specifies if thresholding is enabled for non-Iso Tx, Iso Tx and Rx
22880 + transfers accordingly.
22881 + The driver will automatically detect the value for this parameter if none is
22883 + - Values: 0 to 7 (default 0)
22884 + Bit values indicate:
22885 + - 0: Thresholding disabled
22886 + - 1: Thresholding enabled
22890 + <td>dma_desc_enable</td>
22891 + <td>Specifies whether to enable Descriptor DMA mode.
22892 + The driver will automatically detect the value for this parameter if none is
22894 + - 0: Descriptor DMA disabled
22895 + - 1: Descriptor DMA (default, if available)
22899 + <td>mpi_enable</td>
22900 + <td>Specifies whether to enable MPI enhancement mode.
22901 + The driver will automatically detect the value for this parameter if none is
22903 + - 0: MPI disabled (default)
22908 + <td>pti_enable</td>
22909 + <td>Specifies whether to enable PTI enhancement support.
22910 + The driver will automatically detect the value for this parameter if none is
22912 + - 0: PTI disabled (default)
22917 + <td>lpm_enable</td>
22918 + <td>Specifies whether to enable LPM support.
22919 + The driver will automatically detect the value for this parameter if none is
22921 + - 0: LPM disabled
22922 + - 1: LPM enable (default, if available)
22926 + <td>ahb_thr_ratio</td>
22927 + <td>Specifies AHB Threshold ratio.
22928 + - Values: 0 to 3 (default 0)
22933 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.h
22935 +/* ==========================================================================
22936 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $
22937 + * $Revision: #16 $
22938 + * $Date: 2009/04/03 $
22939 + * $Change: 1225160 $
22941 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
22942 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
22943 + * otherwise expressly agreed to in writing between Synopsys and you.
22945 + * The Software IS NOT an item of Licensed Software or Licensed Product under
22946 + * any End User Software License Agreement or Agreement for Licensed Product
22947 + * with Synopsys or any supplement thereto. You are permitted to use and
22948 + * redistribute this Software in source and binary forms, with or without
22949 + * modification, provided that redistributions of source code must retain this
22950 + * notice. You may not view, use, disclose, copy or distribute this file or
22951 + * any information contained herein except pursuant to this license grant from
22952 + * Synopsys. If you do not agree with this notice, including the disclaimer
22953 + * below, then you are not authorized to use the Software.
22955 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
22956 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22957 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22958 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
22959 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22960 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22961 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22962 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22963 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22964 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
22966 + * ========================================================================== */
22968 +#ifndef __DWC_OTG_DRIVER_H__
22969 +#define __DWC_OTG_DRIVER_H__
22972 + * This file contains the interface to the Linux driver.
22974 +#include "dwc_otg_core_if.h"
22976 +/* Type declarations */
22977 +struct dwc_otg_pcd;
22978 +struct dwc_otg_hcd;
22980 +#ifdef PCI_INTERFACE
22981 +#include <linux/pci.h>
22987 + * This structure is a wrapper that encapsulates the driver components used to
22988 + * manage a single DWC_otg controller.
22990 +typedef struct dwc_otg_device {
22991 + /** Base address returned from ioremap() */
22994 +#ifdef LM_INTERFACE
22995 + struct lm_device *lmdev;
22996 +#elif defined(PCI_INTERFACE)
22999 +#elif defined(PLATFORM_INTERFACE)
23000 + struct platform_device *platformdev;
23003 + /** Pointer to the core interface structure. */
23004 + dwc_otg_core_if_t *core_if;
23006 + /** Register offset for Diagnostic API. */
23007 + uint32_t reg_offset;
23009 + /** Pointer to the PCD structure. */
23010 + struct dwc_otg_pcd *pcd;
23012 + /** Pointer to the HCD structure. */
23013 + struct dwc_otg_hcd *hcd;
23015 + /** Flag to indicate whether the common IRQ handler is installed. */
23016 + uint8_t common_irq_installed;
23018 +} dwc_otg_device_t;
23020 +/*We must clear S3C24XX_EINTPEND external interrupt register
23021 + * because after clearing in this register trigerred IRQ from
23022 + * H/W core in kernel interrupt can be occured again before OTG
23023 + * handlers clear all IRQ sources of Core registers because of
23024 + * timing latencies and Low Level IRQ Type.
23026 +#ifdef CONFIG_MACH_IPMATE
23027 +#define S3C2410X_CLEAR_EINTPEND() \
23029 + __raw_writel(1UL << 11,S3C24XX_EINTPEND); \
23032 +#define S3C2410X_CLEAR_EINTPEND() do { } while (0)
23037 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
23040 +/* ==========================================================================
23041 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
23042 + * $Revision: #87 $
23043 + * $Date: 2009/04/23 $
23044 + * $Change: 1239143 $
23046 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
23047 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
23048 + * otherwise expressly agreed to in writing between Synopsys and you.
23050 + * The Software IS NOT an item of Licensed Software or Licensed Product under
23051 + * any End User Software License Agreement or Agreement for Licensed Product
23052 + * with Synopsys or any supplement thereto. You are permitted to use and
23053 + * redistribute this Software in source and binary forms, with or without
23054 + * modification, provided that redistributions of source code must retain this
23055 + * notice. You may not view, use, disclose, copy or distribute this file or
23056 + * any information contained herein except pursuant to this license grant from
23057 + * Synopsys. If you do not agree with this notice, including the disclaimer
23058 + * below, then you are not authorized to use the Software.
23060 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
23061 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23062 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23063 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
23064 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23065 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23066 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23067 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23068 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23069 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
23071 + * ========================================================================== */
23072 +#ifndef DWC_DEVICE_ONLY
23075 + * This file implements HCD Core. All code in this file is portable and don't
23076 + * use any OS specific functions.
23077 + * Interface provided by HCD Core is defined in <code><hcd_if.h></code>
23081 +#include "dwc_otg_hcd.h"
23082 +#include "dwc_otg_regs.h"
23084 +#ifdef HW2937_WORKAROUND
23085 +//#include <linux/kernel.h>
23086 +#include <linux/spinlock.h>
23089 +dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
23091 + return dwc_alloc(sizeof(dwc_otg_hcd_t));
23095 + * Connection timeout function. An OTG host is required to display a
23096 + * message if the device does not connect within 10 seconds.
23098 +void dwc_otg_hcd_connect_timeout(void *ptr)
23100 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
23101 + DWC_PRINTF("Connect Timeout\n");
23102 + __DWC_ERROR("Device Not Connected/Responding\n");
23106 +static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
23108 + if (qh->channel != NULL) {
23109 + dwc_hc_t *hc = qh->channel;
23110 + dwc_list_link_t *item;
23111 + dwc_otg_qh_t *qh_item;
23112 + int num_channels = hcd->core_if->core_params->host_channels;
23115 + dwc_otg_hc_regs_t *hc_regs;
23116 + hcchar_data_t hcchar;
23117 + hcsplt_data_t hcsplt;
23118 + hctsiz_data_t hctsiz;
23121 + hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
23122 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
23123 + hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
23124 + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
23125 + hcdma = dwc_read_reg32(&hc_regs->hcdma);
23127 + DWC_PRINTF(" Assigned to channel %p:\n", hc);
23128 + DWC_PRINTF(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
23130 + DWC_PRINTF(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
23132 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
23133 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
23134 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
23135 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
23136 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
23137 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
23138 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
23139 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
23140 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
23141 + DWC_PRINTF(" qh: %p\n", hc->qh);
23142 + DWC_PRINTF(" NP inactive sched:\n");
23143 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
23145 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
23146 + DWC_PRINTF(" %p\n", qh_item);
23148 + DWC_PRINTF(" NP active sched:\n");
23149 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
23151 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
23152 + DWC_PRINTF(" %p\n", qh_item);
23154 + DWC_PRINTF(" Channels: \n");
23155 + for (i = 0; i < num_channels; i++) {
23156 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
23157 + DWC_PRINTF(" %2d: %p\n", i, hc);
23161 +#endif /* DEBUG */
23164 + * Work queue function for starting the HCD when A-Cable is connected.
23165 + * The hcd_start() must be called in a process context.
23167 +static void hcd_start_func(void *_vp)
23169 + dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
23171 + DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
23173 + hcd->fops->start(hcd);
23177 +static void del_xfer_timers(dwc_otg_hcd_t * hcd)
23181 + int num_channels = hcd->core_if->core_params->host_channels;
23182 + for (i = 0; i < num_channels; i++) {
23183 + DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
23188 +static void del_timers(dwc_otg_hcd_t * hcd)
23190 + del_xfer_timers(hcd);
23191 + DWC_TIMER_CANCEL(hcd->conn_timer);
23195 + * Processes all the URBs in a single list of QHs. Completes them with
23196 + * -ETIMEDOUT and frees the QTD.
23198 +static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
23200 + dwc_list_link_t *qh_item;
23201 + dwc_otg_qh_t *qh;
23202 + dwc_otg_qtd_t *qtd, *qtd_tmp;
23204 + DWC_LIST_FOREACH(qh_item, qh_list) {
23205 + qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
23206 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
23207 + &qh->qtd_list, qtd_list_entry) {
23208 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
23209 + if (qtd->urb != NULL) {
23210 + hcd->fops->complete(hcd, qtd->urb->priv,
23213 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
23221 + * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
23222 + * and periodic schedules. The QTD associated with each URB is removed from
23223 + * the schedule and freed. This function may be called when a disconnect is
23224 + * detected or when the HCD is being stopped.
23226 +static void kill_all_urbs(dwc_otg_hcd_t * hcd)
23228 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
23229 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
23230 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
23231 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
23232 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
23233 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
23237 + * Start the connection timer. An OTG host is required to display a
23238 + * message if the device does not connect within 10 seconds. The
23239 + * timer is deleted if a port connect interrupt occurs before the
23242 +static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
23244 + DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
23248 + * HCD Callback function for disconnect of the HCD.
23250 + * @param p void pointer to the <code>struct usb_hcd</code>
23252 +static int32_t dwc_otg_hcd_session_start_cb(void *p)
23254 + dwc_otg_hcd_t *dwc_otg_hcd;
23255 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
23257 + dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
23262 + * HCD Callback function for starting the HCD when A-Cable is
23265 + * @param p void pointer to the <code>struct usb_hcd</code>
23267 +static int32_t dwc_otg_hcd_start_cb(void *p)
23269 + dwc_otg_hcd_t *dwc_otg_hcd = p;
23270 + dwc_otg_core_if_t *core_if;
23271 + hprt0_data_t hprt0;
23273 + core_if = dwc_otg_hcd->core_if;
23275 + if (core_if->op_state == B_HOST) {
23277 + * Reset the port. During a HNP mode switch the reset
23278 + * needs to occur within 1ms and have a duration of at
23281 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
23282 + hprt0.b.prtrst = 1;
23283 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
23285 + DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
23286 + hcd_start_func, dwc_otg_hcd, 50,
23293 + * HCD Callback function for disconnect of the HCD.
23295 + * @param p void pointer to the <code>struct usb_hcd</code>
23297 +static int32_t dwc_otg_hcd_disconnect_cb(void *p)
23299 + gintsts_data_t intr;
23300 + dwc_otg_hcd_t *dwc_otg_hcd = p;
23303 + * Set status flags for the hub driver.
23305 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
23306 + dwc_otg_hcd->flags.b.port_connect_status = 0;
23309 + * Shutdown any transfers in process by clearing the Tx FIFO Empty
23310 + * interrupt mask and status bits and disabling subsequent host
23311 + * channel interrupts.
23314 + intr.b.nptxfempty = 1;
23315 + intr.b.ptxfempty = 1;
23316 + intr.b.hcintr = 1;
23317 + dwc_modify_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
23319 + dwc_modify_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
23322 + del_timers(dwc_otg_hcd);
23325 + * Turn off the vbus power only if the core has transitioned to device
23326 + * mode. If still in host mode, need to keep power on to detect a
23329 + if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
23330 + if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
23331 + hprt0_data_t hprt0 = {.d32 = 0 };
23332 + DWC_PRINTF("Disconnect: PortPower off\n");
23333 + hprt0.b.prtpwr = 0;
23334 + dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0,
23338 + dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
23341 + /* Respond with an error status to all URBs in the schedule. */
23342 + kill_all_urbs(dwc_otg_hcd);
23344 + if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
23345 + /* Clean up any host channels that were in use. */
23346 + int num_channels;
23348 + dwc_hc_t *channel;
23349 + dwc_otg_hc_regs_t *hc_regs;
23350 + hcchar_data_t hcchar;
23352 + num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
23354 + if (!dwc_otg_hcd->core_if->dma_enable) {
23355 + /* Flush out any channel requests in slave mode. */
23356 + for (i = 0; i < num_channels; i++) {
23357 + channel = dwc_otg_hcd->hc_ptr_array[i];
23358 + if (DWC_CIRCLEQ_EMPTY_ENTRY
23359 + (channel, hc_list_entry)) {
23361 + dwc_otg_hcd->core_if->host_if->
23364 + dwc_read_reg32(&hc_regs->hcchar);
23365 + if (hcchar.b.chen) {
23366 + hcchar.b.chen = 0;
23367 + hcchar.b.chdis = 1;
23368 + hcchar.b.epdir = 0;
23369 + dwc_write_reg32(&hc_regs->
23377 + for (i = 0; i < num_channels; i++) {
23378 + channel = dwc_otg_hcd->hc_ptr_array[i];
23379 + if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
23381 + dwc_otg_hcd->core_if->host_if->hc_regs[i];
23382 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
23383 + if (hcchar.b.chen) {
23384 + /* Halt the channel. */
23385 + hcchar.b.chdis = 1;
23386 + dwc_write_reg32(&hc_regs->hcchar,
23390 + dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
23392 + DWC_CIRCLEQ_INSERT_TAIL(&dwc_otg_hcd->
23393 + free_hc_list, channel,
23396 + * Added for Descriptor DMA to prevent channel double cleanup
23397 + * in release_channel_ddma(). Which called from ep_disable
23398 + * when device disconnect.
23400 + channel->qh = NULL;
23405 + if (dwc_otg_hcd->fops->disconnect) {
23406 + dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
23413 + * HCD Callback function for stopping the HCD.
23415 + * @param p void pointer to the <code>struct usb_hcd</code>
23417 +static int32_t dwc_otg_hcd_stop_cb(void *p)
23419 + dwc_otg_hcd_t *dwc_otg_hcd = p;
23421 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
23422 + dwc_otg_hcd_stop(dwc_otg_hcd);
23426 +#ifdef CONFIG_USB_DWC_OTG_LPM
23428 + * HCD Callback function for sleep of HCD.
23430 + * @param p void pointer to the <code>struct usb_hcd</code>
23432 +static int dwc_otg_hcd_sleep_cb(void *p)
23434 + dwc_otg_hcd_t *hcd = p;
23436 + dwc_otg_hcd_free_hc_from_lpm(hcd);
23443 + * HCD Callback function for Remote Wakeup.
23445 + * @param p void pointer to the <code>struct usb_hcd</code>
23447 +static int dwc_otg_hcd_rem_wakeup_cb(void *p)
23449 + dwc_otg_hcd_t *hcd = p;
23451 + if (hcd->core_if->lx_state == DWC_OTG_L2) {
23452 + hcd->flags.b.port_suspend_change = 1;
23454 +#ifdef CONFIG_USB_DWC_OTG_LPM
23456 + hcd->flags.b.port_l1_change = 1;
23463 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
23466 +void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
23468 + hprt0_data_t hprt0 = {.d32 = 0 };
23470 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
23473 + * The root hub should be disconnected before this function is called.
23474 + * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
23475 + * and the QH lists (via ..._hcd_endpoint_disable).
23478 + /* Turn off all host-specific interrupts. */
23479 + dwc_otg_disable_host_interrupts(hcd->core_if);
23481 + /* Turn off the vbus power */
23482 + DWC_PRINTF("PortPower off\n");
23483 + hprt0.b.prtpwr = 0;
23484 + dwc_write_reg32(hcd->core_if->host_if->hprt0, hprt0.d32);
23488 +int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
23489 + dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle)
23493 + dwc_otg_qtd_t *qtd;
23495 + if (NULL == hcd->core_if) { //GRAYG
23496 + DWC_ERROR("**** DWC OTG HCD URB Enqueue - HCD has NULL core_if\n");
23497 + /* No longer connected. */
23498 + return -DWC_E_INVALID;
23501 + if (!hcd->flags.b.port_connect_status) {
23502 + /* No longer connected. */
23503 + return -DWC_E_NO_DEVICE;
23506 + qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb);
23507 + if (qtd == NULL) {
23508 + DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
23509 + return -DWC_E_NO_MEMORY;
23511 + if (qtd->urb == NULL) { //GRAYG
23512 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD with no URBs\n");
23513 + return -DWC_E_NO_MEMORY;
23515 + if (qtd->urb->priv == NULL) { //GRAYG
23516 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD URB with no URB handle\n");
23517 + return -DWC_E_NO_MEMORY;
23521 + dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle);
23522 + // creates a new queue in ep_handle if it doesn't exist already
23523 + if (retval < 0) {
23524 + DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
23525 + "Error status %d\n", retval);
23526 + dwc_otg_hcd_qtd_free(qtd);
23528 + qtd->qh = *ep_handle;
23531 + if (hcd->core_if->dma_desc_enable && retval == 0) {
23532 + dwc_otg_transaction_type_e tr_type;
23533 + if ((qtd->qh->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
23534 + /* Do not schedule SG transcations until qtd has URB_GIVEBACK_ASAP set */
23537 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
23538 + tr_type = dwc_otg_hcd_select_transactions(hcd);
23539 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
23540 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
23542 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
23548 +int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
23549 + dwc_otg_hcd_urb_t * dwc_otg_urb)
23553 + dwc_otg_qh_t *qh;
23554 + dwc_otg_qtd_t *urb_qtd;
23556 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
23558 + if (hcd == NULL) { //GRAYG
23559 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL HCD\n");
23560 + return -DWC_E_INVALID;
23562 + if (dwc_otg_urb == NULL) { //GRAYG
23563 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL URB\n");
23564 + return -DWC_E_INVALID;
23566 + if (dwc_otg_urb->qtd == NULL) { //GRAYG
23567 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with NULL QTD\n");
23568 + return -DWC_E_INVALID;
23570 + urb_qtd = dwc_otg_urb->qtd;
23571 + if (urb_qtd->qh == NULL) { //GRAYG
23572 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
23573 + return -DWC_E_INVALID;
23575 + qh = urb_qtd->qh;
23577 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
23578 + if (urb_qtd->in_process) {
23579 + dump_channel_info(hcd, qh);
23583 + if (hcd->core_if == NULL) { //GRAYG
23584 + DWC_ERROR("**** DWC OTG HCD URB Dequeue HCD has NULL core_if\n");
23585 + return -DWC_E_INVALID;
23587 + if (urb_qtd->in_process && qh->channel) {
23588 + /* The QTD is in process (it has been assigned to a channel). */
23589 + if (hcd->flags.b.port_connect_status) {
23591 + * If still connected (i.e. in host mode), halt the
23592 + * channel so it can be used for other transfers. If
23593 + * no longer connected, the host registers can't be
23594 + * written to halt the channel since the core is in
23597 + dwc_otg_hc_halt(hcd->core_if, qh->channel,
23598 + DWC_OTG_HC_XFER_URB_DEQUEUE);
23603 + * Free the QTD and clean up the associated QH. Leave the QH in the
23604 + * schedule if it has any remaining QTDs.
23607 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue - "
23608 + "delete %sQueue handler\n",
23609 + hcd->core_if->dma_desc_enable?"DMA ":""); //GRAYG
23610 + if (!hcd->core_if->dma_desc_enable) {
23611 + uint8_t b = urb_qtd->in_process;
23612 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
23614 + dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
23615 + qh->channel = NULL;
23616 + } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
23617 + dwc_otg_hcd_qh_remove(hcd, qh);
23621 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
23624 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
23629 +int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
23632 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
23637 + retval = -DWC_E_INVALID;
23645 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
23647 + while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
23648 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
23651 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
23654 + dwc_otg_hcd_qh_remove(hcd, qh);
23656 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
23658 + * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
23659 + * and qh_free to prevent stack dump on dwc_dma_free() with
23660 + * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
23661 + * and dwc_otg_hcd_frame_list_alloc().
23663 + dwc_otg_hcd_qh_free(hcd, qh);
23670 + * HCD Callback structure for handling mode switching.
23672 +static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
23673 + .start = dwc_otg_hcd_start_cb,
23674 + .stop = dwc_otg_hcd_stop_cb,
23675 + .disconnect = dwc_otg_hcd_disconnect_cb,
23676 + .session_start = dwc_otg_hcd_session_start_cb,
23677 + .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
23678 +#ifdef CONFIG_USB_DWC_OTG_LPM
23679 + .sleep = dwc_otg_hcd_sleep_cb,
23685 + * Reset tasklet function
23687 +static void reset_tasklet_func(void *data)
23689 + dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
23690 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
23691 + hprt0_data_t hprt0;
23693 + DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
23695 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
23696 + hprt0.b.prtrst = 1;
23697 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
23700 + hprt0.b.prtrst = 0;
23701 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
23702 + dwc_otg_hcd->flags.b.port_reset_change = 1;
23705 +static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
23707 + dwc_list_link_t *item;
23708 + dwc_otg_qh_t *qh;
23710 + if (!qh_list->next) {
23711 + /* The list hasn't been initialized yet. */
23715 + /* Ensure there are no QTDs or URBs left. */
23716 + kill_urbs_in_qh_list(hcd, qh_list);
23718 + DWC_LIST_FOREACH(item, qh_list) {
23719 + qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
23720 + dwc_otg_hcd_qh_remove_and_free(hcd, qh);
23725 + * Frees secondary storage associated with the dwc_otg_hcd structure contained
23726 + * in the struct usb_hcd field.
23728 +static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
23732 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
23734 + del_timers(dwc_otg_hcd);
23736 + /* Free memory for QH/QTD lists */
23737 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
23738 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
23739 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
23740 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
23741 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
23742 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
23744 + /* Free memory for the host channels. */
23745 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
23746 + dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
23749 + if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
23750 + DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
23753 + if (hc != NULL) {
23754 + DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
23760 + if (dwc_otg_hcd->core_if->dma_enable) {
23761 + if (dwc_otg_hcd->status_buf_dma) {
23762 + dwc_dma_free(DWC_OTG_HCD_STATUS_BUF_SIZE,
23763 + dwc_otg_hcd->status_buf,
23764 + dwc_otg_hcd->status_buf_dma);
23766 + } else if (dwc_otg_hcd->status_buf != NULL) {
23767 + dwc_free(dwc_otg_hcd->status_buf);
23769 + DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
23770 + DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
23771 + DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
23772 + dwc_free(dwc_otg_hcd);
23775 +int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
23778 + int num_channels;
23780 + dwc_hc_t *channel;
23782 + hcd->lock = DWC_SPINLOCK_ALLOC();
23784 + DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n",
23785 + hcd, core_if);//GRAYG
23787 + hcd->core_if = core_if;
23788 + /* Register the HCD CIL Callbacks */
23789 + dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
23790 + &hcd_cil_callbacks, hcd);
23792 + /* Initialize the non-periodic schedule. */
23793 + DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
23794 + DWC_LIST_INIT(&hcd->non_periodic_sched_active);
23796 + /* Initialize the periodic schedule. */
23797 + DWC_LIST_INIT(&hcd->periodic_sched_inactive);
23798 + DWC_LIST_INIT(&hcd->periodic_sched_ready);
23799 + DWC_LIST_INIT(&hcd->periodic_sched_assigned);
23800 + DWC_LIST_INIT(&hcd->periodic_sched_queued);
23803 + * Create a host channel descriptor for each host channel implemented
23804 + * in the controller. Initialize the channel descriptor array.
23806 + DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
23807 + num_channels = hcd->core_if->core_params->host_channels;
23808 + DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
23809 + for (i = 0; i < num_channels; i++) {
23810 + channel = dwc_alloc(sizeof(dwc_hc_t));
23811 + if (channel == NULL) {
23812 + retval = -DWC_E_NO_MEMORY;
23813 + DWC_ERROR("%s: host channel allocation failed\n",
23815 + dwc_otg_hcd_free(hcd);
23818 + channel->hc_num = i;
23819 + hcd->hc_ptr_array[i] = channel;
23821 + hcd->core_if->hc_xfer_timer[i] =
23822 + DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
23823 + &hcd->core_if->hc_xfer_info[i]);
23825 + DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
23829 + /* Initialize the Connection timeout timer. */
23830 + hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
23831 + dwc_otg_hcd_connect_timeout, 0);
23833 + /* Initialize reset tasklet. */
23834 + hcd->reset_tasklet = DWC_TASK_ALLOC(reset_tasklet_func, hcd);
23837 + * Allocate space for storing data on status transactions. Normally no
23838 + * data is sent, but this space acts as a bit bucket. This must be
23839 + * done after usb_add_hcd since that function allocates the DMA buffer
23842 + if (hcd->core_if->dma_enable) {
23843 + hcd->status_buf =
23844 + dwc_dma_alloc(DWC_OTG_HCD_STATUS_BUF_SIZE,
23845 + &hcd->status_buf_dma);
23847 + hcd->status_buf = dwc_alloc(DWC_OTG_HCD_STATUS_BUF_SIZE);
23849 + if (!hcd->status_buf) {
23850 + retval = -DWC_E_NO_MEMORY;
23851 + DWC_ERROR("%s: status_buf allocation failed\n", __func__);
23852 + dwc_otg_hcd_free(hcd);
23856 + hcd->otg_port = 1;
23857 + hcd->frame_list = NULL;
23858 + hcd->frame_list_dma = 0;
23860 +#ifdef HW2937_WORKAROUND
23861 + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_IDLE;
23862 + hcd->hw2937_assigned_channels = 0;
23869 +void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
23871 + /* Turn off all host-specific interrupts. */
23872 + dwc_otg_disable_host_interrupts(hcd->core_if);
23874 + dwc_otg_hcd_free(hcd);
23878 + * Initializes dynamic portions of the DWC_otg HCD state.
23880 +static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
23882 + int num_channels;
23884 + dwc_hc_t *channel;
23885 + dwc_hc_t *channel_tmp;
23887 + hcd->flags.d32 = 0;
23889 + hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
23890 + hcd->non_periodic_channels = 0;
23891 + hcd->periodic_channels = 0;
23894 + * Put all channels in the free channel list and clean up channel
23897 + DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
23898 + &hcd->free_hc_list, hc_list_entry) {
23899 + DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
23902 + num_channels = hcd->core_if->core_params->host_channels;
23903 + for (i = 0; i < num_channels; i++) {
23904 + channel = hcd->hc_ptr_array[i];
23905 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
23907 + dwc_otg_hc_cleanup(hcd->core_if, channel);
23910 + /* Initialize the DWC core for host mode operation. */
23911 + dwc_otg_core_host_init(hcd->core_if);
23915 + * Assigns transactions from a QTD to a free host channel and initializes the
23916 + * host channel to perform the transactions. The host channel is removed from
23919 + * @param hcd The HCD state structure.
23920 + * @param qh Transactions from the first QTD for this QH are selected and
23921 + * assigned to a free host channel.
23923 +#ifdef HW2937_WORKAROUND
23924 +static int assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
23926 +static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
23930 + dwc_otg_qtd_t *qtd;
23931 + dwc_otg_hcd_urb_t *urb;
23932 + void* ptr = NULL;
23933 +#ifdef HW2937_WORKAROUND
23937 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
23941 + DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p) - urb %x, actual_length %d\n", __func__, hcd, qh, (unsigned int)urb, urb->actual_length);
23943 +#ifdef HW2937_WORKAROUND
23944 + ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
23945 + if (ep_is_in && ((hcd->hw2937_xfer_mode == HW2937_XFER_MODE_OUT) ||
23946 + (hcd->hw2937_xfer_mode == HW2937_XFER_MODE_PAUSEIN)))
23950 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
23952 + /* Remove the host channel from the free list. */
23953 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
23954 + qh->channel = hc;
23956 + qtd->in_process = 1;
23959 + * Use usb_pipedevice to determine device address. This address is
23960 + * 0 before the SET_ADDRESS command and the correct address afterward.
23962 + hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
23963 + hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
23964 + hc->speed = qh->dev_speed;
23965 + hc->max_packet = dwc_max_packet(qh->maxp);
23967 + hc->xfer_started = 0;
23968 + hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
23969 + hc->error_state = (qtd->error_count > 0);
23970 + hc->halt_on_queue = 0;
23971 + hc->halt_pending = 0;
23972 + hc->requests = 0;
23975 + * The following values may be modified in the transfer type section
23976 + * below. The xfer_len value may be reduced when the transfer is
23977 + * started to accommodate the max widths of the XferSize and PktCnt
23978 + * fields in the HCTSIZn register.
23980 + hc->do_ping = qh->ping_state;
23981 +#ifdef HW2937_WORKAROUND
23982 + hc->ep_is_in = ep_is_in;
23984 + hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
23986 + hc->data_pid_start = qh->data_toggle;
23987 + hc->multi_count = 1;
23989 + if (hcd->core_if->dma_enable) {
23990 + hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
23992 + /* For non-dword aligned case */
23993 + if (((uint32_t)hc->xfer_buff & 0x3) && !hcd->core_if->dma_desc_enable) {
23994 + ptr = (uint8_t *) urb->buf + urb->actual_length;
23997 + hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
23999 + hc->xfer_len = urb->length - urb->actual_length;
24000 + hc->xfer_count = 0;
24003 + * Set the split attributes
24005 + hc->do_split = 0;
24006 + if (qh->do_split) {
24007 + uint32_t hub_addr, port_addr;
24008 + hc->do_split = 1;
24009 + hc->xact_pos = qtd->isoc_split_pos;
24010 + hc->complete_split = qtd->complete_split;
24011 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
24012 + hc->hub_addr = (uint8_t) hub_addr;
24013 + hc->port_addr = (uint8_t) port_addr;
24016 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
24018 + hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
24019 + switch (qtd->control_phase) {
24020 + case DWC_OTG_CONTROL_SETUP:
24021 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n");
24023 + hc->ep_is_in = 0;
24024 + hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
24025 + if (hcd->core_if->dma_enable) {
24026 + hc->xfer_buff = (uint8_t *) urb->setup_dma;
24028 + hc->xfer_buff = (uint8_t *) urb->setup_packet;
24030 + hc->xfer_len = 8;
24033 + case DWC_OTG_CONTROL_DATA:
24034 + DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
24035 + hc->data_pid_start = qtd->data_toggle;
24037 + case DWC_OTG_CONTROL_STATUS:
24039 + * Direction is opposite of data direction or IN if no
24042 + DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n");
24043 + if (urb->length == 0) {
24044 + hc->ep_is_in = 1;
24047 + dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
24049 + if (hc->ep_is_in) {
24053 + hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
24055 + hc->xfer_len = 0;
24056 + if (hcd->core_if->dma_enable) {
24057 + hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
24059 + hc->xfer_buff = (uint8_t *) hcd->status_buf;
24066 + hc->ep_type = DWC_OTG_EP_TYPE_BULK;
24068 + case UE_INTERRUPT:
24069 + hc->ep_type = DWC_OTG_EP_TYPE_INTR;
24071 + case UE_ISOCHRONOUS:
24073 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
24075 + hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
24077 + if (hcd->core_if->dma_desc_enable)
24080 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
24082 + frame_desc->status = 0;
24084 + if (hcd->core_if->dma_enable) {
24085 + hc->xfer_buff = (uint8_t *) urb->dma;
24087 + hc->xfer_buff = (uint8_t *) urb->buf;
24090 + frame_desc->offset + qtd->isoc_split_offset;
24092 + frame_desc->length - qtd->isoc_split_offset;
24094 + /* For non-dword aligned buffers */
24095 + if (((uint32_t)hc->xfer_buff & 0x3) && hcd->core_if->dma_enable) {
24096 + ptr = (uint8_t *) urb->buf + frame_desc->offset + qtd->isoc_split_offset;
24101 + if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
24102 + if (hc->xfer_len <= 188) {
24103 + hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
24106 + DWC_HCSPLIT_XACTPOS_BEGIN;
24112 + /* non DWORD-aligned buffer case */
24114 + uint32_t buf_size;
24115 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
24116 + buf_size = hcd->core_if->core_params->max_transfer_size;
24120 + if (!qh->dw_align_buf) {
24121 + qh->dw_align_buf =
24122 + dwc_dma_alloc_atomic(buf_size,
24123 + &qh->dw_align_buf_dma);
24124 + if (!qh->dw_align_buf) {
24125 + DWC_ERROR("%s: Failed to allocate memory to handle "
24126 + "non-dword aligned buffer case\n", __func__);
24127 +#ifdef HW2937_WORKAROUND
24134 + if (!hc->ep_is_in) {
24135 + dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
24137 + hc->align_buff = qh->dw_align_buf_dma;
24140 + hc->align_buff = 0;
24143 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
24144 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
24146 + * This value may be modified when the transfer is started to
24147 + * reflect the actual transfer length.
24149 + hc->multi_count = dwc_hb_mult(qh->maxp);
24152 + if (hcd->core_if->dma_desc_enable)
24153 + hc->desc_list_addr = qh->desc_list_dma;
24155 + dwc_otg_hc_init(hcd->core_if, hc);
24157 +#ifdef HW2937_WORKAROUND
24158 + hcd->hw2937_assigned_channels |= (1 << hc->hc_num);
24159 + DWC_DEBUGPL(DBG_HW2937, " assign %d -> hw2937_ac %x\n", hc->hc_num, hcd->hw2937_assigned_channels);
24164 +#ifdef HW2937_WORKAROUND
24166 +void debug_halt(void)
24168 + spinlock_t mr_lock = SPIN_LOCK_UNLOCKED;
24169 + unsigned long flags;
24170 + extern void v6_flush_kern_cache_all(void);
24172 + spin_lock_irqsave(&mr_lock, flags);
24173 +#ifdef CONFIG_MACH_BCM2708
24174 + v6_flush_kern_cache_all();
24176 + while (1) continue;
24180 +void dwc_otg_hcd_disable_in_channels(dwc_otg_hcd_t * hcd)
24182 + int num_channels = hcd->core_if->core_params->host_channels;
24183 + static int stall_count = 0;
24184 + static int max_stall_count = 1;
24185 + static int last_stalled = 0;
24189 + DWC_DEBUGPL(DBG_HW2937, " Disable In Channels(%x)\n", hcd->hw2937_assigned_channels);
24191 + for (i = 0; i < num_channels; i++) {
24192 + if (hcd->hw2937_assigned_channels & (1 << i)) {
24193 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
24194 + if (!hc->halt_pending) {
24195 + dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
24196 + hctsiz_data_t hctsiz;
24197 + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
24198 + DWC_DEBUGPL(DBG_HW2937, "pktcnt %d, xfersize %x, xfer_len %x\n", hctsiz.b.pktcnt, hctsiz.b.xfersize, hc->xfer_len);
24199 + if (hctsiz.b.pktcnt == hc->start_pkt_count)
24201 + dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_PAUSE_IN);
24205 + /* Unless a receive is in progress */
24206 + stalled |= (1<<i);
24209 + stalled |= (1<<i);
24214 + if (stalled && (stalled == last_stalled))
24217 + if (stall_count > max_stall_count)
24219 + max_stall_count = stall_count;
24220 + DWC_PRINTF( "stall (%x) count -> %d\n", stalled, stall_count);
24221 + if (stall_count == 10)
24230 + last_stalled = stalled;
24235 +int dwc_otg_hcd_update_transaction_mode(dwc_otg_hcd_t * hcd)
24237 + dwc_list_link_t *qh_ptr;
24238 + dwc_otg_qh_t *qh;
24239 + dwc_otg_qtd_t *qtd;
24240 + dwc_otg_hcd_urb_t *urb;
24241 + int found_in = 0;
24243 + /* If there are any existing out transactions, stay in OUT mode */
24244 + if (hcd->hw2937_xfer_mode == HW2937_XFER_MODE_OUT)
24249 + /* Scan entries in the periodic ready list. */
24250 + qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
24252 + while (qh_ptr != &hcd->periodic_sched_ready) {
24253 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
24254 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
24256 + if (!dwc_otg_hcd_is_pipe_in(&urb->pipe_info)) {
24257 + /* Switch to OUT mode */
24258 + switch (hcd->hw2937_xfer_mode)
24260 + case HW2937_XFER_MODE_IDLE:
24261 + DWC_DEBUGPL(DBG_HW2937, "utm -> OUT\n");
24262 + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_OUT;
24263 + /* Drop through... */
24264 + case HW2937_XFER_MODE_OUT:
24266 + case HW2937_XFER_MODE_IN:
24267 + DWC_DEBUGPL(DBG_HW2937, "utm - halting %x INs\n", hcd->hw2937_assigned_channels);
24268 + /* Disable the channels with outstanding INs */
24269 + dwc_otg_hcd_disable_in_channels(hcd);
24271 + DWC_DEBUGPL(DBG_HW2937, "utm -> PAUSEIN\n");
24272 + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_PAUSEIN;
24273 + /* Drop through... */
24274 + case HW2937_XFER_MODE_PAUSEIN:
24275 + /* Delay until the halt completes */
24280 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
24284 + * Scan entries in the inactive portion of the non-periodic
24287 + qh_ptr = hcd->non_periodic_sched_inactive.next;
24288 + while (qh_ptr != &hcd->non_periodic_sched_inactive) {
24289 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
24290 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
24292 + if (!dwc_otg_hcd_is_pipe_in(&urb->pipe_info)) {
24293 + /* Switch to OUT mode */
24294 + switch (hcd->hw2937_xfer_mode)
24296 + case HW2937_XFER_MODE_IDLE:
24297 + DWC_DEBUGPL(DBG_HW2937, "utm -> OUT\n");
24298 + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_OUT;
24299 + /* Drop through... */
24300 + case HW2937_XFER_MODE_OUT:
24302 + case HW2937_XFER_MODE_IN:
24303 + DWC_DEBUGPL(DBG_HW2937, "utm - halting %x INs\n", hcd->hw2937_assigned_channels);
24304 + /* Disable the channels with outstanding INs */
24305 + dwc_otg_hcd_disable_in_channels(hcd);
24307 + DWC_DEBUGPL(DBG_HW2937, "utm -> PAUSEIN\n");
24308 + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_PAUSEIN;
24309 + /* Drop through... */
24310 + case HW2937_XFER_MODE_PAUSEIN:
24311 + /* Delay until the halt completes */
24316 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
24319 + if (found_in && (hcd->hw2937_xfer_mode == HW2937_XFER_MODE_IDLE))
24321 + DWC_DEBUGPL(DBG_HW2937, "utm -> IN\n");
24322 + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_IN;
24327 +#endif /* HW2937_WORKAROUND */
24330 + * This function selects transactions from the HCD transfer schedule and
24331 + * assigns them to available host channels. It is called from HCD interrupt
24332 + * handler functions.
24334 + * @param hcd The HCD state structure.
24336 + * @return The types of new transactions that were assigned to host channels.
24338 +dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
24340 + dwc_list_link_t *qh_ptr;
24341 + dwc_otg_qh_t *qh;
24342 + int num_channels;
24343 + dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
24346 + DWC_DEBUGPL(DBG_HCD, " Select Transactions\n");
24349 +#ifdef HW2937_WORKAROUND
24350 + if (!dwc_otg_hcd_update_transaction_mode(hcd))
24356 + /* Process entries in the periodic ready list. */
24357 + qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
24359 + while (qh_ptr != &hcd->periodic_sched_ready &&
24360 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
24361 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
24362 +#ifdef HW2937_WORKAROUND
24363 + if (assign_and_init_hc(hcd, qh)) {
24365 + assign_and_init_hc(hcd, qh);
24369 + * Move the QH from the periodic ready schedule to the
24370 + * periodic assigned schedule.
24372 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
24373 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
24374 + &qh->qh_list_entry);
24376 + ret_val = DWC_OTG_TRANSACTION_PERIODIC;
24377 +#ifdef HW2937_WORKAROUND
24379 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
24385 + * Process entries in the inactive portion of the non-periodic
24386 + * schedule. Some free host channels may not be used if they are
24387 + * reserved for periodic transfers.
24389 + qh_ptr = hcd->non_periodic_sched_inactive.next;
24390 + num_channels = hcd->core_if->core_params->host_channels;
24391 + while (qh_ptr != &hcd->non_periodic_sched_inactive &&
24392 + (hcd->non_periodic_channels <
24393 + num_channels - hcd->periodic_channels) &&
24394 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
24396 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
24398 +#ifdef HW2937_WORKAROUND
24399 + if (assign_and_init_hc(hcd, qh)) {
24401 + assign_and_init_hc(hcd, qh);
24405 + * Move the QH from the non-periodic inactive schedule to the
24406 + * non-periodic active schedule.
24408 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
24409 + DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
24410 + &qh->qh_list_entry);
24412 + if (ret_val == DWC_OTG_TRANSACTION_NONE) {
24413 + ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
24415 + ret_val = DWC_OTG_TRANSACTION_ALL;
24418 + hcd->non_periodic_channels++;
24419 +#ifdef HW2937_WORKAROUND
24421 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
24429 + * Attempts to queue a single transaction request for a host channel
24430 + * associated with either a periodic or non-periodic transfer. This function
24431 + * assumes that there is space available in the appropriate request queue. For
24432 + * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
24433 + * is available in the appropriate Tx FIFO.
24435 + * @param hcd The HCD state structure.
24436 + * @param hc Host channel descriptor associated with either a periodic or
24437 + * non-periodic transfer.
24438 + * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx
24439 + * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
24442 + * @return 1 if a request is queued and more requests may be needed to
24443 + * complete the transfer, 0 if no more requests are required for this
24444 + * transfer, -1 if there is insufficient space in the Tx FIFO.
24446 +static int queue_transaction(dwc_otg_hcd_t * hcd,
24447 + dwc_hc_t * hc, uint16_t fifo_dwords_avail)
24451 + if (hcd->core_if->dma_enable) {
24452 + if (hcd->core_if->dma_desc_enable) {
24453 + if (!hc->xfer_started || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
24454 + dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
24455 + hc->qh->ping_state = 0;
24458 + else if (!hc->xfer_started) {
24459 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
24460 + hc->qh->ping_state = 0;
24463 + } else if (hc->halt_pending) {
24464 + /* Don't queue a request if the channel has been halted. */
24466 + } else if (hc->halt_on_queue) {
24467 + dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
24469 + } else if (hc->do_ping) {
24470 + if (!hc->xfer_started) {
24471 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
24474 + } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
24475 + if ((fifo_dwords_avail * 4) >= hc->max_packet) {
24476 + if (!hc->xfer_started) {
24477 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
24481 + dwc_otg_hc_continue_transfer(hcd->core_if,
24488 + if (!hc->xfer_started) {
24489 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
24492 + retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
24500 + * Processes periodic channels for the next frame and queues transactions for
24501 + * these channels to the DWC_otg controller. After queueing transactions, the
24502 + * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
24503 + * to queue as Periodic Tx FIFO or request queue space becomes available.
24504 + * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
24506 +static void process_periodic_channels(dwc_otg_hcd_t * hcd)
24508 + hptxsts_data_t tx_status;
24509 + dwc_list_link_t *qh_ptr;
24510 + dwc_otg_qh_t *qh;
24512 + int no_queue_space = 0;
24513 + int no_fifo_space = 0;
24515 + dwc_otg_host_global_regs_t *host_regs;
24516 + host_regs = hcd->core_if->host_if->host_global_regs;
24518 + DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
24520 + tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
24521 + DWC_DEBUGPL(DBG_HCDV,
24522 + " P Tx Req Queue Space Avail (before queue): %d\n",
24523 + tx_status.b.ptxqspcavail);
24524 + DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n",
24525 + tx_status.b.ptxfspcavail);
24528 + qh_ptr = hcd->periodic_sched_assigned.next;
24529 + while (qh_ptr != &hcd->periodic_sched_assigned) {
24530 + tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
24531 + if (tx_status.b.ptxqspcavail == 0) {
24532 + no_queue_space = 1;
24536 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
24539 + * Set a flag if we're queuing high-bandwidth in slave mode.
24540 + * The flag prevents any halts to get into the request queue in
24541 + * the middle of multiple high-bandwidth packets getting queued.
24543 + if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
24544 + hcd->core_if->queuing_high_bandwidth = 1;
24547 + queue_transaction(hcd, qh->channel,
24548 + tx_status.b.ptxfspcavail);
24549 + if (status < 0) {
24550 + no_fifo_space = 1;
24555 + * In Slave mode, stay on the current transfer until there is
24556 + * nothing more to do or the high-bandwidth request count is
24557 + * reached. In DMA mode, only need to queue one request. The
24558 + * controller automatically handles multiple packets for
24559 + * high-bandwidth transfers.
24561 + if (hcd->core_if->dma_enable || status == 0 ||
24562 + qh->channel->requests == qh->channel->multi_count) {
24563 + qh_ptr = qh_ptr->next;
24565 + * Move the QH from the periodic assigned schedule to
24566 + * the periodic queued schedule.
24568 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
24569 + &qh->qh_list_entry);
24571 + /* done queuing high bandwidth */
24572 + hcd->core_if->queuing_high_bandwidth = 0;
24576 + if (!hcd->core_if->dma_enable) {
24577 + dwc_otg_core_global_regs_t *global_regs;
24578 + gintmsk_data_t intr_mask = {.d32 = 0 };
24580 + global_regs = hcd->core_if->core_global_regs;
24581 + intr_mask.b.ptxfempty = 1;
24583 + tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
24584 + DWC_DEBUGPL(DBG_HCDV,
24585 + " P Tx Req Queue Space Avail (after queue): %d\n",
24586 + tx_status.b.ptxqspcavail);
24587 + DWC_DEBUGPL(DBG_HCDV,
24588 + " P Tx FIFO Space Avail (after queue): %d\n",
24589 + tx_status.b.ptxfspcavail);
24591 + if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
24592 + no_queue_space || no_fifo_space) {
24594 + * May need to queue more transactions as the request
24595 + * queue or Tx FIFO empties. Enable the periodic Tx
24596 + * FIFO empty interrupt. (Always use the half-empty
24597 + * level to ensure that new requests are loaded as
24598 + * soon as possible.)
24600 + dwc_modify_reg32(&global_regs->gintmsk, 0,
24604 + * Disable the Tx FIFO empty interrupt since there are
24605 + * no more transactions that need to be queued right
24606 + * now. This function is called from interrupt
24607 + * handlers to queue more transactions as transfer
24610 + dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32,
24617 + * Processes active non-periodic channels and queues transactions for these
24618 + * channels to the DWC_otg controller. After queueing transactions, the NP Tx
24619 + * FIFO Empty interrupt is enabled if there are more transactions to queue as
24620 + * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
24621 + * FIFO Empty interrupt is disabled.
24623 +static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
24625 + gnptxsts_data_t tx_status;
24626 + dwc_list_link_t *orig_qh_ptr;
24627 + dwc_otg_qh_t *qh;
24629 + int no_queue_space = 0;
24630 + int no_fifo_space = 0;
24631 + int more_to_do = 0;
24633 + dwc_otg_core_global_regs_t *global_regs =
24634 + hcd->core_if->core_global_regs;
24636 + DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
24638 + tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
24639 + DWC_DEBUGPL(DBG_HCDV,
24640 + " NP Tx Req Queue Space Avail (before queue): %d\n",
24641 + tx_status.b.nptxqspcavail);
24642 + DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n",
24643 + tx_status.b.nptxfspcavail);
24646 + * Keep track of the starting point. Skip over the start-of-list
24649 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
24650 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
24652 + orig_qh_ptr = hcd->non_periodic_qh_ptr;
24655 + * Process once through the active list or until no more space is
24656 + * available in the request queue or the Tx FIFO.
24659 + tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
24660 + if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
24661 + no_queue_space = 1;
24665 + qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
24668 + queue_transaction(hcd, qh->channel,
24669 + tx_status.b.nptxfspcavail);
24671 + if (status > 0) {
24673 + } else if (status < 0) {
24674 + no_fifo_space = 1;
24678 + /* Advance to next QH, skipping start-of-list entry. */
24679 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
24680 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
24681 + hcd->non_periodic_qh_ptr =
24682 + hcd->non_periodic_qh_ptr->next;
24685 + } while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
24687 + if (!hcd->core_if->dma_enable) {
24688 + gintmsk_data_t intr_mask = {.d32 = 0 };
24689 + intr_mask.b.nptxfempty = 1;
24692 + tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
24693 + DWC_DEBUGPL(DBG_HCDV,
24694 + " NP Tx Req Queue Space Avail (after queue): %d\n",
24695 + tx_status.b.nptxqspcavail);
24696 + DWC_DEBUGPL(DBG_HCDV,
24697 + " NP Tx FIFO Space Avail (after queue): %d\n",
24698 + tx_status.b.nptxfspcavail);
24700 + if (more_to_do || no_queue_space || no_fifo_space) {
24702 + * May need to queue more transactions as the request
24703 + * queue or Tx FIFO empties. Enable the non-periodic
24704 + * Tx FIFO empty interrupt. (Always use the half-empty
24705 + * level to ensure that new requests are loaded as
24706 + * soon as possible.)
24708 + dwc_modify_reg32(&global_regs->gintmsk, 0,
24712 + * Disable the Tx FIFO empty interrupt since there are
24713 + * no more transactions that need to be queued right
24714 + * now. This function is called from interrupt
24715 + * handlers to queue more transactions as transfer
24718 + dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32,
24725 + * This function processes the currently active host channels and queues
24726 + * transactions for these channels to the DWC_otg controller. It is called
24727 + * from HCD interrupt handler functions.
24729 + * @param hcd The HCD state structure.
24730 + * @param tr_type The type(s) of transactions to queue (non-periodic,
24731 + * periodic, or both).
24733 +void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
24734 + dwc_otg_transaction_type_e tr_type)
24737 + DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
24739 + /* Process host channels associated with periodic transfers. */
24740 + if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
24741 + tr_type == DWC_OTG_TRANSACTION_ALL) &&
24742 + !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
24744 + process_periodic_channels(hcd);
24747 + /* Process host channels associated with non-periodic transfers. */
24748 + if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
24749 + tr_type == DWC_OTG_TRANSACTION_ALL) {
24750 + if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
24751 + process_non_periodic_channels(hcd);
24754 + * Ensure NP Tx FIFO empty interrupt is disabled when
24755 + * there are no non-periodic transfers to process.
24757 + gintmsk_data_t gintmsk = {.d32 = 0 };
24758 + gintmsk.b.nptxfempty = 1;
24759 + dwc_modify_reg32(&hcd->core_if->core_global_regs->
24760 + gintmsk, gintmsk.d32, 0);
24765 +#ifdef DWC_HS_ELECT_TST
24767 + * Quick and dirty hack to implement the HS Electrical Test
24768 + * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
24770 + * This code was copied from our userspace app "hset". It sends a
24771 + * Get Device Descriptor control sequence in two parts, first the
24772 + * Setup packet by itself, followed some time later by the In and
24773 + * Ack packets. Rather than trying to figure out how to add this
24774 + * functionality to the normal driver code, we just hijack the
24775 + * hardware, using these two function to drive the hardware
24779 +static dwc_otg_core_global_regs_t *global_regs;
24780 +static dwc_otg_host_global_regs_t *hc_global_regs;
24781 +static dwc_otg_hc_regs_t *hc_regs;
24782 +static uint32_t *data_fifo;
24784 +static void do_setup(void)
24786 + gintsts_data_t gintsts;
24787 + hctsiz_data_t hctsiz;
24788 + hcchar_data_t hcchar;
24789 + haint_data_t haint;
24790 + hcint_data_t hcint;
24792 + /* Enable HAINTs */
24793 + dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001);
24795 + /* Enable HCINTs */
24796 + dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3);
24798 + /* Read GINTSTS */
24799 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
24802 + haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
24805 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
24807 + /* Read HCCHAR */
24808 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
24810 + /* Clear HCINT */
24811 + dwc_write_reg32(&hc_regs->hcint, hcint.d32);
24813 + /* Clear HAINT */
24814 + dwc_write_reg32(&hc_global_regs->haint, haint.d32);
24816 + /* Clear GINTSTS */
24817 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
24819 + /* Read GINTSTS */
24820 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
24823 + * Send Setup packet (Get Device Descriptor)
24826 + /* Make sure channel is disabled */
24827 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
24828 + if (hcchar.b.chen) {
24829 + hcchar.b.chdis = 1;
24830 +// hcchar.b.chen = 1;
24831 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
24833 + dwc_mdelay(1000);
24835 + /* Read GINTSTS */
24836 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
24839 + haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
24842 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
24844 + /* Read HCCHAR */
24845 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
24847 + /* Clear HCINT */
24848 + dwc_write_reg32(&hc_regs->hcint, hcint.d32);
24850 + /* Clear HAINT */
24851 + dwc_write_reg32(&hc_global_regs->haint, haint.d32);
24853 + /* Clear GINTSTS */
24854 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
24856 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
24861 + hctsiz.b.xfersize = 8;
24862 + hctsiz.b.pktcnt = 1;
24863 + hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
24864 + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
24867 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
24868 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
24869 + hcchar.b.epdir = 0;
24870 + hcchar.b.epnum = 0;
24871 + hcchar.b.mps = 8;
24872 + hcchar.b.chen = 1;
24873 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
24875 + /* Fill FIFO with Setup data for Get Device Descriptor */
24876 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
24877 + dwc_write_reg32(data_fifo++, 0x01000680);
24878 + dwc_write_reg32(data_fifo++, 0x00080000);
24880 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
24882 + /* Wait for host channel interrupt */
24884 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
24885 + } while (gintsts.b.hcintr == 0);
24888 + /* Disable HCINTs */
24889 + dwc_write_reg32(&hc_regs->hcintmsk, 0x0000);
24891 + /* Disable HAINTs */
24892 + dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000);
24895 + haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
24898 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
24900 + /* Read HCCHAR */
24901 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
24903 + /* Clear HCINT */
24904 + dwc_write_reg32(&hc_regs->hcint, hcint.d32);
24906 + /* Clear HAINT */
24907 + dwc_write_reg32(&hc_global_regs->haint, haint.d32);
24909 + /* Clear GINTSTS */
24910 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
24912 + /* Read GINTSTS */
24913 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
24916 +static void do_in_ack(void)
24918 + gintsts_data_t gintsts;
24919 + hctsiz_data_t hctsiz;
24920 + hcchar_data_t hcchar;
24921 + haint_data_t haint;
24922 + hcint_data_t hcint;
24923 + host_grxsts_data_t grxsts;
24925 + /* Enable HAINTs */
24926 + dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001);
24928 + /* Enable HCINTs */
24929 + dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3);
24931 + /* Read GINTSTS */
24932 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
24935 + haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
24938 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
24940 + /* Read HCCHAR */
24941 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
24943 + /* Clear HCINT */
24944 + dwc_write_reg32(&hc_regs->hcint, hcint.d32);
24946 + /* Clear HAINT */
24947 + dwc_write_reg32(&hc_global_regs->haint, haint.d32);
24949 + /* Clear GINTSTS */
24950 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
24952 + /* Read GINTSTS */
24953 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
24956 + * Receive Control In packet
24959 + /* Make sure channel is disabled */
24960 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
24961 + if (hcchar.b.chen) {
24962 + hcchar.b.chdis = 1;
24963 + hcchar.b.chen = 1;
24964 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
24966 + dwc_mdelay(1000);
24968 + /* Read GINTSTS */
24969 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
24972 + haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
24975 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
24977 + /* Read HCCHAR */
24978 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
24980 + /* Clear HCINT */
24981 + dwc_write_reg32(&hc_regs->hcint, hcint.d32);
24983 + /* Clear HAINT */
24984 + dwc_write_reg32(&hc_global_regs->haint, haint.d32);
24986 + /* Clear GINTSTS */
24987 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
24989 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
24994 + hctsiz.b.xfersize = 8;
24995 + hctsiz.b.pktcnt = 1;
24996 + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
24997 + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
25000 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
25001 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
25002 + hcchar.b.epdir = 1;
25003 + hcchar.b.epnum = 0;
25004 + hcchar.b.mps = 8;
25005 + hcchar.b.chen = 1;
25006 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
25008 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25010 + /* Wait for receive status queue interrupt */
25012 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25013 + } while (gintsts.b.rxstsqlvl == 0);
25017 + grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp);
25019 + /* Clear RXSTSQLVL in GINTSTS */
25021 + gintsts.b.rxstsqlvl = 1;
25022 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
25024 + switch (grxsts.b.pktsts) {
25025 + case DWC_GRXSTS_PKTSTS_IN:
25026 + /* Read the data into the host buffer */
25027 + if (grxsts.b.bcnt > 0) {
25029 + int word_count = (grxsts.b.bcnt + 3) / 4;
25031 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
25033 + for (i = 0; i < word_count; i++) {
25034 + (void)dwc_read_reg32(data_fifo++);
25043 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25045 + /* Wait for receive status queue interrupt */
25047 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25048 + } while (gintsts.b.rxstsqlvl == 0);
25052 + grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp);
25054 + /* Clear RXSTSQLVL in GINTSTS */
25056 + gintsts.b.rxstsqlvl = 1;
25057 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
25059 + switch (grxsts.b.pktsts) {
25060 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
25067 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25069 + /* Wait for host channel interrupt */
25071 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25072 + } while (gintsts.b.hcintr == 0);
25076 + haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
25079 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
25081 + /* Read HCCHAR */
25082 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
25084 + /* Clear HCINT */
25085 + dwc_write_reg32(&hc_regs->hcint, hcint.d32);
25087 + /* Clear HAINT */
25088 + dwc_write_reg32(&hc_global_regs->haint, haint.d32);
25090 + /* Clear GINTSTS */
25091 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
25093 + /* Read GINTSTS */
25094 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25096 +// usleep(100000);
25101 + * Send handshake packet
25105 + haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
25108 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
25110 + /* Read HCCHAR */
25111 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
25113 + /* Clear HCINT */
25114 + dwc_write_reg32(&hc_regs->hcint, hcint.d32);
25116 + /* Clear HAINT */
25117 + dwc_write_reg32(&hc_global_regs->haint, haint.d32);
25119 + /* Clear GINTSTS */
25120 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
25122 + /* Read GINTSTS */
25123 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25125 + /* Make sure channel is disabled */
25126 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
25127 + if (hcchar.b.chen) {
25128 + hcchar.b.chdis = 1;
25129 + hcchar.b.chen = 1;
25130 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
25132 + dwc_mdelay(1000);
25134 + /* Read GINTSTS */
25135 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25138 + haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
25141 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
25143 + /* Read HCCHAR */
25144 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
25146 + /* Clear HCINT */
25147 + dwc_write_reg32(&hc_regs->hcint, hcint.d32);
25149 + /* Clear HAINT */
25150 + dwc_write_reg32(&hc_global_regs->haint, haint.d32);
25152 + /* Clear GINTSTS */
25153 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
25155 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
25160 + hctsiz.b.xfersize = 0;
25161 + hctsiz.b.pktcnt = 1;
25162 + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
25163 + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
25166 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
25167 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
25168 + hcchar.b.epdir = 0;
25169 + hcchar.b.epnum = 0;
25170 + hcchar.b.mps = 8;
25171 + hcchar.b.chen = 1;
25172 + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
25174 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25176 + /* Wait for host channel interrupt */
25178 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25179 + } while (gintsts.b.hcintr == 0);
25182 + /* Disable HCINTs */
25183 + dwc_write_reg32(&hc_regs->hcintmsk, 0x0000);
25185 + /* Disable HAINTs */
25186 + dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000);
25189 + haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
25192 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
25194 + /* Read HCCHAR */
25195 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
25197 + /* Clear HCINT */
25198 + dwc_write_reg32(&hc_regs->hcint, hcint.d32);
25200 + /* Clear HAINT */
25201 + dwc_write_reg32(&hc_global_regs->haint, haint.d32);
25203 + /* Clear GINTSTS */
25204 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
25206 + /* Read GINTSTS */
25207 + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
25211 +/** Handles hub class-specific requests. */
25212 +int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
25213 + uint16_t typeReq,
25215 + uint16_t wIndex, uint8_t * buf, uint16_t wLength)
25219 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
25220 + usb_hub_descriptor_t *hub_desc;
25221 + hprt0_data_t hprt0 = {.d32 = 0 };
25223 + uint32_t port_status;
25225 + switch (typeReq) {
25226 + case UCR_CLEAR_HUB_FEATURE:
25227 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25228 + "ClearHubFeature 0x%x\n", wValue);
25229 + switch (wValue) {
25230 + case UHF_C_HUB_LOCAL_POWER:
25231 + case UHF_C_HUB_OVER_CURRENT:
25232 + /* Nothing required here */
25235 + retval = -DWC_E_INVALID;
25236 + DWC_ERROR("DWC OTG HCD - "
25237 + "ClearHubFeature request %xh unknown\n",
25241 + case UCR_CLEAR_PORT_FEATURE:
25242 +#ifdef CONFIG_USB_DWC_OTG_LPM
25243 + if (wValue != UHF_PORT_L1)
25245 + if (!wIndex || wIndex > 1)
25248 + switch (wValue) {
25249 + case UHF_PORT_ENABLE:
25250 + DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
25251 + "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
25252 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
25253 + hprt0.b.prtena = 1;
25254 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
25256 + case UHF_PORT_SUSPEND:
25257 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25258 + "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
25260 + dwc_write_reg32(core_if->pcgcctl, 0);
25263 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
25264 + hprt0.b.prtres = 1;
25265 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
25266 + hprt0.b.prtsusp = 0;
25267 + /* Clear Resume bit */
25269 + hprt0.b.prtres = 0;
25270 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
25272 +#ifdef CONFIG_USB_DWC_OTG_LPM
25273 + case UHF_PORT_L1:
25275 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
25276 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
25279 + dwc_read_reg32(&core_if->core_global_regs->
25281 + lpmcfg.b.en_utmi_sleep = 0;
25282 + lpmcfg.b.hird_thres &= (~(1 << 4));
25283 + lpmcfg.b.prt_sleep_sts = 1;
25284 + dwc_write_reg32(&core_if->core_global_regs->
25285 + glpmcfg, lpmcfg.d32);
25287 + /* Clear Enbl_L1Gating bit. */
25288 + pcgcctl.b.enbl_sleep_gating = 1;
25289 + dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32,
25294 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
25295 + hprt0.b.prtres = 1;
25296 + dwc_write_reg32(core_if->host_if->hprt0,
25298 + /* This bit will be cleared in wakeup interrupt handle */
25302 + case UHF_PORT_POWER:
25303 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25304 + "ClearPortFeature USB_PORT_FEAT_POWER\n");
25305 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
25306 + hprt0.b.prtpwr = 0;
25307 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
25309 + case UHF_PORT_INDICATOR:
25310 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25311 + "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
25312 + /* Port inidicator not supported */
25314 + case UHF_C_PORT_CONNECTION:
25315 + /* Clears drivers internal connect status change
25317 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25318 + "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
25319 + dwc_otg_hcd->flags.b.port_connect_status_change = 0;
25321 + case UHF_C_PORT_RESET:
25322 + /* Clears the driver's internal Port Reset Change
25324 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25325 + "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
25326 + dwc_otg_hcd->flags.b.port_reset_change = 0;
25328 + case UHF_C_PORT_ENABLE:
25329 + /* Clears the driver's internal Port
25330 + * Enable/Disable Change flag */
25331 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25332 + "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
25333 + dwc_otg_hcd->flags.b.port_enable_change = 0;
25335 + case UHF_C_PORT_SUSPEND:
25336 + /* Clears the driver's internal Port Suspend
25337 + * Change flag, which is set when resume signaling on
25338 + * the host port is complete */
25339 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25340 + "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
25341 + dwc_otg_hcd->flags.b.port_suspend_change = 0;
25343 +#ifdef CONFIG_USB_DWC_OTG_LPM
25344 + case UHF_C_PORT_L1:
25345 + dwc_otg_hcd->flags.b.port_l1_change = 0;
25348 + case UHF_C_PORT_OVER_CURRENT:
25349 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25350 + "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
25351 + dwc_otg_hcd->flags.b.port_over_current_change = 0;
25354 + retval = -DWC_E_INVALID;
25355 + DWC_ERROR("DWC OTG HCD - "
25356 + "ClearPortFeature request %xh "
25357 + "unknown or unsupported\n", wValue);
25360 + case UCR_GET_HUB_DESCRIPTOR:
25361 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25362 + "GetHubDescriptor\n");
25363 + hub_desc = (usb_hub_descriptor_t *) buf;
25364 + hub_desc->bDescLength = 9;
25365 + hub_desc->bDescriptorType = 0x29;
25366 + hub_desc->bNbrPorts = 1;
25367 + USETW(hub_desc->wHubCharacteristics, 0x08);
25368 + hub_desc->bPwrOn2PwrGood = 1;
25369 + hub_desc->bHubContrCurrent = 0;
25370 + hub_desc->DeviceRemovable[0] = 0;
25371 + hub_desc->DeviceRemovable[1] = 0xff;
25373 + case UCR_GET_HUB_STATUS:
25374 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25375 + "GetHubStatus\n");
25376 + DWC_MEMSET(buf, 0, 4);
25378 + case UCR_GET_PORT_STATUS:
25379 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25380 + "GetPortStatus\n");
25381 + if (!wIndex || wIndex > 1)
25386 + if (dwc_otg_hcd->flags.b.port_connect_status_change)
25387 + port_status |= (1 << UHF_C_PORT_CONNECTION);
25389 + if (dwc_otg_hcd->flags.b.port_enable_change)
25390 + port_status |= (1 << UHF_C_PORT_ENABLE);
25392 + if (dwc_otg_hcd->flags.b.port_suspend_change)
25393 + port_status |= (1 << UHF_C_PORT_SUSPEND);
25395 + if (dwc_otg_hcd->flags.b.port_l1_change)
25396 + port_status |= (1 << UHF_C_PORT_L1);
25398 + if (dwc_otg_hcd->flags.b.port_reset_change) {
25399 + port_status |= (1 << UHF_C_PORT_RESET);
25402 + if (dwc_otg_hcd->flags.b.port_over_current_change) {
25403 + DWC_ERROR("Device Not Supported\n");
25404 + port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
25407 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
25409 + * The port is disconnected, which means the core is
25410 + * either in device mode or it soon will be. Just
25411 + * return 0's for the remainder of the port status
25412 + * since the port register can't be read if the core
25413 + * is in device mode.
25415 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
25419 + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
25420 + DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32);
25422 + if (hprt0.b.prtconnsts)
25423 + port_status |= (1 << UHF_PORT_CONNECTION);
25425 + if (hprt0.b.prtena)
25426 + port_status |= (1 << UHF_PORT_ENABLE);
25428 + if (hprt0.b.prtsusp)
25429 + port_status |= (1 << UHF_PORT_SUSPEND);
25431 + if (hprt0.b.prtovrcurract)
25432 + port_status |= (1 << UHF_PORT_OVER_CURRENT);
25434 + if (hprt0.b.prtrst)
25435 + port_status |= (1 << UHF_PORT_RESET);
25437 + if (hprt0.b.prtpwr)
25438 + port_status |= (1 << UHF_PORT_POWER);
25440 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
25441 + port_status |= (1 << UHF_PORT_HIGH_SPEED);
25442 + else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
25443 + port_status |= (1 << UHF_PORT_LOW_SPEED);
25445 + if (hprt0.b.prttstctl)
25446 + port_status |= (1 << UHF_PORT_TEST);
25447 + if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
25448 + port_status |= (1 << UHF_PORT_L1);
25451 + /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
25453 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
25456 + case UCR_SET_HUB_FEATURE:
25457 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25458 + "SetHubFeature\n");
25459 + /* No HUB features supported */
25461 + case UCR_SET_PORT_FEATURE:
25462 + if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
25465 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
25467 + * The port is disconnected, which means the core is
25468 + * either in device mode or it soon will be. Just
25469 + * return without doing anything since the port
25470 + * register can't be written if the core is in device
25476 + switch (wValue) {
25477 + case UHF_PORT_SUSPEND:
25478 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25479 + "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
25480 + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
25481 + dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
25482 + gotgctl_data_t gotgctl = {.d32 = 0 };
25483 + gotgctl.b.hstsethnpen = 1;
25484 + dwc_modify_reg32(&core_if->core_global_regs->
25485 + gotgctl, 0, gotgctl.d32);
25486 + core_if->op_state = A_SUSPEND;
25488 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
25489 + hprt0.b.prtsusp = 1;
25490 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
25493 + /* Update lx_state */
25494 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
25495 + core_if->lx_state = DWC_OTG_L2;
25496 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
25498 + /* Suspend the Phy Clock */
25500 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
25501 + pcgcctl.b.stoppclk = 1;
25502 + dwc_modify_reg32(core_if->pcgcctl, 0,
25506 + /* For HNP the bus must be suspended for at least 200ms. */
25507 + if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
25511 + case UHF_PORT_POWER:
25512 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25513 + "SetPortFeature - USB_PORT_FEAT_POWER\n");
25514 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
25515 + hprt0.b.prtpwr = 1;
25516 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
25518 + case UHF_PORT_RESET:
25519 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25520 + "SetPortFeature - USB_PORT_FEAT_RESET\n");
25522 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
25523 + pcgcctl.b.enbl_sleep_gating = 1;
25524 + pcgcctl.b.stoppclk = 1;
25525 + dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32,
25527 + dwc_write_reg32(core_if->pcgcctl, 0);
25529 +#ifdef CONFIG_USB_DWC_OTG_LPM
25531 + glpmcfg_data_t lpmcfg;
25533 + dwc_read_reg32(&core_if->core_global_regs->
25535 + if (lpmcfg.b.prt_sleep_sts) {
25536 + lpmcfg.b.en_utmi_sleep = 0;
25537 + lpmcfg.b.hird_thres &= (~(1 << 4));
25538 + dwc_write_reg32(&core_if->
25539 + core_global_regs->
25540 + glpmcfg, lpmcfg.d32);
25545 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
25546 + /* When B-Host the Port reset bit is set in
25547 + * the Start HCD Callback function, so that
25548 + * the reset is started within 1ms of the HNP
25549 + * success interrupt. */
25550 + if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
25551 + hprt0.b.prtrst = 1;
25552 + dwc_write_reg32(core_if->host_if->hprt0,
25555 + /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
25557 + hprt0.b.prtrst = 0;
25558 + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
25559 + core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */
25561 +#ifdef DWC_HS_ELECT_TST
25562 + case UHF_PORT_TEST:
25565 + gintmsk_data_t gintmsk;
25567 + t = (wIndex >> 8); /* MSB wIndex USB */
25568 + DWC_DEBUGPL(DBG_HCD,
25569 + "DWC OTG HCD HUB CONTROL - "
25570 + "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
25572 + DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
25574 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
25575 + hprt0.b.prttstctl = t;
25576 + dwc_write_reg32(core_if->host_if->hprt0,
25579 + /* Setup global vars with reg addresses (quick and
25580 + * dirty hack, should be cleaned up)
25582 + global_regs = core_if->core_global_regs;
25584 + core_if->host_if->host_global_regs;
25586 + (dwc_otg_hc_regs_t *) ((char *)
25590 + (uint32_t *) ((char *)global_regs +
25593 + if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */
25594 + /* Save current interrupt mask */
25597 + (&global_regs->gintmsk);
25599 + /* Disable all interrupts while we muck with
25600 + * the hardware directly
25602 + dwc_write_reg32(&global_regs->
25605 + /* 15 second delay per the test spec */
25606 + dwc_mdelay(15000);
25608 + /* Drive suspend on the root port */
25610 + dwc_otg_read_hprt0(core_if);
25611 + hprt0.b.prtsusp = 1;
25612 + hprt0.b.prtres = 0;
25613 + dwc_write_reg32(core_if->
25617 + /* 15 second delay per the test spec */
25618 + dwc_mdelay(15000);
25620 + /* Drive resume on the root port */
25622 + dwc_otg_read_hprt0(core_if);
25623 + hprt0.b.prtsusp = 0;
25624 + hprt0.b.prtres = 1;
25625 + dwc_write_reg32(core_if->
25630 + /* Clear the resume bit */
25631 + hprt0.b.prtres = 0;
25632 + dwc_write_reg32(core_if->
25636 + /* Restore interrupts */
25637 + dwc_write_reg32(&global_regs->
25640 + } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
25641 + /* Save current interrupt mask */
25644 + (&global_regs->gintmsk);
25646 + /* Disable all interrupts while we muck with
25647 + * the hardware directly
25649 + dwc_write_reg32(&global_regs->
25652 + /* 15 second delay per the test spec */
25653 + dwc_mdelay(15000);
25655 + /* Send the Setup packet */
25658 + /* 15 second delay so nothing else happens for awhile */
25659 + dwc_mdelay(15000);
25661 + /* Restore interrupts */
25662 + dwc_write_reg32(&global_regs->
25665 + } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
25666 + /* Save current interrupt mask */
25669 + (&global_regs->gintmsk);
25671 + /* Disable all interrupts while we muck with
25672 + * the hardware directly
25674 + dwc_write_reg32(&global_regs->
25677 + /* Send the Setup packet */
25680 + /* 15 second delay so nothing else happens for awhile */
25681 + dwc_mdelay(15000);
25683 + /* Send the In and Ack packets */
25686 + /* 15 second delay so nothing else happens for awhile */
25687 + dwc_mdelay(15000);
25689 + /* Restore interrupts */
25690 + dwc_write_reg32(&global_regs->
25697 +#endif /* DWC_HS_ELECT_TST */
25699 + case UHF_PORT_INDICATOR:
25700 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
25701 + "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
25702 + /* Not supported */
25705 + retval = -DWC_E_INVALID;
25706 + DWC_ERROR("DWC OTG HCD - "
25707 + "SetPortFeature request %xh "
25708 + "unknown or unsupported\n", wValue);
25712 +#ifdef CONFIG_USB_DWC_OTG_LPM
25713 + case UCR_SET_AND_TEST_PORT_FEATURE:
25714 + if (wValue != UHF_PORT_L1) {
25718 + int portnum, hird, devaddr, remwake;
25719 + glpmcfg_data_t lpmcfg;
25720 + uint32_t time_usecs;
25721 + gintsts_data_t gintsts;
25722 + gintmsk_data_t gintmsk;
25724 + if (!dwc_otg_get_param_lpm_enable(core_if)) {
25727 + if (wValue != UHF_PORT_L1 || wLength != 1) {
25730 + /* Check if the port currently is in SLEEP state */
25732 + dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
25733 + if (lpmcfg.b.prt_sleep_sts) {
25734 + DWC_INFO("Port is already in sleep mode\n");
25735 + buf[0] = 0; /* Return success */
25739 + portnum = wIndex & 0xf;
25740 + hird = (wIndex >> 4) & 0xf;
25741 + devaddr = (wIndex >> 8) & 0x7f;
25742 + remwake = (wIndex >> 15);
25744 + if (portnum != 1) {
25745 + retval = -DWC_E_INVALID;
25747 + ("Wrong port number(%d) in SetandTestPortFeature request\n",
25753 + ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
25754 + portnum, hird, devaddr, remwake);
25755 + /* Disable LPM interrupt */
25757 + gintmsk.b.lpmtranrcvd = 1;
25758 + dwc_modify_reg32(&core_if->core_global_regs->gintmsk,
25761 + if (dwc_otg_hcd_send_lpm
25762 + (dwc_otg_hcd, devaddr, hird, remwake)) {
25763 + retval = -DWC_E_INVALID;
25767 + time_usecs = 10 * (lpmcfg.b.retry_count + 1);
25768 + /* We will consider timeout if time_usecs microseconds pass,
25769 + * and we don't receive LPM transaction status.
25770 + * After receiving non-error responce(ACK/NYET/STALL) from device,
25771 + * core will set lpmtranrcvd bit.
25775 + dwc_read_reg32(&core_if->core_global_regs->
25777 + if (gintsts.b.lpmtranrcvd) {
25781 + } while (--time_usecs);
25782 + /* lpm_int bit will be cleared in LPM interrupt handler */
25784 + /* Now fill status
25789 + if (!gintsts.b.lpmtranrcvd) {
25790 + buf[0] = 0x3; /* Completion code is Timeout */
25791 + dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
25794 + dwc_read_reg32(&core_if->core_global_regs->
25796 + if (lpmcfg.b.lpm_resp == 0x3) {
25797 + /* ACK responce from the device */
25798 + buf[0] = 0x00; /* Success */
25799 + } else if (lpmcfg.b.lpm_resp == 0x2) {
25800 + /* NYET responce from the device */
25803 + /* Otherwise responce with Timeout */
25807 + DWC_PRINTF("Device responce to LPM trans is %x\n",
25808 + lpmcfg.b.lpm_resp);
25809 + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, 0,
25814 +#endif /* CONFIG_USB_DWC_OTG_LPM */
25817 + retval = -DWC_E_INVALID;
25818 + DWC_WARN("DWC OTG HCD - "
25819 + "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
25820 + typeReq, wIndex, wValue);
25827 +#ifdef CONFIG_USB_DWC_OTG_LPM
25828 +/** Returns index of host channel to perform LPM transaction. */
25829 +int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
25831 + dwc_otg_core_if_t *core_if = hcd->core_if;
25833 + hcchar_data_t hcchar;
25834 + gintmsk_data_t gintmsk = {.d32 = 0 };
25836 + if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
25837 + DWC_PRINTF("No free channel to select for LPM transaction\n");
25841 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
25843 + /* Mask host channel interrupts. */
25844 + gintmsk.b.hcintr = 1;
25845 + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
25847 + /* Fill fields that core needs for LPM transaction */
25848 + hcchar.b.devaddr = devaddr;
25849 + hcchar.b.epnum = 0;
25850 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
25851 + hcchar.b.mps = 64;
25852 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
25853 + hcchar.b.epdir = 0; /* OUT */
25854 + dwc_write_reg32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
25857 + /* Remove the host channel from the free list. */
25858 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
25860 + DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
25862 + return hc->hc_num;
25865 +/** Release hc after performing LPM transaction */
25866 +void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
25869 + glpmcfg_data_t lpmcfg;
25872 + lpmcfg.d32 = dwc_read_reg32(&hcd->core_if->core_global_regs->glpmcfg);
25873 + hc_num = lpmcfg.b.lpm_chan_index;
25875 + hc = hcd->hc_ptr_array[hc_num];
25877 + DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
25878 + /* Return host channel to free list */
25879 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
25882 +int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
25883 + uint8_t bRemoteWake)
25885 + glpmcfg_data_t lpmcfg;
25886 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
25889 + channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
25890 + if (channel < 0) {
25894 + pcgcctl.b.enbl_sleep_gating = 1;
25895 + dwc_modify_reg32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
25897 + /* Read LPM config register */
25898 + lpmcfg.d32 = dwc_read_reg32(&hcd->core_if->core_global_regs->glpmcfg);
25900 + /* Program LPM transaction fields */
25901 + lpmcfg.b.rem_wkup_en = bRemoteWake;
25902 + lpmcfg.b.hird = hird;
25903 + lpmcfg.b.hird_thres = 0x1c;
25904 + lpmcfg.b.lpm_chan_index = channel;
25905 + lpmcfg.b.en_utmi_sleep = 1;
25906 + /* Program LPM config register */
25907 + dwc_write_reg32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
25909 + /* Send LPM transaction */
25910 + lpmcfg.b.send_lpm = 1;
25911 + dwc_write_reg32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
25916 +#endif /* CONFIG_USB_DWC_OTG_LPM */
25918 +int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
25923 + return -DWC_E_INVALID;
25926 + retval = (hcd->flags.b.port_connect_status_change ||
25927 + hcd->flags.b.port_reset_change ||
25928 + hcd->flags.b.port_enable_change ||
25929 + hcd->flags.b.port_suspend_change ||
25930 + hcd->flags.b.port_over_current_change);
25933 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
25934 + " Root port status changed\n");
25935 + DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n",
25936 + hcd->flags.b.port_connect_status_change);
25937 + DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n",
25938 + hcd->flags.b.port_reset_change);
25939 + DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n",
25940 + hcd->flags.b.port_enable_change);
25941 + DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n",
25942 + hcd->flags.b.port_suspend_change);
25943 + DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n",
25944 + hcd->flags.b.port_over_current_change);
25950 +int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
25952 + hfnum_data_t hfnum;
25953 + hfnum.d32 = dwc_read_reg32(&dwc_otg_hcd->core_if->
25954 + host_if->host_global_regs->hfnum);
25957 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
25960 + return hfnum.b.frnum;
25963 +int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
25964 + struct dwc_otg_hcd_function_ops *fops)
25968 + hcd->fops = fops;
25969 + if (!dwc_otg_is_device_mode(hcd->core_if)) {
25970 + dwc_otg_hcd_reinit(hcd);
25972 + retval = -DWC_E_NO_DEVICE;
25978 +void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
25980 + return hcd->priv;
25983 +void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
25985 + hcd->priv = priv_data;
25988 +uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
25990 + return hcd->otg_port;
25993 +uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
25995 + uint32_t is_b_host;
25996 + if (hcd->core_if->op_state == B_HOST) {
26002 + return is_b_host;
26005 +dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
26006 + int iso_desc_count, int atomic_alloc)
26008 + dwc_otg_hcd_urb_t *dwc_otg_urb;
26012 + sizeof(*dwc_otg_urb) +
26013 + iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
26014 + if (atomic_alloc) {
26015 + dwc_otg_urb = dwc_alloc_atomic(size);
26017 + dwc_otg_urb = dwc_alloc(size);
26019 + dwc_otg_urb->packet_count = iso_desc_count;
26021 + return dwc_otg_urb;
26024 +void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
26025 + uint8_t dev_addr, uint8_t ep_num,
26026 + uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
26028 + dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
26029 + ep_type, ep_dir, mps);
26032 + ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
26033 + dev_addr, ep_num, ep_dir, ep_type, mps);
26037 +void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
26038 + void *urb_handle, void *buf, dwc_dma_t dma,
26039 + uint32_t buflen, void *setup_packet,
26040 + dwc_dma_t setup_dma, uint32_t flags,
26041 + uint16_t interval)
26043 + dwc_otg_urb->priv = urb_handle;
26044 + dwc_otg_urb->buf = buf;
26045 + dwc_otg_urb->dma = dma;
26046 + dwc_otg_urb->length = buflen;
26047 + dwc_otg_urb->setup_packet = setup_packet;
26048 + dwc_otg_urb->setup_dma = setup_dma;
26049 + dwc_otg_urb->flags = flags;
26050 + dwc_otg_urb->interval = interval;
26051 + dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
26054 +uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
26056 + return dwc_otg_urb->status;
26059 +uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
26061 + return dwc_otg_urb->actual_length;
26064 +uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
26066 + return dwc_otg_urb->error_count;
26069 +void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
26070 + int desc_num, uint32_t offset,
26073 + dwc_otg_urb->iso_descs[desc_num].offset = offset;
26074 + dwc_otg_urb->iso_descs[desc_num].length = length;
26077 +uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
26080 + return dwc_otg_urb->iso_descs[desc_num].status;
26083 +uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
26084 + dwc_otg_urb, int desc_num)
26086 + return dwc_otg_urb->iso_descs[desc_num].actual_length;
26089 +int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
26091 + int allocated = 0;
26092 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
26095 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
26099 + return allocated;
26102 +int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
26104 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
26106 + DWC_ASSERT(qh, "qh is not allocated\n");
26108 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
26115 +uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
26117 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
26118 + DWC_ASSERT(qh, "qh is not allocated\n");
26119 + return qh->usecs;
26122 +void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
26125 + int num_channels;
26127 + gnptxsts_data_t np_tx_status;
26128 + hptxsts_data_t p_tx_status;
26130 + num_channels = hcd->core_if->core_params->host_channels;
26131 + DWC_PRINTF("\n");
26133 + ("************************************************************\n");
26134 + DWC_PRINTF("HCD State:\n");
26135 + DWC_PRINTF(" Num channels: %d\n", num_channels);
26136 + for (i = 0; i < num_channels; i++) {
26137 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
26138 + DWC_PRINTF(" Channel %d:\n", i);
26139 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
26140 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
26141 + DWC_PRINTF(" speed: %d\n", hc->speed);
26142 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
26143 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
26144 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
26145 + DWC_PRINTF(" multi_count: %d\n", hc->multi_count);
26146 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
26147 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
26148 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
26149 + DWC_PRINTF(" xfer_count: %d\n", hc->xfer_count);
26150 + DWC_PRINTF(" halt_on_queue: %d\n", hc->halt_on_queue);
26151 + DWC_PRINTF(" halt_pending: %d\n", hc->halt_pending);
26152 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
26153 + DWC_PRINTF(" do_split: %d\n", hc->do_split);
26154 + DWC_PRINTF(" complete_split: %d\n", hc->complete_split);
26155 + DWC_PRINTF(" hub_addr: %d\n", hc->hub_addr);
26156 + DWC_PRINTF(" port_addr: %d\n", hc->port_addr);
26157 + DWC_PRINTF(" xact_pos: %d\n", hc->xact_pos);
26158 + DWC_PRINTF(" requests: %d\n", hc->requests);
26159 + DWC_PRINTF(" qh: %p\n", hc->qh);
26160 + if (hc->xfer_started) {
26161 + hfnum_data_t hfnum;
26162 + hcchar_data_t hcchar;
26163 + hctsiz_data_t hctsiz;
26164 + hcint_data_t hcint;
26165 + hcintmsk_data_t hcintmsk;
26167 + dwc_read_reg32(&hcd->core_if->host_if->
26168 + host_global_regs->hfnum);
26170 + dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
26173 + dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
26176 + dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
26179 + dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
26181 + DWC_PRINTF(" hfnum: 0x%08x\n", hfnum.d32);
26182 + DWC_PRINTF(" hcchar: 0x%08x\n", hcchar.d32);
26183 + DWC_PRINTF(" hctsiz: 0x%08x\n", hctsiz.d32);
26184 + DWC_PRINTF(" hcint: 0x%08x\n", hcint.d32);
26185 + DWC_PRINTF(" hcintmsk: 0x%08x\n", hcintmsk.d32);
26187 + if (hc->xfer_started && hc->qh) {
26188 + dwc_otg_qtd_t *qtd;
26189 + dwc_otg_hcd_urb_t *urb;
26191 + DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
26192 + if(!qtd->in_process)
26196 + DWC_PRINTF(" URB Info:\n");
26197 + DWC_PRINTF(" qtd: %p, urb: %p\n", qtd, urb);
26199 + DWC_PRINTF(" Dev: %d, EP: %d %s\n",
26200 + dwc_otg_hcd_get_dev_addr(&urb->
26202 + dwc_otg_hcd_get_ep_num(&urb->
26204 + dwc_otg_hcd_is_pipe_in(&urb->
26207 + DWC_PRINTF(" Max packet size: %d\n",
26208 + dwc_otg_hcd_get_mps(&urb->
26210 + DWC_PRINTF(" transfer_buffer: %p\n",
26212 + DWC_PRINTF(" transfer_dma: %p\n",
26213 + (void *)urb->dma);
26214 + DWC_PRINTF(" transfer_buffer_length: %d\n",
26216 + DWC_PRINTF(" actual_length: %d\n",
26217 + urb->actual_length);
26222 + DWC_PRINTF(" non_periodic_channels: %d\n", hcd->non_periodic_channels);
26223 + DWC_PRINTF(" periodic_channels: %d\n", hcd->periodic_channels);
26224 + DWC_PRINTF(" periodic_usecs: %d\n", hcd->periodic_usecs);
26225 + np_tx_status.d32 =
26226 + dwc_read_reg32(&hcd->core_if->core_global_regs->gnptxsts);
26227 + DWC_PRINTF(" NP Tx Req Queue Space Avail: %d\n",
26228 + np_tx_status.b.nptxqspcavail);
26229 + DWC_PRINTF(" NP Tx FIFO Space Avail: %d\n",
26230 + np_tx_status.b.nptxfspcavail);
26231 + p_tx_status.d32 =
26232 + dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hptxsts);
26233 + DWC_PRINTF(" P Tx Req Queue Space Avail: %d\n",
26234 + p_tx_status.b.ptxqspcavail);
26235 + DWC_PRINTF(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
26236 + dwc_otg_hcd_dump_frrem(hcd);
26237 + dwc_otg_dump_global_registers(hcd->core_if);
26238 + dwc_otg_dump_host_registers(hcd->core_if);
26240 + ("************************************************************\n");
26241 + DWC_PRINTF("\n");
26246 +void dwc_print_setup_data(uint8_t * setup)
26249 + if (CHK_DEBUG_LEVEL(DBG_HCD)) {
26250 + DWC_PRINTF("Setup Data = MSB ");
26251 + for (i = 7; i >= 0; i--)
26252 + DWC_PRINTF("%02x ", setup[i]);
26253 + DWC_PRINTF("\n");
26254 + DWC_PRINTF(" bmRequestType Tranfer = %s\n",
26255 + (setup[0] & 0x80) ? "Device-to-Host" :
26256 + "Host-to-Device");
26257 + DWC_PRINTF(" bmRequestType Type = ");
26258 + switch ((setup[0] & 0x60) >> 5) {
26260 + DWC_PRINTF("Standard\n");
26263 + DWC_PRINTF("Class\n");
26266 + DWC_PRINTF("Vendor\n");
26269 + DWC_PRINTF("Reserved\n");
26272 + DWC_PRINTF(" bmRequestType Recipient = ");
26273 + switch (setup[0] & 0x1f) {
26275 + DWC_PRINTF("Device\n");
26278 + DWC_PRINTF("Interface\n");
26281 + DWC_PRINTF("Endpoint\n");
26284 + DWC_PRINTF("Other\n");
26287 + DWC_PRINTF("Reserved\n");
26290 + DWC_PRINTF(" bRequest = 0x%0x\n", setup[1]);
26291 + DWC_PRINTF(" wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
26292 + DWC_PRINTF(" wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
26293 + DWC_PRINTF(" wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
26298 +void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
26301 + DWC_PRINTF("Frame remaining at SOF:\n");
26302 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
26303 + hcd->frrem_samples, hcd->frrem_accum,
26304 + (hcd->frrem_samples > 0) ?
26305 + hcd->frrem_accum / hcd->frrem_samples : 0);
26307 + DWC_PRINTF("\n");
26308 + DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
26309 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
26310 + hcd->core_if->hfnum_7_samples,
26311 + hcd->core_if->hfnum_7_frrem_accum,
26312 + (hcd->core_if->hfnum_7_samples >
26313 + 0) ? hcd->core_if->hfnum_7_frrem_accum /
26314 + hcd->core_if->hfnum_7_samples : 0);
26315 + DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
26316 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
26317 + hcd->core_if->hfnum_0_samples,
26318 + hcd->core_if->hfnum_0_frrem_accum,
26319 + (hcd->core_if->hfnum_0_samples >
26320 + 0) ? hcd->core_if->hfnum_0_frrem_accum /
26321 + hcd->core_if->hfnum_0_samples : 0);
26322 + DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
26323 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
26324 + hcd->core_if->hfnum_other_samples,
26325 + hcd->core_if->hfnum_other_frrem_accum,
26326 + (hcd->core_if->hfnum_other_samples >
26327 + 0) ? hcd->core_if->hfnum_other_frrem_accum /
26328 + hcd->core_if->hfnum_other_samples : 0);
26330 + DWC_PRINTF("\n");
26331 + DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
26332 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
26333 + hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
26334 + (hcd->hfnum_7_samples_a > 0) ?
26335 + hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
26336 + DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
26337 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
26338 + hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
26339 + (hcd->hfnum_0_samples_a > 0) ?
26340 + hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
26341 + DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
26342 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
26343 + hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
26344 + (hcd->hfnum_other_samples_a > 0) ?
26345 + hcd->hfnum_other_frrem_accum_a /
26346 + hcd->hfnum_other_samples_a : 0);
26348 + DWC_PRINTF("\n");
26349 + DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
26350 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
26351 + hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
26352 + (hcd->hfnum_7_samples_b > 0) ?
26353 + hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
26354 + DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
26355 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
26356 + hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
26357 + (hcd->hfnum_0_samples_b > 0) ?
26358 + hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
26359 + DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
26360 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
26361 + hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
26362 + (hcd->hfnum_other_samples_b > 0) ?
26363 + hcd->hfnum_other_frrem_accum_b /
26364 + hcd->hfnum_other_samples_b : 0);
26368 +#endif /* DWC_DEVICE_ONLY */
26370 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
26372 +/* ==========================================================================
26373 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $
26374 + * $Revision: #52 $
26375 + * $Date: 2009/04/21 $
26376 + * $Change: 1237472 $
26378 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
26379 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
26380 + * otherwise expressly agreed to in writing between Synopsys and you.
26382 + * The Software IS NOT an item of Licensed Software or Licensed Product under
26383 + * any End User Software License Agreement or Agreement for Licensed Product
26384 + * with Synopsys or any supplement thereto. You are permitted to use and
26385 + * redistribute this Software in source and binary forms, with or without
26386 + * modification, provided that redistributions of source code must retain this
26387 + * notice. You may not view, use, disclose, copy or distribute this file or
26388 + * any information contained herein except pursuant to this license grant from
26389 + * Synopsys. If you do not agree with this notice, including the disclaimer
26390 + * below, then you are not authorized to use the Software.
26392 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
26393 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26394 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26395 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
26396 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26397 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26398 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26399 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26400 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26401 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26403 + * ========================================================================== */
26404 +#ifndef DWC_DEVICE_ONLY
26405 +#ifndef __DWC_HCD_H__
26406 +#define __DWC_HCD_H__
26409 +#include "dwc_otg_hcd_if.h"
26410 +#include "dwc_otg_core_if.h"
26411 +#include "dwc_list.h"
26412 +#include "dwc_otg_cil.h"
26417 + * This file contains the structures, constants, and interfaces for
26418 + * the Host Contoller Driver (HCD).
26420 + * The Host Controller Driver (HCD) is responsible for translating requests
26421 + * from the USB Driver into the appropriate actions on the DWC_otg controller.
26422 + * It isolates the USBD from the specifics of the controller by providing an
26423 + * API to the USBD.
26426 +struct dwc_otg_hcd_pipe_info {
26427 + uint8_t dev_addr;
26429 + uint8_t pipe_type;
26430 + uint8_t pipe_dir;
26434 +struct dwc_otg_hcd_iso_packet_desc {
26437 + uint32_t actual_length;
26441 +struct dwc_otg_qtd;
26443 +struct dwc_otg_hcd_urb {
26445 + struct dwc_otg_qtd *qtd;
26448 + void *setup_packet;
26449 + dwc_dma_t setup_dma;
26451 + uint32_t actual_length;
26453 + uint32_t error_count;
26454 + uint32_t packet_count;
26456 + uint16_t interval;
26457 + struct dwc_otg_hcd_pipe_info pipe_info;
26458 + struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
26461 +static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
26463 + return pipe->ep_num;
26466 +static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info
26469 + return pipe->pipe_type;
26472 +static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe)
26474 + return pipe->mps;
26477 +static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info
26480 + return pipe->dev_addr;
26483 +static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info
26486 + return (pipe->pipe_type == UE_ISOCHRONOUS);
26489 +static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info
26492 + return (pipe->pipe_type == UE_INTERRUPT);
26495 +static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info
26498 + return (pipe->pipe_type == UE_BULK);
26501 +static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info
26504 + return (pipe->pipe_type == UE_CONTROL);
26507 +static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe)
26509 + return (pipe->pipe_dir == UE_DIR_IN);
26512 +static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info
26515 + return (!dwc_otg_hcd_is_pipe_in(pipe));
26518 +static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe,
26519 + uint8_t devaddr, uint8_t ep_num,
26520 + uint8_t pipe_type, uint8_t pipe_dir,
26523 + pipe->dev_addr = devaddr;
26524 + pipe->ep_num = ep_num;
26525 + pipe->pipe_type = pipe_type;
26526 + pipe->pipe_dir = pipe_dir;
26531 + * Phases for control transfers.
26533 +typedef enum dwc_otg_control_phase {
26534 + DWC_OTG_CONTROL_SETUP,
26535 + DWC_OTG_CONTROL_DATA,
26536 + DWC_OTG_CONTROL_STATUS
26537 +} dwc_otg_control_phase_e;
26539 +/** Transaction types. */
26540 +typedef enum dwc_otg_transaction_type {
26541 + DWC_OTG_TRANSACTION_NONE,
26542 + DWC_OTG_TRANSACTION_PERIODIC,
26543 + DWC_OTG_TRANSACTION_NON_PERIODIC,
26544 + DWC_OTG_TRANSACTION_ALL
26545 +} dwc_otg_transaction_type_e;
26547 +struct dwc_otg_qh;
26550 + * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
26551 + * interrupt, or isochronous transfer. A single QTD is created for each URB
26552 + * (of one of these types) submitted to the HCD. The transfer associated with
26553 + * a QTD may require one or multiple transactions.
26555 + * A QTD is linked to a Queue Head, which is entered in either the
26556 + * non-periodic or periodic schedule for execution. When a QTD is chosen for
26557 + * execution, some or all of its transactions may be executed. After
26558 + * execution, the state of the QTD is updated. The QTD may be retired if all
26559 + * its transactions are complete or if an error occurred. Otherwise, it
26560 + * remains in the schedule so more transactions can be executed later.
26562 +typedef struct dwc_otg_qtd {
26564 + * Determines the PID of the next data packet for the data phase of
26565 + * control transfers. Ignored for other transfer types.<br>
26566 + * One of the following values:
26567 + * - DWC_OTG_HC_PID_DATA0
26568 + * - DWC_OTG_HC_PID_DATA1
26570 + uint8_t data_toggle;
26572 + /** Current phase for control transfers (Setup, Data, or Status). */
26573 + dwc_otg_control_phase_e control_phase;
26575 + /** Keep track of the current split type
26576 + * for FS/LS endpoints on a HS Hub */
26577 + uint8_t complete_split;
26579 + /** How many bytes transferred during SSPLIT OUT */
26580 + uint32_t ssplit_out_xfer_count;
26583 + * Holds the number of bus errors that have occurred for a transaction
26584 + * within this transfer.
26586 + uint8_t error_count;
26589 + * Index of the next frame descriptor for an isochronous transfer. A
26590 + * frame descriptor describes the buffer position and length of the
26591 + * data to be transferred in the next scheduled (micro)frame of an
26592 + * isochronous transfer. It also holds status for that transaction.
26593 + * The frame index starts at 0.
26595 + uint16_t isoc_frame_index;
26597 + /** Position of the ISOC split on full/low speed */
26598 + uint8_t isoc_split_pos;
26600 + /** Position of the ISOC split in the buffer for the current frame */
26601 + uint16_t isoc_split_offset;
26603 + /** URB for this transfer */
26604 + struct dwc_otg_hcd_urb *urb;
26606 + struct dwc_otg_qh *qh;
26608 + /** This list of QTDs */
26609 + DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry;
26611 + /** Indicates if this QTD is currently processed by HW. */
26612 + uint8_t in_process;
26614 + /** Number of DMA descriptors for this QTD */
26618 + * Last activated frame(packet) index.
26619 + * Used in Descriptor DMA mode only.
26621 + uint16_t isoc_frame_index_last;
26625 +DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd);
26628 + * A Queue Head (QH) holds the static characteristics of an endpoint and
26629 + * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
26630 + * be entered in either the non-periodic or periodic schedule.
26632 +typedef struct dwc_otg_qh {
26635 + * One of the following values:
26639 + * - UE_ISOCHRONOUS
26642 + uint8_t ep_is_in;
26644 + /** wMaxPacketSize Field of Endpoint Descriptor. */
26649 + * One of the following values:
26650 + * - DWC_OTG_EP_SPEED_LOW
26651 + * - DWC_OTG_EP_SPEED_FULL
26652 + * - DWC_OTG_EP_SPEED_HIGH
26654 + uint8_t dev_speed;
26657 + * Determines the PID of the next data packet for non-control
26658 + * transfers. Ignored for control transfers.<br>
26659 + * One of the following values:
26660 + * - DWC_OTG_HC_PID_DATA0
26661 + * - DWC_OTG_HC_PID_DATA1
26663 + uint8_t data_toggle;
26665 + /** Ping state if 1. */
26666 + uint8_t ping_state;
26669 + * List of QTDs for this QH.
26671 + struct dwc_otg_qtd_list qtd_list;
26673 + /** Host channel currently processing transfers for this QH. */
26674 + struct dwc_hc *channel;
26676 + /** Full/low speed endpoint on high-speed hub requires split. */
26677 + uint8_t do_split;
26679 + /** @name Periodic schedule information */
26682 + /** Bandwidth in microseconds per (micro)frame. */
26685 + /** Interval between transfers in (micro)frames. */
26686 + uint16_t interval;
26689 + * (micro)frame to initialize a periodic transfer. The transfer
26690 + * executes in the following (micro)frame.
26692 + uint16_t sched_frame;
26694 + /** (micro)frame at which last start split was initialized. */
26695 + uint16_t start_split_frame;
26700 + * Used instead of original buffer if
26701 + * it(physical address) is not dword-aligned.
26703 + uint8_t *dw_align_buf;
26704 + dwc_dma_t dw_align_buf_dma;
26706 + /** Entry for QH in either the periodic or non-periodic schedule. */
26707 + dwc_list_link_t qh_list_entry;
26709 + /** @name Descriptor DMA support */
26712 + /** Descriptor List. */
26713 + dwc_otg_host_dma_desc_t *desc_list;
26715 + /** Descriptor List physical address. */
26716 + dwc_dma_t desc_list_dma;
26719 + * Xfer Bytes array.
26720 + * Each element corresponds to a descriptor and indicates
26721 + * original XferSize size value for the descriptor.
26723 + uint32_t *n_bytes;
26725 + /** Actual number of transfer descriptors in a list. */
26728 + /** First activated isochronous transfer descriptor index. */
26729 + uint8_t td_first;
26730 + /** Last activated isochronous transfer descriptor index. */
26737 +DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
26739 +#ifdef HW2937_WORKAROUND
26742 + HW2937_XFER_MODE_IDLE,
26743 + HW2937_XFER_MODE_IN,
26744 + HW2937_XFER_MODE_OUT,
26745 + HW2937_XFER_MODE_PAUSEIN /* Transitioning from IN to IDLE */
26746 +} hw2937_xfer_mode_t;
26750 + * This structure holds the state of the HCD, including the non-periodic and
26751 + * periodic schedules.
26753 +struct dwc_otg_hcd {
26754 + /** DWC OTG Core Interface Layer */
26755 + dwc_otg_core_if_t *core_if;
26757 + /** Function HCD driver callbacks */
26758 + struct dwc_otg_hcd_function_ops *fops;
26760 + /** Internal DWC HCD Flags */
26761 + volatile union dwc_otg_hcd_internal_flags {
26764 + unsigned port_connect_status_change:1;
26765 + unsigned port_connect_status:1;
26766 + unsigned port_reset_change:1;
26767 + unsigned port_enable_change:1;
26768 + unsigned port_suspend_change:1;
26769 + unsigned port_over_current_change:1;
26770 + unsigned port_l1_change:1;
26771 + unsigned reserved:26;
26776 + * Inactive items in the non-periodic schedule. This is a list of
26777 + * Queue Heads. Transfers associated with these Queue Heads are not
26778 + * currently assigned to a host channel.
26780 + dwc_list_link_t non_periodic_sched_inactive;
26783 + * Active items in the non-periodic schedule. This is a list of
26784 + * Queue Heads. Transfers associated with these Queue Heads are
26785 + * currently assigned to a host channel.
26787 + dwc_list_link_t non_periodic_sched_active;
26790 + * Pointer to the next Queue Head to process in the active
26791 + * non-periodic schedule.
26793 + dwc_list_link_t *non_periodic_qh_ptr;
26796 + * Inactive items in the periodic schedule. This is a list of QHs for
26797 + * periodic transfers that are _not_ scheduled for the next frame.
26798 + * Each QH in the list has an interval counter that determines when it
26799 + * needs to be scheduled for execution. This scheduling mechanism
26800 + * allows only a simple calculation for periodic bandwidth used (i.e.
26801 + * must assume that all periodic transfers may need to execute in the
26802 + * same frame). However, it greatly simplifies scheduling and should
26803 + * be sufficient for the vast majority of OTG hosts, which need to
26804 + * connect to a small number of peripherals at one time.
26806 + * Items move from this list to periodic_sched_ready when the QH
26807 + * interval counter is 0 at SOF.
26809 + dwc_list_link_t periodic_sched_inactive;
26812 + * List of periodic QHs that are ready for execution in the next
26813 + * frame, but have not yet been assigned to host channels.
26815 + * Items move from this list to periodic_sched_assigned as host
26816 + * channels become available during the current frame.
26818 + dwc_list_link_t periodic_sched_ready;
26821 + * List of periodic QHs to be executed in the next frame that are
26822 + * assigned to host channels.
26824 + * Items move from this list to periodic_sched_queued as the
26825 + * transactions for the QH are queued to the DWC_otg controller.
26827 + dwc_list_link_t periodic_sched_assigned;
26830 + * List of periodic QHs that have been queued for execution.
26832 + * Items move from this list to either periodic_sched_inactive or
26833 + * periodic_sched_ready when the channel associated with the transfer
26834 + * is released. If the interval for the QH is 1, the item moves to
26835 + * periodic_sched_ready because it must be rescheduled for the next
26836 + * frame. Otherwise, the item moves to periodic_sched_inactive.
26838 + dwc_list_link_t periodic_sched_queued;
26841 + * Total bandwidth claimed so far for periodic transfers. This value
26842 + * is in microseconds per (micro)frame. The assumption is that all
26843 + * periodic transfers may occur in the same (micro)frame.
26845 + uint16_t periodic_usecs;
26848 + * Frame number read from the core at SOF. The value ranges from 0 to
26849 + * DWC_HFNUM_MAX_FRNUM.
26851 + uint16_t frame_number;
26854 + * Free host channels in the controller. This is a list of
26855 + * dwc_hc_t items.
26857 + struct hc_list free_hc_list;
26859 + * Number of host channels assigned to periodic transfers. Currently
26860 + * assuming that there is a dedicated host channel for each periodic
26861 + * transaction and at least one host channel available for
26862 + * non-periodic transactions.
26864 + int periodic_channels;
26867 + * Number of host channels assigned to non-periodic transfers.
26869 + int non_periodic_channels;
26872 + * Array of pointers to the host channel descriptors. Allows accessing
26873 + * a host channel descriptor given the host channel number. This is
26874 + * useful in interrupt handlers.
26876 + struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
26879 + * Buffer to use for any data received during the status phase of a
26880 + * control transfer. Normally no data is transferred during the status
26881 + * phase. This buffer is used as a bit bucket.
26883 + uint8_t *status_buf;
26886 + * DMA address for status_buf.
26888 + dma_addr_t status_buf_dma;
26889 +#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
26892 + * Connection timer. An OTG host must display a message if the device
26893 + * does not connect. Started when the VBus power is turned on via
26894 + * sysfs attribute "buspower".
26896 + dwc_timer_t *conn_timer;
26898 + /* Tasket to do a reset */
26899 + dwc_tasklet_t *reset_tasklet;
26902 + dwc_spinlock_t *lock;
26905 + * Private data that could be used by OS wrapper.
26909 + uint8_t otg_port;
26911 + /** Frame List */
26912 + uint32_t *frame_list;
26914 + /** Frame List DMA address */
26915 + dma_addr_t frame_list_dma;
26917 +#ifdef HW2937_WORKAROUND
26918 + /** Current transfer mode (IN, OUT, or IDLE) */
26919 + hw2937_xfer_mode_t hw2937_xfer_mode;
26921 + /** Mask of channels assigned to the current mode */
26922 + uint32_t hw2937_assigned_channels;
26926 + uint32_t frrem_samples;
26927 + uint64_t frrem_accum;
26929 + uint32_t hfnum_7_samples_a;
26930 + uint64_t hfnum_7_frrem_accum_a;
26931 + uint32_t hfnum_0_samples_a;
26932 + uint64_t hfnum_0_frrem_accum_a;
26933 + uint32_t hfnum_other_samples_a;
26934 + uint64_t hfnum_other_frrem_accum_a;
26936 + uint32_t hfnum_7_samples_b;
26937 + uint64_t hfnum_7_frrem_accum_b;
26938 + uint32_t hfnum_0_samples_b;
26939 + uint64_t hfnum_0_frrem_accum_b;
26940 + uint32_t hfnum_other_samples_b;
26941 + uint64_t hfnum_other_frrem_accum_b;
26945 +/** @name Transaction Execution Functions */
26947 +extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
26949 +extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
26950 + dwc_otg_transaction_type_e tr_type);
26954 +/** @name Interrupt Handler Functions */
26956 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
26957 +extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd);
26958 +extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t *
26960 +extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t *
26962 +extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t *
26964 +extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *
26966 +extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd);
26967 +extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t *
26969 +extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd);
26970 +extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd);
26971 +extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd,
26973 +extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd);
26974 +extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t *
26978 +/** @name Schedule Queue Functions */
26981 +/* Implemented in dwc_otg_hcd_queue.c */
26982 +extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
26983 + dwc_otg_hcd_urb_t * urb);
26984 +extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
26985 +extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
26986 +extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
26987 +extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
26988 + int sched_csplit);
26990 +/** Remove and free a QH */
26991 +static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd,
26992 + dwc_otg_qh_t * qh)
26994 + dwc_otg_hcd_qh_remove(hcd, qh);
26995 + dwc_otg_hcd_qh_free(hcd, qh);
26998 +/** Allocates memory for a QH structure.
26999 + * @return Returns the memory allocate or NULL on error. */
27000 +static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(void)
27002 + return (dwc_otg_qh_t *) dwc_alloc(sizeof(dwc_otg_qh_t));
27005 +extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb);
27006 +extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb);
27007 +extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd,
27008 + dwc_otg_qh_t ** qh);
27010 +/** Allocates memory for a QTD structure.
27011 + * @return Returns the memory allocate or NULL on error. */
27012 +static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(void)
27014 + return (dwc_otg_qtd_t *) dwc_alloc(sizeof(dwc_otg_qtd_t));
27017 +/** Frees the memory for a QTD structure. QTD should already be removed from
27019 + * @param qtd QTD to free.*/
27020 +static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd)
27025 +/** Removes a QTD from list.
27026 + * @param hcd HCD instance.
27027 + * @param qtd QTD to remove from list.
27028 + * @param qh QTD belongs to.
27030 +static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd,
27031 + dwc_otg_qtd_t * qtd,
27032 + dwc_otg_qh_t * qh)
27035 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
27036 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
27037 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
27040 +/** Remove and free a QTD */
27041 +static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd,
27042 + dwc_otg_qtd_t * qtd,
27043 + dwc_otg_qh_t * qh)
27045 + dwc_otg_hcd_qtd_remove(hcd, qtd, qh);
27046 + dwc_otg_hcd_qtd_free(qtd);
27051 +/** @name Descriptor DMA Supporting Functions */
27054 +extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
27055 +extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
27057 + dwc_otg_hc_regs_t * hc_regs,
27058 + dwc_otg_halt_status_e halt_status);
27060 +extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
27061 +extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
27065 +/** @name Internal Functions */
27067 +dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb);
27070 +#ifdef CONFIG_USB_DWC_OTG_LPM
27071 +extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd,
27072 + uint8_t devaddr);
27073 +extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd);
27076 +/** Gets the QH that contains the list_head */
27077 +#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
27079 +/** Gets the QTD that contains the list_head */
27080 +#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
27082 +/** Check if QH is non-periodic */
27083 +#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \
27084 + (_qh_ptr_->ep_type == UE_CONTROL))
27086 +/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
27087 +#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
27089 +/** Packet size for any kind of endpoint descriptor */
27090 +#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
27093 + * Returns true if _frame1 is less than or equal to _frame2. The comparison is
27094 + * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
27095 + * frame number when the max frame number is reached.
27097 +static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
27099 + return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
27100 + (DWC_HFNUM_MAX_FRNUM >> 1);
27104 + * Returns true if _frame1 is greater than _frame2. The comparison is done
27105 + * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
27106 + * number when the max frame number is reached.
27108 +static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
27110 + return (frame1 != frame2) &&
27111 + (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
27112 + (DWC_HFNUM_MAX_FRNUM >> 1));
27116 + * Increments _frame by the amount specified by _inc. The addition is done
27117 + * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
27119 +static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
27121 + return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
27124 +static inline uint16_t dwc_full_frame_num(uint16_t frame)
27126 + return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
27129 +static inline uint16_t dwc_micro_frame_num(uint16_t frame)
27131 + return frame & 0x7;
27134 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
27135 + dwc_otg_hc_regs_t * hc_regs,
27136 + dwc_otg_qtd_t * qtd);
27140 + * Macro to sample the remaining PHY clocks left in the current frame. This
27141 + * may be used during debugging to determine the average time it takes to
27142 + * execute sections of code. There are two possible sample points, "a" and
27143 + * "b", so the _letter argument must be one of these values.
27145 + * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
27146 + * example, "cat /sys/devices/lm0/hcd_frrem".
27148 +#define dwc_sample_frrem(_hcd, _qh, _letter) \
27150 + hfnum_data_t hfnum; \
27151 + dwc_otg_qtd_t *qtd; \
27152 + qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
27153 + if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
27154 + hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
27155 + switch (hfnum.b.frnum & 0x7) { \
27157 + _hcd->hfnum_7_samples_##_letter++; \
27158 + _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
27161 + _hcd->hfnum_0_samples_##_letter++; \
27162 + _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
27165 + _hcd->hfnum_other_samples_##_letter++; \
27166 + _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
27172 +#define dwc_sample_frrem(_hcd, _qh, _letter)
27175 +#endif /* DWC_DEVICE_ONLY */
27177 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
27179 +/*==========================================================================
27180 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
27181 + * $Revision: #2 $
27182 + * $Date: 2009/04/21 $
27183 + * $Change: 1237473 $
27185 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
27186 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
27187 + * otherwise expressly agreed to in writing between Synopsys and you.
27189 + * The Software IS NOT an item of Licensed Software or Licensed Product under
27190 + * any End User Software License Agreement or Agreement for Licensed Product
27191 + * with Synopsys or any supplement thereto. You are permitted to use and
27192 + * redistribute this Software in source and binary forms, with or without
27193 + * modification, provided that redistributions of source code must retain this
27194 + * notice. You may not view, use, disclose, copy or distribute this file or
27195 + * any information contained herein except pursuant to this license grant from
27196 + * Synopsys. If you do not agree with this notice, including the disclaimer
27197 + * below, then you are not authorized to use the Software.
27199 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
27200 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27201 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27202 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
27203 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27204 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27205 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27206 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27207 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27208 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27210 + * ========================================================================== */
27211 +#ifndef DWC_DEVICE_ONLY
27214 + * This file contains Descriptor DMA support implementation for host mode.
27217 +#include "dwc_otg_hcd.h"
27218 +#include "dwc_otg_regs.h"
27221 +static inline uint8_t frame_list_idx(uint16_t frame)
27223 + return (frame & (MAX_FRLIST_EN_NUM - 1));
27226 +static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
27228 + return (idx + inc) &
27229 + (((speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC) - 1);
27232 +static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
27234 + return (idx - inc) &
27235 + (((speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC) - 1);
27238 +static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
27240 + return (((qh->ep_type == UE_ISOCHRONOUS) && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH))
27242 + MAX_DMA_DESC_NUM_HS_ISOC
27244 + MAX_DMA_DESC_NUM_GENERIC);
27246 +static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
27248 + return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)
27249 + ? ((qh->interval + 8 - 1) / 8)
27254 +static int desc_list_alloc(dwc_otg_qh_t * qh)
27258 + qh->desc_list = (dwc_otg_host_dma_desc_t *)
27259 + dwc_dma_alloc(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
27260 + &qh->desc_list_dma
27263 + if (!qh->desc_list) {
27264 + retval = -DWC_E_NO_MEMORY;
27265 + DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
27269 + dwc_memset(qh->desc_list, 0x00, sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
27272 + qh->n_bytes = (uint32_t *) dwc_alloc(sizeof(uint32_t) * max_desc_num(qh));
27274 + if (!qh->n_bytes) {
27275 + retval = -DWC_E_NO_MEMORY;
27276 + DWC_ERROR("%s: Failed to allocate array for descriptors' size actual values\n",
27284 +static void desc_list_free(dwc_otg_qh_t * qh)
27286 + if(qh->desc_list) {
27287 + dwc_dma_free(max_desc_num(qh), qh->desc_list, qh->desc_list_dma);
27288 + qh->desc_list = NULL;
27291 + if (qh->n_bytes) {
27292 + dwc_free(qh->n_bytes);
27293 + qh->n_bytes = NULL;
27297 +static int frame_list_alloc(dwc_otg_hcd_t * hcd)
27300 + if (hcd->frame_list)
27303 + hcd->frame_list = dwc_dma_alloc(4 * MAX_FRLIST_EN_NUM,
27304 + &hcd->frame_list_dma
27306 + if (!hcd->frame_list) {
27307 + retval = -DWC_E_NO_MEMORY;
27308 + DWC_ERROR("%s: Frame List allocation failed\n", __func__);
27311 + dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
27316 +static void frame_list_free(dwc_otg_hcd_t * hcd)
27318 + if (!hcd->frame_list)
27321 + dwc_dma_free(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
27322 + hcd->frame_list = NULL;
27325 +static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
27328 + hcfg_data_t hcfg;
27330 + hcfg.d32 = dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hcfg);
27332 + if (hcfg.b.perschedstat) {
27333 + /* already enabled*/
27337 + dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hflbaddr, hcd->frame_list_dma);
27339 + switch(fr_list_en) {
27341 + hcfg.b.frlisten = 3;
27344 + hcfg.b.frlisten = 2;
27347 + hcfg.b.frlisten = 1;
27349 + hcfg.b.frlisten = 0;
27354 + hcfg.b.perschedena = 1;
27356 + DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
27357 + dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
27361 +static void per_sched_disable(dwc_otg_hcd_t * hcd)
27363 + hcfg_data_t hcfg;
27365 + hcfg.d32 = dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hcfg);
27367 + if (!hcfg.b.perschedstat) {
27368 + /* already disabled */
27371 + hcfg.b.perschedena = 0;
27373 + DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
27374 + dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
27378 + * Activates/Deactivates FrameList entries for the channel
27379 + * based on endpoint servicing period.
27381 +void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
27383 + uint16_t i, j, inc;
27384 + dwc_hc_t *hc = qh->channel;
27386 + inc = frame_incr_val(qh);
27388 + if (qh->ep_type == UE_ISOCHRONOUS)
27389 + i = frame_list_idx(qh->sched_frame);
27396 + hcd->frame_list[j] |= (1 << hc->hc_num);
27398 + hcd->frame_list[j] &= ~(1 << hc->hc_num);
27399 + j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
27407 + if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
27409 + for (i = 0 ; i < 8 / qh->interval; i++) {
27410 + hc->schinfo |= j;
27411 + j = j << qh->interval;
27415 + hc->schinfo = 0xff;
27419 +void dump_frame_list(dwc_otg_hcd_t * hcd)
27422 + DWC_PRINTF("--FRAME LIST (hex) --\n");
27423 + for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
27424 + DWC_PRINTF("%x\t",hcd->frame_list[i]);
27425 + if (!(i % 8) && i)
27426 + DWC_PRINTF("\n");
27428 + DWC_PRINTF("\n----\n");
27433 +static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
27435 + dwc_hc_t *hc = qh->channel;
27436 + if (dwc_qh_is_non_per(qh)) {
27437 + hcd->non_periodic_channels--;
27440 + update_frame_list(hcd, qh, 0);
27443 + * The condition is added to prevent double cleanup try in case of device
27444 + * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
27447 + dwc_otg_hc_cleanup(hcd->core_if, hc);
27448 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
27452 + qh->channel = NULL;
27455 + if (qh->desc_list) {
27456 + dwc_memset(qh->desc_list, 0x00,
27457 + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
27462 + * Initializes a QH structure's Descriptor DMA related members.
27463 + * Allocates memory for descriptor list.
27464 + * On first periodic QH, allocates memory for FrameList
27465 + * and enables periodic scheduling.
27467 + * @param hcd The HCD state structure for the DWC OTG controller.
27468 + * @param qh The QH to init.
27470 + * @return 0 if successful, negative error code otherwise.
27472 +int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
27476 + if (qh->do_split) {
27477 + DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
27481 + retval = desc_list_alloc(qh);
27483 + if ((retval == 0) && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
27484 + if(!hcd->frame_list) {
27485 + retval = frame_list_alloc(hcd);
27486 + /* Enable periodic schedule on first periodic QH */
27488 + per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
27498 + * Frees descriptor list memory associated with the QH.
27499 + * If QH is periodic and the last, frees FrameList memory
27500 + * and disables periodic scheduling.
27502 + * @param hcd The HCD state structure for the DWC OTG controller.
27503 + * @param qh The QH to init.
27505 +void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
27507 + desc_list_free(qh);
27510 + * Channel still assigned due to some reasons.
27511 + * Seen on Isoc URB dequeue. Channel halted but no subsequent
27512 + * ChHalted interrupt to release the channel. Afterwards
27513 + * when it comes here from endpoint disable routine
27514 + * channel remains assigned.
27517 + release_channel_ddma(hcd, qh);
27519 + if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
27520 + && !hcd->periodic_channels && hcd->frame_list) {
27522 + per_sched_disable(hcd);
27523 + frame_list_free(hcd);
27527 +static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
27529 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
27531 + * Descriptor set(8 descriptors) index
27532 + * which is 8-aligned.
27534 + return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
27537 + return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
27542 + * Determine starting frame for Isochronous transfer.
27543 + * Few frames skipped to prevent race condition with HC.
27545 +static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t* skip_frames)
27547 + uint16_t frame = 0;
27548 + hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
27550 + /* sched_frame is always frame number(not uFrame) both in FS and HS !! */
27553 + * skip_frames is used to limit activated descriptors number
27554 + * to avoid the situation when HC services the last activated
27555 + * descriptor firstly.
27556 + * Example for FS:
27557 + * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
27558 + * corresponding to curr_frame+1, the descriptor corresponding to frame 2
27559 + * will be fetched. If the number of descriptors is max=64 (or greather) the list will
27560 + * be fully programmed with Active descriptors and it is possible case(rare) that the latest
27561 + * descriptor(considering rollback) corresponding to frame 2 will be serviced first.
27562 + * HS case is more probable because, in fact, up to 11 uframes(16 in the code)
27563 + * may be skipped.
27565 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
27567 + * Consider uframe counter also, to start xfer asap.
27568 + * If half of the frame elapsed skip 2 frames otherwise
27570 + * Starting descriptor index must be 8-aligned, so
27571 + * if the current frame is near to complete the next one
27572 + * is skipped as well.
27575 + if (dwc_micro_frame_num(hcd->frame_number) >= 5) {
27576 + *skip_frames = 2 * 8;
27577 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
27580 + *skip_frames = 1 * 8;
27581 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
27584 + frame = dwc_full_frame_num(frame);
27587 + * Two frames are skipped for FS - the current and the next.
27588 + * But for descriptor programming, 1 frame(descriptor) is enough,
27589 + * see example above.
27591 + *skip_frames = 1;
27592 + frame = dwc_frame_num_inc(hcd->frame_number, 2);
27598 + * Calculate initial descriptor index for isochronous transfer
27599 + * based on scheduled frame.
27601 +static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
27603 + uint16_t frame = 0, fr_idx, fr_idx_tmp;
27604 + uint8_t skip_frames = 0 ;
27606 + * With current ISOC processing algorithm the channel is being
27607 + * released when no more QTDs in the list(qh->ntd == 0).
27608 + * Thus this function is called only when qh->ntd == 0 and qh->channel == 0.
27610 + * So qh->channel != NULL branch is not used and just not removed from the
27611 + * source file. It is required for another possible approach which is,
27612 + * do not disable and release the channel when ISOC session completed,
27613 + * just move QH to inactive schedule until new QTD arrives.
27614 + * On new QTD, the QH moved back to 'ready' schedule,
27615 + * starting frame and therefore starting desc_index are recalculated.
27616 + * In this case channel is released only on ep_disable.
27619 + /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
27620 + if (qh->channel) {
27621 + frame = calc_starting_frame(hcd, qh, &skip_frames);
27623 + * Calculate initial descriptor index based on FrameList current bitmap
27624 + * and servicing period.
27626 + fr_idx_tmp = frame_list_idx(frame);
27627 + fr_idx = (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) - fr_idx_tmp)
27628 + % frame_incr_val(qh);
27629 + fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
27632 + qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);
27633 + fr_idx = frame_list_idx(qh->sched_frame);
27636 + qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx);
27638 + return skip_frames;
27641 +#define ISOC_URB_GIVEBACK_ASAP
27643 +#define MAX_ISOC_XFER_SIZE_FS 1023
27644 +#define MAX_ISOC_XFER_SIZE_HS 3072
27645 +#define DESCNUM_THRESHOLD 4
27647 +static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t skip_frames)
27649 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
27650 + dwc_otg_qtd_t *qtd;
27651 + dwc_otg_host_dma_desc_t *dma_desc;
27652 + uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
27654 + idx = qh->td_last;
27655 + inc = qh->interval;
27658 + ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
27659 + if (skip_frames && !qh->channel)
27660 + ntd_max = ntd_max - skip_frames / qh->interval;
27662 + max_xfer_size = (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS
27663 + : MAX_ISOC_XFER_SIZE_FS;
27665 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
27666 + while ((qh->ntd < ntd_max) && (qtd->isoc_frame_index_last < qtd->urb->packet_count)) {
27668 + dma_desc = &qh->desc_list[idx];
27669 + dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
27671 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
27673 + if (frame_desc->length > max_xfer_size)
27674 + qh->n_bytes[idx] = max_xfer_size;
27676 + qh->n_bytes[idx] = frame_desc->length;
27677 + dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
27678 + dma_desc->status.b_isoc.a = 1;
27680 + dma_desc->buf = qtd->urb->dma + frame_desc->offset;
27684 + qtd->isoc_frame_index_last++;
27686 + #ifdef ISOC_URB_GIVEBACK_ASAP
27688 + * Set IOC for each descriptor corresponding to the
27689 + * last frame of the URB.
27691 + if (qtd->isoc_frame_index_last == qtd->urb->packet_count)
27692 + dma_desc->status.b_isoc.ioc = 1;
27695 + idx = desclist_idx_inc(idx, inc, qh->dev_speed);
27699 + qtd->in_process = 1;
27702 + qh->td_last = idx;
27704 +#ifdef ISOC_URB_GIVEBACK_ASAP
27705 + /* Set IOC for the last descriptor if descriptor list is full */
27706 + if (qh->ntd == ntd_max) {
27707 + idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
27708 + qh->desc_list[idx].status.b_isoc.ioc = 1;
27712 + * Set IOC bit only for one descriptor.
27713 + * Always try to be ahead of HW processing,
27714 + * i.e. on IOC generation driver activates next descriptors but
27715 + * core continues to process descriptors followed the one with IOC set.
27718 + if (n_desc > DESCNUM_THRESHOLD) {
27720 + * Move IOC "up". Required even if there is only one QTD
27721 + * in the list, cause QTDs migth continue to be queued,
27722 + * but during the activation it was only one queued.
27723 + * Actually more than one QTD might be in the list if this function called
27724 + * from XferCompletion - QTDs was queued during HW processing of the previous
27725 + * descriptor chunk.
27727 + idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
27731 + * Set the IOC for the latest descriptor
27732 + * if either number of descriptor is not greather than threshold
27733 + * or no more new descriptors activated.
27735 + idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
27738 + qh->desc_list[idx].status.b_isoc.ioc = 1;
27743 +static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
27747 + dwc_otg_host_dma_desc_t *dma_desc;
27748 + dwc_otg_qtd_t *qtd;
27749 + int num_packets, len, n_desc = 0;
27751 + hc = qh->channel;
27754 + * Start with hc->xfer_buff initialized in
27755 + * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
27756 + * this pointer re-assigned to the buffer of the currently processed QTD.
27757 + * For non-SG request there is always one QTD active.
27760 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
27763 + /* SG request - more than 1 QTDs */
27764 + hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
27765 + hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
27771 + dma_desc = &qh->desc_list[n_desc];
27772 + len = hc->xfer_len;
27775 + if (len > MAX_DMA_DESC_SIZE)
27776 + len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
27778 + if (hc->ep_is_in) {
27780 + num_packets = (len + hc->max_packet - 1) / hc->max_packet;
27783 + /* Need 1 packet for transfer length of 0. */
27786 + /* Always program an integral # of max packets for IN transfers. */
27787 + len = num_packets * hc->max_packet;
27790 + dma_desc->status.b.n_bytes = len;
27792 + qh->n_bytes[n_desc] = len;
27795 + if ((qh->ep_type == UE_CONTROL) && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
27796 + dma_desc->status.b.sup = 1; /* Setup Packet */
27798 + dma_desc->status.b.a = 1; /* Active descriptor */
27800 + dma_desc->buf = (uint32_t) hc->xfer_buff;
27803 + * Last descriptor(or single) of IN transfer
27804 + * with actual size less than MaxPacket.
27806 + if (len > hc->xfer_len) {
27807 + hc->xfer_len = 0;
27810 + hc->xfer_buff += len;
27811 + hc->xfer_len -= len;
27817 + while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
27820 + qtd->in_process = 1;
27822 + if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
27827 + /* Request Transfer Complete interrupt for the last descriptor */
27828 + qh->desc_list[n_desc-1].status.b.ioc = 1;
27829 + /* End of List indicator */
27830 + qh->desc_list[n_desc-1].status.b.eol = 1;
27832 + hc->ntd = n_desc;
27837 + * For Control and Bulk endpoints initializes descriptor list
27838 + * and starts the transfer.
27840 + * For Interrupt and Isochronous endpoints initializes descriptor list
27841 + * then updates FrameList, marking appropriate entries as active.
27842 + * In case of Isochronous, the starting descriptor index is calculated based
27843 + * on the scheduled frame, but only on the first transfer descriptor within a session.
27844 + * Then starts the transfer via enabling the channel.
27845 + * For Isochronous endpoint the channel is not halted on XferComplete
27846 + * interrupt so remains assigned to the endpoint(QH) until session is done.
27848 + * @param hcd The HCD state structure for the DWC OTG controller.
27849 + * @param qh The QH to init.
27851 + * @return 0 if successful, negative error code otherwise.
27853 +void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
27855 + /* Channel is already assigned */
27856 + dwc_hc_t *hc = qh->channel;
27857 + uint8_t skip_frames = 0;
27859 + switch (hc->ep_type) {
27860 + case DWC_OTG_EP_TYPE_CONTROL:
27861 + case DWC_OTG_EP_TYPE_BULK:
27862 + init_non_isoc_dma_desc(hcd, qh);
27864 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
27866 + case DWC_OTG_EP_TYPE_INTR:
27867 + init_non_isoc_dma_desc(hcd, qh);
27869 + update_frame_list(hcd, qh, 1);
27871 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
27873 + case DWC_OTG_EP_TYPE_ISOC:
27876 + skip_frames = recalc_initial_desc_idx(hcd, qh);
27878 + init_isoc_dma_desc(hcd, qh, skip_frames);
27880 + if (!hc->xfer_started) {
27882 + update_frame_list(hcd, qh, 1);
27885 + * Always set to max, instead of actual size.
27886 + * Otherwise ntd will be changed with
27887 + * channel being enabled. Not recommended.
27890 + hc->ntd = max_desc_num(qh);
27891 + /* Enable channel only once for ISOC */
27892 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
27902 +static void complete_isoc_xfer_ddma(dwc_otg_hcd_t *hcd,
27904 + dwc_otg_hc_regs_t *hc_regs,
27905 + dwc_otg_halt_status_e halt_status)
27907 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
27908 + dwc_otg_qtd_t *qtd, *qtd_tmp;
27909 + dwc_otg_qh_t *qh;
27910 + dwc_otg_host_dma_desc_t *dma_desc;
27911 + uint16_t idx, remain;
27912 + uint8_t urb_compl;
27915 + idx = qh->td_first;
27918 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
27919 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
27920 + qtd->in_process = 0;
27923 + else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) ||
27924 + (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
27926 + * Channel is halted in these error cases.
27927 + * Considered as serious issues.
27928 + * Complete all URBs marking all frames as failed,
27929 + * irrespective whether some of the descriptors(frames) succeeded or no.
27930 + * Pass error code to completion routine as well, to
27931 + * update urb->status, some of class drivers might use it to stop
27932 + * queing transfer requests.
27934 + int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR)
27936 + : (-DWC_E_OVERFLOW);
27938 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
27939 + for(idx = 0; idx < qtd->urb->packet_count; idx++) {
27940 + frame_desc = &qtd->urb->iso_descs[idx];
27941 + frame_desc->status = err;
27943 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
27944 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
27950 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
27952 + if (!qtd->in_process)
27959 + dma_desc = &qh->desc_list[idx];
27961 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
27962 + remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
27964 + if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
27966 + * XactError or, unable to complete all the transactions
27967 + * in the scheduled micro-frame/frame,
27968 + * both indicated by DMA_DESC_STS_PKTERR.
27970 + qtd->urb->error_count++;
27971 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
27972 + frame_desc->status = -DWC_E_PROTOCOL;
27977 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
27978 + frame_desc->status = 0;
27981 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
27983 + * urb->status is not used for isoc transfers here.
27984 + * The individual frame_desc status are used instead.
27987 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
27988 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
27991 + * This check is necessary because urb_dequeue can be called
27992 + * from urb complete callback(sound driver example).
27993 + * All pending URBs are dequeued there, so no need for
27994 + * further processing.
27996 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
28006 + /* Stop if IOC requested descriptor reached */
28007 + if (dma_desc->status.b_isoc.ioc) {
28008 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
28012 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
28017 + while(idx != qh->td_first);
28020 + qh->td_first = idx;
28023 +uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
28025 + dwc_otg_qtd_t * qtd,
28026 + dwc_otg_host_dma_desc_t * dma_desc,
28027 + dwc_otg_halt_status_e halt_status,
28028 + uint32_t n_bytes,
28029 + uint8_t *xfer_done)
28032 + uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
28033 + dwc_otg_hcd_urb_t *urb = qtd->urb;
28036 + if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
28037 + urb->status = -DWC_E_IO;
28040 + if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
28041 + switch (halt_status) {
28042 + case DWC_OTG_HC_XFER_STALL:
28043 + urb->status = -DWC_E_PIPE;
28045 + case DWC_OTG_HC_XFER_BABBLE_ERR:
28046 + urb->status = -DWC_E_OVERFLOW;
28048 + case DWC_OTG_HC_XFER_XACT_ERR:
28049 + urb->status = -DWC_E_PROTOCOL;
28052 + DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
28059 + if (dma_desc->status.b.a == 1) {
28060 + DWC_DEBUGPL(DBG_HCDV, "Active descriptor encountered on channel %d\n", hc->hc_num);
28064 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
28065 + if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
28066 + urb->actual_length += n_bytes - remain;
28067 + if (remain || urb->actual_length == urb->length) {
28069 + * For Control Data stage do not set urb->status=0 to prevent
28070 + * URB callback. Set it when Status phase done. See below.
28076 + else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
28080 + /* No handling for SETUP stage */
28084 + /* BULK and INTR */
28085 + urb->actual_length += n_bytes - remain;
28086 + if (remain || urb->actual_length == urb->length) {
28095 +static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
28097 + dwc_otg_hc_regs_t * hc_regs,
28098 + dwc_otg_halt_status_e halt_status)
28100 + dwc_otg_hcd_urb_t *urb = NULL;
28101 + dwc_otg_qtd_t *qtd, *qtd_tmp;
28102 + dwc_otg_qh_t *qh;
28103 + dwc_otg_host_dma_desc_t *dma_desc;
28104 + uint32_t n_bytes, n_desc, i;
28105 + uint8_t failed = 0, xfer_done;
28112 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
28113 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
28114 + qtd->in_process = 0;
28119 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
28126 + for (i = 0; i < qtd->n_desc; i++) {
28127 + dma_desc = &qh->desc_list[n_desc];
28129 + n_bytes = qh->n_bytes[n_desc];
28132 + failed = update_non_isoc_urb_state_ddma(hcd, hc, qtd, dma_desc,
28133 + halt_status, n_bytes, &xfer_done);
28135 + if (failed || (xfer_done && (urb->status != -DWC_E_IN_PROGRESS))) {
28137 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
28138 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
28143 + else if (qh->ep_type == UE_CONTROL) {
28144 + if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
28145 + if (urb->length > 0) {
28146 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
28148 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
28150 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n");
28152 + else if(qtd->control_phase == DWC_OTG_CONTROL_DATA) {
28154 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
28155 + DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n");
28156 + } else if (i+1 == qtd->n_desc){
28158 + * Last descriptor for Control data stage which is
28159 + * not completed yet.
28161 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
28173 + if (qh->ep_type != UE_CONTROL) {
28175 + * Resetting the data toggle for bulk
28176 + * and interrupt endpoints in case of stall. See handle_hc_stall_intr()
28178 + if (halt_status == DWC_OTG_HC_XFER_STALL) {
28179 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
28182 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
28186 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
28187 + hcint_data_t hcint;
28188 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
28189 + if (hcint.b.nyet) {
28191 + * Got a NYET on the last transaction of the transfer. It
28192 + * means that the endpoint should be in the PING state at the
28193 + * beginning of the next transfer.
28195 + qh->ping_state = 1;
28196 + clear_hc_int(hc_regs, nyet);
28204 + * This function is called from interrupt handlers.
28205 + * Scans the descriptor list, updates URB's status and
28206 + * calls completion routine for the URB if it's done.
28207 + * Releases the channel to be used by other transfers.
28208 + * In case of Isochronous endpoint the channel is not halted until
28209 + * the end of the session, i.e. QTD list is empty.
28210 + * If periodic channel released the FrameList is updated accordingly.
28212 + * Calls transaction selection routines to activate pending transfers.
28214 + * @param hcd The HCD state structure for the DWC OTG controller.
28215 + * @param hc Host channel, the transfer is completed on.
28216 + * @param hc_regs Host channel registers.
28217 + * @param halt_status Reason the channel is being halted,
28218 + * or just XferComplete for isochronous transfer
28220 +void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t *hcd,
28222 + dwc_otg_hc_regs_t *hc_regs,
28223 + dwc_otg_halt_status_e halt_status)
28225 + uint8_t continue_isoc_xfer = 0;
28226 + dwc_otg_transaction_type_e tr_type;
28227 + dwc_otg_qh_t *qh = hc->qh;
28229 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
28231 + complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
28233 + /* Release the channel if halted or session completed */
28234 + if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
28235 + DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
28237 + /* Halt the channel if session completed */
28238 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
28239 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
28242 + release_channel_ddma(hcd, qh);
28243 + dwc_otg_hcd_qh_remove(hcd, qh);
28246 + /* Keep in assigned schedule to continue transfer */
28247 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
28248 + &qh->qh_list_entry);
28249 + continue_isoc_xfer = 1;
28252 + /** @todo Consider the case when period exceeds FrameList size.
28253 + * Frame Rollover interrupt should be used.
28257 + /* Scan descriptor list to complete the URB(s), then release the channel */
28258 + complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
28260 + release_channel_ddma(hcd, qh);
28262 + dwc_otg_hcd_qh_remove(hcd, qh);
28264 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
28265 + /* Add back to inactive non-periodic schedule on normal completion */
28266 + dwc_otg_hcd_qh_add(hcd, qh);
28271 + tr_type = dwc_otg_hcd_select_transactions(hcd);
28272 + if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
28273 + if (continue_isoc_xfer) {
28274 + if (tr_type == DWC_OTG_TRANSACTION_NONE) {
28275 + tr_type = DWC_OTG_TRANSACTION_PERIODIC;
28276 + } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
28277 + tr_type = DWC_OTG_TRANSACTION_ALL;
28280 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
28284 +#endif /* DWC_DEVICE_ONLY */
28286 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
28288 +/* ==========================================================================
28289 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $
28290 + * $Revision: #6 $
28291 + * $Date: 2009/04/21 $
28292 + * $Change: 1237474 $
28294 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
28295 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
28296 + * otherwise expressly agreed to in writing between Synopsys and you.
28298 + * The Software IS NOT an item of Licensed Software or Licensed Product under
28299 + * any End User Software License Agreement or Agreement for Licensed Product
28300 + * with Synopsys or any supplement thereto. You are permitted to use and
28301 + * redistribute this Software in source and binary forms, with or without
28302 + * modification, provided that redistributions of source code must retain this
28303 + * notice. You may not view, use, disclose, copy or distribute this file or
28304 + * any information contained herein except pursuant to this license grant from
28305 + * Synopsys. If you do not agree with this notice, including the disclaimer
28306 + * below, then you are not authorized to use the Software.
28308 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
28309 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28310 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28311 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
28312 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28313 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28314 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28315 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28316 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28317 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28319 + * ========================================================================== */
28320 +#ifndef DWC_DEVICE_ONLY
28321 +#ifndef __DWC_HCD_IF_H__
28322 +#define __DWC_HCD_IF_H__
28324 +#include "dwc_otg_core_if.h"
28327 + * This file defines DWC_OTG HCD Core API.
28330 +struct dwc_otg_hcd;
28331 +typedef struct dwc_otg_hcd dwc_otg_hcd_t;
28333 +struct dwc_otg_hcd_urb;
28334 +typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t;
28336 +/** @name HCD Function Driver Callbacks */
28339 +/** This function is called whenever core switches to host mode. */
28340 +typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd);
28342 +/** This function is called when device has been disconnected */
28343 +typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd);
28345 +/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */
28346 +typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
28347 + void *urb_handle,
28348 + uint32_t * hub_addr,
28349 + uint32_t * port_addr);
28350 +/** Via this function HCD core gets device speed */
28351 +typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
28352 + void *urb_handle);
28354 +/** This function is called when urb is completed */
28355 +typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd,
28356 + void *urb_handle,
28357 + dwc_otg_hcd_urb_t * dwc_otg_urb,
28360 +/** Via this function HCD core gets b_hnp_enable parameter */
28361 +typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd);
28363 +struct dwc_otg_hcd_function_ops {
28364 + dwc_otg_hcd_start_cb_t start;
28365 + dwc_otg_hcd_disconnect_cb_t disconnect;
28366 + dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
28367 + dwc_otg_hcd_speed_from_urb_cb_t speed;
28368 + dwc_otg_hcd_complete_urb_cb_t complete;
28369 + dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
28373 +/** @name HCD Core API */
28375 +/** This function allocates dwc_otg_hcd structure and returns pointer on it. */
28376 +extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void);
28378 +/** This function should be called to initiate HCD Core.
28380 + * @param hcd The HCD
28381 + * @param core_if The DWC_OTG Core
28383 + * Returns -DWC_E_NO_MEMORY if no enough memory.
28384 + * Returns 0 on success
28386 +extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if);
28390 + * @param hcd The HCD
28392 +extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
28394 +/** This function should be called on every hardware interrupt.
28396 + * @param dwc_otg_hcd The HCD
28398 + * Returns non zero if interrupt is handled
28399 + * Return 0 if interrupt is not handled
28401 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
28404 + * Returns private data set by
28405 + * dwc_otg_hcd_set_priv_data function.
28407 + * @param hcd The HCD
28409 +extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd);
28412 + * Set private data.
28414 + * @param hcd The HCD
28415 + * @param priv_data pointer to be stored in private data
28417 +extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data);
28420 + * This function initializes the HCD Core.
28422 + * @param hcd The HCD
28423 + * @param fops The Function Driver Operations data structure containing pointers to all callbacks.
28425 + * Returns -DWC_E_NO_DEVICE if Core is currently is in device mode.
28426 + * Returns 0 on success
28428 +extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
28429 + struct dwc_otg_hcd_function_ops *fops);
28432 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
28435 + * @param hcd The HCD
28437 +extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd);
28440 + * Handles hub class-specific requests.
28442 + * @param dwc_otg_hcd The HCD
28443 + * @param typeReq Request Type
28444 + * @param wValue wValue from control request
28445 + * @param wIndex wIndex from control request
28446 + * @param buf data buffer
28447 + * @param wLength data buffer length
28449 + * Returns -DWC_E_INVALID if invalid argument is passed
28450 + * Returns 0 on success
28452 +extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
28453 + uint16_t typeReq, uint16_t wValue,
28454 + uint16_t wIndex, uint8_t * buf,
28455 + uint16_t wLength);
28458 + * Returns otg port number.
28460 + * @param hcd The HCD
28462 +extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd);
28465 + * Returns 1 if currently core is acting as B host, and 0 otherwise.
28467 + * @param hcd The HCD
28469 +extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd);
28472 + * Returns current frame number.
28474 + * @param hcd The HCD
28476 +extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd);
28479 + * Dumps hcd state.
28481 + * @param hcd The HCD
28483 +extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd);
28486 + * Dump the average frame remaining at SOF. This can be used to
28487 + * determine average interrupt latency. Frame remaining is also shown for
28488 + * start transfer and two additional sample points.
28489 + * Currently this function is not implemented.
28491 + * @param hcd The HCD
28493 +extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd);
28496 + * Sends LPM transaction to the local device.
28498 + * @param hcd The HCD
28499 + * @param devaddr Device Address
28500 + * @param hird Host initiated resume duration
28501 + * @param bRemoteWake Value of bRemoteWake field in LPM transaction
28503 + * Returns negative value if sending LPM transaction was not succeeded.
28504 + * Returns 0 on success.
28506 +extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr,
28507 + uint8_t hird, uint8_t bRemoteWake);
28509 +/* URB interface */
28512 + * Allocates memory for dwc_otg_hcd_urb structure.
28513 + * Allocated memory should be freed by call dwc_free function.
28515 + * @param hcd The HCD
28516 + * @param iso_desc_count Count of ISOC descriptors
28517 + * @param atomic_alloc Specefies whether to perform atomic allocation.
28519 +extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
28520 + int iso_desc_count,
28521 + int atomic_alloc);
28524 + * Set pipe information in URB.
28526 + * @param hcd_urb DWC_OTG URB
28527 + * @param devaddr Device Address
28528 + * @param ep_num Endpoint Number
28529 + * @param ep_type Endpoint Type
28530 + * @param ep_dir Endpoint Direction
28531 + * @param mps Max Packet Size
28533 +extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb,
28534 + uint8_t devaddr, uint8_t ep_num,
28535 + uint8_t ep_type, uint8_t ep_dir,
28538 +/* Transfer flags */
28539 +#define URB_GIVEBACK_ASAP 0x1
28540 +#define URB_SEND_ZERO_PACKET 0x2
28543 + * Sets dwc_otg_hcd_urb parameters.
28545 + * @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
28546 + * @param urb_handle Unique handle for request, this will be passed back
28547 + * to function driver in completion callback.
28548 + * @param buf The buffer for the data
28549 + * @param dma The DMA buffer for the data
28550 + * @param buflen Transfer length
28551 + * @param sp Buffer for setup data
28552 + * @param sp_dma DMA address of setup data buffer
28553 + * @param flags Transfer flags
28554 + * @param interval Polling interval for interrupt or isochronous transfers.
28556 +extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb,
28557 + void *urb_handle, void *buf,
28558 + dwc_dma_t dma, uint32_t buflen, void *sp,
28559 + dwc_dma_t sp_dma, uint32_t flags,
28560 + uint16_t interval);
28562 +/** Gets status from dwc_otg_hcd_urb
28564 + * @param dwc_otg_urb DWC_OTG URB
28566 +extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb);
28568 +/** Gets actual length from dwc_otg_hcd_urb
28570 + * @param dwc_otg_urb DWC_OTG URB
28572 +extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t *
28575 +/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs
28577 + * @param dwc_otg_urb DWC_OTG URB
28579 +extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t *
28582 +/** Set ISOC descriptor offset and length
28584 + * @param dwc_otg_urb DWC_OTG URB
28585 + * @param desc_num ISOC descriptor number
28586 + * @param offset Offset from beginig of buffer.
28587 + * @param length Transaction length
28589 +extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
28590 + int desc_num, uint32_t offset,
28591 + uint32_t length);
28593 +/** Get status of ISOC descriptor, specified by desc_num
28595 + * @param dwc_otg_urb DWC_OTG URB
28596 + * @param desc_num ISOC descriptor number
28598 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t *
28599 + dwc_otg_urb, int desc_num);
28601 +/** Get actual length of ISOC descriptor, specified by desc_num
28603 + * @param dwc_otg_urb DWC_OTG URB
28604 + * @param desc_num ISOC descriptor number
28606 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
28610 +/** Queue URB. After transfer is completes, the complete callback will be called with the URB status
28612 + * @param dwc_otg_hcd The HCD
28613 + * @param dwc_otg_urb DWC_OTG URB
28614 + * @param ep_handle Out parameter for returning endpoint handle
28616 + * Returns -DWC_E_NO_DEVICE if no device is connected.
28617 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
28618 + * Returns 0 on success.
28620 +extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd,
28621 + dwc_otg_hcd_urb_t * dwc_otg_urb,
28622 + void **ep_handle);
28624 +/** De-queue the specified URB
28626 + * @param dwc_otg_hcd The HCD
28627 + * @param dwc_otg_urb DWC_OTG URB
28629 +extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd,
28630 + dwc_otg_hcd_urb_t * dwc_otg_urb);
28632 +/** Frees resources in the DWC_otg controller related to a given endpoint.
28633 + * Any URBs for the endpoint must already be dequeued.
28635 + * @param hcd The HCD
28636 + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
28637 + * @param retry Number of retries if there are queued transfers.
28639 + * Returns -DWC_E_INVALID if invalid arguments are passed.
28640 + * Returns 0 on success
28642 +extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
28645 +/** Returns 1 if status of specified port is changed and 0 otherwise.
28647 + * @param hcd The HCD
28648 + * @param port Port number
28650 +extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port);
28652 +/** Call this function to check if bandwidth was allocated for specified endpoint.
28653 + * Only for ISOC and INTERRUPT endpoints.
28655 + * @param hcd The HCD
28656 + * @param ep_handle Endpoint handle
28658 +extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd,
28659 + void *ep_handle);
28661 +/** Call this function to check if bandwidth was freed for specified endpoint.
28663 + * @param hcd The HCD
28664 + * @param ep_handle Endpoint handle
28666 +extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle);
28668 +/** Returns bandwidth allocated for specified endpoint in microseconds.
28669 + * Only for ISOC and INTERRUPT endpoints.
28671 + * @param hcd The HCD
28672 + * @param ep_handle Endpoint handle
28674 +extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd,
28675 + void *ep_handle);
28679 +#endif /* __DWC_HCD_IF_H__ */
28680 +#endif /* DWC_DEVICE_ONLY */
28682 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
28684 +/* ==========================================================================
28685 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $
28686 + * $Revision: #77 $
28687 + * $Date: 2009/04/21 $
28688 + * $Change: 1237475 $
28690 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
28691 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
28692 + * otherwise expressly agreed to in writing between Synopsys and you.
28694 + * The Software IS NOT an item of Licensed Software or Licensed Product under
28695 + * any End User Software License Agreement or Agreement for Licensed Product
28696 + * with Synopsys or any supplement thereto. You are permitted to use and
28697 + * redistribute this Software in source and binary forms, with or without
28698 + * modification, provided that redistributions of source code must retain this
28699 + * notice. You may not view, use, disclose, copy or distribute this file or
28700 + * any information contained herein except pursuant to this license grant from
28701 + * Synopsys. If you do not agree with this notice, including the disclaimer
28702 + * below, then you are not authorized to use the Software.
28704 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
28705 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28706 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28707 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
28708 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28709 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28710 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28711 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28712 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28713 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28715 + * ========================================================================== */
28716 +#ifndef DWC_DEVICE_ONLY
28718 +#include "dwc_otg_hcd.h"
28719 +#include "dwc_otg_regs.h"
28722 + * This file contains the implementation of the HCD Interrupt handlers.
28725 +/** This function handles interrupts for the HCD. */
28726 +int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
28730 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
28731 + gintsts_data_t gintsts;
28733 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
28735 + //GRAYG: debugging
28736 + if (NULL == global_regs) {
28737 + DWC_DEBUGPL(DBG_HCD, "**** NULL regs: dwc_otg_hcd=%p "
28739 + dwc_otg_hcd, global_regs);
28744 + /* Check if HOST Mode */
28745 + if (dwc_otg_is_host_mode(core_if)) {
28746 + gintsts.d32 = dwc_otg_read_core_intr(core_if);
28747 + if (!gintsts.d32) {
28751 + /* Don't print debug message in the interrupt handler on SOF */
28753 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
28755 + DWC_DEBUGPL(DBG_HCD, "\n");
28760 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
28762 + DWC_DEBUGPL(DBG_HCD,
28763 + "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n",
28764 + gintsts.d32, core_if);
28767 + if (gintsts.b.sofintr) {
28768 + retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
28770 + if (gintsts.b.rxstsqlvl) {
28772 + dwc_otg_hcd_handle_rx_status_q_level_intr
28775 + if (gintsts.b.nptxfempty) {
28777 + dwc_otg_hcd_handle_np_tx_fifo_empty_intr
28780 + if (gintsts.b.i2cintr) {
28781 + /** @todo Implement i2cintr handler. */
28783 + if (gintsts.b.portintr) {
28784 + retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
28786 + if (gintsts.b.hcintr) {
28787 + retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
28789 + if (gintsts.b.ptxfempty) {
28791 + dwc_otg_hcd_handle_perio_tx_fifo_empty_intr
28796 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
28799 + DWC_DEBUGPL(DBG_HCD,
28800 + "DWC OTG HCD Finished Servicing Interrupts\n");
28801 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
28802 + dwc_read_reg32(&global_regs->gintsts));
28803 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
28804 + dwc_read_reg32(&global_regs->gintmsk));
28810 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
28812 + DWC_DEBUGPL(DBG_HCD, "\n");
28820 +#ifdef DWC_TRACK_MISSED_SOFS
28821 +#warning Compiling code to track missed SOFs
28822 +#define FRAME_NUM_ARRAY_SIZE 1000
28824 + * This function is for debug only.
28826 +static inline void track_missed_sofs(uint16_t curr_frame_number)
28828 + static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
28829 + static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
28830 + static int frame_num_idx = 0;
28831 + static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
28832 + static int dumped_frame_num_array = 0;
28834 + if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
28835 + if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
28836 + curr_frame_number) {
28837 + frame_num_array[frame_num_idx] = curr_frame_number;
28838 + last_frame_num_array[frame_num_idx++] = last_frame_num;
28840 + } else if (!dumped_frame_num_array) {
28842 + DWC_PRINTF("Frame Last Frame\n");
28843 + DWC_PRINTF("----- ----------\n");
28844 + for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
28845 + DWC_PRINTF("0x%04x 0x%04x\n",
28846 + frame_num_array[i], last_frame_num_array[i]);
28848 + dumped_frame_num_array = 1;
28850 + last_frame_num = curr_frame_number;
28855 + * Handles the start-of-frame interrupt in host mode. Non-periodic
28856 + * transactions may be queued to the DWC_otg controller for the current
28857 + * (micro)frame. Periodic transactions may be queued to the controller for the
28858 + * next (micro)frame.
28860 +int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd)
28862 + hfnum_data_t hfnum;
28863 + dwc_list_link_t *qh_entry;
28864 + dwc_otg_qh_t *qh;
28865 + dwc_otg_transaction_type_e tr_type;
28866 + gintsts_data_t gintsts = {.d32 = 0 };
28869 + dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hfnum);
28872 + DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
28874 + hcd->frame_number = hfnum.b.frnum;
28877 + hcd->frrem_accum += hfnum.b.frrem;
28878 + hcd->frrem_samples++;
28881 +#ifdef DWC_TRACK_MISSED_SOFS
28882 + track_missed_sofs(hcd->frame_number);
28884 + /* Determine whether any periodic QHs should be executed. */
28885 + qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive);
28886 + while (qh_entry != &hcd->periodic_sched_inactive) {
28887 + qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry);
28888 + qh_entry = qh_entry->next;
28889 + if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
28891 + * Move QH to the ready list to be executed next
28894 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
28895 + &qh->qh_list_entry);
28898 + tr_type = dwc_otg_hcd_select_transactions(hcd);
28899 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
28900 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
28903 + /* Clear interrupt */
28904 + gintsts.b.sofintr = 1;
28905 + dwc_write_reg32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
28910 +/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at
28911 + * least one packet in the Rx FIFO. The packets are moved from the FIFO to
28912 + * memory if the DWC_otg controller is operating in Slave mode. */
28913 +int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd)
28915 + host_grxsts_data_t grxsts;
28916 + dwc_hc_t *hc = NULL;
28918 + DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
28921 + dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp);
28923 + hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
28925 + /* Packet Status */
28926 + DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum);
28927 + DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt);
28928 + DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid,
28929 + hc->data_pid_start);
28930 + DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts);
28932 + switch (grxsts.b.pktsts) {
28933 + case DWC_GRXSTS_PKTSTS_IN:
28934 + /* Read the data into the host buffer. */
28935 + if (grxsts.b.bcnt > 0) {
28936 + dwc_otg_read_packet(dwc_otg_hcd->core_if,
28937 + hc->xfer_buff, grxsts.b.bcnt);
28939 + /* Update the HC fields for the next packet received. */
28940 + hc->xfer_count += grxsts.b.bcnt;
28941 + hc->xfer_buff += grxsts.b.bcnt;
28944 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
28945 + case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
28946 + case DWC_GRXSTS_PKTSTS_CH_HALTED:
28947 + /* Handled in interrupt, just ignore data */
28950 + DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n",
28951 + grxsts.b.pktsts);
28958 +/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
28959 + * data packets may be written to the FIFO for OUT transfers. More requests
28960 + * may be written to the non-periodic request queue for IN transfers. This
28961 + * interrupt is enabled only in Slave mode. */
28962 +int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
28964 + DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
28965 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
28966 + DWC_OTG_TRANSACTION_NON_PERIODIC);
28970 +/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data
28971 + * packets may be written to the FIFO for OUT transfers. More requests may be
28972 + * written to the periodic request queue for IN transfers. This interrupt is
28973 + * enabled only in Slave mode. */
28974 +int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
28976 + DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
28977 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
28978 + DWC_OTG_TRANSACTION_PERIODIC);
28982 +/** There are multiple conditions that can cause a port interrupt. This function
28983 + * determines which interrupt conditions have occurred and handles them
28984 + * appropriately. */
28985 +int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd)
28988 + hprt0_data_t hprt0;
28989 + hprt0_data_t hprt0_modify;
28991 + hprt0.d32 = dwc_read_reg32(dwc_otg_hcd->core_if->host_if->hprt0);
28992 + hprt0_modify.d32 = dwc_read_reg32(dwc_otg_hcd->core_if->host_if->hprt0);
28994 + /* Clear appropriate bits in HPRT0 to clear the interrupt bit in
28997 + hprt0_modify.b.prtena = 0;
28998 + hprt0_modify.b.prtconndet = 0;
28999 + hprt0_modify.b.prtenchng = 0;
29000 + hprt0_modify.b.prtovrcurrchng = 0;
29002 + /* Port Connect Detected
29003 + * Set flag and clear if detected */
29004 + if (hprt0.b.prtconndet) {
29005 + DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
29006 + "Port Connect Detected--\n", hprt0.d32);
29007 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
29008 + dwc_otg_hcd->flags.b.port_connect_status = 1;
29009 + hprt0_modify.b.prtconndet = 1;
29011 + /* B-Device has connected, Delete the connection timer. */
29012 + DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer);
29014 + /* The Hub driver asserts a reset when it sees port connect
29015 + * status change flag */
29019 + /* Port Enable Changed
29020 + * Clear if detected - Set internal flag if disabled */
29021 + if (hprt0.b.prtenchng) {
29022 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
29023 + "Port Enable Changed--\n", hprt0.d32);
29024 + hprt0_modify.b.prtenchng = 1;
29025 + if (hprt0.b.prtena == 1) {
29026 + int do_reset = 0;
29027 + dwc_otg_core_params_t *params =
29028 + dwc_otg_hcd->core_if->core_params;
29029 + dwc_otg_core_global_regs_t *global_regs =
29030 + dwc_otg_hcd->core_if->core_global_regs;
29031 + dwc_otg_host_if_t *host_if =
29032 + dwc_otg_hcd->core_if->host_if;
29034 + /* Check if we need to adjust the PHY clock speed for
29035 + * low power and adjust it */
29036 + if (params->host_support_fs_ls_low_power) {
29037 + gusbcfg_data_t usbcfg;
29040 + dwc_read_reg32(&global_regs->gusbcfg);
29042 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED
29043 + || hprt0.b.prtspd ==
29044 + DWC_HPRT0_PRTSPD_FULL_SPEED) {
29048 + hcfg_data_t hcfg;
29049 + if (usbcfg.b.phylpwrclksel == 0) {
29050 + /* Set PHY low power clock select for FS/LS devices */
29051 + usbcfg.b.phylpwrclksel = 1;
29052 + dwc_write_reg32(&global_regs->
29059 + dwc_read_reg32(&host_if->
29060 + host_global_regs->hcfg);
29062 + if (hprt0.b.prtspd ==
29063 + DWC_HPRT0_PRTSPD_LOW_SPEED
29065 + host_ls_low_power_phy_clk ==
29066 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)
29069 + DWC_DEBUGPL(DBG_CIL,
29070 + "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
29071 + if (hcfg.b.fslspclksel !=
29072 + DWC_HCFG_6_MHZ) {
29073 + hcfg.b.fslspclksel =
29077 + host_global_regs->
29083 + DWC_DEBUGPL(DBG_CIL,
29084 + "FS_PHY programming HCFG to 48 MHz ()\n");
29085 + if (hcfg.b.fslspclksel !=
29086 + DWC_HCFG_48_MHZ) {
29087 + hcfg.b.fslspclksel =
29091 + host_global_regs->
29100 + if (usbcfg.b.phylpwrclksel == 1) {
29101 + usbcfg.b.phylpwrclksel = 0;
29102 + dwc_write_reg32(&global_regs->
29110 + DWC_TASK_SCHEDULE(dwc_otg_hcd->
29116 + /* Port has been enabled set the reset change flag */
29117 + dwc_otg_hcd->flags.b.port_reset_change = 1;
29120 + dwc_otg_hcd->flags.b.port_enable_change = 1;
29125 + /** Overcurrent Change Interrupt */
29126 + if (hprt0.b.prtovrcurrchng) {
29127 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
29128 + "Port Overcurrent Changed--\n", hprt0.d32);
29129 + dwc_otg_hcd->flags.b.port_over_current_change = 1;
29130 + hprt0_modify.b.prtovrcurrchng = 1;
29134 + /* Clear Port Interrupts */
29135 + dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
29140 +/** This interrupt indicates that one or more host channels has a pending
29141 + * interrupt. There are multiple conditions that can cause each host channel
29142 + * interrupt. This function determines which conditions have occurred for each
29143 + * host channel interrupt and handles them appropriately. */
29144 +int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
29148 + haint_data_t haint;
29150 + /* Clear appropriate bits in HCINTn to clear the interrupt bit in
29153 + haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
29155 + for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
29156 + if (haint.b2.chint & (1 << i)) {
29157 + retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
29167 + * Gets the actual length of a transfer after the transfer halts. _halt_status
29168 + * holds the reason for the halt.
29170 + * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE,
29171 + * *short_read is set to 1 upon return if less than the requested
29172 + * number of bytes were transferred. Otherwise, *short_read is set to 0 upon
29173 + * return. short_read may also be NULL on entry, in which case it remains
29176 +static uint32_t get_actual_xfer_length(dwc_hc_t * hc,
29177 + dwc_otg_hc_regs_t * hc_regs,
29178 + dwc_otg_qtd_t * qtd,
29179 + dwc_otg_halt_status_e halt_status,
29182 + hctsiz_data_t hctsiz;
29185 + if (short_read != NULL) {
29188 + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
29190 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
29191 + if (hc->ep_is_in) {
29192 + length = hc->xfer_len - hctsiz.b.xfersize;
29193 + if (short_read != NULL) {
29194 + *short_read = (hctsiz.b.xfersize != 0);
29196 + } else if (hc->qh->do_split) {
29197 + length = qtd->ssplit_out_xfer_count;
29199 + length = hc->xfer_len;
29203 + * Must use the hctsiz.pktcnt field to determine how much data
29204 + * has been transferred. This field reflects the number of
29205 + * packets that have been transferred via the USB. This is
29206 + * always an integral number of packets if the transfer was
29207 + * halted before its normal completion. (Can't use the
29208 + * hctsiz.xfersize field because that reflects the number of
29209 + * bytes transferred via the AHB, not the USB).
29212 + (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet;
29219 + * Updates the state of the URB after a Transfer Complete interrupt on the
29220 + * host channel. Updates the actual_length field of the URB based on the
29221 + * number of bytes transferred via the host channel. Sets the URB status
29222 + * if the data transfer is finished.
29224 + * @return 1 if the data transfer specified by the URB is completely finished,
29227 +static int update_urb_state_xfer_comp(dwc_hc_t * hc,
29228 + dwc_otg_hc_regs_t * hc_regs,
29229 + dwc_otg_hcd_urb_t * urb,
29230 + dwc_otg_qtd_t * qtd)
29232 + int xfer_done = 0;
29233 + int short_read = 0;
29237 + xfer_length = get_actual_xfer_length(hc, hc_regs, qtd,
29238 + DWC_OTG_HC_XFER_COMPLETE,
29242 + /* non DWORD-aligned buffer case handling. */
29243 + if (hc->align_buff && xfer_length && hc->ep_is_in) {
29244 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, xfer_length);
29247 + urb->actual_length += xfer_length;
29249 + if(xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) &&
29250 + (urb->flags & URB_SEND_ZERO_PACKET) && (urb->actual_length == urb->length) &&
29251 + !(urb->length % hc->max_packet)) {
29253 + } else if (short_read || urb->actual_length == urb->length) {
29260 + hctsiz_data_t hctsiz;
29261 + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
29262 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
29263 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
29265 + DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", hc->xfer_len);
29266 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n",
29267 + hctsiz.b.xfersize);
29268 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
29270 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
29271 + urb->actual_length);
29272 + DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n",
29273 + short_read, xfer_done);
29277 + return xfer_done;
29281 + * Save the starting data toggle for the next transfer. The data toggle is
29282 + * saved in the QH for non-control transfers and it's saved in the QTD for
29283 + * control transfers.
29285 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
29286 + dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd)
29288 + hctsiz_data_t hctsiz;
29289 + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
29291 + if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
29292 + dwc_otg_qh_t *qh = hc->qh;
29293 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
29294 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
29296 + qh->data_toggle = DWC_OTG_HC_PID_DATA1;
29299 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
29300 + qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
29302 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
29308 + * Updates the state of an Isochronous URB when the transfer is stopped for
29309 + * any reason. The fields of the current entry in the frame descriptor array
29310 + * are set based on the transfer state and the input _halt_status. Completes
29311 + * the Isochronous URB if all the URB frames have been completed.
29313 + * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be
29314 + * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
29316 +static dwc_otg_halt_status_e
29317 +update_isoc_urb_state(dwc_otg_hcd_t * hcd,
29319 + dwc_otg_hc_regs_t * hc_regs,
29320 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
29322 + dwc_otg_hcd_urb_t *urb = qtd->urb;
29323 + dwc_otg_halt_status_e ret_val = halt_status;
29324 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
29326 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
29327 + switch (halt_status) {
29328 + case DWC_OTG_HC_XFER_COMPLETE:
29329 + frame_desc->status = 0;
29330 + frame_desc->actual_length =
29331 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
29333 + /* non DWORD-aligned buffer case handling. */
29334 + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
29335 + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
29336 + hc->qh->dw_align_buf, frame_desc->actual_length);
29340 + case DWC_OTG_HC_XFER_FRAME_OVERRUN:
29341 + urb->error_count++;
29342 + if (hc->ep_is_in) {
29343 + frame_desc->status = -DWC_E_NO_STREAM_RES;
29345 + frame_desc->status = -DWC_E_COMMUNICATION;
29347 + frame_desc->actual_length = 0;
29349 + case DWC_OTG_HC_XFER_BABBLE_ERR:
29350 + urb->error_count++;
29351 + frame_desc->status = -DWC_E_OVERFLOW;
29352 + /* Don't need to update actual_length in this case. */
29354 + case DWC_OTG_HC_XFER_XACT_ERR:
29355 + urb->error_count++;
29356 + frame_desc->status = -DWC_E_PROTOCOL;
29357 + frame_desc->actual_length =
29358 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
29360 + /* non DWORD-aligned buffer case handling. */
29361 + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
29362 + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
29363 + hc->qh->dw_align_buf, frame_desc->actual_length);
29365 + /* Skip whole frame */
29366 + if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) &&
29367 + hc->ep_is_in && hcd->core_if->dma_enable) {
29368 + qtd->complete_split = 0;
29369 + qtd->isoc_split_offset = 0;
29374 + DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status);
29377 + if (++qtd->isoc_frame_index == urb->packet_count) {
29379 + * urb->status is not used for isoc transfers.
29380 + * The individual frame_desc statuses are used instead.
29382 + hcd->fops->complete(hcd, urb->priv, urb, 0);
29383 + ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
29385 + ret_val = DWC_OTG_HC_XFER_COMPLETE;
29391 + * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
29392 + * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
29393 + * still linked to the QH, the QH is added to the end of the inactive
29394 + * non-periodic schedule. For periodic QHs, removes the QH from the periodic
29395 + * schedule if no more QTDs are linked to the QH.
29397 +static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd)
29399 + int continue_split = 0;
29400 + dwc_otg_qtd_t *qtd;
29402 + DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd);
29404 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
29406 + if (qtd->complete_split) {
29407 + continue_split = 1;
29408 + } else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
29409 + qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) {
29410 + continue_split = 1;
29414 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
29415 + continue_split = 0;
29418 + qh->channel = NULL;
29419 + dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
29423 + * Releases a host channel for use by other transfers. Attempts to select and
29424 + * queue more transactions since at least one host channel is available.
29426 + * @param hcd The HCD state structure.
29427 + * @param hc The host channel to release.
29428 + * @param qtd The QTD associated with the host channel. This QTD may be freed
29429 + * if the transfer is complete or an error has occurred.
29430 + * @param halt_status Reason the channel is being released. This status
29431 + * determines the actions taken by this function.
29433 +static void release_channel(dwc_otg_hcd_t * hcd,
29435 + dwc_otg_qtd_t * qtd,
29436 + dwc_otg_halt_status_e halt_status)
29438 + dwc_otg_transaction_type_e tr_type;
29441 + DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n",
29442 + __func__, hc->hc_num, halt_status, hc->xfer_len);
29444 +#ifdef HW2937_WORKAROUND
29445 + if (hcd->hw2937_assigned_channels & (1<<hc->hc_num))
29447 + if ((hcd->hw2937_assigned_channels &= ~(1<<hc->hc_num)) == 0)
29448 + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_IDLE;
29449 + DWC_DEBUGPL(DBG_HW2937, " release %d, hw2937_ac -> %x\n", hc->hc_num, hcd->hw2937_assigned_channels);
29453 + DWC_DEBUGPL(DBG_ANY, " Unexpected release %d (hw2937_ac = %x)\n", hc->hc_num, hcd->hw2937_assigned_channels);
29457 + switch (halt_status) {
29458 + case DWC_OTG_HC_XFER_URB_COMPLETE:
29461 + case DWC_OTG_HC_XFER_AHB_ERR:
29462 + case DWC_OTG_HC_XFER_STALL:
29463 + case DWC_OTG_HC_XFER_BABBLE_ERR:
29466 + case DWC_OTG_HC_XFER_XACT_ERR:
29467 + if (qtd->error_count >= 3) {
29468 + DWC_DEBUGPL(DBG_HCDV,
29469 + " Complete URB with transaction error\n");
29471 + qtd->urb->status = -DWC_E_PROTOCOL;
29472 + hcd->fops->complete(hcd, qtd->urb->priv,
29473 + qtd->urb, -DWC_E_PROTOCOL);
29478 + case DWC_OTG_HC_XFER_URB_DEQUEUE:
29480 + * The QTD has already been removed and the QH has been
29481 + * deactivated. Don't want to do anything except release the
29482 + * host channel and try to queue more transfers.
29485 + case DWC_OTG_HC_XFER_NO_HALT_STATUS:
29493 + deactivate_qh(hcd, hc->qh, free_qtd);
29497 + * Release the host channel for use by other transfers. The cleanup
29498 + * function clears the channel interrupt enables and conditions, so
29499 + * there's no need to clear the Channel Halted interrupt separately.
29501 + dwc_otg_hc_cleanup(hcd->core_if, hc);
29502 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
29504 + switch (hc->ep_type) {
29505 + case DWC_OTG_EP_TYPE_CONTROL:
29506 + case DWC_OTG_EP_TYPE_BULK:
29507 + hcd->non_periodic_channels--;
29512 + * Don't release reservations for periodic channels here.
29513 + * That's done when a periodic transfer is descheduled (i.e.
29514 + * when the QH is removed from the periodic schedule).
29519 + /* Try to queue more transfers now that there's a free channel. */
29520 + tr_type = dwc_otg_hcd_select_transactions(hcd);
29521 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
29522 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
29528 + * Halts a host channel. If the channel cannot be halted immediately because
29529 + * the request queue is full, this function ensures that the FIFO empty
29530 + * interrupt for the appropriate queue is enabled so that the halt request can
29531 + * be queued when there is space in the request queue.
29533 + * This function may also be called in DMA mode. In that case, the channel is
29534 + * simply released since the core always halts the channel automatically in
29537 +static void halt_channel(dwc_otg_hcd_t * hcd,
29539 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
29541 + if (hcd->core_if->dma_enable) {
29542 + release_channel(hcd, hc, qtd, halt_status);
29546 + /* Slave mode processing... */
29547 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
29549 + if (hc->halt_on_queue) {
29550 + gintmsk_data_t gintmsk = {.d32 = 0 };
29551 + dwc_otg_core_global_regs_t *global_regs;
29552 + global_regs = hcd->core_if->core_global_regs;
29554 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
29555 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
29557 + * Make sure the Non-periodic Tx FIFO empty interrupt
29558 + * is enabled so that the non-periodic schedule will
29561 + gintmsk.b.nptxfempty = 1;
29562 + dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32);
29565 + * Move the QH from the periodic queued schedule to
29566 + * the periodic assigned schedule. This allows the
29567 + * halt to be queued when the periodic schedule is
29570 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
29571 + &hc->qh->qh_list_entry);
29574 + * Make sure the Periodic Tx FIFO Empty interrupt is
29575 + * enabled so that the periodic schedule will be
29578 + gintmsk.b.ptxfempty = 1;
29579 + dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32);
29585 + * Performs common cleanup for non-periodic transfers after a Transfer
29586 + * Complete interrupt. This function should be called after any endpoint type
29587 + * specific handling is finished to release the host channel.
29589 +static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd,
29591 + dwc_otg_hc_regs_t * hc_regs,
29592 + dwc_otg_qtd_t * qtd,
29593 + dwc_otg_halt_status_e halt_status)
29595 + hcint_data_t hcint;
29597 + qtd->error_count = 0;
29599 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
29600 + if (hcint.b.nyet) {
29602 + * Got a NYET on the last transaction of the transfer. This
29603 + * means that the endpoint should be in the PING state at the
29604 + * beginning of the next transfer.
29606 + hc->qh->ping_state = 1;
29607 + clear_hc_int(hc_regs, nyet);
29611 + * Always halt and release the host channel to make it available for
29612 + * more transfers. There may still be more phases for a control
29613 + * transfer or more data packets for a bulk transfer at this point,
29614 + * but the host channel is still halted. A channel will be reassigned
29615 + * to the transfer when the non-periodic schedule is processed after
29616 + * the channel is released. This allows transactions to be queued
29617 + * properly via dwc_otg_hcd_queue_transactions, which also enables the
29618 + * Tx FIFO Empty interrupt if necessary.
29620 + if (hc->ep_is_in) {
29622 + * IN transfers in Slave mode require an explicit disable to
29623 + * halt the channel. (In DMA mode, this call simply releases
29626 + halt_channel(hcd, hc, qtd, halt_status);
29629 + * The channel is automatically disabled by the core for OUT
29630 + * transfers in Slave mode.
29632 + release_channel(hcd, hc, qtd, halt_status);
29637 + * Performs common cleanup for periodic transfers after a Transfer Complete
29638 + * interrupt. This function should be called after any endpoint type specific
29639 + * handling is finished to release the host channel.
29641 +static void complete_periodic_xfer(dwc_otg_hcd_t * hcd,
29643 + dwc_otg_hc_regs_t * hc_regs,
29644 + dwc_otg_qtd_t * qtd,
29645 + dwc_otg_halt_status_e halt_status)
29647 + hctsiz_data_t hctsiz;
29648 + qtd->error_count = 0;
29650 + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
29651 + if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) {
29652 + /* Core halts channel in these cases. */
29653 + release_channel(hcd, hc, qtd, halt_status);
29655 + /* Flush any outstanding requests from the Tx queue. */
29656 + halt_channel(hcd, hc, qtd, halt_status);
29660 +static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd,
29662 + dwc_otg_hc_regs_t * hc_regs,
29663 + dwc_otg_qtd_t * qtd)
29666 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
29667 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
29669 + len = get_actual_xfer_length(hc, hc_regs, qtd,
29670 + DWC_OTG_HC_XFER_COMPLETE,
29674 + qtd->complete_split = 0;
29675 + qtd->isoc_split_offset = 0;
29678 + frame_desc->actual_length += len;
29680 + if (hc->align_buff && len)
29681 + dwc_memcpy(qtd->urb->buf + frame_desc->offset + qtd->isoc_split_offset,
29682 + hc->qh->dw_align_buf,
29684 + qtd->isoc_split_offset += len;
29686 + if (frame_desc->length == frame_desc->actual_length) {
29687 + frame_desc->status = 0;
29688 + qtd->isoc_frame_index++;
29689 + qtd->complete_split = 0;
29690 + qtd->isoc_split_offset = 0;
29693 + if (qtd->isoc_frame_index == qtd->urb->packet_count) {
29694 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
29695 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
29697 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
29700 + return 1; /* Indicates that channel released */
29703 + * Handles a host channel Transfer Complete interrupt. This handler may be
29704 + * called in either DMA mode or Slave mode.
29706 +static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd,
29708 + dwc_otg_hc_regs_t * hc_regs,
29709 + dwc_otg_qtd_t * qtd)
29711 + int urb_xfer_done;
29712 + dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;
29713 + dwc_otg_hcd_urb_t *urb = qtd->urb;
29714 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
29716 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
29717 + "Transfer Complete--\n", hc->hc_num);
29719 + if (hcd->core_if->dma_desc_enable) {
29720 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status);
29721 + if (pipe_type == UE_ISOCHRONOUS) {
29722 + /* Do not disable the interrupt, just clear it */
29723 + clear_hc_int(hc_regs, xfercomp);
29726 + goto handle_xfercomp_done;
29730 + * Handle xfer complete on CSPLIT.
29733 + if (hc->qh->do_split) {
29734 + if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in && hcd->core_if->dma_enable) {
29735 + if (qtd->complete_split && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs, qtd))
29736 + goto handle_xfercomp_done;
29739 + qtd->complete_split = 0;
29743 + /* Update the QTD and URB states. */
29744 + switch (pipe_type) {
29746 + switch (qtd->control_phase) {
29747 + case DWC_OTG_CONTROL_SETUP:
29748 + if (urb->length > 0) {
29749 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
29751 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
29753 + DWC_DEBUGPL(DBG_HCDV,
29754 + " Control setup transaction done\n");
29755 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
29757 + case DWC_OTG_CONTROL_DATA:{
29759 + update_urb_state_xfer_comp(hc, hc_regs, urb,
29761 + if (urb_xfer_done) {
29762 + qtd->control_phase =
29763 + DWC_OTG_CONTROL_STATUS;
29764 + DWC_DEBUGPL(DBG_HCDV,
29765 + " Control data transfer done\n");
29767 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
29769 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
29772 + case DWC_OTG_CONTROL_STATUS:
29773 + DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n");
29774 + if (urb->status == -DWC_E_IN_PROGRESS) {
29777 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
29778 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
29782 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
29785 + DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n");
29787 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
29788 + if (urb_xfer_done) {
29789 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
29790 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
29792 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
29795 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
29796 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
29798 + case UE_INTERRUPT:
29799 + DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n");
29800 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
29803 + * Interrupt URB is done on the first transfer complete
29806 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
29807 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
29808 + complete_periodic_xfer(hcd, hc, hc_regs, qtd,
29809 + DWC_OTG_HC_XFER_URB_COMPLETE);
29811 + case UE_ISOCHRONOUS:
29812 + DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n");
29813 + if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {
29815 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
29816 + DWC_OTG_HC_XFER_COMPLETE);
29818 + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
29822 +handle_xfercomp_done:
29823 + disable_hc_int(hc_regs, xfercompl);
29829 + * Handles a host channel STALL interrupt. This handler may be called in
29830 + * either DMA mode or Slave mode.
29832 +static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd,
29834 + dwc_otg_hc_regs_t * hc_regs,
29835 + dwc_otg_qtd_t * qtd)
29837 + dwc_otg_hcd_urb_t *urb = qtd->urb;
29838 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
29840 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
29841 + "STALL Received--\n", hc->hc_num);
29843 + if (hcd->core_if->dma_desc_enable) {
29844 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL);
29845 + goto handle_stall_done;
29848 + if (pipe_type == UE_CONTROL) {
29849 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
29852 + if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) {
29853 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
29855 + * USB protocol requires resetting the data toggle for bulk
29856 + * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
29857 + * setup command is issued to the endpoint. Anticipate the
29858 + * CLEAR_FEATURE command since a STALL has occurred and reset
29859 + * the data toggle now.
29861 + hc->qh->data_toggle = 0;
29864 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL);
29866 +handle_stall_done:
29867 + disable_hc_int(hc_regs, stall);
29873 + * Updates the state of the URB when a transfer has been stopped due to an
29874 + * abnormal condition before the transfer completes. Modifies the
29875 + * actual_length field of the URB to reflect the number of bytes that have
29876 + * actually been transferred via the host channel.
29878 +static void update_urb_state_xfer_intr(dwc_hc_t * hc,
29879 + dwc_otg_hc_regs_t * hc_regs,
29880 + dwc_otg_hcd_urb_t * urb,
29881 + dwc_otg_qtd_t * qtd,
29882 + dwc_otg_halt_status_e halt_status)
29884 + uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
29885 + halt_status, NULL);
29886 + /* non DWORD-aligned buffer case handling. */
29887 + if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
29888 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, bytes_transferred);
29891 + urb->actual_length += bytes_transferred;
29895 + hctsiz_data_t hctsiz;
29896 + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
29897 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
29898 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
29900 + DWC_DEBUGPL(DBG_HCDV, " hc->start_pkt_count %d\n",
29901 + hc->start_pkt_count);
29902 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
29903 + DWC_DEBUGPL(DBG_HCDV, " hc->max_packet %d\n", hc->max_packet);
29904 + DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n",
29905 + bytes_transferred);
29906 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
29907 + urb->actual_length);
29908 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
29915 + * Handles a host channel NAK interrupt. This handler may be called in either
29916 + * DMA mode or Slave mode.
29918 +static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
29920 + dwc_otg_hc_regs_t * hc_regs,
29921 + dwc_otg_qtd_t * qtd)
29923 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
29924 + "NAK Received--\n", hc->hc_num);
29927 + * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
29928 + * interrupt. Re-start the SSPLIT transfer.
29930 + if (hc->do_split) {
29931 + if (hc->complete_split) {
29932 + qtd->error_count = 0;
29934 + qtd->complete_split = 0;
29935 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
29936 + goto handle_nak_done;
29939 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
29942 + if (hcd->core_if->dma_enable && hc->ep_is_in) {
29943 +#ifdef HW2937_WORKAROUND
29944 + if (hc->halt_status == DWC_OTG_HC_XFER_PAUSE_IN) {
29945 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
29949 + * NAK interrupts are enabled on bulk/control IN
29950 + * transfers in DMA mode for the sole purpose of
29951 + * resetting the error count after a transaction error
29952 + * occurs. The core will continue transferring data.
29954 + qtd->error_count = 0;
29955 + goto handle_nak_done;
29959 + * NAK interrupts normally occur during OUT transfers in DMA
29960 + * or Slave mode. For IN transfers, more requests will be
29961 + * queued as request queue space is available.
29963 + qtd->error_count = 0;
29965 + if (!hc->qh->ping_state) {
29966 + update_urb_state_xfer_intr(hc, hc_regs,
29968 + DWC_OTG_HC_XFER_NAK);
29969 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
29971 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH)
29972 + hc->qh->ping_state = 1;
29976 + * Halt the channel so the transfer can be re-started from
29977 + * the appropriate point or the PING protocol will
29978 + * start/continue.
29980 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
29982 + case UE_INTERRUPT:
29983 + qtd->error_count = 0;
29984 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
29986 + case UE_ISOCHRONOUS:
29987 +#ifdef HW2937_WORKAROUND
29988 + if (hc->halt_status == DWC_OTG_HC_XFER_PAUSE_IN) {
29989 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
29993 + /* Should never get called for isochronous transfers. */
29994 + DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n");
29999 + disable_hc_int(hc_regs, nak);
30005 + * Handles a host channel ACK interrupt. This interrupt is enabled when
30006 + * performing the PING protocol in Slave mode, when errors occur during
30007 + * either Slave mode or DMA mode, and during Start Split transactions.
30009 +static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd,
30011 + dwc_otg_hc_regs_t * hc_regs,
30012 + dwc_otg_qtd_t * qtd)
30014 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
30015 + "ACK Received--\n", hc->hc_num);
30017 + if (hc->do_split) {
30019 + * Handle ACK on SSPLIT.
30020 + * ACK should not occur in CSPLIT.
30022 + if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) {
30023 + qtd->ssplit_out_xfer_count = hc->xfer_len;
30025 + if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) {
30026 + /* Don't need complete for isochronous out transfers. */
30027 + qtd->complete_split = 1;
30031 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
30032 + switch (hc->xact_pos) {
30033 + case DWC_HCSPLIT_XACTPOS_ALL:
30035 + case DWC_HCSPLIT_XACTPOS_END:
30036 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
30037 + qtd->isoc_split_offset = 0;
30039 + case DWC_HCSPLIT_XACTPOS_BEGIN:
30040 + case DWC_HCSPLIT_XACTPOS_MID:
30042 + * For BEGIN or MID, calculate the length for
30043 + * the next microframe to determine the correct
30044 + * SSPLIT token, either MID or END.
30047 + struct dwc_otg_hcd_iso_packet_desc
30051 + &qtd->urb->iso_descs[qtd->
30052 + isoc_frame_index];
30053 + qtd->isoc_split_offset += 188;
30055 + if ((frame_desc->length -
30056 + qtd->isoc_split_offset) <= 188) {
30057 + qtd->isoc_split_pos =
30058 + DWC_HCSPLIT_XACTPOS_END;
30060 + qtd->isoc_split_pos =
30061 + DWC_HCSPLIT_XACTPOS_MID;
30068 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
30071 + qtd->error_count = 0;
30073 + if (hc->qh->ping_state) {
30074 + hc->qh->ping_state = 0;
30076 + * Halt the channel so the transfer can be re-started
30077 + * from the appropriate point. This only happens in
30078 + * Slave mode. In DMA mode, the ping_state is cleared
30079 + * when the transfer is started because the core
30080 + * automatically executes the PING, then the transfer.
30082 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
30084 +#ifdef HW2937_WORKAROUND
30085 + else if (hc->halt_status == DWC_OTG_HC_XFER_PAUSE_IN) {
30086 + dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
30087 + update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd, DWC_OTG_HC_XFER_PAUSE_IN);
30088 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
30089 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_PAUSE_IN);
30095 + * If the ACK occurred when _not_ in the PING state, let the channel
30096 + * continue transferring data after clearing the error count.
30099 + disable_hc_int(hc_regs, ack);
30105 + * Handles a host channel NYET interrupt. This interrupt should only occur on
30106 + * Bulk and Control OUT endpoints and for complete split transactions. If a
30107 + * NYET occurs at the same time as a Transfer Complete interrupt, it is
30108 + * handled in the xfercomp interrupt handler, not here. This handler may be
30109 + * called in either DMA mode or Slave mode.
30111 +static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
30113 + dwc_otg_hc_regs_t * hc_regs,
30114 + dwc_otg_qtd_t * qtd)
30116 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
30117 + "NYET Received--\n", hc->hc_num);
30121 + * re-do the CSPLIT immediately on non-periodic
30123 + if (hc->do_split && hc->complete_split) {
30124 + if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hcd->core_if->dma_enable) {
30125 + qtd->complete_split = 0;
30126 + qtd->isoc_split_offset = 0;
30127 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
30128 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
30129 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
30132 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
30133 + goto handle_nyet_done;
30136 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
30137 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
30138 + int frnum = dwc_otg_hcd_get_frame_number(hcd);
30140 + if (dwc_full_frame_num(frnum) !=
30141 + dwc_full_frame_num(hc->qh->sched_frame)) {
30143 + * No longer in the same full speed frame.
30144 + * Treat this as a transaction error.
30147 + /** @todo Fix system performance so this can
30148 + * be treated as an error. Right now complete
30149 + * splits cannot be scheduled precisely enough
30150 + * due to other system activity, so this error
30151 + * occurs regularly in Slave mode.
30153 + qtd->error_count++;
30155 + qtd->complete_split = 0;
30156 + halt_channel(hcd, hc, qtd,
30157 + DWC_OTG_HC_XFER_XACT_ERR);
30158 + /** @todo add support for isoc release */
30159 + goto handle_nyet_done;
30163 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
30164 + goto handle_nyet_done;
30167 + hc->qh->ping_state = 1;
30168 + qtd->error_count = 0;
30170 + update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd,
30171 + DWC_OTG_HC_XFER_NYET);
30172 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
30175 + * Halt the channel and re-start the transfer so the PING
30176 + * protocol will start.
30178 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
30180 + handle_nyet_done:
30181 + disable_hc_int(hc_regs, nyet);
30186 + * Handles a host channel babble interrupt. This handler may be called in
30187 + * either DMA mode or Slave mode.
30189 +static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd,
30191 + dwc_otg_hc_regs_t * hc_regs,
30192 + dwc_otg_qtd_t * qtd)
30194 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
30195 + "Babble Error--\n", hc->hc_num);
30197 + if (hcd->core_if->dma_desc_enable) {
30198 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_BABBLE_ERR);
30199 + goto handle_babble_done;
30202 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
30203 + hcd->fops->complete(hcd, qtd->urb->priv,
30204 + qtd->urb, -DWC_E_OVERFLOW);
30205 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
30207 + dwc_otg_halt_status_e halt_status;
30208 + halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd,
30209 + DWC_OTG_HC_XFER_BABBLE_ERR);
30210 + halt_channel(hcd, hc, qtd, halt_status);
30213 +handle_babble_done:
30214 + disable_hc_int(hc_regs, bblerr);
30219 + * Handles a host channel AHB error interrupt. This handler is only called in
30222 +static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd,
30224 + dwc_otg_hc_regs_t * hc_regs,
30225 + dwc_otg_qtd_t * qtd)
30227 + hcchar_data_t hcchar;
30228 + hcsplt_data_t hcsplt;
30229 + hctsiz_data_t hctsiz;
30231 + char *pipetype, *speed;
30233 + dwc_otg_hcd_urb_t *urb = qtd->urb;
30235 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
30236 + "AHB Error--\n", hc->hc_num);
30238 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
30239 + hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
30240 + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
30241 + hcdma = dwc_read_reg32(&hc_regs->hcdma);
30243 + DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num);
30244 + DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
30245 + DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
30246 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
30247 + DWC_ERROR(" Device address: %d\n",
30248 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
30249 + DWC_ERROR(" Endpoint: %d, %s\n",
30250 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
30251 + (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"));
30254 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
30256 + pipetype = "CONTROL";
30259 + pipetype = "BULK";
30261 + case UE_INTERRUPT:
30262 + pipetype = "INTERRUPT";
30264 + case UE_ISOCHRONOUS:
30265 + pipetype = "ISOCHRONOUS";
30268 + pipetype = "UNKNOWN";
30272 + DWC_ERROR(" Endpoint type: %s\n", pipetype);
30274 + switch (hc->speed) {
30275 + case DWC_OTG_EP_SPEED_HIGH:
30278 + case DWC_OTG_EP_SPEED_FULL:
30281 + case DWC_OTG_EP_SPEED_LOW:
30285 + speed = "UNKNOWN";
30289 + DWC_ERROR(" Speed: %s\n", speed);
30291 + DWC_ERROR(" Max packet size: %d\n",
30292 + dwc_otg_hcd_get_mps(&urb->pipe_info));
30293 + DWC_ERROR(" Data buffer length: %d\n", urb->length);
30294 + DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n",
30295 + urb->buf, (void *)urb->dma);
30296 + DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n",
30297 + urb->setup_packet, (void *)urb->setup_dma);
30298 + DWC_ERROR(" Interval: %d\n", urb->interval);
30300 + /* Core haltes the channel for Descriptor DMA mode */
30301 + if (hcd->core_if->dma_desc_enable) {
30302 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_AHB_ERR);
30303 + goto handle_ahberr_done;
30306 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO);
30309 + * Force a channel halt. Don't call halt_channel because that won't
30310 + * write to the HCCHARn register in DMA mode to force the halt.
30312 + dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
30313 +handle_ahberr_done:
30314 + disable_hc_int(hc_regs, ahberr);
30319 + * Handles a host channel transaction error interrupt. This handler may be
30320 + * called in either DMA mode or Slave mode.
30322 +static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd,
30324 + dwc_otg_hc_regs_t * hc_regs,
30325 + dwc_otg_qtd_t * qtd)
30327 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
30328 + "Transaction Error--\n", hc->hc_num);
30330 + if (hcd->core_if->dma_desc_enable) {
30331 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_XACT_ERR);
30332 + goto handle_xacterr_done;
30335 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
30338 + qtd->error_count++;
30339 + if (!hc->qh->ping_state) {
30341 + update_urb_state_xfer_intr(hc, hc_regs,
30343 + DWC_OTG_HC_XFER_XACT_ERR);
30344 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
30345 + if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) {
30346 + hc->qh->ping_state = 1;
30351 + * Halt the channel so the transfer can be re-started from
30352 + * the appropriate point or the PING protocol will start.
30354 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
30356 + case UE_INTERRUPT:
30357 + qtd->error_count++;
30358 + if (hc->do_split && hc->complete_split) {
30359 + qtd->complete_split = 0;
30361 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
30363 + case UE_ISOCHRONOUS:
30365 + dwc_otg_halt_status_e halt_status;
30367 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
30368 + DWC_OTG_HC_XFER_XACT_ERR);
30370 + halt_channel(hcd, hc, qtd, halt_status);
30374 +handle_xacterr_done:
30375 + disable_hc_int(hc_regs, xacterr);
30381 + * Handles a host channel frame overrun interrupt. This handler may be called
30382 + * in either DMA mode or Slave mode.
30384 +static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd,
30386 + dwc_otg_hc_regs_t * hc_regs,
30387 + dwc_otg_qtd_t * qtd)
30389 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
30390 + "Frame Overrun--\n", hc->hc_num);
30392 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
30396 + case UE_INTERRUPT:
30397 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
30399 + case UE_ISOCHRONOUS:
30401 + dwc_otg_halt_status_e halt_status;
30403 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
30404 + DWC_OTG_HC_XFER_FRAME_OVERRUN);
30406 + halt_channel(hcd, hc, qtd, halt_status);
30411 + disable_hc_int(hc_regs, frmovrun);
30417 + * Handles a host channel data toggle error interrupt. This handler may be
30418 + * called in either DMA mode or Slave mode.
30420 +static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd,
30422 + dwc_otg_hc_regs_t * hc_regs,
30423 + dwc_otg_qtd_t * qtd)
30425 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
30426 + "Data Toggle Error--\n", hc->hc_num);
30428 + if (hc->ep_is_in) {
30429 + qtd->error_count = 0;
30431 + DWC_ERROR("Data Toggle Error on OUT transfer,"
30432 + "channel %d\n", hc->hc_num);
30435 + disable_hc_int(hc_regs, datatglerr);
30442 + * This function is for debug only. It checks that a valid halt status is set
30443 + * and that HCCHARn.chdis is clear. If there's a problem, corrective action is
30444 + * taken and a warning is issued.
30445 + * @return 1 if halt status is ok, 0 otherwise.
30447 +static inline int halt_status_ok(dwc_otg_hcd_t * hcd,
30449 + dwc_otg_hc_regs_t * hc_regs,
30450 + dwc_otg_qtd_t * qtd)
30452 + hcchar_data_t hcchar;
30453 + hctsiz_data_t hctsiz;
30454 + hcint_data_t hcint;
30455 + hcintmsk_data_t hcintmsk;
30456 + hcsplt_data_t hcsplt;
30458 + if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
30460 + * This code is here only as a check. This condition should
30461 + * never happen. Ignore the halt if it does occur.
30463 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
30464 + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
30465 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
30466 + hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);
30467 + hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
30469 + ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
30470 + "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
30471 + "hcint 0x%08x, hcintmsk 0x%08x, "
30472 + "hcsplt 0x%08x, qtd->complete_split %d\n", __func__,
30473 + hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32,
30474 + hcintmsk.d32, hcsplt.d32, qtd->complete_split);
30476 + DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
30477 + __func__, hc->hc_num);
30479 + clear_hc_int(hc_regs, chhltd);
30484 + * This code is here only as a check. hcchar.chdis should
30485 + * never be set when the halt interrupt occurs. Halt the
30486 + * channel again if it does occur.
30488 + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
30489 + if (hcchar.b.chdis) {
30490 + DWC_WARN("%s: hcchar.chdis set unexpectedly, "
30491 + "hcchar 0x%08x, trying to halt again\n",
30492 + __func__, hcchar.d32);
30493 + clear_hc_int(hc_regs, chhltd);
30494 + hc->halt_pending = 0;
30495 + halt_channel(hcd, hc, qtd, hc->halt_status);
30504 + * Handles a host Channel Halted interrupt in DMA mode. This handler
30505 + * determines the reason the channel halted and proceeds accordingly.
30507 +static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
30509 + dwc_otg_hc_regs_t * hc_regs,
30510 + dwc_otg_qtd_t * qtd)
30512 + hcint_data_t hcint;
30513 + hcintmsk_data_t hcintmsk;
30514 + int out_nak_enh = 0;
30516 + /* For core with OUT NAK enhancement, the flow for high-
30517 + * speed CONTROL/BULK OUT is handled a little differently.
30519 + if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) {
30520 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in &&
30521 + (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
30522 + hc->ep_type == DWC_OTG_EP_TYPE_BULK)) {
30527 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
30528 + (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR && !hcd->core_if->dma_desc_enable)) {
30530 + * Just release the channel. A dequeue can happen on a
30531 + * transfer timeout. In the case of an AHB Error, the channel
30532 + * was forced to halt because there's no way to gracefully
30535 + if (hcd->core_if->dma_desc_enable)
30536 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, hc->halt_status);
30538 + release_channel(hcd, hc, qtd, hc->halt_status);
30542 + /* Read the HCINTn register to determine the cause for the halt. */
30543 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
30544 + hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);
30546 + if (hcint.b.xfercomp) {
30547 + /** @todo This is here because of a possible hardware bug. Spec
30548 + * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
30549 + * interrupt w/ACK bit set should occur, but I only see the
30550 + * XFERCOMP bit, even with it masked out. This is a workaround
30551 + * for that behavior. Should fix this when hardware is fixed.
30553 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
30554 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
30556 + handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
30557 + } else if (hcint.b.stall) {
30558 + handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
30559 + } else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) {
30560 + if (out_nak_enh) {
30561 + if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) {
30562 + DWC_DEBUG("XactErr with NYET/NAK/ACK\n");
30563 + qtd->error_count = 0;
30565 + DWC_DEBUG("XactErr without NYET/NAK/ACK\n");
30570 + * Must handle xacterr before nak or ack. Could get a xacterr
30571 + * at the same time as either of these on a BULK/CONTROL OUT
30572 + * that started with a PING. The xacterr takes precedence.
30574 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
30575 + } else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) {
30576 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
30577 + } else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) {
30578 + handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
30579 + } else if (hcint.b.bblerr) {
30580 + handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
30581 + } else if (hcint.b.frmovrun) {
30582 + handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
30583 + } else if (!out_nak_enh) {
30584 + if (hcint.b.nyet) {
30586 + * Must handle nyet before nak or ack. Could get a nyet at the
30587 + * same time as either of those on a BULK/CONTROL OUT that
30588 + * started with a PING. The nyet takes precedence.
30590 + handle_hc_nyet_intr(hcd, hc, hc_regs, qtd);
30591 + } else if (hcint.b.nak && !hcintmsk.b.nak) {
30593 + * If nak is not masked, it's because a non-split IN transfer
30594 + * is in an error state. In that case, the nak is handled by
30595 + * the nak interrupt handler, not here. Handle nak here for
30596 + * BULK/CONTROL OUT transfers, which halt on a NAK to allow
30597 + * rewinding the buffer pointer.
30599 + handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
30600 + } else if (hcint.b.ack && !hcintmsk.b.ack) {
30602 + * If ack is not masked, it's because a non-split IN transfer
30603 + * is in an error state. In that case, the ack is handled by
30604 + * the ack interrupt handler, not here. Handle ack here for
30605 + * split transfers. Start splits halt on ACK.
30607 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
30609 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
30610 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
30612 + * A periodic transfer halted with no other channel
30613 + * interrupts set. Assume it was halted by the core
30614 + * because it could not be completed in its scheduled
30619 + ("%s: Halt channel %d (assume incomplete periodic transfer)\n",
30620 + __func__, hc->hc_num);
30622 + halt_channel(hcd, hc, qtd,
30623 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
30626 + ("%s: Channel %d, DMA Mode -- ChHltd set, but reason "
30627 + "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
30628 + __func__, hc->hc_num, hcint.d32,
30629 + dwc_read_reg32(&hcd->core_if->
30630 + core_global_regs->gintsts));
30635 + DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n",
30641 + * Handles a host channel Channel Halted interrupt.
30643 + * In slave mode, this handler is called only when the driver specifically
30644 + * requests a halt. This occurs during handling other host channel interrupts
30645 + * (e.g. nak, xacterr, stall, nyet, etc.).
30647 + * In DMA mode, this is the interrupt that occurs when the core has finished
30648 + * processing a transfer on a channel. Other host channel interrupts (except
30649 + * ahberr) are disabled in DMA mode.
30651 +static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
30653 + dwc_otg_hc_regs_t * hc_regs,
30654 + dwc_otg_qtd_t * qtd)
30656 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
30657 + "Channel Halted--\n", hc->hc_num);
30659 + if (hcd->core_if->dma_enable) {
30660 + handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd);
30663 + if (!halt_status_ok(hcd, hc, hc_regs, qtd)) {
30667 + release_channel(hcd, hc, qtd, hc->halt_status);
30673 +/** Handles interrupt for a specific Host Channel */
30674 +int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
30677 + hcint_data_t hcint;
30678 + hcintmsk_data_t hcintmsk;
30680 + dwc_otg_hc_regs_t *hc_regs;
30681 + dwc_otg_qtd_t *qtd;
30683 + DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num);
30685 + hc = dwc_otg_hcd->hc_ptr_array[num];
30686 + hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
30687 + qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
30689 + hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
30690 + hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);
30691 + DWC_DEBUGPL(DBG_HCDV,
30692 + " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
30693 + hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
30694 + hcint.d32 = hcint.d32 & hcintmsk.d32;
30696 + if (!dwc_otg_hcd->core_if->dma_enable) {
30697 + if (hcint.b.chhltd && hcint.d32 != 0x2) {
30698 + hcint.b.chhltd = 0;
30702 + if (hcint.b.xfercomp) {
30704 + handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd);
30706 + * If NYET occurred at same time as Xfer Complete, the NYET is
30707 + * handled by the Xfer Complete interrupt handler. Don't want
30708 + * to call the NYET interrupt handler in this case.
30710 + hcint.b.nyet = 0;
30712 + if (hcint.b.chhltd) {
30713 + retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd);
30715 + if (hcint.b.ahberr) {
30716 + retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
30718 + if (hcint.b.stall) {
30719 + retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd);
30721 + if (hcint.b.nak) {
30722 + retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
30724 + if (hcint.b.ack) {
30725 + retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
30727 + if (hcint.b.nyet) {
30728 + retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
30730 + if (hcint.b.xacterr) {
30731 + retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
30733 + if (hcint.b.bblerr) {
30734 + retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd);
30736 + if (hcint.b.frmovrun) {
30738 + handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd);
30740 + if (hcint.b.datatglerr) {
30742 + handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
30748 +#endif /* DWC_DEVICE_ONLY */
30750 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
30752 +/* ==========================================================================
30753 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
30754 + * $Revision: #11 $
30755 + * $Date: 2009/04/21 $
30756 + * $Change: 1237476 $
30758 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
30759 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
30760 + * otherwise expressly agreed to in writing between Synopsys and you.
30762 + * The Software IS NOT an item of Licensed Software or Licensed Product under
30763 + * any End User Software License Agreement or Agreement for Licensed Product
30764 + * with Synopsys or any supplement thereto. You are permitted to use and
30765 + * redistribute this Software in source and binary forms, with or without
30766 + * modification, provided that redistributions of source code must retain this
30767 + * notice. You may not view, use, disclose, copy or distribute this file or
30768 + * any information contained herein except pursuant to this license grant from
30769 + * Synopsys. If you do not agree with this notice, including the disclaimer
30770 + * below, then you are not authorized to use the Software.
30772 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
30773 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30774 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30775 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
30776 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30777 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30778 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30779 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30780 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30781 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30783 + * ========================================================================== */
30784 +#ifndef DWC_DEVICE_ONLY
30789 + * This file contains the implementation of the HCD. In Linux, the HCD
30790 + * implements the hc_driver API.
30792 +#include <linux/kernel.h>
30793 +#include <linux/module.h>
30794 +#include <linux/moduleparam.h>
30795 +#include <linux/init.h>
30796 +#include <linux/device.h>
30797 +#include <linux/errno.h>
30798 +#include <linux/list.h>
30799 +#include <linux/interrupt.h>
30800 +#include <linux/string.h>
30801 +#include <linux/dma-mapping.h>
30802 +#include <linux/version.h>
30803 +#include <asm/io.h>
30805 +#ifdef LM_INTERFACE
30806 +//#include <asm/arch/regs-irq.h>
30807 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
30808 +#include <asm/arch/lm.h>
30809 +#include <asm/arch/irqs.h>
30811 +#include <mach/lm.h>
30812 +#include <mach/irqs.h>
30814 +#elif defined(PLATFORM_INTERFACE)
30815 +#include <linux/platform_device.h>
30818 +#include <linux/usb.h>
30819 +#include <linux/usb/hcd.h>
30821 +#include "dwc_otg_hcd_if.h"
30822 +#include "dwc_otg_dbg.h"
30823 +#include "dwc_otg_driver.h"
30826 + * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
30827 + * qualified with its direction (possible 32 endpoints per device).
30829 +#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
30830 + ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
30832 +static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
30834 +/** @name Linux HC Driver API Functions */
30836 +/* manage i/o requests, device state */
30837 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
30838 +static int urb_enqueue(struct usb_hcd *hcd,
30839 + struct usb_host_endpoint *ep,
30840 + struct urb *urb, gfp_t mem_flags);
30842 +static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
30844 +static int urb_enqueue(struct usb_hcd *hcd,
30845 + struct urb *urb, gfp_t mem_flags);
30847 +static int urb_dequeue(struct usb_hcd *hcd,
30848 + struct urb *urb, int status);
30851 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
30853 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
30854 +extern int hcd_start(struct usb_hcd *hcd);
30855 +extern void hcd_stop(struct usb_hcd *hcd);
30856 +static int get_frame_number(struct usb_hcd *hcd);
30857 +extern int hub_status_data(struct usb_hcd *hcd, char *buf);
30858 +extern int hub_control(struct usb_hcd *hcd,
30860 + u16 wValue, u16 wIndex, char *buf, u16 wLength);
30862 +struct wrapper_priv_data {
30863 + dwc_otg_hcd_t *dwc_otg_hcd;
30868 +static struct hc_driver dwc_otg_hc_driver = {
30870 + .description = dwc_otg_hcd_name,
30871 + .product_desc = "DWC OTG Controller",
30872 + .hcd_priv_size = sizeof(struct wrapper_priv_data),
30874 + .irq = dwc_otg_hcd_irq,
30876 + .flags = HCD_MEMORY | HCD_USB2,
30879 + .start = hcd_start,
30882 + .stop = hcd_stop,
30884 + .urb_enqueue = urb_enqueue,
30885 + .urb_dequeue = urb_dequeue,
30886 + .endpoint_disable = endpoint_disable,
30888 + .get_frame_number = get_frame_number,
30890 + .hub_status_data = hub_status_data,
30891 + .hub_control = hub_control,
30896 +/** Gets the dwc_otg_hcd from a struct usb_hcd */
30897 +static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
30899 + struct wrapper_priv_data *p;
30900 + p = (struct wrapper_priv_data *)(hcd->hcd_priv);
30901 + return p->dwc_otg_hcd;
30904 +/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
30905 +static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
30907 + return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
30910 +/** Gets the usb_host_endpoint associated with an URB. */
30911 +inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
30913 + struct usb_device *dev = urb->dev;
30914 + int ep_num = usb_pipeendpoint(urb->pipe);
30916 + if (usb_pipein(urb->pipe))
30917 + return dev->ep_in[ep_num];
30919 + return dev->ep_out[ep_num];
30922 +static int _disconnect(dwc_otg_hcd_t * hcd)
30924 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
30926 + usb_hcd->self.is_b_host = 0;
30930 +static int _start(dwc_otg_hcd_t * hcd)
30932 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
30934 + usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
30935 + hcd_start(usb_hcd);
30940 +static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
30941 + uint32_t * port_addr)
30943 + struct urb *urb = (struct urb *)urb_handle;
30944 +#if 1 //GRAYG - temporary
30945 + if (NULL == urb_handle)
30946 + DWC_ERROR("**** %s - NULL URB handle\n", __func__);//GRAYG
30947 + if (NULL == urb->dev)
30948 + DWC_ERROR("**** %s - URB has no device\n", __func__);//GRAYG
30949 + if (NULL == port_addr)
30950 + DWC_ERROR("**** %s - NULL port_address\n", __func__);//GRAYG
30952 + if (urb->dev->tt) {
30953 + if (NULL == urb->dev->tt->hub) {
30954 + DWC_ERROR("**** %s - (URB's transactor has no TT - giving no hub)\n",
30955 + __func__); //GRAYG
30956 + //*hub_addr = (u8)usb_pipedevice(urb->pipe); //GRAYG
30957 + *hub_addr = 0; //GRAYG
30958 + // we probably shouldn't have a transaction translator if
30959 + // there's no associated hub?
30961 + *hub_addr = urb->dev->tt->hub->devnum;
30965 + *port_addr = urb->dev->ttport;
30969 +static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
30971 + struct urb *urb = (struct urb *)urb_handle;
30972 + return urb->dev->speed;
30975 +static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
30977 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
30978 + return usb_hcd->self.b_hnp_enable;
30981 +static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
30984 + hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
30985 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
30986 + hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
30988 + hcd_to_bus(hcd)->bandwidth_int_reqs++;
30992 +static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
30995 + hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
30996 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
30997 + hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
30999 + hcd_to_bus(hcd)->bandwidth_int_reqs--;
31004 + * Sets the final status of an URB and returns it to the device driver. Any
31005 + * required cleanup of the URB is performed.
31007 +static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
31008 + dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
31010 + struct urb *urb = (struct urb *)urb_handle;
31012 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
31013 + DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
31014 + __func__, urb, usb_pipedevice(urb->pipe),
31015 + usb_pipeendpoint(urb->pipe),
31016 + usb_pipein(urb->pipe) ? "IN" : "OUT", status);
31017 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
31019 + for (i = 0; i < urb->number_of_packets; i++) {
31020 + DWC_PRINTF(" ISO Desc %d status: %d\n",
31021 + i, urb->iso_frame_desc[i].status);
31027 + urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
31028 + /* Convert status value. */
31029 + switch (status) {
31030 + case -DWC_E_PROTOCOL:
31031 + status = -EPROTO;
31033 + case -DWC_E_IN_PROGRESS:
31034 + status = -EINPROGRESS;
31036 + case -DWC_E_PIPE:
31042 + case -DWC_E_TIMEOUT:
31043 + status = -ETIMEDOUT;
31045 + case -DWC_E_OVERFLOW:
31046 + status = -EOVERFLOW;
31050 + DWC_PRINTF("Uknown urb status %d\n", status);
31055 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
31058 + urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
31059 + for (i = 0; i < urb->number_of_packets; ++i) {
31060 + urb->iso_frame_desc[i].actual_length =
31061 + dwc_otg_hcd_urb_get_iso_desc_actual_length
31062 + (dwc_otg_urb, i);
31063 + urb->iso_frame_desc[i].status =
31064 + dwc_otg_hcd_urb_get_iso_desc_status
31065 + (dwc_otg_urb, i);
31069 + urb->status = status;
31070 + urb->hcpriv = NULL;
31072 + if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
31073 + (urb->actual_length < urb->transfer_buffer_length)) {
31074 + urb->status = -EREMOTEIO;
31078 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
31079 + (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
31080 + struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
31082 + free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
31083 + dwc_otg_hcd_get_ep_bandwidth(hcd,
31090 + dwc_free(dwc_otg_urb);
31091 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
31092 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
31094 + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
31095 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
31100 +static struct dwc_otg_hcd_function_ops hcd_fops = {
31102 + .disconnect = _disconnect,
31103 + .hub_info = _hub_info,
31105 + .complete = _complete,
31106 + .get_b_hnp_enable = _get_b_hnp_enable,
31110 + * Initializes the HCD. This function allocates memory for and initializes the
31111 + * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
31112 + * USB bus with the core and calls the hc_driver->start() function. It returns
31113 + * a negative error on failure.
31116 +#ifdef LM_INTERFACE
31117 + struct lm_device *_dev
31118 +#elif defined(PCI_INTERFACE)
31119 + struct pci_dev *_dev
31120 +#elif defined(PLATFORM_INTERFACE)
31121 + struct platform_device *_dev
31125 + struct usb_hcd *hcd = NULL;
31126 + dwc_otg_hcd_t *dwc_otg_hcd = NULL;
31127 +#ifdef LM_INTERFACE
31128 + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
31129 +#elif defined(PCI_INTERFACE)
31130 + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
31131 +#elif defined(PLATFORM_INTERFACE)
31132 + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
31138 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev);
31140 + /* Set device flags indicating whether the HCD supports DMA. */
31141 + if (dwc_otg_is_dma_enable(otg_dev->core_if))
31142 + dmamask = DMA_BIT_MASK(32);
31146 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
31147 + dma_set_mask(&_dev->dev, dmamask);
31148 + dma_set_coherent_mask(&_dev->dev, dmamask);
31149 +#elif defined(PCI_INTERFACE)
31150 + pci_set_dma_mask(_dev, dmamask);
31151 + pci_set_consistent_dma_mask(_dev, dmamask);
31155 + * Allocate memory for the base HCD plus the DWC OTG HCD.
31156 + * Initialize the base HCD.
31158 + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev,
31159 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
31160 + _dev->dev.bus_id);
31162 + dev_name(&_dev->dev));
31165 + retval = -ENOMEM;
31169 + hcd->regs = otg_dev->base;
31171 + /* Initialize the DWC OTG HCD. */
31172 + dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
31173 + if (!dwc_otg_hcd) {
31176 + ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
31178 + otg_dev->hcd = dwc_otg_hcd;
31180 + if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
31184 + hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
31187 + * Finish generic HCD initialization and start the HCD. This function
31188 + * allocates the DMA buffer pool, registers the USB bus, requests the
31189 + * IRQ line, and calls hcd_start method.
31191 +#ifdef PLATFORM_INTERFACE
31192 + retval = usb_add_hcd(hcd, platform_get_irq(_dev, 0), IRQF_SHARED);
31194 + retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED);
31196 + if (retval < 0) {
31200 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
31204 + usb_put_hcd(hcd);
31210 + * Removes the HCD.
31211 + * Frees memory and resources associated with the HCD and deregisters the bus.
31214 +#ifdef LM_INTERFACE
31215 + struct lm_device *_dev
31216 +#elif defined(PCI_INTERFACE)
31217 + struct pci_dev *_dev
31218 +#elif defined(PLATFORM_INTERFACE)
31219 + struct platform_device *_dev
31223 +#ifdef LM_INTERFACE
31224 + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
31225 +#elif defined(PCI_INTERFACE)
31226 + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
31227 +#elif defined(PLATFORM_INTERFACE)
31228 + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
31231 + dwc_otg_hcd_t *dwc_otg_hcd;
31232 + struct usb_hcd *hcd;
31234 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE otg_dev=%p\n", otg_dev);
31237 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
31241 + dwc_otg_hcd = otg_dev->hcd;
31243 + if (!dwc_otg_hcd) {
31244 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
31248 + hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
31251 + DWC_DEBUGPL(DBG_ANY,
31252 + "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
31256 + usb_remove_hcd(hcd);
31257 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
31258 + dwc_otg_hcd_remove(dwc_otg_hcd);
31259 + usb_put_hcd(hcd);
31262 +/* =========================================================================
31263 + * Linux HC Driver Functions
31264 + * ========================================================================= */
31266 +/** Initializes the DWC_otg controller and its root hub and prepares it for host
31267 + * mode operation. Activates the root port. Returns 0 on success and a negative
31268 + * error code on failure. */
31269 +int hcd_start(struct usb_hcd *hcd)
31271 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
31272 + struct usb_bus *bus;
31274 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
31275 + bus = hcd_to_bus(hcd);
31277 + hcd->state = HC_STATE_RUNNING;
31278 + if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
31282 + /* Initialize and connect root hub if one is not already attached */
31283 + if (bus->root_hub) {
31284 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
31285 + /* Inform the HUB driver to resume. */
31286 + usb_hcd_resume_root_hub(hcd);
31293 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
31296 +void hcd_stop(struct usb_hcd *hcd)
31298 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
31300 + dwc_otg_hcd_stop(dwc_otg_hcd);
31303 +/** Returns the current frame number. */
31304 +static int get_frame_number(struct usb_hcd *hcd)
31306 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
31308 + return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
31312 +static void dump_urb_info(struct urb *urb, char *fn_name)
31314 + DWC_PRINTF("%s, urb %p\n", fn_name, urb);
31315 + DWC_PRINTF(" Device address: %d\n", usb_pipedevice(urb->pipe));
31316 + DWC_PRINTF(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
31317 + (usb_pipein(urb->pipe) ? "IN" : "OUT"));
31318 + DWC_PRINTF(" Endpoint type: %s\n", ( {
31320 + switch (usb_pipetype(urb->pipe)) {
31321 +case PIPE_CONTROL:
31322 +pipetype = "CONTROL"; break; case PIPE_BULK:
31323 +pipetype = "BULK"; break; case PIPE_INTERRUPT:
31324 +pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
31325 +pipetype = "ISOCHRONOUS"; break; default:
31326 + pipetype = "UNKNOWN"; break;};
31329 + DWC_PRINTF(" Speed: %s\n", ( {
31330 + char *speed; switch (urb->dev->speed) {
31331 +case USB_SPEED_HIGH:
31332 +speed = "HIGH"; break; case USB_SPEED_FULL:
31333 +speed = "FULL"; break; case USB_SPEED_LOW:
31334 +speed = "LOW"; break; default:
31335 + speed = "UNKNOWN"; break;};
31338 + DWC_PRINTF(" Max packet size: %d\n",
31339 + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
31340 + DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length);
31341 + DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n",
31342 + urb->transfer_buffer, (void *)urb->transfer_dma);
31343 + DWC_PRINTF(" Setup buffer: %p, Setup DMA: %p\n",
31344 + urb->setup_packet, (void *)urb->setup_dma);
31345 + DWC_PRINTF(" Interval: %d\n", urb->interval);
31346 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
31348 + for (i = 0; i < urb->number_of_packets; i++) {
31349 + DWC_PRINTF(" ISO Desc %d:\n", i);
31350 + DWC_PRINTF(" offset: %d, length %d\n",
31351 + urb->iso_frame_desc[i].offset,
31352 + urb->iso_frame_desc[i].length);
31359 +/** Starts processing a USB transfer request specified by a USB Request Block
31360 + * (URB). mem_flags indicates the type of memory allocation to use while
31361 + * processing this URB. */
31362 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
31363 +static int urb_enqueue(struct usb_hcd *hcd,
31364 + struct usb_host_endpoint *ep,
31365 + struct urb *urb, gfp_t mem_flags)
31368 +static int urb_enqueue(struct usb_hcd *hcd,
31372 + struct usb_host_endpoint *ep = urb->ep;
31374 + void **ref_ep_hcpriv = &ep->hcpriv;
31376 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
31377 + dwc_otg_hcd_urb_t *dwc_otg_urb;
31379 + int alloc_bandwidth = 0;
31380 + uint8_t ep_type = 0;
31381 + uint32_t flags = 0;
31385 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
31386 + dump_urb_info(urb, "urb_enqueue");
31390 + if (!urb->transfer_buffer && urb->transfer_buffer_length)
31393 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
31394 + || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
31395 + if (!dwc_otg_hcd_is_bandwidth_allocated
31396 + (dwc_otg_hcd, ref_ep_hcpriv)) {
31397 + alloc_bandwidth = 1;
31401 + switch (usb_pipetype(urb->pipe)) {
31402 + case PIPE_CONTROL:
31403 + ep_type = USB_ENDPOINT_XFER_CONTROL;
31405 + case PIPE_ISOCHRONOUS:
31406 + ep_type = USB_ENDPOINT_XFER_ISOC;
31409 + ep_type = USB_ENDPOINT_XFER_BULK;
31411 + case PIPE_INTERRUPT:
31412 + ep_type = USB_ENDPOINT_XFER_INT;
31415 + DWC_WARN("Wrong ep type\n");
31418 + dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
31419 + urb->number_of_packets,
31420 + mem_flags == GFP_ATOMIC ? 1 : 0);
31422 + urb->hcpriv = dwc_otg_urb;
31424 + dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
31425 + usb_pipeendpoint(urb->pipe), ep_type,
31426 + usb_pipein(urb->pipe),
31427 + usb_maxpacket(urb->dev, urb->pipe,
31428 + !(usb_pipein(urb->pipe))));
31430 + buf = urb->transfer_buffer;
31431 + if (hcd->self.uses_dma) {
31433 + * Calculate virtual address from physical address,
31434 + * because some class driver may not fill transfer_buffer.
31435 + * In Buffer DMA mode virual address is used,
31436 + * when handling non DWORD aligned buffers.
31438 + //buf = phys_to_virt(urb->transfer_dma);
31439 + // DMA addresses are bus addresses not physical addresses!
31440 + buf = dma_to_virt(&urb->dev->dev, urb->transfer_dma);
31443 + if (!(urb->transfer_flags & URB_NO_INTERRUPT))
31444 + flags |= URB_GIVEBACK_ASAP;
31445 + if (urb->transfer_flags & URB_ZERO_PACKET)
31446 + flags |= URB_SEND_ZERO_PACKET;
31448 + dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
31449 + urb->transfer_dma,
31450 + urb->transfer_buffer_length,
31451 + urb->setup_packet,
31456 + for (i = 0; i < urb->number_of_packets; ++i) {
31457 + dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
31458 + urb->iso_frame_desc[i].
31460 + urb->iso_frame_desc[i].
31464 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
31465 + retval = usb_hcd_link_urb_to_ep(hcd, urb);
31469 + retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
31470 + /*(dwc_otg_qh_t **)*/
31472 + if (0 == retval) {
31473 + if (alloc_bandwidth) {
31474 + allocate_bus_bandwidth(hcd,
31475 + dwc_otg_hcd_get_ep_bandwidth(
31476 + dwc_otg_hcd, *ref_ep_hcpriv),
31480 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
31481 + usb_hcd_unlink_urb_from_ep(hcd, urb);
31483 + if (retval == -DWC_E_NO_DEVICE) {
31484 + retval = -ENODEV;
31491 +/** Aborts/cancels a USB transfer request. Always returns 0 to indicate
31493 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
31494 +static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
31496 +static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
31499 + dwc_otg_hcd_t *dwc_otg_hcd;
31500 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
31502 + dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
31505 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
31506 + dump_urb_info(urb, "urb_dequeue");
31509 + dwc_otg_hcd_urb_dequeue(dwc_otg_hcd, (dwc_otg_hcd_urb_t *)urb->hcpriv);
31511 + dwc_free(urb->hcpriv);
31512 + urb->hcpriv = NULL;
31514 + /* Higher layer software sets URB status. */
31515 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
31516 + usb_hcd_giveback_urb(hcd, urb);
31518 + usb_hcd_unlink_urb_from_ep(hcd, urb);
31519 + usb_hcd_giveback_urb(hcd, urb, status);
31521 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
31522 + DWC_PRINTF("Called usb_hcd_giveback_urb()\n");
31523 + DWC_PRINTF(" urb->status = %d\n", urb->status);
31529 +/* Frees resources in the DWC_otg controller related to a given endpoint. Also
31530 + * clears state in the HCD related to the endpoint. Any URBs for the endpoint
31531 + * must already be dequeued. */
31532 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
31534 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
31536 + DWC_DEBUGPL(DBG_HCD,
31537 + "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
31538 + "endpoint=%d\n", ep->desc.bEndpointAddress,
31539 + dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
31540 + dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
31541 + ep->hcpriv = NULL;
31544 +/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
31545 + * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
31548 + * This function is called by the USB core when an interrupt occurs */
31549 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
31551 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
31552 + int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
31553 + if (retval != 0) {
31554 + S3C2410X_CLEAR_EINTPEND();
31556 + return IRQ_RETVAL(retval);
31559 +/** Creates Status Change bitmap for the root hub and root port. The bitmap is
31560 + * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
31561 + * is the status change indicator for the single root port. Returns 1 if either
31562 + * change indicator is 1, otherwise returns 0. */
31563 +int hub_status_data(struct usb_hcd *hcd, char *buf)
31565 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
31568 + buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
31570 + return (buf[0] != 0);
31573 +/** Handles hub class-specific requests. */
31574 +int hub_control(struct usb_hcd *hcd,
31575 + u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
31579 + retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
31580 + typeReq, wValue, wIndex, buf, wLength);
31582 + switch (retval) {
31583 + case -DWC_E_INVALID:
31584 + retval = -EINVAL;
31591 +#endif /* DWC_DEVICE_ONLY */
31593 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
31595 +/* ==========================================================================
31596 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
31597 + * $Revision: #39 $
31598 + * $Date: 2009/04/21 $
31599 + * $Change: 1237477 $
31601 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
31602 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
31603 + * otherwise expressly agreed to in writing between Synopsys and you.
31605 + * The Software IS NOT an item of Licensed Software or Licensed Product under
31606 + * any End User Software License Agreement or Agreement for Licensed Product
31607 + * with Synopsys or any supplement thereto. You are permitted to use and
31608 + * redistribute this Software in source and binary forms, with or without
31609 + * modification, provided that redistributions of source code must retain this
31610 + * notice. You may not view, use, disclose, copy or distribute this file or
31611 + * any information contained herein except pursuant to this license grant from
31612 + * Synopsys. If you do not agree with this notice, including the disclaimer
31613 + * below, then you are not authorized to use the Software.
31615 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
31616 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31617 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31618 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
31619 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31620 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31621 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31622 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31623 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31624 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31626 + * ========================================================================== */
31627 +#ifndef DWC_DEVICE_ONLY
31632 + * This file contains the functions to manage Queue Heads and Queue
31633 + * Transfer Descriptors.
31636 +#include "dwc_otg_hcd.h"
31637 +#include "dwc_otg_regs.h"
31640 + * Free each QTD in the QH's QTD-list then free the QH. QH should already be
31641 + * removed from a list. QTD list should already be empty if called from URB
31644 + * @param hcd HCD instance.
31645 + * @param qh The QH to free.
31647 +void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
31649 + dwc_otg_qtd_t *qtd, *qtd_tmp;
31652 + /* Free each QTD in the QTD list */
31653 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
31654 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
31655 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
31656 + dwc_otg_hcd_qtd_free(qtd);
31658 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
31660 + if (hcd->core_if->dma_desc_enable) {
31661 + dwc_otg_hcd_qh_free_ddma(hcd, qh);
31663 + else if (qh->dw_align_buf) {
31664 + uint32_t buf_size;
31665 + if(qh->ep_type == UE_ISOCHRONOUS) {
31668 + buf_size = hcd->core_if->core_params->max_transfer_size;
31670 + dwc_dma_free(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
31679 +#define BitStuffTime(bytecount) ((8 * 7* bytecount) / 6)
31680 +#define HS_HOST_DELAY 5 /* nanoseconds */
31681 +#define FS_LS_HOST_DELAY 1000 /* nanoseconds */
31682 +#define HUB_LS_SETUP 333 /* nanoseconds */
31683 +#define NS_TO_US(ns) ((ns + 500) / 1000)
31684 + /* convert & round nanoseconds to microseconds */
31686 +static uint32_t calc_bus_time(int speed, int is_in, int is_isoc,
31689 + unsigned long retval;
31692 + case USB_SPEED_HIGH:
31695 + ((38 * 8 * 2083) +
31696 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
31700 + ((55 * 8 * 2083) +
31701 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
31705 + case USB_SPEED_FULL:
31708 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
31710 + retval = 7268 + FS_LS_HOST_DELAY + retval;
31712 + retval = 6265 + FS_LS_HOST_DELAY + retval;
31716 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
31717 + retval = 9107 + FS_LS_HOST_DELAY + retval;
31720 + case USB_SPEED_LOW:
31723 + (67667 * (31 + 10 * BitStuffTime(bytecount))) /
31726 + 64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
31730 + (66700 * (31 + 10 * BitStuffTime(bytecount))) /
31733 + 64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
31738 + DWC_WARN("Unknown device speed\n");
31742 + return NS_TO_US(retval);
31746 + * Initializes a QH structure.
31748 + * @param hcd The HCD state structure for the DWC OTG controller.
31749 + * @param qh The QH to init.
31750 + * @param urb Holds the information about the device/endpoint that we need
31751 + * to initialize the QH.
31753 +#define SCHEDULE_SLOP 10
31754 +void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
31755 + dwc_otg_hcd_urb_t * urb)
31757 + char *speed, *type;
31759 + uint32_t hub_addr, hub_port;
31761 + dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
31763 + /* Initialize QH */
31764 + qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
31766 + qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
31768 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
31769 + qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
31770 + DWC_CIRCLEQ_INIT(&qh->qtd_list);
31771 + DWC_LIST_INIT(&qh->qh_list_entry);
31772 + qh->channel = NULL;
31774 + /* FS/LS Enpoint on HS Hub
31775 + * NOT virtual root hub */
31776 + dev_speed = hcd->fops->speed(hcd, urb->priv);
31777 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
31778 + qh->do_split = 0;
31779 + if (((dev_speed == USB_SPEED_LOW) ||
31780 + (dev_speed == USB_SPEED_FULL)) &&
31781 + (hub_addr != 0 && hub_addr != 1)) {
31783 + DWC_DEBUGPL(DBG_HCD,
31784 + "QH init: EP %d: TT found at hub addr %d, for port %d\n",
31785 + dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
31788 + qh->do_split = 1;
31791 + if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
31792 + /* Compute scheduling parameters once and save them. */
31793 + hprt0_data_t hprt;
31795 + /** @todo Account for split transfers in the bus time. */
31797 + dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
31799 + qh->usecs = calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
31801 + (qh->ep_type == UE_ISOCHRONOUS),
31803 + /* Start in a slightly future (micro)frame. */
31804 + qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
31806 + qh->interval = urb->interval;
31809 + /* Increase interrupt polling rate for debugging. */
31810 + if (qh->ep_type == UE_INTERRUPT) {
31811 + qh->interval = 8;
31814 + hprt.d32 = dwc_read_reg32(hcd->core_if->host_if->hprt0);
31815 + if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
31816 + ((dev_speed == USB_SPEED_LOW) ||
31817 + (dev_speed == USB_SPEED_FULL))) {
31818 + qh->interval *= 8;
31819 + qh->sched_frame |= 0x7;
31820 + qh->start_split_frame = qh->sched_frame;
31825 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
31826 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", qh);
31827 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n",
31828 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
31829 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n",
31830 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
31831 + dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
31832 + switch (dev_speed) {
31833 + case USB_SPEED_LOW:
31834 + qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
31837 + case USB_SPEED_FULL:
31838 + qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
31841 + case USB_SPEED_HIGH:
31842 + qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
31849 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", speed);
31851 + switch (qh->ep_type) {
31852 + case UE_ISOCHRONOUS:
31853 + type = "isochronous";
31855 + case UE_INTERRUPT:
31856 + type = "interrupt";
31859 + type = "control";
31869 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", type);
31872 + if (qh->ep_type == UE_INTERRUPT) {
31873 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
31875 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
31883 + * This function allocates and initializes a QH.
31885 + * @param hcd The HCD state structure for the DWC OTG controller.
31886 + * @param urb Holds the information about the device/endpoint that we need
31887 + * to initialize the QH.
31889 + * @return Returns pointer to the newly allocated QH, or NULL on error. */
31890 +dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
31891 + dwc_otg_hcd_urb_t * urb)
31893 + dwc_otg_qh_t *qh;
31895 + /* Allocate memory */
31896 + /** @todo add memflags argument */
31897 + qh = dwc_otg_hcd_qh_alloc();
31898 + if (qh == NULL) {
31902 + qh_init(hcd, qh, urb);
31904 + if (hcd->core_if->dma_desc_enable && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
31905 + dwc_otg_hcd_qh_free(hcd, qh);
31913 + * Checks that a channel is available for a periodic transfer.
31915 + * @return 0 if successful, negative error code otherise.
31917 +static int periodic_channel_available(dwc_otg_hcd_t * hcd)
31920 + * Currently assuming that there is a dedicated host channnel for each
31921 + * periodic transaction plus at least one host channel for
31922 + * non-periodic transactions.
31925 + int num_channels;
31927 + num_channels = hcd->core_if->core_params->host_channels;
31928 + if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels) &&
31929 + (hcd->periodic_channels < num_channels - 1)) {
31932 + DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
31933 + __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels); //NOTICE
31934 + status = -DWC_E_NO_SPACE;
31941 + * Checks that there is sufficient bandwidth for the specified QH in the
31942 + * periodic schedule. For simplicity, this calculation assumes that all the
31943 + * transfers in the periodic schedule may occur in the same (micro)frame.
31945 + * @param hcd The HCD state structure for the DWC OTG controller.
31946 + * @param qh QH containing periodic bandwidth required.
31948 + * @return 0 if successful, negative error code otherwise.
31950 +static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
31953 + int16_t max_claimed_usecs;
31957 + if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
31959 + * High speed mode.
31960 + * Max periodic usecs is 80% x 125 usec = 100 usec.
31963 + max_claimed_usecs = 100 - qh->usecs;
31966 + * Full speed mode.
31967 + * Max periodic usecs is 90% x 1000 usec = 900 usec.
31969 + max_claimed_usecs = 900 - qh->usecs;
31972 + if (hcd->periodic_usecs > max_claimed_usecs) {
31973 + DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs); //NOTICE
31974 + status = -DWC_E_NO_SPACE;
31981 + * Checks that the max transfer size allowed in a host channel is large enough
31982 + * to handle the maximum data transfer in a single (micro)frame for a periodic
31985 + * @param hcd The HCD state structure for the DWC OTG controller.
31986 + * @param qh QH for a periodic endpoint.
31988 + * @return 0 if successful, negative error code otherwise.
31990 +static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
31993 + uint32_t max_xfer_size;
31994 + uint32_t max_channel_xfer_size;
31998 + max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
31999 + max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
32001 + if (max_xfer_size > max_channel_xfer_size) {
32002 + DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
32003 + __func__, max_xfer_size, max_channel_xfer_size); //NOTICE
32004 + status = -DWC_E_NO_SPACE;
32011 + * Schedules an interrupt or isochronous transfer in the periodic schedule.
32013 + * @param hcd The HCD state structure for the DWC OTG controller.
32014 + * @param qh QH for the periodic transfer. The QH should already contain the
32015 + * scheduling information.
32017 + * @return 0 if successful, negative error code otherwise.
32019 +static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
32023 + status = periodic_channel_available(hcd);
32025 + DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE
32029 + status = check_periodic_bandwidth(hcd, qh);
32031 + DWC_INFO("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__); //NOTICE
32035 + status = check_max_xfer_size(hcd, qh);
32037 + DWC_INFO("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__); //NOTICE
32041 + if (hcd->core_if->dma_desc_enable) {
32042 + /* Don't rely on SOF and start in ready schedule */
32043 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
32046 + /* Always start in the inactive schedule. */
32047 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
32050 + /* Reserve the periodic channel. */
32051 + hcd->periodic_channels++;
32053 + /* Update claimed usecs per (micro)frame. */
32054 + hcd->periodic_usecs += qh->usecs;
32060 + * This function adds a QH to either the non periodic or periodic schedule if
32061 + * it is not already in the schedule. If the QH is already in the schedule, no
32062 + * action is taken.
32064 + * @return 0 if successful, negative error code otherwise.
32066 +int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
32071 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
32073 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
32074 + /* QH already in a schedule. */
32078 + /* Add the new QH to the appropriate schedule */
32079 + if (dwc_qh_is_non_per(qh)) {
32080 + /* Always start in the inactive schedule. */
32081 + DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
32082 + &qh->qh_list_entry);
32084 + status = schedule_periodic(hcd, qh);
32088 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
32094 + * Removes an interrupt or isochronous transfer from the periodic schedule.
32096 + * @param hcd The HCD state structure for the DWC OTG controller.
32097 + * @param qh QH for the periodic transfer.
32099 +static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
32101 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
32103 + /* Release the periodic channel reservation. */
32104 + hcd->periodic_channels--;
32106 + /* Update claimed usecs per (micro)frame. */
32107 + hcd->periodic_usecs -= qh->usecs;
32111 + * Removes a QH from either the non-periodic or periodic schedule. Memory is
32114 + * @param hcd The HCD state structure.
32115 + * @param qh QH to remove from schedule. */
32116 +void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
32119 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
32121 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
32122 + /* QH is not in a schedule. */
32126 + if (dwc_qh_is_non_per(qh)) {
32127 + if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
32128 + hcd->non_periodic_qh_ptr =
32129 + hcd->non_periodic_qh_ptr->next;
32131 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
32133 + deschedule_periodic(hcd, qh);
32137 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
32141 + * Deactivates a QH. For non-periodic QHs, removes the QH from the active
32142 + * non-periodic schedule. The QH is added to the inactive non-periodic
32143 + * schedule if any QTDs are still attached to the QH.
32145 + * For periodic QHs, the QH is removed from the periodic queued schedule. If
32146 + * there are any QTDs still attached to the QH, the QH is added to either the
32147 + * periodic inactive schedule or the periodic ready schedule and its next
32148 + * scheduled frame is calculated. The QH is placed in the ready schedule if
32149 + * the scheduled frame has been reached already. Otherwise it's placed in the
32150 + * inactive schedule. If there are no QTDs attached to the QH, the QH is
32151 + * completely removed from the periodic schedule.
32153 +void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
32154 + int sched_next_periodic_split)
32157 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
32159 + if (dwc_qh_is_non_per(qh)) {
32160 + dwc_otg_hcd_qh_remove(hcd, qh);
32161 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
32162 + /* Add back to inactive non-periodic schedule. */
32163 + dwc_otg_hcd_qh_add(hcd, qh);
32166 + uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
32168 + if (qh->do_split) {
32169 + /* Schedule the next continuing periodic split transfer */
32170 + if (sched_next_periodic_split) {
32172 + qh->sched_frame = frame_number;
32173 + if (dwc_frame_num_le(frame_number,
32174 + dwc_frame_num_inc(qh->
32175 + start_split_frame,
32178 + * Allow one frame to elapse after start
32179 + * split microframe before scheduling
32180 + * complete split, but DONT if we are
32181 + * doing the next start split in the
32182 + * same frame for an ISOC out.
32184 + if ((qh->ep_type != UE_ISOCHRONOUS) ||
32185 + (qh->ep_is_in != 0)) {
32186 + qh->sched_frame =
32187 + dwc_frame_num_inc(qh->sched_frame, 1);
32191 + qh->sched_frame =
32192 + dwc_frame_num_inc(qh->start_split_frame,
32194 + if (dwc_frame_num_le
32195 + (qh->sched_frame, frame_number)) {
32196 + qh->sched_frame = frame_number;
32198 + qh->sched_frame |= 0x7;
32199 + qh->start_split_frame = qh->sched_frame;
32202 + qh->sched_frame =
32203 + dwc_frame_num_inc(qh->sched_frame, qh->interval);
32204 + if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
32205 + qh->sched_frame = frame_number;
32209 + if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
32210 + dwc_otg_hcd_qh_remove(hcd, qh);
32213 + * Remove from periodic_sched_queued and move to
32214 + * appropriate queue.
32216 + if (qh->sched_frame == frame_number) {
32217 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
32218 + &qh->qh_list_entry);
32220 + DWC_LIST_MOVE_HEAD(&hcd->
32221 + periodic_sched_inactive,
32222 + &qh->qh_list_entry);
32227 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
32231 + * This function allocates and initializes a QTD.
32233 + * @param urb The URB to create a QTD from. Each URB-QTD pair will end up
32234 + * pointing to each other so each pair should have a unique correlation.
32236 + * @return Returns pointer to the newly allocated QTD, or NULL on error. */
32237 +dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb)
32239 + dwc_otg_qtd_t *qtd;
32241 + qtd = dwc_otg_hcd_qtd_alloc();
32242 + if (qtd == NULL) {
32246 + dwc_otg_hcd_qtd_init(qtd, urb);
32251 + * Initializes a QTD structure.
32253 + * @param qtd The QTD to initialize.
32254 + * @param urb The URB to use for initialization. */
32255 +void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
32257 + dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
32259 + if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
32261 + * The only time the QTD data toggle is used is on the data
32262 + * phase of control transfers. This phase always starts with
32265 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
32266 + qtd->control_phase = DWC_OTG_CONTROL_SETUP;
32269 + /* start split */
32270 + qtd->complete_split = 0;
32271 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
32272 + qtd->isoc_split_offset = 0;
32273 + qtd->in_process = 0;
32275 + /* Store the qtd ptr in the urb to reference what QTD. */
32281 + * This function adds a QTD to the QTD-list of a QH. It will find the correct
32282 + * QH to place the QTD into. If it does not find a QH, then it will create a
32283 + * new QH. If the QH to which the QTD is added is not currently scheduled, it
32284 + * is placed into the proper schedule based on its EP type.
32286 + * @param[in] qtd The QTD to add
32287 + * @param[in] hcd The DWC HCD structure
32288 + * @param[out] qh out parameter to return queue head
32290 + * @return 0 if successful, negative error code otherwise.
32292 +int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
32293 + dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh)
32298 + dwc_otg_hcd_urb_t *urb = qtd->urb;
32300 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
32303 + * Get the QH which holds the QTD-list to insert to. Create QH if it
32306 + if (*qh == NULL) {
32307 + *qh = dwc_otg_hcd_qh_create(hcd, urb);
32308 + if (*qh == NULL) {
32314 + retval = dwc_otg_hcd_qh_add(hcd, *qh);
32315 + if (retval == 0) {
32316 + DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
32321 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
32326 +#endif /* DWC_DEVICE_ONLY */
32328 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.c
32330 +/* ==========================================================================
32331 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
32332 + * $Revision: #79 $
32333 + * $Date: 2009/04/10 $
32334 + * $Change: 1230501 $
32336 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
32337 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
32338 + * otherwise expressly agreed to in writing between Synopsys and you.
32340 + * The Software IS NOT an item of Licensed Software or Licensed Product under
32341 + * any End User Software License Agreement or Agreement for Licensed Product
32342 + * with Synopsys or any supplement thereto. You are permitted to use and
32343 + * redistribute this Software in source and binary forms, with or without
32344 + * modification, provided that redistributions of source code must retain this
32345 + * notice. You may not view, use, disclose, copy or distribute this file or
32346 + * any information contained herein except pursuant to this license grant from
32347 + * Synopsys. If you do not agree with this notice, including the disclaimer
32348 + * below, then you are not authorized to use the Software.
32350 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
32351 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32352 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32353 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
32354 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32355 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32356 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32357 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32358 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32359 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32361 + * ========================================================================== */
32362 +#ifndef DWC_HOST_ONLY
32365 + * This file implements PCD Core. All code in this file is portable and don't
32366 + * use any OS specific functions.
32367 + * PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code>
32368 + * header file, which can be used to implement OS specific PCD interface.
32370 + * An important function of the PCD is managing interrupts generated
32371 + * by the DWC_otg controller. The implementation of the DWC_otg device
32372 + * mode interrupt service routines is in dwc_otg_pcd_intr.c.
32374 + * @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
32375 + * @todo Does it work when the request size is greater than DEPTSIZ
32380 +#include "dwc_otg_pcd.h"
32382 +#ifdef DWC_UTE_CFI
32383 +#include "dwc_otg_cfi.h"
32385 +extern int init_cfi(cfiobject_t * cfiobj);
32388 +static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
32391 + if (pcd->ep0.priv == handle) {
32392 + return &pcd->ep0;
32394 + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
32395 + if (pcd->in_ep[i].priv == handle)
32396 + return &pcd->in_ep[i];
32397 + if (pcd->out_ep[i].priv == handle)
32398 + return &pcd->out_ep[i];
32405 + * This function completes a request. It call's the request call back.
32407 +void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req,
32410 + unsigned stopped = ep->stopped;
32412 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, ep);
32413 + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
32415 + /* don't modify queue heads during completion callback */
32417 + DWC_SPINUNLOCK(ep->pcd->lock);
32418 + ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status,
32420 + DWC_SPINLOCK(ep->pcd->lock);
32422 + if (ep->pcd->request_pending > 0) {
32423 + --ep->pcd->request_pending;
32426 + ep->stopped = stopped;
32431 + * This function terminates all the requsts in the EP request queue.
32433 +void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep)
32435 + dwc_otg_pcd_request_t *req;
32439 + /* called with irqs blocked?? */
32440 + while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
32441 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
32442 + dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN);
32446 +void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
32447 + const struct dwc_otg_pcd_function_ops *fops)
32449 + pcd->fops = fops;
32453 + * PCD Callback function for initializing the PCD when switching to
32456 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
32458 +static int32_t dwc_otg_pcd_start_cb(void *p)
32460 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
32463 + * Initialized the Core for Device mode.
32465 + if (dwc_otg_is_device_mode(GET_CORE_IF(pcd))) {
32466 + dwc_otg_core_dev_init(GET_CORE_IF(pcd));
32471 +/** CFI-specific buffer allocation function for EP */
32472 +#ifdef DWC_UTE_CFI
32473 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
32474 + size_t buflen, int flags)
32476 + dwc_otg_pcd_ep_t *ep;
32477 + ep = get_ep_from_handle(pcd, pep);
32478 + return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen,
32482 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
32483 + size_t buflen, int flags);
32487 + * PCD Callback function for notifying the PCD when resuming from
32490 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
32492 +static int32_t dwc_otg_pcd_resume_cb(void *p)
32494 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
32496 + if (pcd->fops->resume) {
32497 + pcd->fops->resume(pcd);
32500 + /* Stop the SRP timeout timer. */
32501 + if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS)
32502 + || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {
32503 + if (GET_CORE_IF(pcd)->srp_timer_started) {
32504 + GET_CORE_IF(pcd)->srp_timer_started = 0;
32505 + DWC_TIMER_CANCEL(pcd->srp_timer);
32512 + * PCD Callback function for notifying the PCD device is suspended.
32514 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
32516 +static int32_t dwc_otg_pcd_suspend_cb(void *p)
32518 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
32520 + if (pcd->fops->suspend) {
32521 + pcd->fops->suspend(pcd);
32528 + * PCD Callback function for stopping the PCD when switching to Host
32531 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
32533 +static int32_t dwc_otg_pcd_stop_cb(void *p)
32535 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
32536 + extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);
32538 + dwc_otg_pcd_stop(pcd);
32543 + * PCD Callback structure for handling mode switching.
32545 +static dwc_otg_cil_callbacks_t pcd_callbacks = {
32546 + .start = dwc_otg_pcd_start_cb,
32547 + .stop = dwc_otg_pcd_stop_cb,
32548 + .suspend = dwc_otg_pcd_suspend_cb,
32549 + .resume_wakeup = dwc_otg_pcd_resume_cb,
32550 + .p = 0, /* Set at registration */
32554 + * This function allocates a DMA Descriptor chain for the Endpoint
32555 + * buffer to be used for a transfer to/from the specified endpoint.
32557 +dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(uint32_t * dma_desc_addr,
32561 + return dwc_dma_alloc(count * sizeof(dwc_otg_dev_dma_desc_t), dma_desc_addr);
32565 + * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc.
32567 +void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr,
32568 + uint32_t dma_desc_addr, uint32_t count)
32570 + dwc_dma_free(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr,
32574 +#ifdef DWC_EN_ISOC
32577 + * This function initializes a descriptor chain for Isochronous transfer
32579 + * @param core_if Programming view of DWC_otg controller.
32580 + * @param dwc_ep The EP to start the transfer on.
32583 +void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if,
32584 + dwc_ep_t * dwc_ep)
32587 + dsts_data_t dsts = {.d32 = 0 };
32588 + depctl_data_t depctl = {.d32 = 0 };
32589 + volatile uint32_t *addr;
32592 + if (dwc_ep->is_in)
32593 + dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;
32595 + dwc_ep->desc_cnt =
32596 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
32597 + dwc_ep->bInterval;
32599 + /** Allocate descriptors for double buffering */
32600 + dwc_ep->iso_desc_addr =
32601 + dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr,
32602 + dwc_ep->desc_cnt * 2);
32603 + if (dwc_ep->desc_addr) {
32604 + DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__);
32608 + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
32610 + /** ISO OUT EP */
32611 + if (dwc_ep->is_in == 0) {
32612 + dev_dma_desc_sts_t sts = {.d32 = 0 };
32613 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
32614 + dma_addr_t dma_ad;
32615 + uint32_t data_per_desc;
32616 + dwc_otg_dev_out_ep_regs_t *out_regs =
32617 + core_if->dev_if->out_ep_regs[dwc_ep->num];
32620 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
32621 + dma_ad = (dma_addr_t) dwc_read_reg32(&(out_regs->doepdma));
32623 + /** Buffer 0 descriptors setup */
32624 + dma_ad = dwc_ep->dma_addr0;
32626 + sts.b_iso_out.bs = BS_HOST_READY;
32627 + sts.b_iso_out.rxsts = 0;
32628 + sts.b_iso_out.l = 0;
32629 + sts.b_iso_out.sp = 0;
32630 + sts.b_iso_out.ioc = 0;
32631 + sts.b_iso_out.pid = 0;
32632 + sts.b_iso_out.framenum = 0;
32635 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
32636 + i += dwc_ep->pkt_per_frm) {
32638 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
32640 + ((j + 1) * dwc_ep->maxpacket >
32641 + dwc_ep->data_per_frame) ? dwc_ep->
32643 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
32646 + (data_per_desc % 4) ? (4 -
32649 + sts.b_iso_out.rxbytes = data_per_desc;
32650 + dma_desc->buf = dma_ad;
32651 + dma_desc->status.d32 = sts.d32;
32653 + offset += data_per_desc;
32655 + dma_ad += data_per_desc;
32659 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
32661 + ((j + 1) * dwc_ep->maxpacket >
32662 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
32663 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
32665 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
32666 + sts.b_iso_out.rxbytes = data_per_desc;
32667 + dma_desc->buf = dma_ad;
32668 + dma_desc->status.d32 = sts.d32;
32670 + offset += data_per_desc;
32672 + dma_ad += data_per_desc;
32675 + sts.b_iso_out.ioc = 1;
32677 + ((j + 1) * dwc_ep->maxpacket >
32678 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
32679 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
32681 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
32682 + sts.b_iso_out.rxbytes = data_per_desc;
32684 + dma_desc->buf = dma_ad;
32685 + dma_desc->status.d32 = sts.d32;
32688 + /** Buffer 1 descriptors setup */
32689 + sts.b_iso_out.ioc = 0;
32690 + dma_ad = dwc_ep->dma_addr1;
32693 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
32694 + i += dwc_ep->pkt_per_frm) {
32695 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
32697 + ((j + 1) * dwc_ep->maxpacket >
32698 + dwc_ep->data_per_frame) ? dwc_ep->
32700 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
32702 + (data_per_desc % 4) ? (4 -
32705 + sts.b_iso_out.rxbytes = data_per_desc;
32706 + dma_desc->buf = dma_ad;
32707 + dma_desc->status.d32 = sts.d32;
32709 + offset += data_per_desc;
32711 + dma_ad += data_per_desc;
32714 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
32716 + ((j + 1) * dwc_ep->maxpacket >
32717 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
32718 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
32720 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
32721 + sts.b_iso_out.rxbytes = data_per_desc;
32722 + dma_desc->buf = dma_ad;
32723 + dma_desc->status.d32 = sts.d32;
32725 + offset += data_per_desc;
32727 + dma_ad += data_per_desc;
32730 + sts.b_iso_out.ioc = 1;
32731 + sts.b_iso_out.l = 1;
32733 + ((j + 1) * dwc_ep->maxpacket >
32734 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
32735 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
32737 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
32738 + sts.b_iso_out.rxbytes = data_per_desc;
32740 + dma_desc->buf = dma_ad;
32741 + dma_desc->status.d32 = sts.d32;
32743 + dwc_ep->next_frame = 0;
32745 + /** Write dma_ad into DOEPDMA register */
32746 + dwc_write_reg32(&(out_regs->doepdma),
32747 + (uint32_t) dwc_ep->iso_dma_desc_addr);
32752 + dev_dma_desc_sts_t sts = {.d32 = 0 };
32753 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
32754 + dma_addr_t dma_ad;
32755 + dwc_otg_dev_in_ep_regs_t *in_regs =
32756 + core_if->dev_if->in_ep_regs[dwc_ep->num];
32757 + unsigned int frmnumber;
32758 + fifosize_data_t txfifosize, rxfifosize;
32761 + dwc_read_reg32(&core_if->dev_if->in_ep_regs[dwc_ep->num]->
32764 + dwc_read_reg32(&core_if->core_global_regs->grxfsiz);
32766 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
32768 + dma_ad = dwc_ep->dma_addr0;
32771 + dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
32773 + sts.b_iso_in.bs = BS_HOST_READY;
32774 + sts.b_iso_in.txsts = 0;
32775 + sts.b_iso_in.sp =
32776 + (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;
32777 + sts.b_iso_in.ioc = 0;
32778 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
32780 + frmnumber = dwc_ep->next_frame;
32782 + sts.b_iso_in.framenum = frmnumber;
32783 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
32784 + sts.b_iso_in.l = 0;
32786 + /** Buffer 0 descriptors setup */
32787 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
32788 + dma_desc->buf = dma_ad;
32789 + dma_desc->status.d32 = sts.d32;
32792 + dma_ad += dwc_ep->data_per_frame;
32793 + sts.b_iso_in.framenum += dwc_ep->bInterval;
32796 + sts.b_iso_in.ioc = 1;
32797 + dma_desc->buf = dma_ad;
32798 + dma_desc->status.d32 = sts.d32;
32801 + /** Buffer 1 descriptors setup */
32802 + sts.b_iso_in.ioc = 0;
32803 + dma_ad = dwc_ep->dma_addr1;
32805 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
32806 + i += dwc_ep->pkt_per_frm) {
32807 + dma_desc->buf = dma_ad;
32808 + dma_desc->status.d32 = sts.d32;
32811 + dma_ad += dwc_ep->data_per_frame;
32812 + sts.b_iso_in.framenum += dwc_ep->bInterval;
32814 + sts.b_iso_in.ioc = 0;
32816 + sts.b_iso_in.ioc = 1;
32817 + sts.b_iso_in.l = 1;
32819 + dma_desc->buf = dma_ad;
32820 + dma_desc->status.d32 = sts.d32;
32822 + dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval;
32824 + /** Write dma_ad into diepdma register */
32825 + dwc_write_reg32(&(in_regs->diepdma),
32826 + (uint32_t) dwc_ep->iso_dma_desc_addr);
32828 + /** Enable endpoint, clear nak */
32830 + depctl.b.epena = 1;
32831 + depctl.b.usbactep = 1;
32832 + depctl.b.cnak = 1;
32834 + dwc_modify_reg32(addr, depctl.d32, depctl.d32);
32835 + depctl.d32 = dwc_read_reg32(addr);
32839 + * This function initializes a descriptor chain for Isochronous transfer
32841 + * @param core_if Programming view of DWC_otg controller.
32842 + * @param ep The EP to start the transfer on.
32846 +void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
32849 + depctl_data_t depctl = {.d32 = 0 };
32850 + volatile uint32_t *addr;
32853 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
32855 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
32858 + if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) {
32861 + deptsiz_data_t deptsiz = {.d32 = 0 };
32864 + ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval;
32866 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
32867 + ep->xfer_count = 0;
32869 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
32871 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
32874 + /* Program the transfer size and packet count
32875 + * as follows: xfersize = N * maxpacket +
32876 + * short_packet pktcnt = N + (short_packet
32879 + deptsiz.b.mc = ep->pkt_per_frm;
32880 + deptsiz.b.xfersize = ep->xfer_len;
32881 + deptsiz.b.pktcnt =
32882 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
32883 + dwc_write_reg32(&core_if->dev_if->in_ep_regs[ep->num]->
32884 + dieptsiz, deptsiz.d32);
32886 + /* Write the DMA register */
32887 + dwc_write_reg32(&
32888 + (core_if->dev_if->in_ep_regs[ep->num]->
32889 + diepdma), (uint32_t) ep->dma_addr);
32892 + deptsiz.b.pktcnt =
32893 + (ep->xfer_len + (ep->maxpacket - 1)) /
32895 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
32897 + dwc_write_reg32(&core_if->dev_if->out_ep_regs[ep->num]->
32898 + doeptsiz, deptsiz.d32);
32900 + /* Write the DMA register */
32901 + dwc_write_reg32(&
32902 + (core_if->dev_if->out_ep_regs[ep->num]->
32903 + doepdma), (uint32_t) ep->dma_addr);
32906 + /** Enable endpoint, clear nak */
32908 + dwc_modify_reg32(addr, depctl.d32, depctl.d32);
32910 + depctl.b.epena = 1;
32911 + depctl.b.cnak = 1;
32913 + dwc_modify_reg32(addr, depctl.d32, depctl.d32);
32918 + * This function does the setup for a data transfer for an EP and
32919 + * starts the transfer. For an IN transfer, the packets will be
32920 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
32921 + * the packets are unloaded from the Rx FIFO in the ISR. the ISR.
32923 + * @param core_if Programming view of DWC_otg controller.
32924 + * @param ep The EP to start the transfer on.
32927 +static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if,
32930 + if (core_if->dma_enable) {
32931 + if (core_if->dma_desc_enable) {
32933 + ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm;
32935 + ep->desc_cnt = ep->pkt_cnt;
32937 + dwc_otg_iso_ep_start_ddma_transfer(core_if, ep);
32939 + if (core_if->pti_enh_enable) {
32940 + dwc_otg_iso_ep_start_buf_transfer(core_if, ep);
32942 + ep->cur_pkt_addr =
32943 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->
32945 + ep->cur_pkt_dma_addr =
32946 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->
32948 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
32952 + ep->cur_pkt_addr =
32953 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
32954 + ep->cur_pkt_dma_addr =
32955 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
32956 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
32961 + * This function does the setup for a data transfer for an EP and
32962 + * starts the transfer. For an IN transfer, the packets will be
32963 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
32964 + * the packets are unloaded from the Rx FIFO in the ISR. the ISR.
32966 + * @param core_if Programming view of DWC_otg controller.
32967 + * @param ep The EP to start the transfer on.
32970 +void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
32972 + depctl_data_t depctl = {.d32 = 0 };
32973 + volatile uint32_t *addr;
32975 + if (ep->is_in == 1) {
32976 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
32978 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
32981 + /* disable the ep */
32982 + depctl.d32 = dwc_read_reg32(addr);
32984 + depctl.b.epdis = 1;
32985 + depctl.b.snak = 1;
32987 + dwc_write_reg32(addr, depctl.d32);
32989 + if (core_if->dma_desc_enable &&
32990 + ep->iso_desc_addr && ep->iso_dma_desc_addr) {
32991 + dwc_otg_ep_free_desc_chain(ep->iso_desc_addr,
32992 + ep->iso_dma_desc_addr,
32993 + ep->desc_cnt * 2);
32996 + /* reset varibales */
32997 + ep->dma_addr0 = 0;
32998 + ep->dma_addr1 = 0;
32999 + ep->xfer_buff0 = 0;
33000 + ep->xfer_buff1 = 0;
33001 + ep->data_per_frame = 0;
33002 + ep->data_pattern_frame = 0;
33003 + ep->sync_frame = 0;
33004 + ep->buf_proc_intrvl = 0;
33005 + ep->bInterval = 0;
33006 + ep->proc_buf_num = 0;
33007 + ep->pkt_per_frm = 0;
33008 + ep->pkt_per_frm = 0;
33009 + ep->desc_cnt = 0;
33010 + ep->iso_desc_addr = 0;
33011 + ep->iso_dma_desc_addr = 0;
33014 +int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
33015 + uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0,
33016 + dwc_dma_t dma1, int sync_frame, int dp_frame,
33017 + int data_per_frame, int start_frame,
33018 + int buf_proc_intrvl, void *req_handle,
33019 + int atomic_alloc)
33021 + dwc_otg_pcd_ep_t *ep;
33022 + uint64_t flags = 0;
33023 + dwc_ep_t *dwc_ep;
33024 + int32_t frm_data;
33025 + dsts_data_t dsts;
33026 + dwc_otg_core_if_t *core_if;
33028 + ep = get_ep_from_handle(pcd, ep_handle);
33030 + if (!ep->desc || ep->dwc_ep.num == 0) {
33031 + DWC_WARN("bad ep\n");
33032 + return -DWC_E_INVALID;
33035 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
33036 + core_if = GET_CORE_IF(pcd);
33037 + dwc_ep = &ep->dwc_ep;
33039 + if (ep->iso_req_handle) {
33040 + DWC_WARN("ISO request in progress\n");
33043 + dwc_ep->dma_addr0 = dma0;
33044 + dwc_ep->dma_addr1 = dma1;
33046 + dwc_ep->xfer_buff0 = buf0;
33047 + dwc_ep->xfer_buff1 = buf1;
33049 + dwc_ep->data_per_frame = data_per_frame;
33051 + /** @todo - pattern data support is to be implemented in the future */
33052 + dwc_ep->data_pattern_frame = dp_frame;
33053 + dwc_ep->sync_frame = sync_frame;
33055 + dwc_ep->buf_proc_intrvl = buf_proc_intrvl;
33057 + dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);
33059 + dwc_ep->proc_buf_num = 0;
33061 + dwc_ep->pkt_per_frm = 0;
33062 + frm_data = ep->dwc_ep.data_per_frame;
33063 + while (frm_data > 0) {
33064 + dwc_ep->pkt_per_frm++;
33065 + frm_data -= ep->dwc_ep.maxpacket;
33068 + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
33070 + if (start_frame == -1) {
33071 + dwc_ep->next_frame = dsts.b.soffn + 1;
33072 + if (dwc_ep->bInterval != 1) {
33073 + dwc_ep->next_frame =
33074 + dwc_ep->next_frame + (dwc_ep->bInterval - 1 -
33075 + dwc_ep->next_frame %
33076 + dwc_ep->bInterval);
33079 + dwc_ep->next_frame = start_frame;
33082 + if (!core_if->pti_enh_enable) {
33083 + dwc_ep->pkt_cnt =
33084 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
33085 + dwc_ep->bInterval;
33087 + dwc_ep->pkt_cnt =
33088 + (dwc_ep->data_per_frame *
33089 + (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval)
33090 + - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket;
33093 + if (core_if->dma_desc_enable) {
33094 + dwc_ep->desc_cnt =
33095 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
33096 + dwc_ep->bInterval;
33099 + if (atomic_alloc) {
33100 + dwc_ep->pkt_info =
33101 + dwc_alloc_atomic(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
33103 + dwc_ep->pkt_info =
33104 + dwc_alloc(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
33106 + if (!dwc_ep->pkt_info) {
33107 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
33108 + return -DWC_E_NO_MEMORY;
33110 + if (core_if->pti_enh_enable) {
33111 + dwc_memset(dwc_ep->pkt_info, 0,
33112 + sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
33115 + dwc_ep->cur_pkt = 0;
33116 + ep->iso_req_handle = req_handle;
33118 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
33119 + dwc_otg_iso_ep_start_transfer(core_if, dwc_ep);
33123 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
33124 + void *req_handle)
33126 + uint64_t flags = 0;
33127 + dwc_otg_pcd_ep_t *ep;
33128 + dwc_ep_t *dwc_ep;
33130 + ep = get_ep_from_handle(pcd, ep_handle);
33131 + if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
33132 + DWC_WARN("bad ep\n");
33133 + return -DWC_E_INVALID;
33135 + dwc_ep = &ep->dwc_ep;
33137 + dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep);
33139 + dwc_free(dwc_ep->pkt_info);
33140 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
33141 + if (ep->iso_req_handle != req_handle) {
33142 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
33143 + return -DWC_E_INVALID;
33146 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
33148 + ep->iso_req_handle = 0;
33153 + * This function is used for perodical data exchnage between PCD and gadget drivers.
33154 + * for Isochronous EPs
33156 + * - Every time a sync period completes this function is called to
33157 + * perform data exchange between PCD and gadget
33159 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
33160 + void *req_handle)
33163 + dwc_ep_t *dwc_ep;
33165 + dwc_ep = &ep->dwc_ep;
33167 + DWC_SPINUNLOCK(ep->pcd->lock);
33168 + pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle,
33169 + dwc_ep->proc_buf_num ^ 0x1);
33170 + DWC_SPINLOCK(ep->pcd->lock);
33172 + for (i = 0; i < dwc_ep->pkt_cnt; ++i) {
33173 + dwc_ep->pkt_info[i].status = 0;
33174 + dwc_ep->pkt_info[i].offset = 0;
33175 + dwc_ep->pkt_info[i].length = 0;
33179 +int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle,
33180 + void *iso_req_handle)
33182 + dwc_otg_pcd_ep_t *ep;
33183 + dwc_ep_t *dwc_ep;
33185 + ep = get_ep_from_handle(pcd, ep_handle);
33186 + dwc_ep = &ep->dwc_ep;
33188 + return dwc_ep->pkt_cnt;
33191 +void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle,
33192 + void *iso_req_handle, int packet,
33193 + int *status, int *actual, int *offset)
33195 + dwc_otg_pcd_ep_t *ep;
33196 + dwc_ep_t *dwc_ep;
33198 + ep = get_ep_from_handle(pcd, ep_handle);
33199 + dwc_ep = &ep->dwc_ep;
33201 + *status = dwc_ep->pkt_info[packet].status;
33202 + *actual = dwc_ep->pkt_info[packet].length;
33203 + *offset = dwc_ep->pkt_info[packet].offset;
33206 +#endif /* DWC_EN_ISOC */
33208 +static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
33209 + uint32_t is_in, uint32_t ep_num)
33211 + /* Init EP structure */
33212 + pcd_ep->desc = 0;
33213 + pcd_ep->pcd = pcd;
33214 + pcd_ep->stopped = 1;
33215 + pcd_ep->queue_sof = 0;
33217 + /* Init DWC ep structure */
33218 + pcd_ep->dwc_ep.is_in = is_in;
33219 + pcd_ep->dwc_ep.num = ep_num;
33220 + pcd_ep->dwc_ep.active = 0;
33221 + pcd_ep->dwc_ep.tx_fifo_num = 0;
33222 + /* Control until ep is actvated */
33223 + pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
33224 + pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
33225 + pcd_ep->dwc_ep.dma_addr = 0;
33226 + pcd_ep->dwc_ep.start_xfer_buff = 0;
33227 + pcd_ep->dwc_ep.xfer_buff = 0;
33228 + pcd_ep->dwc_ep.xfer_len = 0;
33229 + pcd_ep->dwc_ep.xfer_count = 0;
33230 + pcd_ep->dwc_ep.sent_zlp = 0;
33231 + pcd_ep->dwc_ep.total_len = 0;
33232 + pcd_ep->dwc_ep.desc_addr = 0;
33233 + pcd_ep->dwc_ep.dma_desc_addr = 0;
33234 + DWC_CIRCLEQ_INIT(&pcd_ep->queue);
33238 + * Initialise ep's
33240 +static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
33244 + dwc_otg_pcd_ep_t *ep;
33245 + int in_ep_cntr, out_ep_cntr;
33246 + uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
33247 + uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
33250 + * Initialize the EP0 structure.
33253 + dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
33256 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
33257 + for (i = 1; in_ep_cntr < num_in_eps; i++) {
33258 + if ((hwcfg1 & 0x1) == 0) {
33259 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr];
33262 + * @todo NGS: Add direction to EP, based on contents
33263 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
33266 + dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
33268 + DWC_CIRCLEQ_INIT(&ep->queue);
33274 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
33275 + for (i = 1; out_ep_cntr < num_out_eps; i++) {
33276 + if ((hwcfg1 & 0x1) == 0) {
33277 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr];
33280 + * @todo NGS: Add direction to EP, based on contents
33281 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
33284 + dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
33285 + DWC_CIRCLEQ_INIT(&ep->queue);
33290 + pcd->ep0state = EP0_DISCONNECT;
33291 + pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
33292 + pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
33296 + * This function is called when the SRP timer expires. The SRP should
33297 + * complete within 6 seconds.
33299 +static void srp_timeout(void *ptr)
33301 + gotgctl_data_t gotgctl;
33302 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
33303 + volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
33305 + gotgctl.d32 = dwc_read_reg32(addr);
33307 + core_if->srp_timer_started = 0;
33309 + if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
33310 + (core_if->core_params->i2c_enable)) {
33311 + DWC_PRINTF("SRP Timeout\n");
33313 + if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {
33314 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
33315 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->
33319 + /* Clear Session Request */
33321 + gotgctl.b.sesreq = 1;
33322 + dwc_modify_reg32(&core_if->core_global_regs->gotgctl,
33325 + core_if->srp_success = 0;
33327 + __DWC_ERROR("Device not connected/responding\n");
33328 + gotgctl.b.sesreq = 0;
33329 + dwc_write_reg32(addr, gotgctl.d32);
33331 + } else if (gotgctl.b.sesreq) {
33332 + DWC_PRINTF("SRP Timeout\n");
33334 + __DWC_ERROR("Device not connected/responding\n");
33335 + gotgctl.b.sesreq = 0;
33336 + dwc_write_reg32(addr, gotgctl.d32);
33338 + DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32);
33346 +extern void start_next_request(dwc_otg_pcd_ep_t * ep);
33348 +static void start_xfer_tasklet_func(void *data)
33350 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
33351 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
33354 + depctl_data_t diepctl;
33356 + DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
33358 + diepctl.d32 = dwc_read_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl);
33360 + if (pcd->ep0.queue_sof) {
33361 + pcd->ep0.queue_sof = 0;
33362 + start_next_request(&pcd->ep0);
33366 + for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
33367 + depctl_data_t diepctl;
33369 + dwc_read_reg32(&core_if->dev_if->in_ep_regs[i]->diepctl);
33371 + if (pcd->in_ep[i].queue_sof) {
33372 + pcd->in_ep[i].queue_sof = 0;
33373 + start_next_request(&pcd->in_ep[i]);
33382 + * This function initialized the PCD portion of the driver.
33385 +dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
33387 + dwc_otg_pcd_t *pcd = 0;
33388 + dwc_otg_dev_if_t *dev_if;
33391 + * Allocate PCD structure
33393 + pcd = dwc_alloc(sizeof(dwc_otg_pcd_t));
33399 + pcd->lock = DWC_SPINLOCK_ALLOC();
33400 + DWC_DEBUGPL(DBG_HCDV, "Init of PCD %p given core_if %p\n",
33401 + pcd, core_if);//GRAYG
33402 + pcd->core_if = core_if;
33403 + if (!pcd->lock) {
33404 + DWC_ERROR("Could not allocate lock for pcd");
33408 + dev_if = core_if->dev_if;
33410 + if (core_if->hwcfg4.b.ded_fifo_en) {
33411 + DWC_PRINTF("Dedicated Tx FIFOs mode\n");
33413 + DWC_PRINTF("Shared Tx FIFO mode\n");
33417 + * Initialized the Core for Device mode.
33419 + if (dwc_otg_is_device_mode(core_if)) {
33420 + dwc_otg_core_dev_init(core_if);
33424 + * Register the PCD Callbacks.
33426 + dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd);
33429 + * Initialize the DMA buffer for SETUP packets
33431 + if (GET_CORE_IF(pcd)->dma_enable) {
33433 + dwc_dma_alloc(sizeof(*pcd->setup_pkt) * 5,
33434 + &pcd->setup_pkt_dma_handle);
33435 + if (pcd->setup_pkt == 0) {
33440 + pcd->status_buf =
33441 + dwc_dma_alloc(sizeof(uint16_t),
33442 + &pcd->status_buf_dma_handle);
33443 + if (pcd->status_buf == 0) {
33444 + dwc_dma_free(sizeof(*pcd->setup_pkt) * 5,
33445 + pcd->setup_pkt, pcd->setup_pkt_dma_handle);
33450 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
33451 + dev_if->setup_desc_addr[0] =
33452 + dwc_otg_ep_alloc_desc_chain(&dev_if->
33453 + dma_setup_desc_addr[0],
33455 + dev_if->setup_desc_addr[1] =
33456 + dwc_otg_ep_alloc_desc_chain(&dev_if->
33457 + dma_setup_desc_addr[1],
33459 + dev_if->in_desc_addr =
33460 + dwc_otg_ep_alloc_desc_chain(&dev_if->
33461 + dma_in_desc_addr, 1);
33462 + dev_if->out_desc_addr =
33463 + dwc_otg_ep_alloc_desc_chain(&dev_if->
33464 + dma_out_desc_addr, 1);
33466 + if (dev_if->setup_desc_addr[0] == 0
33467 + || dev_if->setup_desc_addr[1] == 0
33468 + || dev_if->in_desc_addr == 0
33469 + || dev_if->out_desc_addr == 0) {
33471 + if (dev_if->out_desc_addr)
33472 + dwc_otg_ep_free_desc_chain(dev_if->
33475 + dma_out_desc_addr,
33477 + if (dev_if->in_desc_addr)
33478 + dwc_otg_ep_free_desc_chain(dev_if->
33481 + dma_in_desc_addr,
33483 + if (dev_if->setup_desc_addr[1])
33484 + dwc_otg_ep_free_desc_chain(dev_if->
33488 + dma_setup_desc_addr
33490 + if (dev_if->setup_desc_addr[0])
33491 + dwc_otg_ep_free_desc_chain(dev_if->
33495 + dma_setup_desc_addr
33498 + dwc_dma_free(sizeof(*pcd->setup_pkt) * 5,
33500 + pcd->setup_pkt_dma_handle);
33501 + dwc_dma_free(sizeof(*pcd->status_buf),
33503 + pcd->status_buf_dma_handle);
33511 + pcd->setup_pkt = dwc_alloc(sizeof(*pcd->setup_pkt) * 5);
33512 + if (pcd->setup_pkt == 0) {
33517 + pcd->status_buf = dwc_alloc(sizeof(uint16_t));
33518 + if (pcd->status_buf == 0) {
33519 + dwc_free(pcd->setup_pkt);
33525 + dwc_otg_pcd_reinit(pcd);
33527 + /* Allocate the cfi object for the PCD */
33528 +#ifdef DWC_UTE_CFI
33529 + pcd->cfi = dwc_alloc(sizeof(cfiobject_t));
33530 + if (NULL == pcd->cfi)
33532 + if (init_cfi(pcd->cfi)) {
33533 + CFI_INFO("%s: Failed to init the CFI object\n", __func__);
33538 + /* Initialize tasklets */
33539 + pcd->start_xfer_tasklet = DWC_TASK_ALLOC(start_xfer_tasklet_func, pcd);
33540 + pcd->test_mode_tasklet = DWC_TASK_ALLOC(do_test_mode, pcd);
33541 + /* Initialize timer */
33542 + pcd->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
33546 +void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd)
33548 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
33550 + if (GET_CORE_IF(pcd)->dma_enable) {
33551 + dwc_dma_free(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt,
33552 + pcd->setup_pkt_dma_handle);
33553 + dwc_dma_free(sizeof(uint16_t), pcd->status_buf,
33554 + pcd->status_buf_dma_handle);
33555 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
33556 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0],
33558 + dma_setup_desc_addr[0], 1);
33559 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1],
33561 + dma_setup_desc_addr[1], 1);
33562 + dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr,
33563 + dev_if->dma_in_desc_addr, 1);
33564 + dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr,
33565 + dev_if->dma_out_desc_addr,
33569 + dwc_free(pcd->setup_pkt);
33570 + dwc_free(pcd->status_buf);
33572 + DWC_SPINLOCK_FREE(pcd->lock);
33573 + DWC_TASK_FREE(pcd->start_xfer_tasklet);
33574 + DWC_TASK_FREE(pcd->test_mode_tasklet);
33575 + DWC_TIMER_FREE(pcd->srp_timer);
33577 +/* Release the CFI object's dynamic memory */
33578 +#ifdef DWC_UTE_CFI
33579 + if (pcd->cfi->ops.release) {
33580 + pcd->cfi->ops.release(pcd->cfi);
33587 +uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd)
33589 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
33591 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) ||
33592 + ((core_if->hwcfg2.b.hs_phy_type == 2) &&
33593 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
33594 + (core_if->core_params->ulpi_fs_ls))) {
33601 +uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd)
33603 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
33604 + gusbcfg_data_t usbcfg = {.d32 = 0 };
33606 + usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
33607 + if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) {
33615 + * This function assigns periodic Tx FIFO to an periodic EP
33616 + * in shared Tx FIFO mode
33618 +static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if)
33620 + uint32_t TxMsk = 1;
33623 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) {
33624 + if ((TxMsk & core_if->tx_msk) == 0) {
33625 + core_if->tx_msk |= TxMsk;
33634 + * This function assigns periodic Tx FIFO to an periodic EP
33635 + * in shared Tx FIFO mode
33637 +static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if)
33639 + uint32_t PerTxMsk = 1;
33641 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) {
33642 + if ((PerTxMsk & core_if->p_tx_msk) == 0) {
33643 + core_if->p_tx_msk |= PerTxMsk;
33652 + * This function releases periodic Tx FIFO
33653 + * in shared Tx FIFO mode
33655 +static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if,
33656 + uint32_t fifo_num)
33658 + core_if->p_tx_msk =
33659 + (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
33663 + * This function releases periodic Tx FIFO
33664 + * in shared Tx FIFO mode
33666 +static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num)
33668 + core_if->tx_msk =
33669 + (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
33672 +int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
33673 + const uint8_t * ep_desc, void *usb_ep)
33676 + dwc_otg_pcd_ep_t *ep = 0;
33677 + const usb_endpoint_descriptor_t *desc;
33681 + desc = (const usb_endpoint_descriptor_t *)ep_desc;
33684 + pcd->ep0.priv = usb_ep;
33686 + retval = -DWC_E_INVALID;
33690 + num = UE_GET_ADDR(desc->bEndpointAddress);
33691 + dir = UE_GET_DIR(desc->bEndpointAddress);
33693 + if (!desc->wMaxPacketSize) {
33694 + DWC_WARN("bad maxpacketsize\n");
33695 + retval = -DWC_E_INVALID;
33699 + if (dir == UE_DIR_IN) {
33700 + ep = &pcd->in_ep[num - 1];
33702 + ep = &pcd->out_ep[num - 1];
33705 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
33708 + ep->priv = usb_ep;
33711 + * Activate the EP
33715 + ep->dwc_ep.is_in = (dir == UE_DIR_IN);
33716 + ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize);
33718 + ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE;
33720 + if (ep->dwc_ep.is_in) {
33721 + if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
33722 + ep->dwc_ep.tx_fifo_num = 0;
33724 + if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
33726 + * if ISOC EP then assign a Periodic Tx FIFO.
33728 + ep->dwc_ep.tx_fifo_num =
33729 + assign_perio_tx_fifo(GET_CORE_IF(pcd));
33733 + * if Dedicated FIFOs mode is on then assign a Tx FIFO.
33735 + ep->dwc_ep.tx_fifo_num =
33736 + assign_tx_fifo(GET_CORE_IF(pcd));
33740 + /* Set initial data PID. */
33741 + if (ep->dwc_ep.type == UE_BULK) {
33742 + ep->dwc_ep.data_pid_start = 0;
33745 + /* Alloc DMA Descriptors */
33746 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
33747 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
33748 + ep->dwc_ep.desc_addr =
33749 + dwc_otg_ep_alloc_desc_chain(&ep->dwc_ep.
33751 + MAX_DMA_DESC_CNT);
33752 + if (!ep->dwc_ep.desc_addr) {
33753 + DWC_WARN("%s, can't allocate DMA descriptor\n",
33755 + retval = -DWC_E_SHUTDOWN;
33756 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
33762 + DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n",
33763 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
33764 + ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc);
33766 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
33768 +#ifdef DWC_UTE_CFI
33769 + if (pcd->cfi->ops.ep_enable) {
33770 + pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep);
33774 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
33780 +int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle)
33782 + dwc_otg_pcd_ep_t *ep;
33784 + dwc_otg_dev_dma_desc_t *desc_addr;
33785 + dwc_dma_t dma_desc_addr;
33787 + ep = get_ep_from_handle(pcd, ep_handle);
33789 + if (!ep || !ep->desc) {
33790 + DWC_DEBUGPL(DBG_PCD, "%s, %d %s not enabled\n", __func__,
33791 + ep->dwc_ep.num, ep->dwc_ep.is_in ? "IN" : "OUT");
33792 + return -DWC_E_INVALID;
33795 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
33797 + dwc_otg_request_nuke(ep);
33799 + dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep);
33803 + if (ep->dwc_ep.is_in) {
33804 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
33805 + release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
33806 + release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
33809 + /* Free DMA Descriptors */
33810 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
33811 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
33812 + desc_addr = ep->dwc_ep.desc_addr;
33813 + dma_desc_addr = ep->dwc_ep.dma_desc_addr;
33815 + /* Cannot call dma_free_coherent() with IRQs disabled */
33816 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
33817 + dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
33818 + MAX_DMA_DESC_CNT);
33820 + goto out_unlocked;
33824 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
33827 + DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num,
33828 + ep->dwc_ep.is_in ? "IN" : "OUT");
33833 +int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
33834 + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
33835 + int zero, void *req_handle, int atomic_alloc)
33837 + int prevented = 0;
33839 + dwc_otg_pcd_request_t *req;
33840 + dwc_otg_pcd_ep_t *ep;
33841 + uint32_t max_transfer;
33843 + ep = get_ep_from_handle(pcd, ep_handle);
33844 + if ((!ep->desc && ep->dwc_ep.num != 0)) {
33845 + DWC_WARN("bad ep\n");
33846 + return -DWC_E_INVALID;
33849 + if (atomic_alloc) {
33850 + req = dwc_alloc_atomic(sizeof(*req));
33852 + req = dwc_alloc(sizeof(*req));
33856 + return -DWC_E_NO_MEMORY;
33858 + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
33859 + if (!GET_CORE_IF(pcd)->core_params->opt) {
33860 + if (ep->dwc_ep.num != 0) {
33861 + DWC_ERROR("queue req %p, len %d buf %p\n",
33862 + req_handle, buflen, buf);
33867 + req->dma = dma_buf;
33868 + req->length = buflen;
33869 + req->sent_zlp = zero;
33870 + req->priv = req_handle;
33872 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
33875 + * For EP0 IN without premature status, zlp is required?
33877 + if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {
33878 + DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num);
33879 + //_req->zero = 1;
33882 + /* Start the transfer */
33883 + if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) {
33884 + /* EP0 Transfer? */
33885 + if (ep->dwc_ep.num == 0) {
33886 + switch (pcd->ep0state) {
33887 + case EP0_IN_DATA_PHASE:
33888 + DWC_DEBUGPL(DBG_PCD,
33889 + "%s ep0: EP0_IN_DATA_PHASE\n",
33893 + case EP0_OUT_DATA_PHASE:
33894 + DWC_DEBUGPL(DBG_PCD,
33895 + "%s ep0: EP0_OUT_DATA_PHASE\n",
33897 + if (pcd->request_config) {
33898 + /* Complete STATUS PHASE */
33899 + ep->dwc_ep.is_in = 1;
33900 + pcd->ep0state = EP0_IN_STATUS_PHASE;
33904 + case EP0_IN_STATUS_PHASE:
33905 + DWC_DEBUGPL(DBG_PCD,
33906 + "%s ep0: EP0_IN_STATUS_PHASE\n",
33911 + DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
33913 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
33914 + return -DWC_E_SHUTDOWN;
33917 + ep->dwc_ep.dma_addr = dma_buf;
33918 + ep->dwc_ep.start_xfer_buff = buf;
33919 + ep->dwc_ep.xfer_buff = buf;
33920 + ep->dwc_ep.xfer_len = buflen;
33921 + ep->dwc_ep.xfer_count = 0;
33922 + ep->dwc_ep.sent_zlp = 0;
33923 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
33926 + if ((ep->dwc_ep.xfer_len %
33927 + ep->dwc_ep.maxpacket == 0)
33928 + && (ep->dwc_ep.xfer_len != 0)) {
33929 + ep->dwc_ep.sent_zlp = 1;
33934 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
33936 + } // non-ep0 endpoints
33938 +#ifdef DWC_UTE_CFI
33939 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
33940 + /* store the request length */
33941 + ep->dwc_ep.cfi_req_len = buflen;
33942 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd,
33947 + GET_CORE_IF(ep->pcd)->core_params->
33948 + max_transfer_size;
33950 + /* Setup and start the Transfer */
33951 + ep->dwc_ep.dma_addr = dma_buf;
33952 + ep->dwc_ep.start_xfer_buff = buf;
33953 + ep->dwc_ep.xfer_buff = buf;
33954 + ep->dwc_ep.xfer_len = 0;
33955 + ep->dwc_ep.xfer_count = 0;
33956 + ep->dwc_ep.sent_zlp = 0;
33957 + ep->dwc_ep.total_len = buflen;
33959 + ep->dwc_ep.maxxfer = max_transfer;
33960 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
33961 + uint32_t out_max_xfer =
33962 + DDMA_MAX_TRANSFER_SIZE -
33963 + (DDMA_MAX_TRANSFER_SIZE % 4);
33964 + if (ep->dwc_ep.is_in) {
33965 + if (ep->dwc_ep.maxxfer >
33966 + DDMA_MAX_TRANSFER_SIZE) {
33967 + ep->dwc_ep.maxxfer =
33968 + DDMA_MAX_TRANSFER_SIZE;
33971 + if (ep->dwc_ep.maxxfer >
33973 + ep->dwc_ep.maxxfer =
33978 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
33979 + ep->dwc_ep.maxxfer -=
33980 + (ep->dwc_ep.maxxfer %
33981 + ep->dwc_ep.maxpacket);
33985 + if ((ep->dwc_ep.total_len %
33986 + ep->dwc_ep.maxpacket == 0)
33987 + && (ep->dwc_ep.total_len != 0)) {
33988 + ep->dwc_ep.sent_zlp = 1;
33991 +#ifdef DWC_UTE_CFI
33994 + dwc_otg_ep_start_transfer(GET_CORE_IF(pcd),
33999 + if ((req != 0) || prevented) {
34000 + ++pcd->request_pending;
34001 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
34002 + if (ep->dwc_ep.is_in && ep->stopped
34003 + && !(GET_CORE_IF(pcd)->dma_enable)) {
34004 + /** @todo NGS Create a function for this. */
34005 + diepmsk_data_t diepmsk = {.d32 = 0 };
34006 + diepmsk.b.intktxfemp = 1;
34007 + if (GET_CORE_IF(pcd)->multiproc_int_enable) {
34008 + dwc_modify_reg32(&GET_CORE_IF(pcd)->dev_if->
34009 + dev_global_regs->
34010 + diepeachintmsk[ep->dwc_ep.num],
34013 + dwc_modify_reg32(&GET_CORE_IF(pcd)->dev_if->
34014 + dev_global_regs->diepmsk, 0,
34021 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
34025 +int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
34026 + void *req_handle)
34029 + dwc_otg_pcd_request_t *req;
34030 + dwc_otg_pcd_ep_t *ep;
34032 + ep = get_ep_from_handle(pcd, ep_handle);
34033 + if (!ep->desc && ep->dwc_ep.num != 0) {
34034 + DWC_WARN("bad argument\n");
34035 + return -DWC_E_INVALID;
34038 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
34040 + /* make sure it's actually queued on this endpoint */
34041 + DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
34042 + if (req->priv == (void *)req_handle) {
34047 + if (req->priv != (void *)req_handle) {
34048 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
34049 + return -DWC_E_INVALID;
34052 + if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) {
34053 + dwc_otg_request_done(ep, req, -DWC_E_RESTART);
34058 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
34060 + return req ? 0 : -DWC_E_SHUTDOWN;
34065 + * dwc_otg_pcd_ep_wedge - sets the halt feature and ignores clear requests
34067 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
34068 + * requests. If the gadget driver clears the halt status, it will
34069 + * automatically unwedge the endpoint.
34071 + * Returns zero on success, else negative DWC error code.
34073 +int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle)
34075 + dwc_otg_pcd_ep_t *ep;
34079 + ep = get_ep_from_handle(pcd, ep_handle);
34081 + if ((!ep->desc && ep != &pcd->ep0) ||
34082 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
34083 + DWC_WARN("%s, bad ep\n", __func__);
34084 + return -DWC_E_INVALID;
34087 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
34088 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
34089 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
34090 + ep->dwc_ep.is_in ? "IN" : "OUT");
34091 + retval = -DWC_E_AGAIN;
34093 + /* This code needs to be reviewed */
34094 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
34095 + dtxfsts_data_t txstatus;
34096 + fifosize_data_t txfifosize;
34099 + dwc_read_reg32(&GET_CORE_IF(pcd)->core_global_regs->
34100 + dptxfsiz_dieptxf[ep->dwc_ep.
34103 + dwc_read_reg32(&GET_CORE_IF(pcd)->dev_if->
34104 + in_ep_regs[ep->dwc_ep.num]->dtxfsts);
34106 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
34107 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
34108 + retval = -DWC_E_AGAIN;
34110 + if (ep->dwc_ep.num == 0) {
34111 + pcd->ep0state = EP0_STALL;
34115 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
34119 + if (ep->dwc_ep.num == 0) {
34120 + pcd->ep0state = EP0_STALL;
34124 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
34128 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
34133 +int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value)
34135 + dwc_otg_pcd_ep_t *ep;
34139 + ep = get_ep_from_handle(pcd, ep_handle);
34141 + if ((!ep->desc && ep != &pcd->ep0) ||
34142 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
34143 + DWC_WARN("%s, bad ep\n", __func__);
34144 + return -DWC_E_INVALID;
34147 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
34148 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
34149 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
34150 + ep->dwc_ep.is_in ? "IN" : "OUT");
34151 + retval = -DWC_E_AGAIN;
34152 + } else if (value == 0) {
34153 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
34154 + } else if (value == 1) {
34155 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
34156 + dtxfsts_data_t txstatus;
34157 + fifosize_data_t txfifosize;
34160 + dwc_read_reg32(&GET_CORE_IF(pcd)->core_global_regs->
34161 + dptxfsiz_dieptxf[ep->dwc_ep.
34164 + dwc_read_reg32(&GET_CORE_IF(pcd)->dev_if->
34165 + in_ep_regs[ep->dwc_ep.num]->dtxfsts);
34167 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
34168 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
34169 + retval = -DWC_E_AGAIN;
34171 + if (ep->dwc_ep.num == 0) {
34172 + pcd->ep0state = EP0_STALL;
34176 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
34180 + if (ep->dwc_ep.num == 0) {
34181 + pcd->ep0state = EP0_STALL;
34185 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
34187 + } else if (value == 2) {
34188 + ep->dwc_ep.stall_clear_flag = 0;
34189 + } else if (value == 3) {
34190 + ep->dwc_ep.stall_clear_flag = 1;
34193 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
34199 + * This function initiates remote wakeup of the host from suspend state.
34201 +void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set)
34203 + dctl_data_t dctl = { 0 };
34204 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
34205 + dsts_data_t dsts;
34207 + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
34208 + if (!dsts.b.suspsts) {
34209 + DWC_WARN("Remote wakeup while is not in suspend state\n");
34211 + /* Check if DEVICE_REMOTE_WAKEUP feature enabled */
34212 + if (pcd->remote_wakeup_enable) {
34214 + dctl.b.rmtwkupsig = 1;
34215 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
34216 + dctl, 0, dctl.d32);
34217 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
34219 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
34220 + dctl, dctl.d32, 0);
34221 + DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
34224 + DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
34228 +#ifdef CONFIG_USB_DWC_OTG_LPM
34230 + * This function initiates remote wakeup of the host from L1 sleep state.
34232 +void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set)
34234 + glpmcfg_data_t lpmcfg;
34235 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
34237 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
34239 + /* Check if we are in L1 state */
34240 + if (!lpmcfg.b.prt_sleep_sts) {
34241 + DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n");
34245 + /* Check if host allows remote wakeup */
34246 + if (!lpmcfg.b.rem_wkup_en) {
34247 + DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n");
34251 + /* Check if Resume OK */
34252 + if (!lpmcfg.b.sleep_state_resumeok) {
34253 + DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n");
34257 + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
34258 + lpmcfg.b.en_utmi_sleep = 0;
34259 + lpmcfg.b.hird_thres &= (~(1 << 4));
34260 + dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
34263 + dctl_data_t dctl = {.d32 = 0 };
34264 + dctl.b.rmtwkupsig = 1;
34265 + /* Set RmtWkUpSig bit to start remote wakup signaling.
34266 + * Hardware will automatically clear this bit.
34268 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->dctl,
34270 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
34277 + * Performs remote wakeup.
34279 +void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set)
34281 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
34282 + if (dwc_otg_is_device_mode(core_if)) {
34283 +#ifdef CONFIG_USB_DWC_OTG_LPM
34284 + if (core_if->lx_state == DWC_OTG_L1) {
34285 + dwc_otg_pcd_rem_wkup_from_sleep(pcd, set);
34288 + dwc_otg_pcd_rem_wkup_from_suspend(pcd, set);
34289 +#ifdef CONFIG_USB_DWC_OTG_LPM
34296 +int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd)
34298 + dsts_data_t dsts;
34299 + gotgctl_data_t gotgctl;
34302 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
34305 + * This function starts the Protocol if no session is in progress. If
34306 + * a session is already in progress, but the device is suspended,
34307 + * remote wakeup signaling is started.
34310 + /* Check if valid session */
34312 + dwc_read_reg32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
34313 + if (gotgctl.b.bsesvld) {
34314 + /* Check if suspend state */
34317 + (GET_CORE_IF(pcd)->dev_if->dev_global_regs->
34319 + if (dsts.b.suspsts) {
34320 + dwc_otg_pcd_remote_wakeup(pcd, 1);
34323 + dwc_otg_pcd_initiate_srp(pcd);
34326 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
34332 + * Start the SRP timer to detect when the SRP does not complete within
34335 + * @param pcd the pcd structure.
34337 +void dwc_otg_pcd_start_srp_timer(dwc_otg_pcd_t * pcd)
34339 + GET_CORE_IF(pcd)->srp_timer_started = 1;
34340 + DWC_TIMER_SCHEDULE(pcd->srp_timer, 6000 /* 6 secs */ );
34343 +void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd)
34346 + (uint32_t *) & (GET_CORE_IF(pcd)->core_global_regs->gotgctl);
34347 + gotgctl_data_t mem;
34348 + gotgctl_data_t val;
34350 + val.d32 = dwc_read_reg32(addr);
34351 + if (val.b.sesreq) {
34352 + DWC_ERROR("Session Request Already active!\n");
34356 + DWC_INFO("Session Request Initated\n"); //NOTICE
34357 + mem.d32 = dwc_read_reg32(addr);
34358 + mem.b.sesreq = 1;
34359 + dwc_write_reg32(addr, mem.d32);
34361 + /* Start the SRP timer */
34362 + dwc_otg_pcd_start_srp_timer(pcd);
34366 +int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd)
34368 + return dwc_otg_get_frame_number(GET_CORE_IF(pcd));
34371 +int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd)
34373 + return GET_CORE_IF(pcd)->core_params->lpm_enable;
34376 +uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd)
34378 + return pcd->b_hnp_enable;
34381 +uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd)
34383 + return pcd->a_hnp_support;
34386 +uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd)
34388 + return pcd->a_alt_hnp_support;
34391 +int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd)
34393 + return pcd->remote_wakeup_enable;
34396 +#endif /* DWC_HOST_ONLY */
34398 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.h
34400 +/* ==========================================================================
34401 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $
34402 + * $Revision: #39 $
34403 + * $Date: 2008/12/16 $
34404 + * $Change: 1153731 $
34406 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
34407 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
34408 + * otherwise expressly agreed to in writing between Synopsys and you.
34410 + * The Software IS NOT an item of Licensed Software or Licensed Product under
34411 + * any End User Software License Agreement or Agreement for Licensed Product
34412 + * with Synopsys or any supplement thereto. You are permitted to use and
34413 + * redistribute this Software in source and binary forms, with or without
34414 + * modification, provided that redistributions of source code must retain this
34415 + * notice. You may not view, use, disclose, copy or distribute this file or
34416 + * any information contained herein except pursuant to this license grant from
34417 + * Synopsys. If you do not agree with this notice, including the disclaimer
34418 + * below, then you are not authorized to use the Software.
34420 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
34421 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34422 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34423 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
34424 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34425 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34426 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34427 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34428 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34429 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
34431 + * ========================================================================== */
34432 +#ifndef DWC_HOST_ONLY
34433 +#if !defined(__DWC_PCD_H__)
34434 +#define __DWC_PCD_H__
34437 +#include "dwc_otg_cil.h"
34438 +#include "dwc_otg_pcd_if.h"
34444 + * This file contains the structures, constants, and interfaces for
34445 + * the Perpherial Contoller Driver (PCD).
34447 + * The Peripheral Controller Driver (PCD) for Linux will implement the
34448 + * Gadget API, so that the existing Gadget drivers can be used. For
34449 + * the Mass Storage Function driver the File-backed USB Storage Gadget
34450 + * (FBS) driver will be used. The FBS driver supports the
34451 + * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only
34456 +/** Max Transfer size for any EP */
34457 +#define DDMA_MAX_TRANSFER_SIZE 65535
34459 +/** Max DMA Descriptor count for any EP */
34460 +#define MAX_DMA_DESC_CNT 64
34463 + * Get the pointer to the core_if from the pcd pointer.
34465 +#define GET_CORE_IF( _pcd ) (_pcd->core_if)
34470 +typedef enum ep0_state {
34471 + EP0_DISCONNECT, /* no host */
34473 + EP0_IN_DATA_PHASE,
34474 + EP0_OUT_DATA_PHASE,
34475 + EP0_IN_STATUS_PHASE,
34476 + EP0_OUT_STATUS_PHASE,
34480 +/** Fordward declaration.*/
34481 +struct dwc_otg_pcd;
34483 +/** DWC_otg iso request structure.
34486 +typedef struct usb_iso_request dwc_otg_pcd_iso_request_t;
34488 +/** DWC_otg request structure.
34489 + * This structure is a list of requests.
34491 +typedef struct dwc_otg_pcd_request {
34497 + unsigned sent_zlp:1;
34499 + DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry;
34500 +} dwc_otg_pcd_request_t;
34502 +DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request);
34504 +/** PCD EP structure.
34505 + * This structure describes an EP, there is an array of EPs in the PCD
34508 +typedef struct dwc_otg_pcd_ep {
34509 + /** USB EP Descriptor */
34510 + const usb_endpoint_descriptor_t *desc;
34512 + /** queue of dwc_otg_pcd_requests. */
34513 + struct req_list queue;
34514 + unsigned stopped:1;
34515 + unsigned disabling:1;
34517 + unsigned queue_sof:1;
34519 +#ifdef DWC_EN_ISOC
34520 + /** ISOC req handle passed */
34521 + void *iso_req_handle;
34522 +#endif //_EN_ISOC_
34524 + /** DWC_otg ep data. */
34527 + /** Pointer to PCD */
34528 + struct dwc_otg_pcd *pcd;
34531 +} dwc_otg_pcd_ep_t;
34533 +/** DWC_otg PCD Structure.
34534 + * This structure encapsulates the data for the dwc_otg PCD.
34536 +struct dwc_otg_pcd {
34537 + const struct dwc_otg_pcd_function_ops *fops;
34538 + /** Core Interface */
34539 + dwc_otg_core_if_t *core_if;
34540 + /** State of EP0 */
34541 + ep0state_e ep0state;
34542 + /** EP0 Request is pending */
34543 + unsigned ep0_pending:1;
34544 + /** Indicates when SET CONFIGURATION Request is in process */
34545 + unsigned request_config:1;
34546 + /** The state of the Remote Wakeup Enable. */
34547 + unsigned remote_wakeup_enable:1;
34548 + /** The state of the B-Device HNP Enable. */
34549 + unsigned b_hnp_enable:1;
34550 + /** The state of A-Device HNP Support. */
34551 + unsigned a_hnp_support:1;
34552 + /** The state of the A-Device Alt HNP support. */
34553 + unsigned a_alt_hnp_support:1;
34554 + /** Count of pending Requests */
34555 + unsigned request_pending;
34557 + /** SETUP packet for EP0
34558 + * This structure is allocated as a DMA buffer on PCD initialization
34559 + * with enough space for up to 3 setup packets.
34562 + usb_device_request_t req;
34566 + dwc_dma_t setup_pkt_dma_handle;
34568 + /** 2-byte dma buffer used to return status from GET_STATUS */
34569 + uint16_t *status_buf;
34570 + dwc_dma_t status_buf_dma_handle;
34573 + dwc_otg_pcd_ep_t ep0;
34575 + /** Array of IN EPs. */
34576 + dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1];
34577 + /** Array of OUT EPs. */
34578 + dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1];
34579 + /** number of valid EPs in the above array. */
34580 +// unsigned num_eps : 4;
34581 + dwc_spinlock_t *lock;
34582 + /** Timer for SRP. If it expires before SRP is successful
34583 + * clear the SRP. */
34584 + dwc_timer_t *srp_timer;
34586 + /** Tasklet to defer starting of TEST mode transmissions until
34587 + * Status Phase has been completed.
34589 + dwc_tasklet_t *test_mode_tasklet;
34591 + /** Tasklet to delay starting of xfer in DMA mode */
34592 + dwc_tasklet_t *start_xfer_tasklet;
34594 + /** The test mode to enter when the tasklet is executed. */
34595 + unsigned test_mode;
34596 + /** The cfi_api structure that implements most of the CFI API
34597 + * and OTG specific core configuration functionality
34599 +#ifdef DWC_UTE_CFI
34600 + struct cfiobject *cfi;
34605 +//FIXME this functions should be static, and this prototypes should be removed
34606 +extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep);
34607 +extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep,
34608 + dwc_otg_pcd_request_t * req, int32_t status);
34610 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
34611 + void *req_handle);
34613 +extern void do_test_mode(void *data);
34615 +#endif /* DWC_HOST_ONLY */
34617 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
34619 +/* ==========================================================================
34620 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $
34621 + * $Revision: #6 $
34622 + * $Date: 2009/04/03 $
34623 + * $Change: 1225059 $
34625 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
34626 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
34627 + * otherwise expressly agreed to in writing between Synopsys and you.
34629 + * The Software IS NOT an item of Licensed Software or Licensed Product under
34630 + * any End User Software License Agreement or Agreement for Licensed Product
34631 + * with Synopsys or any supplement thereto. You are permitted to use and
34632 + * redistribute this Software in source and binary forms, with or without
34633 + * modification, provided that redistributions of source code must retain this
34634 + * notice. You may not view, use, disclose, copy or distribute this file or
34635 + * any information contained herein except pursuant to this license grant from
34636 + * Synopsys. If you do not agree with this notice, including the disclaimer
34637 + * below, then you are not authorized to use the Software.
34639 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
34640 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34641 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34642 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
34643 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34644 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34645 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34646 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34647 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34648 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
34650 + * ========================================================================== */
34651 +#ifndef DWC_HOST_ONLY
34653 +#if !defined(__DWC_PCD_IF_H__)
34654 +#define __DWC_PCD_IF_H__
34656 +#include "dwc_os.h"
34657 +#include "dwc_otg_core_if.h"
34660 + * This file defines DWC_OTG PCD Core API.
34663 +struct dwc_otg_pcd;
34664 +typedef struct dwc_otg_pcd dwc_otg_pcd_t;
34666 +/** Maxpacket size for EP0 */
34667 +#define MAX_EP0_SIZE 64
34668 +/** Maxpacket size for any EP */
34669 +#define MAX_PACKET_SIZE 1024
34671 +/** @name Function Driver Callbacks */
34674 +/** This function will be called whenever a previously queued request has
34675 + * completed. The status value will be set to -DWC_E_SHUTDOWN to indicated a
34676 + * failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset,
34677 + * or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid
34679 +typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
34680 + void *req_handle, int32_t status,
34681 + uint32_t actual);
34683 + * This function will be called whenever a previousle queued ISOC request has
34684 + * completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count
34686 + * The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_*
34689 +typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
34690 + void *req_handle, int proc_buf_num);
34691 +/** This function should handle any SETUP request that cannot be handled by the
34692 + * PCD Core. This includes most GET_DESCRIPTORs, SET_CONFIGS, Any
34693 + * class-specific requests, etc. The function must non-blocking.
34695 + * Returns 0 on success.
34696 + * Returns -DWC_E_NOT_SUPPORTED if the request is not supported.
34697 + * Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes.
34698 + * Returns -DWC_E_SHUTDOWN on any other error. */
34699 +typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes);
34700 +/** This is called whenever the device has been disconnected. The function
34701 + * driver should take appropriate action to clean up all pending requests in the
34702 + * PCD Core, remove all endpoints (except ep0), and initialize back to reset
34704 +typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd);
34705 +/** This function is called when device has been connected. */
34706 +typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed);
34707 +/** This function is called when device has been suspended */
34708 +typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd);
34709 +/** This function is called when device has received LPM tokens, i.e.
34710 + * device has been sent to sleep state. */
34711 +typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd);
34712 +/** This function is called when device has been resumed
34713 + * from suspend(L2) or L1 sleep state. */
34714 +typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd);
34715 +/** This function is called whenever hnp params has been changed.
34716 + * User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions
34717 + * to get hnp parameters. */
34718 +typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd);
34719 +/** This function is called whenever USB RESET is detected. */
34720 +typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd);
34722 +typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes);
34724 +/** Function Driver Ops Data Structure */
34725 +struct dwc_otg_pcd_function_ops {
34726 + dwc_connect_cb_t connect;
34727 + dwc_disconnect_cb_t disconnect;
34728 + dwc_setup_cb_t setup;
34729 + dwc_completion_cb_t complete;
34730 + dwc_isoc_completion_cb_t isoc_complete;
34731 + dwc_suspend_cb_t suspend;
34732 + dwc_sleep_cb_t sleep;
34733 + dwc_resume_cb_t resume;
34734 + dwc_reset_cb_t reset;
34735 + dwc_hnp_params_changed_cb_t hnp_changed;
34736 + cfi_setup_cb_t cfi_setup;
34740 +/** @name Function Driver Functions */
34743 +/** Call this function to get pointer on dwc_otg_pcd_t,
34744 + * this pointer will be used for all PCD API functions.
34746 + * @param core_if The DWC_OTG Core
34748 +extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if);
34750 +/** Frees PCD allocated by dwc_otg_pcd_init
34752 + * @param pcd The PCD
34754 +extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd);
34756 +/** Call this to bind the function driver to the PCD Core.
34758 + * @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
34759 + * @param fops The Function Driver Ops data structure containing pointers to all callbacks.
34761 +extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
34762 + const struct dwc_otg_pcd_function_ops *fops);
34764 +/** Enables an endpoint for use. This function enables an endpoint in
34765 + * the PCD. The endpoint is described by the ep_desc which has the
34766 + * same format as a USB ep descriptor. The ep_handle parameter is used to refer
34767 + * to the endpoint from other API functions and in callbacks. Normally this
34768 + * should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the
34769 + * core for that interface.
34771 + * Returns -DWC_E_INVALID if invalid parameters were passed.
34772 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
34773 + * Returns 0 on success.
34775 + * @param pcd The PCD
34776 + * @param ep_desc Endpoint descriptor
34777 + * @param ep_handle Handle on endpoint, that will be used to identify endpoint.
34779 +extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
34780 + const uint8_t * ep_desc, void *ep_handle);
34782 +/** Disable the endpoint referenced by ep_handle.
34784 + * Returns -DWC_E_INVALID if invalid parameters were passed.
34785 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
34786 + * Returns 0 on success. */
34787 +extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle);
34789 +/** Queue a data transfer request on the endpoint referenced by ep_handle.
34790 + * After the transfer is completes, the complete callback will be called with
34791 + * the request status.
34793 + * @param pcd The PCD
34794 + * @param ep_handle The handle of the endpoint
34795 + * @param buf The buffer for the data
34796 + * @param dma_buf The DMA buffer for the data
34797 + * @param buflen The length of the data transfer
34798 + * @param zero Specifies whether to send zero length last packet.
34799 + * @param req_handle Set this handle to any value to use to reference this
34800 + * request in the ep_dequeue function or from the complete callback
34801 + * @param atomic_alloc If driver need to perform atomic allocations
34802 + * for internal data structures.
34804 + * Returns -DWC_E_INVALID if invalid parameters were passed.
34805 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
34806 + * Returns 0 on success. */
34807 +extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
34808 + uint8_t * buf, dwc_dma_t dma_buf,
34809 + uint32_t buflen, int zero, void *req_handle,
34810 + int atomic_alloc);
34812 +/** De-queue the specified data transfer that has not yet completed.
34814 + * Returns -DWC_E_INVALID if invalid parameters were passed.
34815 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
34816 + * Returns 0 on success. */
34817 +extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
34818 + void *req_handle);
34820 +/** Halt (STALL) an endpoint or clear it.
34822 + * Returns -DWC_E_INVALID if invalid parameters were passed.
34823 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
34824 + * Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later
34825 + * Returns 0 on success. */
34826 +extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value);
34828 +/** This function */
34829 +extern int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle);
34831 +/** This function should be called on every hardware interrupt */
34832 +extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd);
34834 +/** This function returns current frame number */
34835 +extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd);
34838 + * Start isochronous transfers on the endpoint referenced by ep_handle.
34839 + * For isochronous transfers duble buffering is used.
34840 + * After processing each of buffers comlete callback will be called with
34841 + * status for each transaction.
34843 + * @param pcd The PCD
34844 + * @param ep_handle The handle of the endpoint
34845 + * @param buf0 The virtual address of first data buffer
34846 + * @param buf1 The virtual address of second data buffer
34847 + * @param dma0 The DMA address of first data buffer
34848 + * @param dma1 The DMA address of second data buffer
34849 + * @param sync_frame Data pattern frame number
34850 + * @param dp_frame Data size for pattern frame
34851 + * @param data_per_frame Data size for regular frame
34852 + * @param start_frame Frame number to start transfers, if -1 then start transfers ASAP.
34853 + * @param buf_proc_intrvl Interval of ISOC Buffer processing
34854 + * @param req_handle Handle of ISOC request
34855 + * @param atomic_alloc Specefies whether to perform atomic allocation for
34856 + * internal data structures.
34858 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
34859 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function.
34860 + * Returns -DW_E_SHUTDOWN for any other error.
34861 + * Returns 0 on success
34863 +extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
34864 + uint8_t * buf0, uint8_t * buf1,
34865 + dwc_dma_t dma0, dwc_dma_t dma1,
34866 + int sync_frame, int dp_frame,
34867 + int data_per_frame, int start_frame,
34868 + int buf_proc_intrvl, void *req_handle,
34869 + int atomic_alloc);
34871 +/** Stop ISOC transfers on endpoint referenced by ep_handle.
34873 + * @param pcd The PCD
34874 + * @param ep_handle The handle of the endpoint
34875 + * @param req_handle Handle of ISOC request
34877 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function
34878 + * Returns 0 on success
34880 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
34881 + void *req_handle);
34883 +/** Get ISOC packet status.
34885 + * @param pcd The PCD
34886 + * @param ep_handle The handle of the endpoint
34887 + * @param iso_req_handle Isochronoush request handle
34888 + * @param packet Number of packet
34889 + * @param status Out parameter for returning status
34890 + * @param actual Out parameter for returning actual length
34891 + * @param offset Out parameter for returning offset
34894 +extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd,
34896 + void *iso_req_handle, int packet,
34897 + int *status, int *actual,
34900 +/** Get ISOC packet count.
34902 + * @param pcd The PCD
34903 + * @param ep_handle The handle of the endpoint
34904 + * @param iso_req_handle
34906 +extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd,
34908 + void *iso_req_handle);
34910 +/** This function starts the SRP Protocol if no session is in progress. If
34911 + * a session is already in progress, but the device is suspended,
34912 + * remote wakeup signaling is started.
34914 +extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd);
34916 +/** This function returns 1 if LPM support is enabled, and 0 otherwise. */
34917 +extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd);
34919 +/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */
34920 +extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd);
34922 +/** Initiate SRP */
34923 +extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd);
34925 +/** Starts remote wakeup signaling. */
34926 +extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set);
34928 +/** This function returns whether device is dualspeed.*/
34929 +extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd);
34931 +/** This function returns whether device is otg. */
34932 +extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd);
34934 +/** These functions allow to get hnp parameters */
34935 +extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd);
34936 +extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd);
34937 +extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd);
34939 +/** CFI specific Interface functions */
34940 +/** Allocate a cfi buffer */
34941 +extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep,
34942 + dwc_dma_t * addr, size_t buflen,
34945 +/******************************************************************************/
34949 +#endif /* __DWC_PCD_IF_H__ */
34951 +#endif /* DWC_HOST_ONLY */
34953 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
34955 +/* ==========================================================================
34956 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $
34957 + * $Revision: #93 $
34958 + * $Date: 2009/04/02 $
34959 + * $Change: 1224216 $
34961 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
34962 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
34963 + * otherwise expressly agreed to in writing between Synopsys and you.
34965 + * The Software IS NOT an item of Licensed Software or Licensed Product under
34966 + * any End User Software License Agreement or Agreement for Licensed Product
34967 + * with Synopsys or any supplement thereto. You are permitted to use and
34968 + * redistribute this Software in source and binary forms, with or without
34969 + * modification, provided that redistributions of source code must retain this
34970 + * notice. You may not view, use, disclose, copy or distribute this file or
34971 + * any information contained herein except pursuant to this license grant from
34972 + * Synopsys. If you do not agree with this notice, including the disclaimer
34973 + * below, then you are not authorized to use the Software.
34975 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
34976 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34977 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34978 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
34979 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34980 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34981 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34982 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34983 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34984 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
34986 + * ========================================================================== */
34987 +#ifndef DWC_HOST_ONLY
34989 +#include "dwc_otg_pcd.h"
34991 +#ifdef DWC_UTE_CFI
34992 +#include "dwc_otg_cfi.h"
34995 +//#define PRINT_CFI_DMA_DESCS
35000 + * This function updates OTG.
35002 +static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset)
35006 + pcd->b_hnp_enable = 0;
35007 + pcd->a_hnp_support = 0;
35008 + pcd->a_alt_hnp_support = 0;
35011 + if (pcd->fops->hnp_changed) {
35012 + pcd->fops->hnp_changed(pcd);
35017 + * This file contains the implementation of the PCD Interrupt handlers.
35019 + * The PCD handles the device interrupts. Many conditions can cause a
35020 + * device interrupt. When an interrupt occurs, the device interrupt
35021 + * service routine determines the cause of the interrupt and
35022 + * dispatches handling to the appropriate function. These interrupt
35023 + * handling functions are described below.
35024 + * All interrupt registers are processed from LSB to MSB.
35028 + * This function prints the ep0 state for debug purposes.
35030 +static inline void print_ep0_state(dwc_otg_pcd_t * pcd)
35035 + switch (pcd->ep0state) {
35036 + case EP0_DISCONNECT:
35037 + dwc_strcpy(str, "EP0_DISCONNECT");
35040 + dwc_strcpy(str, "EP0_IDLE");
35042 + case EP0_IN_DATA_PHASE:
35043 + dwc_strcpy(str, "EP0_IN_DATA_PHASE");
35045 + case EP0_OUT_DATA_PHASE:
35046 + dwc_strcpy(str, "EP0_OUT_DATA_PHASE");
35048 + case EP0_IN_STATUS_PHASE:
35049 + dwc_strcpy(str, "EP0_IN_STATUS_PHASE");
35051 + case EP0_OUT_STATUS_PHASE:
35052 + dwc_strcpy(str, "EP0_OUT_STATUS_PHASE");
35055 + dwc_strcpy(str, "EP0_STALL");
35058 + dwc_strcpy(str, "EP0_INVALID");
35061 + DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state);
35065 +#ifdef DWC_UTE_CFI
35066 +static inline void print_desc(struct dwc_otg_dma_desc *ddesc,
35067 + const uint8_t * epname, int descnum)
35070 + ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n",
35071 + epname, descnum, ddesc->buf, ddesc->status.b.bytes,
35072 + ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts,
35073 + ddesc->status.b.bs);
35078 + * This function returns pointer to in ep struct with number ep_num
35080 +static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
35083 + int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
35084 + if (ep_num == 0) {
35085 + return &pcd->ep0;
35087 + for (i = 0; i < num_in_eps; ++i) {
35088 + if (pcd->in_ep[i].dwc_ep.num == ep_num)
35089 + return &pcd->in_ep[i];
35096 + * This function returns pointer to out ep struct with number ep_num
35098 +static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
35101 + int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
35102 + if (ep_num == 0) {
35103 + return &pcd->ep0;
35105 + for (i = 0; i < num_out_eps; ++i) {
35106 + if (pcd->out_ep[i].dwc_ep.num == ep_num)
35107 + return &pcd->out_ep[i];
35114 + * This functions gets a pointer to an EP from the wIndex address
35115 + * value of the control request.
35117 +dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex)
35119 + dwc_otg_pcd_ep_t *ep;
35120 + uint32_t ep_num = UE_GET_ADDR(wIndex);
35122 + if (ep_num == 0) {
35124 + } else if (UE_GET_DIR(wIndex) == UE_DIR_IN) { /* in ep */
35125 + ep = &pcd->in_ep[ep_num - 1];
35127 + ep = &pcd->out_ep[ep_num - 1];
35134 + * This function checks the EP request queue, if the queue is not
35135 + * empty the next request is started.
35137 +void start_next_request(dwc_otg_pcd_ep_t * ep)
35139 + dwc_otg_pcd_request_t *req = 0;
35140 + uint32_t max_transfer =
35141 + GET_CORE_IF(ep->pcd)->core_params->max_transfer_size;
35143 +#ifdef DWC_UTE_CFI
35144 + struct dwc_otg_pcd *pcd;
35148 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
35149 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
35151 +#ifdef DWC_UTE_CFI
35152 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
35153 + ep->dwc_ep.cfi_req_len = req->length;
35154 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req);
35157 + /* Setup and start the Transfer */
35158 + ep->dwc_ep.dma_addr = req->dma;
35159 + ep->dwc_ep.start_xfer_buff = req->buf;
35160 + ep->dwc_ep.xfer_buff = req->buf;
35161 + ep->dwc_ep.sent_zlp = 0;
35162 + ep->dwc_ep.total_len = req->length;
35163 + ep->dwc_ep.xfer_len = 0;
35164 + ep->dwc_ep.xfer_count = 0;
35166 + ep->dwc_ep.maxxfer = max_transfer;
35167 + if (GET_CORE_IF(ep->pcd)->dma_desc_enable) {
35168 + uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE
35169 + - (DDMA_MAX_TRANSFER_SIZE % 4);
35170 + if (ep->dwc_ep.is_in) {
35171 + if (ep->dwc_ep.maxxfer >
35172 + DDMA_MAX_TRANSFER_SIZE) {
35173 + ep->dwc_ep.maxxfer =
35174 + DDMA_MAX_TRANSFER_SIZE;
35177 + if (ep->dwc_ep.maxxfer > out_max_xfer) {
35178 + ep->dwc_ep.maxxfer =
35183 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
35184 + ep->dwc_ep.maxxfer -=
35185 + (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket);
35187 + if (req->sent_zlp) {
35188 + if ((ep->dwc_ep.total_len %
35189 + ep->dwc_ep.maxpacket == 0)
35190 + && (ep->dwc_ep.total_len != 0)) {
35191 + ep->dwc_ep.sent_zlp = 1;
35195 +#ifdef DWC_UTE_CFI
35198 + dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep);
35203 + * This function handles the SOF Interrupts. At this time the SOF
35204 + * Interrupt is disabled.
35206 +int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd)
35208 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
35210 + gintsts_data_t gintsts;
35212 + DWC_DEBUGPL(DBG_PCD, "SOF\n");
35214 + /* Clear interrupt */
35216 + gintsts.b.sofintr = 1;
35217 + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
35223 + * This function handles the Rx Status Queue Level Interrupt, which
35224 + * indicates that there is a least one packet in the Rx FIFO. The
35225 + * packets are moved from the FIFO to memory, where they will be
35226 + * processed when the Endpoint Interrupt Register indicates Transfer
35227 + * Complete or SETUP Phase Done.
35229 + * Repeat the following until the Rx Status Queue is empty:
35230 + * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
35232 + * -# If Receive FIFO is empty then skip to step Clear the interrupt
35234 + * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
35235 + * SETUP data to the buffer
35236 + * -# If OUT Data Packet call dwc_otg_read_packet to copy the data
35237 + * to the destination buffer
35239 +int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd)
35241 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
35242 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
35243 + gintmsk_data_t gintmask = {.d32 = 0 };
35244 + device_grxsts_data_t status;
35245 + dwc_otg_pcd_ep_t *ep;
35246 + gintsts_data_t gintsts;
35248 + static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" };
35251 + //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
35252 + /* Disable the Rx Status Queue Level interrupt */
35253 + gintmask.b.rxstsqlvl = 1;
35254 + dwc_modify_reg32(&global_regs->gintmsk, gintmask.d32, 0);
35256 + /* Get the Status from the top of the FIFO */
35257 + status.d32 = dwc_read_reg32(&global_regs->grxstsp);
35259 + DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
35260 + "pktsts:%x Frame:%d(0x%0x)\n",
35261 + status.b.epnum, status.b.bcnt,
35262 + dpid_str[status.b.dpid],
35263 + status.b.pktsts, status.b.fn, status.b.fn);
35264 + /* Get pointer to EP structure */
35265 + ep = get_out_ep(pcd, status.b.epnum);
35267 + switch (status.b.pktsts) {
35268 + case DWC_DSTS_GOUT_NAK:
35269 + DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
35271 + case DWC_STS_DATA_UPDT:
35272 + DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
35273 + if (status.b.bcnt && ep->dwc_ep.xfer_buff) {
35274 + /** @todo NGS Check for buffer overflow? */
35275 + dwc_otg_read_packet(core_if,
35276 + ep->dwc_ep.xfer_buff,
35278 + ep->dwc_ep.xfer_count += status.b.bcnt;
35279 + ep->dwc_ep.xfer_buff += status.b.bcnt;
35282 + case DWC_STS_XFER_COMP:
35283 + DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
35285 + case DWC_DSTS_SETUP_COMP:
35287 + DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
35290 + case DWC_DSTS_SETUP_UPDT:
35291 + dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32);
35293 + DWC_DEBUGPL(DBG_PCD,
35294 + "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
35295 + pcd->setup_pkt->req.bmRequestType,
35296 + pcd->setup_pkt->req.bRequest,
35297 + UGETW(pcd->setup_pkt->req.wValue),
35298 + UGETW(pcd->setup_pkt->req.wIndex),
35299 + UGETW(pcd->setup_pkt->req.wLength));
35301 + ep->dwc_ep.xfer_count += status.b.bcnt;
35304 + DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
35305 + status.b.pktsts);
35309 + /* Enable the Rx Status Queue Level interrupt */
35310 + dwc_modify_reg32(&global_regs->gintmsk, 0, gintmask.d32);
35311 + /* Clear interrupt */
35313 + gintsts.b.rxstsqlvl = 1;
35314 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
35316 + //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
35321 + * This function examines the Device IN Token Learning Queue to
35322 + * determine the EP number of the last IN token received. This
35323 + * implementation is for the Mass Storage device where there are only
35324 + * 2 IN EPs (Control-IN and BULK-IN).
35326 + * The EP numbers for the first six IN Tokens are in DTKNQR1 and there
35327 + * are 8 EP Numbers in each of the other possible DTKNQ Registers.
35329 + * @param core_if Programming view of DWC_otg controller.
35332 +static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if)
35334 + dwc_otg_device_global_regs_t *dev_global_regs =
35335 + core_if->dev_if->dev_global_regs;
35336 + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
35337 + /* Number of Token Queue Registers */
35338 + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
35339 + dtknq1_data_t dtknqr1;
35340 + uint32_t in_tkn_epnums[4];
35343 + volatile uint32_t *addr = &dev_global_regs->dtknqr1;
35346 + //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
35348 + /* Read the DTKNQ Registers */
35349 + for (i = 0; i < DTKNQ_REG_CNT; i++) {
35350 + in_tkn_epnums[i] = dwc_read_reg32(addr);
35351 + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
35352 + in_tkn_epnums[i]);
35353 + if (addr == &dev_global_regs->dvbusdis) {
35354 + addr = &dev_global_regs->dtknqr3_dthrctl;
35361 + /* Copy the DTKNQR1 data to the bit field. */
35362 + dtknqr1.d32 = in_tkn_epnums[0];
35363 + /* Get the EP numbers */
35364 + in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
35365 + ndx = dtknqr1.b.intknwptr - 1;
35367 + //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
35369 + /** @todo Find a simpler way to calculate the max
35370 + * queue position.*/
35371 + int cnt = TOKEN_Q_DEPTH;
35372 + if (TOKEN_Q_DEPTH <= 6) {
35373 + cnt = TOKEN_Q_DEPTH - 1;
35374 + } else if (TOKEN_Q_DEPTH <= 14) {
35375 + cnt = TOKEN_Q_DEPTH - 7;
35376 + } else if (TOKEN_Q_DEPTH <= 22) {
35377 + cnt = TOKEN_Q_DEPTH - 15;
35379 + cnt = TOKEN_Q_DEPTH - 23;
35381 + epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF;
35384 + epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
35385 + } else if (ndx <= 13) {
35387 + epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
35388 + } else if (ndx <= 21) {
35390 + epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
35391 + } else if (ndx <= 29) {
35393 + epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
35396 + //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
35401 + * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
35402 + * The active request is checked for the next packet to be loaded into
35403 + * the non-periodic Tx FIFO.
35405 +int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd)
35407 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
35408 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
35409 + dwc_otg_dev_in_ep_regs_t *ep_regs;
35410 + gnptxsts_data_t txstatus = {.d32 = 0 };
35411 + gintsts_data_t gintsts;
35414 + dwc_otg_pcd_ep_t *ep = 0;
35415 + uint32_t len = 0;
35418 + /* Get the epnum from the IN Token Learning Queue. */
35419 + epnum = get_ep_of_last_in_token(core_if);
35420 + ep = get_in_ep(pcd, epnum);
35422 + DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum);
35424 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
35426 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
35427 + if (len > ep->dwc_ep.maxpacket) {
35428 + len = ep->dwc_ep.maxpacket;
35430 + dwords = (len + 3) / 4;
35432 + /* While there is space in the queue and space in the FIFO and
35433 + * More data to tranfer, Write packets to the Tx FIFO */
35434 + txstatus.d32 = dwc_read_reg32(&global_regs->gnptxsts);
35435 + DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32);
35437 + while (txstatus.b.nptxqspcavail > 0 &&
35438 + txstatus.b.nptxfspcavail > dwords &&
35439 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) {
35440 + /* Write the FIFO */
35441 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
35442 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
35444 + if (len > ep->dwc_ep.maxpacket) {
35445 + len = ep->dwc_ep.maxpacket;
35448 + dwords = (len + 3) / 4;
35449 + txstatus.d32 = dwc_read_reg32(&global_regs->gnptxsts);
35450 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32);
35453 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
35454 + dwc_read_reg32(&global_regs->gnptxsts));
35456 + /* Clear interrupt */
35458 + gintsts.b.nptxfempty = 1;
35459 + dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
35465 + * This function is called when dedicated Tx FIFO Empty interrupt occurs.
35466 + * The active request is checked for the next packet to be loaded into
35467 + * apropriate Tx FIFO.
35469 +static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum)
35471 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
35472 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
35473 + dwc_otg_dev_in_ep_regs_t *ep_regs;
35474 + dtxfsts_data_t txstatus = {.d32 = 0 };
35475 + dwc_otg_pcd_ep_t *ep = 0;
35476 + uint32_t len = 0;
35479 + ep = get_in_ep(pcd, epnum);
35481 + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
35483 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
35485 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
35487 + if (len > ep->dwc_ep.maxpacket) {
35488 + len = ep->dwc_ep.maxpacket;
35491 + dwords = (len + 3) / 4;
35493 + /* While there is space in the queue and space in the FIFO and
35494 + * More data to tranfer, Write packets to the Tx FIFO */
35495 + txstatus.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts);
35496 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
35498 + while (txstatus.b.txfspcavail > dwords &&
35499 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
35500 + ep->dwc_ep.xfer_len != 0) {
35501 + /* Write the FIFO */
35502 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
35504 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
35505 + if (len > ep->dwc_ep.maxpacket) {
35506 + len = ep->dwc_ep.maxpacket;
35509 + dwords = (len + 3) / 4;
35511 + dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts);
35512 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
35516 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
35517 + dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts));
35523 + * This function is called when the Device is disconnected. It stops
35524 + * any active requests and informs the Gadget driver of the
35527 +void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd)
35529 + int i, num_in_eps, num_out_eps;
35530 + dwc_otg_pcd_ep_t *ep;
35532 + gintmsk_data_t intr_mask = {.d32 = 0 };
35534 + DWC_SPINLOCK(pcd->lock);
35536 + num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
35537 + num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
35539 + DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__);
35540 + /* don't disconnect drivers more than once */
35541 + if (pcd->ep0state == EP0_DISCONNECT) {
35542 + DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__);
35545 + pcd->ep0state = EP0_DISCONNECT;
35547 + /* Reset the OTG state. */
35548 + dwc_otg_pcd_update_otg(pcd, 1);
35550 + /* Disable the NP Tx Fifo Empty Interrupt. */
35551 + intr_mask.b.nptxfempty = 1;
35552 + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
35553 + intr_mask.d32, 0);
35555 + /* Flush the FIFOs */
35556 + /**@todo NGS Flush Periodic FIFOs */
35557 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10);
35558 + dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd));
35560 + /* prevent new request submissions, kill any outstanding requests */
35562 + dwc_otg_request_nuke(ep);
35563 + /* prevent new request submissions, kill any outstanding requests */
35564 + for (i = 0; i < num_in_eps; i++) {
35565 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i];
35566 + dwc_otg_request_nuke(ep);
35568 + /* prevent new request submissions, kill any outstanding requests */
35569 + for (i = 0; i < num_out_eps; i++) {
35570 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i];
35571 + dwc_otg_request_nuke(ep);
35574 + /* report disconnect; the driver is already quiesced */
35575 + if (pcd->fops->disconnect) {
35576 + DWC_SPINUNLOCK(pcd->lock);
35577 + pcd->fops->disconnect(pcd);
35578 + DWC_SPINLOCK(pcd->lock);
35580 + DWC_SPINUNLOCK(pcd->lock);
35584 + * This interrupt indicates that ...
35586 +int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd)
35588 + gintmsk_data_t intr_mask = {.d32 = 0 };
35589 + gintsts_data_t gintsts;
35591 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr");
35592 + intr_mask.b.i2cintr = 1;
35593 + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
35594 + intr_mask.d32, 0);
35596 + /* Clear interrupt */
35598 + gintsts.b.i2cintr = 1;
35599 + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
35605 + * This interrupt indicates that ...
35607 +int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd)
35609 + gintsts_data_t gintsts;
35610 +#if defined(VERBOSE)
35611 + DWC_PRINTF("Early Suspend Detected\n");
35613 + /* Clear interrupt */
35615 + gintsts.b.erlysuspend = 1;
35616 + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
35622 + * This function configures EPO to receive SETUP packets.
35624 + * @todo NGS: Update the comments from the HW FS.
35626 + * -# Program the following fields in the endpoint specific registers
35627 + * for Control OUT EP 0, in order to receive a setup packet
35628 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
35630 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
35631 + * to back setup packets)
35632 + * - In DMA mode, DOEPDMA0 Register with a memory address to
35633 + * store any setup packets received
35635 + * @param core_if Programming view of DWC_otg controller.
35636 + * @param pcd Programming view of the PCD.
35638 +static inline void ep0_out_start(dwc_otg_core_if_t * core_if,
35639 + dwc_otg_pcd_t * pcd)
35641 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
35642 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
35643 + dwc_otg_dev_dma_desc_t *dma_desc;
35644 + depctl_data_t doepctl = {.d32 = 0 };
35647 + DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__,
35648 + dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
35651 + doeptsize0.b.supcnt = 3;
35652 + doeptsize0.b.pktcnt = 1;
35653 + doeptsize0.b.xfersize = 8 * 3;
35655 + if (core_if->dma_enable) {
35656 + if (!core_if->dma_desc_enable) {
35657 + /** put here as for Hermes mode deptisz register should not be written */
35658 + dwc_write_reg32(&dev_if->out_ep_regs[0]->doeptsiz,
35661 + /** @todo dma needs to handle multiple setup packets (up to 3) */
35662 + dwc_write_reg32(&dev_if->out_ep_regs[0]->doepdma,
35663 + pcd->setup_pkt_dma_handle);
35665 + dev_if->setup_desc_index =
35666 + (dev_if->setup_desc_index + 1) & 1;
35668 + dev_if->setup_desc_addr[dev_if->setup_desc_index];
35670 + /** DMA Descriptor Setup */
35671 + dma_desc->status.b.bs = BS_HOST_BUSY;
35672 + dma_desc->status.b.l = 1;
35673 + dma_desc->status.b.ioc = 1;
35674 + dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket;
35675 + dma_desc->buf = pcd->setup_pkt_dma_handle;
35676 + dma_desc->status.b.bs = BS_HOST_READY;
35678 + /** DOEPDMA0 Register write */
35679 + dwc_write_reg32(&dev_if->out_ep_regs[0]->doepdma,
35680 + dev_if->dma_setup_desc_addr[dev_if->
35681 + setup_desc_index]);
35685 + /** put here as for Hermes mode deptisz register should not be written */
35686 + dwc_write_reg32(&dev_if->out_ep_regs[0]->doeptsiz,
35690 + /** DOEPCTL0 Register write */
35691 + doepctl.b.epena = 1;
35692 + doepctl.b.cnak = 1;
35693 + dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
35696 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
35697 + dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
35698 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
35699 + dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl));
35704 + * This interrupt occurs when a USB Reset is detected. When the USB
35705 + * Reset Interrupt occurs the device state is set to DEFAULT and the
35706 + * EP0 state is set to IDLE.
35707 + * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
35708 + * -# Unmask the following interrupt bits
35709 + * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
35710 + * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
35711 + * - DOEPMSK.SETUP = 1
35712 + * - DOEPMSK.XferCompl = 1
35713 + * - DIEPMSK.XferCompl = 1
35714 + * - DIEPMSK.TimeOut = 1
35715 + * -# Program the following fields in the endpoint specific registers
35716 + * for Control OUT EP 0, in order to receive a setup packet
35717 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
35719 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
35720 + * to back setup packets)
35721 + * - In DMA mode, DOEPDMA0 Register with a memory address to
35722 + * store any setup packets received
35723 + * At this point, all the required initialization, except for enabling
35724 + * the control 0 OUT endpoint is done, for receiving SETUP packets.
35726 +int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd)
35728 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
35729 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
35730 + depctl_data_t doepctl = {.d32 = 0 };
35731 + daint_data_t daintmsk = {.d32 = 0 };
35732 + doepmsk_data_t doepmsk = {.d32 = 0 };
35733 + diepmsk_data_t diepmsk = {.d32 = 0 };
35734 + dcfg_data_t dcfg = {.d32 = 0 };
35735 + grstctl_t resetctl = {.d32 = 0 };
35736 + dctl_data_t dctl = {.d32 = 0 };
35738 + gintsts_data_t gintsts;
35739 + pcgcctl_data_t power = {.d32 = 0 };
35741 + power.d32 = dwc_read_reg32(core_if->pcgcctl);
35742 + if (power.b.stoppclk) {
35744 + power.b.stoppclk = 1;
35745 + dwc_modify_reg32(core_if->pcgcctl, power.d32, 0);
35747 + power.b.pwrclmp = 1;
35748 + dwc_modify_reg32(core_if->pcgcctl, power.d32, 0);
35750 + power.b.rstpdwnmodule = 1;
35751 + dwc_modify_reg32(core_if->pcgcctl, power.d32, 0);
35754 + core_if->lx_state = DWC_OTG_L0;
35756 + DWC_PRINTF("USB RESET\n");
35757 +#ifdef DWC_EN_ISOC
35758 + for (i = 1; i < 16; ++i) {
35759 + dwc_otg_pcd_ep_t *ep;
35760 + dwc_ep_t *dwc_ep;
35761 + ep = get_in_ep(pcd, i);
35763 + dwc_ep = &ep->dwc_ep;
35764 + dwc_ep->next_frame = 0xffffffff;
35767 +#endif /* DWC_EN_ISOC */
35769 + /* reset the HNP settings */
35770 + dwc_otg_pcd_update_otg(pcd, 1);
35772 + /* Clear the Remote Wakeup Signalling */
35773 + dctl.b.rmtwkupsig = 1;
35774 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
35776 + /* Set NAK for all OUT EPs */
35777 + doepctl.b.snak = 1;
35778 + for (i = 0; i <= dev_if->num_out_eps; i++) {
35779 + dwc_write_reg32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
35782 + /* Flush the NP Tx FIFO */
35783 + dwc_otg_flush_tx_fifo(core_if, 0x10);
35784 + /* Flush the Learning Queue */
35785 + resetctl.b.intknqflsh = 1;
35786 + dwc_write_reg32(&core_if->core_global_regs->grstctl, resetctl.d32);
35788 + if (core_if->multiproc_int_enable) {
35789 + daintmsk.b.inep0 = 1;
35790 + daintmsk.b.outep0 = 1;
35791 + dwc_write_reg32(&dev_if->dev_global_regs->deachintmsk,
35794 + doepmsk.b.setup = 1;
35795 + doepmsk.b.xfercompl = 1;
35796 + doepmsk.b.ahberr = 1;
35797 + doepmsk.b.epdisabled = 1;
35799 + if (core_if->dma_desc_enable) {
35800 + doepmsk.b.stsphsercvd = 1;
35801 + doepmsk.b.bna = 1;
35804 + doepmsk.b.babble = 1;
35805 + doepmsk.b.nyet = 1;
35807 + if(core_if->dma_enable) {
35808 + doepmsk.b.nak = 1;
35811 + dwc_write_reg32(&dev_if->dev_global_regs->doepeachintmsk[0],
35814 + diepmsk.b.xfercompl = 1;
35815 + diepmsk.b.timeout = 1;
35816 + diepmsk.b.epdisabled = 1;
35817 + diepmsk.b.ahberr = 1;
35818 + diepmsk.b.intknepmis = 1;
35820 + if (core_if->dma_desc_enable) {
35821 + diepmsk.b.bna = 1;
35824 + if(core_if->dma_enable) {
35825 + diepmsk.b.nak = 1;
35828 + dwc_write_reg32(&dev_if->dev_global_regs->diepeachintmsk[0],
35831 + daintmsk.b.inep0 = 1;
35832 + daintmsk.b.outep0 = 1;
35833 + dwc_write_reg32(&dev_if->dev_global_regs->daintmsk,
35836 + doepmsk.b.setup = 1;
35837 + doepmsk.b.xfercompl = 1;
35838 + doepmsk.b.ahberr = 1;
35839 + doepmsk.b.epdisabled = 1;
35841 + if (core_if->dma_desc_enable) {
35842 + doepmsk.b.stsphsercvd = 1;
35843 + doepmsk.b.bna = 1;
35845 + dwc_write_reg32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32);
35847 + diepmsk.b.xfercompl = 1;
35848 + diepmsk.b.timeout = 1;
35849 + diepmsk.b.epdisabled = 1;
35850 + diepmsk.b.ahberr = 1;
35851 + diepmsk.b.intknepmis = 1;
35853 + if (core_if->dma_desc_enable) {
35854 + diepmsk.b.bna = 1;
35857 + dwc_write_reg32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32);
35860 + /* Reset Device Address */
35861 + dcfg.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dcfg);
35862 + dcfg.b.devaddr = 0;
35863 + dwc_write_reg32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
35865 + /* setup EP0 to receive SETUP packets */
35866 + ep0_out_start(core_if, pcd);
35868 + /* Clear interrupt */
35870 + gintsts.b.usbreset = 1;
35871 + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
35877 + * Get the device speed from the device status register and convert it
35878 + * to USB speed constant.
35880 + * @param core_if Programming view of DWC_otg controller.
35882 +static int get_device_speed(dwc_otg_core_if_t * core_if)
35884 + dsts_data_t dsts;
35886 + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
35888 + switch (dsts.b.enumspd) {
35889 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
35890 + speed = USB_SPEED_HIGH;
35892 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
35893 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
35894 + speed = USB_SPEED_FULL;
35897 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
35898 + speed = USB_SPEED_LOW;
35906 + * Read the device status register and set the device speed in the
35907 + * data structure.
35908 + * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
35910 +int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd)
35912 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
35913 + gintsts_data_t gintsts;
35914 + gusbcfg_data_t gusbcfg;
35915 + dwc_otg_core_global_regs_t *global_regs =
35916 + GET_CORE_IF(pcd)->core_global_regs;
35917 + uint8_t utmi16b, utmi8b;
35919 + DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
35921 + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
35928 + dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep);
35931 + print_ep0_state(pcd);
35934 + if (pcd->ep0state == EP0_DISCONNECT) {
35935 + pcd->ep0state = EP0_IDLE;
35936 + } else if (pcd->ep0state == EP0_STALL) {
35937 + pcd->ep0state = EP0_IDLE;
35940 + pcd->ep0state = EP0_IDLE;
35942 + ep0->stopped = 0;
35944 + speed = get_device_speed(GET_CORE_IF(pcd));
35945 + pcd->fops->connect(pcd, speed);
35947 + /* Set USB turnaround time based on device speed and PHY interface. */
35948 + gusbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
35949 + if (speed == USB_SPEED_HIGH) {
35950 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
35951 + DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
35952 + /* ULPI interface */
35953 + gusbcfg.b.usbtrdtim = 9;
35955 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
35956 + DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
35957 + /* UTMI+ interface */
35958 + if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) {
35959 + gusbcfg.b.usbtrdtim = utmi8b;
35960 + } else if (GET_CORE_IF(pcd)->hwcfg4.b.
35961 + utmi_phy_data_width == 1) {
35962 + gusbcfg.b.usbtrdtim = utmi16b;
35963 + } else if (GET_CORE_IF(pcd)->core_params->
35964 + phy_utmi_width == 8) {
35965 + gusbcfg.b.usbtrdtim = utmi8b;
35967 + gusbcfg.b.usbtrdtim = utmi16b;
35970 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
35971 + DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
35972 + /* UTMI+ OR ULPI interface */
35973 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
35974 + /* ULPI interface */
35975 + gusbcfg.b.usbtrdtim = 9;
35977 + /* UTMI+ interface */
35978 + if (GET_CORE_IF(pcd)->core_params->
35979 + phy_utmi_width == 16) {
35980 + gusbcfg.b.usbtrdtim = utmi16b;
35982 + gusbcfg.b.usbtrdtim = utmi8b;
35987 + /* Full or low speed */
35988 + gusbcfg.b.usbtrdtim = 9;
35990 + dwc_write_reg32(&global_regs->gusbcfg, gusbcfg.d32);
35992 + /* Clear interrupt */
35994 + gintsts.b.enumdone = 1;
35995 + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
36001 + * This interrupt indicates that the ISO OUT Packet was dropped due to
36002 + * Rx FIFO full or Rx Status Queue Full. If this interrupt occurs
36003 + * read all the data from the Rx FIFO.
36005 +int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd)
36007 + gintmsk_data_t intr_mask = {.d32 = 0 };
36008 + gintsts_data_t gintsts;
36010 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
36011 + "ISOC Out Dropped");
36013 + intr_mask.b.isooutdrop = 1;
36014 + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
36015 + intr_mask.d32, 0);
36017 + /* Clear interrupt */
36019 + gintsts.b.isooutdrop = 1;
36020 + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
36027 + * This interrupt indicates the end of the portion of the micro-frame
36028 + * for periodic transactions. If there is a periodic transaction for
36029 + * the next frame, load the packets into the EP periodic Tx FIFO.
36031 +int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd)
36033 + gintmsk_data_t intr_mask = {.d32 = 0 };
36034 + gintsts_data_t gintsts;
36035 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP");
36037 + intr_mask.b.eopframe = 1;
36038 + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
36039 + intr_mask.d32, 0);
36041 + /* Clear interrupt */
36043 + gintsts.b.eopframe = 1;
36044 + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
36051 + * This interrupt indicates that EP of the packet on the top of the
36052 + * non-periodic Tx FIFO does not match EP of the IN Token received.
36054 + * The "Device IN Token Queue" Registers are read to determine the
36055 + * order the IN Tokens have been received. The non-periodic Tx FIFO
36056 + * is flushed, so it can be reloaded in the order seen in the IN Token
36059 +int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_core_if_t * core_if)
36061 + gintsts_data_t gintsts;
36062 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
36064 + /* Clear interrupt */
36066 + gintsts.b.epmismatch = 1;
36067 + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
36073 + * This funcion stalls EP0.
36075 +static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val)
36077 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
36078 + usb_device_request_t *ctrl = &pcd->setup_pkt->req;
36079 + DWC_WARN("req %02x.%02x protocol STALL; err %d\n",
36080 + ctrl->bmRequestType, ctrl->bRequest, err_val);
36082 + ep0->dwc_ep.is_in = 1;
36083 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep);
36084 + pcd->ep0.stopped = 1;
36085 + pcd->ep0state = EP0_IDLE;
36086 + ep0_out_start(GET_CORE_IF(pcd), pcd);
36090 + * This functions delegates the setup command to the gadget driver.
36092 +static inline void do_gadget_setup(dwc_otg_pcd_t * pcd,
36093 + usb_device_request_t * ctrl)
36096 + DWC_SPINUNLOCK(pcd->lock);
36097 + ret = pcd->fops->setup(pcd, (uint8_t *) ctrl);
36098 + DWC_SPINLOCK(pcd->lock);
36100 + ep0_do_stall(pcd, ret);
36103 + /** @todo This is a g_file_storage gadget driver specific
36104 + * workaround: a DELAYED_STATUS result from the fsg_setup
36105 + * routine will result in the gadget queueing a EP0 IN status
36106 + * phase for a two-stage control transfer. Exactly the same as
36107 + * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
36108 + * specific request. Need a generic way to know when the gadget
36109 + * driver will queue the status phase. Can we assume when we
36110 + * call the gadget driver setup() function that it will always
36111 + * queue and require the following flag? Need to look into
36115 + if (ret == 256 + 999) {
36116 + pcd->request_config = 1;
36120 +#ifdef DWC_UTE_CFI
36122 + * This functions delegates the CFI setup commands to the gadget driver.
36123 + * This function will return a negative value to indicate a failure.
36125 +static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd,
36126 + struct cfi_usb_ctrlrequest *ctrl_req)
36130 + if (pcd->fops && pcd->fops->cfi_setup) {
36131 + DWC_SPINUNLOCK(pcd->lock);
36132 + ret = pcd->fops->cfi_setup(pcd, ctrl_req);
36133 + DWC_SPINLOCK(pcd->lock);
36135 + ep0_do_stall(pcd, ret);
36145 + * This function starts the Zero-Length Packet for the IN status phase
36146 + * of a 2 stage control transfer.
36148 +static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd)
36150 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
36151 + if (pcd->ep0state == EP0_STALL) {
36155 + pcd->ep0state = EP0_IN_STATUS_PHASE;
36157 + /* Prepare for more SETUP Packets */
36158 + DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
36159 + ep0->dwc_ep.xfer_len = 0;
36160 + ep0->dwc_ep.xfer_count = 0;
36161 + ep0->dwc_ep.is_in = 1;
36162 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
36163 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
36165 + /* Prepare for more SETUP Packets */
36166 + //ep0_out_start(GET_CORE_IF(pcd), pcd);
36170 + * This function starts the Zero-Length Packet for the OUT status phase
36171 + * of a 2 stage control transfer.
36173 +static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd)
36175 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
36176 + if (pcd->ep0state == EP0_STALL) {
36177 + DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
36180 + pcd->ep0state = EP0_OUT_STATUS_PHASE;
36182 + DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
36183 + ep0->dwc_ep.xfer_len = 0;
36184 + ep0->dwc_ep.xfer_count = 0;
36185 + ep0->dwc_ep.is_in = 0;
36186 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
36187 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
36189 + /* Prepare for more SETUP Packets */
36190 + if (GET_CORE_IF(pcd)->dma_enable == 0) {
36191 + ep0_out_start(GET_CORE_IF(pcd), pcd);
36196 + * Clear the EP halt (STALL) and if pending requests start the
36199 +static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
36201 + if (ep->dwc_ep.stall_clear_flag == 0)
36202 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
36204 + /* Reactive the EP */
36205 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
36206 + if (ep->stopped) {
36208 + /* If there is a request in the EP queue start it */
36210 + /** @todo FIXME: this causes an EP mismatch in DMA mode.
36211 + * epmismatch not yet implemented. */
36214 + * Above fixme is solved by implmenting a tasklet to call the
36215 + * start_next_request(), outside of interrupt context at some
36216 + * time after the current time, after a clear-halt setup packet.
36217 + * Still need to implement ep mismatch in the future if a gadget
36218 + * ever uses more than one endpoint at once
36220 + ep->queue_sof = 1;
36221 + DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet);
36223 + /* Start Control Status Phase */
36224 + do_setup_in_status_phase(pcd);
36228 + * This function is called when the SET_FEATURE TEST_MODE Setup packet
36229 + * is sent from the host. The Device Control register is written with
36230 + * the Test Mode bits set to the specified Test Mode. This is done as
36231 + * a tasklet so that the "Status" phase of the control transfer
36232 + * completes before transmitting the TEST packets.
36234 + * @todo This has not been tested since the tasklet struct was put
36235 + * into the PCD struct!
36238 +void do_test_mode(void *data)
36240 + dctl_data_t dctl;
36241 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
36242 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
36243 + int test_mode = pcd->test_mode;
36245 +// DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
36247 + dctl.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dctl);
36248 + switch (test_mode) {
36249 + case 1: // TEST_J
36250 + dctl.b.tstctl = 1;
36253 + case 2: // TEST_K
36254 + dctl.b.tstctl = 2;
36257 + case 3: // TEST_SE0_NAK
36258 + dctl.b.tstctl = 3;
36261 + case 4: // TEST_PACKET
36262 + dctl.b.tstctl = 4;
36265 + case 5: // TEST_FORCE_ENABLE
36266 + dctl.b.tstctl = 5;
36269 + dwc_write_reg32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
36273 + * This function process the GET_STATUS Setup Commands.
36275 +static inline void do_get_status(dwc_otg_pcd_t * pcd)
36277 + usb_device_request_t ctrl = pcd->setup_pkt->req;
36278 + dwc_otg_pcd_ep_t *ep;
36279 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
36280 + uint16_t *status = pcd->status_buf;
36283 + DWC_DEBUGPL(DBG_PCD,
36284 + "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
36285 + ctrl.bmRequestType, ctrl.bRequest,
36286 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
36287 + UGETW(ctrl.wLength));
36290 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
36292 + *status = 0x1; /* Self powered */
36293 + *status |= pcd->remote_wakeup_enable << 1;
36296 + case UT_INTERFACE:
36300 + case UT_ENDPOINT:
36301 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
36302 + if (ep == 0 || UGETW(ctrl.wLength) > 2) {
36303 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
36306 + /** @todo check for EP stall */
36307 + *status = ep->stopped;
36310 + pcd->ep0_pending = 1;
36311 + ep0->dwc_ep.start_xfer_buff = (uint8_t *) status;
36312 + ep0->dwc_ep.xfer_buff = (uint8_t *) status;
36313 + ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle;
36314 + ep0->dwc_ep.xfer_len = 2;
36315 + ep0->dwc_ep.xfer_count = 0;
36316 + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
36317 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
36321 + * This function process the SET_FEATURE Setup Commands.
36323 +static inline void do_set_feature(dwc_otg_pcd_t * pcd)
36325 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
36326 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
36327 + usb_device_request_t ctrl = pcd->setup_pkt->req;
36328 + dwc_otg_pcd_ep_t *ep = 0;
36329 + int32_t otg_cap_param = core_if->core_params->otg_cap;
36330 + gotgctl_data_t gotgctl = {.d32 = 0 };
36332 + DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
36333 + ctrl.bmRequestType, ctrl.bRequest,
36334 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
36335 + UGETW(ctrl.wLength));
36336 + DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param);
36338 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
36340 + switch (UGETW(ctrl.wValue)) {
36341 + case UF_DEVICE_REMOTE_WAKEUP:
36342 + pcd->remote_wakeup_enable = 1;
36345 + case UF_TEST_MODE:
36346 + /* Setup the Test Mode tasklet to do the Test
36347 + * Packet generation after the SETUP Status
36348 + * phase has completed. */
36350 + /** @todo This has not been tested since the
36351 + * tasklet struct was put into the PCD
36353 + pcd->test_mode = UGETW(ctrl.wIndex) >> 8;
36354 + DWC_TASK_SCHEDULE(pcd->test_mode_tasklet);
36357 + case UF_DEVICE_B_HNP_ENABLE:
36358 + DWC_DEBUGPL(DBG_PCDV,
36359 + "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
36361 + /* dev may initiate HNP */
36362 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
36363 + pcd->b_hnp_enable = 1;
36364 + dwc_otg_pcd_update_otg(pcd, 0);
36365 + DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
36366 + /**@todo Is the gotgctl.devhnpen cleared
36367 + * by a USB Reset? */
36368 + gotgctl.b.devhnpen = 1;
36369 + gotgctl.b.hnpreq = 1;
36370 + dwc_write_reg32(&global_regs->gotgctl,
36373 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
36377 + case UF_DEVICE_A_HNP_SUPPORT:
36378 + /* RH port supports HNP */
36379 + DWC_DEBUGPL(DBG_PCDV,
36380 + "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
36381 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
36382 + pcd->a_hnp_support = 1;
36383 + dwc_otg_pcd_update_otg(pcd, 0);
36385 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
36389 + case UF_DEVICE_A_ALT_HNP_SUPPORT:
36390 + /* other RH port does */
36391 + DWC_DEBUGPL(DBG_PCDV,
36392 + "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
36393 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
36394 + pcd->a_alt_hnp_support = 1;
36395 + dwc_otg_pcd_update_otg(pcd, 0);
36397 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
36401 + do_setup_in_status_phase(pcd);
36404 + case UT_INTERFACE:
36405 + do_gadget_setup(pcd, &ctrl);
36408 + case UT_ENDPOINT:
36409 + if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) {
36410 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
36412 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
36416 + dwc_otg_ep_set_stall(core_if, &ep->dwc_ep);
36418 + do_setup_in_status_phase(pcd);
36424 + * This function process the CLEAR_FEATURE Setup Commands.
36426 +static inline void do_clear_feature(dwc_otg_pcd_t * pcd)
36428 + usb_device_request_t ctrl = pcd->setup_pkt->req;
36429 + dwc_otg_pcd_ep_t *ep = 0;
36431 + DWC_DEBUGPL(DBG_PCD,
36432 + "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
36433 + ctrl.bmRequestType, ctrl.bRequest,
36434 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
36435 + UGETW(ctrl.wLength));
36437 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
36439 + switch (UGETW(ctrl.wValue)) {
36440 + case UF_DEVICE_REMOTE_WAKEUP:
36441 + pcd->remote_wakeup_enable = 0;
36444 + case UF_TEST_MODE:
36445 + /** @todo Add CLEAR_FEATURE for TEST modes. */
36448 + do_setup_in_status_phase(pcd);
36451 + case UT_ENDPOINT:
36452 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
36454 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
36458 + pcd_clear_halt(pcd, ep);
36465 + * This function process the SET_ADDRESS Setup Commands.
36467 +static inline void do_set_address(dwc_otg_pcd_t * pcd)
36469 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
36470 + usb_device_request_t ctrl = pcd->setup_pkt->req;
36472 + if (ctrl.bmRequestType == UT_DEVICE) {
36473 + dcfg_data_t dcfg = {.d32 = 0 };
36476 +// DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
36478 + dcfg.b.devaddr = UGETW(ctrl.wValue);
36479 + dwc_modify_reg32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32);
36480 + do_setup_in_status_phase(pcd);
36485 + * This function processes SETUP commands. In Linux, the USB Command
36486 + * processing is done in two places - the first being the PCD and the
36487 + * second in the Gadget Driver (for example, the File-Backed Storage
36488 + * Gadget Driver).
36491 + * <tr><td>Command </td><td>Driver </td><td>Description</td></tr>
36493 + * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as
36494 + * defined in chapter 9 of the USB 2.0 Specification chapter 9
36497 + * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint
36498 + * requests are the ENDPOINT_HALT feature is procesed, all others the
36499 + * interface requests are ignored.</td></tr>
36501 + * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint
36502 + * requests are processed by the PCD. Interface requests are passed
36503 + * to the Gadget Driver.</td></tr>
36505 + * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg,
36506 + * with device address received </td></tr>
36508 + * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the
36509 + * requested descriptor</td></tr>
36511 + * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional -
36512 + * not implemented by any of the existing Gadget Drivers.</td></tr>
36514 + * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable
36515 + * all EPs and enable EPs for new configuration.</td></tr>
36517 + * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return
36518 + * the current configuration</td></tr>
36520 + * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all
36521 + * EPs and enable EPs for new configuration.</td></tr>
36523 + * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the
36524 + * current interface.</td></tr>
36526 + * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug
36527 + * message.</td></tr>
36530 + * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are
36531 + * processed by pcd_setup. Calling the Function Driver's setup function from
36532 + * pcd_setup processes the gadget SETUP commands.
36534 +static inline void pcd_setup(dwc_otg_pcd_t * pcd)
36536 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
36537 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
36538 + usb_device_request_t ctrl = pcd->setup_pkt->req;
36539 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
36541 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
36543 +#ifdef DWC_UTE_CFI
36545 + struct cfi_usb_ctrlrequest cfi_req;
36549 + DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
36550 + ctrl.bmRequestType, ctrl.bRequest,
36551 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
36552 + UGETW(ctrl.wLength));
36555 + doeptsize0.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doeptsiz);
36557 + /** @todo handle > 1 setup packet , assert error for now */
36559 + if (core_if->dma_enable && core_if->dma_desc_enable == 0
36560 + && (doeptsize0.b.supcnt < 2)) {
36562 + ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n");
36565 + /* Clean up the request queue */
36566 + dwc_otg_request_nuke(ep0);
36567 + ep0->stopped = 0;
36569 + if (ctrl.bmRequestType & UE_DIR_IN) {
36570 + ep0->dwc_ep.is_in = 1;
36571 + pcd->ep0state = EP0_IN_DATA_PHASE;
36573 + ep0->dwc_ep.is_in = 0;
36574 + pcd->ep0state = EP0_OUT_DATA_PHASE;
36577 + if (UGETW(ctrl.wLength) == 0) {
36578 + ep0->dwc_ep.is_in = 1;
36579 + pcd->ep0state = EP0_IN_STATUS_PHASE;
36582 + if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) {
36584 +#ifdef DWC_UTE_CFI
36585 + DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t));
36587 + //printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n", ctrl.bRequestType, ctrl.bRequest);
36588 + if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) {
36589 + if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) {
36590 + retval = cfi_setup(pcd, &cfi_req);
36591 + if (retval < 0) {
36592 + ep0_do_stall(pcd, retval);
36593 + pcd->ep0_pending = 0;
36597 + /* if need gadget setup then call it and check the retval */
36598 + if (pcd->cfi->need_gadget_att) {
36600 + cfi_gadget_setup(pcd,
36603 + if (retval < 0) {
36604 + pcd->ep0_pending = 0;
36609 + if (pcd->cfi->need_status_in_complete) {
36610 + do_setup_in_status_phase(pcd);
36617 + /* handle non-standard (class/vendor) requests in the gadget driver */
36618 + do_gadget_setup(pcd, &ctrl);
36622 + /** @todo NGS: Handle bad setup packet? */
36624 +///////////////////////////////////////////
36625 +//// --- Standard Request handling --- ////
36627 + switch (ctrl.bRequest) {
36628 + case UR_GET_STATUS:
36629 + do_get_status(pcd);
36632 + case UR_CLEAR_FEATURE:
36633 + do_clear_feature(pcd);
36636 + case UR_SET_FEATURE:
36637 + do_set_feature(pcd);
36640 + case UR_SET_ADDRESS:
36641 + do_set_address(pcd);
36644 + case UR_SET_INTERFACE:
36645 + case UR_SET_CONFIG:
36646 +// _pcd->request_config = 1; /* Configuration changed */
36647 + do_gadget_setup(pcd, &ctrl);
36650 + case UR_SYNCH_FRAME:
36651 + do_gadget_setup(pcd, &ctrl);
36655 + /* Call the Gadget Driver's setup functions */
36656 + do_gadget_setup(pcd, &ctrl);
36662 + * This function completes the ep0 control transfer.
36664 +static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep)
36666 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
36667 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
36668 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
36669 + dev_if->in_ep_regs[ep->dwc_ep.num];
36671 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
36672 + dev_if->out_ep_regs[ep->dwc_ep.num];
36674 + deptsiz0_data_t deptsiz;
36675 + dev_dma_desc_sts_t desc_sts;
36676 + dwc_otg_pcd_request_t *req;
36678 + dwc_otg_pcd_t *pcd = ep->pcd;
36680 +#ifdef DWC_UTE_CFI
36681 + struct cfi_usb_ctrlrequest *ctrlreq;
36682 + int retval = -DWC_E_NOT_SUPPORTED;
36685 + if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) {
36686 + if (ep->dwc_ep.is_in) {
36688 + DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
36690 + do_setup_out_status_phase(pcd);
36693 + DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
36696 +#ifdef DWC_UTE_CFI
36697 + ctrlreq = &pcd->cfi->ctrl_req;
36699 + if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) {
36700 + if (ctrlreq->bRequest > 0xB0
36701 + && ctrlreq->bRequest < 0xBF) {
36703 + /* Return if the PCD failed to handle the request */
36706 + ctrl_write_complete(pcd->cfi,
36709 + ("ERROR setting a new value in the PCD(%d)\n",
36711 + ep0_do_stall(pcd, retval);
36712 + pcd->ep0_pending = 0;
36716 + /* If the gadget needs to be notified on the request */
36717 + if (pcd->cfi->need_gadget_att == 1) {
36718 + //retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req);
36720 + cfi_gadget_setup(pcd,
36724 + /* Return from the function if the gadget failed to process
36725 + * the request properly - this should never happen !!!
36727 + if (retval < 0) {
36729 + ("ERROR setting a new value in the gadget(%d)\n",
36731 + pcd->ep0_pending = 0;
36736 + CFI_INFO("%s: RETVAL=%d\n", __func__,
36738 + /* If we hit here then the PCD and the gadget has properly
36739 + * handled the request - so send the ZLP IN to the host.
36741 + /* @todo: MAS - decide whether we need to start the setup
36742 + * stage based on the need_setup value of the cfi object
36744 + do_setup_in_status_phase(pcd);
36745 + pcd->ep0_pending = 0;
36751 + do_setup_in_status_phase(pcd);
36753 + pcd->ep0_pending = 0;
36757 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
36760 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
36762 + if (pcd->ep0state == EP0_OUT_STATUS_PHASE
36763 + || pcd->ep0state == EP0_IN_STATUS_PHASE) {
36765 + } else if (ep->dwc_ep.is_in) {
36766 + deptsiz.d32 = dwc_read_reg32(&in_ep_regs->dieptsiz);
36767 + if (core_if->dma_desc_enable != 0)
36768 + desc_sts = dev_if->in_desc_addr->status;
36770 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xfersize=%d pktcnt=%d\n",
36771 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
36772 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
36775 + if (((core_if->dma_desc_enable == 0)
36776 + && (deptsiz.b.xfersize == 0))
36777 + || ((core_if->dma_desc_enable != 0)
36778 + && (desc_sts.b.bytes == 0))) {
36779 + req->actual = ep->dwc_ep.xfer_count;
36780 + /* Is a Zero Len Packet needed? */
36781 + if (req->sent_zlp) {
36783 + DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
36785 + req->sent_zlp = 0;
36787 + do_setup_out_status_phase(pcd);
36792 + deptsiz.d32 = dwc_read_reg32(&out_ep_regs->doeptsiz);
36793 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n",
36794 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
36795 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
36797 + req->actual = ep->dwc_ep.xfer_count;
36799 + /* Is a Zero Len Packet needed? */
36800 + if (req->sent_zlp) {
36802 + DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
36804 + req->sent_zlp = 0;
36806 + if (core_if->dma_desc_enable == 0)
36807 + do_setup_in_status_phase(pcd);
36810 + /* Complete the request */
36812 + dwc_otg_request_done(ep, req, 0);
36813 + ep->dwc_ep.start_xfer_buff = 0;
36814 + ep->dwc_ep.xfer_buff = 0;
36815 + ep->dwc_ep.xfer_len = 0;
36821 +#ifdef DWC_UTE_CFI
36823 + * This function calculates traverses all the CFI DMA descriptors and
36824 + * and accumulates the bytes that are left to be transfered.
36826 + * @return The total bytes left to transfered, or a negative value as failure
36828 +static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep)
36832 + struct dwc_otg_dma_desc *ddesc = NULL;
36833 + struct cfi_ep *cfiep;
36835 + /* See if the pcd_ep has its respective cfi_ep mapped */
36836 + cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep);
36838 + CFI_INFO("%s: Failed to find ep\n", __func__);
36842 + ddesc = ep->dwc_ep.descs;
36844 + for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) {
36846 +#if defined(PRINT_CFI_DMA_DESCS)
36847 + print_desc(ddesc, ep->ep.name, i);
36849 + ret += ddesc->status.b.bytes;
36854 + CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__,
36862 + * This function completes the request for the EP. If there are
36863 + * additional requests for the EP in the queue they will be started.
36865 +static void complete_ep(dwc_otg_pcd_ep_t * ep)
36867 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
36868 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
36869 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
36870 + dev_if->in_ep_regs[ep->dwc_ep.num];
36871 + deptsiz_data_t deptsiz;
36872 + dev_dma_desc_sts_t desc_sts;
36873 + dwc_otg_pcd_request_t *req = 0;
36874 + dwc_otg_dev_dma_desc_t *dma_desc;
36875 + uint32_t byte_count = 0;
36879 + DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num,
36880 + (ep->dwc_ep.is_in ? "IN" : "OUT"));
36882 + /* Get any pending requests */
36883 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
36884 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
36886 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
36890 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
36894 + DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending);
36896 + if (ep->dwc_ep.is_in) {
36897 + deptsiz.d32 = dwc_read_reg32(&in_ep_regs->dieptsiz);
36899 + if (core_if->dma_enable) {
36900 + if (core_if->dma_desc_enable == 0) {
36901 + if (deptsiz.b.xfersize == 0
36902 + && deptsiz.b.pktcnt == 0) {
36904 + ep->dwc_ep.xfer_len -
36905 + ep->dwc_ep.xfer_count;
36907 + ep->dwc_ep.xfer_buff += byte_count;
36908 + ep->dwc_ep.dma_addr += byte_count;
36909 + ep->dwc_ep.xfer_count += byte_count;
36911 + DWC_DEBUGPL(DBG_PCDV,
36912 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
36915 + is_in ? "IN" : "OUT"),
36916 + ep->dwc_ep.xfer_len,
36917 + deptsiz.b.xfersize,
36918 + deptsiz.b.pktcnt);
36920 + if (ep->dwc_ep.xfer_len <
36921 + ep->dwc_ep.total_len) {
36922 + dwc_otg_ep_start_transfer
36923 + (core_if, &ep->dwc_ep);
36924 + } else if (ep->dwc_ep.sent_zlp) {
36926 + * This fragment of code should initiate 0
36927 + * length trasfer in case if it is queued
36928 + * a trasfer with size divisible to EPs max
36929 + * packet size and with usb_request zero field
36930 + * is set, which means that after data is transfered,
36931 + * it is also should be transfered
36932 + * a 0 length packet at the end. For Slave and
36933 + * Buffer DMA modes in this case SW has
36934 + * to initiate 2 transfers one with transfer size,
36935 + * and the second with 0 size. For Desriptor
36936 + * DMA mode SW is able to initiate a transfer,
36937 + * which will handle all the packets including
36938 + * the last 0 legth.
36940 + ep->dwc_ep.sent_zlp = 0;
36941 + dwc_otg_ep_start_zl_transfer
36942 + (core_if, &ep->dwc_ep);
36948 + ("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n",
36950 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
36951 + deptsiz.b.xfersize,
36952 + deptsiz.b.pktcnt);
36955 + dma_desc = ep->dwc_ep.desc_addr;
36957 + ep->dwc_ep.sent_zlp = 0;
36959 +#ifdef DWC_UTE_CFI
36960 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
36961 + ep->dwc_ep.buff_mode);
36962 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
36965 + residue = cfi_calc_desc_residue(ep);
36969 + byte_count = residue;
36972 + for (i = 0; i < ep->dwc_ep.desc_cnt;
36974 + desc_sts = dma_desc->status;
36975 + byte_count += desc_sts.b.bytes;
36978 +#ifdef DWC_UTE_CFI
36981 + if (byte_count == 0) {
36982 + ep->dwc_ep.xfer_count =
36983 + ep->dwc_ep.total_len;
36986 + DWC_WARN("Incomplete transfer\n");
36990 + if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) {
36991 + DWC_DEBUGPL(DBG_PCDV,
36992 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
36994 + ep->dwc_ep.is_in ? "IN" : "OUT",
36995 + ep->dwc_ep.xfer_len,
36996 + deptsiz.b.xfersize,
36997 + deptsiz.b.pktcnt);
36999 + /* Check if the whole transfer was completed,
37000 + * if no, setup transfer for next portion of data
37002 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
37003 + dwc_otg_ep_start_transfer(core_if,
37005 + } else if (ep->dwc_ep.sent_zlp) {
37007 + * This fragment of code should initiate 0
37008 + * length trasfer in case if it is queued
37009 + * a trasfer with size divisible to EPs max
37010 + * packet size and with usb_request zero field
37011 + * is set, which means that after data is transfered,
37012 + * it is also should be transfered
37013 + * a 0 length packet at the end. For Slave and
37014 + * Buffer DMA modes in this case SW has
37015 + * to initiate 2 transfers one with transfer size,
37016 + * and the second with 0 size. For Desriptor
37017 + * DMA mode SW is able to initiate a transfer,
37018 + * which will handle all the packets including
37019 + * the last 0 legth.
37021 + ep->dwc_ep.sent_zlp = 0;
37022 + dwc_otg_ep_start_zl_transfer(core_if,
37030 + ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n",
37032 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
37033 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
37037 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
37038 + dev_if->out_ep_regs[ep->dwc_ep.num];
37039 + desc_sts.d32 = 0;
37040 + if (core_if->dma_enable) {
37041 + if (core_if->dma_desc_enable) {
37042 + dma_desc = ep->dwc_ep.desc_addr;
37044 + ep->dwc_ep.sent_zlp = 0;
37046 +#ifdef DWC_UTE_CFI
37047 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
37048 + ep->dwc_ep.buff_mode);
37049 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
37051 + residue = cfi_calc_desc_residue(ep);
37054 + byte_count = residue;
37058 + for (i = 0; i < ep->dwc_ep.desc_cnt;
37060 + desc_sts = dma_desc->status;
37061 + byte_count += desc_sts.b.bytes;
37065 +#ifdef DWC_UTE_CFI
37068 + ep->dwc_ep.xfer_count = ep->dwc_ep.total_len
37070 + ((4 - (ep->dwc_ep.total_len & 0x3)) & 0x3);
37075 + dwc_read_reg32(&out_ep_regs->doeptsiz);
37077 + byte_count = (ep->dwc_ep.xfer_len -
37078 + ep->dwc_ep.xfer_count -
37079 + deptsiz.b.xfersize);
37080 + ep->dwc_ep.xfer_buff += byte_count;
37081 + ep->dwc_ep.dma_addr += byte_count;
37082 + ep->dwc_ep.xfer_count += byte_count;
37084 + /* Check if the whole transfer was completed,
37085 + * if no, setup transfer for next portion of data
37087 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
37088 + dwc_otg_ep_start_transfer(core_if,
37090 + } else if (ep->dwc_ep.sent_zlp) {
37092 + * This fragment of code should initiate 0
37093 + * length trasfer in case if it is queued
37094 + * a trasfer with size divisible to EPs max
37095 + * packet size and with usb_request zero field
37096 + * is set, which means that after data is transfered,
37097 + * it is also should be transfered
37098 + * a 0 length packet at the end. For Slave and
37099 + * Buffer DMA modes in this case SW has
37100 + * to initiate 2 transfers one with transfer size,
37101 + * and the second with 0 size. For Desriptor
37102 + * DMA mode SW is able to initiate a transfer,
37103 + * which will handle all the packets including
37104 + * the last 0 legth.
37106 + ep->dwc_ep.sent_zlp = 0;
37107 + dwc_otg_ep_start_zl_transfer(core_if,
37115 + /* Check if the whole transfer was completed,
37116 + * if no, setup transfer for next portion of data
37118 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
37119 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
37120 + } else if (ep->dwc_ep.sent_zlp) {
37122 + * This fragment of code should initiate 0
37123 + * length trasfer in case if it is queued
37124 + * a trasfer with size divisible to EPs max
37125 + * packet size and with usb_request zero field
37126 + * is set, which means that after data is transfered,
37127 + * it is also should be transfered
37128 + * a 0 length packet at the end. For Slave and
37129 + * Buffer DMA modes in this case SW has
37130 + * to initiate 2 transfers one with transfer size,
37131 + * and the second with 0 size. For Desriptor
37132 + * DMA mode SW is able to initiate a transfer,
37133 + * which will handle all the packets including
37134 + * the last 0 legth.
37136 + ep->dwc_ep.sent_zlp = 0;
37137 + dwc_otg_ep_start_zl_transfer(core_if,
37144 + DWC_DEBUGPL(DBG_PCDV,
37145 + "addr %p, %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n",
37146 + &out_ep_regs->doeptsiz, ep->dwc_ep.num,
37147 + ep->dwc_ep.is_in ? "IN" : "OUT",
37148 + ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count,
37149 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
37152 + /* Complete the request */
37154 +#ifdef DWC_UTE_CFI
37155 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
37156 + req->actual = ep->dwc_ep.cfi_req_len - byte_count;
37159 + req->actual = ep->dwc_ep.xfer_count;
37160 +#ifdef DWC_UTE_CFI
37164 + dwc_otg_request_done(ep, req, 0);
37166 + ep->dwc_ep.start_xfer_buff = 0;
37167 + ep->dwc_ep.xfer_buff = 0;
37168 + ep->dwc_ep.xfer_len = 0;
37170 + /* If there is a request in the queue start it. */
37171 + start_next_request(ep);
37175 +#ifdef DWC_EN_ISOC
37178 + * This function BNA interrupt for Isochronous EPs
37181 +static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep)
37183 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
37184 + volatile uint32_t *addr;
37185 + depctl_data_t depctl = {.d32 = 0 };
37186 + dwc_otg_pcd_t *pcd = ep->pcd;
37187 + dwc_otg_dev_dma_desc_t *dma_desc;
37191 + dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num);
37193 + if (dwc_ep->is_in) {
37194 + dev_dma_desc_sts_t sts = {.d32 = 0 };
37195 + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
37196 + sts.d32 = dma_desc->status.d32;
37197 + sts.b_iso_in.bs = BS_HOST_READY;
37198 + dma_desc->status.d32 = sts.d32;
37201 + dev_dma_desc_sts_t sts = {.d32 = 0 };
37202 + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
37203 + sts.d32 = dma_desc->status.d32;
37204 + sts.b_iso_out.bs = BS_HOST_READY;
37205 + dma_desc->status.d32 = sts.d32;
37209 + if (dwc_ep->is_in == 0) {
37211 + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->
37215 + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
37217 + depctl.b.epena = 1;
37218 + dwc_modify_reg32(addr, depctl.d32, depctl.d32);
37222 + * This function sets latest iso packet information(non-PTI mode)
37224 + * @param core_if Programming view of DWC_otg controller.
37225 + * @param ep The EP to start the transfer on.
37228 +void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
37230 + deptsiz_data_t deptsiz = {.d32 = 0 };
37231 + dma_addr_t dma_addr;
37234 + if (ep->proc_buf_num)
37235 + dma_addr = ep->dma_addr1;
37237 + dma_addr = ep->dma_addr0;
37241 + dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]->
37243 + offset = ep->data_per_frame;
37246 + dwc_read_reg32(&core_if->dev_if->out_ep_regs[ep->num]->
37249 + ep->data_per_frame +
37250 + (0x4 & (0x4 - (ep->data_per_frame & 0x3)));
37253 + if (!deptsiz.b.xfersize) {
37254 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
37255 + ep->pkt_info[ep->cur_pkt].offset =
37256 + ep->cur_pkt_dma_addr - dma_addr;
37257 + ep->pkt_info[ep->cur_pkt].status = 0;
37259 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
37260 + ep->pkt_info[ep->cur_pkt].offset =
37261 + ep->cur_pkt_dma_addr - dma_addr;
37262 + ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA;
37264 + ep->cur_pkt_addr += offset;
37265 + ep->cur_pkt_dma_addr += offset;
37270 + * This function sets latest iso packet information(DDMA mode)
37272 + * @param core_if Programming view of DWC_otg controller.
37273 + * @param dwc_ep The EP to start the transfer on.
37276 +static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if,
37277 + dwc_ep_t * dwc_ep)
37279 + dwc_otg_dev_dma_desc_t *dma_desc;
37280 + dev_dma_desc_sts_t sts = {.d32 = 0 };
37281 + iso_pkt_info_t *iso_packet;
37282 + uint32_t data_per_desc;
37286 + iso_packet = dwc_ep->pkt_info;
37288 + /** Reinit closed DMA Descriptors*/
37289 + /** ISO OUT EP */
37290 + if (dwc_ep->is_in == 0) {
37292 + dwc_ep->iso_desc_addr +
37293 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
37296 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
37297 + i += dwc_ep->pkt_per_frm) {
37298 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
37300 + ((j + 1) * dwc_ep->maxpacket >
37301 + dwc_ep->data_per_frame) ? dwc_ep->
37303 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
37305 + (data_per_desc % 4) ? (4 -
37309 + sts.d32 = dma_desc->status.d32;
37311 + /* Write status in iso_packet_decsriptor */
37312 + iso_packet->status =
37313 + sts.b_iso_out.rxsts +
37314 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
37315 + if (iso_packet->status) {
37316 + iso_packet->status = -DWC_E_NO_DATA;
37319 + /* Received data length */
37320 + if (!sts.b_iso_out.rxbytes) {
37321 + iso_packet->length =
37323 + sts.b_iso_out.rxbytes;
37325 + iso_packet->length =
37327 + sts.b_iso_out.rxbytes + (4 -
37333 + iso_packet->offset = offset;
37335 + offset += data_per_desc;
37341 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
37343 + ((j + 1) * dwc_ep->maxpacket >
37344 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
37345 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
37347 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
37349 + sts.d32 = dma_desc->status.d32;
37351 + /* Write status in iso_packet_decsriptor */
37352 + iso_packet->status =
37353 + sts.b_iso_out.rxsts +
37354 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
37355 + if (iso_packet->status) {
37356 + iso_packet->status = -DWC_E_NO_DATA;
37359 + /* Received data length */
37360 + iso_packet->length =
37361 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
37363 + iso_packet->offset = offset;
37365 + offset += data_per_desc;
37370 + sts.d32 = dma_desc->status.d32;
37372 + /* Write status in iso_packet_decsriptor */
37373 + iso_packet->status =
37374 + sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE);
37375 + if (iso_packet->status) {
37376 + iso_packet->status = -DWC_E_NO_DATA;
37378 + /* Received data length */
37379 + if (!sts.b_iso_out.rxbytes) {
37380 + iso_packet->length =
37381 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
37383 + iso_packet->length =
37384 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes +
37385 + (4 - dwc_ep->data_per_frame % 4);
37388 + iso_packet->offset = offset;
37393 + dwc_ep->iso_desc_addr +
37394 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
37396 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
37397 + sts.d32 = dma_desc->status.d32;
37399 + /* Write status in iso packet descriptor */
37400 + iso_packet->status =
37401 + sts.b_iso_in.txsts +
37402 + (sts.b_iso_in.bs ^ BS_DMA_DONE);
37403 + if (iso_packet->status != 0) {
37404 + iso_packet->status = -DWC_E_NO_DATA;
37407 + /* Bytes has been transfered */
37408 + iso_packet->length =
37409 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
37415 + sts.d32 = dma_desc->status.d32;
37416 + while (sts.b_iso_in.bs == BS_DMA_BUSY) {
37417 + sts.d32 = dma_desc->status.d32;
37420 + /* Write status in iso packet descriptor ??? do be done with ERROR codes */
37421 + iso_packet->status =
37422 + sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE);
37423 + if (iso_packet->status != 0) {
37424 + iso_packet->status = -DWC_E_NO_DATA;
37427 + /* Bytes has been transfered */
37428 + iso_packet->length =
37429 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
37434 + * This function reinitialize DMA Descriptors for Isochronous transfer
37436 + * @param core_if Programming view of DWC_otg controller.
37437 + * @param dwc_ep The EP to start the transfer on.
37440 +static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
37443 + dwc_otg_dev_dma_desc_t *dma_desc;
37444 + dma_addr_t dma_ad;
37445 + volatile uint32_t *addr;
37446 + dev_dma_desc_sts_t sts = {.d32 = 0 };
37447 + uint32_t data_per_desc;
37449 + if (dwc_ep->is_in == 0) {
37450 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
37452 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
37455 + if (dwc_ep->proc_buf_num == 0) {
37456 + /** Buffer 0 descriptors setup */
37457 + dma_ad = dwc_ep->dma_addr0;
37459 + /** Buffer 1 descriptors setup */
37460 + dma_ad = dwc_ep->dma_addr1;
37463 + /** Reinit closed DMA Descriptors*/
37464 + /** ISO OUT EP */
37465 + if (dwc_ep->is_in == 0) {
37467 + dwc_ep->iso_desc_addr +
37468 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
37470 + sts.b_iso_out.bs = BS_HOST_READY;
37471 + sts.b_iso_out.rxsts = 0;
37472 + sts.b_iso_out.l = 0;
37473 + sts.b_iso_out.sp = 0;
37474 + sts.b_iso_out.ioc = 0;
37475 + sts.b_iso_out.pid = 0;
37476 + sts.b_iso_out.framenum = 0;
37478 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
37479 + i += dwc_ep->pkt_per_frm) {
37480 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
37482 + ((j + 1) * dwc_ep->maxpacket >
37483 + dwc_ep->data_per_frame) ? dwc_ep->
37485 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
37487 + (data_per_desc % 4) ? (4 -
37490 + sts.b_iso_out.rxbytes = data_per_desc;
37491 + dma_desc->buf = dma_ad;
37492 + dma_desc->status.d32 = sts.d32;
37494 + dma_ad += data_per_desc;
37499 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
37502 + ((j + 1) * dwc_ep->maxpacket >
37503 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
37504 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
37506 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
37507 + sts.b_iso_out.rxbytes = data_per_desc;
37509 + dma_desc->buf = dma_ad;
37510 + dma_desc->status.d32 = sts.d32;
37513 + dma_ad += data_per_desc;
37516 + sts.b_iso_out.ioc = 1;
37517 + sts.b_iso_out.l = dwc_ep->proc_buf_num;
37520 + ((j + 1) * dwc_ep->maxpacket >
37521 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
37522 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
37524 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
37525 + sts.b_iso_out.rxbytes = data_per_desc;
37527 + dma_desc->buf = dma_ad;
37528 + dma_desc->status.d32 = sts.d32;
37533 + dwc_ep->iso_desc_addr +
37534 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
37536 + sts.b_iso_in.bs = BS_HOST_READY;
37537 + sts.b_iso_in.txsts = 0;
37538 + sts.b_iso_in.sp = 0;
37539 + sts.b_iso_in.ioc = 0;
37540 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
37541 + sts.b_iso_in.framenum = dwc_ep->next_frame;
37542 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
37543 + sts.b_iso_in.l = 0;
37545 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
37546 + dma_desc->buf = dma_ad;
37547 + dma_desc->status.d32 = sts.d32;
37549 + sts.b_iso_in.framenum += dwc_ep->bInterval;
37550 + dma_ad += dwc_ep->data_per_frame;
37554 + sts.b_iso_in.ioc = 1;
37555 + sts.b_iso_in.l = dwc_ep->proc_buf_num;
37557 + dma_desc->buf = dma_ad;
37558 + dma_desc->status.d32 = sts.d32;
37560 + dwc_ep->next_frame =
37561 + sts.b_iso_in.framenum + dwc_ep->bInterval * 1;
37563 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
37567 + * This function is to handle Iso EP transfer complete interrupt
37568 + * in case Iso out packet was dropped
37570 + * @param core_if Programming view of DWC_otg controller.
37571 + * @param dwc_ep The EP for wihich transfer complete was asserted
37574 +static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if,
37575 + dwc_ep_t * dwc_ep)
37577 + uint32_t dma_addr;
37578 + uint32_t drp_pkt;
37579 + uint32_t drp_pkt_cnt;
37580 + deptsiz_data_t deptsiz = {.d32 = 0 };
37581 + depctl_data_t depctl = {.d32 = 0 };
37585 + dwc_read_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->
37588 + drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt;
37589 + drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm);
37591 + /* Setting dropped packets status */
37592 + for (i = 0; i < drp_pkt_cnt; ++i) {
37593 + dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA;
37595 + deptsiz.b.pktcnt--;
37598 + if (deptsiz.b.pktcnt > 0) {
37599 + deptsiz.b.xfersize =
37600 + dwc_ep->xfer_len - (dwc_ep->pkt_cnt -
37601 + deptsiz.b.pktcnt) * dwc_ep->maxpacket;
37603 + deptsiz.b.xfersize = 0;
37604 + deptsiz.b.pktcnt = 0;
37607 + dwc_write_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz,
37610 + if (deptsiz.b.pktcnt > 0) {
37611 + if (dwc_ep->proc_buf_num) {
37613 + dwc_ep->dma_addr1 + dwc_ep->xfer_len -
37614 + deptsiz.b.xfersize;
37617 + dwc_ep->dma_addr0 + dwc_ep->xfer_len -
37618 + deptsiz.b.xfersize;;
37621 + dwc_write_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->
37622 + doepdma, dma_addr);
37624 + /** Re-enable endpoint, clear nak */
37626 + depctl.b.epena = 1;
37627 + depctl.b.cnak = 1;
37629 + dwc_modify_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->
37630 + doepctl, depctl.d32, depctl.d32);
37638 + * This function sets iso packets information(PTI mode)
37640 + * @param core_if Programming view of DWC_otg controller.
37641 + * @param ep The EP to start the transfer on.
37644 +static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
37647 + dma_addr_t dma_ad;
37648 + iso_pkt_info_t *packet_info = ep->pkt_info;
37650 + uint32_t frame_data;
37651 + deptsiz_data_t deptsiz;
37653 + if (ep->proc_buf_num == 0) {
37654 + /** Buffer 0 descriptors setup */
37655 + dma_ad = ep->dma_addr0;
37657 + /** Buffer 1 descriptors setup */
37658 + dma_ad = ep->dma_addr1;
37663 + dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]->
37667 + dwc_read_reg32(&core_if->dev_if->out_ep_regs[ep->num]->
37671 + if (!deptsiz.b.xfersize) {
37673 + for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) {
37674 + frame_data = ep->data_per_frame;
37675 + for (j = 0; j < ep->pkt_per_frm; ++j) {
37677 + /* Packet status - is not set as initially
37678 + * it is set to 0 and if packet was sent
37679 + successfully, status field will remain 0*/
37681 + /* Bytes has been transfered */
37682 + packet_info->length =
37684 + frame_data) ? ep->maxpacket : frame_data;
37686 + /* Received packet offset */
37687 + packet_info->offset = offset;
37688 + offset += packet_info->length;
37689 + frame_data -= packet_info->length;
37696 + /* This is a workaround for in case of Transfer Complete with
37697 + * PktDrpSts interrupts merging - in this case Transfer complete
37698 + * interrupt for Isoc Out Endpoint is asserted without PktDrpSts
37699 + * set and with DOEPTSIZ register non zero. Investigations showed,
37700 + * that this happens when Out packet is dropped, but because of
37701 + * interrupts merging during first interrupt handling PktDrpSts
37702 + * bit is cleared and for next merged interrupts it is not reset.
37703 + * In this case SW hadles the interrupt as if PktDrpSts bit is set.
37708 + return handle_iso_out_pkt_dropped(core_if, ep);
37714 + * This function is to handle Iso EP transfer complete interrupt
37716 + * @param pcd The PCD
37717 + * @param ep The EP for which transfer complete was asserted
37720 +static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
37722 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
37723 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
37724 + uint8_t is_last = 0;
37726 + if(ep->dwc_ep.next_frame == 0xffffffff) {
37727 + DWC_WARN("Next frame is not set!\n");
37731 + if (core_if->dma_enable) {
37732 + if (core_if->dma_desc_enable) {
37733 + set_ddma_iso_pkts_info(core_if, dwc_ep);
37734 + reinit_ddma_iso_xfer(core_if, dwc_ep);
37737 + if (core_if->pti_enh_enable) {
37738 + if (set_iso_pkts_info(core_if, dwc_ep)) {
37739 + dwc_ep->proc_buf_num =
37740 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
37741 + dwc_otg_iso_ep_start_buf_transfer
37742 + (core_if, dwc_ep);
37746 + set_current_pkt_info(core_if, dwc_ep);
37747 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
37749 + dwc_ep->cur_pkt = 0;
37750 + dwc_ep->proc_buf_num =
37751 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
37752 + if (dwc_ep->proc_buf_num) {
37753 + dwc_ep->cur_pkt_addr =
37754 + dwc_ep->xfer_buff1;
37755 + dwc_ep->cur_pkt_dma_addr =
37756 + dwc_ep->dma_addr1;
37758 + dwc_ep->cur_pkt_addr =
37759 + dwc_ep->xfer_buff0;
37760 + dwc_ep->cur_pkt_dma_addr =
37761 + dwc_ep->dma_addr0;
37765 + dwc_otg_iso_ep_start_frm_transfer(core_if,
37770 + set_current_pkt_info(core_if, dwc_ep);
37771 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
37773 + dwc_ep->cur_pkt = 0;
37774 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
37775 + if (dwc_ep->proc_buf_num) {
37776 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1;
37777 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1;
37779 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0;
37780 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0;
37784 + dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep);
37787 + dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle);
37789 +#endif /* DWC_EN_ISOC */
37792 + * This function handles EP0 Control transfers.
37794 + * The state of the control tranfers are tracked in
37795 + * <code>ep0state</code>.
37797 +static void handle_ep0(dwc_otg_pcd_t * pcd)
37799 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
37800 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
37801 + dev_dma_desc_sts_t desc_sts;
37802 + deptsiz0_data_t deptsiz;
37803 + uint32_t byte_count;
37806 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
37807 + print_ep0_state(pcd);
37810 +// DWC_PRINTF("HANDLE EP0\n");
37812 + switch (pcd->ep0state) {
37813 + case EP0_DISCONNECT:
37817 + pcd->request_config = 0;
37822 + case EP0_IN_DATA_PHASE:
37824 + DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
37825 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
37826 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
37829 + if (core_if->dma_enable != 0) {
37831 + * For EP0 we can only program 1 packet at a time so we
37832 + * need to do the make calculations after each complete.
37833 + * Call write_packet to make the calculations, as in
37834 + * slave mode, and use those values to determine if we
37837 + if (core_if->dma_desc_enable == 0) {
37839 + dwc_read_reg32(&core_if->dev_if->
37840 + in_ep_regs[0]->dieptsiz);
37842 + ep0->dwc_ep.xfer_len - deptsiz.b.xfersize;
37845 + core_if->dev_if->in_desc_addr->status;
37847 + ep0->dwc_ep.xfer_len - desc_sts.b.bytes;
37849 + ep0->dwc_ep.xfer_count += byte_count;
37850 + ep0->dwc_ep.xfer_buff += byte_count;
37851 + ep0->dwc_ep.dma_addr += byte_count;
37853 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
37854 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
37856 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
37857 + } else if (ep0->dwc_ep.sent_zlp) {
37858 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
37860 + ep0->dwc_ep.sent_zlp = 0;
37861 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
37863 + ep0_complete_request(ep0);
37864 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
37867 + case EP0_OUT_DATA_PHASE:
37869 + DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
37870 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
37871 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
37873 + if (core_if->dma_enable != 0) {
37874 + if (core_if->dma_desc_enable == 0) {
37876 + dwc_read_reg32(&core_if->dev_if->
37877 + out_ep_regs[0]->doeptsiz);
37879 + ep0->dwc_ep.maxpacket - deptsiz.b.xfersize;
37882 + core_if->dev_if->out_desc_addr->status;
37884 + ep0->dwc_ep.maxpacket - desc_sts.b.bytes;
37886 + ep0->dwc_ep.xfer_count += byte_count;
37887 + ep0->dwc_ep.xfer_buff += byte_count;
37888 + ep0->dwc_ep.dma_addr += byte_count;
37890 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
37891 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
37893 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
37894 + } else if (ep0->dwc_ep.sent_zlp) {
37895 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
37897 + ep0->dwc_ep.sent_zlp = 0;
37898 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
37900 + ep0_complete_request(ep0);
37901 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
37905 + case EP0_IN_STATUS_PHASE:
37906 + case EP0_OUT_STATUS_PHASE:
37907 + DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
37908 + ep0_complete_request(ep0);
37909 + pcd->ep0state = EP0_IDLE;
37910 + ep0->stopped = 1;
37911 + ep0->dwc_ep.is_in = 0; /* OUT for next SETUP */
37913 + /* Prepare for more SETUP Packets */
37914 + if (core_if->dma_enable) {
37915 + ep0_out_start(core_if, pcd);
37920 + DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
37924 + print_ep0_state(pcd);
37929 + * Restart transfer
37931 +static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum)
37933 + dwc_otg_core_if_t *core_if;
37934 + dwc_otg_dev_if_t *dev_if;
37935 + deptsiz_data_t dieptsiz = {.d32 = 0 };
37936 + dwc_otg_pcd_ep_t *ep;
37938 + ep = get_in_ep(pcd, epnum);
37940 +#ifdef DWC_EN_ISOC
37941 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
37944 +#endif /* DWC_EN_ISOC */
37946 + core_if = GET_CORE_IF(pcd);
37947 + dev_if = core_if->dev_if;
37949 + dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dieptsiz);
37951 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x"
37952 + " stopped=%d\n", ep->dwc_ep.xfer_buff,
37953 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped);
37955 + * If xfersize is 0 and pktcnt in not 0, resend the last packet.
37957 + if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
37958 + ep->dwc_ep.start_xfer_buff != 0) {
37959 + if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) {
37960 + ep->dwc_ep.xfer_count = 0;
37961 + ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
37962 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
37964 + ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
37965 + /* convert packet size to dwords. */
37966 + ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
37967 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
37970 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x "
37971 + "xfer_len=%0x stopped=%d\n",
37972 + ep->dwc_ep.xfer_buff,
37973 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len,
37975 + if (epnum == 0) {
37976 + dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
37978 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
37984 + * handle the IN EP disable interrupt.
37986 +static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd,
37987 + const uint32_t epnum)
37989 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
37990 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
37991 + deptsiz_data_t dieptsiz = {.d32 = 0 };
37992 + dctl_data_t dctl = {.d32 = 0 };
37993 + dwc_otg_pcd_ep_t *ep;
37994 + dwc_ep_t *dwc_ep;
37996 + ep = get_in_ep(pcd, epnum);
37997 + dwc_ep = &ep->dwc_ep;
37999 + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
38000 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
38004 + DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum,
38005 + dwc_read_reg32(&dev_if->in_ep_regs[epnum]->diepctl));
38006 + dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dieptsiz);
38008 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
38009 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
38011 + if (ep->stopped) {
38012 + /* Flush the Tx FIFO */
38013 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
38014 + /* Clear the Global IN NP NAK */
38016 + dctl.b.cgnpinnak = 1;
38017 + dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, 0);
38018 + /* Restart the transaction */
38019 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
38020 + restart_transfer(pcd, epnum);
38023 + /* Restart the transaction */
38024 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
38025 + restart_transfer(pcd, epnum);
38027 + DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
38032 + * Handler for the IN EP timeout handshake interrupt.
38034 +static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd,
38035 + const uint32_t epnum)
38037 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
38038 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
38041 + deptsiz_data_t dieptsiz = {.d32 = 0 };
38042 + uint32_t num = 0;
38044 + dctl_data_t dctl = {.d32 = 0 };
38045 + dwc_otg_pcd_ep_t *ep;
38047 + gintmsk_data_t intr_mask = {.d32 = 0 };
38049 + ep = get_in_ep(pcd, epnum);
38051 + /* Disable the NP Tx Fifo Empty Interrrupt */
38052 + if (!core_if->dma_enable) {
38053 + intr_mask.b.nptxfempty = 1;
38054 + dwc_modify_reg32(&core_if->core_global_regs->gintmsk,
38055 + intr_mask.d32, 0);
38057 + /** @todo NGS Check EP type.
38058 + * Implement for Periodic EPs */
38060 + * Non-periodic EP
38062 + /* Enable the Global IN NAK Effective Interrupt */
38063 + intr_mask.b.ginnakeff = 1;
38064 + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
38066 + /* Set Global IN NAK */
38067 + dctl.b.sgnpinnak = 1;
38068 + dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
38073 + dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[num]->dieptsiz);
38074 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
38075 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
38078 +#ifdef DISABLE_PERIODIC_EP
38080 + * Set the NAK bit for this EP to
38081 + * start the disable process.
38084 + diepctl.b.snak = 1;
38085 + dwc_modify_reg32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32,
38087 + ep->disabling = 1;
38093 + * Handler for the IN EP NAK interrupt.
38095 +static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd,
38096 + const uint32_t epnum)
38098 + /** @todo implement ISR */
38099 + dwc_otg_core_if_t *core_if;
38100 + diepmsk_data_t intr_mask = {.d32 = 0 };
38102 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK");
38103 + core_if = GET_CORE_IF(pcd);
38104 + intr_mask.b.nak = 1;
38106 + if (core_if->multiproc_int_enable) {
38107 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
38108 + diepeachintmsk[epnum], intr_mask.d32, 0);
38110 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->diepmsk,
38111 + intr_mask.d32, 0);
38118 + * Handler for the OUT EP Babble interrupt.
38120 +static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd,
38121 + const uint32_t epnum)
38123 + /** @todo implement ISR */
38124 + dwc_otg_core_if_t *core_if;
38125 + doepmsk_data_t intr_mask = {.d32 = 0 };
38127 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
38128 + "OUT EP Babble");
38129 + core_if = GET_CORE_IF(pcd);
38130 + intr_mask.b.babble = 1;
38132 + if (core_if->multiproc_int_enable) {
38133 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
38134 + doepeachintmsk[epnum], intr_mask.d32, 0);
38136 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->doepmsk,
38137 + intr_mask.d32, 0);
38144 + * Handler for the OUT EP NAK interrupt.
38146 +static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd,
38147 + const uint32_t epnum)
38149 + /** @todo implement ISR */
38150 + dwc_otg_core_if_t *core_if;
38151 + doepmsk_data_t intr_mask = {.d32 = 0 };
38153 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NAK");
38154 + core_if = GET_CORE_IF(pcd);
38155 + intr_mask.b.nak = 1;
38157 + if (core_if->multiproc_int_enable) {
38158 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
38159 + doepeachintmsk[epnum], intr_mask.d32, 0);
38161 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->doepmsk,
38162 + intr_mask.d32, 0);
38169 + * Handler for the OUT EP NYET interrupt.
38171 +static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd,
38172 + const uint32_t epnum)
38174 + /** @todo implement ISR */
38175 + dwc_otg_core_if_t *core_if;
38176 + doepmsk_data_t intr_mask = {.d32 = 0 };
38178 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET");
38179 + core_if = GET_CORE_IF(pcd);
38180 + intr_mask.b.nyet = 1;
38182 + if (core_if->multiproc_int_enable) {
38183 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
38184 + doepeachintmsk[epnum], intr_mask.d32, 0);
38186 + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->doepmsk,
38187 + intr_mask.d32, 0);
38194 + * This interrupt indicates that an IN EP has a pending Interrupt.
38195 + * The sequence for handling the IN EP interrupt is shown below:
38196 + * -# Read the Device All Endpoint Interrupt register
38197 + * -# Repeat the following for each IN EP interrupt bit set (from
38199 + * -# Read the Device Endpoint Interrupt (DIEPINTn) register
38200 + * -# If "Transfer Complete" call the request complete function
38201 + * -# If "Endpoint Disabled" complete the EP disable procedure.
38202 + * -# If "AHB Error Interrupt" log error
38203 + * -# If "Time-out Handshake" log error
38204 + * -# If "IN Token Received when TxFIFO Empty" write packet to Tx
38206 + * -# If "IN Token EP Mismatch" (disable, this is handled by EP
38207 + * Mismatch Interrupt)
38209 +static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd)
38211 +#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
38213 + diepint_data_t diepint = {.d32=0}; \
38214 + diepint.b.__intr = 1; \
38215 + dwc_write_reg32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
38219 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
38220 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
38221 + diepint_data_t diepint = {.d32 = 0 };
38222 + dctl_data_t dctl = {.d32 = 0 };
38223 + depctl_data_t depctl = {.d32 = 0 };
38224 + uint32_t ep_intr;
38225 + uint32_t epnum = 0;
38226 + dwc_otg_pcd_ep_t *ep;
38227 + dwc_ep_t *dwc_ep;
38228 + gintmsk_data_t intr_mask = {.d32 = 0 };
38230 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd);
38232 + /* Read in the device interrupt bits */
38233 + ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if);
38235 + /* Service the Device IN interrupts for each endpoint */
38236 + while (ep_intr) {
38237 + if (ep_intr & 0x1) {
38238 + uint32_t empty_msk;
38239 + /* Get EP pointer */
38240 + ep = get_in_ep(pcd, epnum);
38241 + dwc_ep = &ep->dwc_ep;
38244 + dwc_read_reg32(&dev_if->in_ep_regs[epnum]->diepctl);
38246 + dwc_read_reg32(&dev_if->dev_global_regs->
38247 + dtknqr4_fifoemptymsk);
38249 + DWC_DEBUGPL(DBG_PCDV,
38250 + "IN EP INTERRUPT - %d\nepmty_msk - %8x diepctl - %8x\n",
38251 + epnum, empty_msk, depctl.d32);
38253 + DWC_DEBUGPL(DBG_PCD,
38254 + "EP%d-%s: type=%d, mps=%d\n",
38255 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
38256 + dwc_ep->type, dwc_ep->maxpacket);
38259 + dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep);
38261 + DWC_DEBUGPL(DBG_PCDV,
38262 + "EP %d Interrupt Register - 0x%x\n", epnum,
38264 + /* Transfer complete */
38265 + if (diepint.b.xfercompl) {
38266 + /* Disable the NP Tx FIFO Empty
38268 + if (core_if->en_multiple_tx_fifo == 0) {
38269 + intr_mask.b.nptxfempty = 1;
38270 + dwc_modify_reg32(&core_if->
38271 + core_global_regs->
38272 + gintmsk, intr_mask.d32,
38275 + /* Disable the Tx FIFO Empty Interrupt for this EP */
38276 + uint32_t fifoemptymsk =
38277 + 0x1 << dwc_ep->num;
38278 + dwc_modify_reg32(&core_if->dev_if->
38279 + dev_global_regs->
38280 + dtknqr4_fifoemptymsk,
38281 + fifoemptymsk, 0);
38283 + /* Clear the bit in DIEPINTn for this interrupt */
38284 + CLEAR_IN_EP_INTR(core_if, epnum, xfercompl);
38286 + /* Complete the transfer */
38287 + if (epnum == 0) {
38290 +#ifdef DWC_EN_ISOC
38291 + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
38292 + if (!ep->stopped)
38293 + complete_iso_ep(pcd, ep);
38295 +#endif /* DWC_EN_ISOC */
38301 + /* Endpoint disable */
38302 + if (diepint.b.epdisabled) {
38303 + DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n",
38305 + handle_in_ep_disable_intr(pcd, epnum);
38307 + /* Clear the bit in DIEPINTn for this interrupt */
38308 + CLEAR_IN_EP_INTR(core_if, epnum, epdisabled);
38311 + if (diepint.b.ahberr) {
38312 + DWC_DEBUGPL(DBG_ANY, "EP%d IN AHB Error\n",
38314 + /* Clear the bit in DIEPINTn for this interrupt */
38315 + CLEAR_IN_EP_INTR(core_if, epnum, ahberr);
38317 + /* TimeOUT Handshake (non-ISOC IN EPs) */
38318 + if (diepint.b.timeout) {
38319 + DWC_DEBUGPL(DBG_ANY, "EP%d IN Time-out\n",
38321 + handle_in_ep_timeout_intr(pcd, epnum);
38323 + CLEAR_IN_EP_INTR(core_if, epnum, timeout);
38325 + /** IN Token received with TxF Empty */
38326 + if (diepint.b.intktxfemp) {
38327 + DWC_DEBUGPL(DBG_ANY,
38328 + "EP%d IN TKN TxFifo Empty\n",
38330 + if (!ep->stopped && epnum != 0) {
38332 + diepmsk_data_t diepmsk = {.d32 = 0 };
38333 + diepmsk.b.intktxfemp = 1;
38335 + if (core_if->multiproc_int_enable) {
38336 + dwc_modify_reg32(&dev_if->
38337 + dev_global_regs->
38343 + dwc_modify_reg32(&dev_if->
38344 + dev_global_regs->
38349 + } else if (core_if->dma_desc_enable
38351 + && pcd->ep0state ==
38352 + EP0_OUT_STATUS_PHASE) {
38353 + // EP0 IN set STALL
38355 + dwc_read_reg32(&dev_if->
38356 + in_ep_regs[epnum]->
38359 + /* set the disable and stall bits */
38360 + if (depctl.b.epena) {
38361 + depctl.b.epdis = 1;
38363 + depctl.b.stall = 1;
38364 + dwc_write_reg32(&dev_if->
38365 + in_ep_regs[epnum]->
38366 + diepctl, depctl.d32);
38368 + CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp);
38370 + /** IN Token Received with EP mismatch */
38371 + if (diepint.b.intknepmis) {
38372 + DWC_DEBUGPL(DBG_ANY,
38373 + "EP%d IN TKN EP Mismatch\n", epnum);
38374 + CLEAR_IN_EP_INTR(core_if, epnum, intknepmis);
38376 + /** IN Endpoint NAK Effective */
38377 + if (diepint.b.inepnakeff) {
38378 + DWC_DEBUGPL(DBG_ANY,
38379 + "EP%d IN EP NAK Effective\n",
38381 + /* Periodic EP */
38382 + if (ep->disabling) {
38384 + depctl.b.snak = 1;
38385 + depctl.b.epdis = 1;
38386 + dwc_modify_reg32(&dev_if->
38387 + in_ep_regs[epnum]->
38388 + diepctl, depctl.d32,
38391 + CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff);
38395 + /** IN EP Tx FIFO Empty Intr */
38396 + if (diepint.b.emptyintr) {
38397 + DWC_DEBUGPL(DBG_ANY,
38398 + "EP%d Tx FIFO Empty Intr \n",
38400 + write_empty_tx_fifo(pcd, epnum);
38402 + CLEAR_IN_EP_INTR(core_if, epnum, emptyintr);
38406 + /** IN EP BNA Intr */
38407 + if (diepint.b.bna) {
38408 + CLEAR_IN_EP_INTR(core_if, epnum, bna);
38409 + if (core_if->dma_desc_enable) {
38410 +#ifdef DWC_EN_ISOC
38411 + if (dwc_ep->type ==
38412 + DWC_OTG_EP_TYPE_ISOC) {
38414 + * This checking is performed to prevent first "false" BNA
38415 + * handling occuring right after reconnect
38417 + if (dwc_ep->next_frame !=
38419 + dwc_otg_pcd_handle_iso_bna
38422 +#endif /* DWC_EN_ISOC */
38425 + dwc_read_reg32(&dev_if->
38426 + dev_global_regs->
38429 + /* If Global Continue on BNA is disabled - disable EP */
38430 + if (!dctl.b.gcontbna) {
38432 + depctl.b.snak = 1;
38433 + depctl.b.epdis = 1;
38436 + in_ep_regs[epnum]->
38441 + start_next_request(ep);
38446 + /* NAK Interrutp */
38447 + if (diepint.b.nak) {
38448 + DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n",
38450 + handle_in_ep_nak_intr(pcd, epnum);
38452 + CLEAR_IN_EP_INTR(core_if, epnum, nak);
38460 +#undef CLEAR_IN_EP_INTR
38464 + * This interrupt indicates that an OUT EP has a pending Interrupt.
38465 + * The sequence for handling the OUT EP interrupt is shown below:
38466 + * -# Read the Device All Endpoint Interrupt register
38467 + * -# Repeat the following for each OUT EP interrupt bit set (from
38469 + * -# Read the Device Endpoint Interrupt (DOEPINTn) register
38470 + * -# If "Transfer Complete" call the request complete function
38471 + * -# If "Endpoint Disabled" complete the EP disable procedure.
38472 + * -# If "AHB Error Interrupt" log error
38473 + * -# If "Setup Phase Done" process Setup Packet (See Standard USB
38474 + * Command Processing)
38476 +static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd)
38478 +#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
38480 + doepint_data_t doepint = {.d32=0}; \
38481 + doepint.b.__intr = 1; \
38482 + dwc_write_reg32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
38486 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
38487 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
38488 + uint32_t ep_intr;
38489 + doepint_data_t doepint = {.d32 = 0 };
38490 + dctl_data_t dctl = {.d32 = 0 };
38491 + depctl_data_t doepctl = {.d32 = 0 };
38492 + uint32_t epnum = 0;
38493 + dwc_otg_pcd_ep_t *ep;
38494 + dwc_ep_t *dwc_ep;
38496 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
38498 + /* Read in the device interrupt bits */
38499 + ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if);
38501 + while (ep_intr) {
38502 + if (ep_intr & 0x1) {
38503 + /* Get EP pointer */
38504 + ep = get_out_ep(pcd, epnum);
38505 + dwc_ep = &ep->dwc_ep;
38508 + DWC_DEBUGPL(DBG_PCDV,
38509 + "EP%d-%s: type=%d, mps=%d\n",
38510 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
38511 + dwc_ep->type, dwc_ep->maxpacket);
38514 + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
38516 + /* Transfer complete */
38517 + if (doepint.b.xfercompl) {
38519 + if (epnum == 0) {
38520 + /* Clear the bit in DOEPINTn for this interrupt */
38521 + CLEAR_OUT_EP_INTR(core_if, epnum,
38523 + if (core_if->dma_desc_enable == 0
38524 + || pcd->ep0state != EP0_IDLE)
38526 +#ifdef DWC_EN_ISOC
38527 + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
38528 + if (doepint.b.pktdrpsts == 0) {
38529 + /* Clear the bit in DOEPINTn for this interrupt */
38530 + CLEAR_OUT_EP_INTR(core_if,
38533 + complete_iso_ep(pcd, ep);
38536 + doepint_data_t doepint = {.d32 =
38538 + doepint.b.xfercompl = 1;
38539 + doepint.b.pktdrpsts = 1;
38540 + dwc_write_reg32(&core_if->
38546 + if (handle_iso_out_pkt_dropped
38547 + (core_if, dwc_ep)) {
38548 + complete_iso_ep(pcd,
38552 +#endif /* DWC_EN_ISOC */
38554 + /* Clear the bit in DOEPINTn for this interrupt */
38555 + CLEAR_OUT_EP_INTR(core_if, epnum,
38562 + /* Endpoint disable */
38563 + if (doepint.b.epdisabled) {
38565 + /* Clear the bit in DOEPINTn for this interrupt */
38566 + CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled);
38569 + if (doepint.b.ahberr) {
38570 + DWC_DEBUGPL(DBG_PCD, "EP%d OUT AHB Error\n",
38572 + DWC_DEBUGPL(DBG_PCD, "EP DMA REG %d \n",
38573 + core_if->dev_if->
38574 + out_ep_regs[epnum]->doepdma);
38575 + CLEAR_OUT_EP_INTR(core_if, epnum, ahberr);
38577 + /* Setup Phase Done (contorl EPs) */
38578 + if (doepint.b.setup) {
38580 + DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n",
38583 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
38588 + /** OUT EP BNA Intr */
38589 + if (doepint.b.bna) {
38590 + CLEAR_OUT_EP_INTR(core_if, epnum, bna);
38591 + if (core_if->dma_desc_enable) {
38592 +#ifdef DWC_EN_ISOC
38593 + if (dwc_ep->type ==
38594 + DWC_OTG_EP_TYPE_ISOC) {
38596 + * This checking is performed to prevent first "false" BNA
38597 + * handling occuring right after reconnect
38599 + if (dwc_ep->next_frame !=
38601 + dwc_otg_pcd_handle_iso_bna
38604 +#endif /* DWC_EN_ISOC */
38607 + dwc_read_reg32(&dev_if->
38608 + dev_global_regs->
38611 + /* If Global Continue on BNA is disabled - disable EP */
38612 + if (!dctl.b.gcontbna) {
38614 + doepctl.b.snak = 1;
38615 + doepctl.b.epdis = 1;
38619 + [epnum]->doepctl,
38623 + start_next_request(ep);
38628 + if (doepint.b.stsphsercvd) {
38629 + CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd);
38630 + if (core_if->dma_desc_enable) {
38631 + do_setup_in_status_phase(pcd);
38634 + /* Babble Interrutp */
38635 + if (doepint.b.babble) {
38636 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n",
38638 + handle_out_ep_babble_intr(pcd, epnum);
38640 + CLEAR_OUT_EP_INTR(core_if, epnum, babble);
38642 + /* NAK Interrutp */
38643 + if (doepint.b.nak) {
38644 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum);
38645 + handle_out_ep_nak_intr(pcd, epnum);
38647 + CLEAR_OUT_EP_INTR(core_if, epnum, nak);
38649 + /* NYET Interrutp */
38650 + if (doepint.b.nyet) {
38651 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum);
38652 + handle_out_ep_nyet_intr(pcd, epnum);
38654 + CLEAR_OUT_EP_INTR(core_if, epnum, nyet);
38664 +#undef CLEAR_OUT_EP_INTR
38668 + * Incomplete ISO IN Transfer Interrupt.
38669 + * This interrupt indicates one of the following conditions occurred
38670 + * while transmitting an ISOC transaction.
38671 + * - Corrupted IN Token for ISOC EP.
38672 + * - Packet not complete in FIFO.
38673 + * The follow actions will be taken:
38674 + * -# Determine the EP
38675 + * -# Set incomplete flag in dwc_ep structure
38676 + * -# Disable EP; when "Endpoint Disabled" interrupt is received
38679 +int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd)
38681 + gintsts_data_t gintsts;
38683 +#ifdef DWC_EN_ISOC
38684 + dwc_otg_dev_if_t *dev_if;
38685 + deptsiz_data_t deptsiz = {.d32 = 0 };
38686 + depctl_data_t depctl = {.d32 = 0 };
38687 + dsts_data_t dsts = {.d32 = 0 };
38688 + dwc_ep_t *dwc_ep;
38691 + dev_if = GET_CORE_IF(pcd)->dev_if;
38693 + for (i = 1; i <= dev_if->num_in_eps; ++i) {
38694 + dwc_ep = &pcd->in_ep[i].dwc_ep;
38695 + if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
38697 + dwc_read_reg32(&dev_if->in_ep_regs[i]->dieptsiz);
38699 + dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl);
38701 + if (depctl.b.epdis && deptsiz.d32) {
38702 + set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep);
38703 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
38704 + dwc_ep->cur_pkt = 0;
38705 + dwc_ep->proc_buf_num =
38706 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
38708 + if (dwc_ep->proc_buf_num) {
38709 + dwc_ep->cur_pkt_addr =
38710 + dwc_ep->xfer_buff1;
38711 + dwc_ep->cur_pkt_dma_addr =
38712 + dwc_ep->dma_addr1;
38714 + dwc_ep->cur_pkt_addr =
38715 + dwc_ep->xfer_buff0;
38716 + dwc_ep->cur_pkt_dma_addr =
38717 + dwc_ep->dma_addr0;
38723 + dwc_read_reg32(&GET_CORE_IF(pcd)->dev_if->
38724 + dev_global_regs->dsts);
38725 + dwc_ep->next_frame = dsts.b.soffn;
38727 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
38735 + gintmsk_data_t intr_mask = {.d32 = 0 };
38736 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
38737 + "IN ISOC Incomplete");
38739 + intr_mask.b.incomplisoin = 1;
38740 + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
38741 + intr_mask.d32, 0);
38742 +#endif //DWC_EN_ISOC
38744 + /* Clear interrupt */
38746 + gintsts.b.incomplisoin = 1;
38747 + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
38754 + * Incomplete ISO OUT Transfer Interrupt.
38756 + * This interrupt indicates that the core has dropped an ISO OUT
38757 + * packet. The following conditions can be the cause:
38758 + * - FIFO Full, the entire packet would not fit in the FIFO.
38760 + * - Corrupted Token
38761 + * The follow actions will be taken:
38762 + * -# Determine the EP
38763 + * -# Set incomplete flag in dwc_ep structure
38764 + * -# Read any data from the FIFO
38765 + * -# Disable EP. when "Endpoint Disabled" interrupt is received
38768 +int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd)
38771 + gintsts_data_t gintsts;
38773 +#ifdef DWC_EN_ISOC
38774 + dwc_otg_dev_if_t *dev_if;
38775 + deptsiz_data_t deptsiz = {.d32 = 0 };
38776 + depctl_data_t depctl = {.d32 = 0 };
38777 + dsts_data_t dsts = {.d32 = 0 };
38778 + dwc_ep_t *dwc_ep;
38781 + dev_if = GET_CORE_IF(pcd)->dev_if;
38783 + for (i = 1; i <= dev_if->num_out_eps; ++i) {
38784 + dwc_ep = &pcd->in_ep[i].dwc_ep;
38785 + if (pcd->out_ep[i].dwc_ep.active &&
38786 + pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
38788 + dwc_read_reg32(&dev_if->out_ep_regs[i]->doeptsiz);
38790 + dwc_read_reg32(&dev_if->out_ep_regs[i]->doepctl);
38792 + if (depctl.b.epdis && deptsiz.d32) {
38793 + set_current_pkt_info(GET_CORE_IF(pcd),
38794 + &pcd->out_ep[i].dwc_ep);
38795 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
38796 + dwc_ep->cur_pkt = 0;
38797 + dwc_ep->proc_buf_num =
38798 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
38800 + if (dwc_ep->proc_buf_num) {
38801 + dwc_ep->cur_pkt_addr =
38802 + dwc_ep->xfer_buff1;
38803 + dwc_ep->cur_pkt_dma_addr =
38804 + dwc_ep->dma_addr1;
38806 + dwc_ep->cur_pkt_addr =
38807 + dwc_ep->xfer_buff0;
38808 + dwc_ep->cur_pkt_dma_addr =
38809 + dwc_ep->dma_addr0;
38815 + dwc_read_reg32(&GET_CORE_IF(pcd)->dev_if->
38816 + dev_global_regs->dsts);
38817 + dwc_ep->next_frame = dsts.b.soffn;
38819 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
38826 + /** @todo implement ISR */
38827 + gintmsk_data_t intr_mask = {.d32 = 0 };
38829 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
38830 + "OUT ISOC Incomplete");
38832 + intr_mask.b.incomplisoout = 1;
38833 + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
38834 + intr_mask.d32, 0);
38836 +#endif /* DWC_EN_ISOC */
38838 + /* Clear interrupt */
38840 + gintsts.b.incomplisoout = 1;
38841 + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
38848 + * This function handles the Global IN NAK Effective interrupt.
38851 +int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd)
38853 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
38854 + depctl_data_t diepctl = {.d32 = 0 };
38855 + depctl_data_t diepctl_rd = {.d32 = 0 };
38856 + gintmsk_data_t intr_mask = {.d32 = 0 };
38857 + gintsts_data_t gintsts;
38860 + DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
38862 + /* Disable all active IN EPs */
38863 + diepctl.b.epdis = 1;
38864 + diepctl.b.snak = 1;
38866 + for (i = 0; i <= dev_if->num_in_eps; i++) {
38868 + dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl);
38869 + if (diepctl_rd.b.epena) {
38870 + dwc_write_reg32(&dev_if->in_ep_regs[i]->diepctl,
38874 + /* Disable the Global IN NAK Effective Interrupt */
38875 + intr_mask.b.ginnakeff = 1;
38876 + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
38877 + intr_mask.d32, 0);
38879 + /* Clear interrupt */
38881 + gintsts.b.ginnakeff = 1;
38882 + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
38889 + * OUT NAK Effective.
38892 +int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd)
38894 + gintmsk_data_t intr_mask = {.d32 = 0 };
38895 + gintsts_data_t gintsts;
38897 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
38898 + "Global IN NAK Effective\n");
38899 + /* Disable the Global IN NAK Effective Interrupt */
38900 + intr_mask.b.goutnakeff = 1;
38901 + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
38902 + intr_mask.d32, 0);
38904 + /* Clear interrupt */
38906 + gintsts.b.goutnakeff = 1;
38907 + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
38914 + * PCD interrupt handler.
38916 + * The PCD handles the device interrupts. Many conditions can cause a
38917 + * device interrupt. When an interrupt occurs, the device interrupt
38918 + * service routine determines the cause of the interrupt and
38919 + * dispatches handling to the appropriate function. These interrupt
38920 + * handling functions are described below.
38922 + * All interrupt registers are processed from LSB to MSB.
38925 +int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd)
38927 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
38929 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
38931 + gintsts_data_t gintr_status;
38932 + int32_t retval = 0;
38935 + DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x gintmsk=%08x\n",
38937 + dwc_read_reg32(&global_regs->gintsts),
38938 + dwc_read_reg32(&global_regs->gintmsk));
38941 + if (dwc_otg_is_device_mode(core_if)) {
38942 + DWC_SPINLOCK(pcd->lock);
38944 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x gintmsk=%08x\n",
38946 + dwc_read_reg32(&global_regs->gintsts),
38947 + dwc_read_reg32(&global_regs->gintmsk));
38950 + gintr_status.d32 = dwc_otg_read_core_intr(core_if);
38952 + DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
38953 + __func__, gintr_status.d32);
38955 + if (gintr_status.b.sofintr) {
38956 + retval |= dwc_otg_pcd_handle_sof_intr(pcd);
38958 + if (gintr_status.b.rxstsqlvl) {
38960 + dwc_otg_pcd_handle_rx_status_q_level_intr(pcd);
38962 + if (gintr_status.b.nptxfempty) {
38963 + retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd);
38965 + if (gintr_status.b.ginnakeff) {
38966 + retval |= dwc_otg_pcd_handle_in_nak_effective(pcd);
38968 + if (gintr_status.b.goutnakeff) {
38969 + retval |= dwc_otg_pcd_handle_out_nak_effective(pcd);
38971 + if (gintr_status.b.i2cintr) {
38972 + retval |= dwc_otg_pcd_handle_i2c_intr(pcd);
38974 + if (gintr_status.b.erlysuspend) {
38975 + retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd);
38977 + if (gintr_status.b.usbreset) {
38978 + retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd);
38980 + if (gintr_status.b.enumdone) {
38981 + retval |= dwc_otg_pcd_handle_enum_done_intr(pcd);
38983 + if (gintr_status.b.isooutdrop) {
38985 + dwc_otg_pcd_handle_isoc_out_packet_dropped_intr
38988 + if (gintr_status.b.eopframe) {
38990 + dwc_otg_pcd_handle_end_periodic_frame_intr(pcd);
38992 + if (gintr_status.b.epmismatch) {
38993 + retval |= dwc_otg_pcd_handle_ep_mismatch_intr(core_if);
38995 + if (gintr_status.b.inepint) {
38996 + if (!core_if->multiproc_int_enable) {
38997 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
39000 + if (gintr_status.b.outepintr) {
39001 + if (!core_if->multiproc_int_enable) {
39002 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
39005 + if (gintr_status.b.incomplisoin) {
39007 + dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd);
39009 + if (gintr_status.b.incomplisoout) {
39011 + dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd);
39014 + /* In MPI mode De vice Endpoints intterrupts are asserted
39015 + * without setting outepintr and inepint bits set, so these
39016 + * Interrupt handlers are called without checking these bit-fields
39018 + if (core_if->multiproc_int_enable) {
39019 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
39020 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
39023 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
39024 + dwc_read_reg32(&global_regs->gintsts));
39026 + DWC_SPINUNLOCK(pcd->lock);
39031 +#endif /* DWC_HOST_ONLY */
39033 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
39035 + /* ==========================================================================
39036 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
39037 + * $Revision: #7 $
39038 + * $Date: 2009/04/03 $
39039 + * $Change: 1225160 $
39041 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
39042 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
39043 + * otherwise expressly agreed to in writing between Synopsys and you.
39045 + * The Software IS NOT an item of Licensed Software or Licensed Product under
39046 + * any End User Software License Agreement or Agreement for Licensed Product
39047 + * with Synopsys or any supplement thereto. You are permitted to use and
39048 + * redistribute this Software in source and binary forms, with or without
39049 + * modification, provided that redistributions of source code must retain this
39050 + * notice. You may not view, use, disclose, copy or distribute this file or
39051 + * any information contained herein except pursuant to this license grant from
39052 + * Synopsys. If you do not agree with this notice, including the disclaimer
39053 + * below, then you are not authorized to use the Software.
39055 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
39056 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39057 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39058 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
39059 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39060 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39061 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39062 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39063 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39064 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39066 + * ========================================================================== */
39067 +#ifndef DWC_HOST_ONLY
39070 + * This file implements the Peripheral Controller Driver.
39072 + * The Peripheral Controller Driver (PCD) is responsible for
39073 + * translating requests from the Function Driver into the appropriate
39074 + * actions on the DWC_otg controller. It isolates the Function Driver
39075 + * from the specifics of the controller by providing an API to the
39076 + * Function Driver.
39078 + * The Peripheral Controller Driver for Linux will implement the
39079 + * Gadget API, so that the existing Gadget drivers can be used.
39080 + * (Gadget Driver is the Linux terminology for a Function Driver.)
39082 + * The Linux Gadget API is defined in the header file
39083 + * <code><linux/usb_gadget.h></code>. The USB EP operations API is
39084 + * defined in the structure <code>usb_ep_ops</code> and the USB
39085 + * Controller API is defined in the structure
39086 + * <code>usb_gadget_ops</code>.
39090 +#include <linux/kernel.h>
39091 +#include <linux/module.h>
39092 +#include <linux/moduleparam.h>
39093 +#include <linux/init.h>
39094 +#include <linux/device.h>
39095 +#include <linux/errno.h>
39096 +#include <linux/list.h>
39097 +#include <linux/interrupt.h>
39098 +#include <linux/string.h>
39099 +#include <linux/dma-mapping.h>
39100 +#include <linux/version.h>
39102 +#if defined(LM_INTERFACE)
39103 +//# include <asm/arch/regs-irq.h>
39104 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
39105 +#include <asm/arch/lm.h>
39107 +/* by 2.6.31, at least, the location of some headers has changed
39109 +#include <mach/lm.h>
39112 +#elif defined(PLATFORM_INTERFACE)
39113 +#include <linux/platform_device.h>
39116 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
39117 +#include <asm/arch/irqs.h>
39118 +#include <linux/usb_ch9.h>
39119 +#include <linux/usb_gadget.h>
39121 +/* by 2.6.31, at least, the location of some headers has changed
39123 +#include <mach/irqs.h>
39124 +#include <linux/usb/ch9.h>
39125 +#include <linux/usb/gadget.h>
39128 +#include <asm/io.h>
39130 +#include "dwc_otg_pcd_if.h"
39131 +#include "dwc_otg_driver.h"
39132 +#include "dwc_otg_dbg.h"
39134 +static struct gadget_wrapper {
39135 + dwc_otg_pcd_t *pcd;
39137 + struct usb_gadget gadget;
39138 + struct usb_gadget_driver *driver;
39140 + struct usb_ep ep0;
39141 + struct usb_ep in_ep[16];
39142 + struct usb_ep out_ep[16];
39144 +} *gadget_wrapper;
39146 +/* Display the contents of the buffer */
39147 +extern void dump_msg(const u8 * buf, unsigned int length);
39149 +/* USB Endpoint Operations */
39151 + * The following sections briefly describe the behavior of the Gadget
39152 + * API endpoint operations implemented in the DWC_otg driver
39153 + * software. Detailed descriptions of the generic behavior of each of
39154 + * these functions can be found in the Linux header file
39155 + * include/linux/usb_gadget.h.
39157 + * The Gadget API provides wrapper functions for each of the function
39158 + * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
39159 + * function, which then calls the underlying PCD function. The
39160 + * following sections are named according to the wrapper
39161 + * functions. Within each section, the corresponding DWC_otg PCD
39162 + * function name is specified.
39167 + * This function is called by the Gadget Driver for each EP to be
39168 + * configured for the current configuration (SET_CONFIGURATION).
39170 + * This function initializes the dwc_otg_ep_t data structure, and then
39171 + * calls dwc_otg_ep_activate.
39173 +static int ep_enable(struct usb_ep *usb_ep,
39174 + const struct usb_endpoint_descriptor *ep_desc)
39178 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
39180 + if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
39181 + DWC_WARN("%s, bad ep or descriptor\n", __func__);
39184 + if (usb_ep == &gadget_wrapper->ep0) {
39185 + DWC_WARN("%s, bad ep(0)\n", __func__);
39189 + /* Check FIFO size? */
39190 + if (!ep_desc->wMaxPacketSize) {
39191 + DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
39195 + if (!gadget_wrapper->driver ||
39196 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
39197 + DWC_WARN("%s, bogus device state\n", __func__);
39198 + return -ESHUTDOWN;
39201 + retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
39202 + (const uint8_t *)ep_desc,
39205 + DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
39209 + usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
39215 + * This function is called when an EP is disabled due to disconnect or
39216 + * change in configuration. Any pending requests will terminate with a
39217 + * status of -ESHUTDOWN.
39219 + * This function modifies the dwc_otg_ep_t data structure for this EP,
39220 + * and then calls dwc_otg_ep_deactivate.
39222 +static int ep_disable(struct usb_ep *usb_ep)
39226 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
39228 + DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
39229 + usb_ep ? usb_ep->name : NULL);
39233 + retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
39235 + retval = -EINVAL;
39242 + * This function allocates a request object to use with the specified
39245 + * @param ep The endpoint to be used with with the request
39246 + * @param gfp_flags the GFP_* flags to use.
39248 +static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
39251 + struct usb_request *usb_req;
39253 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
39255 + DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
39258 + usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
39259 + if (0 == usb_req) {
39260 + DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
39263 + memset(usb_req, 0, sizeof(*usb_req));
39264 + usb_req->dma = DWC_INVALID_DMA_ADDR;
39270 + * This function frees a request object.
39272 + * @param ep The endpoint associated with the request
39273 + * @param req The request being freed
39275 +static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
39277 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
39279 + if (0 == ep || 0 == req) {
39280 + DWC_WARN("%s() %s\n", __func__,
39281 + "Invalid ep or req argument!\n");
39288 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
39290 + * This function allocates an I/O buffer to be used for a transfer
39291 + * to/from the specified endpoint.
39293 + * @param usb_ep The endpoint to be used with with the request
39294 + * @param bytes The desired number of bytes for the buffer
39295 + * @param dma Pointer to the buffer's DMA address; must be valid
39296 + * @param gfp_flags the GFP_* flags to use.
39297 + * @return address of a new buffer or null is buffer could not be allocated.
39299 +static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
39300 + dma_addr_t * dma, gfp_t gfp_flags)
39303 + dwc_otg_pcd_t *pcd = 0;
39305 + pcd = gadget_wrapper->pcd;
39307 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
39310 + /* Check dword alignment */
39311 + if ((bytes & 0x3UL) != 0) {
39312 + DWC_WARN("%s() Buffer size is not a multiple of"
39313 + "DWORD size (%d)", __func__, bytes);
39316 + buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
39318 + /* Check dword alignment */
39319 + if (((int)buf & 0x3UL) != 0) {
39320 + DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
39328 + * This function frees an I/O buffer that was allocated by alloc_buffer.
39330 + * @param usb_ep the endpoint associated with the buffer
39331 + * @param buf address of the buffer
39332 + * @param dma The buffer's DMA address
39333 + * @param bytes The number of bytes of the buffer
39335 +static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
39336 + dma_addr_t dma, unsigned bytes)
39338 + dwc_otg_pcd_t *pcd = 0;
39340 + pcd = gadget_wrapper->pcd;
39342 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
39344 + dma_free_coherent(NULL, bytes, buf, dma);
39349 + * This function is used to submit an I/O Request to an EP.
39351 + * - When the request completes the request's completion callback
39352 + * is called to return the request to the driver.
39353 + * - An EP, except control EPs, may have multiple requests
39355 + * - Once submitted the request cannot be examined or modified.
39356 + * - Each request is turned into one or more packets.
39357 + * - A BULK EP can queue any amount of data; the transfer is
39359 + * - Zero length Packets are specified with the request 'zero'
39362 +static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
39365 + dwc_otg_pcd_t *pcd;
39368 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
39369 + __func__, usb_ep, usb_req, gfp_flags);
39371 + if (!usb_req || !usb_req->complete || !usb_req->buf) {
39372 + DWC_WARN("bad params\n");
39377 + DWC_WARN("bad ep\n");
39381 + pcd = gadget_wrapper->pcd;
39382 + if (!gadget_wrapper->driver ||
39383 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
39384 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
39385 + gadget_wrapper->gadget.speed);
39386 + DWC_WARN("bogus device state\n");
39387 + return -ESHUTDOWN;
39390 + DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
39391 + usb_ep->name, usb_req, usb_req->length, usb_req->buf);
39393 + usb_req->status = -EINPROGRESS;
39394 + usb_req->actual = 0;
39396 + retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, usb_req->dma,
39397 + usb_req->length, usb_req->zero, usb_req,
39398 + gfp_flags == GFP_ATOMIC ? 1 : 0);
39407 + * This function cancels an I/O request from an EP.
39409 +static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
39411 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
39413 + if (!usb_ep || !usb_req) {
39414 + DWC_WARN("bad argument\n");
39417 + if (!gadget_wrapper->driver ||
39418 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
39419 + DWC_WARN("bogus device state\n");
39420 + return -ESHUTDOWN;
39422 + if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
39430 + * usb_ep_set_halt stalls an endpoint.
39432 + * usb_ep_clear_halt clears an endpoint halt and resets its data
39435 + * Both of these functions are implemented with the same underlying
39436 + * function. The behavior depends on the value argument.
39438 + * @param[in] usb_ep the Endpoint to halt or clear halt.
39439 + * @param[in] value
39440 + * - 0 means clear_halt.
39441 + * - 1 means set_halt,
39442 + * - 2 means clear stall lock flag.
39443 + * - 3 means set stall lock flag.
39445 +static int ep_halt(struct usb_ep *usb_ep, int value)
39449 + DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
39452 + DWC_WARN("bad ep\n");
39456 + retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
39457 + if (retval == -DWC_E_AGAIN) {
39459 + } else if (retval) {
39460 + retval = -EINVAL;
39466 +//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
39469 + * ep_wedge: sets the halt feature and ignores clear requests
39471 + * @usb_ep: the endpoint being wedged
39473 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
39474 + * requests. If the gadget driver clears the halt status, it will
39475 + * automatically unwedge the endpoint.
39477 + * Returns zero on success, else negative errno. *
39478 + * Check usb_ep_set_wedge() at "usb_gadget.h" for details
39480 +static int ep_wedge(struct usb_ep *usb_ep)
39484 + DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name);
39487 + DWC_WARN("bad ep\n");
39491 + retval = dwc_otg_pcd_ep_wedge(gadget_wrapper->pcd, usb_ep);
39492 + if (retval == -DWC_E_AGAIN) {
39493 + retval = -EAGAIN;
39494 + } else if (retval) {
39495 + retval = -EINVAL;
39502 +#ifdef DWC_EN_ISOC
39504 + * This function is used to submit an ISOC Transfer Request to an EP.
39506 + * - Every time a sync period completes the request's completion callback
39507 + * is called to provide data to the gadget driver.
39508 + * - Once submitted the request cannot be modified.
39509 + * - Each request is turned into periodic data packets untill ISO
39510 + * Transfer is stopped..
39512 +static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
39517 + if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
39518 + DWC_WARN("bad params\n");
39523 + DWC_PRINTF("bad params\n");
39527 + req->status = -EINPROGRESS;
39530 + dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
39531 + req->buf1, req->dma0, req->dma1,
39532 + req->sync_frame, req->data_pattern_frame,
39533 + req->data_per_frame,
39534 + req->flags & USB_REQ_ISO_ASAP ? -1 : req->
39535 + start_frame, req->buf_proc_intrvl, req,
39536 + gfp_flags == GFP_ATOMIC ? 1 : 0);
39546 + * This function stops ISO EP Periodic Data Transfer.
39548 +static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
39552 + DWC_WARN("bad ep\n");
39555 + if (!gadget_wrapper->driver ||
39556 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
39557 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
39558 + gadget_wrapper->gadget.speed);
39559 + DWC_WARN("bogus device state\n");
39562 + dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
39564 + retval = -EINVAL;
39570 +static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
39571 + int packets, gfp_t gfp_flags)
39573 + struct usb_iso_request *pReq = NULL;
39574 + uint32_t req_size;
39576 + req_size = sizeof(struct usb_iso_request);
39578 + (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
39580 + pReq = kmalloc(req_size, gfp_flags);
39582 + DWC_WARN("Can't allocate Iso Request\n");
39585 + pReq->iso_packet_desc0 = (void *)(pReq + 1);
39587 + pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
39592 +static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
39597 +static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
39599 + .enable = ep_enable,
39600 + .disable = ep_disable,
39602 + .alloc_request = dwc_otg_pcd_alloc_request,
39603 + .free_request = dwc_otg_pcd_free_request,
39605 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
39606 + .free_buffer = dwc_otg_pcd_free_buffer,
39608 + .queue = ep_queue,
39609 + .dequeue = ep_dequeue,
39611 + .set_halt = ep_halt,
39612 + .fifo_status = 0,
39615 + .iso_ep_start = iso_ep_start,
39616 + .iso_ep_stop = iso_ep_stop,
39617 + .alloc_iso_request = alloc_iso_request,
39618 + .free_iso_request = free_iso_request,
39623 + int (*enable) (struct usb_ep *ep,
39624 + const struct usb_endpoint_descriptor *desc);
39625 + int (*disable) (struct usb_ep *ep);
39627 + struct usb_request *(*alloc_request) (struct usb_ep *ep,
39628 + gfp_t gfp_flags);
39629 + void (*free_request) (struct usb_ep *ep, struct usb_request *req);
39631 + int (*queue) (struct usb_ep *ep, struct usb_request *req,
39632 + gfp_t gfp_flags);
39633 + int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
39635 + int (*set_halt) (struct usb_ep *ep, int value);
39636 + int (*set_wedge) (struct usb_ep *ep);
39638 + int (*fifo_status) (struct usb_ep *ep);
39639 + void (*fifo_flush) (struct usb_ep *ep);
39640 +static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
39641 + .enable = ep_enable,
39642 + .disable = ep_disable,
39644 + .alloc_request = dwc_otg_pcd_alloc_request,
39645 + .free_request = dwc_otg_pcd_free_request,
39647 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
39648 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
39649 + .free_buffer = dwc_otg_pcd_free_buffer,
39651 + /* .set_wedge = ep_wedge, */
39652 + .set_wedge = NULL, /* uses set_halt instead */
39655 + .queue = ep_queue,
39656 + .dequeue = ep_dequeue,
39658 + .set_halt = ep_halt,
39659 + .fifo_status = 0,
39664 +#endif /* _EN_ISOC_ */
39665 +/* Gadget Operations */
39667 + * The following gadget operations will be implemented in the DWC_otg
39668 + * PCD. Functions in the API that are not described below are not
39671 + * The Gadget API provides wrapper functions for each of the function
39672 + * pointers defined in usb_gadget_ops. The Gadget Driver calls the
39673 + * wrapper function, which then calls the underlying PCD function. The
39674 + * following sections are named according to the wrapper functions
39675 + * (except for ioctl, which doesn't have a wrapper function). Within
39676 + * each section, the corresponding DWC_otg PCD function name is
39682 + *Gets the USB Frame number of the last SOF.
39684 +static int get_frame_number(struct usb_gadget *gadget)
39686 + struct gadget_wrapper *d;
39688 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
39690 + if (gadget == 0) {
39694 + d = container_of(gadget, struct gadget_wrapper, gadget);
39695 + return dwc_otg_pcd_get_frame_number(d->pcd);
39698 +#ifdef CONFIG_USB_DWC_OTG_LPM
39699 +static int test_lpm_enabled(struct usb_gadget *gadget)
39701 + struct gadget_wrapper *d;
39703 + d = container_of(gadget, struct gadget_wrapper, gadget);
39705 + return dwc_otg_pcd_is_lpm_enabled(d->pcd);
39710 + * Initiates Session Request Protocol (SRP) to wakeup the host if no
39711 + * session is in progress. If a session is already in progress, but
39712 + * the device is suspended, remote wakeup signaling is started.
39715 +static int wakeup(struct usb_gadget *gadget)
39717 + struct gadget_wrapper *d;
39719 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
39721 + if (gadget == 0) {
39724 + d = container_of(gadget, struct gadget_wrapper, gadget);
39726 + dwc_otg_pcd_wakeup(d->pcd);
39730 +static const struct usb_gadget_ops dwc_otg_pcd_ops = {
39731 + .get_frame = get_frame_number,
39732 + .wakeup = wakeup,
39733 +#ifdef CONFIG_USB_DWC_OTG_LPM
39734 + .lpm_support = test_lpm_enabled,
39736 + // current versions must always be self-powered
39739 +static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
39741 + int retval = -DWC_E_NOT_SUPPORTED;
39742 + if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
39743 + retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
39744 + (struct usb_ctrlrequest
39748 + if (retval == -ENOTSUPP) {
39749 + retval = -DWC_E_NOT_SUPPORTED;
39750 + } else if (retval < 0) {
39751 + retval = -DWC_E_INVALID;
39757 +#ifdef DWC_EN_ISOC
39758 +static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
39759 + void *req_handle, int proc_buf_num)
39761 + int i, packet_count;
39762 + struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
39763 + struct usb_iso_request *iso_req = req_handle;
39765 + if (proc_buf_num) {
39766 + iso_packet = iso_req->iso_packet_desc1;
39768 + iso_packet = iso_req->iso_packet_desc0;
39771 + dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
39772 + for (i = 0; i < packet_count; ++i) {
39776 + dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
39777 + i, &status, &actual, &offset);
39778 + switch (status) {
39779 + case -DWC_E_NO_DATA:
39780 + status = -ENODATA;
39784 + DWC_PRINTF("unknown status in isoc packet\n");
39788 + iso_packet[i].status = status;
39789 + iso_packet[i].offset = offset;
39790 + iso_packet[i].actual_length = actual;
39793 + iso_req->status = 0;
39794 + iso_req->process_buffer(ep_handle, iso_req);
39798 +#endif /* DWC_EN_ISOC */
39800 +static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
39801 + void *req_handle, int32_t status, uint32_t actual)
39803 + struct usb_request *req = (struct usb_request *)req_handle;
39805 + if (req && req->complete) {
39806 + switch (status) {
39807 + case -DWC_E_SHUTDOWN:
39808 + req->status = -ESHUTDOWN;
39810 + case -DWC_E_RESTART:
39811 + req->status = -ECONNRESET;
39813 + case -DWC_E_INVALID:
39814 + req->status = -EINVAL;
39816 + case -DWC_E_TIMEOUT:
39817 + req->status = -ETIMEDOUT;
39820 + req->status = status;
39823 + req->actual = actual;
39824 + req->complete(ep_handle, req);
39830 +static int _connect(dwc_otg_pcd_t * pcd, int speed)
39832 + gadget_wrapper->gadget.speed = speed;
39836 +static int _disconnect(dwc_otg_pcd_t * pcd)
39838 + if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
39839 + gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
39844 +static int _resume(dwc_otg_pcd_t * pcd)
39846 + if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
39847 + gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
39853 +static int _suspend(dwc_otg_pcd_t * pcd)
39855 + if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
39856 + gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
39862 + * This function updates the otg values in the gadget structure.
39864 +static int _hnp_changed(dwc_otg_pcd_t * pcd)
39867 + if (!gadget_wrapper->gadget.is_otg)
39870 + gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
39871 + gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
39872 + gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
39876 +static int _reset(dwc_otg_pcd_t * pcd)
39881 +#ifdef DWC_UTE_CFI
39882 +static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
39884 + int retval = -DWC_E_INVALID;
39885 + if (gadget_wrapper->driver->cfi_feature_setup) {
39887 + gadget_wrapper->driver->cfi_feature_setup(&gadget_wrapper->
39890 + cfi_usb_ctrlrequest
39898 +static const struct dwc_otg_pcd_function_ops fops = {
39899 + .complete = _complete,
39900 +#ifdef DWC_EN_ISOC
39901 + .isoc_complete = _isoc_complete,
39904 + .disconnect = _disconnect,
39905 + .connect = _connect,
39906 + .resume = _resume,
39907 + .suspend = _suspend,
39908 + .hnp_changed = _hnp_changed,
39910 +#ifdef DWC_UTE_CFI
39911 + .cfi_setup = _cfi_setup,
39916 + * This function is the top level PCD interrupt handler.
39918 +static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
39920 + dwc_otg_pcd_t *pcd = dev;
39921 + int32_t retval = IRQ_NONE;
39923 + retval = dwc_otg_pcd_handle_intr(pcd);
39924 + if (retval != 0) {
39925 + S3C2410X_CLEAR_EINTPEND();
39927 + return IRQ_RETVAL(retval);
39931 + * This function initialized the usb_ep structures to there default
39934 + * @param d Pointer on gadget_wrapper.
39936 +void gadget_add_eps(struct gadget_wrapper *d)
39938 + static const char *names[] = {
39974 + struct usb_ep *ep;
39976 + DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
39978 + INIT_LIST_HEAD(&d->gadget.ep_list);
39979 + d->gadget.ep0 = &d->ep0;
39980 + d->gadget.speed = USB_SPEED_UNKNOWN;
39982 + INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
39985 + * Initialize the EP0 structure.
39989 + /* Init the usb_ep structure. */
39990 + ep->name = names[0];
39991 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
39994 + * @todo NGS: What should the max packet size be set to
39995 + * here? Before EP type is set?
39997 + ep->maxpacket = MAX_PACKET_SIZE;
39998 + dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
40000 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
40003 + * Initialize the EP structures.
40006 + for (i = 0; i < 15; i++) {
40007 + ep = &d->in_ep[i];
40009 + /* Init the usb_ep structure. */
40010 + ep->name = names[i + 1];
40011 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
40014 + * @todo NGS: What should the max packet size be set to
40015 + * here? Before EP type is set?
40017 + ep->maxpacket = MAX_PACKET_SIZE;
40018 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
40021 + for (i = 0; i < 15; i++) {
40022 + ep = &d->out_ep[i];
40024 + /* Init the usb_ep structure. */
40025 + ep->name = names[15 + i + 1];
40026 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
40029 + * @todo NGS: What should the max packet size be set to
40030 + * here? Before EP type is set?
40032 + ep->maxpacket = MAX_PACKET_SIZE;
40034 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
40037 + /* remove ep0 from the list. There is a ep0 pointer. */
40038 + list_del_init(&d->ep0.ep_list);
40040 + d->ep0.maxpacket = MAX_EP0_SIZE;
40044 + * This function releases the Gadget device.
40045 + * required by device_unregister().
40047 + * @todo Should this do something? Should it free the PCD?
40049 +static void dwc_otg_pcd_gadget_release(struct device *dev)
40051 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
40054 +static struct gadget_wrapper *alloc_wrapper(
40055 +#ifdef LM_INTERFACE
40056 + struct lm_device *_dev
40057 +#elif defined(PCI_INTERFACE)
40058 + struct pci_dev *_dev
40059 +#elif defined(PLATFORM_INTERFACE)
40060 + struct platform_device *_dev
40064 +#ifdef LM_INTERFACE
40065 + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
40066 +#elif defined(PCI_INTERFACE)
40067 + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
40068 +#elif defined(PLATFORM_INTERFACE)
40069 + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
40071 + static char pcd_name[] = "dwc_otg_pcd";
40073 + struct gadget_wrapper *d;
40076 + d = dwc_alloc(sizeof(*d));
40081 + memset(d, 0, sizeof(*d));
40083 + d->gadget.name = pcd_name;
40084 + d->pcd = otg_dev->pcd;
40085 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
40086 + strcpy(d->gadget.dev.bus_id, "gadget");
40088 + /*d->gadget.dev.bus = NULL;*/
40089 + d->gadget.dev.init_name = "gadget";
40091 + d->gadget.dev.parent = &_dev->dev;
40092 + d->gadget.dev.release = dwc_otg_pcd_gadget_release;
40093 + d->gadget.ops = &dwc_otg_pcd_ops;
40094 + d->gadget.max_speed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd)?USB_SPEED_HIGH:0;
40095 + d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
40098 + /* Register the gadget device */
40099 + retval = device_register(&d->gadget.dev);
40100 + if (retval != 0) {
40101 + DWC_ERROR("device_register failed\n");
40109 +static void free_wrapper(struct gadget_wrapper *d)
40112 + /* should have been done already by driver model core */
40113 + DWC_WARN("driver '%s' is still registered\n",
40114 + d->driver->driver.name);
40115 + usb_gadget_unregister_driver(d->driver);
40118 + device_unregister(&d->gadget.dev);
40123 + * This function initialized the PCD portion of the driver.
40127 +#ifdef LM_INTERFACE
40128 + struct lm_device *_dev
40129 +#elif defined(PCI_INTERFACE)
40130 + struct pci_dev *_dev
40131 +#elif defined(PLATFORM_INTERFACE)
40132 + struct platform_device *_dev
40137 +#ifdef LM_INTERFACE
40138 + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
40139 +#elif defined(PCI_INTERFACE)
40140 + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
40141 +#elif defined(PLATFORM_INTERFACE)
40142 + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
40148 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev=%p\n", __func__, _dev, otg_dev);
40150 + otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
40152 + if (!otg_dev->pcd) {
40153 + DWC_ERROR("dwc_otg_pcd_init failed\n");
40157 + gadget_wrapper = alloc_wrapper(_dev);
40160 + * Initialize EP structures
40162 + gadget_add_eps(gadget_wrapper);
40165 + * Setup interupt handler
40167 +#ifdef PLATFORM_INTERFACE
40168 + devirq = platform_get_irq(_dev, 0);
40170 + devirq = _dev->irq;
40172 + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", devirq);
40173 + retval = request_irq(devirq, dwc_otg_pcd_irq,
40174 + IRQF_SHARED, gadget_wrapper->gadget.name,
40176 + if (retval != 0) {
40177 + DWC_ERROR("request of irq%d failed\n", devirq);
40178 + free_wrapper(gadget_wrapper);
40182 + dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
40188 + * Cleanup the PCD.
40191 +#ifdef LM_INTERFACE
40192 + struct lm_device *_dev
40193 +#elif defined(PCI_INTERFACE)
40194 + struct pci_dev *_dev
40195 +#elif defined(PLATFORM_INTERFACE)
40196 + struct platform_device *_dev
40200 +#ifdef LM_INTERFACE
40201 + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
40202 +#elif defined(PCI_INTERFACE)
40203 + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
40204 +#elif defined(PLATFORM_INTERFACE)
40205 + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
40207 + dwc_otg_pcd_t *pcd = otg_dev->pcd;
40209 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
40214 +#ifdef PLATFORM_INTERFACE
40215 + free_irq(platform_get_irq(_dev, 0), pcd);
40217 + free_irq(_dev->irq, pcd);
40219 + dwc_otg_pcd_remove(otg_dev->pcd);
40220 + free_wrapper(gadget_wrapper);
40221 + otg_dev->pcd = 0;
40225 + * This function registers a gadget driver with the PCD.
40227 + * When a driver is successfully registered, it will receive control
40228 + * requests including set_configuration(), which enables non-control
40229 + * requests. then usb traffic follows until a disconnect is reported.
40230 + * then a host may connect again, or the driver might get unbound.
40232 + * @param driver The driver being registered
40234 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
40235 +int usb_gadget_register_driver(struct usb_gadget_driver *driver)
40237 +int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
40238 + int (*bind)(struct usb_gadget *))
40243 + DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
40244 + driver->driver.name);
40246 + if (!driver || driver->max_speed == USB_SPEED_UNKNOWN ||
40247 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
40252 + !driver->unbind || !driver->disconnect || !driver->setup) {
40253 + DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
40256 + if (gadget_wrapper == 0) {
40257 + DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
40260 + if (gadget_wrapper->driver != 0) {
40261 + DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
40265 + /* hook up the driver */
40266 + gadget_wrapper->driver = driver;
40267 + gadget_wrapper->gadget.dev.driver = &driver->driver;
40269 + DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
40270 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
40271 + retval = driver->bind(&gadget_wrapper->gadget);
40273 + retval = bind(&gadget_wrapper->gadget);
40276 + DWC_ERROR("bind to driver %s --> error %d\n",
40277 + driver->driver.name, retval);
40278 + gadget_wrapper->driver = 0;
40279 + gadget_wrapper->gadget.dev.driver = 0;
40282 + DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
40283 + driver->driver.name);
40287 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
40288 +EXPORT_SYMBOL(usb_gadget_register_driver);
40290 +EXPORT_SYMBOL(usb_gadget_probe_driver);
40294 + * This function unregisters a gadget driver
40296 + * @param driver The driver being unregistered
40298 +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
40300 + //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
40302 + if (gadget_wrapper == 0) {
40303 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
40307 + if (driver == 0 || driver != gadget_wrapper->driver) {
40308 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
40313 + driver->unbind(&gadget_wrapper->gadget);
40314 + gadget_wrapper->driver = 0;
40316 + DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
40320 +EXPORT_SYMBOL(usb_gadget_unregister_driver);
40322 +#endif /* DWC_HOST_ONLY */
40324 +++ b/drivers/usb/host/dwc_otg/dwc_otg_regs.h
40326 +/* ==========================================================================
40327 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $
40328 + * $Revision: #76 $
40329 + * $Date: 2009/04/02 $
40330 + * $Change: 1224216 $
40332 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
40333 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
40334 + * otherwise expressly agreed to in writing between Synopsys and you.
40336 + * The Software IS NOT an item of Licensed Software or Licensed Product under
40337 + * any End User Software License Agreement or Agreement for Licensed Product
40338 + * with Synopsys or any supplement thereto. You are permitted to use and
40339 + * redistribute this Software in source and binary forms, with or without
40340 + * modification, provided that redistributions of source code must retain this
40341 + * notice. You may not view, use, disclose, copy or distribute this file or
40342 + * any information contained herein except pursuant to this license grant from
40343 + * Synopsys. If you do not agree with this notice, including the disclaimer
40344 + * below, then you are not authorized to use the Software.
40346 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
40347 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40348 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40349 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
40350 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40351 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
40352 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
40353 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40354 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40355 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
40357 + * ========================================================================== */
40359 +#ifndef __DWC_OTG_REGS_H__
40360 +#define __DWC_OTG_REGS_H__
40362 +#include "dwc_otg_core_if.h"
40367 + * This file contains the data structures for accessing the DWC_otg core registers.
40369 + * The application interfaces with the HS OTG core by reading from and
40370 + * writing to the Control and Status Register (CSR) space through the
40371 + * AHB Slave interface. These registers are 32 bits wide, and the
40372 + * addresses are 32-bit-block aligned.
40373 + * CSRs are classified as follows:
40374 + * - Core Global Registers
40375 + * - Device Mode Registers
40376 + * - Device Global Registers
40377 + * - Device Endpoint Specific Registers
40378 + * - Host Mode Registers
40379 + * - Host Global Registers
40380 + * - Host Port CSRs
40381 + * - Host Channel Specific Registers
40383 + * Only the Core Global registers can be accessed in both Device and
40384 + * Host modes. When the HS OTG core is operating in one mode, either
40385 + * Device or Host, the application must not access registers from the
40386 + * other mode. When the core switches from one mode to another, the
40387 + * registers in the new mode of operation must be reprogrammed as they
40388 + * would be after a power-on reset.
40391 +/****************************************************************************/
40392 +/** DWC_otg Core registers .
40393 + * The dwc_otg_core_global_regs structure defines the size
40394 + * and relative field offsets for the Core Global registers.
40396 +typedef struct dwc_otg_core_global_regs {
40397 + /** OTG Control and Status Register. <i>Offset: 000h</i> */
40398 + volatile uint32_t gotgctl;
40399 + /** OTG Interrupt Register. <i>Offset: 004h</i> */
40400 + volatile uint32_t gotgint;
40401 + /**Core AHB Configuration Register. <i>Offset: 008h</i> */
40402 + volatile uint32_t gahbcfg;
40404 +#define DWC_GLBINTRMASK 0x0001
40405 +#define DWC_DMAENABLE 0x0020
40406 +#define DWC_NPTXEMPTYLVL_EMPTY 0x0080
40407 +#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000
40408 +#define DWC_PTXEMPTYLVL_EMPTY 0x0100
40409 +#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000
40411 + /**Core USB Configuration Register. <i>Offset: 00Ch</i> */
40412 + volatile uint32_t gusbcfg;
40413 + /**Core Reset Register. <i>Offset: 010h</i> */
40414 + volatile uint32_t grstctl;
40415 + /**Core Interrupt Register. <i>Offset: 014h</i> */
40416 + volatile uint32_t gintsts;
40417 + /**Core Interrupt Mask Register. <i>Offset: 018h</i> */
40418 + volatile uint32_t gintmsk;
40419 + /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */
40420 + volatile uint32_t grxstsr;
40421 + /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/
40422 + volatile uint32_t grxstsp;
40423 + /**Receive FIFO Size Register. <i>Offset: 024h</i> */
40424 + volatile uint32_t grxfsiz;
40425 + /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */
40426 + volatile uint32_t gnptxfsiz;
40427 + /**Non Periodic Transmit FIFO/Queue Status Register (Read
40428 + * Only). <i>Offset: 02Ch</i> */
40429 + volatile uint32_t gnptxsts;
40430 + /**I2C Access Register. <i>Offset: 030h</i> */
40431 + volatile uint32_t gi2cctl;
40432 + /**PHY Vendor Control Register. <i>Offset: 034h</i> */
40433 + volatile uint32_t gpvndctl;
40434 + /**General Purpose Input/Output Register. <i>Offset: 038h</i> */
40435 + volatile uint32_t ggpio;
40436 + /**User ID Register. <i>Offset: 03Ch</i> */
40437 + volatile uint32_t guid;
40438 + /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */
40439 + volatile uint32_t gsnpsid;
40440 + /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */
40441 + volatile uint32_t ghwcfg1;
40442 + /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */
40443 + volatile uint32_t ghwcfg2;
40444 +#define DWC_SLAVE_ONLY_ARCH 0
40445 +#define DWC_EXT_DMA_ARCH 1
40446 +#define DWC_INT_DMA_ARCH 2
40448 +#define DWC_MODE_HNP_SRP_CAPABLE 0
40449 +#define DWC_MODE_SRP_ONLY_CAPABLE 1
40450 +#define DWC_MODE_NO_HNP_SRP_CAPABLE 2
40451 +#define DWC_MODE_SRP_CAPABLE_DEVICE 3
40452 +#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4
40453 +#define DWC_MODE_SRP_CAPABLE_HOST 5
40454 +#define DWC_MODE_NO_SRP_CAPABLE_HOST 6
40456 + /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */
40457 + volatile uint32_t ghwcfg3;
40458 + /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/
40459 + volatile uint32_t ghwcfg4;
40460 + /** Core LPM Configuration register */
40461 + volatile uint32_t glpmcfg;
40462 + /** Reserved <i>Offset: 058h-0FFh</i> */
40463 + volatile uint32_t reserved[42];
40464 + /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */
40465 + volatile uint32_t hptxfsiz;
40466 + /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled,
40467 + otherwise Device Transmit FIFO#n Register.
40468 + * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */
40469 + volatile uint32_t dptxfsiz_dieptxf[15];
40470 +} dwc_otg_core_global_regs_t;
40473 + * This union represents the bit fields of the Core OTG Control
40474 + * and Status Register (GOTGCTL). Set the bits using the bit
40475 + * fields then write the <i>d32</i> value to the register.
40477 +typedef union gotgctl_data {
40478 + /** raw register data */
40480 + /** register bits */
40482 + unsigned sesreqscs:1;
40483 + unsigned sesreq:1;
40484 + unsigned reserved2_7:6;
40485 + unsigned hstnegscs:1;
40486 + unsigned hnpreq:1;
40487 + unsigned hstsethnpen:1;
40488 + unsigned devhnpen:1;
40489 + unsigned reserved12_15:4;
40490 + unsigned conidsts:1;
40491 + unsigned reserved17:1;
40492 + unsigned asesvld:1;
40493 + unsigned bsesvld:1;
40494 + unsigned currmod:1;
40495 + unsigned reserved21_31:11;
40500 + * This union represents the bit fields of the Core OTG Interrupt Register
40501 + * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i>
40502 + * value to the register.
40504 +typedef union gotgint_data {
40505 + /** raw register data */
40507 + /** register bits */
40509 + /** Current Mode */
40510 + unsigned reserved0_1:2;
40512 + /** Session End Detected */
40513 + unsigned sesenddet:1;
40515 + unsigned reserved3_7:5;
40517 + /** Session Request Success Status Change */
40518 + unsigned sesreqsucstschng:1;
40519 + /** Host Negotiation Success Status Change */
40520 + unsigned hstnegsucstschng:1;
40522 + unsigned reserver10_16:7;
40524 + /** Host Negotiation Detected */
40525 + unsigned hstnegdet:1;
40526 + /** A-Device Timeout Change */
40527 + unsigned adevtoutchng:1;
40528 + /** Debounce Done */
40529 + unsigned debdone:1;
40531 + unsigned reserved31_20:12;
40537 + * This union represents the bit fields of the Core AHB Configuration
40538 + * Register (GAHBCFG). Set/clear the bits using the bit fields then
40539 + * write the <i>d32</i> value to the register.
40541 +typedef union gahbcfg_data {
40542 + /** raw register data */
40544 + /** register bits */
40546 + unsigned glblintrmsk:1;
40547 +#define DWC_GAHBCFG_GLBINT_ENABLE 1
40549 + unsigned hburstlen:4;
40550 +#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0
40551 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1
40552 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3
40553 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5
40554 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7
40556 + unsigned dmaenable:1;
40557 +#define DWC_GAHBCFG_DMAENABLE 1
40558 + unsigned reserved:1;
40559 + unsigned nptxfemplvl_txfemplvl:1;
40560 + unsigned ptxfemplvl:1;
40561 +#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1
40562 +#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0
40563 + unsigned reserved9_31:23;
40568 + * This union represents the bit fields of the Core USB Configuration
40569 + * Register (GUSBCFG). Set the bits using the bit fields then write
40570 + * the <i>d32</i> value to the register.
40572 +typedef union gusbcfg_data {
40573 + /** raw register data */
40575 + /** register bits */
40577 + unsigned toutcal:3;
40578 + unsigned phyif:1;
40579 + unsigned ulpi_utmi_sel:1;
40580 + unsigned fsintf:1;
40581 + unsigned physel:1;
40582 + unsigned ddrsel:1;
40583 + unsigned srpcap:1;
40584 + unsigned hnpcap:1;
40585 + unsigned usbtrdtim:4;
40586 + unsigned nptxfrwnden:1;
40587 + unsigned phylpwrclksel:1;
40588 + unsigned otgutmifssel:1;
40589 + unsigned ulpi_fsls:1;
40590 + unsigned ulpi_auto_res:1;
40591 + unsigned ulpi_clk_sus_m:1;
40592 + unsigned ulpi_ext_vbus_drv:1;
40593 + unsigned ulpi_int_vbus_indicator:1;
40594 + unsigned term_sel_dl_pulse:1;
40595 + unsigned reserved23_25:3;
40596 + unsigned ic_usb_cap:1;
40597 + unsigned ic_traffic_pull_remove:1;
40598 + unsigned tx_end_delay:1;
40599 + unsigned reserved29_31:3;
40604 + * This union represents the bit fields of the Core LPM Configuration
40605 + * Register (GLPMCFG). Set the bits using bit fields then write
40606 + * the <i>d32</i> value to the register.
40608 +typedef union glpmctl_data {
40609 + /** raw register data */
40611 + /** register bits */
40613 + /** LPM-Capable (LPMCap) (Device and Host)
40614 + * The application uses this bit to control
40615 + * the DWC_otg core LPM capabilities.
40617 + unsigned lpm_cap_en:1;
40618 + /** LPM response programmed by application (AppL1Res) (Device)
40619 + * Handshake response to LPM token pre-programmed
40620 + * by device application software.
40622 + unsigned appl_resp:1;
40623 + /** Host Initiated Resume Duration (HIRD) (Device and Host)
40624 + * In Host mode this field indicates the value of HIRD
40625 + * to be sent in an LPM transaction.
40626 + * In Device mode this field is updated with the
40627 + * Received LPM Token HIRD bmAttribute
40628 + * when an ACK/NYET/STALL response is sent
40629 + * to an LPM transaction.
40632 + /** RemoteWakeEnable (bRemoteWake) (Device and Host)
40633 + * In Host mode this bit indicates the value of remote
40634 + * wake up to be sent in wIndex field of LPM transaction.
40635 + * In Device mode this field is updated with the
40636 + * Received LPM Token bRemoteWake bmAttribute
40637 + * when an ACK/NYET/STALL response is sent
40638 + * to an LPM transaction.
40640 + unsigned rem_wkup_en:1;
40641 + /** Enable utmi_sleep_n (EnblSlpM) (Device and Host)
40642 + * The application uses this bit to control
40643 + * the utmi_sleep_n assertion to the PHY when in L1 state.
40645 + unsigned en_utmi_sleep:1;
40646 + /** HIRD Threshold (HIRD_Thres) (Device and Host)
40648 + unsigned hird_thres:5;
40649 + /** LPM Response (CoreL1Res) (Device and Host)
40650 + * In Host mode this bit contains handsake response to
40651 + * LPM transaction.
40652 + * In Device mode the response of the core to
40653 + * LPM transaction received is reflected in these two bits.
40654 + - 0x0 : ERROR (No handshake response)
40659 + unsigned lpm_resp:2;
40660 + /** Port Sleep Status (SlpSts) (Device and Host)
40661 + * This bit is set as long as a Sleep condition
40662 + * is present on the USB bus.
40664 + unsigned prt_sleep_sts:1;
40665 + /** Sleep State Resume OK (L1ResumeOK) (Device and Host)
40666 + * Indicates that the application or host
40667 + * can start resume from Sleep state.
40669 + unsigned sleep_state_resumeok:1;
40670 + /** LPM channel Index (LPM_Chnl_Indx) (Host)
40671 + * The channel number on which the LPM transaction
40672 + * has to be applied while sending
40673 + * an LPM transaction to the local device.
40675 + unsigned lpm_chan_index:4;
40676 + /** LPM Retry Count (LPM_Retry_Cnt) (Host)
40677 + * Number host retries that would be performed
40678 + * if the device response was not valid response.
40680 + unsigned retry_count:3;
40681 + /** Send LPM Transaction (SndLPM) (Host)
40682 + * When set by application software,
40683 + * an LPM transaction containing two tokens
40686 + unsigned send_lpm:1;
40687 + /** LPM Retry status (LPM_RetryCnt_Sts) (Host)
40688 + * Number of LPM Host Retries still remaining
40689 + * to be transmitted for the current LPM sequence
40691 + unsigned retry_count_sts:3;
40692 + unsigned reserved28_29:2;
40693 + /** In host mode once this bit is set, the host
40694 + * configures to drive the HSIC Idle state on the bus.
40695 + * It then waits for the device to initiate the Connect sequence.
40696 + * In device mode once this bit is set, the device waits for
40697 + * the HSIC Idle line state on the bus. Upon receving the Idle
40698 + * line state, it initiates the HSIC Connect sequence.
40700 + unsigned hsic_connect:1;
40701 + /** This bit overrides and functionally inverts
40702 + * the if_select_hsic input port signal.
40704 + unsigned inv_sel_hsic:1;
40709 + * This union represents the bit fields of the Core Reset Register
40710 + * (GRSTCTL). Set/clear the bits using the bit fields then write the
40711 + * <i>d32</i> value to the register.
40713 +typedef union grstctl_data {
40714 + /** raw register data */
40716 + /** register bits */
40718 + /** Core Soft Reset (CSftRst) (Device and Host)
40720 + * The application can flush the control logic in the
40721 + * entire core using this bit. This bit resets the
40722 + * pipelines in the AHB Clock domain as well as the
40723 + * PHY Clock domain.
40725 + * The state machines are reset to an IDLE state, the
40726 + * control bits in the CSRs are cleared, all the
40727 + * transmit FIFOs and the receive FIFO are flushed.
40729 + * The status mask bits that control the generation of
40730 + * the interrupt, are cleared, to clear the
40731 + * interrupt. The interrupt status bits are not
40732 + * cleared, so the application can get the status of
40733 + * any events that occurred in the core after it has
40736 + * Any transactions on the AHB are terminated as soon
40737 + * as possible following the protocol. Any
40738 + * transactions on the USB are terminated immediately.
40740 + * The configuration settings in the CSRs are
40741 + * unchanged, so the software doesn't have to
40742 + * reprogram these registers (Device
40743 + * Configuration/Host Configuration/Core System
40744 + * Configuration/Core PHY Configuration).
40746 + * The application can write to this bit, any time it
40747 + * wants to reset the core. This is a self clearing
40748 + * bit and the core clears this bit after all the
40749 + * necessary logic is reset in the core, which may
40750 + * take several clocks, depending on the current state
40753 + unsigned csftrst:1;
40754 + /** Hclk Soft Reset
40756 + * The application uses this bit to reset the control logic in
40757 + * the AHB clock domain. Only AHB clock domain pipelines are
40760 + unsigned hsftrst:1;
40761 + /** Host Frame Counter Reset (Host Only)<br>
40763 + * The application can reset the (micro)frame number
40764 + * counter inside the core, using this bit. When the
40765 + * (micro)frame counter is reset, the subsequent SOF
40766 + * sent out by the core, will have a (micro)frame
40769 + unsigned hstfrm:1;
40770 + /** In Token Sequence Learning Queue Flush
40771 + * (INTknQFlsh) (Device Only)
40773 + unsigned intknqflsh:1;
40774 + /** RxFIFO Flush (RxFFlsh) (Device and Host)
40776 + * The application can flush the entire Receive FIFO
40777 + * using this bit. <p>The application must first
40778 + * ensure that the core is not in the middle of a
40779 + * transaction. <p>The application should write into
40780 + * this bit, only after making sure that neither the
40781 + * DMA engine is reading from the RxFIFO nor the MAC
40782 + * is writing the data in to the FIFO. <p>The
40783 + * application should wait until the bit is cleared
40784 + * before performing any other operations. This bit
40785 + * will takes 8 clocks (slowest of PHY or AHB clock)
40788 + unsigned rxfflsh:1;
40789 + /** TxFIFO Flush (TxFFlsh) (Device and Host).
40791 + * This bit is used to selectively flush a single or
40792 + * all transmit FIFOs. The application must first
40793 + * ensure that the core is not in the middle of a
40794 + * transaction. <p>The application should write into
40795 + * this bit, only after making sure that neither the
40796 + * DMA engine is writing into the TxFIFO nor the MAC
40797 + * is reading the data out of the FIFO. <p>The
40798 + * application should wait until the core clears this
40799 + * bit, before performing any operations. This bit
40800 + * will takes 8 clocks (slowest of PHY or AHB clock)
40803 + unsigned txfflsh:1;
40805 + /** TxFIFO Number (TxFNum) (Device and Host).
40807 + * This is the FIFO number which needs to be flushed,
40808 + * using the TxFIFO Flush bit. This field should not
40809 + * be changed until the TxFIFO Flush bit is cleared by
40811 + * - 0x0 : Non Periodic TxFIFO Flush
40812 + * - 0x1 : Periodic TxFIFO #1 Flush in device mode
40813 + * or Periodic TxFIFO in host mode
40814 + * - 0x2 : Periodic TxFIFO #2 Flush in device mode.
40816 + * - 0xF : Periodic TxFIFO #15 Flush in device mode
40817 + * - 0x10: Flush all the Transmit NonPeriodic and
40818 + * Transmit Periodic FIFOs in the core
40820 + unsigned txfnum:5;
40822 + unsigned reserved11_29:19;
40823 + /** DMA Request Signal. Indicated DMA request is in
40824 + * probress. Used for debug purpose. */
40825 + unsigned dmareq:1;
40826 + /** AHB Master Idle. Indicates the AHB Master State
40827 + * Machine is in IDLE condition. */
40828 + unsigned ahbidle:1;
40833 + * This union represents the bit fields of the Core Interrupt Mask
40834 + * Register (GINTMSK). Set/clear the bits using the bit fields then
40835 + * write the <i>d32</i> value to the register.
40837 +typedef union gintmsk_data {
40838 + /** raw register data */
40840 + /** register bits */
40842 + unsigned reserved0:1;
40843 + unsigned modemismatch:1;
40844 + unsigned otgintr:1;
40845 + unsigned sofintr:1;
40846 + unsigned rxstsqlvl:1;
40847 + unsigned nptxfempty:1;
40848 + unsigned ginnakeff:1;
40849 + unsigned goutnakeff:1;
40850 + unsigned reserved8:1;
40851 + unsigned i2cintr:1;
40852 + unsigned erlysuspend:1;
40853 + unsigned usbsuspend:1;
40854 + unsigned usbreset:1;
40855 + unsigned enumdone:1;
40856 + unsigned isooutdrop:1;
40857 + unsigned eopframe:1;
40858 + unsigned reserved16:1;
40859 + unsigned epmismatch:1;
40860 + unsigned inepintr:1;
40861 + unsigned outepintr:1;
40862 + unsigned incomplisoin:1;
40863 + unsigned incomplisoout:1;
40864 + unsigned reserved22_23:2;
40865 + unsigned portintr:1;
40866 + unsigned hcintr:1;
40867 + unsigned ptxfempty:1;
40868 + unsigned lpmtranrcvd:1;
40869 + unsigned conidstschng:1;
40870 + unsigned disconnect:1;
40871 + unsigned sessreqintr:1;
40872 + unsigned wkupintr:1;
40876 + * This union represents the bit fields of the Core Interrupt Register
40877 + * (GINTSTS). Set/clear the bits using the bit fields then write the
40878 + * <i>d32</i> value to the register.
40880 +typedef union gintsts_data {
40881 + /** raw register data */
40883 +#define DWC_SOF_INTR_MASK 0x0008
40884 + /** register bits */
40886 +#define DWC_HOST_MODE 1
40887 + unsigned curmode:1;
40888 + unsigned modemismatch:1;
40889 + unsigned otgintr:1;
40890 + unsigned sofintr:1;
40891 + unsigned rxstsqlvl:1;
40892 + unsigned nptxfempty:1;
40893 + unsigned ginnakeff:1;
40894 + unsigned goutnakeff:1;
40895 + unsigned reserved8:1;
40896 + unsigned i2cintr:1;
40897 + unsigned erlysuspend:1;
40898 + unsigned usbsuspend:1;
40899 + unsigned usbreset:1;
40900 + unsigned enumdone:1;
40901 + unsigned isooutdrop:1;
40902 + unsigned eopframe:1;
40903 + unsigned intokenrx:1;
40904 + unsigned epmismatch:1;
40905 + unsigned inepint:1;
40906 + unsigned outepintr:1;
40907 + unsigned incomplisoin:1;
40908 + unsigned incomplisoout:1;
40909 + unsigned reserved22_23:2;
40910 + unsigned portintr:1;
40911 + unsigned hcintr:1;
40912 + unsigned ptxfempty:1;
40913 + unsigned lpmtranrcvd:1;
40914 + unsigned conidstschng:1;
40915 + unsigned disconnect:1;
40916 + unsigned sessreqintr:1;
40917 + unsigned wkupintr:1;
40922 + * This union represents the bit fields in the Device Receive Status Read and
40923 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
40924 + * element then read out the bits using the <i>b</i>it elements.
40926 +typedef union device_grxsts_data {
40927 + /** raw register data */
40929 + /** register bits */
40931 + unsigned epnum:4;
40932 + unsigned bcnt:11;
40935 +#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet
40936 +#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete
40938 +#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK
40939 +#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete
40940 +#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet
40941 + unsigned pktsts:4;
40943 + unsigned reserved:7;
40945 +} device_grxsts_data_t;
40948 + * This union represents the bit fields in the Host Receive Status Read and
40949 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
40950 + * element then read out the bits using the <i>b</i>it elements.
40952 +typedef union host_grxsts_data {
40953 + /** raw register data */
40955 + /** register bits */
40957 + unsigned chnum:4;
40958 + unsigned bcnt:11;
40961 + unsigned pktsts:4;
40962 +#define DWC_GRXSTS_PKTSTS_IN 0x2
40963 +#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3
40964 +#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
40965 +#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7
40967 + unsigned reserved:11;
40969 +} host_grxsts_data_t;
40972 + * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ,
40973 + * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the <i>d32</i> element then
40974 + * read out the bits using the <i>b</i>it elements.
40976 +typedef union fifosize_data {
40977 + /** raw register data */
40979 + /** register bits */
40981 + unsigned startaddr:16;
40982 + unsigned depth:16;
40984 +} fifosize_data_t;
40987 + * This union represents the bit fields in the Non-Periodic Transmit
40988 + * FIFO/Queue Status Register (GNPTXSTS). Read the register into the
40989 + * <i>d32</i> element then read out the bits using the <i>b</i>it
40992 +typedef union gnptxsts_data {
40993 + /** raw register data */
40995 + /** register bits */
40997 + unsigned nptxfspcavail:16;
40998 + unsigned nptxqspcavail:8;
40999 + /** Top of the Non-Periodic Transmit Request Queue
41000 + * - bit 24 - Terminate (Last entry for the selected
41002 + * - bits 26:25 - Token Type
41003 + * - 2'b00 - IN/OUT
41004 + * - 2'b01 - Zero Length OUT
41005 + * - 2'b10 - PING/Complete Split
41006 + * - 2'b11 - Channel Halt
41007 + * - bits 30:27 - Channel/EP Number
41009 + unsigned nptxqtop_terminate:1;
41010 + unsigned nptxqtop_token:2;
41011 + unsigned nptxqtop_chnep:4;
41012 + unsigned reserved:1;
41014 +} gnptxsts_data_t;
41017 + * This union represents the bit fields in the Transmit
41018 + * FIFO Status Register (DTXFSTS). Read the register into the
41019 + * <i>d32</i> element then read out the bits using the <i>b</i>it
41022 +typedef union dtxfsts_data {
41023 + /** raw register data */
41025 + /** register bits */
41027 + unsigned txfspcavail:16;
41028 + unsigned reserved:16;
41033 + * This union represents the bit fields in the I2C Control Register
41034 + * (I2CCTL). Read the register into the <i>d32</i> element then read out the
41035 + * bits using the <i>b</i>it elements.
41037 +typedef union gi2cctl_data {
41038 + /** raw register data */
41040 + /** register bits */
41042 + unsigned rwdata:8;
41043 + unsigned regaddr:8;
41045 + unsigned i2cen:1;
41047 + unsigned i2csuspctl:1;
41048 + unsigned i2cdevaddr:2;
41049 + unsigned reserved:2;
41051 + unsigned bsydne:1;
41056 + * This union represents the bit fields in the User HW Config1
41057 + * Register. Read the register into the <i>d32</i> element then read
41058 + * out the bits using the <i>b</i>it elements.
41060 +typedef union hwcfg1_data {
41061 + /** raw register data */
41063 + /** register bits */
41065 + unsigned ep_dir0:2;
41066 + unsigned ep_dir1:2;
41067 + unsigned ep_dir2:2;
41068 + unsigned ep_dir3:2;
41069 + unsigned ep_dir4:2;
41070 + unsigned ep_dir5:2;
41071 + unsigned ep_dir6:2;
41072 + unsigned ep_dir7:2;
41073 + unsigned ep_dir8:2;
41074 + unsigned ep_dir9:2;
41075 + unsigned ep_dir10:2;
41076 + unsigned ep_dir11:2;
41077 + unsigned ep_dir12:2;
41078 + unsigned ep_dir13:2;
41079 + unsigned ep_dir14:2;
41080 + unsigned ep_dir15:2;
41085 + * This union represents the bit fields in the User HW Config2
41086 + * Register. Read the register into the <i>d32</i> element then read
41087 + * out the bits using the <i>b</i>it elements.
41089 +typedef union hwcfg2_data {
41090 + /** raw register data */
41092 + /** register bits */
41095 + unsigned op_mode:3;
41096 +#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
41097 +#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
41098 +#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
41099 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
41100 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
41101 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
41102 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
41104 + unsigned architecture:2;
41105 + unsigned point2point:1;
41106 + unsigned hs_phy_type:2;
41107 +#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
41108 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
41109 +#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
41110 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
41112 + unsigned fs_phy_type:2;
41113 + unsigned num_dev_ep:4;
41114 + unsigned num_host_chan:4;
41115 + unsigned perio_ep_supported:1;
41116 + unsigned dynamic_fifo:1;
41117 + unsigned multi_proc_int:1;
41118 + unsigned reserved21:1;
41119 + unsigned nonperio_tx_q_depth:2;
41120 + unsigned host_perio_tx_q_depth:2;
41121 + unsigned dev_token_q_depth:5;
41122 + unsigned reserved31:1;
41127 + * This union represents the bit fields in the User HW Config3
41128 + * Register. Read the register into the <i>d32</i> element then read
41129 + * out the bits using the <i>b</i>it elements.
41131 +typedef union hwcfg3_data {
41132 + /** raw register data */
41134 + /** register bits */
41137 + unsigned xfer_size_cntr_width:4;
41138 + unsigned packet_size_cntr_width:3;
41139 + unsigned otg_func:1;
41141 + unsigned vendor_ctrl_if:1;
41142 + unsigned optional_features:1;
41143 + unsigned synch_reset_type:1;
41144 + unsigned otg_enable_ic_usb:1;
41145 + unsigned otg_enable_hsic:1;
41146 + unsigned reserved14:1;
41147 + unsigned otg_lpm_en:1;
41148 + unsigned dfifo_depth:16;
41153 + * This union represents the bit fields in the User HW Config4
41154 + * Register. Read the register into the <i>d32</i> element then read
41155 + * out the bits using the <i>b</i>it elements.
41157 +typedef union hwcfg4_data {
41158 + /** raw register data */
41160 + /** register bits */
41162 + unsigned num_dev_perio_in_ep:4;
41163 + unsigned power_optimiz:1;
41164 + unsigned min_ahb_freq:9;
41165 + unsigned utmi_phy_data_width:2;
41166 + unsigned num_dev_mode_ctrl_ep:4;
41167 + unsigned iddig_filt_en:1;
41168 + unsigned vbus_valid_filt_en:1;
41169 + unsigned a_valid_filt_en:1;
41170 + unsigned b_valid_filt_en:1;
41171 + unsigned session_end_filt_en:1;
41172 + unsigned ded_fifo_en:1;
41173 + unsigned num_in_eps:4;
41174 + unsigned desc_dma:1;
41175 + unsigned desc_dma_dyn:1;
41179 +////////////////////////////////////////////
41180 +// Device Registers
41182 + * Device Global Registers. <i>Offsets 800h-BFFh</i>
41184 + * The following structures define the size and relative field offsets
41185 + * for the Device Mode Registers.
41187 + * <i>These registers are visible only in Device mode and must not be
41188 + * accessed in Host mode, as the results are unknown.</i>
41190 +typedef struct dwc_otg_dev_global_regs {
41191 + /** Device Configuration Register. <i>Offset 800h</i> */
41192 + volatile uint32_t dcfg;
41193 + /** Device Control Register. <i>Offset: 804h</i> */
41194 + volatile uint32_t dctl;
41195 + /** Device Status Register (Read Only). <i>Offset: 808h</i> */
41196 + volatile uint32_t dsts;
41197 + /** Reserved. <i>Offset: 80Ch</i> */
41199 + /** Device IN Endpoint Common Interrupt Mask
41200 + * Register. <i>Offset: 810h</i> */
41201 + volatile uint32_t diepmsk;
41202 + /** Device OUT Endpoint Common Interrupt Mask
41203 + * Register. <i>Offset: 814h</i> */
41204 + volatile uint32_t doepmsk;
41205 + /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */
41206 + volatile uint32_t daint;
41207 + /** Device All Endpoints Interrupt Mask Register. <i>Offset:
41209 + volatile uint32_t daintmsk;
41210 + /** Device IN Token Queue Read Register-1 (Read Only).
41211 + * <i>Offset: 820h</i> */
41212 + volatile uint32_t dtknqr1;
41213 + /** Device IN Token Queue Read Register-2 (Read Only).
41214 + * <i>Offset: 824h</i> */
41215 + volatile uint32_t dtknqr2;
41216 + /** Device VBUS discharge Register. <i>Offset: 828h</i> */
41217 + volatile uint32_t dvbusdis;
41218 + /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */
41219 + volatile uint32_t dvbuspulse;
41220 + /** Device IN Token Queue Read Register-3 (Read Only). /
41221 + * Device Thresholding control register (Read/Write)
41222 + * <i>Offset: 830h</i> */
41223 + volatile uint32_t dtknqr3_dthrctl;
41224 + /** Device IN Token Queue Read Register-4 (Read Only). /
41225 + * Device IN EPs empty Inr. Mask Register (Read/Write)
41226 + * <i>Offset: 834h</i> */
41227 + volatile uint32_t dtknqr4_fifoemptymsk;
41228 + /** Device Each Endpoint Interrupt Register (Read Only). /
41229 + * <i>Offset: 838h</i> */
41230 + volatile uint32_t deachint;
41231 + /** Device Each Endpoint Interrupt mask Register (Read/Write). /
41232 + * <i>Offset: 83Ch</i> */
41233 + volatile uint32_t deachintmsk;
41234 + /** Device Each In Endpoint Interrupt mask Register (Read/Write). /
41235 + * <i>Offset: 840h</i> */
41236 + volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS];
41237 + /** Device Each Out Endpoint Interrupt mask Register (Read/Write). /
41238 + * <i>Offset: 880h</i> */
41239 + volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS];
41240 +} dwc_otg_device_global_regs_t;
41243 + * This union represents the bit fields in the Device Configuration
41244 + * Register. Read the register into the <i>d32</i> member then
41245 + * set/clear the bits using the <i>b</i>it elements. Write the
41246 + * <i>d32</i> member to the dcfg register.
41248 +typedef union dcfg_data {
41249 + /** raw register data */
41251 + /** register bits */
41253 + /** Device Speed */
41254 + unsigned devspd:2;
41255 + /** Non Zero Length Status OUT Handshake */
41256 + unsigned nzstsouthshk:1;
41257 +#define DWC_DCFG_SEND_STALL 1
41259 + unsigned reserved3:1;
41260 + /** Device Addresses */
41261 + unsigned devaddr:7;
41262 + /** Periodic Frame Interval */
41263 + unsigned perfrint:2;
41264 +#define DWC_DCFG_FRAME_INTERVAL_80 0
41265 +#define DWC_DCFG_FRAME_INTERVAL_85 1
41266 +#define DWC_DCFG_FRAME_INTERVAL_90 2
41267 +#define DWC_DCFG_FRAME_INTERVAL_95 3
41269 + unsigned reserved13_17:5;
41270 + /** In Endpoint Mis-match count */
41271 + unsigned epmscnt:5;
41272 + /** Enable Descriptor DMA in Device mode */
41273 + unsigned descdma:1;
41278 + * This union represents the bit fields in the Device Control
41279 + * Register. Read the register into the <i>d32</i> member then
41280 + * set/clear the bits using the <i>b</i>it elements.
41282 +typedef union dctl_data {
41283 + /** raw register data */
41285 + /** register bits */
41287 + /** Remote Wakeup */
41288 + unsigned rmtwkupsig:1;
41289 + /** Soft Disconnect */
41290 + unsigned sftdiscon:1;
41291 + /** Global Non-Periodic IN NAK Status */
41292 + unsigned gnpinnaksts:1;
41293 + /** Global OUT NAK Status */
41294 + unsigned goutnaksts:1;
41295 + /** Test Control */
41296 + unsigned tstctl:3;
41297 + /** Set Global Non-Periodic IN NAK */
41298 + unsigned sgnpinnak:1;
41299 + /** Clear Global Non-Periodic IN NAK */
41300 + unsigned cgnpinnak:1;
41301 + /** Set Global OUT NAK */
41302 + unsigned sgoutnak:1;
41303 + /** Clear Global OUT NAK */
41304 + unsigned cgoutnak:1;
41306 + /** Power-On Programming Done */
41307 + unsigned pwronprgdone:1;
41308 + /** Global Continue on BNA */
41309 + unsigned gcontbna:1;
41310 + /** Global Multi Count */
41312 + /** Ignore Frame Number for ISOC EPs */
41313 + unsigned ifrmnum:1;
41314 + /** NAK on Babble */
41315 + unsigned nakonbble:1;
41317 + unsigned reserved17_31:15;
41322 + * This union represents the bit fields in the Device Status
41323 + * Register. Read the register into the <i>d32</i> member then
41324 + * set/clear the bits using the <i>b</i>it elements.
41326 +typedef union dsts_data {
41327 + /** raw register data */
41329 + /** register bits */
41331 + /** Suspend Status */
41332 + unsigned suspsts:1;
41333 + /** Enumerated Speed */
41334 + unsigned enumspd:2;
41335 +#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
41336 +#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
41337 +#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2
41338 +#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3
41339 + /** Erratic Error */
41340 + unsigned errticerr:1;
41341 + unsigned reserved4_7:4;
41342 + /** Frame or Microframe Number of the received SOF */
41343 + unsigned soffn:14;
41344 + unsigned reserved22_31:10;
41349 + * This union represents the bit fields in the Device IN EP Interrupt
41350 + * Register and the Device IN EP Common Mask Register.
41352 + * - Read the register into the <i>d32</i> member then set/clear the
41353 + * bits using the <i>b</i>it elements.
41355 +typedef union diepint_data {
41356 + /** raw register data */
41358 + /** register bits */
41360 + /** Transfer complete mask */
41361 + unsigned xfercompl:1;
41362 + /** Endpoint disable mask */
41363 + unsigned epdisabled:1;
41364 + /** AHB Error mask */
41365 + unsigned ahberr:1;
41366 + /** TimeOUT Handshake mask (non-ISOC EPs) */
41367 + unsigned timeout:1;
41368 + /** IN Token received with TxF Empty mask */
41369 + unsigned intktxfemp:1;
41370 + /** IN Token Received with EP mismatch mask */
41371 + unsigned intknepmis:1;
41372 + /** IN Endpoint HAK Effective mask */
41373 + unsigned inepnakeff:1;
41374 + /** IN Endpoint HAK Effective mask */
41375 + unsigned emptyintr:1;
41377 + unsigned txfifoundrn:1;
41379 + /** BNA Interrupt mask */
41382 + unsigned reserved10_12:3;
41383 + /** BNA Interrupt mask */
41386 + unsigned reserved14_31:18;
41391 + * This union represents the bit fields in the Device IN EP
41392 + * Common/Dedicated Interrupt Mask Register.
41394 +typedef union diepint_data diepmsk_data_t;
41397 + * This union represents the bit fields in the Device OUT EP Interrupt
41398 + * Registerand Device OUT EP Common Interrupt Mask Register.
41400 + * - Read the register into the <i>d32</i> member then set/clear the
41401 + * bits using the <i>b</i>it elements.
41403 +typedef union doepint_data {
41404 + /** raw register data */
41406 + /** register bits */
41408 + /** Transfer complete */
41409 + unsigned xfercompl:1;
41410 + /** Endpoint disable */
41411 + unsigned epdisabled:1;
41413 + unsigned ahberr:1;
41414 + /** Setup Phase Done (contorl EPs) */
41415 + unsigned setup:1;
41416 + /** OUT Token Received when Endpoint Disabled */
41417 + unsigned outtknepdis:1;
41419 + unsigned stsphsercvd:1;
41420 + /** Back-to-Back SETUP Packets Received */
41421 + unsigned back2backsetup:1;
41423 + unsigned reserved7:1;
41424 + /** OUT packet Error */
41425 + unsigned outpkterr:1;
41426 + /** BNA Interrupt */
41429 + unsigned reserved10:1;
41430 + /** Packet Drop Status */
41431 + unsigned pktdrpsts:1;
41432 + /** Babble Interrupt */
41433 + unsigned babble:1;
41434 + /** NAK Interrupt */
41436 + /** NYET Interrupt */
41439 + unsigned reserved15_31:17;
41444 + * This union represents the bit fields in the Device OUT EP
41445 + * Common/Dedicated Interrupt Mask Register.
41447 +typedef union doepint_data doepmsk_data_t;
41450 + * This union represents the bit fields in the Device All EP Interrupt
41451 + * and Mask Registers.
41452 + * - Read the register into the <i>d32</i> member then set/clear the
41453 + * bits using the <i>b</i>it elements.
41455 +typedef union daint_data {
41456 + /** raw register data */
41458 + /** register bits */
41460 + /** IN Endpoint bits */
41462 + /** OUT Endpoint bits */
41466 + /** IN Endpoint bits */
41467 + unsigned inep0:1;
41468 + unsigned inep1:1;
41469 + unsigned inep2:1;
41470 + unsigned inep3:1;
41471 + unsigned inep4:1;
41472 + unsigned inep5:1;
41473 + unsigned inep6:1;
41474 + unsigned inep7:1;
41475 + unsigned inep8:1;
41476 + unsigned inep9:1;
41477 + unsigned inep10:1;
41478 + unsigned inep11:1;
41479 + unsigned inep12:1;
41480 + unsigned inep13:1;
41481 + unsigned inep14:1;
41482 + unsigned inep15:1;
41483 + /** OUT Endpoint bits */
41484 + unsigned outep0:1;
41485 + unsigned outep1:1;
41486 + unsigned outep2:1;
41487 + unsigned outep3:1;
41488 + unsigned outep4:1;
41489 + unsigned outep5:1;
41490 + unsigned outep6:1;
41491 + unsigned outep7:1;
41492 + unsigned outep8:1;
41493 + unsigned outep9:1;
41494 + unsigned outep10:1;
41495 + unsigned outep11:1;
41496 + unsigned outep12:1;
41497 + unsigned outep13:1;
41498 + unsigned outep14:1;
41499 + unsigned outep15:1;
41504 + * This union represents the bit fields in the Device IN Token Queue
41505 + * Read Registers.
41506 + * - Read the register into the <i>d32</i> member.
41507 + * - READ-ONLY Register
41509 +typedef union dtknq1_data {
41510 + /** raw register data */
41512 + /** register bits */
41514 + /** In Token Queue Write Pointer */
41515 + unsigned intknwptr:5;
41517 + unsigned reserved05_06:2;
41518 + /** write pointer has wrapped. */
41519 + unsigned wrap_bit:1;
41520 + /** EP Numbers of IN Tokens 0 ... 4 */
41521 + unsigned epnums0_5:24;
41526 + * This union represents Threshold control Register
41527 + * - Read and write the register into the <i>d32</i> member.
41528 + * - READ-WRITABLE Register
41530 +typedef union dthrctl_data {
41531 + /** raw register data */
41533 + /** register bits */
41535 + /** non ISO Tx Thr. Enable */
41536 + unsigned non_iso_thr_en:1;
41537 + /** ISO Tx Thr. Enable */
41538 + unsigned iso_thr_en:1;
41539 + /** Tx Thr. Length */
41540 + unsigned tx_thr_len:9;
41541 + /** AHB Threshold ratio */
41542 + unsigned ahb_thr_ratio:2;
41544 + unsigned reserved13_15:3;
41545 + /** Rx Thr. Enable */
41546 + unsigned rx_thr_en:1;
41547 + /** Rx Thr. Length */
41548 + unsigned rx_thr_len:9;
41550 + unsigned reserved26_31:6;
41555 + * Device Logical IN Endpoint-Specific Registers. <i>Offsets
41558 + * There will be one set of endpoint registers per logical endpoint
41561 + * <i>These registers are visible only in Device mode and must not be
41562 + * accessed in Host mode, as the results are unknown.</i>
41564 +typedef struct dwc_otg_dev_in_ep_regs {
41565 + /** Device IN Endpoint Control Register. <i>Offset:900h +
41566 + * (ep_num * 20h) + 00h</i> */
41567 + volatile uint32_t diepctl;
41568 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */
41569 + uint32_t reserved04;
41570 + /** Device IN Endpoint Interrupt Register. <i>Offset:900h +
41571 + * (ep_num * 20h) + 08h</i> */
41572 + volatile uint32_t diepint;
41573 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */
41574 + uint32_t reserved0C;
41575 + /** Device IN Endpoint Transfer Size
41576 + * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */
41577 + volatile uint32_t dieptsiz;
41578 + /** Device IN Endpoint DMA Address Register. <i>Offset:900h +
41579 + * (ep_num * 20h) + 14h</i> */
41580 + volatile uint32_t diepdma;
41581 + /** Device IN Endpoint Transmit FIFO Status Register. <i>Offset:900h +
41582 + * (ep_num * 20h) + 18h</i> */
41583 + volatile uint32_t dtxfsts;
41584 + /** Device IN Endpoint DMA Buffer Register. <i>Offset:900h +
41585 + * (ep_num * 20h) + 1Ch</i> */
41586 + volatile uint32_t diepdmab;
41587 +} dwc_otg_dev_in_ep_regs_t;
41590 + * Device Logical OUT Endpoint-Specific Registers. <i>Offsets:
41593 + * There will be one set of endpoint registers per logical endpoint
41596 + * <i>These registers are visible only in Device mode and must not be
41597 + * accessed in Host mode, as the results are unknown.</i>
41599 +typedef struct dwc_otg_dev_out_ep_regs {
41600 + /** Device OUT Endpoint Control Register. <i>Offset:B00h +
41601 + * (ep_num * 20h) + 00h</i> */
41602 + volatile uint32_t doepctl;
41603 + /** Device OUT Endpoint Frame number Register. <i>Offset:
41604 + * B00h + (ep_num * 20h) + 04h</i> */
41605 + volatile uint32_t doepfn;
41606 + /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h +
41607 + * (ep_num * 20h) + 08h</i> */
41608 + volatile uint32_t doepint;
41609 + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */
41610 + uint32_t reserved0C;
41611 + /** Device OUT Endpoint Transfer Size Register. <i>Offset:
41612 + * B00h + (ep_num * 20h) + 10h</i> */
41613 + volatile uint32_t doeptsiz;
41614 + /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h
41615 + * + (ep_num * 20h) + 14h</i> */
41616 + volatile uint32_t doepdma;
41617 + /** Reserved. <i>Offset:B00h + * (ep_num * 20h) + 18h</i> */
41619 + /** Device OUT Endpoint DMA Buffer Register. <i>Offset:B00h
41620 + * + (ep_num * 20h) + 1Ch</i> */
41621 + uint32_t doepdmab;
41622 +} dwc_otg_dev_out_ep_regs_t;
41625 + * This union represents the bit fields in the Device EP Control
41626 + * Register. Read the register into the <i>d32</i> member then
41627 + * set/clear the bits using the <i>b</i>it elements.
41629 +typedef union depctl_data {
41630 + /** raw register data */
41632 + /** register bits */
41634 + /** Maximum Packet Size
41636 + * IN/OUT EP0 - 2 bits
41637 + * 2'b00: 64 Bytes
41642 +#define DWC_DEP0CTL_MPS_64 0
41643 +#define DWC_DEP0CTL_MPS_32 1
41644 +#define DWC_DEP0CTL_MPS_16 2
41645 +#define DWC_DEP0CTL_MPS_8 3
41647 + /** Next Endpoint
41649 + * OUT EPn/OUT EP0 - reserved */
41650 + unsigned nextep:4;
41652 + /** USB Active Endpoint */
41653 + unsigned usbactep:1;
41655 + /** Endpoint DPID (INTR/Bulk IN and OUT endpoints)
41656 + * This field contains the PID of the packet going to
41657 + * be received or transmitted on this endpoint. The
41658 + * application should program the PID of the first
41659 + * packet going to be received or transmitted on this
41660 + * endpoint , after the endpoint is
41661 + * activated. Application use the SetD1PID and
41662 + * SetD0PID fields of this register to program either
41665 + * The encoding for this field is
41671 + /** NAK Status */
41672 + unsigned naksts:1;
41674 + /** Endpoint Type
41676 + * 2'b01: Isochronous
41678 + * 2'b11: Interrupt */
41679 + unsigned eptype:2;
41682 + * OUT EPn/OUT EP0
41683 + * IN EPn/IN EP0 - reserved */
41686 + /** Stall Handshake */
41687 + unsigned stall:1;
41689 + /** Tx Fifo Number
41691 + * OUT EPn/OUT EP0 - reserved */
41692 + unsigned txfnum:4;
41698 + /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints)
41699 + * Writing to this field sets the Endpoint DPID (DPID)
41700 + * field in this register to DATA0. Set Even
41701 + * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints)
41702 + * Writing to this field sets the Even/Odd
41703 + * (micro)frame (EO_FrNum) field to even (micro)
41706 + unsigned setd0pid:1;
41707 + /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints)
41708 + * Writing to this field sets the Endpoint DPID (DPID)
41709 + * field in this register to DATA1 Set Odd
41710 + * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints)
41711 + * Writing to this field sets the Even/Odd
41712 + * (micro)frame (EO_FrNum) field to odd (micro) frame.
41714 + unsigned setd1pid:1;
41716 + /** Endpoint Disable */
41717 + unsigned epdis:1;
41718 + /** Endpoint Enable */
41719 + unsigned epena:1;
41724 + * This union represents the bit fields in the Device EP Transfer
41725 + * Size Register. Read the register into the <i>d32</i> member then
41726 + * set/clear the bits using the <i>b</i>it elements.
41728 +typedef union deptsiz_data {
41729 + /** raw register data */
41731 + /** register bits */
41733 + /** Transfer size */
41734 + unsigned xfersize:19;
41735 + /** Packet Count */
41736 + unsigned pktcnt:10;
41737 + /** Multi Count - Periodic IN endpoints */
41739 + unsigned reserved:1;
41744 + * This union represents the bit fields in the Device EP 0 Transfer
41745 + * Size Register. Read the register into the <i>d32</i> member then
41746 + * set/clear the bits using the <i>b</i>it elements.
41748 +typedef union deptsiz0_data {
41749 + /** raw register data */
41751 + /** register bits */
41753 + /** Transfer size */
41754 + unsigned xfersize:7;
41756 + unsigned reserved7_18:12;
41757 + /** Packet Count */
41758 + unsigned pktcnt:1;
41760 + unsigned reserved20_28:9;
41761 + /**Setup Packet Count (DOEPTSIZ0 Only) */
41762 + unsigned supcnt:2;
41763 + unsigned reserved31;
41765 +} deptsiz0_data_t;
41767 +/////////////////////////////////////////////////
41768 +// DMA Descriptor Specific Structures
41771 +/** Buffer status definitions */
41773 +#define BS_HOST_READY 0x0
41774 +#define BS_DMA_BUSY 0x1
41775 +#define BS_DMA_DONE 0x2
41776 +#define BS_HOST_BUSY 0x3
41778 +/** Receive/Transmit status definitions */
41780 +#define RTS_SUCCESS 0x0
41781 +#define RTS_BUFFLUSH 0x1
41782 +#define RTS_RESERVED 0x2
41783 +#define RTS_BUFERR 0x3
41786 + * This union represents the bit fields in the DMA Descriptor
41787 + * status quadlet. Read the quadlet into the <i>d32</i> member then
41788 + * set/clear the bits using the <i>b</i>it, <i>b_iso_out</i> and
41789 + * <i>b_iso_in</i> elements.
41791 +typedef union dev_dma_desc_sts {
41792 + /** raw register data */
41794 + /** quadlet bits */
41796 + /** Received number of bytes */
41797 + unsigned bytes:16;
41799 + unsigned reserved16_22:7;
41800 + /** Multiple Transfer - only for OUT EPs */
41802 + /** Setup Packet received - only for OUT EPs */
41804 + /** Interrupt On Complete */
41806 + /** Short Packet */
41810 + /** Receive Status */
41812 + /** Buffer Status */
41816 +#ifdef DWC_EN_ISOC
41817 + /** iso out quadlet bits */
41819 + /** Received number of bytes */
41820 + unsigned rxbytes:11;
41822 + unsigned reserved11:1;
41823 + /** Frame Number */
41824 + unsigned framenum:11;
41825 + /** Received ISO Data PID */
41827 + /** Interrupt On Complete */
41829 + /** Short Packet */
41833 + /** Receive Status */
41834 + unsigned rxsts:2;
41835 + /** Buffer Status */
41839 + /** iso in quadlet bits */
41841 + /** Transmited number of bytes */
41842 + unsigned txbytes:12;
41843 + /** Frame Number */
41844 + unsigned framenum:11;
41845 + /** Transmited ISO Data PID */
41847 + /** Interrupt On Complete */
41849 + /** Short Packet */
41853 + /** Transmit Status */
41854 + unsigned txsts:2;
41855 + /** Buffer Status */
41858 +#endif /* DWC_EN_ISOC */
41859 +} dev_dma_desc_sts_t;
41862 + * DMA Descriptor structure
41864 + * DMA Descriptor structure contains two quadlets:
41865 + * Status quadlet and Data buffer pointer.
41867 +typedef struct dwc_otg_dev_dma_desc {
41868 + /** DMA Descriptor status quadlet */
41869 + dev_dma_desc_sts_t status;
41870 + /** DMA Descriptor data buffer pointer */
41872 +} dwc_otg_dev_dma_desc_t;
41875 + * The dwc_otg_dev_if structure contains information needed to manage
41876 + * the DWC_otg controller acting in device mode. It represents the
41877 + * programming view of the device-specific aspects of the controller.
41879 +typedef struct dwc_otg_dev_if {
41880 + /** Pointer to device Global registers.
41881 + * Device Global Registers starting at offset 800h
41883 + dwc_otg_device_global_regs_t *dev_global_regs;
41884 +#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
41887 + * Device Logical IN Endpoint-Specific Registers 900h-AFCh
41889 + dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS];
41890 +#define DWC_DEV_IN_EP_REG_OFFSET 0x900
41891 +#define DWC_EP_REG_OFFSET 0x20
41893 + /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
41894 + dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];
41895 +#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
41897 + /* Device configuration information */
41898 + uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */
41899 + uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */
41900 + uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/
41902 + /** Size of periodic FIFOs (Bytes) */
41903 + uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS];
41905 + /** Size of Tx FIFOs (Bytes) */
41906 + uint16_t tx_fifo_size[MAX_TX_FIFOS];
41908 + /** Thresholding enable flags and length varaiables **/
41909 + uint16_t rx_thr_en;
41910 + uint16_t iso_tx_thr_en;
41911 + uint16_t non_iso_tx_thr_en;
41913 + uint16_t rx_thr_length;
41914 + uint16_t tx_thr_length;
41917 + * Pointers to the DMA Descriptors for EP0 Control
41918 + * transfers (virtual and physical)
41921 + /** 2 descriptors for SETUP packets */
41922 + dwc_dma_t dma_setup_desc_addr[2];
41923 + dwc_otg_dev_dma_desc_t *setup_desc_addr[2];
41925 + /** Pointer to Descriptor with latest SETUP packet */
41926 + dwc_otg_dev_dma_desc_t *psetup;
41928 + /** Index of current SETUP handler descriptor */
41929 + uint32_t setup_desc_index;
41931 + /** Descriptor for Data In or Status In phases */
41932 + dwc_dma_t dma_in_desc_addr;
41933 + dwc_otg_dev_dma_desc_t *in_desc_addr;
41935 + /** Descriptor for Data Out or Status Out phases */
41936 + dwc_dma_t dma_out_desc_addr;
41937 + dwc_otg_dev_dma_desc_t *out_desc_addr;
41939 + /** Setup Packet Detected - if set clear NAK when queueing */
41942 +} dwc_otg_dev_if_t;
41944 +/////////////////////////////////////////////////
41945 +// Host Mode Register Structures
41948 + * The Host Global Registers structure defines the size and relative
41949 + * field offsets for the Host Mode Global Registers. Host Global
41950 + * Registers offsets 400h-7FFh.
41952 +typedef struct dwc_otg_host_global_regs {
41953 + /** Host Configuration Register. <i>Offset: 400h</i> */
41954 + volatile uint32_t hcfg;
41955 + /** Host Frame Interval Register. <i>Offset: 404h</i> */
41956 + volatile uint32_t hfir;
41957 + /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */
41958 + volatile uint32_t hfnum;
41959 + /** Reserved. <i>Offset: 40Ch</i> */
41960 + uint32_t reserved40C;
41961 + /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */
41962 + volatile uint32_t hptxsts;
41963 + /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */
41964 + volatile uint32_t haint;
41965 + /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */
41966 + volatile uint32_t haintmsk;
41967 + /** Host Frame List Base Address Register . <i>Offset: 41Ch</i> */
41968 + volatile uint32_t hflbaddr;
41969 +} dwc_otg_host_global_regs_t;
41973 + * This union represents the bit fields in the Host Configuration Register.
41974 + * Read the register into the <i>d32</i> member then set/clear the bits using
41975 + * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register.
41977 +typedef union hcfg_data
41979 + /** raw register data */
41982 + /** register bits */
41985 + /** FS/LS Phy Clock Select */
41986 + unsigned fslspclksel:2;
41987 +#define DWC_HCFG_30_60_MHZ 0
41988 +#define DWC_HCFG_48_MHZ 1
41989 +#define DWC_HCFG_6_MHZ 2
41991 + /** FS/LS Only Support */
41992 + unsigned fslssupp:1;
41993 + unsigned reserved3_22 : 20;
41994 + /** Enable Scatter/gather DMA in Host mode */
41995 + unsigned descdma : 1;
41996 + /** Frame List Entries */
41997 + unsigned frlisten: 2;
41998 + /** Enable Periodic Scheduling */
41999 + unsigned perschedena: 1;
42000 + /** Periodic Scheduling Enabled Status */
42001 + unsigned perschedstat: 1;
42006 + * This union represents the bit fields in the Host Frame Remaing/Number
42009 +typedef union hfir_data {
42010 + /** raw register data */
42013 + /** register bits */
42015 + unsigned frint:16;
42016 + unsigned reserved:16;
42021 + * This union represents the bit fields in the Host Frame Remaing/Number
42024 +typedef union hfnum_data {
42025 + /** raw register data */
42028 + /** register bits */
42030 + unsigned frnum:16;
42031 +#define DWC_HFNUM_MAX_FRNUM 0x3FFF
42032 + unsigned frrem:16;
42036 +typedef union hptxsts_data {
42037 + /** raw register data */
42040 + /** register bits */
42042 + unsigned ptxfspcavail:16;
42043 + unsigned ptxqspcavail:8;
42044 + /** Top of the Periodic Transmit Request Queue
42045 + * - bit 24 - Terminate (last entry for the selected channel)
42046 + * - bits 26:25 - Token Type
42047 + * - 2'b00 - Zero length
42049 + * - 2'b10 - Disable
42050 + * - bits 30:27 - Channel Number
42051 + * - bit 31 - Odd/even microframe
42053 + unsigned ptxqtop_terminate:1;
42054 + unsigned ptxqtop_token:2;
42055 + unsigned ptxqtop_chnum:4;
42056 + unsigned ptxqtop_odd:1;
42061 + * This union represents the bit fields in the Host Port Control and Status
42062 + * Register. Read the register into the <i>d32</i> member then set/clear the
42063 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
42064 + * hprt0 register.
42066 +typedef union hprt0_data {
42067 + /** raw register data */
42069 + /** register bits */
42071 + unsigned prtconnsts:1;
42072 + unsigned prtconndet:1;
42073 + unsigned prtena:1;
42074 + unsigned prtenchng:1;
42075 + unsigned prtovrcurract:1;
42076 + unsigned prtovrcurrchng:1;
42077 + unsigned prtres:1;
42078 + unsigned prtsusp:1;
42079 + unsigned prtrst:1;
42080 + unsigned reserved9:1;
42081 + unsigned prtlnsts:2;
42082 + unsigned prtpwr:1;
42083 + unsigned prttstctl:4;
42084 + unsigned prtspd:2;
42085 +#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
42086 +#define DWC_HPRT0_PRTSPD_FULL_SPEED 1
42087 +#define DWC_HPRT0_PRTSPD_LOW_SPEED 2
42088 + unsigned reserved19_31:13;
42093 + * This union represents the bit fields in the Host All Interrupt
42096 +typedef union haint_data {
42097 + /** raw register data */
42099 + /** register bits */
42117 + unsigned reserved:16;
42121 + unsigned chint:16;
42122 + unsigned reserved:16;
42127 + * This union represents the bit fields in the Host All Interrupt
42130 +typedef union haintmsk_data {
42131 + /** raw register data */
42133 + /** register bits */
42151 + unsigned reserved:16;
42155 + unsigned chint:16;
42156 + unsigned reserved:16;
42158 +} haintmsk_data_t;
42161 + * Host Channel Specific Registers. <i>500h-5FCh</i>
42163 +typedef struct dwc_otg_hc_regs
42165 + /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */
42166 + volatile uint32_t hcchar;
42167 + /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */
42168 + volatile uint32_t hcsplt;
42169 + /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */
42170 + volatile uint32_t hcint;
42171 + /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */
42172 + volatile uint32_t hcintmsk;
42173 + /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */
42174 + volatile uint32_t hctsiz;
42175 + /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */
42176 + volatile uint32_t hcdma;
42177 + volatile uint32_t reserved;
42178 + /** Host Channel 0 DMA Buffer Address Register. <i>Offset: 500h + (chan_num * 20h) + 1Ch</i> */
42179 + volatile uint32_t hcdmab;
42180 +} dwc_otg_hc_regs_t;
42183 + * This union represents the bit fields in the Host Channel Characteristics
42184 + * Register. Read the register into the <i>d32</i> member then set/clear the
42185 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
42186 + * hcchar register.
42188 +typedef union hcchar_data {
42189 + /** raw register data */
42192 + /** register bits */
42194 + /** Maximum packet size in bytes */
42197 + /** Endpoint number */
42198 + unsigned epnum:4;
42200 + /** 0: OUT, 1: IN */
42201 + unsigned epdir:1;
42203 + unsigned reserved:1;
42205 + /** 0: Full/high speed device, 1: Low speed device */
42206 + unsigned lspddev:1;
42208 + /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
42209 + unsigned eptype:2;
42211 + /** Packets per frame for periodic transfers. 0 is reserved. */
42212 + unsigned multicnt:2;
42214 + /** Device address */
42215 + unsigned devaddr:7;
42218 + * Frame to transmit periodic transaction.
42219 + * 0: even, 1: odd
42221 + unsigned oddfrm:1;
42223 + /** Channel disable */
42224 + unsigned chdis:1;
42226 + /** Channel enable */
42231 +typedef union hcsplt_data {
42232 + /** raw register data */
42235 + /** register bits */
42237 + /** Port Address */
42238 + unsigned prtaddr:7;
42240 + /** Hub Address */
42241 + unsigned hubaddr:7;
42243 + /** Transaction Position */
42244 + unsigned xactpos:2;
42245 +#define DWC_HCSPLIT_XACTPOS_MID 0
42246 +#define DWC_HCSPLIT_XACTPOS_END 1
42247 +#define DWC_HCSPLIT_XACTPOS_BEGIN 2
42248 +#define DWC_HCSPLIT_XACTPOS_ALL 3
42250 + /** Do Complete Split */
42251 + unsigned compsplt:1;
42254 + unsigned reserved:14;
42256 + /** Split Enble */
42257 + unsigned spltena:1;
42262 + * This union represents the bit fields in the Host All Interrupt
42265 +typedef union hcint_data
42267 + /** raw register data */
42269 + /** register bits */
42272 + /** Transfer Complete */
42273 + unsigned xfercomp:1;
42274 + /** Channel Halted */
42275 + unsigned chhltd:1;
42277 + unsigned ahberr:1;
42278 + /** STALL Response Received */
42279 + unsigned stall:1;
42280 + /** NAK Response Received */
42282 + /** ACK Response Received */
42284 + /** NYET Response Received */
42286 + /** Transaction Err */
42287 + unsigned xacterr:1;
42288 + /** Babble Error */
42289 + unsigned bblerr:1;
42290 + /** Frame Overrun */
42291 + unsigned frmovrun:1;
42292 + /** Data Toggle Error */
42293 + unsigned datatglerr:1;
42294 + /** Buffer Not Available (only for DDMA mode) */
42295 + unsigned bna : 1;
42296 + /** Exessive transaction error (only for DDMA mode) */
42297 + unsigned xcs_xact : 1;
42298 + /** Frame List Rollover interrupt */
42299 + unsigned frm_list_roll : 1;
42301 + unsigned reserved14_31 : 18;
42306 + * This union represents the bit fields in the Host Channel Interrupt Mask
42307 + * Register. Read the register into the <i>d32</i> member then set/clear the
42308 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
42309 + * hcintmsk register.
42311 +typedef union hcintmsk_data
42313 + /** raw register data */
42316 + /** register bits */
42319 + unsigned xfercompl : 1;
42320 + unsigned chhltd : 1;
42321 + unsigned ahberr : 1;
42322 + unsigned stall : 1;
42323 + unsigned nak : 1;
42324 + unsigned ack : 1;
42325 + unsigned nyet : 1;
42326 + unsigned xacterr : 1;
42327 + unsigned bblerr : 1;
42328 + unsigned frmovrun : 1;
42329 + unsigned datatglerr : 1;
42330 + unsigned bna : 1;
42331 + unsigned xcs_xact : 1;
42332 + unsigned frm_list_roll : 1;
42333 + unsigned reserved14_31 : 18;
42335 +} hcintmsk_data_t;
42338 + * This union represents the bit fields in the Host Channel Transfer Size
42339 + * Register. Read the register into the <i>d32</i> member then set/clear the
42340 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
42341 + * hcchar register.
42344 +typedef union hctsiz_data
42346 + /** raw register data */
42349 + /** register bits */
42352 + /** Total transfer size in bytes */
42353 + unsigned xfersize:19;
42355 + /** Data packets to transfer */
42356 + unsigned pktcnt:10;
42359 + * Packet ID for next data packet
42363 + * 3: MDATA (non-Control), SETUP (Control)
42366 +#define DWC_HCTSIZ_DATA0 0
42367 +#define DWC_HCTSIZ_DATA1 2
42368 +#define DWC_HCTSIZ_DATA2 1
42369 +#define DWC_HCTSIZ_MDATA 3
42370 +#define DWC_HCTSIZ_SETUP 3
42372 + /** Do PING protocol when 1 */
42373 + unsigned dopng:1;
42376 + /** register bits */
42379 + /** Scheduling information */
42380 + unsigned schinfo : 8;
42382 + /** Number of transfer descriptors.
42385 + * 256 only for HS isochronous endpoint.
42387 + unsigned ntd : 8;
42389 + /** Data packets to transfer */
42390 + unsigned reserved16_28 : 13;
42393 + * Packet ID for next data packet
42397 + * 3: MDATA (non-Control)
42399 + unsigned pid : 2;
42401 + /** Do PING protocol when 1 */
42402 + unsigned dopng : 1;
42408 + * This union represents the bit fields in the Host DMA Address
42409 + * Register used in Descriptor DMA mode.
42411 +typedef union hcdma_data
42413 + /** raw register data */
42415 + /** register bits */
42418 + unsigned reserved0_2 : 3;
42419 + /** Current Transfer Descriptor. Not used for ISOC */
42420 + unsigned ctd : 8;
42421 + /** Start Address of Descriptor List */
42422 + unsigned dma_addr : 21;
42427 + * This union represents the bit fields in the DMA Descriptor
42428 + * status quadlet for host mode. Read the quadlet into the <i>d32</i> member then
42429 + * set/clear the bits using the <i>b</i>it elements.
42431 +typedef union host_dma_desc_sts
42433 + /** raw register data */
42435 + /** quadlet bits */
42437 + /* for non-isochronous */
42439 + /** Number of bytes */
42440 + unsigned n_bytes : 17;
42441 + /** QTD offset to jump when Short Packet received - only for IN EPs */
42442 + unsigned qtd_offset : 6;
42444 + * Set to request the core to jump to alternate QTD if
42445 + * Short Packet received - only for IN EPs
42447 + unsigned a_qtd : 1;
42449 + * Setup Packet bit. When set indicates that buffer contains
42452 + unsigned sup : 1;
42453 + /** Interrupt On Complete */
42454 + unsigned ioc : 1;
42455 + /** End of List */
42456 + unsigned eol : 1;
42457 + unsigned reserved27 : 1;
42458 + /** Rx/Tx Status */
42459 + unsigned sts : 2;
42460 + #define DMA_DESC_STS_PKTERR 1
42461 + unsigned reserved30 : 1;
42462 + /** Active Bit */
42465 + /* for isochronous */
42467 + /** Number of bytes */
42468 + unsigned n_bytes : 12;
42469 + unsigned reserved12_24 : 13;
42470 + /** Interrupt On Complete */
42471 + unsigned ioc : 1;
42472 + unsigned reserved26_27 : 2;
42473 + /** Rx/Tx Status */
42474 + unsigned sts : 2;
42475 + unsigned reserved30 : 1;
42476 + /** Active Bit */
42479 +} host_dma_desc_sts_t;
42481 +#define MAX_DMA_DESC_SIZE 131071
42482 +#define MAX_DMA_DESC_NUM_GENERIC 64
42483 +#define MAX_DMA_DESC_NUM_HS_ISOC 256
42484 +#define MAX_FRLIST_EN_NUM 64
42486 + * Host-mode DMA Descriptor structure
42488 + * DMA Descriptor structure contains two quadlets:
42489 + * Status quadlet and Data buffer pointer.
42491 +typedef struct dwc_otg_host_dma_desc
42493 + /** DMA Descriptor status quadlet */
42494 + host_dma_desc_sts_t status;
42495 + /** DMA Descriptor data buffer pointer */
42497 +} dwc_otg_host_dma_desc_t;
42499 +/** OTG Host Interface Structure.
42501 + * The OTG Host Interface Structure structure contains information
42502 + * needed to manage the DWC_otg controller acting in host mode. It
42503 + * represents the programming view of the host-specific aspects of the
42506 +typedef struct dwc_otg_host_if {
42507 + /** Host Global Registers starting at offset 400h.*/
42508 + dwc_otg_host_global_regs_t *host_global_regs;
42509 +#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
42511 + /** Host Port 0 Control and Status Register */
42512 + volatile uint32_t *hprt0;
42513 +#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
42515 + /** Host Channel Specific Registers at offsets 500h-5FCh. */
42516 + dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS];
42517 +#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
42518 +#define DWC_OTG_CHAN_REGS_OFFSET 0x20
42520 + /* Host configuration information */
42521 + /** Number of Host Channels (range: 1-16) */
42522 + uint8_t num_host_channels;
42523 + /** Periodic EPs supported (0: no, 1: yes) */
42524 + uint8_t perio_eps_supported;
42525 + /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */
42526 + uint16_t perio_tx_fifo_size;
42528 +} dwc_otg_host_if_t;
42531 + * This union represents the bit fields in the Power and Clock Gating Control
42532 + * Register. Read the register into the <i>d32</i> member then set/clear the
42533 + * bits using the <i>b</i>it elements.
42535 +typedef union pcgcctl_data {
42536 + /** raw register data */
42539 + /** register bits */
42542 + unsigned stoppclk:1;
42544 + unsigned gatehclk:1;
42545 + /** Power Clamp */
42546 + unsigned pwrclmp:1;
42547 + /** Reset Power Down Modules */
42548 + unsigned rstpdwnmodule:1;
42549 + /** PHY Suspended */
42550 + unsigned physuspended:1;
42551 + /** Enable Sleep Clock Gating (Enbl_L1Gating) */
42552 + unsigned enbl_sleep_gating:1;
42553 + /** PHY In Sleep (PhySleep) */
42554 + unsigned phy_in_sleep:1;
42556 + unsigned deep_sleep:1;
42558 + unsigned reserved31_8:24;
42564 +++ b/drivers/usb/host/dwc_otg/test/Makefile
42567 +PERL=/usr/bin/perl
42568 +PL_TESTS=test_sysfs.pl test_mod_param.pl
42575 + @echo Running perl tests
42576 + @for test in $(PL_TESTS); do \
42577 + if $(PERL) ./$$test ; then \
42578 + echo "=======> $$test, PASSED" ; \
42579 + else echo "=======> $$test, FAILED" ; \
42583 +++ b/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
42585 +package dwc_otg_test;
42590 +use vars qw(@ISA @EXPORT
42591 +$sysfsdir $paramdir $errors $params
42594 +@ISA = qw(Exporter);
42599 +$sysfsdir = "/sys/devices/lm0";
42600 +$paramdir = "/sys/module/dwc_otg";
42605 + NAME => "otg_cap",
42612 + NAME => "dma_enable",
42619 + NAME => "dma_burst_size",
42621 + ENUM => [1, 4, 8, 16, 32, 64, 128, 256],
42626 + NAME => "host_speed",
42633 + NAME => "host_support_fs_ls_low_power",
42640 + NAME => "host_ls_low_power_phy_clk",
42647 + NAME => "dev_speed",
42654 + NAME => "enable_dynamic_fifo",
42661 + NAME => "data_fifo_size",
42668 + NAME => "dev_rx_fifo_size",
42675 + NAME => "dev_nperio_tx_fifo_size",
42682 + NAME => "dev_perio_tx_fifo_size_1",
42689 + NAME => "dev_perio_tx_fifo_size_2",
42696 + NAME => "dev_perio_tx_fifo_size_3",
42703 + NAME => "dev_perio_tx_fifo_size_4",
42710 + NAME => "dev_perio_tx_fifo_size_5",
42717 + NAME => "dev_perio_tx_fifo_size_6",
42724 + NAME => "dev_perio_tx_fifo_size_7",
42731 + NAME => "dev_perio_tx_fifo_size_8",
42738 + NAME => "dev_perio_tx_fifo_size_9",
42745 + NAME => "dev_perio_tx_fifo_size_10",
42752 + NAME => "dev_perio_tx_fifo_size_11",
42759 + NAME => "dev_perio_tx_fifo_size_12",
42766 + NAME => "dev_perio_tx_fifo_size_13",
42773 + NAME => "dev_perio_tx_fifo_size_14",
42780 + NAME => "dev_perio_tx_fifo_size_15",
42787 + NAME => "host_rx_fifo_size",
42794 + NAME => "host_nperio_tx_fifo_size",
42801 + NAME => "host_perio_tx_fifo_size",
42808 + NAME => "max_transfer_size",
42809 + DEFAULT => 65535,
42815 + NAME => "max_packet_count",
42822 + NAME => "host_channels",
42829 + NAME => "dev_endpoints",
42836 + NAME => "phy_type",
42843 + NAME => "phy_utmi_width",
42850 + NAME => "phy_ulpi_ddr",
42864 + unless (m/armv4tl/) {
42865 + warn "# \n# Can't execute on $_. Run on integrator platform.\n# \n";
42874 + my $params = shift;
42875 + print "\nRemoving Module\n";
42876 + system "rmmod dwc_otg";
42877 + print "Loading Module\n";
42878 + if ($params ne "") {
42879 + print "Module Parameters: $params\n";
42881 + if (system("modprobe dwc_otg $params")) {
42882 + warn "Unable to load module\n";
42895 + if (defined $arg) {
42896 + warn "WARNING: $arg\n";
42899 + if ($errors > 0) {
42900 + warn "TEST FAILED with $errors errors\n";
42903 + print "TEST PASSED\n";
42904 + return 0 if (defined $arg);
42923 +++ b/drivers/usb/host/dwc_otg/test/test_mod_param.pl
42925 +#!/usr/bin/perl -w
42927 +# Run this program on the integrator.
42929 +# - Tests module parameter default values.
42930 +# - Tests setting of valid module parameter values via modprobe.
42931 +# - Tests invalid module parameter values.
42932 +# -----------------------------------------------------------------------------
42936 +check_arch() or die;
42941 + my ($param,$expected) = @_;
42942 + my $value = get($param);
42944 + if ($value == $expected) {
42945 + print "$param = $value, okay\n";
42949 + warn "ERROR: value of $param != $expected, $value\n";
42957 + my $param = shift;
42958 + my $tmp = `cat $paramdir/$param`;
42967 + print "\nTesting Module Parameters\n";
42969 + load_module("") or die;
42971 + # Test initial values
42972 + print "\nTesting Default Values\n";
42973 + foreach (@{$params}) {
42974 + test ($_->{NAME}, $_->{DEFAULT});
42978 + print "\nTesting Low Value\n";
42979 + my $cmd_params = "";
42980 + foreach (@{$params}) {
42981 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{LOW} ";
42983 + load_module($cmd_params) or die;
42985 + foreach (@{$params}) {
42986 + test ($_->{NAME}, $_->{LOW});
42989 + # Test high value
42990 + print "\nTesting High Value\n";
42991 + $cmd_params = "";
42992 + foreach (@{$params}) {
42993 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{HIGH} ";
42995 + load_module($cmd_params) or die;
42997 + foreach (@{$params}) {
42998 + test ($_->{NAME}, $_->{HIGH});
43002 + print "\nTesting Enumerated\n";
43003 + foreach (@{$params}) {
43004 + if (defined $_->{ENUM}) {
43006 + foreach $value (@{$_->{ENUM}}) {
43007 + $cmd_params = "$_->{NAME}=$value";
43008 + load_module($cmd_params) or die;
43009 + test ($_->{NAME}, $value);
43014 + # Test Invalid Values
43015 + print "\nTesting Invalid Values\n";
43016 + $cmd_params = "";
43017 + foreach (@{$params}) {
43018 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{LOW}-1;
43020 + load_module($cmd_params) or die;
43022 + foreach (@{$params}) {
43023 + test ($_->{NAME}, $_->{DEFAULT});
43026 + $cmd_params = "";
43027 + foreach (@{$params}) {
43028 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{HIGH}+1;
43030 + load_module($cmd_params) or die;
43032 + foreach (@{$params}) {
43033 + test ($_->{NAME}, $_->{DEFAULT});
43036 + print "\nTesting Enumerated\n";
43037 + foreach (@{$params}) {
43038 + if (defined $_->{ENUM}) {
43040 + foreach $value (@{$_->{ENUM}}) {
43041 + $value = $value + 1;
43042 + $cmd_params = "$_->{NAME}=$value";
43043 + load_module($cmd_params) or die;
43044 + test ($_->{NAME}, $_->{DEFAULT});
43045 + $value = $value - 2;
43046 + $cmd_params = "$_->{NAME}=$value";
43047 + load_module($cmd_params) or die;
43048 + test ($_->{NAME}, $_->{DEFAULT});
43053 + test_status() or die;
43059 +++ b/drivers/usb/host/dwc_otg/test/test_sysfs.pl
43061 +#!/usr/bin/perl -w
43063 +# Run this program on the integrator
43064 +# - Tests select sysfs attributes.
43065 +# - Todo ... test more attributes, hnp/srp, buspower/bussuspend, etc.
43066 +# -----------------------------------------------------------------------------
43070 +check_arch() or die;
43075 + my ($attr,$expected) = @_;
43076 + my $string = get($attr);
43078 + if ($string eq $expected) {
43079 + printf("$attr = $string, okay\n");
43082 + warn "ERROR: value of $attr != $expected, $string\n";
43090 + my ($reg, $value) = @_;
43091 + system "echo $value > $sysfsdir/$reg";
43097 + my $attr = shift;
43098 + my $string = `cat $sysfsdir/$attr`;
43100 + if ($string =~ m/\s\=\s/) {
43102 + ($tmp, $string) = split /\s=\s/, $string;
43110 + print("\nTesting Sysfs Attributes\n");
43112 + load_module("") or die;
43114 + # Test initial values of regoffset/regvalue/guid/gsnpsid
43115 + print("\nTesting Default Values\n");
43117 + test("regoffset", "0xffffffff");
43118 + test("regvalue", "invalid offset");
43119 + test("guid", "0x12345678"); # this will fail if it has been changed
43120 + test("gsnpsid", "0x4f54200a");
43122 + # Test operation of regoffset/regvalue
43123 + print("\nTesting regoffset\n");
43124 + set('regoffset', '5a5a5a5a');
43125 + test("regoffset", "0xffffffff");
43127 + set('regoffset', '0');
43128 + test("regoffset", "0x00000000");
43130 + set('regoffset', '40000');
43131 + test("regoffset", "0x00000000");
43133 + set('regoffset', '3ffff');
43134 + test("regoffset", "0x0003ffff");
43136 + set('regoffset', '1');
43137 + test("regoffset", "0x00000001");
43139 + print("\nTesting regvalue\n");
43140 + set('regoffset', '3c');
43141 + test("regvalue", "0x12345678");
43142 + set('regvalue', '5a5a5a5a');
43143 + test("regvalue", "0x5a5a5a5a");
43144 + set('regvalue','a5a5a5a5');
43145 + test("regvalue", "0xa5a5a5a5");
43146 + set('guid','12345678');
43148 + # Test HNP Capable
43149 + print("\nTesting HNP Capable bit\n");
43150 + set('hnpcapable', '1');
43151 + test("hnpcapable", "0x1");
43152 + set('hnpcapable','0');
43153 + test("hnpcapable", "0x0");
43155 + set('regoffset','0c');
43157 + my $old = get('gusbcfg');
43158 + print("setting hnpcapable\n");
43159 + set('hnpcapable', '1');
43160 + test("hnpcapable", "0x1");
43161 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<9)));
43162 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<9)));
43164 + $old = get('gusbcfg');
43165 + print("clearing hnpcapable\n");
43166 + set('hnpcapable', '0');
43167 + test("hnpcapable", "0x0");
43168 + test ('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<9)));
43169 + test ('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<9)));
43171 + # Test SRP Capable
43172 + print("\nTesting SRP Capable bit\n");
43173 + set('srpcapable', '1');
43174 + test("srpcapable", "0x1");
43175 + set('srpcapable','0');
43176 + test("srpcapable", "0x0");
43178 + set('regoffset','0c');
43180 + $old = get('gusbcfg');
43181 + print("setting srpcapable\n");
43182 + set('srpcapable', '1');
43183 + test("srpcapable", "0x1");
43184 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<8)));
43185 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<8)));
43187 + $old = get('gusbcfg');
43188 + print("clearing srpcapable\n");
43189 + set('srpcapable', '0');
43190 + test("srpcapable", "0x0");
43191 + test('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<8)));
43192 + test('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<8)));
43195 + print("\nTesting GGPIO\n");
43196 + set('ggpio','5a5a5a5a');
43197 + test('ggpio','0x5a5a0000');
43198 + set('ggpio','a5a5a5a5');
43199 + test('ggpio','0xa5a50000');
43200 + set('ggpio','11110000');
43201 + test('ggpio','0x11110000');
43202 + set('ggpio','00001111');
43203 + test('ggpio','0x00000000');
43206 + print("\nTesting DEVSPEED\n");
43207 + set('regoffset','800');
43208 + $old = get('regvalue');
43209 + set('devspeed','0');
43210 + test('devspeed','0x0');
43211 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
43212 + set('devspeed','1');
43213 + test('devspeed','0x1');
43214 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
43215 + set('devspeed','2');
43216 + test('devspeed','0x2');
43217 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 2));
43218 + set('devspeed','3');
43219 + test('devspeed','0x3');
43220 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 3));
43221 + set('devspeed','4');
43222 + test('devspeed','0x0');
43223 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
43224 + set('devspeed','5');
43225 + test('devspeed','0x1');
43226 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
43229 + # mode Returns the current mode:0 for device mode1 for host mode Read
43230 + # hnp Initiate the Host Negotiation Protocol. Read returns the status. Read/Write
43231 + # srp Initiate the Session Request Protocol. Read returns the status. Read/Write
43232 + # buspower Get or Set the Power State of the bus (0 - Off or 1 - On) Read/Write
43233 + # bussuspend Suspend the USB bus. Read/Write
43234 + # busconnected Get the connection status of the bus Read
43236 + # gotgctl Get or set the Core Control Status Register. Read/Write
43237 + ## gusbcfg Get or set the Core USB Configuration Register Read/Write
43238 + # grxfsiz Get or set the Receive FIFO Size Register Read/Write
43239 + # gnptxfsiz Get or set the non-periodic Transmit Size Register Read/Write
43240 + # gpvndctl Get or set the PHY Vendor Control Register Read/Write
43241 + ## ggpio Get the value in the lower 16-bits of the General Purpose IO Register or Set the upper 16 bits. Read/Write
43242 + ## guid Get or set the value of the User ID Register Read/Write
43243 + ## gsnpsid Get the value of the Synopsys ID Regester Read
43244 + ## devspeed Get or set the device speed setting in the DCFG register Read/Write
43245 + # enumspeed Gets the device enumeration Speed. Read
43246 + # hptxfsiz Get the value of the Host Periodic Transmit FIFO Read
43247 + # hprt0 Get or Set the value in the Host Port Control and Status Register Read/Write
43249 + test_status("TEST NYI") or die;