brcm2708: update against latest rpi-3.10.y branch
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-3.10 / 0002-Add-dwc_otg-driver.patch
1 From ee24f1f0affd88d3e101a7e66c5ebfd8e582b868 Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Wed, 1 May 2013 19:46:17 +0100
4 Subject: [PATCH 002/174] Add dwc_otg driver
5
6 Signed-off-by: popcornmix <popcornmix@gmail.com>
7 ---
8 drivers/usb/Makefile | 1 +
9 drivers/usb/core/generic.c | 1 +
10 drivers/usb/core/message.c | 79 +
11 drivers/usb/core/otg_whitelist.h | 172 +-
12 drivers/usb/gadget/file_storage.c | 3676 ++++++++++
13 drivers/usb/host/Kconfig | 13 +
14 drivers/usb/host/Makefile | 2 +
15 drivers/usb/host/dwc_common_port/Makefile | 58 +
16 drivers/usb/host/dwc_common_port/Makefile.fbsd | 17 +
17 drivers/usb/host/dwc_common_port/Makefile.linux | 49 +
18 drivers/usb/host/dwc_common_port/changes.txt | 174 +
19 drivers/usb/host/dwc_common_port/doc/doxygen.cfg | 270 +
20 drivers/usb/host/dwc_common_port/dwc_cc.c | 532 ++
21 drivers/usb/host/dwc_common_port/dwc_cc.h | 225 +
22 drivers/usb/host/dwc_common_port/dwc_common_fbsd.c | 1308 ++++
23 .../usb/host/dwc_common_port/dwc_common_linux.c | 1421 ++++
24 drivers/usb/host/dwc_common_port/dwc_common_nbsd.c | 1275 ++++
25 drivers/usb/host/dwc_common_port/dwc_crypto.c | 308 +
26 drivers/usb/host/dwc_common_port/dwc_crypto.h | 111 +
27 drivers/usb/host/dwc_common_port/dwc_dh.c | 291 +
28 drivers/usb/host/dwc_common_port/dwc_dh.h | 106 +
29 drivers/usb/host/dwc_common_port/dwc_list.h | 594 ++
30 drivers/usb/host/dwc_common_port/dwc_mem.c | 245 +
31 drivers/usb/host/dwc_common_port/dwc_modpow.c | 636 ++
32 drivers/usb/host/dwc_common_port/dwc_modpow.h | 34 +
33 drivers/usb/host/dwc_common_port/dwc_notifier.c | 319 +
34 drivers/usb/host/dwc_common_port/dwc_notifier.h | 122 +
35 drivers/usb/host/dwc_common_port/dwc_os.h | 1260 ++++
36 drivers/usb/host/dwc_common_port/usb.h | 946 +++
37 drivers/usb/host/dwc_otg/Makefile | 80 +
38 drivers/usb/host/dwc_otg/doc/doxygen.cfg | 224 +
39 drivers/usb/host/dwc_otg/dummy_audio.c | 1575 +++++
40 drivers/usb/host/dwc_otg/dwc_cfi_common.h | 142 +
41 drivers/usb/host/dwc_otg/dwc_otg_adp.c | 854 +++
42 drivers/usb/host/dwc_otg/dwc_otg_adp.h | 80 +
43 drivers/usb/host/dwc_otg/dwc_otg_attr.c | 1210 ++++
44 drivers/usb/host/dwc_otg/dwc_otg_attr.h | 89 +
45 drivers/usb/host/dwc_otg/dwc_otg_cfi.c | 1876 +++++
46 drivers/usb/host/dwc_otg/dwc_otg_cfi.h | 320 +
47 drivers/usb/host/dwc_otg/dwc_otg_cil.c | 7151 ++++++++++++++++++++
48 drivers/usb/host/dwc_otg/dwc_otg_cil.h | 1464 ++++
49 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 1563 +++++
50 drivers/usb/host/dwc_otg/dwc_otg_core_if.h | 705 ++
51 drivers/usb/host/dwc_otg/dwc_otg_dbg.h | 116 +
52 drivers/usb/host/dwc_otg/dwc_otg_driver.c | 1700 +++++
53 drivers/usb/host/dwc_otg/dwc_otg_driver.h | 86 +
54 drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 3473 ++++++++++
55 drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 824 +++
56 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 1133 ++++
57 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 412 ++
58 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2106 ++++++
59 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 893 +++
60 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 922 +++
61 drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 185 +
62 drivers/usb/host/dwc_otg/dwc_otg_pcd.c | 2708 ++++++++
63 drivers/usb/host/dwc_otg/dwc_otg_pcd.h | 266 +
64 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h | 360 +
65 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 5147 ++++++++++++++
66 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 1358 ++++
67 drivers/usb/host/dwc_otg/dwc_otg_regs.h | 2550 +++++++
68 drivers/usb/host/dwc_otg/test/Makefile | 16 +
69 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm | 337 +
70 drivers/usb/host/dwc_otg/test/test_mod_param.pl | 133 +
71 drivers/usb/host/dwc_otg/test/test_sysfs.pl | 193 +
72 64 files changed, 56447 insertions(+), 49 deletions(-)
73 create mode 100644 drivers/usb/gadget/file_storage.c
74 create mode 100644 drivers/usb/host/dwc_common_port/Makefile
75 create mode 100644 drivers/usb/host/dwc_common_port/Makefile.fbsd
76 create mode 100644 drivers/usb/host/dwc_common_port/Makefile.linux
77 create mode 100644 drivers/usb/host/dwc_common_port/changes.txt
78 create mode 100644 drivers/usb/host/dwc_common_port/doc/doxygen.cfg
79 create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.c
80 create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.h
81 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
82 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_linux.c
83 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
84 create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.c
85 create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.h
86 create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.c
87 create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.h
88 create mode 100644 drivers/usb/host/dwc_common_port/dwc_list.h
89 create mode 100644 drivers/usb/host/dwc_common_port/dwc_mem.c
90 create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.c
91 create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.h
92 create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.c
93 create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.h
94 create mode 100644 drivers/usb/host/dwc_common_port/dwc_os.h
95 create mode 100644 drivers/usb/host/dwc_common_port/usb.h
96 create mode 100644 drivers/usb/host/dwc_otg/Makefile
97 create mode 100644 drivers/usb/host/dwc_otg/doc/doxygen.cfg
98 create mode 100644 drivers/usb/host/dwc_otg/dummy_audio.c
99 create mode 100644 drivers/usb/host/dwc_otg/dwc_cfi_common.h
100 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.c
101 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.h
102 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.c
103 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.h
104 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.c
105 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.h
106 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.c
107 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.h
108 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
109 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_core_if.h
110 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_dbg.h
111 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.c
112 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.h
113 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.c
114 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.h
115 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
116 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
117 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
118 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
119 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
120 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
121 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.c
122 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.h
123 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
124 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
125 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
126 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_regs.h
127 create mode 100644 drivers/usb/host/dwc_otg/test/Makefile
128 create mode 100644 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
129 create mode 100644 drivers/usb/host/dwc_otg/test/test_mod_param.pl
130 create mode 100644 drivers/usb/host/dwc_otg/test/test_sysfs.pl
131
132 --- a/drivers/usb/Makefile
133 +++ b/drivers/usb/Makefile
134 @@ -23,6 +23,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/
135 obj-$(CONFIG_USB_R8A66597_HCD) += host/
136 obj-$(CONFIG_USB_HWA_HCD) += host/
137 obj-$(CONFIG_USB_ISP1760_HCD) += host/
138 +obj-$(CONFIG_USB_DWCOTG) += host/
139 obj-$(CONFIG_USB_IMX21_HCD) += host/
140 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
141
142 --- a/drivers/usb/core/generic.c
143 +++ b/drivers/usb/core/generic.c
144 @@ -152,6 +152,7 @@ int usb_choose_configuration(struct usb_
145 dev_warn(&udev->dev,
146 "no configuration chosen from %d choice%s\n",
147 num_configs, plural(num_configs));
148 + dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA);
149 }
150 return i;
151 }
152 --- a/drivers/usb/core/message.c
153 +++ b/drivers/usb/core/message.c
154 @@ -1875,6 +1875,85 @@ free_interfaces:
155 if (cp->string == NULL &&
156 !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
157 cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
158 +/* Uncomment this define to enable the HS Electrical Test support */
159 +#define DWC_HS_ELECT_TST 1
160 +#ifdef DWC_HS_ELECT_TST
161 + /* Here we implement the HS Electrical Test support. The
162 + * tester uses a vendor ID of 0x1A0A to indicate we should
163 + * run a special test sequence. The product ID tells us
164 + * which sequence to run. We invoke the test sequence by
165 + * sending a non-standard SetFeature command to our root
166 + * hub port. Our dwc_otg_hcd_hub_control() routine will
167 + * recognize the command and perform the desired test
168 + * sequence.
169 + */
170 + if (dev->descriptor.idVendor == 0x1A0A) {
171 + /* HSOTG Electrical Test */
172 + dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n");
173 +
174 + if (dev->bus && dev->bus->root_hub) {
175 + struct usb_device *hdev = dev->bus->root_hub;
176 + dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct);
177 +
178 + switch (dev->descriptor.idProduct) {
179 + case 0x0101: /* TEST_SE0_NAK */
180 + dev_warn(&dev->dev, "TEST_SE0_NAK\n");
181 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
182 + USB_REQ_SET_FEATURE, USB_RT_PORT,
183 + USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ);
184 + break;
185 +
186 + case 0x0102: /* TEST_J */
187 + dev_warn(&dev->dev, "TEST_J\n");
188 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
189 + USB_REQ_SET_FEATURE, USB_RT_PORT,
190 + USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ);
191 + break;
192 +
193 + case 0x0103: /* TEST_K */
194 + dev_warn(&dev->dev, "TEST_K\n");
195 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
196 + USB_REQ_SET_FEATURE, USB_RT_PORT,
197 + USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ);
198 + break;
199 +
200 + case 0x0104: /* TEST_PACKET */
201 + dev_warn(&dev->dev, "TEST_PACKET\n");
202 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
203 + USB_REQ_SET_FEATURE, USB_RT_PORT,
204 + USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ);
205 + break;
206 +
207 + case 0x0105: /* TEST_FORCE_ENABLE */
208 + dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n");
209 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
210 + USB_REQ_SET_FEATURE, USB_RT_PORT,
211 + USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ);
212 + break;
213 +
214 + case 0x0106: /* HS_HOST_PORT_SUSPEND_RESUME */
215 + dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n");
216 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
217 + USB_REQ_SET_FEATURE, USB_RT_PORT,
218 + USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ);
219 + break;
220 +
221 + case 0x0107: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
222 + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n");
223 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
224 + USB_REQ_SET_FEATURE, USB_RT_PORT,
225 + USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ);
226 + break;
227 +
228 + case 0x0108: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
229 + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n");
230 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
231 + USB_REQ_SET_FEATURE, USB_RT_PORT,
232 + USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ);
233 + }
234 + }
235 + }
236 +#endif /* DWC_HS_ELECT_TST */
237
238 /* Now that the interfaces are installed, re-enable LPM. */
239 usb_unlocked_enable_lpm(dev);
240 --- a/drivers/usb/core/otg_whitelist.h
241 +++ b/drivers/usb/core/otg_whitelist.h
242 @@ -19,33 +19,82 @@
243 static struct usb_device_id whitelist_table [] = {
244
245 /* hubs are optional in OTG, but very handy ... */
246 +#define CERT_WITHOUT_HUBS
247 +#if defined(CERT_WITHOUT_HUBS)
248 +{ USB_DEVICE( 0x0000, 0x0000 ), }, /* Root HUB Only*/
249 +#else
250 { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
251 { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
252 +{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), },
253 +#endif
254
255 #ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
256 /* FIXME actually, printers are NOT supposed to use device classes;
257 * they're supposed to use interface classes...
258 */
259 -{ USB_DEVICE_INFO(7, 1, 1) },
260 -{ USB_DEVICE_INFO(7, 1, 2) },
261 -{ USB_DEVICE_INFO(7, 1, 3) },
262 +//{ USB_DEVICE_INFO(7, 1, 1) },
263 +//{ USB_DEVICE_INFO(7, 1, 2) },
264 +//{ USB_DEVICE_INFO(7, 1, 3) },
265 #endif
266
267 #ifdef CONFIG_USB_NET_CDCETHER
268 /* Linux-USB CDC Ethernet gadget */
269 -{ USB_DEVICE(0x0525, 0xa4a1), },
270 +//{ USB_DEVICE(0x0525, 0xa4a1), },
271 /* Linux-USB CDC Ethernet + RNDIS gadget */
272 -{ USB_DEVICE(0x0525, 0xa4a2), },
273 +//{ USB_DEVICE(0x0525, 0xa4a2), },
274 #endif
275
276 #if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
277 /* gadget zero, for testing */
278 -{ USB_DEVICE(0x0525, 0xa4a0), },
279 +//{ USB_DEVICE(0x0525, 0xa4a0), },
280 #endif
281 +
282 +/* OPT Tester */
283 +{ USB_DEVICE( 0x1a0a, 0x0101 ), }, /* TEST_SE0_NAK */
284 +{ USB_DEVICE( 0x1a0a, 0x0102 ), }, /* Test_J */
285 +{ USB_DEVICE( 0x1a0a, 0x0103 ), }, /* Test_K */
286 +{ USB_DEVICE( 0x1a0a, 0x0104 ), }, /* Test_PACKET */
287 +{ USB_DEVICE( 0x1a0a, 0x0105 ), }, /* Test_FORCE_ENABLE */
288 +{ USB_DEVICE( 0x1a0a, 0x0106 ), }, /* HS_PORT_SUSPEND_RESUME */
289 +{ USB_DEVICE( 0x1a0a, 0x0107 ), }, /* SINGLE_STEP_GET_DESCRIPTOR setup */
290 +{ USB_DEVICE( 0x1a0a, 0x0108 ), }, /* SINGLE_STEP_GET_DESCRIPTOR execute */
291 +
292 +/* Sony cameras */
293 +{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), },
294 +
295 +/* Memory Devices */
296 +//{ USB_DEVICE( 0x0781, 0x5150 ), }, /* SanDisk */
297 +//{ USB_DEVICE( 0x05DC, 0x0080 ), }, /* Lexar */
298 +//{ USB_DEVICE( 0x4146, 0x9281 ), }, /* IOMEGA */
299 +//{ USB_DEVICE( 0x067b, 0x2507 ), }, /* Hammer 20GB External HD */
300 +{ USB_DEVICE( 0x0EA0, 0x2168 ), }, /* Ours Technology Inc. (BUFFALO ClipDrive)*/
301 +//{ USB_DEVICE( 0x0457, 0x0150 ), }, /* Silicon Integrated Systems Corp. */
302 +
303 +/* HP Printers */
304 +//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */
305 +//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */
306 +
307 +/* Speakers */
308 +//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */
309 +//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */
310
311 { } /* Terminating entry */
312 };
313
314 +static inline void report_errors(struct usb_device *dev)
315 +{
316 + /* OTG MESSAGE: report errors here, customize to match your product */
317 + dev_info(&dev->dev, "device Vendor:%04x Product:%04x is not supported\n",
318 + le16_to_cpu(dev->descriptor.idVendor),
319 + le16_to_cpu(dev->descriptor.idProduct));
320 + if (USB_CLASS_HUB == dev->descriptor.bDeviceClass){
321 + dev_printk(KERN_CRIT, &dev->dev, "Unsupported Hub Topology\n");
322 + } else {
323 + dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n");
324 + }
325 +}
326 +
327 +
328 static int is_targeted(struct usb_device *dev)
329 {
330 struct usb_device_id *id = whitelist_table;
331 @@ -55,58 +104,83 @@ static int is_targeted(struct usb_device
332 return 1;
333
334 /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
335 - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
336 - le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
337 - return 0;
338 + if (dev->descriptor.idVendor == 0x1a0a &&
339 + dev->descriptor.idProduct == 0xbadd) {
340 + return 0;
341 + } else if (!enable_whitelist) {
342 + return 1;
343 + } else {
344
345 - /* NOTE: can't use usb_match_id() since interface caches
346 - * aren't set up yet. this is cut/paste from that code.
347 - */
348 - for (id = whitelist_table; id->match_flags; id++) {
349 - if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
350 - id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
351 - continue;
352 -
353 - if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
354 - id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
355 - continue;
356 -
357 - /* No need to test id->bcdDevice_lo != 0, since 0 is never
358 - greater than any unsigned number. */
359 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
360 - (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
361 - continue;
362 -
363 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
364 - (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
365 - continue;
366 -
367 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
368 - (id->bDeviceClass != dev->descriptor.bDeviceClass))
369 - continue;
370 -
371 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
372 - (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
373 - continue;
374 -
375 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
376 - (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
377 - continue;
378 +#ifdef DEBUG
379 + dev_dbg(&dev->dev, "device V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
380 + dev->descriptor.idVendor,
381 + dev->descriptor.idProduct,
382 + dev->descriptor.bDeviceClass,
383 + dev->descriptor.bDeviceSubClass,
384 + dev->descriptor.bDeviceProtocol);
385 +#endif
386
387 return 1;
388 + /* NOTE: can't use usb_match_id() since interface caches
389 + * aren't set up yet. this is cut/paste from that code.
390 + */
391 + for (id = whitelist_table; id->match_flags; id++) {
392 +#ifdef DEBUG
393 + dev_dbg(&dev->dev,
394 + "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
395 + id->idVendor,
396 + id->idProduct,
397 + id->bDeviceClass,
398 + id->bDeviceSubClass,
399 + id->bDeviceProtocol);
400 +#endif
401 +
402 + if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
403 + id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
404 + continue;
405 +
406 + if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
407 + id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
408 + continue;
409 +
410 + /* No need to test id->bcdDevice_lo != 0, since 0 is never
411 + greater than any unsigned number. */
412 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
413 + (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
414 + continue;
415 +
416 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
417 + (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
418 + continue;
419 +
420 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
421 + (id->bDeviceClass != dev->descriptor.bDeviceClass))
422 + continue;
423 +
424 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
425 + (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
426 + continue;
427 +
428 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
429 + (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
430 + continue;
431 +
432 + return 1;
433 + }
434 }
435
436 /* add other match criteria here ... */
437
438 -
439 - /* OTG MESSAGE: report errors here, customize to match your product */
440 - dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
441 - le16_to_cpu(dev->descriptor.idVendor),
442 - le16_to_cpu(dev->descriptor.idProduct));
443 #ifdef CONFIG_USB_OTG_WHITELIST
444 + report_errors(dev);
445 return 0;
446 #else
447 - return 1;
448 + if (enable_whitelist) {
449 + report_errors(dev);
450 + return 0;
451 + } else {
452 + return 1;
453 + }
454 #endif
455 }
456
457 --- /dev/null
458 +++ b/drivers/usb/gadget/file_storage.c
459 @@ -0,0 +1,3676 @@
460 +/*
461 + * file_storage.c -- File-backed USB Storage Gadget, for USB development
462 + *
463 + * Copyright (C) 2003-2008 Alan Stern
464 + * All rights reserved.
465 + *
466 + * Redistribution and use in source and binary forms, with or without
467 + * modification, are permitted provided that the following conditions
468 + * are met:
469 + * 1. Redistributions of source code must retain the above copyright
470 + * notice, this list of conditions, and the following disclaimer,
471 + * without modification.
472 + * 2. Redistributions in binary form must reproduce the above copyright
473 + * notice, this list of conditions and the following disclaimer in the
474 + * documentation and/or other materials provided with the distribution.
475 + * 3. The names of the above-listed copyright holders may not be used
476 + * to endorse or promote products derived from this software without
477 + * specific prior written permission.
478 + *
479 + * ALTERNATIVELY, this software may be distributed under the terms of the
480 + * GNU General Public License ("GPL") as published by the Free Software
481 + * Foundation, either version 2 of that License or (at your option) any
482 + * later version.
483 + *
484 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
485 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
486 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
487 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
488 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
489 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
490 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
491 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
492 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
493 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
494 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
495 + */
496 +
497 +
498 +/*
499 + * The File-backed Storage Gadget acts as a USB Mass Storage device,
500 + * appearing to the host as a disk drive or as a CD-ROM drive. In addition
501 + * to providing an example of a genuinely useful gadget driver for a USB
502 + * device, it also illustrates a technique of double-buffering for increased
503 + * throughput. Last but not least, it gives an easy way to probe the
504 + * behavior of the Mass Storage drivers in a USB host.
505 + *
506 + * Backing storage is provided by a regular file or a block device, specified
507 + * by the "file" module parameter. Access can be limited to read-only by
508 + * setting the optional "ro" module parameter. (For CD-ROM emulation,
509 + * access is always read-only.) The gadget will indicate that it has
510 + * removable media if the optional "removable" module parameter is set.
511 + *
512 + * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
513 + * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
514 + * by the optional "transport" module parameter. It also supports the
515 + * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
516 + * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
517 + * the optional "protocol" module parameter. In addition, the default
518 + * Vendor ID, Product ID, release number and serial number can be overridden.
519 + *
520 + * There is support for multiple logical units (LUNs), each of which has
521 + * its own backing file. The number of LUNs can be set using the optional
522 + * "luns" module parameter (anywhere from 1 to 8), and the corresponding
523 + * files are specified using comma-separated lists for "file" and "ro".
524 + * The default number of LUNs is taken from the number of "file" elements;
525 + * it is 1 if "file" is not given. If "removable" is not set then a backing
526 + * file must be specified for each LUN. If it is set, then an unspecified
527 + * or empty backing filename means the LUN's medium is not loaded. Ideally
528 + * each LUN would be settable independently as a disk drive or a CD-ROM
529 + * drive, but currently all LUNs have to be the same type. The CD-ROM
530 + * emulation includes a single data track and no audio tracks; hence there
531 + * need be only one backing file per LUN.
532 + *
533 + * Requirements are modest; only a bulk-in and a bulk-out endpoint are
534 + * needed (an interrupt-out endpoint is also needed for CBI). The memory
535 + * requirement amounts to two 16K buffers, size configurable by a parameter.
536 + * Support is included for both full-speed and high-speed operation.
537 + *
538 + * Note that the driver is slightly non-portable in that it assumes a
539 + * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
540 + * interrupt-in endpoints. With most device controllers this isn't an
541 + * issue, but there may be some with hardware restrictions that prevent
542 + * a buffer from being used by more than one endpoint.
543 + *
544 + * Module options:
545 + *
546 + * file=filename[,filename...]
547 + * Required if "removable" is not set, names of
548 + * the files or block devices used for
549 + * backing storage
550 + * serial=HHHH... Required serial number (string of hex chars)
551 + * ro=b[,b...] Default false, booleans for read-only access
552 + * removable Default false, boolean for removable media
553 + * luns=N Default N = number of filenames, number of
554 + * LUNs to support
555 + * nofua=b[,b...] Default false, booleans for ignore FUA flag
556 + * in SCSI WRITE(10,12) commands
557 + * stall Default determined according to the type of
558 + * USB device controller (usually true),
559 + * boolean to permit the driver to halt
560 + * bulk endpoints
561 + * cdrom Default false, boolean for whether to emulate
562 + * a CD-ROM drive
563 + * transport=XXX Default BBB, transport name (CB, CBI, or BBB)
564 + * protocol=YYY Default SCSI, protocol name (RBC, 8020 or
565 + * ATAPI, QIC, UFI, 8070, or SCSI;
566 + * also 1 - 6)
567 + * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
568 + * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
569 + * release=0xRRRR Override the USB release number (bcdDevice)
570 + * buflen=N Default N=16384, buffer size used (will be
571 + * rounded down to a multiple of
572 + * PAGE_CACHE_SIZE)
573 + *
574 + * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro",
575 + * "removable", "luns", "nofua", "stall", and "cdrom" options are available;
576 + * default values are used for everything else.
577 + *
578 + * The pathnames of the backing files and the ro settings are available in
579 + * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of
580 + * the gadget's sysfs directory. If the "removable" option is set, writing to
581 + * these files will simulate ejecting/loading the medium (writing an empty
582 + * line means eject) and adjusting a write-enable tab. Changes to the ro
583 + * setting are not allowed when the medium is loaded or if CD-ROM emulation
584 + * is being used.
585 + *
586 + * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
587 + * The driver's SCSI command interface was based on the "Information
588 + * technology - Small Computer System Interface - 2" document from
589 + * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at
590 + * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception
591 + * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the
592 + * "Universal Serial Bus Mass Storage Class UFI Command Specification"
593 + * document, Revision 1.0, December 14, 1998, available at
594 + * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
595 + */
596 +
597 +
598 +/*
599 + * Driver Design
600 + *
601 + * The FSG driver is fairly straightforward. There is a main kernel
602 + * thread that handles most of the work. Interrupt routines field
603 + * callbacks from the controller driver: bulk- and interrupt-request
604 + * completion notifications, endpoint-0 events, and disconnect events.
605 + * Completion events are passed to the main thread by wakeup calls. Many
606 + * ep0 requests are handled at interrupt time, but SetInterface,
607 + * SetConfiguration, and device reset requests are forwarded to the
608 + * thread in the form of "exceptions" using SIGUSR1 signals (since they
609 + * should interrupt any ongoing file I/O operations).
610 + *
611 + * The thread's main routine implements the standard command/data/status
612 + * parts of a SCSI interaction. It and its subroutines are full of tests
613 + * for pending signals/exceptions -- all this polling is necessary since
614 + * the kernel has no setjmp/longjmp equivalents. (Maybe this is an
615 + * indication that the driver really wants to be running in userspace.)
616 + * An important point is that so long as the thread is alive it keeps an
617 + * open reference to the backing file. This will prevent unmounting
618 + * the backing file's underlying filesystem and could cause problems
619 + * during system shutdown, for example. To prevent such problems, the
620 + * thread catches INT, TERM, and KILL signals and converts them into
621 + * an EXIT exception.
622 + *
623 + * In normal operation the main thread is started during the gadget's
624 + * fsg_bind() callback and stopped during fsg_unbind(). But it can also
625 + * exit when it receives a signal, and there's no point leaving the
626 + * gadget running when the thread is dead. So just before the thread
627 + * exits, it deregisters the gadget driver. This makes things a little
628 + * tricky: The driver is deregistered at two places, and the exiting
629 + * thread can indirectly call fsg_unbind() which in turn can tell the
630 + * thread to exit. The first problem is resolved through the use of the
631 + * REGISTERED atomic bitflag; the driver will only be deregistered once.
632 + * The second problem is resolved by having fsg_unbind() check
633 + * fsg->state; it won't try to stop the thread if the state is already
634 + * FSG_STATE_TERMINATED.
635 + *
636 + * To provide maximum throughput, the driver uses a circular pipeline of
637 + * buffer heads (struct fsg_buffhd). In principle the pipeline can be
638 + * arbitrarily long; in practice the benefits don't justify having more
639 + * than 2 stages (i.e., double buffering). But it helps to think of the
640 + * pipeline as being a long one. Each buffer head contains a bulk-in and
641 + * a bulk-out request pointer (since the buffer can be used for both
642 + * output and input -- directions always are given from the host's
643 + * point of view) as well as a pointer to the buffer and various state
644 + * variables.
645 + *
646 + * Use of the pipeline follows a simple protocol. There is a variable
647 + * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
648 + * At any time that buffer head may still be in use from an earlier
649 + * request, so each buffer head has a state variable indicating whether
650 + * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the
651 + * buffer head to be EMPTY, filling the buffer either by file I/O or by
652 + * USB I/O (during which the buffer head is BUSY), and marking the buffer
653 + * head FULL when the I/O is complete. Then the buffer will be emptied
654 + * (again possibly by USB I/O, during which it is marked BUSY) and
655 + * finally marked EMPTY again (possibly by a completion routine).
656 + *
657 + * A module parameter tells the driver to avoid stalling the bulk
658 + * endpoints wherever the transport specification allows. This is
659 + * necessary for some UDCs like the SuperH, which cannot reliably clear a
660 + * halt on a bulk endpoint. However, under certain circumstances the
661 + * Bulk-only specification requires a stall. In such cases the driver
662 + * will halt the endpoint and set a flag indicating that it should clear
663 + * the halt in software during the next device reset. Hopefully this
664 + * will permit everything to work correctly. Furthermore, although the
665 + * specification allows the bulk-out endpoint to halt when the host sends
666 + * too much data, implementing this would cause an unavoidable race.
667 + * The driver will always use the "no-stall" approach for OUT transfers.
668 + *
669 + * One subtle point concerns sending status-stage responses for ep0
670 + * requests. Some of these requests, such as device reset, can involve
671 + * interrupting an ongoing file I/O operation, which might take an
672 + * arbitrarily long time. During that delay the host might give up on
673 + * the original ep0 request and issue a new one. When that happens the
674 + * driver should not notify the host about completion of the original
675 + * request, as the host will no longer be waiting for it. So the driver
676 + * assigns to each ep0 request a unique tag, and it keeps track of the
677 + * tag value of the request associated with a long-running exception
678 + * (device-reset, interface-change, or configuration-change). When the
679 + * exception handler is finished, the status-stage response is submitted
680 + * only if the current ep0 request tag is equal to the exception request
681 + * tag. Thus only the most recently received ep0 request will get a
682 + * status-stage response.
683 + *
684 + * Warning: This driver source file is too long. It ought to be split up
685 + * into a header file plus about 3 separate .c files, to handle the details
686 + * of the Gadget, USB Mass Storage, and SCSI protocols.
687 + */
688 +
689 +
690 +/* #define VERBOSE_DEBUG */
691 +/* #define DUMP_MSGS */
692 +
693 +
694 +#include <linux/blkdev.h>
695 +#include <linux/completion.h>
696 +#include <linux/dcache.h>
697 +#include <linux/delay.h>
698 +#include <linux/device.h>
699 +#include <linux/fcntl.h>
700 +#include <linux/file.h>
701 +#include <linux/fs.h>
702 +#include <linux/kref.h>
703 +#include <linux/kthread.h>
704 +#include <linux/limits.h>
705 +#include <linux/module.h>
706 +#include <linux/rwsem.h>
707 +#include <linux/slab.h>
708 +#include <linux/spinlock.h>
709 +#include <linux/string.h>
710 +#include <linux/freezer.h>
711 +#include <linux/utsname.h>
712 +
713 +#include <linux/usb/ch9.h>
714 +#include <linux/usb/gadget.h>
715 +
716 +#include "gadget_chips.h"
717 +
718 +
719 +
720 +/*
721 + * Kbuild is not very cooperative with respect to linking separately
722 + * compiled library objects into one module. So for now we won't use
723 + * separate compilation ... ensuring init/exit sections work to shrink
724 + * the runtime footprint, and giving us at least some parts of what
725 + * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
726 + */
727 +#include "usbstring.c"
728 +#include "config.c"
729 +#include "epautoconf.c"
730 +
731 +/*-------------------------------------------------------------------------*/
732 +
733 +#define DRIVER_DESC "File-backed Storage Gadget"
734 +#define DRIVER_NAME "g_file_storage"
735 +#define DRIVER_VERSION "1 September 2010"
736 +
737 +static char fsg_string_manufacturer[64];
738 +static const char fsg_string_product[] = DRIVER_DESC;
739 +static const char fsg_string_config[] = "Self-powered";
740 +static const char fsg_string_interface[] = "Mass Storage";
741 +
742 +
743 +#include "storage_common.c"
744 +
745 +
746 +MODULE_DESCRIPTION(DRIVER_DESC);
747 +MODULE_AUTHOR("Alan Stern");
748 +MODULE_LICENSE("Dual BSD/GPL");
749 +
750 +/*
751 + * This driver assumes self-powered hardware and has no way for users to
752 + * trigger remote wakeup. It uses autoconfiguration to select endpoints
753 + * and endpoint addresses.
754 + */
755 +
756 +
757 +/*-------------------------------------------------------------------------*/
758 +
759 +
760 +/* Encapsulate the module parameter settings */
761 +
762 +static struct {
763 + char *file[FSG_MAX_LUNS];
764 + char *serial;
765 + bool ro[FSG_MAX_LUNS];
766 + bool nofua[FSG_MAX_LUNS];
767 + unsigned int num_filenames;
768 + unsigned int num_ros;
769 + unsigned int num_nofuas;
770 + unsigned int nluns;
771 +
772 + bool removable;
773 + bool can_stall;
774 + bool cdrom;
775 +
776 + char *transport_parm;
777 + char *protocol_parm;
778 + unsigned short vendor;
779 + unsigned short product;
780 + unsigned short release;
781 + unsigned int buflen;
782 +
783 + int transport_type;
784 + char *transport_name;
785 + int protocol_type;
786 + char *protocol_name;
787 +
788 +} mod_data = { // Default values
789 + .transport_parm = "BBB",
790 + .protocol_parm = "SCSI",
791 + .removable = 0,
792 + .can_stall = 1,
793 + .cdrom = 0,
794 + .vendor = FSG_VENDOR_ID,
795 + .product = FSG_PRODUCT_ID,
796 + .release = 0xffff, // Use controller chip type
797 + .buflen = 16384,
798 + };
799 +
800 +
801 +module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
802 + S_IRUGO);
803 +MODULE_PARM_DESC(file, "names of backing files or devices");
804 +
805 +module_param_named(serial, mod_data.serial, charp, S_IRUGO);
806 +MODULE_PARM_DESC(serial, "USB serial number");
807 +
808 +module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
809 +MODULE_PARM_DESC(ro, "true to force read-only");
810 +
811 +module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas,
812 + S_IRUGO);
813 +MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit");
814 +
815 +module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
816 +MODULE_PARM_DESC(luns, "number of LUNs");
817 +
818 +module_param_named(removable, mod_data.removable, bool, S_IRUGO);
819 +MODULE_PARM_DESC(removable, "true to simulate removable media");
820 +
821 +module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
822 +MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
823 +
824 +module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
825 +MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
826 +
827 +/* In the non-TEST version, only the module parameters listed above
828 + * are available. */
829 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
830 +
831 +module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO);
832 +MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");
833 +
834 +module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO);
835 +MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, "
836 + "8070, or SCSI)");
837 +
838 +module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO);
839 +MODULE_PARM_DESC(vendor, "USB Vendor ID");
840 +
841 +module_param_named(product, mod_data.product, ushort, S_IRUGO);
842 +MODULE_PARM_DESC(product, "USB Product ID");
843 +
844 +module_param_named(release, mod_data.release, ushort, S_IRUGO);
845 +MODULE_PARM_DESC(release, "USB release number");
846 +
847 +module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
848 +MODULE_PARM_DESC(buflen, "I/O buffer size");
849 +
850 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
851 +
852 +
853 +/*
854 + * These definitions will permit the compiler to avoid generating code for
855 + * parts of the driver that aren't used in the non-TEST version. Even gcc
856 + * can recognize when a test of a constant expression yields a dead code
857 + * path.
858 + */
859 +
860 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
861 +
862 +#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK)
863 +#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI)
864 +#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI)
865 +
866 +#else
867 +
868 +#define transport_is_bbb() 1
869 +#define transport_is_cbi() 0
870 +#define protocol_is_scsi() 1
871 +
872 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
873 +
874 +
875 +/*-------------------------------------------------------------------------*/
876 +
877 +
878 +struct fsg_dev {
879 + /* lock protects: state, all the req_busy's, and cbbuf_cmnd */
880 + spinlock_t lock;
881 + struct usb_gadget *gadget;
882 +
883 + /* filesem protects: backing files in use */
884 + struct rw_semaphore filesem;
885 +
886 + /* reference counting: wait until all LUNs are released */
887 + struct kref ref;
888 +
889 + struct usb_ep *ep0; // Handy copy of gadget->ep0
890 + struct usb_request *ep0req; // For control responses
891 + unsigned int ep0_req_tag;
892 + const char *ep0req_name;
893 +
894 + struct usb_request *intreq; // For interrupt responses
895 + int intreq_busy;
896 + struct fsg_buffhd *intr_buffhd;
897 +
898 + unsigned int bulk_out_maxpacket;
899 + enum fsg_state state; // For exception handling
900 + unsigned int exception_req_tag;
901 +
902 + u8 config, new_config;
903 +
904 + unsigned int running : 1;
905 + unsigned int bulk_in_enabled : 1;
906 + unsigned int bulk_out_enabled : 1;
907 + unsigned int intr_in_enabled : 1;
908 + unsigned int phase_error : 1;
909 + unsigned int short_packet_received : 1;
910 + unsigned int bad_lun_okay : 1;
911 +
912 + unsigned long atomic_bitflags;
913 +#define REGISTERED 0
914 +#define IGNORE_BULK_OUT 1
915 +#define SUSPENDED 2
916 +
917 + struct usb_ep *bulk_in;
918 + struct usb_ep *bulk_out;
919 + struct usb_ep *intr_in;
920 +
921 + struct fsg_buffhd *next_buffhd_to_fill;
922 + struct fsg_buffhd *next_buffhd_to_drain;
923 +
924 + int thread_wakeup_needed;
925 + struct completion thread_notifier;
926 + struct task_struct *thread_task;
927 +
928 + int cmnd_size;
929 + u8 cmnd[MAX_COMMAND_SIZE];
930 + enum data_direction data_dir;
931 + u32 data_size;
932 + u32 data_size_from_cmnd;
933 + u32 tag;
934 + unsigned int lun;
935 + u32 residue;
936 + u32 usb_amount_left;
937 +
938 + /* The CB protocol offers no way for a host to know when a command
939 + * has completed. As a result the next command may arrive early,
940 + * and we will still have to handle it. For that reason we need
941 + * a buffer to store new commands when using CB (or CBI, which
942 + * does not oblige a host to wait for command completion either). */
943 + int cbbuf_cmnd_size;
944 + u8 cbbuf_cmnd[MAX_COMMAND_SIZE];
945 +
946 + unsigned int nluns;
947 + struct fsg_lun *luns;
948 + struct fsg_lun *curlun;
949 + /* Must be the last entry */
950 + struct fsg_buffhd buffhds[];
951 +};
952 +
953 +typedef void (*fsg_routine_t)(struct fsg_dev *);
954 +
955 +static int exception_in_progress(struct fsg_dev *fsg)
956 +{
957 + return (fsg->state > FSG_STATE_IDLE);
958 +}
959 +
960 +/* Make bulk-out requests be divisible by the maxpacket size */
961 +static void set_bulk_out_req_length(struct fsg_dev *fsg,
962 + struct fsg_buffhd *bh, unsigned int length)
963 +{
964 + unsigned int rem;
965 +
966 + bh->bulk_out_intended_length = length;
967 + rem = length % fsg->bulk_out_maxpacket;
968 + if (rem > 0)
969 + length += fsg->bulk_out_maxpacket - rem;
970 + bh->outreq->length = length;
971 +}
972 +
973 +static struct fsg_dev *the_fsg;
974 +static struct usb_gadget_driver fsg_driver;
975 +
976 +
977 +/*-------------------------------------------------------------------------*/
978 +
979 +static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
980 +{
981 + const char *name;
982 +
983 + if (ep == fsg->bulk_in)
984 + name = "bulk-in";
985 + else if (ep == fsg->bulk_out)
986 + name = "bulk-out";
987 + else
988 + name = ep->name;
989 + DBG(fsg, "%s set halt\n", name);
990 + return usb_ep_set_halt(ep);
991 +}
992 +
993 +
994 +/*-------------------------------------------------------------------------*/
995 +
996 +/*
997 + * DESCRIPTORS ... most are static, but strings and (full) configuration
998 + * descriptors are built on demand. Also the (static) config and interface
999 + * descriptors are adjusted during fsg_bind().
1000 + */
1001 +
1002 +/* There is only one configuration. */
1003 +#define CONFIG_VALUE 1
1004 +
1005 +static struct usb_device_descriptor
1006 +device_desc = {
1007 + .bLength = sizeof device_desc,
1008 + .bDescriptorType = USB_DT_DEVICE,
1009 +
1010 + .bcdUSB = cpu_to_le16(0x0200),
1011 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
1012 +
1013 + /* The next three values can be overridden by module parameters */
1014 + .idVendor = cpu_to_le16(FSG_VENDOR_ID),
1015 + .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
1016 + .bcdDevice = cpu_to_le16(0xffff),
1017 +
1018 + .iManufacturer = FSG_STRING_MANUFACTURER,
1019 + .iProduct = FSG_STRING_PRODUCT,
1020 + .iSerialNumber = FSG_STRING_SERIAL,
1021 + .bNumConfigurations = 1,
1022 +};
1023 +
1024 +static struct usb_config_descriptor
1025 +config_desc = {
1026 + .bLength = sizeof config_desc,
1027 + .bDescriptorType = USB_DT_CONFIG,
1028 +
1029 + /* wTotalLength computed by usb_gadget_config_buf() */
1030 + .bNumInterfaces = 1,
1031 + .bConfigurationValue = CONFIG_VALUE,
1032 + .iConfiguration = FSG_STRING_CONFIG,
1033 + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
1034 + .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
1035 +};
1036 +
1037 +
1038 +static struct usb_qualifier_descriptor
1039 +dev_qualifier = {
1040 + .bLength = sizeof dev_qualifier,
1041 + .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
1042 +
1043 + .bcdUSB = cpu_to_le16(0x0200),
1044 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
1045 +
1046 + .bNumConfigurations = 1,
1047 +};
1048 +
1049 +static int populate_bos(struct fsg_dev *fsg, u8 *buf)
1050 +{
1051 + memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
1052 + buf += USB_DT_BOS_SIZE;
1053 +
1054 + memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
1055 + buf += USB_DT_USB_EXT_CAP_SIZE;
1056 +
1057 + memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
1058 +
1059 + return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
1060 + + USB_DT_USB_EXT_CAP_SIZE;
1061 +}
1062 +
1063 +/*
1064 + * Config descriptors must agree with the code that sets configurations
1065 + * and with code managing interfaces and their altsettings. They must
1066 + * also handle different speeds and other-speed requests.
1067 + */
1068 +static int populate_config_buf(struct usb_gadget *gadget,
1069 + u8 *buf, u8 type, unsigned index)
1070 +{
1071 + enum usb_device_speed speed = gadget->speed;
1072 + int len;
1073 + const struct usb_descriptor_header **function;
1074 +
1075 + if (index > 0)
1076 + return -EINVAL;
1077 +
1078 + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
1079 + speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
1080 + function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH
1081 + ? (const struct usb_descriptor_header **)fsg_hs_function
1082 + : (const struct usb_descriptor_header **)fsg_fs_function;
1083 +
1084 + /* for now, don't advertise srp-only devices */
1085 + if (!gadget_is_otg(gadget))
1086 + function++;
1087 +
1088 + len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
1089 + ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
1090 + return len;
1091 +}
1092 +
1093 +
1094 +/*-------------------------------------------------------------------------*/
1095 +
1096 +/* These routines may be called in process context or in_irq */
1097 +
1098 +/* Caller must hold fsg->lock */
1099 +static void wakeup_thread(struct fsg_dev *fsg)
1100 +{
1101 + /* Tell the main thread that something has happened */
1102 + fsg->thread_wakeup_needed = 1;
1103 + if (fsg->thread_task)
1104 + wake_up_process(fsg->thread_task);
1105 +}
1106 +
1107 +
1108 +static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
1109 +{
1110 + unsigned long flags;
1111 +
1112 + /* Do nothing if a higher-priority exception is already in progress.
1113 + * If a lower-or-equal priority exception is in progress, preempt it
1114 + * and notify the main thread by sending it a signal. */
1115 + spin_lock_irqsave(&fsg->lock, flags);
1116 + if (fsg->state <= new_state) {
1117 + fsg->exception_req_tag = fsg->ep0_req_tag;
1118 + fsg->state = new_state;
1119 + if (fsg->thread_task)
1120 + send_sig_info(SIGUSR1, SEND_SIG_FORCED,
1121 + fsg->thread_task);
1122 + }
1123 + spin_unlock_irqrestore(&fsg->lock, flags);
1124 +}
1125 +
1126 +
1127 +/*-------------------------------------------------------------------------*/
1128 +
1129 +/* The disconnect callback and ep0 routines. These always run in_irq,
1130 + * except that ep0_queue() is called in the main thread to acknowledge
1131 + * completion of various requests: set config, set interface, and
1132 + * Bulk-only device reset. */
1133 +
1134 +static void fsg_disconnect(struct usb_gadget *gadget)
1135 +{
1136 + struct fsg_dev *fsg = get_gadget_data(gadget);
1137 +
1138 + DBG(fsg, "disconnect or port reset\n");
1139 + raise_exception(fsg, FSG_STATE_DISCONNECT);
1140 +}
1141 +
1142 +
1143 +static int ep0_queue(struct fsg_dev *fsg)
1144 +{
1145 + int rc;
1146 +
1147 + rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
1148 + if (rc != 0 && rc != -ESHUTDOWN) {
1149 +
1150 + /* We can't do much more than wait for a reset */
1151 + WARNING(fsg, "error in submission: %s --> %d\n",
1152 + fsg->ep0->name, rc);
1153 + }
1154 + return rc;
1155 +}
1156 +
1157 +static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
1158 +{
1159 + struct fsg_dev *fsg = ep->driver_data;
1160 +
1161 + if (req->actual > 0)
1162 + dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
1163 + if (req->status || req->actual != req->length)
1164 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1165 + req->status, req->actual, req->length);
1166 + if (req->status == -ECONNRESET) // Request was cancelled
1167 + usb_ep_fifo_flush(ep);
1168 +
1169 + if (req->status == 0 && req->context)
1170 + ((fsg_routine_t) (req->context))(fsg);
1171 +}
1172 +
1173 +
1174 +/*-------------------------------------------------------------------------*/
1175 +
1176 +/* Bulk and interrupt endpoint completion handlers.
1177 + * These always run in_irq. */
1178 +
1179 +static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
1180 +{
1181 + struct fsg_dev *fsg = ep->driver_data;
1182 + struct fsg_buffhd *bh = req->context;
1183 +
1184 + if (req->status || req->actual != req->length)
1185 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1186 + req->status, req->actual, req->length);
1187 + if (req->status == -ECONNRESET) // Request was cancelled
1188 + usb_ep_fifo_flush(ep);
1189 +
1190 + /* Hold the lock while we update the request and buffer states */
1191 + smp_wmb();
1192 + spin_lock(&fsg->lock);
1193 + bh->inreq_busy = 0;
1194 + bh->state = BUF_STATE_EMPTY;
1195 + wakeup_thread(fsg);
1196 + spin_unlock(&fsg->lock);
1197 +}
1198 +
1199 +static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
1200 +{
1201 + struct fsg_dev *fsg = ep->driver_data;
1202 + struct fsg_buffhd *bh = req->context;
1203 +
1204 + dump_msg(fsg, "bulk-out", req->buf, req->actual);
1205 + if (req->status || req->actual != bh->bulk_out_intended_length)
1206 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1207 + req->status, req->actual,
1208 + bh->bulk_out_intended_length);
1209 + if (req->status == -ECONNRESET) // Request was cancelled
1210 + usb_ep_fifo_flush(ep);
1211 +
1212 + /* Hold the lock while we update the request and buffer states */
1213 + smp_wmb();
1214 + spin_lock(&fsg->lock);
1215 + bh->outreq_busy = 0;
1216 + bh->state = BUF_STATE_FULL;
1217 + wakeup_thread(fsg);
1218 + spin_unlock(&fsg->lock);
1219 +}
1220 +
1221 +
1222 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
1223 +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
1224 +{
1225 + struct fsg_dev *fsg = ep->driver_data;
1226 + struct fsg_buffhd *bh = req->context;
1227 +
1228 + if (req->status || req->actual != req->length)
1229 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1230 + req->status, req->actual, req->length);
1231 + if (req->status == -ECONNRESET) // Request was cancelled
1232 + usb_ep_fifo_flush(ep);
1233 +
1234 + /* Hold the lock while we update the request and buffer states */
1235 + smp_wmb();
1236 + spin_lock(&fsg->lock);
1237 + fsg->intreq_busy = 0;
1238 + bh->state = BUF_STATE_EMPTY;
1239 + wakeup_thread(fsg);
1240 + spin_unlock(&fsg->lock);
1241 +}
1242 +
1243 +#else
1244 +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
1245 +{}
1246 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
1247 +
1248 +
1249 +/*-------------------------------------------------------------------------*/
1250 +
1251 +/* Ep0 class-specific handlers. These always run in_irq. */
1252 +
1253 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
1254 +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1255 +{
1256 + struct usb_request *req = fsg->ep0req;
1257 + static u8 cbi_reset_cmnd[6] = {
1258 + SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
1259 +
1260 + /* Error in command transfer? */
1261 + if (req->status || req->length != req->actual ||
1262 + req->actual < 6 || req->actual > MAX_COMMAND_SIZE) {
1263 +
1264 + /* Not all controllers allow a protocol stall after
1265 + * receiving control-out data, but we'll try anyway. */
1266 + fsg_set_halt(fsg, fsg->ep0);
1267 + return; // Wait for reset
1268 + }
1269 +
1270 + /* Is it the special reset command? */
1271 + if (req->actual >= sizeof cbi_reset_cmnd &&
1272 + memcmp(req->buf, cbi_reset_cmnd,
1273 + sizeof cbi_reset_cmnd) == 0) {
1274 +
1275 + /* Raise an exception to stop the current operation
1276 + * and reinitialize our state. */
1277 + DBG(fsg, "cbi reset request\n");
1278 + raise_exception(fsg, FSG_STATE_RESET);
1279 + return;
1280 + }
1281 +
1282 + VDBG(fsg, "CB[I] accept device-specific command\n");
1283 + spin_lock(&fsg->lock);
1284 +
1285 + /* Save the command for later */
1286 + if (fsg->cbbuf_cmnd_size)
1287 + WARNING(fsg, "CB[I] overwriting previous command\n");
1288 + fsg->cbbuf_cmnd_size = req->actual;
1289 + memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
1290 +
1291 + wakeup_thread(fsg);
1292 + spin_unlock(&fsg->lock);
1293 +}
1294 +
1295 +#else
1296 +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1297 +{}
1298 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
1299 +
1300 +
1301 +static int class_setup_req(struct fsg_dev *fsg,
1302 + const struct usb_ctrlrequest *ctrl)
1303 +{
1304 + struct usb_request *req = fsg->ep0req;
1305 + int value = -EOPNOTSUPP;
1306 + u16 w_index = le16_to_cpu(ctrl->wIndex);
1307 + u16 w_value = le16_to_cpu(ctrl->wValue);
1308 + u16 w_length = le16_to_cpu(ctrl->wLength);
1309 +
1310 + if (!fsg->config)
1311 + return value;
1312 +
1313 + /* Handle Bulk-only class-specific requests */
1314 + if (transport_is_bbb()) {
1315 + switch (ctrl->bRequest) {
1316 +
1317 + case US_BULK_RESET_REQUEST:
1318 + if (ctrl->bRequestType != (USB_DIR_OUT |
1319 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1320 + break;
1321 + if (w_index != 0 || w_value != 0 || w_length != 0) {
1322 + value = -EDOM;
1323 + break;
1324 + }
1325 +
1326 + /* Raise an exception to stop the current operation
1327 + * and reinitialize our state. */
1328 + DBG(fsg, "bulk reset request\n");
1329 + raise_exception(fsg, FSG_STATE_RESET);
1330 + value = DELAYED_STATUS;
1331 + break;
1332 +
1333 + case US_BULK_GET_MAX_LUN:
1334 + if (ctrl->bRequestType != (USB_DIR_IN |
1335 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1336 + break;
1337 + if (w_index != 0 || w_value != 0 || w_length != 1) {
1338 + value = -EDOM;
1339 + break;
1340 + }
1341 + VDBG(fsg, "get max LUN\n");
1342 + *(u8 *) req->buf = fsg->nluns - 1;
1343 + value = 1;
1344 + break;
1345 + }
1346 + }
1347 +
1348 + /* Handle CBI class-specific requests */
1349 + else {
1350 + switch (ctrl->bRequest) {
1351 +
1352 + case USB_CBI_ADSC_REQUEST:
1353 + if (ctrl->bRequestType != (USB_DIR_OUT |
1354 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1355 + break;
1356 + if (w_index != 0 || w_value != 0) {
1357 + value = -EDOM;
1358 + break;
1359 + }
1360 + if (w_length > MAX_COMMAND_SIZE) {
1361 + value = -EOVERFLOW;
1362 + break;
1363 + }
1364 + value = w_length;
1365 + fsg->ep0req->context = received_cbi_adsc;
1366 + break;
1367 + }
1368 + }
1369 +
1370 + if (value == -EOPNOTSUPP)
1371 + VDBG(fsg,
1372 + "unknown class-specific control req "
1373 + "%02x.%02x v%04x i%04x l%u\n",
1374 + ctrl->bRequestType, ctrl->bRequest,
1375 + le16_to_cpu(ctrl->wValue), w_index, w_length);
1376 + return value;
1377 +}
1378 +
1379 +
1380 +/*-------------------------------------------------------------------------*/
1381 +
1382 +/* Ep0 standard request handlers. These always run in_irq. */
1383 +
1384 +static int standard_setup_req(struct fsg_dev *fsg,
1385 + const struct usb_ctrlrequest *ctrl)
1386 +{
1387 + struct usb_request *req = fsg->ep0req;
1388 + int value = -EOPNOTSUPP;
1389 + u16 w_index = le16_to_cpu(ctrl->wIndex);
1390 + u16 w_value = le16_to_cpu(ctrl->wValue);
1391 +
1392 + /* Usually this just stores reply data in the pre-allocated ep0 buffer,
1393 + * but config change events will also reconfigure hardware. */
1394 + switch (ctrl->bRequest) {
1395 +
1396 + case USB_REQ_GET_DESCRIPTOR:
1397 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1398 + USB_RECIP_DEVICE))
1399 + break;
1400 + switch (w_value >> 8) {
1401 +
1402 + case USB_DT_DEVICE:
1403 + VDBG(fsg, "get device descriptor\n");
1404 + device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
1405 + value = sizeof device_desc;
1406 + memcpy(req->buf, &device_desc, value);
1407 + break;
1408 + case USB_DT_DEVICE_QUALIFIER:
1409 + VDBG(fsg, "get device qualifier\n");
1410 + if (!gadget_is_dualspeed(fsg->gadget) ||
1411 + fsg->gadget->speed == USB_SPEED_SUPER)
1412 + break;
1413 + /*
1414 + * Assume ep0 uses the same maxpacket value for both
1415 + * speeds
1416 + */
1417 + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
1418 + value = sizeof dev_qualifier;
1419 + memcpy(req->buf, &dev_qualifier, value);
1420 + break;
1421 +
1422 + case USB_DT_OTHER_SPEED_CONFIG:
1423 + VDBG(fsg, "get other-speed config descriptor\n");
1424 + if (!gadget_is_dualspeed(fsg->gadget) ||
1425 + fsg->gadget->speed == USB_SPEED_SUPER)
1426 + break;
1427 + goto get_config;
1428 + case USB_DT_CONFIG:
1429 + VDBG(fsg, "get configuration descriptor\n");
1430 +get_config:
1431 + value = populate_config_buf(fsg->gadget,
1432 + req->buf,
1433 + w_value >> 8,
1434 + w_value & 0xff);
1435 + break;
1436 +
1437 + case USB_DT_STRING:
1438 + VDBG(fsg, "get string descriptor\n");
1439 +
1440 + /* wIndex == language code */
1441 + value = usb_gadget_get_string(&fsg_stringtab,
1442 + w_value & 0xff, req->buf);
1443 + break;
1444 +
1445 + case USB_DT_BOS:
1446 + VDBG(fsg, "get bos descriptor\n");
1447 +
1448 + if (gadget_is_superspeed(fsg->gadget))
1449 + value = populate_bos(fsg, req->buf);
1450 + break;
1451 + }
1452 +
1453 + break;
1454 +
1455 + /* One config, two speeds */
1456 + case USB_REQ_SET_CONFIGURATION:
1457 + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
1458 + USB_RECIP_DEVICE))
1459 + break;
1460 + VDBG(fsg, "set configuration\n");
1461 + if (w_value == CONFIG_VALUE || w_value == 0) {
1462 + fsg->new_config = w_value;
1463 +
1464 + /* Raise an exception to wipe out previous transaction
1465 + * state (queued bufs, etc) and set the new config. */
1466 + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
1467 + value = DELAYED_STATUS;
1468 + }
1469 + break;
1470 + case USB_REQ_GET_CONFIGURATION:
1471 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1472 + USB_RECIP_DEVICE))
1473 + break;
1474 + VDBG(fsg, "get configuration\n");
1475 + *(u8 *) req->buf = fsg->config;
1476 + value = 1;
1477 + break;
1478 +
1479 + case USB_REQ_SET_INTERFACE:
1480 + if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
1481 + USB_RECIP_INTERFACE))
1482 + break;
1483 + if (fsg->config && w_index == 0) {
1484 +
1485 + /* Raise an exception to wipe out previous transaction
1486 + * state (queued bufs, etc) and install the new
1487 + * interface altsetting. */
1488 + raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
1489 + value = DELAYED_STATUS;
1490 + }
1491 + break;
1492 + case USB_REQ_GET_INTERFACE:
1493 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1494 + USB_RECIP_INTERFACE))
1495 + break;
1496 + if (!fsg->config)
1497 + break;
1498 + if (w_index != 0) {
1499 + value = -EDOM;
1500 + break;
1501 + }
1502 + VDBG(fsg, "get interface\n");
1503 + *(u8 *) req->buf = 0;
1504 + value = 1;
1505 + break;
1506 +
1507 + default:
1508 + VDBG(fsg,
1509 + "unknown control req %02x.%02x v%04x i%04x l%u\n",
1510 + ctrl->bRequestType, ctrl->bRequest,
1511 + w_value, w_index, le16_to_cpu(ctrl->wLength));
1512 + }
1513 +
1514 + return value;
1515 +}
1516 +
1517 +
1518 +static int fsg_setup(struct usb_gadget *gadget,
1519 + const struct usb_ctrlrequest *ctrl)
1520 +{
1521 + struct fsg_dev *fsg = get_gadget_data(gadget);
1522 + int rc;
1523 + int w_length = le16_to_cpu(ctrl->wLength);
1524 +
1525 + ++fsg->ep0_req_tag; // Record arrival of a new request
1526 + fsg->ep0req->context = NULL;
1527 + fsg->ep0req->length = 0;
1528 + dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
1529 +
1530 + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
1531 + rc = class_setup_req(fsg, ctrl);
1532 + else
1533 + rc = standard_setup_req(fsg, ctrl);
1534 +
1535 + /* Respond with data/status or defer until later? */
1536 + if (rc >= 0 && rc != DELAYED_STATUS) {
1537 + rc = min(rc, w_length);
1538 + fsg->ep0req->length = rc;
1539 + fsg->ep0req->zero = rc < w_length;
1540 + fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
1541 + "ep0-in" : "ep0-out");
1542 + rc = ep0_queue(fsg);
1543 + }
1544 +
1545 + /* Device either stalls (rc < 0) or reports success */
1546 + return rc;
1547 +}
1548 +
1549 +
1550 +/*-------------------------------------------------------------------------*/
1551 +
1552 +/* All the following routines run in process context */
1553 +
1554 +
1555 +/* Use this for bulk or interrupt transfers, not ep0 */
1556 +static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
1557 + struct usb_request *req, int *pbusy,
1558 + enum fsg_buffer_state *state)
1559 +{
1560 + int rc;
1561 +
1562 + if (ep == fsg->bulk_in)
1563 + dump_msg(fsg, "bulk-in", req->buf, req->length);
1564 + else if (ep == fsg->intr_in)
1565 + dump_msg(fsg, "intr-in", req->buf, req->length);
1566 +
1567 + spin_lock_irq(&fsg->lock);
1568 + *pbusy = 1;
1569 + *state = BUF_STATE_BUSY;
1570 + spin_unlock_irq(&fsg->lock);
1571 + rc = usb_ep_queue(ep, req, GFP_KERNEL);
1572 + if (rc != 0) {
1573 + *pbusy = 0;
1574 + *state = BUF_STATE_EMPTY;
1575 +
1576 + /* We can't do much more than wait for a reset */
1577 +
1578 + /* Note: currently the net2280 driver fails zero-length
1579 + * submissions if DMA is enabled. */
1580 + if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
1581 + req->length == 0))
1582 + WARNING(fsg, "error in submission: %s --> %d\n",
1583 + ep->name, rc);
1584 + }
1585 +}
1586 +
1587 +
1588 +static int sleep_thread(struct fsg_dev *fsg)
1589 +{
1590 + int rc = 0;
1591 +
1592 + /* Wait until a signal arrives or we are woken up */
1593 + for (;;) {
1594 + try_to_freeze();
1595 + set_current_state(TASK_INTERRUPTIBLE);
1596 + if (signal_pending(current)) {
1597 + rc = -EINTR;
1598 + break;
1599 + }
1600 + if (fsg->thread_wakeup_needed)
1601 + break;
1602 + schedule();
1603 + }
1604 + __set_current_state(TASK_RUNNING);
1605 + fsg->thread_wakeup_needed = 0;
1606 + return rc;
1607 +}
1608 +
1609 +
1610 +/*-------------------------------------------------------------------------*/
1611 +
1612 +static int do_read(struct fsg_dev *fsg)
1613 +{
1614 + struct fsg_lun *curlun = fsg->curlun;
1615 + u32 lba;
1616 + struct fsg_buffhd *bh;
1617 + int rc;
1618 + u32 amount_left;
1619 + loff_t file_offset, file_offset_tmp;
1620 + unsigned int amount;
1621 + ssize_t nread;
1622 +
1623 + /* Get the starting Logical Block Address and check that it's
1624 + * not too big */
1625 + if (fsg->cmnd[0] == READ_6)
1626 + lba = get_unaligned_be24(&fsg->cmnd[1]);
1627 + else {
1628 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1629 +
1630 + /* We allow DPO (Disable Page Out = don't save data in the
1631 + * cache) and FUA (Force Unit Access = don't read from the
1632 + * cache), but we don't implement them. */
1633 + if ((fsg->cmnd[1] & ~0x18) != 0) {
1634 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1635 + return -EINVAL;
1636 + }
1637 + }
1638 + if (lba >= curlun->num_sectors) {
1639 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1640 + return -EINVAL;
1641 + }
1642 + file_offset = ((loff_t) lba) << curlun->blkbits;
1643 +
1644 + /* Carry out the file reads */
1645 + amount_left = fsg->data_size_from_cmnd;
1646 + if (unlikely(amount_left == 0))
1647 + return -EIO; // No default reply
1648 +
1649 + for (;;) {
1650 +
1651 + /* Figure out how much we need to read:
1652 + * Try to read the remaining amount.
1653 + * But don't read more than the buffer size.
1654 + * And don't try to read past the end of the file.
1655 + */
1656 + amount = min((unsigned int) amount_left, mod_data.buflen);
1657 + amount = min((loff_t) amount,
1658 + curlun->file_length - file_offset);
1659 +
1660 + /* Wait for the next buffer to become available */
1661 + bh = fsg->next_buffhd_to_fill;
1662 + while (bh->state != BUF_STATE_EMPTY) {
1663 + rc = sleep_thread(fsg);
1664 + if (rc)
1665 + return rc;
1666 + }
1667 +
1668 + /* If we were asked to read past the end of file,
1669 + * end with an empty buffer. */
1670 + if (amount == 0) {
1671 + curlun->sense_data =
1672 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1673 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1674 + curlun->info_valid = 1;
1675 + bh->inreq->length = 0;
1676 + bh->state = BUF_STATE_FULL;
1677 + break;
1678 + }
1679 +
1680 + /* Perform the read */
1681 + file_offset_tmp = file_offset;
1682 + nread = vfs_read(curlun->filp,
1683 + (char __user *) bh->buf,
1684 + amount, &file_offset_tmp);
1685 + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
1686 + (unsigned long long) file_offset,
1687 + (int) nread);
1688 + if (signal_pending(current))
1689 + return -EINTR;
1690 +
1691 + if (nread < 0) {
1692 + LDBG(curlun, "error in file read: %d\n",
1693 + (int) nread);
1694 + nread = 0;
1695 + } else if (nread < amount) {
1696 + LDBG(curlun, "partial file read: %d/%u\n",
1697 + (int) nread, amount);
1698 + nread = round_down(nread, curlun->blksize);
1699 + }
1700 + file_offset += nread;
1701 + amount_left -= nread;
1702 + fsg->residue -= nread;
1703 +
1704 + /* Except at the end of the transfer, nread will be
1705 + * equal to the buffer size, which is divisible by the
1706 + * bulk-in maxpacket size.
1707 + */
1708 + bh->inreq->length = nread;
1709 + bh->state = BUF_STATE_FULL;
1710 +
1711 + /* If an error occurred, report it and its position */
1712 + if (nread < amount) {
1713 + curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
1714 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1715 + curlun->info_valid = 1;
1716 + break;
1717 + }
1718 +
1719 + if (amount_left == 0)
1720 + break; // No more left to read
1721 +
1722 + /* Send this buffer and go read some more */
1723 + bh->inreq->zero = 0;
1724 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
1725 + &bh->inreq_busy, &bh->state);
1726 + fsg->next_buffhd_to_fill = bh->next;
1727 + }
1728 +
1729 + return -EIO; // No default reply
1730 +}
1731 +
1732 +
1733 +/*-------------------------------------------------------------------------*/
1734 +
1735 +static int do_write(struct fsg_dev *fsg)
1736 +{
1737 + struct fsg_lun *curlun = fsg->curlun;
1738 + u32 lba;
1739 + struct fsg_buffhd *bh;
1740 + int get_some_more;
1741 + u32 amount_left_to_req, amount_left_to_write;
1742 + loff_t usb_offset, file_offset, file_offset_tmp;
1743 + unsigned int amount;
1744 + ssize_t nwritten;
1745 + int rc;
1746 +
1747 + if (curlun->ro) {
1748 + curlun->sense_data = SS_WRITE_PROTECTED;
1749 + return -EINVAL;
1750 + }
1751 + spin_lock(&curlun->filp->f_lock);
1752 + curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait
1753 + spin_unlock(&curlun->filp->f_lock);
1754 +
1755 + /* Get the starting Logical Block Address and check that it's
1756 + * not too big */
1757 + if (fsg->cmnd[0] == WRITE_6)
1758 + lba = get_unaligned_be24(&fsg->cmnd[1]);
1759 + else {
1760 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1761 +
1762 + /* We allow DPO (Disable Page Out = don't save data in the
1763 + * cache) and FUA (Force Unit Access = write directly to the
1764 + * medium). We don't implement DPO; we implement FUA by
1765 + * performing synchronous output. */
1766 + if ((fsg->cmnd[1] & ~0x18) != 0) {
1767 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1768 + return -EINVAL;
1769 + }
1770 + /* FUA */
1771 + if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) {
1772 + spin_lock(&curlun->filp->f_lock);
1773 + curlun->filp->f_flags |= O_DSYNC;
1774 + spin_unlock(&curlun->filp->f_lock);
1775 + }
1776 + }
1777 + if (lba >= curlun->num_sectors) {
1778 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1779 + return -EINVAL;
1780 + }
1781 +
1782 + /* Carry out the file writes */
1783 + get_some_more = 1;
1784 + file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
1785 + amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
1786 +
1787 + while (amount_left_to_write > 0) {
1788 +
1789 + /* Queue a request for more data from the host */
1790 + bh = fsg->next_buffhd_to_fill;
1791 + if (bh->state == BUF_STATE_EMPTY && get_some_more) {
1792 +
1793 + /* Figure out how much we want to get:
1794 + * Try to get the remaining amount,
1795 + * but not more than the buffer size.
1796 + */
1797 + amount = min(amount_left_to_req, mod_data.buflen);
1798 +
1799 + /* Beyond the end of the backing file? */
1800 + if (usb_offset >= curlun->file_length) {
1801 + get_some_more = 0;
1802 + curlun->sense_data =
1803 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1804 + curlun->sense_data_info = usb_offset >> curlun->blkbits;
1805 + curlun->info_valid = 1;
1806 + continue;
1807 + }
1808 +
1809 + /* Get the next buffer */
1810 + usb_offset += amount;
1811 + fsg->usb_amount_left -= amount;
1812 + amount_left_to_req -= amount;
1813 + if (amount_left_to_req == 0)
1814 + get_some_more = 0;
1815 +
1816 + /* Except at the end of the transfer, amount will be
1817 + * equal to the buffer size, which is divisible by
1818 + * the bulk-out maxpacket size.
1819 + */
1820 + set_bulk_out_req_length(fsg, bh, amount);
1821 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
1822 + &bh->outreq_busy, &bh->state);
1823 + fsg->next_buffhd_to_fill = bh->next;
1824 + continue;
1825 + }
1826 +
1827 + /* Write the received data to the backing file */
1828 + bh = fsg->next_buffhd_to_drain;
1829 + if (bh->state == BUF_STATE_EMPTY && !get_some_more)
1830 + break; // We stopped early
1831 + if (bh->state == BUF_STATE_FULL) {
1832 + smp_rmb();
1833 + fsg->next_buffhd_to_drain = bh->next;
1834 + bh->state = BUF_STATE_EMPTY;
1835 +
1836 + /* Did something go wrong with the transfer? */
1837 + if (bh->outreq->status != 0) {
1838 + curlun->sense_data = SS_COMMUNICATION_FAILURE;
1839 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1840 + curlun->info_valid = 1;
1841 + break;
1842 + }
1843 +
1844 + amount = bh->outreq->actual;
1845 + if (curlun->file_length - file_offset < amount) {
1846 + LERROR(curlun,
1847 + "write %u @ %llu beyond end %llu\n",
1848 + amount, (unsigned long long) file_offset,
1849 + (unsigned long long) curlun->file_length);
1850 + amount = curlun->file_length - file_offset;
1851 + }
1852 +
1853 + /* Don't accept excess data. The spec doesn't say
1854 + * what to do in this case. We'll ignore the error.
1855 + */
1856 + amount = min(amount, bh->bulk_out_intended_length);
1857 +
1858 + /* Don't write a partial block */
1859 + amount = round_down(amount, curlun->blksize);
1860 + if (amount == 0)
1861 + goto empty_write;
1862 +
1863 + /* Perform the write */
1864 + file_offset_tmp = file_offset;
1865 + nwritten = vfs_write(curlun->filp,
1866 + (char __user *) bh->buf,
1867 + amount, &file_offset_tmp);
1868 + VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
1869 + (unsigned long long) file_offset,
1870 + (int) nwritten);
1871 + if (signal_pending(current))
1872 + return -EINTR; // Interrupted!
1873 +
1874 + if (nwritten < 0) {
1875 + LDBG(curlun, "error in file write: %d\n",
1876 + (int) nwritten);
1877 + nwritten = 0;
1878 + } else if (nwritten < amount) {
1879 + LDBG(curlun, "partial file write: %d/%u\n",
1880 + (int) nwritten, amount);
1881 + nwritten = round_down(nwritten, curlun->blksize);
1882 + }
1883 + file_offset += nwritten;
1884 + amount_left_to_write -= nwritten;
1885 + fsg->residue -= nwritten;
1886 +
1887 + /* If an error occurred, report it and its position */
1888 + if (nwritten < amount) {
1889 + curlun->sense_data = SS_WRITE_ERROR;
1890 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1891 + curlun->info_valid = 1;
1892 + break;
1893 + }
1894 +
1895 + empty_write:
1896 + /* Did the host decide to stop early? */
1897 + if (bh->outreq->actual < bh->bulk_out_intended_length) {
1898 + fsg->short_packet_received = 1;
1899 + break;
1900 + }
1901 + continue;
1902 + }
1903 +
1904 + /* Wait for something to happen */
1905 + rc = sleep_thread(fsg);
1906 + if (rc)
1907 + return rc;
1908 + }
1909 +
1910 + return -EIO; // No default reply
1911 +}
1912 +
1913 +
1914 +/*-------------------------------------------------------------------------*/
1915 +
1916 +static int do_synchronize_cache(struct fsg_dev *fsg)
1917 +{
1918 + struct fsg_lun *curlun = fsg->curlun;
1919 + int rc;
1920 +
1921 + /* We ignore the requested LBA and write out all file's
1922 + * dirty data buffers. */
1923 + rc = fsg_lun_fsync_sub(curlun);
1924 + if (rc)
1925 + curlun->sense_data = SS_WRITE_ERROR;
1926 + return 0;
1927 +}
1928 +
1929 +
1930 +/*-------------------------------------------------------------------------*/
1931 +
1932 +static void invalidate_sub(struct fsg_lun *curlun)
1933 +{
1934 + struct file *filp = curlun->filp;
1935 + struct inode *inode = filp->f_path.dentry->d_inode;
1936 + unsigned long rc;
1937 +
1938 + rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
1939 + VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
1940 +}
1941 +
1942 +static int do_verify(struct fsg_dev *fsg)
1943 +{
1944 + struct fsg_lun *curlun = fsg->curlun;
1945 + u32 lba;
1946 + u32 verification_length;
1947 + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
1948 + loff_t file_offset, file_offset_tmp;
1949 + u32 amount_left;
1950 + unsigned int amount;
1951 + ssize_t nread;
1952 +
1953 + /* Get the starting Logical Block Address and check that it's
1954 + * not too big */
1955 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1956 + if (lba >= curlun->num_sectors) {
1957 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1958 + return -EINVAL;
1959 + }
1960 +
1961 + /* We allow DPO (Disable Page Out = don't save data in the
1962 + * cache) but we don't implement it. */
1963 + if ((fsg->cmnd[1] & ~0x10) != 0) {
1964 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1965 + return -EINVAL;
1966 + }
1967 +
1968 + verification_length = get_unaligned_be16(&fsg->cmnd[7]);
1969 + if (unlikely(verification_length == 0))
1970 + return -EIO; // No default reply
1971 +
1972 + /* Prepare to carry out the file verify */
1973 + amount_left = verification_length << curlun->blkbits;
1974 + file_offset = ((loff_t) lba) << curlun->blkbits;
1975 +
1976 + /* Write out all the dirty buffers before invalidating them */
1977 + fsg_lun_fsync_sub(curlun);
1978 + if (signal_pending(current))
1979 + return -EINTR;
1980 +
1981 + invalidate_sub(curlun);
1982 + if (signal_pending(current))
1983 + return -EINTR;
1984 +
1985 + /* Just try to read the requested blocks */
1986 + while (amount_left > 0) {
1987 +
1988 + /* Figure out how much we need to read:
1989 + * Try to read the remaining amount, but not more than
1990 + * the buffer size.
1991 + * And don't try to read past the end of the file.
1992 + */
1993 + amount = min((unsigned int) amount_left, mod_data.buflen);
1994 + amount = min((loff_t) amount,
1995 + curlun->file_length - file_offset);
1996 + if (amount == 0) {
1997 + curlun->sense_data =
1998 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1999 + curlun->sense_data_info = file_offset >> curlun->blkbits;
2000 + curlun->info_valid = 1;
2001 + break;
2002 + }
2003 +
2004 + /* Perform the read */
2005 + file_offset_tmp = file_offset;
2006 + nread = vfs_read(curlun->filp,
2007 + (char __user *) bh->buf,
2008 + amount, &file_offset_tmp);
2009 + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
2010 + (unsigned long long) file_offset,
2011 + (int) nread);
2012 + if (signal_pending(current))
2013 + return -EINTR;
2014 +
2015 + if (nread < 0) {
2016 + LDBG(curlun, "error in file verify: %d\n",
2017 + (int) nread);
2018 + nread = 0;
2019 + } else if (nread < amount) {
2020 + LDBG(curlun, "partial file verify: %d/%u\n",
2021 + (int) nread, amount);
2022 + nread = round_down(nread, curlun->blksize);
2023 + }
2024 + if (nread == 0) {
2025 + curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
2026 + curlun->sense_data_info = file_offset >> curlun->blkbits;
2027 + curlun->info_valid = 1;
2028 + break;
2029 + }
2030 + file_offset += nread;
2031 + amount_left -= nread;
2032 + }
2033 + return 0;
2034 +}
2035 +
2036 +
2037 +/*-------------------------------------------------------------------------*/
2038 +
2039 +static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2040 +{
2041 + u8 *buf = (u8 *) bh->buf;
2042 +
2043 + static char vendor_id[] = "Linux ";
2044 + static char product_disk_id[] = "File-Stor Gadget";
2045 + static char product_cdrom_id[] = "File-CD Gadget ";
2046 +
2047 + if (!fsg->curlun) { // Unsupported LUNs are okay
2048 + fsg->bad_lun_okay = 1;
2049 + memset(buf, 0, 36);
2050 + buf[0] = 0x7f; // Unsupported, no device-type
2051 + buf[4] = 31; // Additional length
2052 + return 36;
2053 + }
2054 +
2055 + memset(buf, 0, 8);
2056 + buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK);
2057 + if (mod_data.removable)
2058 + buf[1] = 0x80;
2059 + buf[2] = 2; // ANSI SCSI level 2
2060 + buf[3] = 2; // SCSI-2 INQUIRY data format
2061 + buf[4] = 31; // Additional length
2062 + // No special options
2063 + sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
2064 + (mod_data.cdrom ? product_cdrom_id :
2065 + product_disk_id),
2066 + mod_data.release);
2067 + return 36;
2068 +}
2069 +
2070 +
2071 +static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2072 +{
2073 + struct fsg_lun *curlun = fsg->curlun;
2074 + u8 *buf = (u8 *) bh->buf;
2075 + u32 sd, sdinfo;
2076 + int valid;
2077 +
2078 + /*
2079 + * From the SCSI-2 spec., section 7.9 (Unit attention condition):
2080 + *
2081 + * If a REQUEST SENSE command is received from an initiator
2082 + * with a pending unit attention condition (before the target
2083 + * generates the contingent allegiance condition), then the
2084 + * target shall either:
2085 + * a) report any pending sense data and preserve the unit
2086 + * attention condition on the logical unit, or,
2087 + * b) report the unit attention condition, may discard any
2088 + * pending sense data, and clear the unit attention
2089 + * condition on the logical unit for that initiator.
2090 + *
2091 + * FSG normally uses option a); enable this code to use option b).
2092 + */
2093 +#if 0
2094 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
2095 + curlun->sense_data = curlun->unit_attention_data;
2096 + curlun->unit_attention_data = SS_NO_SENSE;
2097 + }
2098 +#endif
2099 +
2100 + if (!curlun) { // Unsupported LUNs are okay
2101 + fsg->bad_lun_okay = 1;
2102 + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
2103 + sdinfo = 0;
2104 + valid = 0;
2105 + } else {
2106 + sd = curlun->sense_data;
2107 + sdinfo = curlun->sense_data_info;
2108 + valid = curlun->info_valid << 7;
2109 + curlun->sense_data = SS_NO_SENSE;
2110 + curlun->sense_data_info = 0;
2111 + curlun->info_valid = 0;
2112 + }
2113 +
2114 + memset(buf, 0, 18);
2115 + buf[0] = valid | 0x70; // Valid, current error
2116 + buf[2] = SK(sd);
2117 + put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */
2118 + buf[7] = 18 - 8; // Additional sense length
2119 + buf[12] = ASC(sd);
2120 + buf[13] = ASCQ(sd);
2121 + return 18;
2122 +}
2123 +
2124 +
2125 +static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2126 +{
2127 + struct fsg_lun *curlun = fsg->curlun;
2128 + u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
2129 + int pmi = fsg->cmnd[8];
2130 + u8 *buf = (u8 *) bh->buf;
2131 +
2132 + /* Check the PMI and LBA fields */
2133 + if (pmi > 1 || (pmi == 0 && lba != 0)) {
2134 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2135 + return -EINVAL;
2136 + }
2137 +
2138 + put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
2139 + /* Max logical block */
2140 + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
2141 + return 8;
2142 +}
2143 +
2144 +
2145 +static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2146 +{
2147 + struct fsg_lun *curlun = fsg->curlun;
2148 + int msf = fsg->cmnd[1] & 0x02;
2149 + u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
2150 + u8 *buf = (u8 *) bh->buf;
2151 +
2152 + if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
2153 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2154 + return -EINVAL;
2155 + }
2156 + if (lba >= curlun->num_sectors) {
2157 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
2158 + return -EINVAL;
2159 + }
2160 +
2161 + memset(buf, 0, 8);
2162 + buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */
2163 + store_cdrom_address(&buf[4], msf, lba);
2164 + return 8;
2165 +}
2166 +
2167 +
2168 +static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2169 +{
2170 + struct fsg_lun *curlun = fsg->curlun;
2171 + int msf = fsg->cmnd[1] & 0x02;
2172 + int start_track = fsg->cmnd[6];
2173 + u8 *buf = (u8 *) bh->buf;
2174 +
2175 + if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
2176 + start_track > 1) {
2177 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2178 + return -EINVAL;
2179 + }
2180 +
2181 + memset(buf, 0, 20);
2182 + buf[1] = (20-2); /* TOC data length */
2183 + buf[2] = 1; /* First track number */
2184 + buf[3] = 1; /* Last track number */
2185 + buf[5] = 0x16; /* Data track, copying allowed */
2186 + buf[6] = 0x01; /* Only track is number 1 */
2187 + store_cdrom_address(&buf[8], msf, 0);
2188 +
2189 + buf[13] = 0x16; /* Lead-out track is data */
2190 + buf[14] = 0xAA; /* Lead-out track number */
2191 + store_cdrom_address(&buf[16], msf, curlun->num_sectors);
2192 + return 20;
2193 +}
2194 +
2195 +
2196 +static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2197 +{
2198 + struct fsg_lun *curlun = fsg->curlun;
2199 + int mscmnd = fsg->cmnd[0];
2200 + u8 *buf = (u8 *) bh->buf;
2201 + u8 *buf0 = buf;
2202 + int pc, page_code;
2203 + int changeable_values, all_pages;
2204 + int valid_page = 0;
2205 + int len, limit;
2206 +
2207 + if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD
2208 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2209 + return -EINVAL;
2210 + }
2211 + pc = fsg->cmnd[2] >> 6;
2212 + page_code = fsg->cmnd[2] & 0x3f;
2213 + if (pc == 3) {
2214 + curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
2215 + return -EINVAL;
2216 + }
2217 + changeable_values = (pc == 1);
2218 + all_pages = (page_code == 0x3f);
2219 +
2220 + /* Write the mode parameter header. Fixed values are: default
2221 + * medium type, no cache control (DPOFUA), and no block descriptors.
2222 + * The only variable value is the WriteProtect bit. We will fill in
2223 + * the mode data length later. */
2224 + memset(buf, 0, 8);
2225 + if (mscmnd == MODE_SENSE) {
2226 + buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
2227 + buf += 4;
2228 + limit = 255;
2229 + } else { // MODE_SENSE_10
2230 + buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
2231 + buf += 8;
2232 + limit = 65535; // Should really be mod_data.buflen
2233 + }
2234 +
2235 + /* No block descriptors */
2236 +
2237 + /* The mode pages, in numerical order. The only page we support
2238 + * is the Caching page. */
2239 + if (page_code == 0x08 || all_pages) {
2240 + valid_page = 1;
2241 + buf[0] = 0x08; // Page code
2242 + buf[1] = 10; // Page length
2243 + memset(buf+2, 0, 10); // None of the fields are changeable
2244 +
2245 + if (!changeable_values) {
2246 + buf[2] = 0x04; // Write cache enable,
2247 + // Read cache not disabled
2248 + // No cache retention priorities
2249 + put_unaligned_be16(0xffff, &buf[4]);
2250 + /* Don't disable prefetch */
2251 + /* Minimum prefetch = 0 */
2252 + put_unaligned_be16(0xffff, &buf[8]);
2253 + /* Maximum prefetch */
2254 + put_unaligned_be16(0xffff, &buf[10]);
2255 + /* Maximum prefetch ceiling */
2256 + }
2257 + buf += 12;
2258 + }
2259 +
2260 + /* Check that a valid page was requested and the mode data length
2261 + * isn't too long. */
2262 + len = buf - buf0;
2263 + if (!valid_page || len > limit) {
2264 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2265 + return -EINVAL;
2266 + }
2267 +
2268 + /* Store the mode data length */
2269 + if (mscmnd == MODE_SENSE)
2270 + buf0[0] = len - 1;
2271 + else
2272 + put_unaligned_be16(len - 2, buf0);
2273 + return len;
2274 +}
2275 +
2276 +
2277 +static int do_start_stop(struct fsg_dev *fsg)
2278 +{
2279 + struct fsg_lun *curlun = fsg->curlun;
2280 + int loej, start;
2281 +
2282 + if (!mod_data.removable) {
2283 + curlun->sense_data = SS_INVALID_COMMAND;
2284 + return -EINVAL;
2285 + }
2286 +
2287 + // int immed = fsg->cmnd[1] & 0x01;
2288 + loej = fsg->cmnd[4] & 0x02;
2289 + start = fsg->cmnd[4] & 0x01;
2290 +
2291 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
2292 + if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed
2293 + (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start
2294 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2295 + return -EINVAL;
2296 + }
2297 +
2298 + if (!start) {
2299 +
2300 + /* Are we allowed to unload the media? */
2301 + if (curlun->prevent_medium_removal) {
2302 + LDBG(curlun, "unload attempt prevented\n");
2303 + curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
2304 + return -EINVAL;
2305 + }
2306 + if (loej) { // Simulate an unload/eject
2307 + up_read(&fsg->filesem);
2308 + down_write(&fsg->filesem);
2309 + fsg_lun_close(curlun);
2310 + up_write(&fsg->filesem);
2311 + down_read(&fsg->filesem);
2312 + }
2313 + } else {
2314 +
2315 + /* Our emulation doesn't support mounting; the medium is
2316 + * available for use as soon as it is loaded. */
2317 + if (!fsg_lun_is_open(curlun)) {
2318 + curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
2319 + return -EINVAL;
2320 + }
2321 + }
2322 +#endif
2323 + return 0;
2324 +}
2325 +
2326 +
2327 +static int do_prevent_allow(struct fsg_dev *fsg)
2328 +{
2329 + struct fsg_lun *curlun = fsg->curlun;
2330 + int prevent;
2331 +
2332 + if (!mod_data.removable) {
2333 + curlun->sense_data = SS_INVALID_COMMAND;
2334 + return -EINVAL;
2335 + }
2336 +
2337 + prevent = fsg->cmnd[4] & 0x01;
2338 + if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent
2339 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2340 + return -EINVAL;
2341 + }
2342 +
2343 + if (curlun->prevent_medium_removal && !prevent)
2344 + fsg_lun_fsync_sub(curlun);
2345 + curlun->prevent_medium_removal = prevent;
2346 + return 0;
2347 +}
2348 +
2349 +
2350 +static int do_read_format_capacities(struct fsg_dev *fsg,
2351 + struct fsg_buffhd *bh)
2352 +{
2353 + struct fsg_lun *curlun = fsg->curlun;
2354 + u8 *buf = (u8 *) bh->buf;
2355 +
2356 + buf[0] = buf[1] = buf[2] = 0;
2357 + buf[3] = 8; // Only the Current/Maximum Capacity Descriptor
2358 + buf += 4;
2359 +
2360 + put_unaligned_be32(curlun->num_sectors, &buf[0]);
2361 + /* Number of blocks */
2362 + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
2363 + buf[4] = 0x02; /* Current capacity */
2364 + return 12;
2365 +}
2366 +
2367 +
2368 +static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2369 +{
2370 + struct fsg_lun *curlun = fsg->curlun;
2371 +
2372 + /* We don't support MODE SELECT */
2373 + curlun->sense_data = SS_INVALID_COMMAND;
2374 + return -EINVAL;
2375 +}
2376 +
2377 +
2378 +/*-------------------------------------------------------------------------*/
2379 +
2380 +static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
2381 +{
2382 + int rc;
2383 +
2384 + rc = fsg_set_halt(fsg, fsg->bulk_in);
2385 + if (rc == -EAGAIN)
2386 + VDBG(fsg, "delayed bulk-in endpoint halt\n");
2387 + while (rc != 0) {
2388 + if (rc != -EAGAIN) {
2389 + WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
2390 + rc = 0;
2391 + break;
2392 + }
2393 +
2394 + /* Wait for a short time and then try again */
2395 + if (msleep_interruptible(100) != 0)
2396 + return -EINTR;
2397 + rc = usb_ep_set_halt(fsg->bulk_in);
2398 + }
2399 + return rc;
2400 +}
2401 +
2402 +static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
2403 +{
2404 + int rc;
2405 +
2406 + DBG(fsg, "bulk-in set wedge\n");
2407 + rc = usb_ep_set_wedge(fsg->bulk_in);
2408 + if (rc == -EAGAIN)
2409 + VDBG(fsg, "delayed bulk-in endpoint wedge\n");
2410 + while (rc != 0) {
2411 + if (rc != -EAGAIN) {
2412 + WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
2413 + rc = 0;
2414 + break;
2415 + }
2416 +
2417 + /* Wait for a short time and then try again */
2418 + if (msleep_interruptible(100) != 0)
2419 + return -EINTR;
2420 + rc = usb_ep_set_wedge(fsg->bulk_in);
2421 + }
2422 + return rc;
2423 +}
2424 +
2425 +static int throw_away_data(struct fsg_dev *fsg)
2426 +{
2427 + struct fsg_buffhd *bh;
2428 + u32 amount;
2429 + int rc;
2430 +
2431 + while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY ||
2432 + fsg->usb_amount_left > 0) {
2433 +
2434 + /* Throw away the data in a filled buffer */
2435 + if (bh->state == BUF_STATE_FULL) {
2436 + smp_rmb();
2437 + bh->state = BUF_STATE_EMPTY;
2438 + fsg->next_buffhd_to_drain = bh->next;
2439 +
2440 + /* A short packet or an error ends everything */
2441 + if (bh->outreq->actual < bh->bulk_out_intended_length ||
2442 + bh->outreq->status != 0) {
2443 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2444 + return -EINTR;
2445 + }
2446 + continue;
2447 + }
2448 +
2449 + /* Try to submit another request if we need one */
2450 + bh = fsg->next_buffhd_to_fill;
2451 + if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
2452 + amount = min(fsg->usb_amount_left,
2453 + (u32) mod_data.buflen);
2454 +
2455 + /* Except at the end of the transfer, amount will be
2456 + * equal to the buffer size, which is divisible by
2457 + * the bulk-out maxpacket size.
2458 + */
2459 + set_bulk_out_req_length(fsg, bh, amount);
2460 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
2461 + &bh->outreq_busy, &bh->state);
2462 + fsg->next_buffhd_to_fill = bh->next;
2463 + fsg->usb_amount_left -= amount;
2464 + continue;
2465 + }
2466 +
2467 + /* Otherwise wait for something to happen */
2468 + rc = sleep_thread(fsg);
2469 + if (rc)
2470 + return rc;
2471 + }
2472 + return 0;
2473 +}
2474 +
2475 +
2476 +static int finish_reply(struct fsg_dev *fsg)
2477 +{
2478 + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
2479 + int rc = 0;
2480 +
2481 + switch (fsg->data_dir) {
2482 + case DATA_DIR_NONE:
2483 + break; // Nothing to send
2484 +
2485 + /* If we don't know whether the host wants to read or write,
2486 + * this must be CB or CBI with an unknown command. We mustn't
2487 + * try to send or receive any data. So stall both bulk pipes
2488 + * if we can and wait for a reset. */
2489 + case DATA_DIR_UNKNOWN:
2490 + if (mod_data.can_stall) {
2491 + fsg_set_halt(fsg, fsg->bulk_out);
2492 + rc = halt_bulk_in_endpoint(fsg);
2493 + }
2494 + break;
2495 +
2496 + /* All but the last buffer of data must have already been sent */
2497 + case DATA_DIR_TO_HOST:
2498 + if (fsg->data_size == 0)
2499 + ; // Nothing to send
2500 +
2501 + /* If there's no residue, simply send the last buffer */
2502 + else if (fsg->residue == 0) {
2503 + bh->inreq->zero = 0;
2504 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2505 + &bh->inreq_busy, &bh->state);
2506 + fsg->next_buffhd_to_fill = bh->next;
2507 + }
2508 +
2509 + /* There is a residue. For CB and CBI, simply mark the end
2510 + * of the data with a short packet. However, if we are
2511 + * allowed to stall, there was no data at all (residue ==
2512 + * data_size), and the command failed (invalid LUN or
2513 + * sense data is set), then halt the bulk-in endpoint
2514 + * instead. */
2515 + else if (!transport_is_bbb()) {
2516 + if (mod_data.can_stall &&
2517 + fsg->residue == fsg->data_size &&
2518 + (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) {
2519 + bh->state = BUF_STATE_EMPTY;
2520 + rc = halt_bulk_in_endpoint(fsg);
2521 + } else {
2522 + bh->inreq->zero = 1;
2523 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2524 + &bh->inreq_busy, &bh->state);
2525 + fsg->next_buffhd_to_fill = bh->next;
2526 + }
2527 + }
2528 +
2529 + /*
2530 + * For Bulk-only, mark the end of the data with a short
2531 + * packet. If we are allowed to stall, halt the bulk-in
2532 + * endpoint. (Note: This violates the Bulk-Only Transport
2533 + * specification, which requires us to pad the data if we
2534 + * don't halt the endpoint. Presumably nobody will mind.)
2535 + */
2536 + else {
2537 + bh->inreq->zero = 1;
2538 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2539 + &bh->inreq_busy, &bh->state);
2540 + fsg->next_buffhd_to_fill = bh->next;
2541 + if (mod_data.can_stall)
2542 + rc = halt_bulk_in_endpoint(fsg);
2543 + }
2544 + break;
2545 +
2546 + /* We have processed all we want from the data the host has sent.
2547 + * There may still be outstanding bulk-out requests. */
2548 + case DATA_DIR_FROM_HOST:
2549 + if (fsg->residue == 0)
2550 + ; // Nothing to receive
2551 +
2552 + /* Did the host stop sending unexpectedly early? */
2553 + else if (fsg->short_packet_received) {
2554 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2555 + rc = -EINTR;
2556 + }
2557 +
2558 + /* We haven't processed all the incoming data. Even though
2559 + * we may be allowed to stall, doing so would cause a race.
2560 + * The controller may already have ACK'ed all the remaining
2561 + * bulk-out packets, in which case the host wouldn't see a
2562 + * STALL. Not realizing the endpoint was halted, it wouldn't
2563 + * clear the halt -- leading to problems later on. */
2564 +#if 0
2565 + else if (mod_data.can_stall) {
2566 + fsg_set_halt(fsg, fsg->bulk_out);
2567 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2568 + rc = -EINTR;
2569 + }
2570 +#endif
2571 +
2572 + /* We can't stall. Read in the excess data and throw it
2573 + * all away. */
2574 + else
2575 + rc = throw_away_data(fsg);
2576 + break;
2577 + }
2578 + return rc;
2579 +}
2580 +
2581 +
2582 +static int send_status(struct fsg_dev *fsg)
2583 +{
2584 + struct fsg_lun *curlun = fsg->curlun;
2585 + struct fsg_buffhd *bh;
2586 + int rc;
2587 + u8 status = US_BULK_STAT_OK;
2588 + u32 sd, sdinfo = 0;
2589 +
2590 + /* Wait for the next buffer to become available */
2591 + bh = fsg->next_buffhd_to_fill;
2592 + while (bh->state != BUF_STATE_EMPTY) {
2593 + rc = sleep_thread(fsg);
2594 + if (rc)
2595 + return rc;
2596 + }
2597 +
2598 + if (curlun) {
2599 + sd = curlun->sense_data;
2600 + sdinfo = curlun->sense_data_info;
2601 + } else if (fsg->bad_lun_okay)
2602 + sd = SS_NO_SENSE;
2603 + else
2604 + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
2605 +
2606 + if (fsg->phase_error) {
2607 + DBG(fsg, "sending phase-error status\n");
2608 + status = US_BULK_STAT_PHASE;
2609 + sd = SS_INVALID_COMMAND;
2610 + } else if (sd != SS_NO_SENSE) {
2611 + DBG(fsg, "sending command-failure status\n");
2612 + status = US_BULK_STAT_FAIL;
2613 + VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
2614 + " info x%x\n",
2615 + SK(sd), ASC(sd), ASCQ(sd), sdinfo);
2616 + }
2617 +
2618 + if (transport_is_bbb()) {
2619 + struct bulk_cs_wrap *csw = bh->buf;
2620 +
2621 + /* Store and send the Bulk-only CSW */
2622 + csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
2623 + csw->Tag = fsg->tag;
2624 + csw->Residue = cpu_to_le32(fsg->residue);
2625 + csw->Status = status;
2626 +
2627 + bh->inreq->length = US_BULK_CS_WRAP_LEN;
2628 + bh->inreq->zero = 0;
2629 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2630 + &bh->inreq_busy, &bh->state);
2631 +
2632 + } else if (mod_data.transport_type == USB_PR_CB) {
2633 +
2634 + /* Control-Bulk transport has no status phase! */
2635 + return 0;
2636 +
2637 + } else { // USB_PR_CBI
2638 + struct interrupt_data *buf = bh->buf;
2639 +
2640 + /* Store and send the Interrupt data. UFI sends the ASC
2641 + * and ASCQ bytes. Everything else sends a Type (which
2642 + * is always 0) and the status Value. */
2643 + if (mod_data.protocol_type == USB_SC_UFI) {
2644 + buf->bType = ASC(sd);
2645 + buf->bValue = ASCQ(sd);
2646 + } else {
2647 + buf->bType = 0;
2648 + buf->bValue = status;
2649 + }
2650 + fsg->intreq->length = CBI_INTERRUPT_DATA_LEN;
2651 +
2652 + fsg->intr_buffhd = bh; // Point to the right buffhd
2653 + fsg->intreq->buf = bh->inreq->buf;
2654 + fsg->intreq->context = bh;
2655 + start_transfer(fsg, fsg->intr_in, fsg->intreq,
2656 + &fsg->intreq_busy, &bh->state);
2657 + }
2658 +
2659 + fsg->next_buffhd_to_fill = bh->next;
2660 + return 0;
2661 +}
2662 +
2663 +
2664 +/*-------------------------------------------------------------------------*/
2665 +
2666 +/* Check whether the command is properly formed and whether its data size
2667 + * and direction agree with the values we already have. */
2668 +static int check_command(struct fsg_dev *fsg, int cmnd_size,
2669 + enum data_direction data_dir, unsigned int mask,
2670 + int needs_medium, const char *name)
2671 +{
2672 + int i;
2673 + int lun = fsg->cmnd[1] >> 5;
2674 + static const char dirletter[4] = {'u', 'o', 'i', 'n'};
2675 + char hdlen[20];
2676 + struct fsg_lun *curlun;
2677 +
2678 + /* Adjust the expected cmnd_size for protocol encapsulation padding.
2679 + * Transparent SCSI doesn't pad. */
2680 + if (protocol_is_scsi())
2681 + ;
2682 +
2683 + /* There's some disagreement as to whether RBC pads commands or not.
2684 + * We'll play it safe and accept either form. */
2685 + else if (mod_data.protocol_type == USB_SC_RBC) {
2686 + if (fsg->cmnd_size == 12)
2687 + cmnd_size = 12;
2688 +
2689 + /* All the other protocols pad to 12 bytes */
2690 + } else
2691 + cmnd_size = 12;
2692 +
2693 + hdlen[0] = 0;
2694 + if (fsg->data_dir != DATA_DIR_UNKNOWN)
2695 + sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir],
2696 + fsg->data_size);
2697 + VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
2698 + name, cmnd_size, dirletter[(int) data_dir],
2699 + fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen);
2700 +
2701 + /* We can't reply at all until we know the correct data direction
2702 + * and size. */
2703 + if (fsg->data_size_from_cmnd == 0)
2704 + data_dir = DATA_DIR_NONE;
2705 + if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI
2706 + fsg->data_dir = data_dir;
2707 + fsg->data_size = fsg->data_size_from_cmnd;
2708 +
2709 + } else { // Bulk-only
2710 + if (fsg->data_size < fsg->data_size_from_cmnd) {
2711 +
2712 + /* Host data size < Device data size is a phase error.
2713 + * Carry out the command, but only transfer as much
2714 + * as we are allowed. */
2715 + fsg->data_size_from_cmnd = fsg->data_size;
2716 + fsg->phase_error = 1;
2717 + }
2718 + }
2719 + fsg->residue = fsg->usb_amount_left = fsg->data_size;
2720 +
2721 + /* Conflicting data directions is a phase error */
2722 + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) {
2723 + fsg->phase_error = 1;
2724 + return -EINVAL;
2725 + }
2726 +
2727 + /* Verify the length of the command itself */
2728 + if (cmnd_size != fsg->cmnd_size) {
2729 +
2730 + /* Special case workaround: There are plenty of buggy SCSI
2731 + * implementations. Many have issues with cbw->Length
2732 + * field passing a wrong command size. For those cases we
2733 + * always try to work around the problem by using the length
2734 + * sent by the host side provided it is at least as large
2735 + * as the correct command length.
2736 + * Examples of such cases would be MS-Windows, which issues
2737 + * REQUEST SENSE with cbw->Length == 12 where it should
2738 + * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
2739 + * REQUEST SENSE with cbw->Length == 10 where it should
2740 + * be 6 as well.
2741 + */
2742 + if (cmnd_size <= fsg->cmnd_size) {
2743 + DBG(fsg, "%s is buggy! Expected length %d "
2744 + "but we got %d\n", name,
2745 + cmnd_size, fsg->cmnd_size);
2746 + cmnd_size = fsg->cmnd_size;
2747 + } else {
2748 + fsg->phase_error = 1;
2749 + return -EINVAL;
2750 + }
2751 + }
2752 +
2753 + /* Check that the LUN values are consistent */
2754 + if (transport_is_bbb()) {
2755 + if (fsg->lun != lun)
2756 + DBG(fsg, "using LUN %d from CBW, "
2757 + "not LUN %d from CDB\n",
2758 + fsg->lun, lun);
2759 + }
2760 +
2761 + /* Check the LUN */
2762 + curlun = fsg->curlun;
2763 + if (curlun) {
2764 + if (fsg->cmnd[0] != REQUEST_SENSE) {
2765 + curlun->sense_data = SS_NO_SENSE;
2766 + curlun->sense_data_info = 0;
2767 + curlun->info_valid = 0;
2768 + }
2769 + } else {
2770 + fsg->bad_lun_okay = 0;
2771 +
2772 + /* INQUIRY and REQUEST SENSE commands are explicitly allowed
2773 + * to use unsupported LUNs; all others may not. */
2774 + if (fsg->cmnd[0] != INQUIRY &&
2775 + fsg->cmnd[0] != REQUEST_SENSE) {
2776 + DBG(fsg, "unsupported LUN %d\n", fsg->lun);
2777 + return -EINVAL;
2778 + }
2779 + }
2780 +
2781 + /* If a unit attention condition exists, only INQUIRY and
2782 + * REQUEST SENSE commands are allowed; anything else must fail. */
2783 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
2784 + fsg->cmnd[0] != INQUIRY &&
2785 + fsg->cmnd[0] != REQUEST_SENSE) {
2786 + curlun->sense_data = curlun->unit_attention_data;
2787 + curlun->unit_attention_data = SS_NO_SENSE;
2788 + return -EINVAL;
2789 + }
2790 +
2791 + /* Check that only command bytes listed in the mask are non-zero */
2792 + fsg->cmnd[1] &= 0x1f; // Mask away the LUN
2793 + for (i = 1; i < cmnd_size; ++i) {
2794 + if (fsg->cmnd[i] && !(mask & (1 << i))) {
2795 + if (curlun)
2796 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2797 + return -EINVAL;
2798 + }
2799 + }
2800 +
2801 + /* If the medium isn't mounted and the command needs to access
2802 + * it, return an error. */
2803 + if (curlun && !fsg_lun_is_open(curlun) && needs_medium) {
2804 + curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
2805 + return -EINVAL;
2806 + }
2807 +
2808 + return 0;
2809 +}
2810 +
2811 +/* wrapper of check_command for data size in blocks handling */
2812 +static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
2813 + enum data_direction data_dir, unsigned int mask,
2814 + int needs_medium, const char *name)
2815 +{
2816 + if (fsg->curlun)
2817 + fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
2818 + return check_command(fsg, cmnd_size, data_dir,
2819 + mask, needs_medium, name);
2820 +}
2821 +
2822 +static int do_scsi_command(struct fsg_dev *fsg)
2823 +{
2824 + struct fsg_buffhd *bh;
2825 + int rc;
2826 + int reply = -EINVAL;
2827 + int i;
2828 + static char unknown[16];
2829 +
2830 + dump_cdb(fsg);
2831 +
2832 + /* Wait for the next buffer to become available for data or status */
2833 + bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
2834 + while (bh->state != BUF_STATE_EMPTY) {
2835 + rc = sleep_thread(fsg);
2836 + if (rc)
2837 + return rc;
2838 + }
2839 + fsg->phase_error = 0;
2840 + fsg->short_packet_received = 0;
2841 +
2842 + down_read(&fsg->filesem); // We're using the backing file
2843 + switch (fsg->cmnd[0]) {
2844 +
2845 + case INQUIRY:
2846 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2847 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2848 + (1<<4), 0,
2849 + "INQUIRY")) == 0)
2850 + reply = do_inquiry(fsg, bh);
2851 + break;
2852 +
2853 + case MODE_SELECT:
2854 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2855 + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
2856 + (1<<1) | (1<<4), 0,
2857 + "MODE SELECT(6)")) == 0)
2858 + reply = do_mode_select(fsg, bh);
2859 + break;
2860 +
2861 + case MODE_SELECT_10:
2862 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2863 + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
2864 + (1<<1) | (3<<7), 0,
2865 + "MODE SELECT(10)")) == 0)
2866 + reply = do_mode_select(fsg, bh);
2867 + break;
2868 +
2869 + case MODE_SENSE:
2870 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2871 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2872 + (1<<1) | (1<<2) | (1<<4), 0,
2873 + "MODE SENSE(6)")) == 0)
2874 + reply = do_mode_sense(fsg, bh);
2875 + break;
2876 +
2877 + case MODE_SENSE_10:
2878 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2879 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2880 + (1<<1) | (1<<2) | (3<<7), 0,
2881 + "MODE SENSE(10)")) == 0)
2882 + reply = do_mode_sense(fsg, bh);
2883 + break;
2884 +
2885 + case ALLOW_MEDIUM_REMOVAL:
2886 + fsg->data_size_from_cmnd = 0;
2887 + if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
2888 + (1<<4), 0,
2889 + "PREVENT-ALLOW MEDIUM REMOVAL")) == 0)
2890 + reply = do_prevent_allow(fsg);
2891 + break;
2892 +
2893 + case READ_6:
2894 + i = fsg->cmnd[4];
2895 + fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
2896 + if ((reply = check_command_size_in_blocks(fsg, 6,
2897 + DATA_DIR_TO_HOST,
2898 + (7<<1) | (1<<4), 1,
2899 + "READ(6)")) == 0)
2900 + reply = do_read(fsg);
2901 + break;
2902 +
2903 + case READ_10:
2904 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2905 + if ((reply = check_command_size_in_blocks(fsg, 10,
2906 + DATA_DIR_TO_HOST,
2907 + (1<<1) | (0xf<<2) | (3<<7), 1,
2908 + "READ(10)")) == 0)
2909 + reply = do_read(fsg);
2910 + break;
2911 +
2912 + case READ_12:
2913 + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
2914 + if ((reply = check_command_size_in_blocks(fsg, 12,
2915 + DATA_DIR_TO_HOST,
2916 + (1<<1) | (0xf<<2) | (0xf<<6), 1,
2917 + "READ(12)")) == 0)
2918 + reply = do_read(fsg);
2919 + break;
2920 +
2921 + case READ_CAPACITY:
2922 + fsg->data_size_from_cmnd = 8;
2923 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2924 + (0xf<<2) | (1<<8), 1,
2925 + "READ CAPACITY")) == 0)
2926 + reply = do_read_capacity(fsg, bh);
2927 + break;
2928 +
2929 + case READ_HEADER:
2930 + if (!mod_data.cdrom)
2931 + goto unknown_cmnd;
2932 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2933 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2934 + (3<<7) | (0x1f<<1), 1,
2935 + "READ HEADER")) == 0)
2936 + reply = do_read_header(fsg, bh);
2937 + break;
2938 +
2939 + case READ_TOC:
2940 + if (!mod_data.cdrom)
2941 + goto unknown_cmnd;
2942 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2943 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2944 + (7<<6) | (1<<1), 1,
2945 + "READ TOC")) == 0)
2946 + reply = do_read_toc(fsg, bh);
2947 + break;
2948 +
2949 + case READ_FORMAT_CAPACITIES:
2950 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2951 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2952 + (3<<7), 1,
2953 + "READ FORMAT CAPACITIES")) == 0)
2954 + reply = do_read_format_capacities(fsg, bh);
2955 + break;
2956 +
2957 + case REQUEST_SENSE:
2958 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2959 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2960 + (1<<4), 0,
2961 + "REQUEST SENSE")) == 0)
2962 + reply = do_request_sense(fsg, bh);
2963 + break;
2964 +
2965 + case START_STOP:
2966 + fsg->data_size_from_cmnd = 0;
2967 + if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
2968 + (1<<1) | (1<<4), 0,
2969 + "START-STOP UNIT")) == 0)
2970 + reply = do_start_stop(fsg);
2971 + break;
2972 +
2973 + case SYNCHRONIZE_CACHE:
2974 + fsg->data_size_from_cmnd = 0;
2975 + if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
2976 + (0xf<<2) | (3<<7), 1,
2977 + "SYNCHRONIZE CACHE")) == 0)
2978 + reply = do_synchronize_cache(fsg);
2979 + break;
2980 +
2981 + case TEST_UNIT_READY:
2982 + fsg->data_size_from_cmnd = 0;
2983 + reply = check_command(fsg, 6, DATA_DIR_NONE,
2984 + 0, 1,
2985 + "TEST UNIT READY");
2986 + break;
2987 +
2988 + /* Although optional, this command is used by MS-Windows. We
2989 + * support a minimal version: BytChk must be 0. */
2990 + case VERIFY:
2991 + fsg->data_size_from_cmnd = 0;
2992 + if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
2993 + (1<<1) | (0xf<<2) | (3<<7), 1,
2994 + "VERIFY")) == 0)
2995 + reply = do_verify(fsg);
2996 + break;
2997 +
2998 + case WRITE_6:
2999 + i = fsg->cmnd[4];
3000 + fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
3001 + if ((reply = check_command_size_in_blocks(fsg, 6,
3002 + DATA_DIR_FROM_HOST,
3003 + (7<<1) | (1<<4), 1,
3004 + "WRITE(6)")) == 0)
3005 + reply = do_write(fsg);
3006 + break;
3007 +
3008 + case WRITE_10:
3009 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
3010 + if ((reply = check_command_size_in_blocks(fsg, 10,
3011 + DATA_DIR_FROM_HOST,
3012 + (1<<1) | (0xf<<2) | (3<<7), 1,
3013 + "WRITE(10)")) == 0)
3014 + reply = do_write(fsg);
3015 + break;
3016 +
3017 + case WRITE_12:
3018 + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
3019 + if ((reply = check_command_size_in_blocks(fsg, 12,
3020 + DATA_DIR_FROM_HOST,
3021 + (1<<1) | (0xf<<2) | (0xf<<6), 1,
3022 + "WRITE(12)")) == 0)
3023 + reply = do_write(fsg);
3024 + break;
3025 +
3026 + /* Some mandatory commands that we recognize but don't implement.
3027 + * They don't mean much in this setting. It's left as an exercise
3028 + * for anyone interested to implement RESERVE and RELEASE in terms
3029 + * of Posix locks. */
3030 + case FORMAT_UNIT:
3031 + case RELEASE:
3032 + case RESERVE:
3033 + case SEND_DIAGNOSTIC:
3034 + // Fall through
3035 +
3036 + default:
3037 + unknown_cmnd:
3038 + fsg->data_size_from_cmnd = 0;
3039 + sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
3040 + if ((reply = check_command(fsg, fsg->cmnd_size,
3041 + DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) {
3042 + fsg->curlun->sense_data = SS_INVALID_COMMAND;
3043 + reply = -EINVAL;
3044 + }
3045 + break;
3046 + }
3047 + up_read(&fsg->filesem);
3048 +
3049 + if (reply == -EINTR || signal_pending(current))
3050 + return -EINTR;
3051 +
3052 + /* Set up the single reply buffer for finish_reply() */
3053 + if (reply == -EINVAL)
3054 + reply = 0; // Error reply length
3055 + if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
3056 + reply = min((u32) reply, fsg->data_size_from_cmnd);
3057 + bh->inreq->length = reply;
3058 + bh->state = BUF_STATE_FULL;
3059 + fsg->residue -= reply;
3060 + } // Otherwise it's already set
3061 +
3062 + return 0;
3063 +}
3064 +
3065 +
3066 +/*-------------------------------------------------------------------------*/
3067 +
3068 +static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
3069 +{
3070 + struct usb_request *req = bh->outreq;
3071 + struct bulk_cb_wrap *cbw = req->buf;
3072 +
3073 + /* Was this a real packet? Should it be ignored? */
3074 + if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
3075 + return -EINVAL;
3076 +
3077 + /* Is the CBW valid? */
3078 + if (req->actual != US_BULK_CB_WRAP_LEN ||
3079 + cbw->Signature != cpu_to_le32(
3080 + US_BULK_CB_SIGN)) {
3081 + DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
3082 + req->actual,
3083 + le32_to_cpu(cbw->Signature));
3084 +
3085 + /* The Bulk-only spec says we MUST stall the IN endpoint
3086 + * (6.6.1), so it's unavoidable. It also says we must
3087 + * retain this state until the next reset, but there's
3088 + * no way to tell the controller driver it should ignore
3089 + * Clear-Feature(HALT) requests.
3090 + *
3091 + * We aren't required to halt the OUT endpoint; instead
3092 + * we can simply accept and discard any data received
3093 + * until the next reset. */
3094 + wedge_bulk_in_endpoint(fsg);
3095 + set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
3096 + return -EINVAL;
3097 + }
3098 +
3099 + /* Is the CBW meaningful? */
3100 + if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
3101 + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
3102 + DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
3103 + "cmdlen %u\n",
3104 + cbw->Lun, cbw->Flags, cbw->Length);
3105 +
3106 + /* We can do anything we want here, so let's stall the
3107 + * bulk pipes if we are allowed to. */
3108 + if (mod_data.can_stall) {
3109 + fsg_set_halt(fsg, fsg->bulk_out);
3110 + halt_bulk_in_endpoint(fsg);
3111 + }
3112 + return -EINVAL;
3113 + }
3114 +
3115 + /* Save the command for later */
3116 + fsg->cmnd_size = cbw->Length;
3117 + memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
3118 + if (cbw->Flags & US_BULK_FLAG_IN)
3119 + fsg->data_dir = DATA_DIR_TO_HOST;
3120 + else
3121 + fsg->data_dir = DATA_DIR_FROM_HOST;
3122 + fsg->data_size = le32_to_cpu(cbw->DataTransferLength);
3123 + if (fsg->data_size == 0)
3124 + fsg->data_dir = DATA_DIR_NONE;
3125 + fsg->lun = cbw->Lun;
3126 + fsg->tag = cbw->Tag;
3127 + return 0;
3128 +}
3129 +
3130 +
3131 +static int get_next_command(struct fsg_dev *fsg)
3132 +{
3133 + struct fsg_buffhd *bh;
3134 + int rc = 0;
3135 +
3136 + if (transport_is_bbb()) {
3137 +
3138 + /* Wait for the next buffer to become available */
3139 + bh = fsg->next_buffhd_to_fill;
3140 + while (bh->state != BUF_STATE_EMPTY) {
3141 + rc = sleep_thread(fsg);
3142 + if (rc)
3143 + return rc;
3144 + }
3145 +
3146 + /* Queue a request to read a Bulk-only CBW */
3147 + set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN);
3148 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
3149 + &bh->outreq_busy, &bh->state);
3150 +
3151 + /* We will drain the buffer in software, which means we
3152 + * can reuse it for the next filling. No need to advance
3153 + * next_buffhd_to_fill. */
3154 +
3155 + /* Wait for the CBW to arrive */
3156 + while (bh->state != BUF_STATE_FULL) {
3157 + rc = sleep_thread(fsg);
3158 + if (rc)
3159 + return rc;
3160 + }
3161 + smp_rmb();
3162 + rc = received_cbw(fsg, bh);
3163 + bh->state = BUF_STATE_EMPTY;
3164 +
3165 + } else { // USB_PR_CB or USB_PR_CBI
3166 +
3167 + /* Wait for the next command to arrive */
3168 + while (fsg->cbbuf_cmnd_size == 0) {
3169 + rc = sleep_thread(fsg);
3170 + if (rc)
3171 + return rc;
3172 + }
3173 +
3174 + /* Is the previous status interrupt request still busy?
3175 + * The host is allowed to skip reading the status,
3176 + * so we must cancel it. */
3177 + if (fsg->intreq_busy)
3178 + usb_ep_dequeue(fsg->intr_in, fsg->intreq);
3179 +
3180 + /* Copy the command and mark the buffer empty */
3181 + fsg->data_dir = DATA_DIR_UNKNOWN;
3182 + spin_lock_irq(&fsg->lock);
3183 + fsg->cmnd_size = fsg->cbbuf_cmnd_size;
3184 + memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
3185 + fsg->cbbuf_cmnd_size = 0;
3186 + spin_unlock_irq(&fsg->lock);
3187 +
3188 + /* Use LUN from the command */
3189 + fsg->lun = fsg->cmnd[1] >> 5;
3190 + }
3191 +
3192 + /* Update current lun */
3193 + if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
3194 + fsg->curlun = &fsg->luns[fsg->lun];
3195 + else
3196 + fsg->curlun = NULL;
3197 +
3198 + return rc;
3199 +}
3200 +
3201 +
3202 +/*-------------------------------------------------------------------------*/
3203 +
3204 +static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
3205 + const struct usb_endpoint_descriptor *d)
3206 +{
3207 + int rc;
3208 +
3209 + ep->driver_data = fsg;
3210 + ep->desc = d;
3211 + rc = usb_ep_enable(ep);
3212 + if (rc)
3213 + ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
3214 + return rc;
3215 +}
3216 +
3217 +static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep,
3218 + struct usb_request **preq)
3219 +{
3220 + *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
3221 + if (*preq)
3222 + return 0;
3223 + ERROR(fsg, "can't allocate request for %s\n", ep->name);
3224 + return -ENOMEM;
3225 +}
3226 +
3227 +/*
3228 + * Reset interface setting and re-init endpoint state (toggle etc).
3229 + * Call with altsetting < 0 to disable the interface. The only other
3230 + * available altsetting is 0, which enables the interface.
3231 + */
3232 +static int do_set_interface(struct fsg_dev *fsg, int altsetting)
3233 +{
3234 + int rc = 0;
3235 + int i;
3236 + const struct usb_endpoint_descriptor *d;
3237 +
3238 + if (fsg->running)
3239 + DBG(fsg, "reset interface\n");
3240 +
3241 +reset:
3242 + /* Deallocate the requests */
3243 + for (i = 0; i < fsg_num_buffers; ++i) {
3244 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3245 +
3246 + if (bh->inreq) {
3247 + usb_ep_free_request(fsg->bulk_in, bh->inreq);
3248 + bh->inreq = NULL;
3249 + }
3250 + if (bh->outreq) {
3251 + usb_ep_free_request(fsg->bulk_out, bh->outreq);
3252 + bh->outreq = NULL;
3253 + }
3254 + }
3255 + if (fsg->intreq) {
3256 + usb_ep_free_request(fsg->intr_in, fsg->intreq);
3257 + fsg->intreq = NULL;
3258 + }
3259 +
3260 + /* Disable the endpoints */
3261 + if (fsg->bulk_in_enabled) {
3262 + usb_ep_disable(fsg->bulk_in);
3263 + fsg->bulk_in_enabled = 0;
3264 + }
3265 + if (fsg->bulk_out_enabled) {
3266 + usb_ep_disable(fsg->bulk_out);
3267 + fsg->bulk_out_enabled = 0;
3268 + }
3269 + if (fsg->intr_in_enabled) {
3270 + usb_ep_disable(fsg->intr_in);
3271 + fsg->intr_in_enabled = 0;
3272 + }
3273 +
3274 + fsg->running = 0;
3275 + if (altsetting < 0 || rc != 0)
3276 + return rc;
3277 +
3278 + DBG(fsg, "set interface %d\n", altsetting);
3279 +
3280 + /* Enable the endpoints */
3281 + d = fsg_ep_desc(fsg->gadget,
3282 + &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
3283 + &fsg_ss_bulk_in_desc);
3284 + if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
3285 + goto reset;
3286 + fsg->bulk_in_enabled = 1;
3287 +
3288 + d = fsg_ep_desc(fsg->gadget,
3289 + &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
3290 + &fsg_ss_bulk_out_desc);
3291 + if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
3292 + goto reset;
3293 + fsg->bulk_out_enabled = 1;
3294 + fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
3295 + clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
3296 +
3297 + if (transport_is_cbi()) {
3298 + d = fsg_ep_desc(fsg->gadget,
3299 + &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
3300 + &fsg_ss_intr_in_desc);
3301 + if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
3302 + goto reset;
3303 + fsg->intr_in_enabled = 1;
3304 + }
3305 +
3306 + /* Allocate the requests */
3307 + for (i = 0; i < fsg_num_buffers; ++i) {
3308 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3309 +
3310 + if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
3311 + goto reset;
3312 + if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
3313 + goto reset;
3314 + bh->inreq->buf = bh->outreq->buf = bh->buf;
3315 + bh->inreq->context = bh->outreq->context = bh;
3316 + bh->inreq->complete = bulk_in_complete;
3317 + bh->outreq->complete = bulk_out_complete;
3318 + }
3319 + if (transport_is_cbi()) {
3320 + if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0)
3321 + goto reset;
3322 + fsg->intreq->complete = intr_in_complete;
3323 + }
3324 +
3325 + fsg->running = 1;
3326 + for (i = 0; i < fsg->nluns; ++i)
3327 + fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
3328 + return rc;
3329 +}
3330 +
3331 +
3332 +/*
3333 + * Change our operational configuration. This code must agree with the code
3334 + * that returns config descriptors, and with interface altsetting code.
3335 + *
3336 + * It's also responsible for power management interactions. Some
3337 + * configurations might not work with our current power sources.
3338 + * For now we just assume the gadget is always self-powered.
3339 + */
3340 +static int do_set_config(struct fsg_dev *fsg, u8 new_config)
3341 +{
3342 + int rc = 0;
3343 +
3344 + /* Disable the single interface */
3345 + if (fsg->config != 0) {
3346 + DBG(fsg, "reset config\n");
3347 + fsg->config = 0;
3348 + rc = do_set_interface(fsg, -1);
3349 + }
3350 +
3351 + /* Enable the interface */
3352 + if (new_config != 0) {
3353 + fsg->config = new_config;
3354 + if ((rc = do_set_interface(fsg, 0)) != 0)
3355 + fsg->config = 0; // Reset on errors
3356 + else
3357 + INFO(fsg, "%s config #%d\n",
3358 + usb_speed_string(fsg->gadget->speed),
3359 + fsg->config);
3360 + }
3361 + return rc;
3362 +}
3363 +
3364 +
3365 +/*-------------------------------------------------------------------------*/
3366 +
3367 +static void handle_exception(struct fsg_dev *fsg)
3368 +{
3369 + siginfo_t info;
3370 + int sig;
3371 + int i;
3372 + int num_active;
3373 + struct fsg_buffhd *bh;
3374 + enum fsg_state old_state;
3375 + u8 new_config;
3376 + struct fsg_lun *curlun;
3377 + unsigned int exception_req_tag;
3378 + int rc;
3379 +
3380 + /* Clear the existing signals. Anything but SIGUSR1 is converted
3381 + * into a high-priority EXIT exception. */
3382 + for (;;) {
3383 + sig = dequeue_signal_lock(current, &current->blocked, &info);
3384 + if (!sig)
3385 + break;
3386 + if (sig != SIGUSR1) {
3387 + if (fsg->state < FSG_STATE_EXIT)
3388 + DBG(fsg, "Main thread exiting on signal\n");
3389 + raise_exception(fsg, FSG_STATE_EXIT);
3390 + }
3391 + }
3392 +
3393 + /* Cancel all the pending transfers */
3394 + if (fsg->intreq_busy)
3395 + usb_ep_dequeue(fsg->intr_in, fsg->intreq);
3396 + for (i = 0; i < fsg_num_buffers; ++i) {
3397 + bh = &fsg->buffhds[i];
3398 + if (bh->inreq_busy)
3399 + usb_ep_dequeue(fsg->bulk_in, bh->inreq);
3400 + if (bh->outreq_busy)
3401 + usb_ep_dequeue(fsg->bulk_out, bh->outreq);
3402 + }
3403 +
3404 + /* Wait until everything is idle */
3405 + for (;;) {
3406 + num_active = fsg->intreq_busy;
3407 + for (i = 0; i < fsg_num_buffers; ++i) {
3408 + bh = &fsg->buffhds[i];
3409 + num_active += bh->inreq_busy + bh->outreq_busy;
3410 + }
3411 + if (num_active == 0)
3412 + break;
3413 + if (sleep_thread(fsg))
3414 + return;
3415 + }
3416 +
3417 + /* Clear out the controller's fifos */
3418 + if (fsg->bulk_in_enabled)
3419 + usb_ep_fifo_flush(fsg->bulk_in);
3420 + if (fsg->bulk_out_enabled)
3421 + usb_ep_fifo_flush(fsg->bulk_out);
3422 + if (fsg->intr_in_enabled)
3423 + usb_ep_fifo_flush(fsg->intr_in);
3424 +
3425 + /* Reset the I/O buffer states and pointers, the SCSI
3426 + * state, and the exception. Then invoke the handler. */
3427 + spin_lock_irq(&fsg->lock);
3428 +
3429 + for (i = 0; i < fsg_num_buffers; ++i) {
3430 + bh = &fsg->buffhds[i];
3431 + bh->state = BUF_STATE_EMPTY;
3432 + }
3433 + fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain =
3434 + &fsg->buffhds[0];
3435 +
3436 + exception_req_tag = fsg->exception_req_tag;
3437 + new_config = fsg->new_config;
3438 + old_state = fsg->state;
3439 +
3440 + if (old_state == FSG_STATE_ABORT_BULK_OUT)
3441 + fsg->state = FSG_STATE_STATUS_PHASE;
3442 + else {
3443 + for (i = 0; i < fsg->nluns; ++i) {
3444 + curlun = &fsg->luns[i];
3445 + curlun->prevent_medium_removal = 0;
3446 + curlun->sense_data = curlun->unit_attention_data =
3447 + SS_NO_SENSE;
3448 + curlun->sense_data_info = 0;
3449 + curlun->info_valid = 0;
3450 + }
3451 + fsg->state = FSG_STATE_IDLE;
3452 + }
3453 + spin_unlock_irq(&fsg->lock);
3454 +
3455 + /* Carry out any extra actions required for the exception */
3456 + switch (old_state) {
3457 + default:
3458 + break;
3459 +
3460 + case FSG_STATE_ABORT_BULK_OUT:
3461 + send_status(fsg);
3462 + spin_lock_irq(&fsg->lock);
3463 + if (fsg->state == FSG_STATE_STATUS_PHASE)
3464 + fsg->state = FSG_STATE_IDLE;
3465 + spin_unlock_irq(&fsg->lock);
3466 + break;
3467 +
3468 + case FSG_STATE_RESET:
3469 + /* In case we were forced against our will to halt a
3470 + * bulk endpoint, clear the halt now. (The SuperH UDC
3471 + * requires this.) */
3472 + if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
3473 + usb_ep_clear_halt(fsg->bulk_in);
3474 +
3475 + if (transport_is_bbb()) {
3476 + if (fsg->ep0_req_tag == exception_req_tag)
3477 + ep0_queue(fsg); // Complete the status stage
3478 +
3479 + } else if (transport_is_cbi())
3480 + send_status(fsg); // Status by interrupt pipe
3481 +
3482 + /* Technically this should go here, but it would only be
3483 + * a waste of time. Ditto for the INTERFACE_CHANGE and
3484 + * CONFIG_CHANGE cases. */
3485 + // for (i = 0; i < fsg->nluns; ++i)
3486 + // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
3487 + break;
3488 +
3489 + case FSG_STATE_INTERFACE_CHANGE:
3490 + rc = do_set_interface(fsg, 0);
3491 + if (fsg->ep0_req_tag != exception_req_tag)
3492 + break;
3493 + if (rc != 0) // STALL on errors
3494 + fsg_set_halt(fsg, fsg->ep0);
3495 + else // Complete the status stage
3496 + ep0_queue(fsg);
3497 + break;
3498 +
3499 + case FSG_STATE_CONFIG_CHANGE:
3500 + rc = do_set_config(fsg, new_config);
3501 + if (fsg->ep0_req_tag != exception_req_tag)
3502 + break;
3503 + if (rc != 0) // STALL on errors
3504 + fsg_set_halt(fsg, fsg->ep0);
3505 + else // Complete the status stage
3506 + ep0_queue(fsg);
3507 + break;
3508 +
3509 + case FSG_STATE_DISCONNECT:
3510 + for (i = 0; i < fsg->nluns; ++i)
3511 + fsg_lun_fsync_sub(fsg->luns + i);
3512 + do_set_config(fsg, 0); // Unconfigured state
3513 + break;
3514 +
3515 + case FSG_STATE_EXIT:
3516 + case FSG_STATE_TERMINATED:
3517 + do_set_config(fsg, 0); // Free resources
3518 + spin_lock_irq(&fsg->lock);
3519 + fsg->state = FSG_STATE_TERMINATED; // Stop the thread
3520 + spin_unlock_irq(&fsg->lock);
3521 + break;
3522 + }
3523 +}
3524 +
3525 +
3526 +/*-------------------------------------------------------------------------*/
3527 +
3528 +static int fsg_main_thread(void *fsg_)
3529 +{
3530 + struct fsg_dev *fsg = fsg_;
3531 +
3532 + /* Allow the thread to be killed by a signal, but set the signal mask
3533 + * to block everything but INT, TERM, KILL, and USR1. */
3534 + allow_signal(SIGINT);
3535 + allow_signal(SIGTERM);
3536 + allow_signal(SIGKILL);
3537 + allow_signal(SIGUSR1);
3538 +
3539 + /* Allow the thread to be frozen */
3540 + set_freezable();
3541 +
3542 + /* Arrange for userspace references to be interpreted as kernel
3543 + * pointers. That way we can pass a kernel pointer to a routine
3544 + * that expects a __user pointer and it will work okay. */
3545 + set_fs(get_ds());
3546 +
3547 + /* The main loop */
3548 + while (fsg->state != FSG_STATE_TERMINATED) {
3549 + if (exception_in_progress(fsg) || signal_pending(current)) {
3550 + handle_exception(fsg);
3551 + continue;
3552 + }
3553 +
3554 + if (!fsg->running) {
3555 + sleep_thread(fsg);
3556 + continue;
3557 + }
3558 +
3559 + if (get_next_command(fsg))
3560 + continue;
3561 +
3562 + spin_lock_irq(&fsg->lock);
3563 + if (!exception_in_progress(fsg))
3564 + fsg->state = FSG_STATE_DATA_PHASE;
3565 + spin_unlock_irq(&fsg->lock);
3566 +
3567 + if (do_scsi_command(fsg) || finish_reply(fsg))
3568 + continue;
3569 +
3570 + spin_lock_irq(&fsg->lock);
3571 + if (!exception_in_progress(fsg))
3572 + fsg->state = FSG_STATE_STATUS_PHASE;
3573 + spin_unlock_irq(&fsg->lock);
3574 +
3575 + if (send_status(fsg))
3576 + continue;
3577 +
3578 + spin_lock_irq(&fsg->lock);
3579 + if (!exception_in_progress(fsg))
3580 + fsg->state = FSG_STATE_IDLE;
3581 + spin_unlock_irq(&fsg->lock);
3582 + }
3583 +
3584 + spin_lock_irq(&fsg->lock);
3585 + fsg->thread_task = NULL;
3586 + spin_unlock_irq(&fsg->lock);
3587 +
3588 + /* If we are exiting because of a signal, unregister the
3589 + * gadget driver. */
3590 + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
3591 + usb_gadget_unregister_driver(&fsg_driver);
3592 +
3593 + /* Let the unbind and cleanup routines know the thread has exited */
3594 + complete_and_exit(&fsg->thread_notifier, 0);
3595 +}
3596 +
3597 +
3598 +/*-------------------------------------------------------------------------*/
3599 +
3600 +
3601 +/* The write permissions and store_xxx pointers are set in fsg_bind() */
3602 +static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL);
3603 +static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL);
3604 +static DEVICE_ATTR(file, 0444, fsg_show_file, NULL);
3605 +
3606 +
3607 +/*-------------------------------------------------------------------------*/
3608 +
3609 +static void fsg_release(struct kref *ref)
3610 +{
3611 + struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref);
3612 +
3613 + kfree(fsg->luns);
3614 + kfree(fsg);
3615 +}
3616 +
3617 +static void lun_release(struct device *dev)
3618 +{
3619 + struct rw_semaphore *filesem = dev_get_drvdata(dev);
3620 + struct fsg_dev *fsg =
3621 + container_of(filesem, struct fsg_dev, filesem);
3622 +
3623 + kref_put(&fsg->ref, fsg_release);
3624 +}
3625 +
3626 +static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
3627 +{
3628 + struct fsg_dev *fsg = get_gadget_data(gadget);
3629 + int i;
3630 + struct fsg_lun *curlun;
3631 + struct usb_request *req = fsg->ep0req;
3632 +
3633 + DBG(fsg, "unbind\n");
3634 + clear_bit(REGISTERED, &fsg->atomic_bitflags);
3635 +
3636 + /* If the thread isn't already dead, tell it to exit now */
3637 + if (fsg->state != FSG_STATE_TERMINATED) {
3638 + raise_exception(fsg, FSG_STATE_EXIT);
3639 + wait_for_completion(&fsg->thread_notifier);
3640 +
3641 + /* The cleanup routine waits for this completion also */
3642 + complete(&fsg->thread_notifier);
3643 + }
3644 +
3645 + /* Unregister the sysfs attribute files and the LUNs */
3646 + for (i = 0; i < fsg->nluns; ++i) {
3647 + curlun = &fsg->luns[i];
3648 + if (curlun->registered) {
3649 + device_remove_file(&curlun->dev, &dev_attr_nofua);
3650 + device_remove_file(&curlun->dev, &dev_attr_ro);
3651 + device_remove_file(&curlun->dev, &dev_attr_file);
3652 + fsg_lun_close(curlun);
3653 + device_unregister(&curlun->dev);
3654 + curlun->registered = 0;
3655 + }
3656 + }
3657 +
3658 + /* Free the data buffers */
3659 + for (i = 0; i < fsg_num_buffers; ++i)
3660 + kfree(fsg->buffhds[i].buf);
3661 +
3662 + /* Free the request and buffer for endpoint 0 */
3663 + if (req) {
3664 + kfree(req->buf);
3665 + usb_ep_free_request(fsg->ep0, req);
3666 + }
3667 +
3668 + set_gadget_data(gadget, NULL);
3669 +}
3670 +
3671 +
3672 +static int __init check_parameters(struct fsg_dev *fsg)
3673 +{
3674 + int prot;
3675 + int gcnum;
3676 +
3677 + /* Store the default values */
3678 + mod_data.transport_type = USB_PR_BULK;
3679 + mod_data.transport_name = "Bulk-only";
3680 + mod_data.protocol_type = USB_SC_SCSI;
3681 + mod_data.protocol_name = "Transparent SCSI";
3682 +
3683 + /* Some peripheral controllers are known not to be able to
3684 + * halt bulk endpoints correctly. If one of them is present,
3685 + * disable stalls.
3686 + */
3687 + if (gadget_is_at91(fsg->gadget))
3688 + mod_data.can_stall = 0;
3689 +
3690 + if (mod_data.release == 0xffff) { // Parameter wasn't set
3691 + gcnum = usb_gadget_controller_number(fsg->gadget);
3692 + if (gcnum >= 0)
3693 + mod_data.release = 0x0300 + gcnum;
3694 + else {
3695 + WARNING(fsg, "controller '%s' not recognized\n",
3696 + fsg->gadget->name);
3697 + mod_data.release = 0x0399;
3698 + }
3699 + }
3700 +
3701 + prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
3702 +
3703 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
3704 + if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) {
3705 + ; // Use default setting
3706 + } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) {
3707 + mod_data.transport_type = USB_PR_CB;
3708 + mod_data.transport_name = "Control-Bulk";
3709 + } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) {
3710 + mod_data.transport_type = USB_PR_CBI;
3711 + mod_data.transport_name = "Control-Bulk-Interrupt";
3712 + } else {
3713 + ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm);
3714 + return -EINVAL;
3715 + }
3716 +
3717 + if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 ||
3718 + prot == USB_SC_SCSI) {
3719 + ; // Use default setting
3720 + } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 ||
3721 + prot == USB_SC_RBC) {
3722 + mod_data.protocol_type = USB_SC_RBC;
3723 + mod_data.protocol_name = "RBC";
3724 + } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 ||
3725 + strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 ||
3726 + prot == USB_SC_8020) {
3727 + mod_data.protocol_type = USB_SC_8020;
3728 + mod_data.protocol_name = "8020i (ATAPI)";
3729 + } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 ||
3730 + prot == USB_SC_QIC) {
3731 + mod_data.protocol_type = USB_SC_QIC;
3732 + mod_data.protocol_name = "QIC-157";
3733 + } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 ||
3734 + prot == USB_SC_UFI) {
3735 + mod_data.protocol_type = USB_SC_UFI;
3736 + mod_data.protocol_name = "UFI";
3737 + } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 ||
3738 + prot == USB_SC_8070) {
3739 + mod_data.protocol_type = USB_SC_8070;
3740 + mod_data.protocol_name = "8070i";
3741 + } else {
3742 + ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm);
3743 + return -EINVAL;
3744 + }
3745 +
3746 + mod_data.buflen &= PAGE_CACHE_MASK;
3747 + if (mod_data.buflen <= 0) {
3748 + ERROR(fsg, "invalid buflen\n");
3749 + return -ETOOSMALL;
3750 + }
3751 +
3752 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
3753 +
3754 + /* Serial string handling.
3755 + * On a real device, the serial string would be loaded
3756 + * from permanent storage. */
3757 + if (mod_data.serial) {
3758 + const char *ch;
3759 + unsigned len = 0;
3760 +
3761 + /* Sanity check :
3762 + * The CB[I] specification limits the serial string to
3763 + * 12 uppercase hexadecimal characters.
3764 + * BBB need at least 12 uppercase hexadecimal characters,
3765 + * with a maximum of 126. */
3766 + for (ch = mod_data.serial; *ch; ++ch) {
3767 + ++len;
3768 + if ((*ch < '0' || *ch > '9') &&
3769 + (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
3770 + WARNING(fsg,
3771 + "Invalid serial string character: %c\n",
3772 + *ch);
3773 + goto no_serial;
3774 + }
3775 + }
3776 + if (len > 126 ||
3777 + (mod_data.transport_type == USB_PR_BULK && len < 12) ||
3778 + (mod_data.transport_type != USB_PR_BULK && len > 12)) {
3779 + WARNING(fsg, "Invalid serial string length!\n");
3780 + goto no_serial;
3781 + }
3782 + fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial;
3783 + } else {
3784 + WARNING(fsg, "No serial-number string provided!\n");
3785 + no_serial:
3786 + device_desc.iSerialNumber = 0;
3787 + }
3788 +
3789 + return 0;
3790 +}
3791 +
3792 +
3793 +static int __init fsg_bind(struct usb_gadget *gadget)
3794 +{
3795 + struct fsg_dev *fsg = the_fsg;
3796 + int rc;
3797 + int i;
3798 + struct fsg_lun *curlun;
3799 + struct usb_ep *ep;
3800 + struct usb_request *req;
3801 + char *pathbuf, *p;
3802 +
3803 + fsg->gadget = gadget;
3804 + set_gadget_data(gadget, fsg);
3805 + fsg->ep0 = gadget->ep0;
3806 + fsg->ep0->driver_data = fsg;
3807 +
3808 + if ((rc = check_parameters(fsg)) != 0)
3809 + goto out;
3810 +
3811 + if (mod_data.removable) { // Enable the store_xxx attributes
3812 + dev_attr_file.attr.mode = 0644;
3813 + dev_attr_file.store = fsg_store_file;
3814 + if (!mod_data.cdrom) {
3815 + dev_attr_ro.attr.mode = 0644;
3816 + dev_attr_ro.store = fsg_store_ro;
3817 + }
3818 + }
3819 +
3820 + /* Only for removable media? */
3821 + dev_attr_nofua.attr.mode = 0644;
3822 + dev_attr_nofua.store = fsg_store_nofua;
3823 +
3824 + /* Find out how many LUNs there should be */
3825 + i = mod_data.nluns;
3826 + if (i == 0)
3827 + i = max(mod_data.num_filenames, 1u);
3828 + if (i > FSG_MAX_LUNS) {
3829 + ERROR(fsg, "invalid number of LUNs: %d\n", i);
3830 + rc = -EINVAL;
3831 + goto out;
3832 + }
3833 +
3834 + /* Create the LUNs, open their backing files, and register the
3835 + * LUN devices in sysfs. */
3836 + fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL);
3837 + if (!fsg->luns) {
3838 + rc = -ENOMEM;
3839 + goto out;
3840 + }
3841 + fsg->nluns = i;
3842 +
3843 + for (i = 0; i < fsg->nluns; ++i) {
3844 + curlun = &fsg->luns[i];
3845 + curlun->cdrom = !!mod_data.cdrom;
3846 + curlun->ro = mod_data.cdrom || mod_data.ro[i];
3847 + curlun->initially_ro = curlun->ro;
3848 + curlun->removable = mod_data.removable;
3849 + curlun->nofua = mod_data.nofua[i];
3850 + curlun->dev.release = lun_release;
3851 + curlun->dev.parent = &gadget->dev;
3852 + curlun->dev.driver = &fsg_driver.driver;
3853 + dev_set_drvdata(&curlun->dev, &fsg->filesem);
3854 + dev_set_name(&curlun->dev,"%s-lun%d",
3855 + dev_name(&gadget->dev), i);
3856 +
3857 + kref_get(&fsg->ref);
3858 + rc = device_register(&curlun->dev);
3859 + if (rc) {
3860 + INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
3861 + put_device(&curlun->dev);
3862 + goto out;
3863 + }
3864 + curlun->registered = 1;
3865 +
3866 + rc = device_create_file(&curlun->dev, &dev_attr_ro);
3867 + if (rc)
3868 + goto out;
3869 + rc = device_create_file(&curlun->dev, &dev_attr_nofua);
3870 + if (rc)
3871 + goto out;
3872 + rc = device_create_file(&curlun->dev, &dev_attr_file);
3873 + if (rc)
3874 + goto out;
3875 +
3876 + if (mod_data.file[i] && *mod_data.file[i]) {
3877 + rc = fsg_lun_open(curlun, mod_data.file[i]);
3878 + if (rc)
3879 + goto out;
3880 + } else if (!mod_data.removable) {
3881 + ERROR(fsg, "no file given for LUN%d\n", i);
3882 + rc = -EINVAL;
3883 + goto out;
3884 + }
3885 + }
3886 +
3887 + /* Find all the endpoints we will use */
3888 + usb_ep_autoconfig_reset(gadget);
3889 + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
3890 + if (!ep)
3891 + goto autoconf_fail;
3892 + ep->driver_data = fsg; // claim the endpoint
3893 + fsg->bulk_in = ep;
3894 +
3895 + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
3896 + if (!ep)
3897 + goto autoconf_fail;
3898 + ep->driver_data = fsg; // claim the endpoint
3899 + fsg->bulk_out = ep;
3900 +
3901 + if (transport_is_cbi()) {
3902 + ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc);
3903 + if (!ep)
3904 + goto autoconf_fail;
3905 + ep->driver_data = fsg; // claim the endpoint
3906 + fsg->intr_in = ep;
3907 + }
3908 +
3909 + /* Fix up the descriptors */
3910 + device_desc.idVendor = cpu_to_le16(mod_data.vendor);
3911 + device_desc.idProduct = cpu_to_le16(mod_data.product);
3912 + device_desc.bcdDevice = cpu_to_le16(mod_data.release);
3913 +
3914 + i = (transport_is_cbi() ? 3 : 2); // Number of endpoints
3915 + fsg_intf_desc.bNumEndpoints = i;
3916 + fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type;
3917 + fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type;
3918 + fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3919 +
3920 + if (gadget_is_dualspeed(gadget)) {
3921 + fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3922 +
3923 + /* Assume endpoint addresses are the same for both speeds */
3924 + fsg_hs_bulk_in_desc.bEndpointAddress =
3925 + fsg_fs_bulk_in_desc.bEndpointAddress;
3926 + fsg_hs_bulk_out_desc.bEndpointAddress =
3927 + fsg_fs_bulk_out_desc.bEndpointAddress;
3928 + fsg_hs_intr_in_desc.bEndpointAddress =
3929 + fsg_fs_intr_in_desc.bEndpointAddress;
3930 + }
3931 +
3932 + if (gadget_is_superspeed(gadget)) {
3933 + unsigned max_burst;
3934 +
3935 + fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3936 +
3937 + /* Calculate bMaxBurst, we know packet size is 1024 */
3938 + max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
3939 +
3940 + /* Assume endpoint addresses are the same for both speeds */
3941 + fsg_ss_bulk_in_desc.bEndpointAddress =
3942 + fsg_fs_bulk_in_desc.bEndpointAddress;
3943 + fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
3944 +
3945 + fsg_ss_bulk_out_desc.bEndpointAddress =
3946 + fsg_fs_bulk_out_desc.bEndpointAddress;
3947 + fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
3948 + }
3949 +
3950 + if (gadget_is_otg(gadget))
3951 + fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
3952 +
3953 + rc = -ENOMEM;
3954 +
3955 + /* Allocate the request and buffer for endpoint 0 */
3956 + fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
3957 + if (!req)
3958 + goto out;
3959 + req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
3960 + if (!req->buf)
3961 + goto out;
3962 + req->complete = ep0_complete;
3963 +
3964 + /* Allocate the data buffers */
3965 + for (i = 0; i < fsg_num_buffers; ++i) {
3966 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3967 +
3968 + /* Allocate for the bulk-in endpoint. We assume that
3969 + * the buffer will also work with the bulk-out (and
3970 + * interrupt-in) endpoint. */
3971 + bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
3972 + if (!bh->buf)
3973 + goto out;
3974 + bh->next = bh + 1;
3975 + }
3976 + fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0];
3977 +
3978 + /* This should reflect the actual gadget power source */
3979 + usb_gadget_set_selfpowered(gadget);
3980 +
3981 + snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer,
3982 + "%s %s with %s",
3983 + init_utsname()->sysname, init_utsname()->release,
3984 + gadget->name);
3985 +
3986 + fsg->thread_task = kthread_create(fsg_main_thread, fsg,
3987 + "file-storage-gadget");
3988 + if (IS_ERR(fsg->thread_task)) {
3989 + rc = PTR_ERR(fsg->thread_task);
3990 + goto out;
3991 + }
3992 +
3993 + INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
3994 + INFO(fsg, "NOTE: This driver is deprecated. "
3995 + "Consider using g_mass_storage instead.\n");
3996 + INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
3997 +
3998 + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
3999 + for (i = 0; i < fsg->nluns; ++i) {
4000 + curlun = &fsg->luns[i];
4001 + if (fsg_lun_is_open(curlun)) {
4002 + p = NULL;
4003 + if (pathbuf) {
4004 + p = d_path(&curlun->filp->f_path,
4005 + pathbuf, PATH_MAX);
4006 + if (IS_ERR(p))
4007 + p = NULL;
4008 + }
4009 + LINFO(curlun, "ro=%d, nofua=%d, file: %s\n",
4010 + curlun->ro, curlun->nofua, (p ? p : "(error)"));
4011 + }
4012 + }
4013 + kfree(pathbuf);
4014 +
4015 + DBG(fsg, "transport=%s (x%02x)\n",
4016 + mod_data.transport_name, mod_data.transport_type);
4017 + DBG(fsg, "protocol=%s (x%02x)\n",
4018 + mod_data.protocol_name, mod_data.protocol_type);
4019 + DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
4020 + mod_data.vendor, mod_data.product, mod_data.release);
4021 + DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n",
4022 + mod_data.removable, mod_data.can_stall,
4023 + mod_data.cdrom, mod_data.buflen);
4024 + DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
4025 +
4026 + set_bit(REGISTERED, &fsg->atomic_bitflags);
4027 +
4028 + /* Tell the thread to start working */
4029 + wake_up_process(fsg->thread_task);
4030 + return 0;
4031 +
4032 +autoconf_fail:
4033 + ERROR(fsg, "unable to autoconfigure all endpoints\n");
4034 + rc = -ENOTSUPP;
4035 +
4036 +out:
4037 + fsg->state = FSG_STATE_TERMINATED; // The thread is dead
4038 + fsg_unbind(gadget);
4039 + complete(&fsg->thread_notifier);
4040 + return rc;
4041 +}
4042 +
4043 +
4044 +/*-------------------------------------------------------------------------*/
4045 +
4046 +static void fsg_suspend(struct usb_gadget *gadget)
4047 +{
4048 + struct fsg_dev *fsg = get_gadget_data(gadget);
4049 +
4050 + DBG(fsg, "suspend\n");
4051 + set_bit(SUSPENDED, &fsg->atomic_bitflags);
4052 +}
4053 +
4054 +static void fsg_resume(struct usb_gadget *gadget)
4055 +{
4056 + struct fsg_dev *fsg = get_gadget_data(gadget);
4057 +
4058 + DBG(fsg, "resume\n");
4059 + clear_bit(SUSPENDED, &fsg->atomic_bitflags);
4060 +}
4061 +
4062 +
4063 +/*-------------------------------------------------------------------------*/
4064 +
4065 +static struct usb_gadget_driver fsg_driver = {
4066 + .max_speed = USB_SPEED_SUPER,
4067 + .function = (char *) fsg_string_product,
4068 + .unbind = fsg_unbind,
4069 + .disconnect = fsg_disconnect,
4070 + .setup = fsg_setup,
4071 + .suspend = fsg_suspend,
4072 + .resume = fsg_resume,
4073 +
4074 + .driver = {
4075 + .name = DRIVER_NAME,
4076 + .owner = THIS_MODULE,
4077 + // .release = ...
4078 + // .suspend = ...
4079 + // .resume = ...
4080 + },
4081 +};
4082 +
4083 +
4084 +static int __init fsg_alloc(void)
4085 +{
4086 + struct fsg_dev *fsg;
4087 +
4088 + fsg = kzalloc(sizeof *fsg +
4089 + fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL);
4090 +
4091 + if (!fsg)
4092 + return -ENOMEM;
4093 + spin_lock_init(&fsg->lock);
4094 + init_rwsem(&fsg->filesem);
4095 + kref_init(&fsg->ref);
4096 + init_completion(&fsg->thread_notifier);
4097 +
4098 + the_fsg = fsg;
4099 + return 0;
4100 +}
4101 +
4102 +
4103 +static int __init fsg_init(void)
4104 +{
4105 + int rc;
4106 + struct fsg_dev *fsg;
4107 +
4108 + rc = fsg_num_buffers_validate();
4109 + if (rc != 0)
4110 + return rc;
4111 +
4112 + if ((rc = fsg_alloc()) != 0)
4113 + return rc;
4114 + fsg = the_fsg;
4115 + if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
4116 + kref_put(&fsg->ref, fsg_release);
4117 + return rc;
4118 +}
4119 +module_init(fsg_init);
4120 +
4121 +
4122 +static void __exit fsg_cleanup(void)
4123 +{
4124 + struct fsg_dev *fsg = the_fsg;
4125 +
4126 + /* Unregister the driver iff the thread hasn't already done so */
4127 + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
4128 + usb_gadget_unregister_driver(&fsg_driver);
4129 +
4130 + /* Wait for the thread to finish up */
4131 + wait_for_completion(&fsg->thread_notifier);
4132 +
4133 + kref_put(&fsg->ref, fsg_release);
4134 +}
4135 +module_exit(fsg_cleanup);
4136 --- a/drivers/usb/host/Kconfig
4137 +++ b/drivers/usb/host/Kconfig
4138 @@ -663,6 +663,19 @@ config USB_HWA_HCD
4139 To compile this driver a module, choose M here: the module
4140 will be called "hwa-hc".
4141
4142 +config USB_DWCOTG
4143 + tristate "Synopsis DWC host support"
4144 + depends on USB
4145 + help
4146 + The Synopsis DWC controller is a dual-role
4147 + host/peripheral/OTG ("On The Go") USB controllers.
4148 +
4149 + Enable this option to support this IP in host controller mode.
4150 + If unsure, say N.
4151 +
4152 + To compile this driver as a module, choose M here: the
4153 + modules built will be called dwc_otg and dwc_common_port.
4154 +
4155 config USB_IMX21_HCD
4156 tristate "i.MX21 HCD support"
4157 depends on ARM && ARCH_MXC
4158 --- a/drivers/usb/host/Makefile
4159 +++ b/drivers/usb/host/Makefile
4160 @@ -47,6 +47,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
4161 obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
4162 obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
4163 obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
4164 +
4165 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/
4166 obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
4167 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
4168 obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
4169 --- /dev/null
4170 +++ b/drivers/usb/host/dwc_common_port/Makefile
4171 @@ -0,0 +1,58 @@
4172 +#
4173 +# Makefile for DWC_common library
4174 +#
4175 +
4176 +ifneq ($(KERNELRELEASE),)
4177 +
4178 +EXTRA_CFLAGS += -DDWC_LINUX
4179 +#EXTRA_CFLAGS += -DDEBUG
4180 +#EXTRA_CFLAGS += -DDWC_DEBUG_REGS
4181 +#EXTRA_CFLAGS += -DDWC_DEBUG_MEMORY
4182 +
4183 +EXTRA_CFLAGS += -DDWC_LIBMODULE
4184 +EXTRA_CFLAGS += -DDWC_CCLIB
4185 +#EXTRA_CFLAGS += -DDWC_CRYPTOLIB
4186 +EXTRA_CFLAGS += -DDWC_NOTIFYLIB
4187 +EXTRA_CFLAGS += -DDWC_UTFLIB
4188 +
4189 +obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o
4190 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
4191 + dwc_crypto.o dwc_notifier.o \
4192 + dwc_common_linux.o dwc_mem.o
4193 +
4194 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
4195 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
4196 +
4197 +ifneq ($(kernrel3),2.6.20)
4198 +# grayg - I only know that we use EXTRA_CFLAGS in 2.6.31 actually
4199 +EXTRA_CFLAGS += $(CPPFLAGS)
4200 +endif
4201 +
4202 +else
4203 +
4204 +#ifeq ($(KDIR),)
4205 +#$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
4206 +#endif
4207 +
4208 +ifeq ($(ARCH),)
4209 +$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
4210 + cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
4211 +endif
4212 +
4213 +ifeq ($(DOXYGEN),)
4214 +DOXYGEN := doxygen
4215 +endif
4216 +
4217 +default:
4218 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
4219 +
4220 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
4221 + $(DOXYGEN) doc/doxygen.cfg
4222 +
4223 +tags: $(wildcard *.[hc])
4224 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
4225 +
4226 +endif
4227 +
4228 +clean:
4229 + rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
4230 --- /dev/null
4231 +++ b/drivers/usb/host/dwc_common_port/Makefile.fbsd
4232 @@ -0,0 +1,17 @@
4233 +CFLAGS += -I/sys/i386/compile/GENERIC -I/sys/i386/include -I/usr/include
4234 +CFLAGS += -DDWC_FREEBSD
4235 +CFLAGS += -DDEBUG
4236 +#CFLAGS += -DDWC_DEBUG_REGS
4237 +#CFLAGS += -DDWC_DEBUG_MEMORY
4238 +
4239 +#CFLAGS += -DDWC_LIBMODULE
4240 +#CFLAGS += -DDWC_CCLIB
4241 +#CFLAGS += -DDWC_CRYPTOLIB
4242 +#CFLAGS += -DDWC_NOTIFYLIB
4243 +#CFLAGS += -DDWC_UTFLIB
4244 +
4245 +KMOD = dwc_common_port_lib
4246 +SRCS = dwc_cc.c dwc_modpow.c dwc_dh.c dwc_crypto.c dwc_notifier.c \
4247 + dwc_common_fbsd.c dwc_mem.c
4248 +
4249 +.include <bsd.kmod.mk>
4250 --- /dev/null
4251 +++ b/drivers/usb/host/dwc_common_port/Makefile.linux
4252 @@ -0,0 +1,49 @@
4253 +#
4254 +# Makefile for DWC_common library
4255 +#
4256 +ifneq ($(KERNELRELEASE),)
4257 +
4258 +EXTRA_CFLAGS += -DDWC_LINUX
4259 +#EXTRA_CFLAGS += -DDEBUG
4260 +#EXTRA_CFLAGS += -DDWC_DEBUG_REGS
4261 +#EXTRA_CFLAGS += -DDWC_DEBUG_MEMORY
4262 +
4263 +EXTRA_CFLAGS += -DDWC_LIBMODULE
4264 +EXTRA_CFLAGS += -DDWC_CCLIB
4265 +EXTRA_CFLAGS += -DDWC_CRYPTOLIB
4266 +EXTRA_CFLAGS += -DDWC_NOTIFYLIB
4267 +EXTRA_CFLAGS += -DDWC_UTFLIB
4268 +
4269 +obj-m := dwc_common_port_lib.o
4270 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
4271 + dwc_crypto.o dwc_notifier.o \
4272 + dwc_common_linux.o dwc_mem.o
4273 +
4274 +else
4275 +
4276 +ifeq ($(KDIR),)
4277 +$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
4278 +endif
4279 +
4280 +ifeq ($(ARCH),)
4281 +$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
4282 + cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
4283 +endif
4284 +
4285 +ifeq ($(DOXYGEN),)
4286 +DOXYGEN := doxygen
4287 +endif
4288 +
4289 +default:
4290 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
4291 +
4292 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
4293 + $(DOXYGEN) doc/doxygen.cfg
4294 +
4295 +tags: $(wildcard *.[hc])
4296 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
4297 +
4298 +endif
4299 +
4300 +clean:
4301 + rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
4302 --- /dev/null
4303 +++ b/drivers/usb/host/dwc_common_port/changes.txt
4304 @@ -0,0 +1,174 @@
4305 +
4306 +dwc_read_reg32() and friends now take an additional parameter, a pointer to an
4307 +IO context struct. The IO context struct should live in an os-dependent struct
4308 +in your driver. As an example, the dwc_usb3 driver has an os-dependent struct
4309 +named 'os_dep' embedded in the main device struct. So there these calls look
4310 +like this:
4311 +
4312 + dwc_read_reg32(&usb3_dev->os_dep.ioctx, &pcd->dev_global_regs->dcfg);
4313 +
4314 + dwc_write_reg32(&usb3_dev->os_dep.ioctx,
4315 + &pcd->dev_global_regs->dcfg, 0);
4316 +
4317 +Note that for the existing Linux driver ports, it is not necessary to actually
4318 +define the 'ioctx' member in the os-dependent struct. Since Linux does not
4319 +require an IO context, its macros for dwc_read_reg32() and friends do not
4320 +use the context pointer, so it is optimized away by the compiler. But it is
4321 +necessary to add the pointer parameter to all of the call sites, to be ready
4322 +for any future ports (such as FreeBSD) which do require an IO context.
4323 +
4324 +
4325 +Similarly, dwc_alloc(), dwc_alloc_atomic(), dwc_strdup(), and dwc_free() now
4326 +take an additional parameter, a pointer to a memory context. Examples:
4327 +
4328 + addr = dwc_alloc(&usb3_dev->os_dep.memctx, size);
4329 +
4330 + dwc_free(&usb3_dev->os_dep.memctx, addr);
4331 +
4332 +Again, for the Linux ports, it is not necessary to actually define the memctx
4333 +member, but it is necessary to add the pointer parameter to all of the call
4334 +sites.
4335 +
4336 +
4337 +Same for dwc_dma_alloc() and dwc_dma_free(). Examples:
4338 +
4339 + virt_addr = dwc_dma_alloc(&usb3_dev->os_dep.dmactx, size, &phys_addr);
4340 +
4341 + dwc_dma_free(&usb3_dev->os_dep.dmactx, size, virt_addr, phys_addr);
4342 +
4343 +
4344 +Same for dwc_mutex_alloc() and dwc_mutex_free(). Examples:
4345 +
4346 + mutex = dwc_mutex_alloc(&usb3_dev->os_dep.mtxctx);
4347 +
4348 + dwc_mutex_free(&usb3_dev->os_dep.mtxctx, mutex);
4349 +
4350 +
4351 +Same for dwc_spinlock_alloc() and dwc_spinlock_free(). Examples:
4352 +
4353 + lock = dwc_spinlock_alloc(&usb3_dev->osdep.splctx);
4354 +
4355 + dwc_spinlock_free(&usb3_dev->osdep.splctx, lock);
4356 +
4357 +
4358 +Same for dwc_timer_alloc(). Example:
4359 +
4360 + timer = dwc_timer_alloc(&usb3_dev->os_dep.tmrctx, "dwc_usb3_tmr1",
4361 + cb_func, cb_data);
4362 +
4363 +
4364 +Same for dwc_waitq_alloc(). Example:
4365 +
4366 + waitq = dwc_waitq_alloc(&usb3_dev->os_dep.wtqctx);
4367 +
4368 +
4369 +Same for dwc_thread_run(). Example:
4370 +
4371 + thread = dwc_thread_run(&usb3_dev->os_dep.thdctx, func,
4372 + "dwc_usb3_thd1", data);
4373 +
4374 +
4375 +Same for dwc_workq_alloc(). Example:
4376 +
4377 + workq = dwc_workq_alloc(&usb3_dev->osdep.wkqctx, "dwc_usb3_wkq1");
4378 +
4379 +
4380 +Same for dwc_task_alloc(). Example:
4381 +
4382 + task = dwc_task_alloc(&usb3_dev->os_dep.tskctx, "dwc_usb3_tsk1",
4383 + cb_func, cb_data);
4384 +
4385 +
4386 +In addition to the context pointer additions, a few core functions have had
4387 +other changes made to their parameters:
4388 +
4389 +The 'flags' parameter to dwc_spinlock_irqsave() and dwc_spinunlock_irqrestore()
4390 +has been changed from a uint64_t to a dwc_irqflags_t.
4391 +
4392 +dwc_thread_should_stop() now takes a 'dwc_thread_t *' parameter, because the
4393 +FreeBSD equivalent of that function requires it.
4394 +
4395 +And, in addition to the context pointer, dwc_task_alloc() also adds a
4396 +'char *name' parameter, to be consistent with dwc_thread_run() and
4397 +dwc_workq_alloc(), and because the FreeBSD equivalent of that function
4398 +requires a unique name.
4399 +
4400 +
4401 +Here is a complete list of the core functions that now take a pointer to a
4402 +context as their first parameter:
4403 +
4404 + dwc_read_reg32
4405 + dwc_read_reg64
4406 + dwc_write_reg32
4407 + dwc_write_reg64
4408 + dwc_modify_reg32
4409 + dwc_modify_reg64
4410 + dwc_alloc
4411 + dwc_alloc_atomic
4412 + dwc_strdup
4413 + dwc_free
4414 + dwc_dma_alloc
4415 + dwc_dma_free
4416 + dwc_mutex_alloc
4417 + dwc_mutex_free
4418 + dwc_spinlock_alloc
4419 + dwc_spinlock_free
4420 + dwc_timer_alloc
4421 + dwc_waitq_alloc
4422 + dwc_thread_run
4423 + dwc_workq_alloc
4424 + dwc_task_alloc Also adds a 'char *name' as its 2nd parameter
4425 +
4426 +And here are the core functions that have other changes to their parameters:
4427 +
4428 + dwc_spinlock_irqsave 'flags' param is now a 'dwc_irqflags_t *'
4429 + dwc_spinunlock_irqrestore 'flags' param is now a 'dwc_irqflags_t'
4430 + dwc_thread_should_stop Adds a 'dwc_thread_t *' parameter
4431 +
4432 +
4433 +
4434 +The changes to the core functions also require some of the other library
4435 +functions to change:
4436 +
4437 + dwc_cc_if_alloc() and dwc_cc_if_free() now take a 'void *memctx'
4438 + (for memory allocation) as the 1st param and a 'void *mtxctx'
4439 + (for mutex allocation) as the 2nd param.
4440 +
4441 + dwc_cc_clear(), dwc_cc_add(), dwc_cc_change(), dwc_cc_remove(),
4442 + dwc_cc_data_for_save(), and dwc_cc_restore_from_data() now take a
4443 + 'void *memctx' as the 1st param.
4444 +
4445 + dwc_dh_modpow(), dwc_dh_pk(), and dwc_dh_derive_keys() now take a
4446 + 'void *memctx' as the 1st param.
4447 +
4448 + dwc_modpow() now takes a 'void *memctx' as the 1st param.
4449 +
4450 + dwc_alloc_notification_manager() now takes a 'void *memctx' as the
4451 + 1st param and a 'void *wkqctx' (for work queue allocation) as the 2nd
4452 + param, and also now returns an integer value that is non-zero if
4453 + allocation of its data structures or work queue fails.
4454 +
4455 + dwc_register_notifier() now takes a 'void *memctx' as the 1st param.
4456 +
4457 + dwc_memory_debug_start() now takes a 'void *mem_ctx' as the first
4458 + param, and also now returns an integer value that is non-zero if
4459 + allocation of its data structures fails.
4460 +
4461 +
4462 +
4463 +Other miscellaneous changes:
4464 +
4465 +The DEBUG_MEMORY and DEBUG_REGS #define's have been renamed to
4466 +DWC_DEBUG_MEMORY and DWC_DEBUG_REGS.
4467 +
4468 +The following #define's have been added to allow selectively compiling library
4469 +features:
4470 +
4471 + DWC_CCLIB
4472 + DWC_CRYPTOLIB
4473 + DWC_NOTIFYLIB
4474 + DWC_UTFLIB
4475 +
4476 +A DWC_LIBMODULE #define has also been added. If this is not defined, then the
4477 +module code in dwc_common_linux.c is not compiled in. This allows linking the
4478 +library code directly into a driver module, instead of as a standalone module.
4479 --- /dev/null
4480 +++ b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
4481 @@ -0,0 +1,270 @@
4482 +# Doxyfile 1.4.5
4483 +
4484 +#---------------------------------------------------------------------------
4485 +# Project related configuration options
4486 +#---------------------------------------------------------------------------
4487 +PROJECT_NAME = "Synopsys DWC Portability and Common Library for UWB"
4488 +PROJECT_NUMBER =
4489 +OUTPUT_DIRECTORY = doc
4490 +CREATE_SUBDIRS = NO
4491 +OUTPUT_LANGUAGE = English
4492 +BRIEF_MEMBER_DESC = YES
4493 +REPEAT_BRIEF = YES
4494 +ABBREVIATE_BRIEF = "The $name class" \
4495 + "The $name widget" \
4496 + "The $name file" \
4497 + is \
4498 + provides \
4499 + specifies \
4500 + contains \
4501 + represents \
4502 + a \
4503 + an \
4504 + the
4505 +ALWAYS_DETAILED_SEC = YES
4506 +INLINE_INHERITED_MEMB = NO
4507 +FULL_PATH_NAMES = NO
4508 +STRIP_FROM_PATH = ..
4509 +STRIP_FROM_INC_PATH =
4510 +SHORT_NAMES = NO
4511 +JAVADOC_AUTOBRIEF = YES
4512 +MULTILINE_CPP_IS_BRIEF = NO
4513 +DETAILS_AT_TOP = YES
4514 +INHERIT_DOCS = YES
4515 +SEPARATE_MEMBER_PAGES = NO
4516 +TAB_SIZE = 8
4517 +ALIASES =
4518 +OPTIMIZE_OUTPUT_FOR_C = YES
4519 +OPTIMIZE_OUTPUT_JAVA = NO
4520 +BUILTIN_STL_SUPPORT = NO
4521 +DISTRIBUTE_GROUP_DOC = NO
4522 +SUBGROUPING = NO
4523 +#---------------------------------------------------------------------------
4524 +# Build related configuration options
4525 +#---------------------------------------------------------------------------
4526 +EXTRACT_ALL = NO
4527 +EXTRACT_PRIVATE = NO
4528 +EXTRACT_STATIC = YES
4529 +EXTRACT_LOCAL_CLASSES = NO
4530 +EXTRACT_LOCAL_METHODS = NO
4531 +HIDE_UNDOC_MEMBERS = NO
4532 +HIDE_UNDOC_CLASSES = NO
4533 +HIDE_FRIEND_COMPOUNDS = NO
4534 +HIDE_IN_BODY_DOCS = NO
4535 +INTERNAL_DOCS = NO
4536 +CASE_SENSE_NAMES = YES
4537 +HIDE_SCOPE_NAMES = NO
4538 +SHOW_INCLUDE_FILES = NO
4539 +INLINE_INFO = YES
4540 +SORT_MEMBER_DOCS = NO
4541 +SORT_BRIEF_DOCS = NO
4542 +SORT_BY_SCOPE_NAME = NO
4543 +GENERATE_TODOLIST = YES
4544 +GENERATE_TESTLIST = YES
4545 +GENERATE_BUGLIST = YES
4546 +GENERATE_DEPRECATEDLIST= YES
4547 +ENABLED_SECTIONS =
4548 +MAX_INITIALIZER_LINES = 30
4549 +SHOW_USED_FILES = YES
4550 +SHOW_DIRECTORIES = YES
4551 +FILE_VERSION_FILTER =
4552 +#---------------------------------------------------------------------------
4553 +# configuration options related to warning and progress messages
4554 +#---------------------------------------------------------------------------
4555 +QUIET = YES
4556 +WARNINGS = YES
4557 +WARN_IF_UNDOCUMENTED = NO
4558 +WARN_IF_DOC_ERROR = YES
4559 +WARN_NO_PARAMDOC = YES
4560 +WARN_FORMAT = "$file:$line: $text"
4561 +WARN_LOGFILE =
4562 +#---------------------------------------------------------------------------
4563 +# configuration options related to the input files
4564 +#---------------------------------------------------------------------------
4565 +INPUT = .
4566 +FILE_PATTERNS = *.c \
4567 + *.cc \
4568 + *.cxx \
4569 + *.cpp \
4570 + *.c++ \
4571 + *.d \
4572 + *.java \
4573 + *.ii \
4574 + *.ixx \
4575 + *.ipp \
4576 + *.i++ \
4577 + *.inl \
4578 + *.h \
4579 + *.hh \
4580 + *.hxx \
4581 + *.hpp \
4582 + *.h++ \
4583 + *.idl \
4584 + *.odl \
4585 + *.cs \
4586 + *.php \
4587 + *.php3 \
4588 + *.inc \
4589 + *.m \
4590 + *.mm \
4591 + *.dox \
4592 + *.py \
4593 + *.C \
4594 + *.CC \
4595 + *.C++ \
4596 + *.II \
4597 + *.I++ \
4598 + *.H \
4599 + *.HH \
4600 + *.H++ \
4601 + *.CS \
4602 + *.PHP \
4603 + *.PHP3 \
4604 + *.M \
4605 + *.MM \
4606 + *.PY
4607 +RECURSIVE = NO
4608 +EXCLUDE =
4609 +EXCLUDE_SYMLINKS = NO
4610 +EXCLUDE_PATTERNS =
4611 +EXAMPLE_PATH =
4612 +EXAMPLE_PATTERNS = *
4613 +EXAMPLE_RECURSIVE = NO
4614 +IMAGE_PATH =
4615 +INPUT_FILTER =
4616 +FILTER_PATTERNS =
4617 +FILTER_SOURCE_FILES = NO
4618 +#---------------------------------------------------------------------------
4619 +# configuration options related to source browsing
4620 +#---------------------------------------------------------------------------
4621 +SOURCE_BROWSER = NO
4622 +INLINE_SOURCES = NO
4623 +STRIP_CODE_COMMENTS = YES
4624 +REFERENCED_BY_RELATION = YES
4625 +REFERENCES_RELATION = YES
4626 +USE_HTAGS = NO
4627 +VERBATIM_HEADERS = NO
4628 +#---------------------------------------------------------------------------
4629 +# configuration options related to the alphabetical class index
4630 +#---------------------------------------------------------------------------
4631 +ALPHABETICAL_INDEX = NO
4632 +COLS_IN_ALPHA_INDEX = 5
4633 +IGNORE_PREFIX =
4634 +#---------------------------------------------------------------------------
4635 +# configuration options related to the HTML output
4636 +#---------------------------------------------------------------------------
4637 +GENERATE_HTML = YES
4638 +HTML_OUTPUT = html
4639 +HTML_FILE_EXTENSION = .html
4640 +HTML_HEADER =
4641 +HTML_FOOTER =
4642 +HTML_STYLESHEET =
4643 +HTML_ALIGN_MEMBERS = YES
4644 +GENERATE_HTMLHELP = NO
4645 +CHM_FILE =
4646 +HHC_LOCATION =
4647 +GENERATE_CHI = NO
4648 +BINARY_TOC = NO
4649 +TOC_EXPAND = NO
4650 +DISABLE_INDEX = NO
4651 +ENUM_VALUES_PER_LINE = 4
4652 +GENERATE_TREEVIEW = YES
4653 +TREEVIEW_WIDTH = 250
4654 +#---------------------------------------------------------------------------
4655 +# configuration options related to the LaTeX output
4656 +#---------------------------------------------------------------------------
4657 +GENERATE_LATEX = NO
4658 +LATEX_OUTPUT = latex
4659 +LATEX_CMD_NAME = latex
4660 +MAKEINDEX_CMD_NAME = makeindex
4661 +COMPACT_LATEX = NO
4662 +PAPER_TYPE = a4wide
4663 +EXTRA_PACKAGES =
4664 +LATEX_HEADER =
4665 +PDF_HYPERLINKS = NO
4666 +USE_PDFLATEX = NO
4667 +LATEX_BATCHMODE = NO
4668 +LATEX_HIDE_INDICES = NO
4669 +#---------------------------------------------------------------------------
4670 +# configuration options related to the RTF output
4671 +#---------------------------------------------------------------------------
4672 +GENERATE_RTF = NO
4673 +RTF_OUTPUT = rtf
4674 +COMPACT_RTF = NO
4675 +RTF_HYPERLINKS = NO
4676 +RTF_STYLESHEET_FILE =
4677 +RTF_EXTENSIONS_FILE =
4678 +#---------------------------------------------------------------------------
4679 +# configuration options related to the man page output
4680 +#---------------------------------------------------------------------------
4681 +GENERATE_MAN = NO
4682 +MAN_OUTPUT = man
4683 +MAN_EXTENSION = .3
4684 +MAN_LINKS = NO
4685 +#---------------------------------------------------------------------------
4686 +# configuration options related to the XML output
4687 +#---------------------------------------------------------------------------
4688 +GENERATE_XML = NO
4689 +XML_OUTPUT = xml
4690 +XML_SCHEMA =
4691 +XML_DTD =
4692 +XML_PROGRAMLISTING = YES
4693 +#---------------------------------------------------------------------------
4694 +# configuration options for the AutoGen Definitions output
4695 +#---------------------------------------------------------------------------
4696 +GENERATE_AUTOGEN_DEF = NO
4697 +#---------------------------------------------------------------------------
4698 +# configuration options related to the Perl module output
4699 +#---------------------------------------------------------------------------
4700 +GENERATE_PERLMOD = NO
4701 +PERLMOD_LATEX = NO
4702 +PERLMOD_PRETTY = YES
4703 +PERLMOD_MAKEVAR_PREFIX =
4704 +#---------------------------------------------------------------------------
4705 +# Configuration options related to the preprocessor
4706 +#---------------------------------------------------------------------------
4707 +ENABLE_PREPROCESSING = YES
4708 +MACRO_EXPANSION = NO
4709 +EXPAND_ONLY_PREDEF = NO
4710 +SEARCH_INCLUDES = YES
4711 +INCLUDE_PATH =
4712 +INCLUDE_FILE_PATTERNS =
4713 +PREDEFINED = DEBUG DEBUG_MEMORY
4714 +EXPAND_AS_DEFINED =
4715 +SKIP_FUNCTION_MACROS = YES
4716 +#---------------------------------------------------------------------------
4717 +# Configuration::additions related to external references
4718 +#---------------------------------------------------------------------------
4719 +TAGFILES =
4720 +GENERATE_TAGFILE =
4721 +ALLEXTERNALS = NO
4722 +EXTERNAL_GROUPS = YES
4723 +PERL_PATH = /usr/bin/perl
4724 +#---------------------------------------------------------------------------
4725 +# Configuration options related to the dot tool
4726 +#---------------------------------------------------------------------------
4727 +CLASS_DIAGRAMS = YES
4728 +HIDE_UNDOC_RELATIONS = YES
4729 +HAVE_DOT = NO
4730 +CLASS_GRAPH = YES
4731 +COLLABORATION_GRAPH = YES
4732 +GROUP_GRAPHS = YES
4733 +UML_LOOK = NO
4734 +TEMPLATE_RELATIONS = NO
4735 +INCLUDE_GRAPH = NO
4736 +INCLUDED_BY_GRAPH = YES
4737 +CALL_GRAPH = NO
4738 +GRAPHICAL_HIERARCHY = YES
4739 +DIRECTORY_GRAPH = YES
4740 +DOT_IMAGE_FORMAT = png
4741 +DOT_PATH =
4742 +DOTFILE_DIRS =
4743 +MAX_DOT_GRAPH_DEPTH = 1000
4744 +DOT_TRANSPARENT = NO
4745 +DOT_MULTI_TARGETS = NO
4746 +GENERATE_LEGEND = YES
4747 +DOT_CLEANUP = YES
4748 +#---------------------------------------------------------------------------
4749 +# Configuration::additions related to the search engine
4750 +#---------------------------------------------------------------------------
4751 +SEARCHENGINE = NO
4752 --- /dev/null
4753 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.c
4754 @@ -0,0 +1,532 @@
4755 +/* =========================================================================
4756 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
4757 + * $Revision: #4 $
4758 + * $Date: 2010/11/04 $
4759 + * $Change: 1621692 $
4760 + *
4761 + * Synopsys Portability Library Software and documentation
4762 + * (hereinafter, "Software") is an Unsupported proprietary work of
4763 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
4764 + * between Synopsys and you.
4765 + *
4766 + * The Software IS NOT an item of Licensed Software or Licensed Product
4767 + * under any End User Software License Agreement or Agreement for
4768 + * Licensed Product with Synopsys or any supplement thereto. You are
4769 + * permitted to use and redistribute this Software in source and binary
4770 + * forms, with or without modification, provided that redistributions
4771 + * of source code must retain this notice. You may not view, use,
4772 + * disclose, copy or distribute this file or any information contained
4773 + * herein except pursuant to this license grant from Synopsys. If you
4774 + * do not agree with this notice, including the disclaimer below, then
4775 + * you are not authorized to use the Software.
4776 + *
4777 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
4778 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4779 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
4780 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
4781 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
4782 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
4783 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
4784 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
4785 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4786 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
4787 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
4788 + * DAMAGE.
4789 + * ========================================================================= */
4790 +#ifdef DWC_CCLIB
4791 +
4792 +#include "dwc_cc.h"
4793 +
4794 +typedef struct dwc_cc
4795 +{
4796 + uint32_t uid;
4797 + uint8_t chid[16];
4798 + uint8_t cdid[16];
4799 + uint8_t ck[16];
4800 + uint8_t *name;
4801 + uint8_t length;
4802 + DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
4803 +} dwc_cc_t;
4804 +
4805 +DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
4806 +
4807 +/** The main structure for CC management. */
4808 +struct dwc_cc_if
4809 +{
4810 + dwc_mutex_t *mutex;
4811 + char *filename;
4812 +
4813 + unsigned is_host:1;
4814 +
4815 + dwc_notifier_t *notifier;
4816 +
4817 + struct context_list list;
4818 +};
4819 +
4820 +#ifdef DEBUG
4821 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
4822 +{
4823 + int i;
4824 + DWC_PRINTF("%s: ", name);
4825 + for (i=0; i<len; i++) {
4826 + DWC_PRINTF("%02x ", bytes[i]);
4827 + }
4828 + DWC_PRINTF("\n");
4829 +}
4830 +#else
4831 +#define dump_bytes(x...)
4832 +#endif
4833 +
4834 +static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
4835 +{
4836 + dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
4837 + if (!cc) {
4838 + return NULL;
4839 + }
4840 + DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
4841 +
4842 + if (name) {
4843 + cc->length = length;
4844 + cc->name = dwc_alloc(mem_ctx, length);
4845 + if (!cc->name) {
4846 + dwc_free(mem_ctx, cc);
4847 + return NULL;
4848 + }
4849 +
4850 + DWC_MEMCPY(cc->name, name, length);
4851 + }
4852 +
4853 + return cc;
4854 +}
4855 +
4856 +static void free_cc(void *mem_ctx, dwc_cc_t *cc)
4857 +{
4858 + if (cc->name) {
4859 + dwc_free(mem_ctx, cc->name);
4860 + }
4861 + dwc_free(mem_ctx, cc);
4862 +}
4863 +
4864 +static uint32_t next_uid(dwc_cc_if_t *cc_if)
4865 +{
4866 + uint32_t uid = 0;
4867 + dwc_cc_t *cc;
4868 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4869 + if (cc->uid > uid) {
4870 + uid = cc->uid;
4871 + }
4872 + }
4873 +
4874 + if (uid == 0) {
4875 + uid = 255;
4876 + }
4877 +
4878 + return uid + 1;
4879 +}
4880 +
4881 +static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
4882 +{
4883 + dwc_cc_t *cc;
4884 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4885 + if (cc->uid == uid) {
4886 + return cc;
4887 + }
4888 + }
4889 + return NULL;
4890 +}
4891 +
4892 +static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
4893 +{
4894 + unsigned int size = 0;
4895 + dwc_cc_t *cc;
4896 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4897 + size += (48 + 1);
4898 + if (cc->name) {
4899 + size += cc->length;
4900 + }
4901 + }
4902 + return size;
4903 +}
4904 +
4905 +static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
4906 +{
4907 + uint32_t uid = 0;
4908 + dwc_cc_t *cc;
4909 +
4910 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4911 + if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
4912 + uid = cc->uid;
4913 + break;
4914 + }
4915 + }
4916 + return uid;
4917 +}
4918 +static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
4919 +{
4920 + uint32_t uid = 0;
4921 + dwc_cc_t *cc;
4922 +
4923 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4924 + if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
4925 + uid = cc->uid;
4926 + break;
4927 + }
4928 + }
4929 + return uid;
4930 +}
4931 +
4932 +/* Internal cc_add */
4933 +static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
4934 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
4935 +{
4936 + dwc_cc_t *cc;
4937 + uint32_t uid;
4938 +
4939 + if (cc_if->is_host) {
4940 + uid = cc_match_cdid(cc_if, cdid);
4941 + }
4942 + else {
4943 + uid = cc_match_chid(cc_if, chid);
4944 + }
4945 +
4946 + if (uid) {
4947 + DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
4948 + cc = cc_find(cc_if, uid);
4949 + }
4950 + else {
4951 + cc = alloc_cc(mem_ctx, name, length);
4952 + cc->uid = next_uid(cc_if);
4953 + DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
4954 + }
4955 +
4956 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
4957 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
4958 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
4959 +
4960 + DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
4961 + dump_bytes("CHID", cc->chid, 16);
4962 + dump_bytes("CDID", cc->cdid, 16);
4963 + dump_bytes("CK", cc->ck, 16);
4964 + return cc->uid;
4965 +}
4966 +
4967 +/* Internal cc_clear */
4968 +static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
4969 +{
4970 + while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
4971 + dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
4972 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
4973 + free_cc(mem_ctx, cc);
4974 + }
4975 +}
4976 +
4977 +dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
4978 + dwc_notifier_t *notifier, unsigned is_host)
4979 +{
4980 + dwc_cc_if_t *cc_if = NULL;
4981 +
4982 + /* Allocate a common_cc_if structure */
4983 + cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
4984 +
4985 + if (!cc_if)
4986 + return NULL;
4987 +
4988 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
4989 + DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
4990 +#else
4991 + cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
4992 +#endif
4993 + if (!cc_if->mutex) {
4994 + dwc_free(mem_ctx, cc_if);
4995 + return NULL;
4996 + }
4997 +
4998 + DWC_CIRCLEQ_INIT(&cc_if->list);
4999 + cc_if->is_host = is_host;
5000 + cc_if->notifier = notifier;
5001 + return cc_if;
5002 +}
5003 +
5004 +void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
5005 +{
5006 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
5007 + DWC_MUTEX_FREE(cc_if->mutex);
5008 +#else
5009 + dwc_mutex_free(mtx_ctx, cc_if->mutex);
5010 +#endif
5011 + cc_clear(mem_ctx, cc_if);
5012 + dwc_free(mem_ctx, cc_if);
5013 +}
5014 +
5015 +static void cc_changed(dwc_cc_if_t *cc_if)
5016 +{
5017 + if (cc_if->notifier) {
5018 + dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
5019 + }
5020 +}
5021 +
5022 +void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
5023 +{
5024 + DWC_MUTEX_LOCK(cc_if->mutex);
5025 + cc_clear(mem_ctx, cc_if);
5026 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5027 + cc_changed(cc_if);
5028 +}
5029 +
5030 +int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
5031 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
5032 +{
5033 + uint32_t uid;
5034 +
5035 + DWC_MUTEX_LOCK(cc_if->mutex);
5036 + uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
5037 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5038 + cc_changed(cc_if);
5039 +
5040 + return uid;
5041 +}
5042 +
5043 +void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
5044 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
5045 +{
5046 + dwc_cc_t* cc;
5047 +
5048 + DWC_DEBUGC("Change connection context %d", id);
5049 +
5050 + DWC_MUTEX_LOCK(cc_if->mutex);
5051 + cc = cc_find(cc_if, id);
5052 + if (!cc) {
5053 + DWC_ERROR("Uid %d not found in cc list\n", id);
5054 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5055 + return;
5056 + }
5057 +
5058 + if (chid) {
5059 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
5060 + }
5061 + if (cdid) {
5062 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
5063 + }
5064 + if (ck) {
5065 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
5066 + }
5067 +
5068 + if (name) {
5069 + if (cc->name) {
5070 + dwc_free(mem_ctx, cc->name);
5071 + }
5072 + cc->name = dwc_alloc(mem_ctx, length);
5073 + if (!cc->name) {
5074 + DWC_ERROR("Out of memory in dwc_cc_change()\n");
5075 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5076 + return;
5077 + }
5078 + cc->length = length;
5079 + DWC_MEMCPY(cc->name, name, length);
5080 + }
5081 +
5082 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5083 +
5084 + cc_changed(cc_if);
5085 +
5086 + DWC_DEBUGC("Changed connection context id=%d\n", id);
5087 + dump_bytes("New CHID", cc->chid, 16);
5088 + dump_bytes("New CDID", cc->cdid, 16);
5089 + dump_bytes("New CK", cc->ck, 16);
5090 +}
5091 +
5092 +void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
5093 +{
5094 + dwc_cc_t *cc;
5095 +
5096 + DWC_DEBUGC("Removing connection context %d", id);
5097 +
5098 + DWC_MUTEX_LOCK(cc_if->mutex);
5099 + cc = cc_find(cc_if, id);
5100 + if (!cc) {
5101 + DWC_ERROR("Uid %d not found in cc list\n", id);
5102 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5103 + return;
5104 + }
5105 +
5106 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
5107 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5108 + free_cc(mem_ctx, cc);
5109 +
5110 + cc_changed(cc_if);
5111 +}
5112 +
5113 +uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
5114 +{
5115 + uint8_t *buf, *x;
5116 + uint8_t zero = 0;
5117 + dwc_cc_t *cc;
5118 +
5119 + DWC_MUTEX_LOCK(cc_if->mutex);
5120 + *length = cc_data_size(cc_if);
5121 + if (!(*length)) {
5122 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5123 + return NULL;
5124 + }
5125 +
5126 + DWC_DEBUGC("Creating data for saving (length=%d)", *length);
5127 +
5128 + buf = dwc_alloc(mem_ctx, *length);
5129 + if (!buf) {
5130 + *length = 0;
5131 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5132 + return NULL;
5133 + }
5134 +
5135 + x = buf;
5136 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
5137 + DWC_MEMCPY(x, cc->chid, 16);
5138 + x += 16;
5139 + DWC_MEMCPY(x, cc->cdid, 16);
5140 + x += 16;
5141 + DWC_MEMCPY(x, cc->ck, 16);
5142 + x += 16;
5143 + if (cc->name) {
5144 + DWC_MEMCPY(x, &cc->length, 1);
5145 + x += 1;
5146 + DWC_MEMCPY(x, cc->name, cc->length);
5147 + x += cc->length;
5148 + }
5149 + else {
5150 + DWC_MEMCPY(x, &zero, 1);
5151 + x += 1;
5152 + }
5153 + }
5154 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5155 +
5156 + return buf;
5157 +}
5158 +
5159 +void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
5160 +{
5161 + uint8_t name_length;
5162 + uint8_t *name;
5163 + uint8_t *chid;
5164 + uint8_t *cdid;
5165 + uint8_t *ck;
5166 + uint32_t i = 0;
5167 +
5168 + DWC_MUTEX_LOCK(cc_if->mutex);
5169 + cc_clear(mem_ctx, cc_if);
5170 +
5171 + while (i < length) {
5172 + chid = &data[i];
5173 + i += 16;
5174 + cdid = &data[i];
5175 + i += 16;
5176 + ck = &data[i];
5177 + i += 16;
5178 +
5179 + name_length = data[i];
5180 + i ++;
5181 +
5182 + if (name_length) {
5183 + name = &data[i];
5184 + i += name_length;
5185 + }
5186 + else {
5187 + name = NULL;
5188 + }
5189 +
5190 + /* check to see if we haven't overflown the buffer */
5191 + if (i > length) {
5192 + DWC_ERROR("Data format error while attempting to load CCs "
5193 + "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
5194 + break;
5195 + }
5196 +
5197 + cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
5198 + }
5199 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5200 +
5201 + cc_changed(cc_if);
5202 +}
5203 +
5204 +uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
5205 +{
5206 + uint32_t uid = 0;
5207 +
5208 + DWC_MUTEX_LOCK(cc_if->mutex);
5209 + uid = cc_match_chid(cc_if, chid);
5210 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5211 + return uid;
5212 +}
5213 +uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
5214 +{
5215 + uint32_t uid = 0;
5216 +
5217 + DWC_MUTEX_LOCK(cc_if->mutex);
5218 + uid = cc_match_cdid(cc_if, cdid);
5219 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5220 + return uid;
5221 +}
5222 +
5223 +uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
5224 +{
5225 + uint8_t *ck = NULL;
5226 + dwc_cc_t *cc;
5227 +
5228 + DWC_MUTEX_LOCK(cc_if->mutex);
5229 + cc = cc_find(cc_if, id);
5230 + if (cc) {
5231 + ck = cc->ck;
5232 + }
5233 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5234 +
5235 + return ck;
5236 +
5237 +}
5238 +
5239 +uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
5240 +{
5241 + uint8_t *retval = NULL;
5242 + dwc_cc_t *cc;
5243 +
5244 + DWC_MUTEX_LOCK(cc_if->mutex);
5245 + cc = cc_find(cc_if, id);
5246 + if (cc) {
5247 + retval = cc->chid;
5248 + }
5249 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5250 +
5251 + return retval;
5252 +}
5253 +
5254 +uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
5255 +{
5256 + uint8_t *retval = NULL;
5257 + dwc_cc_t *cc;
5258 +
5259 + DWC_MUTEX_LOCK(cc_if->mutex);
5260 + cc = cc_find(cc_if, id);
5261 + if (cc) {
5262 + retval = cc->cdid;
5263 + }
5264 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5265 +
5266 + return retval;
5267 +}
5268 +
5269 +uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
5270 +{
5271 + uint8_t *retval = NULL;
5272 + dwc_cc_t *cc;
5273 +
5274 + DWC_MUTEX_LOCK(cc_if->mutex);
5275 + *length = 0;
5276 + cc = cc_find(cc_if, id);
5277 + if (cc) {
5278 + *length = cc->length;
5279 + retval = cc->name;
5280 + }
5281 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5282 +
5283 + return retval;
5284 +}
5285 +
5286 +#endif /* DWC_CCLIB */
5287 --- /dev/null
5288 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.h
5289 @@ -0,0 +1,225 @@
5290 +/* =========================================================================
5291 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $
5292 + * $Revision: #4 $
5293 + * $Date: 2010/09/28 $
5294 + * $Change: 1596182 $
5295 + *
5296 + * Synopsys Portability Library Software and documentation
5297 + * (hereinafter, "Software") is an Unsupported proprietary work of
5298 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
5299 + * between Synopsys and you.
5300 + *
5301 + * The Software IS NOT an item of Licensed Software or Licensed Product
5302 + * under any End User Software License Agreement or Agreement for
5303 + * Licensed Product with Synopsys or any supplement thereto. You are
5304 + * permitted to use and redistribute this Software in source and binary
5305 + * forms, with or without modification, provided that redistributions
5306 + * of source code must retain this notice. You may not view, use,
5307 + * disclose, copy or distribute this file or any information contained
5308 + * herein except pursuant to this license grant from Synopsys. If you
5309 + * do not agree with this notice, including the disclaimer below, then
5310 + * you are not authorized to use the Software.
5311 + *
5312 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
5313 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5314 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
5315 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
5316 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
5317 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
5318 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
5319 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
5320 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5321 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
5322 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
5323 + * DAMAGE.
5324 + * ========================================================================= */
5325 +#ifndef _DWC_CC_H_
5326 +#define _DWC_CC_H_
5327 +
5328 +#ifdef __cplusplus
5329 +extern "C" {
5330 +#endif
5331 +
5332 +/** @file
5333 + *
5334 + * This file defines the Context Context library.
5335 + *
5336 + * The main data structure is dwc_cc_if_t which is returned by either the
5337 + * dwc_cc_if_alloc function or returned by the module to the user via a provided
5338 + * function. The data structure is opaque and should only be manipulated via the
5339 + * functions provied in this API.
5340 + *
5341 + * It manages a list of connection contexts and operations can be performed to
5342 + * add, remove, query, search, and change, those contexts. Additionally,
5343 + * a dwc_notifier_t object can be requested from the manager so that
5344 + * the user can be notified whenever the context list has changed.
5345 + */
5346 +
5347 +#include "dwc_os.h"
5348 +#include "dwc_list.h"
5349 +#include "dwc_notifier.h"
5350 +
5351 +
5352 +/* Notifications */
5353 +#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
5354 +
5355 +struct dwc_cc_if;
5356 +typedef struct dwc_cc_if dwc_cc_if_t;
5357 +
5358 +
5359 +/** @name Connection Context Operations */
5360 +/** @{ */
5361 +
5362 +/** This function allocates memory for a dwc_cc_if_t structure, initializes
5363 + * fields to default values, and returns a pointer to the structure or NULL on
5364 + * error. */
5365 +extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
5366 + dwc_notifier_t *notifier, unsigned is_host);
5367 +
5368 +/** Frees the memory for the specified CC structure allocated from
5369 + * dwc_cc_if_alloc(). */
5370 +extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if);
5371 +
5372 +/** Removes all contexts from the connection context list */
5373 +extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if);
5374 +
5375 +/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
5376 + * If a CHID already exists, the CK and name are overwritten. Statistics are
5377 + * not overwritten.
5378 + *
5379 + * @param cc_if The cc_if structure.
5380 + * @param chid A pointer to the 16-byte CHID. This value will be copied.
5381 + * @param ck A pointer to the 16-byte CK. This value will be copied.
5382 + * @param cdid A pointer to the 16-byte CDID. This value will be copied.
5383 + * @param name An optional host friendly name as defined in the association model
5384 + * spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name.
5385 + * @param length The length othe unicode string.
5386 + * @return A unique identifier used to refer to this context that is valid for
5387 + * as long as this context is still in the list. */
5388 +extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
5389 + uint8_t *cdid, uint8_t *ck, uint8_t *name,
5390 + uint8_t length);
5391 +
5392 +/** Changes the CHID, CK, CDID, or Name values of a connection context in the
5393 + * list, preserving any accumulated statistics. This would typically be called
5394 + * if the host decideds to change the context with a SET_CONNECTION request.
5395 + *
5396 + * @param cc_if The cc_if structure.
5397 + * @param id The identifier of the connection context.
5398 + * @param chid A pointer to the 16-byte CHID. This value will be copied. NULL
5399 + * indicates no change.
5400 + * @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL
5401 + * indicates no change.
5402 + * @param ck A pointer to the 16-byte CK. This value will be copied. NULL
5403 + * indicates no change.
5404 + * @param name Host friendly name UTF16-LE. NULL indicates no change.
5405 + * @param length Length of name. */
5406 +extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id,
5407 + uint8_t *chid, uint8_t *cdid, uint8_t *ck,
5408 + uint8_t *name, uint8_t length);
5409 +
5410 +/** Remove the specified connection context.
5411 + * @param cc_if The cc_if structure.
5412 + * @param id The identifier of the connection context to remove. */
5413 +extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id);
5414 +
5415 +/** Get a binary block of data for the connection context list and attributes.
5416 + * This data can be used by the OS specific driver to save the connection
5417 + * context list into non-volatile memory.
5418 + *
5419 + * @param cc_if The cc_if structure.
5420 + * @param length Return the length of the data buffer.
5421 + * @return A pointer to the data buffer. The memory for this buffer should be
5422 + * freed with DWC_FREE() after use. */
5423 +extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if,
5424 + unsigned int *length);
5425 +
5426 +/** Restore the connection context list from the binary data that was previously
5427 + * returned from a call to dwc_cc_data_for_save. This can be used by the OS specific
5428 + * driver to load a connection context list from non-volatile memory.
5429 + *
5430 + * @param cc_if The cc_if structure.
5431 + * @param data The data bytes as returned from dwc_cc_data_for_save.
5432 + * @param length The length of the data. */
5433 +extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if,
5434 + uint8_t *data, unsigned int length);
5435 +
5436 +/** Find the connection context from the specified CHID.
5437 + *
5438 + * @param cc_if The cc_if structure.
5439 + * @param chid A pointer to the CHID data.
5440 + * @return A non-zero identifier of the connection context if the CHID matches.
5441 + * Otherwise returns 0. */
5442 +extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
5443 +
5444 +/** Find the connection context from the specified CDID.
5445 + *
5446 + * @param cc_if The cc_if structure.
5447 + * @param cdid A pointer to the CDID data.
5448 + * @return A non-zero identifier of the connection context if the CHID matches.
5449 + * Otherwise returns 0. */
5450 +extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
5451 +
5452 +/** Retrieve the CK from the specified connection context.
5453 + *
5454 + * @param cc_if The cc_if structure.
5455 + * @param id The identifier of the connection context.
5456 + * @return A pointer to the CK data. The memory does not need to be freed. */
5457 +extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
5458 +
5459 +/** Retrieve the CHID from the specified connection context.
5460 + *
5461 + * @param cc_if The cc_if structure.
5462 + * @param id The identifier of the connection context.
5463 + * @return A pointer to the CHID data. The memory does not need to be freed. */
5464 +extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
5465 +
5466 +/** Retrieve the CDID from the specified connection context.
5467 + *
5468 + * @param cc_if The cc_if structure.
5469 + * @param id The identifier of the connection context.
5470 + * @return A pointer to the CDID data. The memory does not need to be freed. */
5471 +extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
5472 +
5473 +extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
5474 +
5475 +/** Checks a buffer for non-zero.
5476 + * @param id A pointer to a 16 byte buffer.
5477 + * @return true if the 16 byte value is non-zero. */
5478 +static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
5479 + int i;
5480 + for (i=0; i<16; i++) {
5481 + if (id[i]) return 1;
5482 + }
5483 + return 0;
5484 +}
5485 +
5486 +/** Checks a buffer for zero.
5487 + * @param id A pointer to a 16 byte buffer.
5488 + * @return true if the 16 byte value is zero. */
5489 +static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
5490 + return !dwc_assoc_is_not_zero_id(id);
5491 +}
5492 +
5493 +/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
5494 + * buffer. */
5495 +static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
5496 + char *ptr = buffer;
5497 + int i;
5498 + for (i=0; i<16; i++) {
5499 + ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
5500 + if (i < 15) {
5501 + ptr += DWC_SPRINTF(ptr, " ");
5502 + }
5503 + }
5504 + return ptr - buffer;
5505 +}
5506 +
5507 +/** @} */
5508 +
5509 +#ifdef __cplusplus
5510 +}
5511 +#endif
5512 +
5513 +#endif /* _DWC_CC_H_ */
5514 +
5515 --- /dev/null
5516 +++ b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
5517 @@ -0,0 +1,1308 @@
5518 +#include "dwc_os.h"
5519 +#include "dwc_list.h"
5520 +
5521 +#ifdef DWC_CCLIB
5522 +# include "dwc_cc.h"
5523 +#endif
5524 +
5525 +#ifdef DWC_CRYPTOLIB
5526 +# include "dwc_modpow.h"
5527 +# include "dwc_dh.h"
5528 +# include "dwc_crypto.h"
5529 +#endif
5530 +
5531 +#ifdef DWC_NOTIFYLIB
5532 +# include "dwc_notifier.h"
5533 +#endif
5534 +
5535 +/* OS-Level Implementations */
5536 +
5537 +/* This is the FreeBSD 7.0 kernel implementation of the DWC platform library. */
5538 +
5539 +
5540 +/* MISC */
5541 +
5542 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
5543 +{
5544 + return memset(dest, byte, size);
5545 +}
5546 +
5547 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
5548 +{
5549 + return memcpy(dest, src, size);
5550 +}
5551 +
5552 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
5553 +{
5554 + bcopy(src, dest, size);
5555 + return dest;
5556 +}
5557 +
5558 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
5559 +{
5560 + return memcmp(m1, m2, size);
5561 +}
5562 +
5563 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
5564 +{
5565 + return strncmp(s1, s2, size);
5566 +}
5567 +
5568 +int DWC_STRCMP(void *s1, void *s2)
5569 +{
5570 + return strcmp(s1, s2);
5571 +}
5572 +
5573 +int DWC_STRLEN(char const *str)
5574 +{
5575 + return strlen(str);
5576 +}
5577 +
5578 +char *DWC_STRCPY(char *to, char const *from)
5579 +{
5580 + return strcpy(to, from);
5581 +}
5582 +
5583 +char *DWC_STRDUP(char const *str)
5584 +{
5585 + int len = DWC_STRLEN(str) + 1;
5586 + char *new = DWC_ALLOC_ATOMIC(len);
5587 +
5588 + if (!new) {
5589 + return NULL;
5590 + }
5591 +
5592 + DWC_MEMCPY(new, str, len);
5593 + return new;
5594 +}
5595 +
5596 +int DWC_ATOI(char *str, int32_t *value)
5597 +{
5598 + char *end = NULL;
5599 +
5600 + *value = strtol(str, &end, 0);
5601 + if (*end == '\0') {
5602 + return 0;
5603 + }
5604 +
5605 + return -1;
5606 +}
5607 +
5608 +int DWC_ATOUI(char *str, uint32_t *value)
5609 +{
5610 + char *end = NULL;
5611 +
5612 + *value = strtoul(str, &end, 0);
5613 + if (*end == '\0') {
5614 + return 0;
5615 + }
5616 +
5617 + return -1;
5618 +}
5619 +
5620 +
5621 +#ifdef DWC_UTFLIB
5622 +/* From usbstring.c */
5623 +
5624 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
5625 +{
5626 + int count = 0;
5627 + u8 c;
5628 + u16 uchar;
5629 +
5630 + /* this insists on correct encodings, though not minimal ones.
5631 + * BUT it currently rejects legit 4-byte UTF-8 code points,
5632 + * which need surrogate pairs. (Unicode 3.1 can use them.)
5633 + */
5634 + while (len != 0 && (c = (u8) *s++) != 0) {
5635 + if (unlikely(c & 0x80)) {
5636 + // 2-byte sequence:
5637 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
5638 + if ((c & 0xe0) == 0xc0) {
5639 + uchar = (c & 0x1f) << 6;
5640 +
5641 + c = (u8) *s++;
5642 + if ((c & 0xc0) != 0xc0)
5643 + goto fail;
5644 + c &= 0x3f;
5645 + uchar |= c;
5646 +
5647 + // 3-byte sequence (most CJKV characters):
5648 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
5649 + } else if ((c & 0xf0) == 0xe0) {
5650 + uchar = (c & 0x0f) << 12;
5651 +
5652 + c = (u8) *s++;
5653 + if ((c & 0xc0) != 0xc0)
5654 + goto fail;
5655 + c &= 0x3f;
5656 + uchar |= c << 6;
5657 +
5658 + c = (u8) *s++;
5659 + if ((c & 0xc0) != 0xc0)
5660 + goto fail;
5661 + c &= 0x3f;
5662 + uchar |= c;
5663 +
5664 + /* no bogus surrogates */
5665 + if (0xd800 <= uchar && uchar <= 0xdfff)
5666 + goto fail;
5667 +
5668 + // 4-byte sequence (surrogate pairs, currently rare):
5669 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
5670 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
5671 + // (uuuuu = wwww + 1)
5672 + // FIXME accept the surrogate code points (only)
5673 + } else
5674 + goto fail;
5675 + } else
5676 + uchar = c;
5677 + put_unaligned (cpu_to_le16 (uchar), cp++);
5678 + count++;
5679 + len--;
5680 + }
5681 + return count;
5682 +fail:
5683 + return -1;
5684 +}
5685 +
5686 +#endif /* DWC_UTFLIB */
5687 +
5688 +
5689 +/* dwc_debug.h */
5690 +
5691 +dwc_bool_t DWC_IN_IRQ(void)
5692 +{
5693 +// return in_irq();
5694 + return 0;
5695 +}
5696 +
5697 +dwc_bool_t DWC_IN_BH(void)
5698 +{
5699 +// return in_softirq();
5700 + return 0;
5701 +}
5702 +
5703 +void DWC_VPRINTF(char *format, va_list args)
5704 +{
5705 + vprintf(format, args);
5706 +}
5707 +
5708 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
5709 +{
5710 + return vsnprintf(str, size, format, args);
5711 +}
5712 +
5713 +void DWC_PRINTF(char *format, ...)
5714 +{
5715 + va_list args;
5716 +
5717 + va_start(args, format);
5718 + DWC_VPRINTF(format, args);
5719 + va_end(args);
5720 +}
5721 +
5722 +int DWC_SPRINTF(char *buffer, char *format, ...)
5723 +{
5724 + int retval;
5725 + va_list args;
5726 +
5727 + va_start(args, format);
5728 + retval = vsprintf(buffer, format, args);
5729 + va_end(args);
5730 + return retval;
5731 +}
5732 +
5733 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
5734 +{
5735 + int retval;
5736 + va_list args;
5737 +
5738 + va_start(args, format);
5739 + retval = vsnprintf(buffer, size, format, args);
5740 + va_end(args);
5741 + return retval;
5742 +}
5743 +
5744 +void __DWC_WARN(char *format, ...)
5745 +{
5746 + va_list args;
5747 +
5748 + va_start(args, format);
5749 + DWC_VPRINTF(format, args);
5750 + va_end(args);
5751 +}
5752 +
5753 +void __DWC_ERROR(char *format, ...)
5754 +{
5755 + va_list args;
5756 +
5757 + va_start(args, format);
5758 + DWC_VPRINTF(format, args);
5759 + va_end(args);
5760 +}
5761 +
5762 +void DWC_EXCEPTION(char *format, ...)
5763 +{
5764 + va_list args;
5765 +
5766 + va_start(args, format);
5767 + DWC_VPRINTF(format, args);
5768 + va_end(args);
5769 +// BUG_ON(1); ???
5770 +}
5771 +
5772 +#ifdef DEBUG
5773 +void __DWC_DEBUG(char *format, ...)
5774 +{
5775 + va_list args;
5776 +
5777 + va_start(args, format);
5778 + DWC_VPRINTF(format, args);
5779 + va_end(args);
5780 +}
5781 +#endif
5782 +
5783 +
5784 +/* dwc_mem.h */
5785 +
5786 +#if 0
5787 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
5788 + uint32_t align,
5789 + uint32_t alloc)
5790 +{
5791 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
5792 + size, align, alloc);
5793 + return (dwc_pool_t *)pool;
5794 +}
5795 +
5796 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
5797 +{
5798 + dma_pool_destroy((struct dma_pool *)pool);
5799 +}
5800 +
5801 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
5802 +{
5803 +// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
5804 + return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
5805 +}
5806 +
5807 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
5808 +{
5809 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
5810 + memset(..);
5811 +}
5812 +
5813 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
5814 +{
5815 + dma_pool_free(pool, vaddr, daddr);
5816 +}
5817 +#endif
5818 +
5819 +static void dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
5820 +{
5821 + if (error)
5822 + return;
5823 + *(bus_addr_t *)arg = segs[0].ds_addr;
5824 +}
5825 +
5826 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
5827 +{
5828 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
5829 + int error;
5830 +
5831 + error = bus_dma_tag_create(
5832 +#if __FreeBSD_version >= 700000
5833 + bus_get_dma_tag(dma->dev), /* parent */
5834 +#else
5835 + NULL, /* parent */
5836 +#endif
5837 + 4, 0, /* alignment, bounds */
5838 + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
5839 + BUS_SPACE_MAXADDR, /* highaddr */
5840 + NULL, NULL, /* filter, filterarg */
5841 + size, /* maxsize */
5842 + 1, /* nsegments */
5843 + size, /* maxsegsize */
5844 + 0, /* flags */
5845 + NULL, /* lockfunc */
5846 + NULL, /* lockarg */
5847 + &dma->dma_tag);
5848 + if (error) {
5849 + device_printf(dma->dev, "%s: bus_dma_tag_create failed: %d\n",
5850 + __func__, error);
5851 + goto fail_0;
5852 + }
5853 +
5854 + error = bus_dmamem_alloc(dma->dma_tag, &dma->dma_vaddr,
5855 + BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map);
5856 + if (error) {
5857 + device_printf(dma->dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n",
5858 + __func__, (uintmax_t)size, error);
5859 + goto fail_1;
5860 + }
5861 +
5862 + dma->dma_paddr = 0;
5863 + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size,
5864 + dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT);
5865 + if (error || dma->dma_paddr == 0) {
5866 + device_printf(dma->dev, "%s: bus_dmamap_load failed: %d\n",
5867 + __func__, error);
5868 + goto fail_2;
5869 + }
5870 +
5871 + *dma_addr = dma->dma_paddr;
5872 + return dma->dma_vaddr;
5873 +
5874 +fail_2:
5875 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
5876 +fail_1:
5877 + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
5878 + bus_dma_tag_destroy(dma->dma_tag);
5879 +fail_0:
5880 + dma->dma_map = NULL;
5881 + dma->dma_tag = NULL;
5882 +
5883 + return NULL;
5884 +}
5885 +
5886 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
5887 +{
5888 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
5889 +
5890 + if (dma->dma_tag == NULL)
5891 + return;
5892 + if (dma->dma_map != NULL) {
5893 + bus_dmamap_sync(dma->dma_tag, dma->dma_map,
5894 + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
5895 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
5896 + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
5897 + dma->dma_map = NULL;
5898 + }
5899 +
5900 + bus_dma_tag_destroy(dma->dma_tag);
5901 + dma->dma_tag = NULL;
5902 +}
5903 +
5904 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
5905 +{
5906 + return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
5907 +}
5908 +
5909 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
5910 +{
5911 + return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
5912 +}
5913 +
5914 +void __DWC_FREE(void *mem_ctx, void *addr)
5915 +{
5916 + free(addr, M_DEVBUF);
5917 +}
5918 +
5919 +
5920 +#ifdef DWC_CRYPTOLIB
5921 +/* dwc_crypto.h */
5922 +
5923 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
5924 +{
5925 + get_random_bytes(buffer, length);
5926 +}
5927 +
5928 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
5929 +{
5930 + struct crypto_blkcipher *tfm;
5931 + struct blkcipher_desc desc;
5932 + struct scatterlist sgd;
5933 + struct scatterlist sgs;
5934 +
5935 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
5936 + if (tfm == NULL) {
5937 + printk("failed to load transform for aes CBC\n");
5938 + return -1;
5939 + }
5940 +
5941 + crypto_blkcipher_setkey(tfm, key, keylen);
5942 + crypto_blkcipher_set_iv(tfm, iv, 16);
5943 +
5944 + sg_init_one(&sgd, out, messagelen);
5945 + sg_init_one(&sgs, message, messagelen);
5946 +
5947 + desc.tfm = tfm;
5948 + desc.flags = 0;
5949 +
5950 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
5951 + crypto_free_blkcipher(tfm);
5952 + DWC_ERROR("AES CBC encryption failed");
5953 + return -1;
5954 + }
5955 +
5956 + crypto_free_blkcipher(tfm);
5957 + return 0;
5958 +}
5959 +
5960 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
5961 +{
5962 + struct crypto_hash *tfm;
5963 + struct hash_desc desc;
5964 + struct scatterlist sg;
5965 +
5966 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
5967 + if (IS_ERR(tfm)) {
5968 + DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
5969 + return 0;
5970 + }
5971 + desc.tfm = tfm;
5972 + desc.flags = 0;
5973 +
5974 + sg_init_one(&sg, message, len);
5975 + crypto_hash_digest(&desc, &sg, len, out);
5976 + crypto_free_hash(tfm);
5977 +
5978 + return 1;
5979 +}
5980 +
5981 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
5982 + uint8_t *key, uint32_t keylen, uint8_t *out)
5983 +{
5984 + struct crypto_hash *tfm;
5985 + struct hash_desc desc;
5986 + struct scatterlist sg;
5987 +
5988 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
5989 + if (IS_ERR(tfm)) {
5990 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
5991 + return 0;
5992 + }
5993 + desc.tfm = tfm;
5994 + desc.flags = 0;
5995 +
5996 + sg_init_one(&sg, message, messagelen);
5997 + crypto_hash_setkey(tfm, key, keylen);
5998 + crypto_hash_digest(&desc, &sg, messagelen, out);
5999 + crypto_free_hash(tfm);
6000 +
6001 + return 1;
6002 +}
6003 +
6004 +#endif /* DWC_CRYPTOLIB */
6005 +
6006 +
6007 +/* Byte Ordering Conversions */
6008 +
6009 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
6010 +{
6011 +#ifdef __LITTLE_ENDIAN
6012 + return *p;
6013 +#else
6014 + uint8_t *u_p = (uint8_t *)p;
6015 +
6016 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6017 +#endif
6018 +}
6019 +
6020 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
6021 +{
6022 +#ifdef __BIG_ENDIAN
6023 + return *p;
6024 +#else
6025 + uint8_t *u_p = (uint8_t *)p;
6026 +
6027 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6028 +#endif
6029 +}
6030 +
6031 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
6032 +{
6033 +#ifdef __LITTLE_ENDIAN
6034 + return *p;
6035 +#else
6036 + uint8_t *u_p = (uint8_t *)p;
6037 +
6038 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6039 +#endif
6040 +}
6041 +
6042 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
6043 +{
6044 +#ifdef __BIG_ENDIAN
6045 + return *p;
6046 +#else
6047 + uint8_t *u_p = (uint8_t *)p;
6048 +
6049 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6050 +#endif
6051 +}
6052 +
6053 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
6054 +{
6055 +#ifdef __LITTLE_ENDIAN
6056 + return *p;
6057 +#else
6058 + uint8_t *u_p = (uint8_t *)p;
6059 + return (u_p[1] | (u_p[0] << 8));
6060 +#endif
6061 +}
6062 +
6063 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
6064 +{
6065 +#ifdef __BIG_ENDIAN
6066 + return *p;
6067 +#else
6068 + uint8_t *u_p = (uint8_t *)p;
6069 + return (u_p[1] | (u_p[0] << 8));
6070 +#endif
6071 +}
6072 +
6073 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
6074 +{
6075 +#ifdef __LITTLE_ENDIAN
6076 + return *p;
6077 +#else
6078 + uint8_t *u_p = (uint8_t *)p;
6079 + return (u_p[1] | (u_p[0] << 8));
6080 +#endif
6081 +}
6082 +
6083 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
6084 +{
6085 +#ifdef __BIG_ENDIAN
6086 + return *p;
6087 +#else
6088 + uint8_t *u_p = (uint8_t *)p;
6089 + return (u_p[1] | (u_p[0] << 8));
6090 +#endif
6091 +}
6092 +
6093 +
6094 +/* Registers */
6095 +
6096 +uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
6097 +{
6098 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6099 + bus_size_t ior = (bus_size_t)reg;
6100 +
6101 + return bus_space_read_4(io->iot, io->ioh, ior);
6102 +}
6103 +
6104 +#if 0
6105 +uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
6106 +{
6107 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6108 + bus_size_t ior = (bus_size_t)reg;
6109 +
6110 + return bus_space_read_8(io->iot, io->ioh, ior);
6111 +}
6112 +#endif
6113 +
6114 +void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
6115 +{
6116 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6117 + bus_size_t ior = (bus_size_t)reg;
6118 +
6119 + bus_space_write_4(io->iot, io->ioh, ior, value);
6120 +}
6121 +
6122 +#if 0
6123 +void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
6124 +{
6125 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6126 + bus_size_t ior = (bus_size_t)reg;
6127 +
6128 + bus_space_write_8(io->iot, io->ioh, ior, value);
6129 +}
6130 +#endif
6131 +
6132 +void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
6133 + uint32_t set_mask)
6134 +{
6135 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6136 + bus_size_t ior = (bus_size_t)reg;
6137 +
6138 + bus_space_write_4(io->iot, io->ioh, ior,
6139 + (bus_space_read_4(io->iot, io->ioh, ior) &
6140 + ~clear_mask) | set_mask);
6141 +}
6142 +
6143 +#if 0
6144 +void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
6145 + uint64_t set_mask)
6146 +{
6147 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6148 + bus_size_t ior = (bus_size_t)reg;
6149 +
6150 + bus_space_write_8(io->iot, io->ioh, ior,
6151 + (bus_space_read_8(io->iot, io->ioh, ior) &
6152 + ~clear_mask) | set_mask);
6153 +}
6154 +#endif
6155 +
6156 +
6157 +/* Locking */
6158 +
6159 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
6160 +{
6161 + struct mtx *sl = DWC_ALLOC(sizeof(*sl));
6162 +
6163 + if (!sl) {
6164 + DWC_ERROR("Cannot allocate memory for spinlock");
6165 + return NULL;
6166 + }
6167 +
6168 + mtx_init(sl, "dw3spn", NULL, MTX_SPIN);
6169 + return (dwc_spinlock_t *)sl;
6170 +}
6171 +
6172 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
6173 +{
6174 + struct mtx *sl = (struct mtx *)lock;
6175 +
6176 + mtx_destroy(sl);
6177 + DWC_FREE(sl);
6178 +}
6179 +
6180 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
6181 +{
6182 + mtx_lock_spin((struct mtx *)lock); // ???
6183 +}
6184 +
6185 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
6186 +{
6187 + mtx_unlock_spin((struct mtx *)lock); // ???
6188 +}
6189 +
6190 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
6191 +{
6192 + mtx_lock_spin((struct mtx *)lock);
6193 +}
6194 +
6195 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
6196 +{
6197 + mtx_unlock_spin((struct mtx *)lock);
6198 +}
6199 +
6200 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
6201 +{
6202 + struct mtx *m;
6203 + dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mtx));
6204 +
6205 + if (!mutex) {
6206 + DWC_ERROR("Cannot allocate memory for mutex");
6207 + return NULL;
6208 + }
6209 +
6210 + m = (struct mtx *)mutex;
6211 + mtx_init(m, "dw3mtx", NULL, MTX_DEF);
6212 + return mutex;
6213 +}
6214 +
6215 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
6216 +#else
6217 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
6218 +{
6219 + mtx_destroy((struct mtx *)mutex);
6220 + DWC_FREE(mutex);
6221 +}
6222 +#endif
6223 +
6224 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
6225 +{
6226 + struct mtx *m = (struct mtx *)mutex;
6227 +
6228 + mtx_lock(m);
6229 +}
6230 +
6231 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
6232 +{
6233 + struct mtx *m = (struct mtx *)mutex;
6234 +
6235 + return mtx_trylock(m);
6236 +}
6237 +
6238 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
6239 +{
6240 + struct mtx *m = (struct mtx *)mutex;
6241 +
6242 + mtx_unlock(m);
6243 +}
6244 +
6245 +
6246 +/* Timing */
6247 +
6248 +void DWC_UDELAY(uint32_t usecs)
6249 +{
6250 + DELAY(usecs);
6251 +}
6252 +
6253 +void DWC_MDELAY(uint32_t msecs)
6254 +{
6255 + do {
6256 + DELAY(1000);
6257 + } while (--msecs);
6258 +}
6259 +
6260 +void DWC_MSLEEP(uint32_t msecs)
6261 +{
6262 + struct timeval tv;
6263 +
6264 + tv.tv_sec = msecs / 1000;
6265 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
6266 + pause("dw3slp", tvtohz(&tv));
6267 +}
6268 +
6269 +uint32_t DWC_TIME(void)
6270 +{
6271 + struct timeval tv;
6272 +
6273 + microuptime(&tv); // or getmicrouptime? (less precise, but faster)
6274 + return tv.tv_sec * 1000 + tv.tv_usec / 1000;
6275 +}
6276 +
6277 +
6278 +/* Timers */
6279 +
6280 +struct dwc_timer {
6281 + struct callout t;
6282 + char *name;
6283 + dwc_spinlock_t *lock;
6284 + dwc_timer_callback_t cb;
6285 + void *data;
6286 +};
6287 +
6288 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
6289 +{
6290 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
6291 +
6292 + if (!t) {
6293 + DWC_ERROR("Cannot allocate memory for timer");
6294 + return NULL;
6295 + }
6296 +
6297 + callout_init(&t->t, 1);
6298 +
6299 + t->name = DWC_STRDUP(name);
6300 + if (!t->name) {
6301 + DWC_ERROR("Cannot allocate memory for timer->name");
6302 + goto no_name;
6303 + }
6304 +
6305 + t->lock = DWC_SPINLOCK_ALLOC();
6306 + if (!t->lock) {
6307 + DWC_ERROR("Cannot allocate memory for lock");
6308 + goto no_lock;
6309 + }
6310 +
6311 + t->cb = cb;
6312 + t->data = data;
6313 +
6314 + return t;
6315 +
6316 + no_lock:
6317 + DWC_FREE(t->name);
6318 + no_name:
6319 + DWC_FREE(t);
6320 +
6321 + return NULL;
6322 +}
6323 +
6324 +void DWC_TIMER_FREE(dwc_timer_t *timer)
6325 +{
6326 + callout_stop(&timer->t);
6327 + DWC_SPINLOCK_FREE(timer->lock);
6328 + DWC_FREE(timer->name);
6329 + DWC_FREE(timer);
6330 +}
6331 +
6332 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
6333 +{
6334 + struct timeval tv;
6335 +
6336 + tv.tv_sec = time / 1000;
6337 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
6338 + callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
6339 +}
6340 +
6341 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
6342 +{
6343 + callout_stop(&timer->t);
6344 +}
6345 +
6346 +
6347 +/* Wait Queues */
6348 +
6349 +struct dwc_waitq {
6350 + struct mtx lock;
6351 + int abort;
6352 +};
6353 +
6354 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
6355 +{
6356 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
6357 +
6358 + if (!wq) {
6359 + DWC_ERROR("Cannot allocate memory for waitqueue");
6360 + return NULL;
6361 + }
6362 +
6363 + mtx_init(&wq->lock, "dw3wtq", NULL, MTX_DEF);
6364 + wq->abort = 0;
6365 +
6366 + return wq;
6367 +}
6368 +
6369 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
6370 +{
6371 + mtx_destroy(&wq->lock);
6372 + DWC_FREE(wq);
6373 +}
6374 +
6375 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
6376 +{
6377 +// intrmask_t ipl;
6378 + int result = 0;
6379 +
6380 + mtx_lock(&wq->lock);
6381 +// ipl = splbio();
6382 +
6383 + /* Skip the sleep if already aborted or triggered */
6384 + if (!wq->abort && !cond(data)) {
6385 +// splx(ipl);
6386 + result = msleep(wq, &wq->lock, PCATCH, "dw3wat", 0); // infinite timeout
6387 +// ipl = splbio();
6388 + }
6389 +
6390 + if (result == ERESTART) { // signaled - restart
6391 + result = -DWC_E_RESTART;
6392 +
6393 + } else if (result == EINTR) { // signaled - interrupt
6394 + result = -DWC_E_ABORT;
6395 +
6396 + } else if (wq->abort) {
6397 + result = -DWC_E_ABORT;
6398 +
6399 + } else {
6400 + result = 0;
6401 + }
6402 +
6403 + wq->abort = 0;
6404 +// splx(ipl);
6405 + mtx_unlock(&wq->lock);
6406 + return result;
6407 +}
6408 +
6409 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
6410 + void *data, int32_t msecs)
6411 +{
6412 + struct timeval tv, tv1, tv2;
6413 +// intrmask_t ipl;
6414 + int result = 0;
6415 +
6416 + tv.tv_sec = msecs / 1000;
6417 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
6418 +
6419 + mtx_lock(&wq->lock);
6420 +// ipl = splbio();
6421 +
6422 + /* Skip the sleep if already aborted or triggered */
6423 + if (!wq->abort && !cond(data)) {
6424 +// splx(ipl);
6425 + getmicrouptime(&tv1);
6426 + result = msleep(wq, &wq->lock, PCATCH, "dw3wto", tvtohz(&tv));
6427 + getmicrouptime(&tv2);
6428 +// ipl = splbio();
6429 + }
6430 +
6431 + if (result == 0) { // awoken
6432 + if (wq->abort) {
6433 + result = -DWC_E_ABORT;
6434 + } else {
6435 + tv2.tv_usec -= tv1.tv_usec;
6436 + if (tv2.tv_usec < 0) {
6437 + tv2.tv_usec += 1000000;
6438 + tv2.tv_sec--;
6439 + }
6440 +
6441 + tv2.tv_sec -= tv1.tv_sec;
6442 + result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
6443 + result = msecs - result;
6444 + if (result <= 0)
6445 + result = 1;
6446 + }
6447 + } else if (result == ERESTART) { // signaled - restart
6448 + result = -DWC_E_RESTART;
6449 +
6450 + } else if (result == EINTR) { // signaled - interrupt
6451 + result = -DWC_E_ABORT;
6452 +
6453 + } else { // timed out
6454 + result = -DWC_E_TIMEOUT;
6455 + }
6456 +
6457 + wq->abort = 0;
6458 +// splx(ipl);
6459 + mtx_unlock(&wq->lock);
6460 + return result;
6461 +}
6462 +
6463 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
6464 +{
6465 + wakeup(wq);
6466 +}
6467 +
6468 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
6469 +{
6470 +// intrmask_t ipl;
6471 +
6472 + mtx_lock(&wq->lock);
6473 +// ipl = splbio();
6474 + wq->abort = 1;
6475 + wakeup(wq);
6476 +// splx(ipl);
6477 + mtx_unlock(&wq->lock);
6478 +}
6479 +
6480 +
6481 +/* Threading */
6482 +
6483 +struct dwc_thread {
6484 + struct proc *proc;
6485 + int abort;
6486 +};
6487 +
6488 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
6489 +{
6490 + int retval;
6491 + dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
6492 +
6493 + if (!thread) {
6494 + return NULL;
6495 + }
6496 +
6497 + thread->abort = 0;
6498 + retval = kthread_create((void (*)(void *))func, data, &thread->proc,
6499 + RFPROC | RFNOWAIT, 0, "%s", name);
6500 + if (retval) {
6501 + DWC_FREE(thread);
6502 + return NULL;
6503 + }
6504 +
6505 + return thread;
6506 +}
6507 +
6508 +int DWC_THREAD_STOP(dwc_thread_t *thread)
6509 +{
6510 + int retval;
6511 +
6512 + thread->abort = 1;
6513 + retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
6514 +
6515 + if (retval == 0) {
6516 + /* DWC_THREAD_EXIT() will free the thread struct */
6517 + return 0;
6518 + }
6519 +
6520 + /* NOTE: We leak the thread struct if thread doesn't die */
6521 +
6522 + if (retval == EWOULDBLOCK) {
6523 + return -DWC_E_TIMEOUT;
6524 + }
6525 +
6526 + return -DWC_E_UNKNOWN;
6527 +}
6528 +
6529 +dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
6530 +{
6531 + return thread->abort;
6532 +}
6533 +
6534 +void DWC_THREAD_EXIT(dwc_thread_t *thread)
6535 +{
6536 + wakeup(&thread->abort);
6537 + DWC_FREE(thread);
6538 + kthread_exit(0);
6539 +}
6540 +
6541 +
6542 +/* tasklets
6543 + - Runs in interrupt context (cannot sleep)
6544 + - Each tasklet runs on a single CPU [ How can we ensure this on FreeBSD? Does it matter? ]
6545 + - Different tasklets can be running simultaneously on different CPUs [ shouldn't matter ]
6546 + */
6547 +struct dwc_tasklet {
6548 + struct task t;
6549 + dwc_tasklet_callback_t cb;
6550 + void *data;
6551 +};
6552 +
6553 +static void tasklet_callback(void *data, int pending) // what to do with pending ???
6554 +{
6555 + dwc_tasklet_t *task = (dwc_tasklet_t *)data;
6556 +
6557 + task->cb(task->data);
6558 +}
6559 +
6560 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
6561 +{
6562 + dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
6563 +
6564 + if (task) {
6565 + task->cb = cb;
6566 + task->data = data;
6567 + TASK_INIT(&task->t, 0, tasklet_callback, task);
6568 + } else {
6569 + DWC_ERROR("Cannot allocate memory for tasklet");
6570 + }
6571 +
6572 + return task;
6573 +}
6574 +
6575 +void DWC_TASK_FREE(dwc_tasklet_t *task)
6576 +{
6577 + taskqueue_drain(taskqueue_fast, &task->t); // ???
6578 + DWC_FREE(task);
6579 +}
6580 +
6581 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
6582 +{
6583 + /* Uses predefined system queue */
6584 + taskqueue_enqueue_fast(taskqueue_fast, &task->t);
6585 +}
6586 +
6587 +
6588 +/* workqueues
6589 + - Runs in process context (can sleep)
6590 + */
6591 +typedef struct work_container {
6592 + dwc_work_callback_t cb;
6593 + void *data;
6594 + dwc_workq_t *wq;
6595 + char *name;
6596 + int hz;
6597 +
6598 +#ifdef DEBUG
6599 + DWC_CIRCLEQ_ENTRY(work_container) entry;
6600 +#endif
6601 + struct task task;
6602 +} work_container_t;
6603 +
6604 +#ifdef DEBUG
6605 +DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
6606 +#endif
6607 +
6608 +struct dwc_workq {
6609 + struct taskqueue *taskq;
6610 + dwc_spinlock_t *lock;
6611 + dwc_waitq_t *waitq;
6612 + int pending;
6613 +
6614 +#ifdef DEBUG
6615 + struct work_container_queue entries;
6616 +#endif
6617 +};
6618 +
6619 +static void do_work(void *data, int pending) // what to do with pending ???
6620 +{
6621 + work_container_t *container = (work_container_t *)data;
6622 + dwc_workq_t *wq = container->wq;
6623 + dwc_irqflags_t flags;
6624 +
6625 + if (container->hz) {
6626 + pause("dw3wrk", container->hz);
6627 + }
6628 +
6629 + container->cb(container->data);
6630 + DWC_DEBUG("Work done: %s, container=%p", container->name, container);
6631 +
6632 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6633 +
6634 +#ifdef DEBUG
6635 + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
6636 +#endif
6637 + if (container->name)
6638 + DWC_FREE(container->name);
6639 + DWC_FREE(container);
6640 + wq->pending--;
6641 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6642 + DWC_WAITQ_TRIGGER(wq->waitq);
6643 +}
6644 +
6645 +static int work_done(void *data)
6646 +{
6647 + dwc_workq_t *workq = (dwc_workq_t *)data;
6648 +
6649 + return workq->pending == 0;
6650 +}
6651 +
6652 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
6653 +{
6654 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
6655 +}
6656 +
6657 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
6658 +{
6659 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
6660 +
6661 + if (!wq) {
6662 + DWC_ERROR("Cannot allocate memory for workqueue");
6663 + return NULL;
6664 + }
6665 +
6666 + wq->taskq = taskqueue_create(name, M_NOWAIT, taskqueue_thread_enqueue, &wq->taskq);
6667 + if (!wq->taskq) {
6668 + DWC_ERROR("Cannot allocate memory for taskqueue");
6669 + goto no_taskq;
6670 + }
6671 +
6672 + wq->pending = 0;
6673 +
6674 + wq->lock = DWC_SPINLOCK_ALLOC();
6675 + if (!wq->lock) {
6676 + DWC_ERROR("Cannot allocate memory for spinlock");
6677 + goto no_lock;
6678 + }
6679 +
6680 + wq->waitq = DWC_WAITQ_ALLOC();
6681 + if (!wq->waitq) {
6682 + DWC_ERROR("Cannot allocate memory for waitqueue");
6683 + goto no_waitq;
6684 + }
6685 +
6686 + taskqueue_start_threads(&wq->taskq, 1, PWAIT, "%s taskq", "dw3tsk");
6687 +
6688 +#ifdef DEBUG
6689 + DWC_CIRCLEQ_INIT(&wq->entries);
6690 +#endif
6691 + return wq;
6692 +
6693 + no_waitq:
6694 + DWC_SPINLOCK_FREE(wq->lock);
6695 + no_lock:
6696 + taskqueue_free(wq->taskq);
6697 + no_taskq:
6698 + DWC_FREE(wq);
6699 +
6700 + return NULL;
6701 +}
6702 +
6703 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
6704 +{
6705 +#ifdef DEBUG
6706 + dwc_irqflags_t flags;
6707 +
6708 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6709 +
6710 + if (wq->pending != 0) {
6711 + struct work_container *container;
6712 +
6713 + DWC_ERROR("Destroying work queue with pending work");
6714 +
6715 + DWC_CIRCLEQ_FOREACH(container, &wq->entries, entry) {
6716 + DWC_ERROR("Work %s still pending", container->name);
6717 + }
6718 + }
6719 +
6720 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6721 +#endif
6722 + DWC_WAITQ_FREE(wq->waitq);
6723 + DWC_SPINLOCK_FREE(wq->lock);
6724 + taskqueue_free(wq->taskq);
6725 + DWC_FREE(wq);
6726 +}
6727 +
6728 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
6729 + char *format, ...)
6730 +{
6731 + dwc_irqflags_t flags;
6732 + work_container_t *container;
6733 + static char name[128];
6734 + va_list args;
6735 +
6736 + va_start(args, format);
6737 + DWC_VSNPRINTF(name, 128, format, args);
6738 + va_end(args);
6739 +
6740 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6741 + wq->pending++;
6742 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6743 + DWC_WAITQ_TRIGGER(wq->waitq);
6744 +
6745 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
6746 + if (!container) {
6747 + DWC_ERROR("Cannot allocate memory for container");
6748 + return;
6749 + }
6750 +
6751 + container->name = DWC_STRDUP(name);
6752 + if (!container->name) {
6753 + DWC_ERROR("Cannot allocate memory for container->name");
6754 + DWC_FREE(container);
6755 + return;
6756 + }
6757 +
6758 + container->cb = cb;
6759 + container->data = data;
6760 + container->wq = wq;
6761 + container->hz = 0;
6762 +
6763 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
6764 +
6765 + TASK_INIT(&container->task, 0, do_work, container);
6766 +
6767 +#ifdef DEBUG
6768 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
6769 +#endif
6770 + taskqueue_enqueue_fast(wq->taskq, &container->task);
6771 +}
6772 +
6773 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
6774 + void *data, uint32_t time, char *format, ...)
6775 +{
6776 + dwc_irqflags_t flags;
6777 + work_container_t *container;
6778 + static char name[128];
6779 + struct timeval tv;
6780 + va_list args;
6781 +
6782 + va_start(args, format);
6783 + DWC_VSNPRINTF(name, 128, format, args);
6784 + va_end(args);
6785 +
6786 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6787 + wq->pending++;
6788 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6789 + DWC_WAITQ_TRIGGER(wq->waitq);
6790 +
6791 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
6792 + if (!container) {
6793 + DWC_ERROR("Cannot allocate memory for container");
6794 + return;
6795 + }
6796 +
6797 + container->name = DWC_STRDUP(name);
6798 + if (!container->name) {
6799 + DWC_ERROR("Cannot allocate memory for container->name");
6800 + DWC_FREE(container);
6801 + return;
6802 + }
6803 +
6804 + container->cb = cb;
6805 + container->data = data;
6806 + container->wq = wq;
6807 +
6808 + tv.tv_sec = time / 1000;
6809 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
6810 + container->hz = tvtohz(&tv);
6811 +
6812 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
6813 +
6814 + TASK_INIT(&container->task, 0, do_work, container);
6815 +
6816 +#ifdef DEBUG
6817 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
6818 +#endif
6819 + taskqueue_enqueue_fast(wq->taskq, &container->task);
6820 +}
6821 +
6822 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
6823 +{
6824 + return wq->pending;
6825 +}
6826 --- /dev/null
6827 +++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
6828 @@ -0,0 +1,1421 @@
6829 +#include <linux/kernel.h>
6830 +#include <linux/init.h>
6831 +#include <linux/module.h>
6832 +#include <linux/kthread.h>
6833 +
6834 +#ifdef DWC_CCLIB
6835 +# include "dwc_cc.h"
6836 +#endif
6837 +
6838 +#ifdef DWC_CRYPTOLIB
6839 +# include "dwc_modpow.h"
6840 +# include "dwc_dh.h"
6841 +# include "dwc_crypto.h"
6842 +#endif
6843 +
6844 +#ifdef DWC_NOTIFYLIB
6845 +# include "dwc_notifier.h"
6846 +#endif
6847 +
6848 +/* OS-Level Implementations */
6849 +
6850 +/* This is the Linux kernel implementation of the DWC platform library. */
6851 +#include <linux/moduleparam.h>
6852 +#include <linux/ctype.h>
6853 +#include <linux/crypto.h>
6854 +#include <linux/delay.h>
6855 +#include <linux/device.h>
6856 +#include <linux/dma-mapping.h>
6857 +#include <linux/cdev.h>
6858 +#include <linux/errno.h>
6859 +#include <linux/interrupt.h>
6860 +#include <linux/jiffies.h>
6861 +#include <linux/list.h>
6862 +#include <linux/pci.h>
6863 +#include <linux/random.h>
6864 +#include <linux/scatterlist.h>
6865 +#include <linux/slab.h>
6866 +#include <linux/stat.h>
6867 +#include <linux/string.h>
6868 +#include <linux/timer.h>
6869 +#include <linux/usb.h>
6870 +
6871 +#include <linux/version.h>
6872 +
6873 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
6874 +# include <linux/usb/gadget.h>
6875 +#else
6876 +# include <linux/usb_gadget.h>
6877 +#endif
6878 +
6879 +#include <asm/io.h>
6880 +#include <asm/page.h>
6881 +#include <asm/uaccess.h>
6882 +#include <asm/unaligned.h>
6883 +
6884 +#include "dwc_os.h"
6885 +#include "dwc_list.h"
6886 +
6887 +
6888 +/* MISC */
6889 +
6890 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
6891 +{
6892 + return memset(dest, byte, size);
6893 +}
6894 +
6895 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
6896 +{
6897 + return memcpy(dest, src, size);
6898 +}
6899 +
6900 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
6901 +{
6902 + return memmove(dest, src, size);
6903 +}
6904 +
6905 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
6906 +{
6907 + return memcmp(m1, m2, size);
6908 +}
6909 +
6910 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
6911 +{
6912 + return strncmp(s1, s2, size);
6913 +}
6914 +
6915 +int DWC_STRCMP(void *s1, void *s2)
6916 +{
6917 + return strcmp(s1, s2);
6918 +}
6919 +
6920 +int DWC_STRLEN(char const *str)
6921 +{
6922 + return strlen(str);
6923 +}
6924 +
6925 +char *DWC_STRCPY(char *to, char const *from)
6926 +{
6927 + return strcpy(to, from);
6928 +}
6929 +
6930 +char *DWC_STRDUP(char const *str)
6931 +{
6932 + int len = DWC_STRLEN(str) + 1;
6933 + char *new = DWC_ALLOC_ATOMIC(len);
6934 +
6935 + if (!new) {
6936 + return NULL;
6937 + }
6938 +
6939 + DWC_MEMCPY(new, str, len);
6940 + return new;
6941 +}
6942 +
6943 +int DWC_ATOI(const char *str, int32_t *value)
6944 +{
6945 + char *end = NULL;
6946 +
6947 + *value = simple_strtol(str, &end, 0);
6948 + if (*end == '\0') {
6949 + return 0;
6950 + }
6951 +
6952 + return -1;
6953 +}
6954 +
6955 +int DWC_ATOUI(const char *str, uint32_t *value)
6956 +{
6957 + char *end = NULL;
6958 +
6959 + *value = simple_strtoul(str, &end, 0);
6960 + if (*end == '\0') {
6961 + return 0;
6962 + }
6963 +
6964 + return -1;
6965 +}
6966 +
6967 +
6968 +#ifdef DWC_UTFLIB
6969 +/* From usbstring.c */
6970 +
6971 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
6972 +{
6973 + int count = 0;
6974 + u8 c;
6975 + u16 uchar;
6976 +
6977 + /* this insists on correct encodings, though not minimal ones.
6978 + * BUT it currently rejects legit 4-byte UTF-8 code points,
6979 + * which need surrogate pairs. (Unicode 3.1 can use them.)
6980 + */
6981 + while (len != 0 && (c = (u8) *s++) != 0) {
6982 + if (unlikely(c & 0x80)) {
6983 + // 2-byte sequence:
6984 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
6985 + if ((c & 0xe0) == 0xc0) {
6986 + uchar = (c & 0x1f) << 6;
6987 +
6988 + c = (u8) *s++;
6989 + if ((c & 0xc0) != 0xc0)
6990 + goto fail;
6991 + c &= 0x3f;
6992 + uchar |= c;
6993 +
6994 + // 3-byte sequence (most CJKV characters):
6995 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
6996 + } else if ((c & 0xf0) == 0xe0) {
6997 + uchar = (c & 0x0f) << 12;
6998 +
6999 + c = (u8) *s++;
7000 + if ((c & 0xc0) != 0xc0)
7001 + goto fail;
7002 + c &= 0x3f;
7003 + uchar |= c << 6;
7004 +
7005 + c = (u8) *s++;
7006 + if ((c & 0xc0) != 0xc0)
7007 + goto fail;
7008 + c &= 0x3f;
7009 + uchar |= c;
7010 +
7011 + /* no bogus surrogates */
7012 + if (0xd800 <= uchar && uchar <= 0xdfff)
7013 + goto fail;
7014 +
7015 + // 4-byte sequence (surrogate pairs, currently rare):
7016 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
7017 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
7018 + // (uuuuu = wwww + 1)
7019 + // FIXME accept the surrogate code points (only)
7020 + } else
7021 + goto fail;
7022 + } else
7023 + uchar = c;
7024 + put_unaligned (cpu_to_le16 (uchar), cp++);
7025 + count++;
7026 + len--;
7027 + }
7028 + return count;
7029 +fail:
7030 + return -1;
7031 +}
7032 +#endif /* DWC_UTFLIB */
7033 +
7034 +
7035 +/* dwc_debug.h */
7036 +
7037 +dwc_bool_t DWC_IN_IRQ(void)
7038 +{
7039 + return in_irq();
7040 +}
7041 +
7042 +dwc_bool_t DWC_IN_BH(void)
7043 +{
7044 + return in_softirq();
7045 +}
7046 +
7047 +void DWC_VPRINTF(char *format, va_list args)
7048 +{
7049 + vprintk(format, args);
7050 +}
7051 +
7052 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
7053 +{
7054 + return vsnprintf(str, size, format, args);
7055 +}
7056 +
7057 +void DWC_PRINTF(char *format, ...)
7058 +{
7059 + va_list args;
7060 +
7061 + va_start(args, format);
7062 + DWC_VPRINTF(format, args);
7063 + va_end(args);
7064 +}
7065 +
7066 +int DWC_SPRINTF(char *buffer, char *format, ...)
7067 +{
7068 + int retval;
7069 + va_list args;
7070 +
7071 + va_start(args, format);
7072 + retval = vsprintf(buffer, format, args);
7073 + va_end(args);
7074 + return retval;
7075 +}
7076 +
7077 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
7078 +{
7079 + int retval;
7080 + va_list args;
7081 +
7082 + va_start(args, format);
7083 + retval = vsnprintf(buffer, size, format, args);
7084 + va_end(args);
7085 + return retval;
7086 +}
7087 +
7088 +void __DWC_WARN(char *format, ...)
7089 +{
7090 + va_list args;
7091 +
7092 + va_start(args, format);
7093 + DWC_PRINTF(KERN_WARNING);
7094 + DWC_VPRINTF(format, args);
7095 + va_end(args);
7096 +}
7097 +
7098 +void __DWC_ERROR(char *format, ...)
7099 +{
7100 + va_list args;
7101 +
7102 + va_start(args, format);
7103 + DWC_PRINTF(KERN_ERR);
7104 + DWC_VPRINTF(format, args);
7105 + va_end(args);
7106 +}
7107 +
7108 +void DWC_EXCEPTION(char *format, ...)
7109 +{
7110 + va_list args;
7111 +
7112 + va_start(args, format);
7113 + DWC_PRINTF(KERN_ERR);
7114 + DWC_VPRINTF(format, args);
7115 + va_end(args);
7116 + BUG_ON(1);
7117 +}
7118 +
7119 +#ifdef DEBUG
7120 +void __DWC_DEBUG(char *format, ...)
7121 +{
7122 + va_list args;
7123 +
7124 + va_start(args, format);
7125 + DWC_PRINTF(KERN_DEBUG);
7126 + DWC_VPRINTF(format, args);
7127 + va_end(args);
7128 +}
7129 +#endif
7130 +
7131 +
7132 +/* dwc_mem.h */
7133 +
7134 +#if 0
7135 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
7136 + uint32_t align,
7137 + uint32_t alloc)
7138 +{
7139 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
7140 + size, align, alloc);
7141 + return (dwc_pool_t *)pool;
7142 +}
7143 +
7144 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
7145 +{
7146 + dma_pool_destroy((struct dma_pool *)pool);
7147 +}
7148 +
7149 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
7150 +{
7151 + return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
7152 +}
7153 +
7154 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
7155 +{
7156 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
7157 + memset(..);
7158 +}
7159 +
7160 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
7161 +{
7162 + dma_pool_free(pool, vaddr, daddr);
7163 +}
7164 +#endif
7165 +
7166 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
7167 +{
7168 +#ifdef xxCOSIM /* Only works for 32-bit cosim */
7169 + void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL);
7170 +#else
7171 + void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL | GFP_DMA32);
7172 +#endif
7173 + if (!buf) {
7174 + return NULL;
7175 + }
7176 +
7177 + memset(buf, 0, (size_t)size);
7178 + return buf;
7179 +}
7180 +
7181 +void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
7182 +{
7183 + void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC);
7184 + if (!buf) {
7185 + return NULL;
7186 + }
7187 + memset(buf, 0, (size_t)size);
7188 + return buf;
7189 +}
7190 +
7191 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
7192 +{
7193 + dma_free_coherent(dma_ctx, size, virt_addr, dma_addr);
7194 +}
7195 +
7196 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
7197 +{
7198 + return kzalloc(size, GFP_KERNEL);
7199 +}
7200 +
7201 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
7202 +{
7203 + return kzalloc(size, GFP_ATOMIC);
7204 +}
7205 +
7206 +void __DWC_FREE(void *mem_ctx, void *addr)
7207 +{
7208 + kfree(addr);
7209 +}
7210 +
7211 +
7212 +#ifdef DWC_CRYPTOLIB
7213 +/* dwc_crypto.h */
7214 +
7215 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
7216 +{
7217 + get_random_bytes(buffer, length);
7218 +}
7219 +
7220 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
7221 +{
7222 + struct crypto_blkcipher *tfm;
7223 + struct blkcipher_desc desc;
7224 + struct scatterlist sgd;
7225 + struct scatterlist sgs;
7226 +
7227 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
7228 + if (tfm == NULL) {
7229 + printk("failed to load transform for aes CBC\n");
7230 + return -1;
7231 + }
7232 +
7233 + crypto_blkcipher_setkey(tfm, key, keylen);
7234 + crypto_blkcipher_set_iv(tfm, iv, 16);
7235 +
7236 + sg_init_one(&sgd, out, messagelen);
7237 + sg_init_one(&sgs, message, messagelen);
7238 +
7239 + desc.tfm = tfm;
7240 + desc.flags = 0;
7241 +
7242 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
7243 + crypto_free_blkcipher(tfm);
7244 + DWC_ERROR("AES CBC encryption failed");
7245 + return -1;
7246 + }
7247 +
7248 + crypto_free_blkcipher(tfm);
7249 + return 0;
7250 +}
7251 +
7252 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
7253 +{
7254 + struct crypto_hash *tfm;
7255 + struct hash_desc desc;
7256 + struct scatterlist sg;
7257 +
7258 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
7259 + if (IS_ERR(tfm)) {
7260 + DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm));
7261 + return 0;
7262 + }
7263 + desc.tfm = tfm;
7264 + desc.flags = 0;
7265 +
7266 + sg_init_one(&sg, message, len);
7267 + crypto_hash_digest(&desc, &sg, len, out);
7268 + crypto_free_hash(tfm);
7269 +
7270 + return 1;
7271 +}
7272 +
7273 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
7274 + uint8_t *key, uint32_t keylen, uint8_t *out)
7275 +{
7276 + struct crypto_hash *tfm;
7277 + struct hash_desc desc;
7278 + struct scatterlist sg;
7279 +
7280 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
7281 + if (IS_ERR(tfm)) {
7282 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm));
7283 + return 0;
7284 + }
7285 + desc.tfm = tfm;
7286 + desc.flags = 0;
7287 +
7288 + sg_init_one(&sg, message, messagelen);
7289 + crypto_hash_setkey(tfm, key, keylen);
7290 + crypto_hash_digest(&desc, &sg, messagelen, out);
7291 + crypto_free_hash(tfm);
7292 +
7293 + return 1;
7294 +}
7295 +#endif /* DWC_CRYPTOLIB */
7296 +
7297 +
7298 +/* Byte Ordering Conversions */
7299 +
7300 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
7301 +{
7302 +#ifdef __LITTLE_ENDIAN
7303 + return *p;
7304 +#else
7305 + uint8_t *u_p = (uint8_t *)p;
7306 +
7307 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7308 +#endif
7309 +}
7310 +
7311 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
7312 +{
7313 +#ifdef __BIG_ENDIAN
7314 + return *p;
7315 +#else
7316 + uint8_t *u_p = (uint8_t *)p;
7317 +
7318 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7319 +#endif
7320 +}
7321 +
7322 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
7323 +{
7324 +#ifdef __LITTLE_ENDIAN
7325 + return *p;
7326 +#else
7327 + uint8_t *u_p = (uint8_t *)p;
7328 +
7329 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7330 +#endif
7331 +}
7332 +
7333 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
7334 +{
7335 +#ifdef __BIG_ENDIAN
7336 + return *p;
7337 +#else
7338 + uint8_t *u_p = (uint8_t *)p;
7339 +
7340 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7341 +#endif
7342 +}
7343 +
7344 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
7345 +{
7346 +#ifdef __LITTLE_ENDIAN
7347 + return *p;
7348 +#else
7349 + uint8_t *u_p = (uint8_t *)p;
7350 + return (u_p[1] | (u_p[0] << 8));
7351 +#endif
7352 +}
7353 +
7354 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
7355 +{
7356 +#ifdef __BIG_ENDIAN
7357 + return *p;
7358 +#else
7359 + uint8_t *u_p = (uint8_t *)p;
7360 + return (u_p[1] | (u_p[0] << 8));
7361 +#endif
7362 +}
7363 +
7364 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
7365 +{
7366 +#ifdef __LITTLE_ENDIAN
7367 + return *p;
7368 +#else
7369 + uint8_t *u_p = (uint8_t *)p;
7370 + return (u_p[1] | (u_p[0] << 8));
7371 +#endif
7372 +}
7373 +
7374 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
7375 +{
7376 +#ifdef __BIG_ENDIAN
7377 + return *p;
7378 +#else
7379 + uint8_t *u_p = (uint8_t *)p;
7380 + return (u_p[1] | (u_p[0] << 8));
7381 +#endif
7382 +}
7383 +
7384 +
7385 +/* Registers */
7386 +
7387 +uint32_t DWC_READ_REG32(uint32_t volatile *reg)
7388 +{
7389 + return readl(reg);
7390 +}
7391 +
7392 +#if 0
7393 +uint64_t DWC_READ_REG64(uint64_t volatile *reg)
7394 +{
7395 +}
7396 +#endif
7397 +
7398 +void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
7399 +{
7400 + writel(value, reg);
7401 +}
7402 +
7403 +#if 0
7404 +void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
7405 +{
7406 +}
7407 +#endif
7408 +
7409 +void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
7410 +{
7411 + writel((readl(reg) & ~clear_mask) | set_mask, reg);
7412 +}
7413 +
7414 +#if 0
7415 +void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask)
7416 +{
7417 +}
7418 +#endif
7419 +
7420 +
7421 +/* Locking */
7422 +
7423 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
7424 +{
7425 + spinlock_t *sl = (spinlock_t *)1;
7426 +
7427 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7428 + sl = DWC_ALLOC(sizeof(*sl));
7429 + if (!sl) {
7430 + DWC_ERROR("Cannot allocate memory for spinlock\n");
7431 + return NULL;
7432 + }
7433 +
7434 + spin_lock_init(sl);
7435 +#endif
7436 + return (dwc_spinlock_t *)sl;
7437 +}
7438 +
7439 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
7440 +{
7441 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7442 + DWC_FREE(lock);
7443 +#endif
7444 +}
7445 +
7446 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
7447 +{
7448 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7449 + spin_lock((spinlock_t *)lock);
7450 +#endif
7451 +}
7452 +
7453 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
7454 +{
7455 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7456 + spin_unlock((spinlock_t *)lock);
7457 +#endif
7458 +}
7459 +
7460 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
7461 +{
7462 + dwc_irqflags_t f;
7463 +
7464 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7465 + spin_lock_irqsave((spinlock_t *)lock, f);
7466 +#else
7467 + local_irq_save(f);
7468 +#endif
7469 + *flags = f;
7470 +}
7471 +
7472 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
7473 +{
7474 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7475 + spin_unlock_irqrestore((spinlock_t *)lock, flags);
7476 +#else
7477 + local_irq_restore(flags);
7478 +#endif
7479 +}
7480 +
7481 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
7482 +{
7483 + struct mutex *m;
7484 + dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex));
7485 +
7486 + if (!mutex) {
7487 + DWC_ERROR("Cannot allocate memory for mutex\n");
7488 + return NULL;
7489 + }
7490 +
7491 + m = (struct mutex *)mutex;
7492 + mutex_init(m);
7493 + return mutex;
7494 +}
7495 +
7496 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
7497 +#else
7498 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
7499 +{
7500 + mutex_destroy((struct mutex *)mutex);
7501 + DWC_FREE(mutex);
7502 +}
7503 +#endif
7504 +
7505 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
7506 +{
7507 + struct mutex *m = (struct mutex *)mutex;
7508 + mutex_lock(m);
7509 +}
7510 +
7511 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
7512 +{
7513 + struct mutex *m = (struct mutex *)mutex;
7514 + return mutex_trylock(m);
7515 +}
7516 +
7517 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
7518 +{
7519 + struct mutex *m = (struct mutex *)mutex;
7520 + mutex_unlock(m);
7521 +}
7522 +
7523 +
7524 +/* Timing */
7525 +
7526 +void DWC_UDELAY(uint32_t usecs)
7527 +{
7528 + udelay(usecs);
7529 +}
7530 +
7531 +void DWC_MDELAY(uint32_t msecs)
7532 +{
7533 + mdelay(msecs);
7534 +}
7535 +
7536 +void DWC_MSLEEP(uint32_t msecs)
7537 +{
7538 + msleep(msecs);
7539 +}
7540 +
7541 +uint32_t DWC_TIME(void)
7542 +{
7543 + return jiffies_to_msecs(jiffies);
7544 +}
7545 +
7546 +
7547 +/* Timers */
7548 +
7549 +struct dwc_timer {
7550 + struct timer_list *t;
7551 + char *name;
7552 + dwc_timer_callback_t cb;
7553 + void *data;
7554 + uint8_t scheduled;
7555 + dwc_spinlock_t *lock;
7556 +};
7557 +
7558 +static void timer_callback(unsigned long data)
7559 +{
7560 + dwc_timer_t *timer = (dwc_timer_t *)data;
7561 + dwc_irqflags_t flags;
7562 +
7563 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7564 + timer->scheduled = 0;
7565 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7566 + DWC_DEBUGC("Timer %s callback", timer->name);
7567 + timer->cb(timer->data);
7568 +}
7569 +
7570 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
7571 +{
7572 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
7573 +
7574 + if (!t) {
7575 + DWC_ERROR("Cannot allocate memory for timer");
7576 + return NULL;
7577 + }
7578 +
7579 + t->t = DWC_ALLOC(sizeof(*t->t));
7580 + if (!t->t) {
7581 + DWC_ERROR("Cannot allocate memory for timer->t");
7582 + goto no_timer;
7583 + }
7584 +
7585 + t->name = DWC_STRDUP(name);
7586 + if (!t->name) {
7587 + DWC_ERROR("Cannot allocate memory for timer->name");
7588 + goto no_name;
7589 + }
7590 +
7591 + t->lock = DWC_SPINLOCK_ALLOC();
7592 + if (!t->lock) {
7593 + DWC_ERROR("Cannot allocate memory for lock");
7594 + goto no_lock;
7595 + }
7596 +
7597 + t->scheduled = 0;
7598 + t->t->base = &boot_tvec_bases;
7599 + t->t->expires = jiffies;
7600 + setup_timer(t->t, timer_callback, (unsigned long)t);
7601 +
7602 + t->cb = cb;
7603 + t->data = data;
7604 +
7605 + return t;
7606 +
7607 + no_lock:
7608 + DWC_FREE(t->name);
7609 + no_name:
7610 + DWC_FREE(t->t);
7611 + no_timer:
7612 + DWC_FREE(t);
7613 + return NULL;
7614 +}
7615 +
7616 +void DWC_TIMER_FREE(dwc_timer_t *timer)
7617 +{
7618 + dwc_irqflags_t flags;
7619 +
7620 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7621 +
7622 + if (timer->scheduled) {
7623 + del_timer(timer->t);
7624 + timer->scheduled = 0;
7625 + }
7626 +
7627 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7628 + DWC_SPINLOCK_FREE(timer->lock);
7629 + DWC_FREE(timer->t);
7630 + DWC_FREE(timer->name);
7631 + DWC_FREE(timer);
7632 +}
7633 +
7634 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
7635 +{
7636 + dwc_irqflags_t flags;
7637 +
7638 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7639 +
7640 + if (!timer->scheduled) {
7641 + timer->scheduled = 1;
7642 + DWC_DEBUGC("Scheduling timer %s to expire in +%d msec", timer->name, time);
7643 + timer->t->expires = jiffies + msecs_to_jiffies(time);
7644 + add_timer(timer->t);
7645 + } else {
7646 + DWC_DEBUGC("Modifying timer %s to expire in +%d msec", timer->name, time);
7647 + mod_timer(timer->t, jiffies + msecs_to_jiffies(time));
7648 + }
7649 +
7650 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7651 +}
7652 +
7653 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
7654 +{
7655 + del_timer(timer->t);
7656 +}
7657 +
7658 +
7659 +/* Wait Queues */
7660 +
7661 +struct dwc_waitq {
7662 + wait_queue_head_t queue;
7663 + int abort;
7664 +};
7665 +
7666 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
7667 +{
7668 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
7669 +
7670 + if (!wq) {
7671 + DWC_ERROR("Cannot allocate memory for waitqueue\n");
7672 + return NULL;
7673 + }
7674 +
7675 + init_waitqueue_head(&wq->queue);
7676 + wq->abort = 0;
7677 + return wq;
7678 +}
7679 +
7680 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
7681 +{
7682 + DWC_FREE(wq);
7683 +}
7684 +
7685 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
7686 +{
7687 + int result = wait_event_interruptible(wq->queue,
7688 + cond(data) || wq->abort);
7689 + if (result == -ERESTARTSYS) {
7690 + wq->abort = 0;
7691 + return -DWC_E_RESTART;
7692 + }
7693 +
7694 + if (wq->abort == 1) {
7695 + wq->abort = 0;
7696 + return -DWC_E_ABORT;
7697 + }
7698 +
7699 + wq->abort = 0;
7700 +
7701 + if (result == 0) {
7702 + return 0;
7703 + }
7704 +
7705 + return -DWC_E_UNKNOWN;
7706 +}
7707 +
7708 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
7709 + void *data, int32_t msecs)
7710 +{
7711 + int32_t tmsecs;
7712 + int result = wait_event_interruptible_timeout(wq->queue,
7713 + cond(data) || wq->abort,
7714 + msecs_to_jiffies(msecs));
7715 + if (result == -ERESTARTSYS) {
7716 + wq->abort = 0;
7717 + return -DWC_E_RESTART;
7718 + }
7719 +
7720 + if (wq->abort == 1) {
7721 + wq->abort = 0;
7722 + return -DWC_E_ABORT;
7723 + }
7724 +
7725 + wq->abort = 0;
7726 +
7727 + if (result > 0) {
7728 + tmsecs = jiffies_to_msecs(result);
7729 + if (!tmsecs) {
7730 + return 1;
7731 + }
7732 +
7733 + return tmsecs;
7734 + }
7735 +
7736 + if (result == 0) {
7737 + return -DWC_E_TIMEOUT;
7738 + }
7739 +
7740 + return -DWC_E_UNKNOWN;
7741 +}
7742 +
7743 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
7744 +{
7745 + wq->abort = 0;
7746 + wake_up_interruptible(&wq->queue);
7747 +}
7748 +
7749 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
7750 +{
7751 + wq->abort = 1;
7752 + wake_up_interruptible(&wq->queue);
7753 +}
7754 +
7755 +
7756 +/* Threading */
7757 +
7758 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
7759 +{
7760 + struct task_struct *thread = kthread_run(func, data, name);
7761 +
7762 + if (thread == ERR_PTR(-ENOMEM)) {
7763 + return NULL;
7764 + }
7765 +
7766 + return (dwc_thread_t *)thread;
7767 +}
7768 +
7769 +int DWC_THREAD_STOP(dwc_thread_t *thread)
7770 +{
7771 + return kthread_stop((struct task_struct *)thread);
7772 +}
7773 +
7774 +dwc_bool_t DWC_THREAD_SHOULD_STOP(void)
7775 +{
7776 + return kthread_should_stop();
7777 +}
7778 +
7779 +
7780 +/* tasklets
7781 + - run in interrupt context (cannot sleep)
7782 + - each tasklet runs on a single CPU
7783 + - different tasklets can be running simultaneously on different CPUs
7784 + */
7785 +struct dwc_tasklet {
7786 + struct tasklet_struct t;
7787 + dwc_tasklet_callback_t cb;
7788 + void *data;
7789 +};
7790 +
7791 +static void tasklet_callback(unsigned long data)
7792 +{
7793 + dwc_tasklet_t *t = (dwc_tasklet_t *)data;
7794 + t->cb(t->data);
7795 +}
7796 +
7797 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
7798 +{
7799 + dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t));
7800 +
7801 + if (t) {
7802 + t->cb = cb;
7803 + t->data = data;
7804 + tasklet_init(&t->t, tasklet_callback, (unsigned long)t);
7805 + } else {
7806 + DWC_ERROR("Cannot allocate memory for tasklet\n");
7807 + }
7808 +
7809 + return t;
7810 +}
7811 +
7812 +void DWC_TASK_FREE(dwc_tasklet_t *task)
7813 +{
7814 + DWC_FREE(task);
7815 +}
7816 +
7817 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
7818 +{
7819 + tasklet_schedule(&task->t);
7820 +}
7821 +
7822 +
7823 +/* workqueues
7824 + - run in process context (can sleep)
7825 + */
7826 +typedef struct work_container {
7827 + dwc_work_callback_t cb;
7828 + void *data;
7829 + dwc_workq_t *wq;
7830 + char *name;
7831 +
7832 +#ifdef DEBUG
7833 + DWC_CIRCLEQ_ENTRY(work_container) entry;
7834 +#endif
7835 + struct delayed_work work;
7836 +} work_container_t;
7837 +
7838 +#ifdef DEBUG
7839 +DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
7840 +#endif
7841 +
7842 +struct dwc_workq {
7843 + struct workqueue_struct *wq;
7844 + dwc_spinlock_t *lock;
7845 + dwc_waitq_t *waitq;
7846 + int pending;
7847 +
7848 +#ifdef DEBUG
7849 + struct work_container_queue entries;
7850 +#endif
7851 +};
7852 +
7853 +static void do_work(struct work_struct *work)
7854 +{
7855 + dwc_irqflags_t flags;
7856 + struct delayed_work *dw = container_of(work, struct delayed_work, work);
7857 + work_container_t *container = container_of(dw, struct work_container, work);
7858 + dwc_workq_t *wq = container->wq;
7859 +
7860 + container->cb(container->data);
7861 +
7862 +#ifdef DEBUG
7863 + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
7864 +#endif
7865 + DWC_DEBUGC("Work done: %s, container=%p", container->name, container);
7866 + if (container->name) {
7867 + DWC_FREE(container->name);
7868 + }
7869 + DWC_FREE(container);
7870 +
7871 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
7872 + wq->pending--;
7873 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
7874 + DWC_WAITQ_TRIGGER(wq->waitq);
7875 +}
7876 +
7877 +static int work_done(void *data)
7878 +{
7879 + dwc_workq_t *workq = (dwc_workq_t *)data;
7880 + return workq->pending == 0;
7881 +}
7882 +
7883 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
7884 +{
7885 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
7886 +}
7887 +
7888 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
7889 +{
7890 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
7891 +
7892 + if (!wq) {
7893 + return NULL;
7894 + }
7895 +
7896 + wq->wq = create_singlethread_workqueue(name);
7897 + if (!wq->wq) {
7898 + goto no_wq;
7899 + }
7900 +
7901 + wq->pending = 0;
7902 +
7903 + wq->lock = DWC_SPINLOCK_ALLOC();
7904 + if (!wq->lock) {
7905 + goto no_lock;
7906 + }
7907 +
7908 + wq->waitq = DWC_WAITQ_ALLOC();
7909 + if (!wq->waitq) {
7910 + goto no_waitq;
7911 + }
7912 +
7913 +#ifdef DEBUG
7914 + DWC_CIRCLEQ_INIT(&wq->entries);
7915 +#endif
7916 + return wq;
7917 +
7918 + no_waitq:
7919 + DWC_SPINLOCK_FREE(wq->lock);
7920 + no_lock:
7921 + destroy_workqueue(wq->wq);
7922 + no_wq:
7923 + DWC_FREE(wq);
7924 +
7925 + return NULL;
7926 +}
7927 +
7928 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
7929 +{
7930 +#ifdef DEBUG
7931 + if (wq->pending != 0) {
7932 + struct work_container *wc;
7933 + DWC_ERROR("Destroying work queue with pending work");
7934 + DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) {
7935 + DWC_ERROR("Work %s still pending", wc->name);
7936 + }
7937 + }
7938 +#endif
7939 + destroy_workqueue(wq->wq);
7940 + DWC_SPINLOCK_FREE(wq->lock);
7941 + DWC_WAITQ_FREE(wq->waitq);
7942 + DWC_FREE(wq);
7943 +}
7944 +
7945 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
7946 + char *format, ...)
7947 +{
7948 + dwc_irqflags_t flags;
7949 + work_container_t *container;
7950 + static char name[128];
7951 + va_list args;
7952 +
7953 + va_start(args, format);
7954 + DWC_VSNPRINTF(name, 128, format, args);
7955 + va_end(args);
7956 +
7957 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
7958 + wq->pending++;
7959 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
7960 + DWC_WAITQ_TRIGGER(wq->waitq);
7961 +
7962 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
7963 + if (!container) {
7964 + DWC_ERROR("Cannot allocate memory for container\n");
7965 + return;
7966 + }
7967 +
7968 + container->name = DWC_STRDUP(name);
7969 + if (!container->name) {
7970 + DWC_ERROR("Cannot allocate memory for container->name\n");
7971 + DWC_FREE(container);
7972 + return;
7973 + }
7974 +
7975 + container->cb = cb;
7976 + container->data = data;
7977 + container->wq = wq;
7978 + DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
7979 + INIT_WORK(&container->work.work, do_work);
7980 +
7981 +#ifdef DEBUG
7982 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
7983 +#endif
7984 + queue_work(wq->wq, &container->work.work);
7985 +}
7986 +
7987 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
7988 + void *data, uint32_t time, char *format, ...)
7989 +{
7990 + dwc_irqflags_t flags;
7991 + work_container_t *container;
7992 + static char name[128];
7993 + va_list args;
7994 +
7995 + va_start(args, format);
7996 + DWC_VSNPRINTF(name, 128, format, args);
7997 + va_end(args);
7998 +
7999 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
8000 + wq->pending++;
8001 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
8002 + DWC_WAITQ_TRIGGER(wq->waitq);
8003 +
8004 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
8005 + if (!container) {
8006 + DWC_ERROR("Cannot allocate memory for container\n");
8007 + return;
8008 + }
8009 +
8010 + container->name = DWC_STRDUP(name);
8011 + if (!container->name) {
8012 + DWC_ERROR("Cannot allocate memory for container->name\n");
8013 + DWC_FREE(container);
8014 + return;
8015 + }
8016 +
8017 + container->cb = cb;
8018 + container->data = data;
8019 + container->wq = wq;
8020 + DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
8021 + INIT_DELAYED_WORK(&container->work, do_work);
8022 +
8023 +#ifdef DEBUG
8024 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
8025 +#endif
8026 + queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time));
8027 +}
8028 +
8029 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
8030 +{
8031 + return wq->pending;
8032 +}
8033 +
8034 +
8035 +#ifdef DWC_LIBMODULE
8036 +
8037 +#ifdef DWC_CCLIB
8038 +/* CC */
8039 +EXPORT_SYMBOL(dwc_cc_if_alloc);
8040 +EXPORT_SYMBOL(dwc_cc_if_free);
8041 +EXPORT_SYMBOL(dwc_cc_clear);
8042 +EXPORT_SYMBOL(dwc_cc_add);
8043 +EXPORT_SYMBOL(dwc_cc_remove);
8044 +EXPORT_SYMBOL(dwc_cc_change);
8045 +EXPORT_SYMBOL(dwc_cc_data_for_save);
8046 +EXPORT_SYMBOL(dwc_cc_restore_from_data);
8047 +EXPORT_SYMBOL(dwc_cc_match_chid);
8048 +EXPORT_SYMBOL(dwc_cc_match_cdid);
8049 +EXPORT_SYMBOL(dwc_cc_ck);
8050 +EXPORT_SYMBOL(dwc_cc_chid);
8051 +EXPORT_SYMBOL(dwc_cc_cdid);
8052 +EXPORT_SYMBOL(dwc_cc_name);
8053 +#endif /* DWC_CCLIB */
8054 +
8055 +#ifdef DWC_CRYPTOLIB
8056 +# ifndef CONFIG_MACH_IPMATE
8057 +/* Modpow */
8058 +EXPORT_SYMBOL(dwc_modpow);
8059 +
8060 +/* DH */
8061 +EXPORT_SYMBOL(dwc_dh_modpow);
8062 +EXPORT_SYMBOL(dwc_dh_derive_keys);
8063 +EXPORT_SYMBOL(dwc_dh_pk);
8064 +# endif /* CONFIG_MACH_IPMATE */
8065 +
8066 +/* Crypto */
8067 +EXPORT_SYMBOL(dwc_wusb_aes_encrypt);
8068 +EXPORT_SYMBOL(dwc_wusb_cmf);
8069 +EXPORT_SYMBOL(dwc_wusb_prf);
8070 +EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce);
8071 +EXPORT_SYMBOL(dwc_wusb_gen_nonce);
8072 +EXPORT_SYMBOL(dwc_wusb_gen_key);
8073 +EXPORT_SYMBOL(dwc_wusb_gen_mic);
8074 +#endif /* DWC_CRYPTOLIB */
8075 +
8076 +/* Notification */
8077 +#ifdef DWC_NOTIFYLIB
8078 +EXPORT_SYMBOL(dwc_alloc_notification_manager);
8079 +EXPORT_SYMBOL(dwc_free_notification_manager);
8080 +EXPORT_SYMBOL(dwc_register_notifier);
8081 +EXPORT_SYMBOL(dwc_unregister_notifier);
8082 +EXPORT_SYMBOL(dwc_add_observer);
8083 +EXPORT_SYMBOL(dwc_remove_observer);
8084 +EXPORT_SYMBOL(dwc_notify);
8085 +#endif
8086 +
8087 +/* Memory Debugging Routines */
8088 +#ifdef DWC_DEBUG_MEMORY
8089 +EXPORT_SYMBOL(dwc_alloc_debug);
8090 +EXPORT_SYMBOL(dwc_alloc_atomic_debug);
8091 +EXPORT_SYMBOL(dwc_free_debug);
8092 +EXPORT_SYMBOL(dwc_dma_alloc_debug);
8093 +EXPORT_SYMBOL(dwc_dma_free_debug);
8094 +#endif
8095 +
8096 +EXPORT_SYMBOL(DWC_MEMSET);
8097 +EXPORT_SYMBOL(DWC_MEMCPY);
8098 +EXPORT_SYMBOL(DWC_MEMMOVE);
8099 +EXPORT_SYMBOL(DWC_MEMCMP);
8100 +EXPORT_SYMBOL(DWC_STRNCMP);
8101 +EXPORT_SYMBOL(DWC_STRCMP);
8102 +EXPORT_SYMBOL(DWC_STRLEN);
8103 +EXPORT_SYMBOL(DWC_STRCPY);
8104 +EXPORT_SYMBOL(DWC_STRDUP);
8105 +EXPORT_SYMBOL(DWC_ATOI);
8106 +EXPORT_SYMBOL(DWC_ATOUI);
8107 +
8108 +#ifdef DWC_UTFLIB
8109 +EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE);
8110 +#endif /* DWC_UTFLIB */
8111 +
8112 +EXPORT_SYMBOL(DWC_IN_IRQ);
8113 +EXPORT_SYMBOL(DWC_IN_BH);
8114 +EXPORT_SYMBOL(DWC_VPRINTF);
8115 +EXPORT_SYMBOL(DWC_VSNPRINTF);
8116 +EXPORT_SYMBOL(DWC_PRINTF);
8117 +EXPORT_SYMBOL(DWC_SPRINTF);
8118 +EXPORT_SYMBOL(DWC_SNPRINTF);
8119 +EXPORT_SYMBOL(__DWC_WARN);
8120 +EXPORT_SYMBOL(__DWC_ERROR);
8121 +EXPORT_SYMBOL(DWC_EXCEPTION);
8122 +
8123 +#ifdef DEBUG
8124 +EXPORT_SYMBOL(__DWC_DEBUG);
8125 +#endif
8126 +
8127 +EXPORT_SYMBOL(__DWC_DMA_ALLOC);
8128 +EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC);
8129 +EXPORT_SYMBOL(__DWC_DMA_FREE);
8130 +EXPORT_SYMBOL(__DWC_ALLOC);
8131 +EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC);
8132 +EXPORT_SYMBOL(__DWC_FREE);
8133 +
8134 +#ifdef DWC_CRYPTOLIB
8135 +EXPORT_SYMBOL(DWC_RANDOM_BYTES);
8136 +EXPORT_SYMBOL(DWC_AES_CBC);
8137 +EXPORT_SYMBOL(DWC_SHA256);
8138 +EXPORT_SYMBOL(DWC_HMAC_SHA256);
8139 +#endif
8140 +
8141 +EXPORT_SYMBOL(DWC_CPU_TO_LE32);
8142 +EXPORT_SYMBOL(DWC_CPU_TO_BE32);
8143 +EXPORT_SYMBOL(DWC_LE32_TO_CPU);
8144 +EXPORT_SYMBOL(DWC_BE32_TO_CPU);
8145 +EXPORT_SYMBOL(DWC_CPU_TO_LE16);
8146 +EXPORT_SYMBOL(DWC_CPU_TO_BE16);
8147 +EXPORT_SYMBOL(DWC_LE16_TO_CPU);
8148 +EXPORT_SYMBOL(DWC_BE16_TO_CPU);
8149 +EXPORT_SYMBOL(DWC_READ_REG32);
8150 +EXPORT_SYMBOL(DWC_WRITE_REG32);
8151 +EXPORT_SYMBOL(DWC_MODIFY_REG32);
8152 +
8153 +#if 0
8154 +EXPORT_SYMBOL(DWC_READ_REG64);
8155 +EXPORT_SYMBOL(DWC_WRITE_REG64);
8156 +EXPORT_SYMBOL(DWC_MODIFY_REG64);
8157 +#endif
8158 +
8159 +EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC);
8160 +EXPORT_SYMBOL(DWC_SPINLOCK_FREE);
8161 +EXPORT_SYMBOL(DWC_SPINLOCK);
8162 +EXPORT_SYMBOL(DWC_SPINUNLOCK);
8163 +EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE);
8164 +EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE);
8165 +EXPORT_SYMBOL(DWC_MUTEX_ALLOC);
8166 +
8167 +#if (!defined(DWC_LINUX) || !defined(CONFIG_DEBUG_MUTEXES))
8168 +EXPORT_SYMBOL(DWC_MUTEX_FREE);
8169 +#endif
8170 +
8171 +EXPORT_SYMBOL(DWC_MUTEX_LOCK);
8172 +EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK);
8173 +EXPORT_SYMBOL(DWC_MUTEX_UNLOCK);
8174 +EXPORT_SYMBOL(DWC_UDELAY);
8175 +EXPORT_SYMBOL(DWC_MDELAY);
8176 +EXPORT_SYMBOL(DWC_MSLEEP);
8177 +EXPORT_SYMBOL(DWC_TIME);
8178 +EXPORT_SYMBOL(DWC_TIMER_ALLOC);
8179 +EXPORT_SYMBOL(DWC_TIMER_FREE);
8180 +EXPORT_SYMBOL(DWC_TIMER_SCHEDULE);
8181 +EXPORT_SYMBOL(DWC_TIMER_CANCEL);
8182 +EXPORT_SYMBOL(DWC_WAITQ_ALLOC);
8183 +EXPORT_SYMBOL(DWC_WAITQ_FREE);
8184 +EXPORT_SYMBOL(DWC_WAITQ_WAIT);
8185 +EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT);
8186 +EXPORT_SYMBOL(DWC_WAITQ_TRIGGER);
8187 +EXPORT_SYMBOL(DWC_WAITQ_ABORT);
8188 +EXPORT_SYMBOL(DWC_THREAD_RUN);
8189 +EXPORT_SYMBOL(DWC_THREAD_STOP);
8190 +EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP);
8191 +EXPORT_SYMBOL(DWC_TASK_ALLOC);
8192 +EXPORT_SYMBOL(DWC_TASK_FREE);
8193 +EXPORT_SYMBOL(DWC_TASK_SCHEDULE);
8194 +EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE);
8195 +EXPORT_SYMBOL(DWC_WORKQ_ALLOC);
8196 +EXPORT_SYMBOL(DWC_WORKQ_FREE);
8197 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE);
8198 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED);
8199 +EXPORT_SYMBOL(DWC_WORKQ_PENDING);
8200 +
8201 +static int dwc_common_port_init_module(void)
8202 +{
8203 + int result = 0;
8204 +
8205 + printk(KERN_DEBUG "Module dwc_common_port init\n" );
8206 +
8207 +#ifdef DWC_DEBUG_MEMORY
8208 + result = dwc_memory_debug_start(NULL);
8209 + if (result) {
8210 + printk(KERN_ERR
8211 + "dwc_memory_debug_start() failed with error %d\n",
8212 + result);
8213 + return result;
8214 + }
8215 +#endif
8216 +
8217 +#ifdef DWC_NOTIFYLIB
8218 + result = dwc_alloc_notification_manager(NULL, NULL);
8219 + if (result) {
8220 + printk(KERN_ERR
8221 + "dwc_alloc_notification_manager() failed with error %d\n",
8222 + result);
8223 + return result;
8224 + }
8225 +#endif
8226 + return result;
8227 +}
8228 +
8229 +static void dwc_common_port_exit_module(void)
8230 +{
8231 + printk(KERN_DEBUG "Module dwc_common_port exit\n" );
8232 +
8233 +#ifdef DWC_NOTIFYLIB
8234 + dwc_free_notification_manager();
8235 +#endif
8236 +
8237 +#ifdef DWC_DEBUG_MEMORY
8238 + dwc_memory_debug_stop();
8239 +#endif
8240 +}
8241 +
8242 +module_init(dwc_common_port_init_module);
8243 +module_exit(dwc_common_port_exit_module);
8244 +
8245 +MODULE_DESCRIPTION("DWC Common Library - Portable version");
8246 +MODULE_AUTHOR("Synopsys Inc.");
8247 +MODULE_LICENSE ("GPL");
8248 +
8249 +#endif /* DWC_LIBMODULE */
8250 --- /dev/null
8251 +++ b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
8252 @@ -0,0 +1,1275 @@
8253 +#include "dwc_os.h"
8254 +#include "dwc_list.h"
8255 +
8256 +#ifdef DWC_CCLIB
8257 +# include "dwc_cc.h"
8258 +#endif
8259 +
8260 +#ifdef DWC_CRYPTOLIB
8261 +# include "dwc_modpow.h"
8262 +# include "dwc_dh.h"
8263 +# include "dwc_crypto.h"
8264 +#endif
8265 +
8266 +#ifdef DWC_NOTIFYLIB
8267 +# include "dwc_notifier.h"
8268 +#endif
8269 +
8270 +/* OS-Level Implementations */
8271 +
8272 +/* This is the NetBSD 4.0.1 kernel implementation of the DWC platform library. */
8273 +
8274 +
8275 +/* MISC */
8276 +
8277 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
8278 +{
8279 + return memset(dest, byte, size);
8280 +}
8281 +
8282 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
8283 +{
8284 + return memcpy(dest, src, size);
8285 +}
8286 +
8287 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
8288 +{
8289 + bcopy(src, dest, size);
8290 + return dest;
8291 +}
8292 +
8293 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
8294 +{
8295 + return memcmp(m1, m2, size);
8296 +}
8297 +
8298 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
8299 +{
8300 + return strncmp(s1, s2, size);
8301 +}
8302 +
8303 +int DWC_STRCMP(void *s1, void *s2)
8304 +{
8305 + return strcmp(s1, s2);
8306 +}
8307 +
8308 +int DWC_STRLEN(char const *str)
8309 +{
8310 + return strlen(str);
8311 +}
8312 +
8313 +char *DWC_STRCPY(char *to, char const *from)
8314 +{
8315 + return strcpy(to, from);
8316 +}
8317 +
8318 +char *DWC_STRDUP(char const *str)
8319 +{
8320 + int len = DWC_STRLEN(str) + 1;
8321 + char *new = DWC_ALLOC_ATOMIC(len);
8322 +
8323 + if (!new) {
8324 + return NULL;
8325 + }
8326 +
8327 + DWC_MEMCPY(new, str, len);
8328 + return new;
8329 +}
8330 +
8331 +int DWC_ATOI(char *str, int32_t *value)
8332 +{
8333 + char *end = NULL;
8334 +
8335 + /* NetBSD doesn't have 'strtol' in the kernel, but 'strtoul'
8336 + * should be equivalent on 2's complement machines
8337 + */
8338 + *value = strtoul(str, &end, 0);
8339 + if (*end == '\0') {
8340 + return 0;
8341 + }
8342 +
8343 + return -1;
8344 +}
8345 +
8346 +int DWC_ATOUI(char *str, uint32_t *value)
8347 +{
8348 + char *end = NULL;
8349 +
8350 + *value = strtoul(str, &end, 0);
8351 + if (*end == '\0') {
8352 + return 0;
8353 + }
8354 +
8355 + return -1;
8356 +}
8357 +
8358 +
8359 +#ifdef DWC_UTFLIB
8360 +/* From usbstring.c */
8361 +
8362 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
8363 +{
8364 + int count = 0;
8365 + u8 c;
8366 + u16 uchar;
8367 +
8368 + /* this insists on correct encodings, though not minimal ones.
8369 + * BUT it currently rejects legit 4-byte UTF-8 code points,
8370 + * which need surrogate pairs. (Unicode 3.1 can use them.)
8371 + */
8372 + while (len != 0 && (c = (u8) *s++) != 0) {
8373 + if (unlikely(c & 0x80)) {
8374 + // 2-byte sequence:
8375 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
8376 + if ((c & 0xe0) == 0xc0) {
8377 + uchar = (c & 0x1f) << 6;
8378 +
8379 + c = (u8) *s++;
8380 + if ((c & 0xc0) != 0xc0)
8381 + goto fail;
8382 + c &= 0x3f;
8383 + uchar |= c;
8384 +
8385 + // 3-byte sequence (most CJKV characters):
8386 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
8387 + } else if ((c & 0xf0) == 0xe0) {
8388 + uchar = (c & 0x0f) << 12;
8389 +
8390 + c = (u8) *s++;
8391 + if ((c & 0xc0) != 0xc0)
8392 + goto fail;
8393 + c &= 0x3f;
8394 + uchar |= c << 6;
8395 +
8396 + c = (u8) *s++;
8397 + if ((c & 0xc0) != 0xc0)
8398 + goto fail;
8399 + c &= 0x3f;
8400 + uchar |= c;
8401 +
8402 + /* no bogus surrogates */
8403 + if (0xd800 <= uchar && uchar <= 0xdfff)
8404 + goto fail;
8405 +
8406 + // 4-byte sequence (surrogate pairs, currently rare):
8407 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
8408 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
8409 + // (uuuuu = wwww + 1)
8410 + // FIXME accept the surrogate code points (only)
8411 + } else
8412 + goto fail;
8413 + } else
8414 + uchar = c;
8415 + put_unaligned (cpu_to_le16 (uchar), cp++);
8416 + count++;
8417 + len--;
8418 + }
8419 + return count;
8420 +fail:
8421 + return -1;
8422 +}
8423 +
8424 +#endif /* DWC_UTFLIB */
8425 +
8426 +
8427 +/* dwc_debug.h */
8428 +
8429 +dwc_bool_t DWC_IN_IRQ(void)
8430 +{
8431 +// return in_irq();
8432 + return 0;
8433 +}
8434 +
8435 +dwc_bool_t DWC_IN_BH(void)
8436 +{
8437 +// return in_softirq();
8438 + return 0;
8439 +}
8440 +
8441 +void DWC_VPRINTF(char *format, va_list args)
8442 +{
8443 + vprintf(format, args);
8444 +}
8445 +
8446 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
8447 +{
8448 + return vsnprintf(str, size, format, args);
8449 +}
8450 +
8451 +void DWC_PRINTF(char *format, ...)
8452 +{
8453 + va_list args;
8454 +
8455 + va_start(args, format);
8456 + DWC_VPRINTF(format, args);
8457 + va_end(args);
8458 +}
8459 +
8460 +int DWC_SPRINTF(char *buffer, char *format, ...)
8461 +{
8462 + int retval;
8463 + va_list args;
8464 +
8465 + va_start(args, format);
8466 + retval = vsprintf(buffer, format, args);
8467 + va_end(args);
8468 + return retval;
8469 +}
8470 +
8471 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
8472 +{
8473 + int retval;
8474 + va_list args;
8475 +
8476 + va_start(args, format);
8477 + retval = vsnprintf(buffer, size, format, args);
8478 + va_end(args);
8479 + return retval;
8480 +}
8481 +
8482 +void __DWC_WARN(char *format, ...)
8483 +{
8484 + va_list args;
8485 +
8486 + va_start(args, format);
8487 + DWC_VPRINTF(format, args);
8488 + va_end(args);
8489 +}
8490 +
8491 +void __DWC_ERROR(char *format, ...)
8492 +{
8493 + va_list args;
8494 +
8495 + va_start(args, format);
8496 + DWC_VPRINTF(format, args);
8497 + va_end(args);
8498 +}
8499 +
8500 +void DWC_EXCEPTION(char *format, ...)
8501 +{
8502 + va_list args;
8503 +
8504 + va_start(args, format);
8505 + DWC_VPRINTF(format, args);
8506 + va_end(args);
8507 +// BUG_ON(1); ???
8508 +}
8509 +
8510 +#ifdef DEBUG
8511 +void __DWC_DEBUG(char *format, ...)
8512 +{
8513 + va_list args;
8514 +
8515 + va_start(args, format);
8516 + DWC_VPRINTF(format, args);
8517 + va_end(args);
8518 +}
8519 +#endif
8520 +
8521 +
8522 +/* dwc_mem.h */
8523 +
8524 +#if 0
8525 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
8526 + uint32_t align,
8527 + uint32_t alloc)
8528 +{
8529 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
8530 + size, align, alloc);
8531 + return (dwc_pool_t *)pool;
8532 +}
8533 +
8534 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
8535 +{
8536 + dma_pool_destroy((struct dma_pool *)pool);
8537 +}
8538 +
8539 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
8540 +{
8541 +// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
8542 + return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
8543 +}
8544 +
8545 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
8546 +{
8547 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
8548 + memset(..);
8549 +}
8550 +
8551 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
8552 +{
8553 + dma_pool_free(pool, vaddr, daddr);
8554 +}
8555 +#endif
8556 +
8557 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
8558 +{
8559 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
8560 + int error;
8561 +
8562 + error = bus_dmamem_alloc(dma->dma_tag, size, 1, size, dma->segs,
8563 + sizeof(dma->segs) / sizeof(dma->segs[0]),
8564 + &dma->nsegs, BUS_DMA_NOWAIT);
8565 + if (error) {
8566 + printf("%s: bus_dmamem_alloc(%ju) failed: %d\n", __func__,
8567 + (uintmax_t)size, error);
8568 + goto fail_0;
8569 + }
8570 +
8571 + error = bus_dmamem_map(dma->dma_tag, dma->segs, dma->nsegs, size,
8572 + (caddr_t *)&dma->dma_vaddr,
8573 + BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
8574 + if (error) {
8575 + printf("%s: bus_dmamem_map failed: %d\n", __func__, error);
8576 + goto fail_1;
8577 + }
8578 +
8579 + error = bus_dmamap_create(dma->dma_tag, size, 1, size, 0,
8580 + BUS_DMA_NOWAIT, &dma->dma_map);
8581 + if (error) {
8582 + printf("%s: bus_dmamap_create failed: %d\n", __func__, error);
8583 + goto fail_2;
8584 + }
8585 +
8586 + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
8587 + size, NULL, BUS_DMA_NOWAIT);
8588 + if (error) {
8589 + printf("%s: bus_dmamap_load failed: %d\n", __func__, error);
8590 + goto fail_3;
8591 + }
8592 +
8593 + dma->dma_paddr = (bus_addr_t)dma->segs[0].ds_addr;
8594 + *dma_addr = dma->dma_paddr;
8595 + return dma->dma_vaddr;
8596 +
8597 +fail_3:
8598 + bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
8599 +fail_2:
8600 + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
8601 +fail_1:
8602 + bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
8603 +fail_0:
8604 + dma->dma_map = NULL;
8605 + dma->dma_vaddr = NULL;
8606 + dma->nsegs = 0;
8607 +
8608 + return NULL;
8609 +}
8610 +
8611 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
8612 +{
8613 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
8614 +
8615 + if (dma->dma_map != NULL) {
8616 + bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, size,
8617 + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
8618 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
8619 + bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
8620 + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
8621 + bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
8622 + dma->dma_paddr = 0;
8623 + dma->dma_map = NULL;
8624 + dma->dma_vaddr = NULL;
8625 + dma->nsegs = 0;
8626 + }
8627 +}
8628 +
8629 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
8630 +{
8631 + return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
8632 +}
8633 +
8634 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
8635 +{
8636 + return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
8637 +}
8638 +
8639 +void __DWC_FREE(void *mem_ctx, void *addr)
8640 +{
8641 + free(addr, M_DEVBUF);
8642 +}
8643 +
8644 +
8645 +#ifdef DWC_CRYPTOLIB
8646 +/* dwc_crypto.h */
8647 +
8648 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
8649 +{
8650 + get_random_bytes(buffer, length);
8651 +}
8652 +
8653 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
8654 +{
8655 + struct crypto_blkcipher *tfm;
8656 + struct blkcipher_desc desc;
8657 + struct scatterlist sgd;
8658 + struct scatterlist sgs;
8659 +
8660 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
8661 + if (tfm == NULL) {
8662 + printk("failed to load transform for aes CBC\n");
8663 + return -1;
8664 + }
8665 +
8666 + crypto_blkcipher_setkey(tfm, key, keylen);
8667 + crypto_blkcipher_set_iv(tfm, iv, 16);
8668 +
8669 + sg_init_one(&sgd, out, messagelen);
8670 + sg_init_one(&sgs, message, messagelen);
8671 +
8672 + desc.tfm = tfm;
8673 + desc.flags = 0;
8674 +
8675 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
8676 + crypto_free_blkcipher(tfm);
8677 + DWC_ERROR("AES CBC encryption failed");
8678 + return -1;
8679 + }
8680 +
8681 + crypto_free_blkcipher(tfm);
8682 + return 0;
8683 +}
8684 +
8685 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
8686 +{
8687 + struct crypto_hash *tfm;
8688 + struct hash_desc desc;
8689 + struct scatterlist sg;
8690 +
8691 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
8692 + if (IS_ERR(tfm)) {
8693 + DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
8694 + return 0;
8695 + }
8696 + desc.tfm = tfm;
8697 + desc.flags = 0;
8698 +
8699 + sg_init_one(&sg, message, len);
8700 + crypto_hash_digest(&desc, &sg, len, out);
8701 + crypto_free_hash(tfm);
8702 +
8703 + return 1;
8704 +}
8705 +
8706 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
8707 + uint8_t *key, uint32_t keylen, uint8_t *out)
8708 +{
8709 + struct crypto_hash *tfm;
8710 + struct hash_desc desc;
8711 + struct scatterlist sg;
8712 +
8713 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
8714 + if (IS_ERR(tfm)) {
8715 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
8716 + return 0;
8717 + }
8718 + desc.tfm = tfm;
8719 + desc.flags = 0;
8720 +
8721 + sg_init_one(&sg, message, messagelen);
8722 + crypto_hash_setkey(tfm, key, keylen);
8723 + crypto_hash_digest(&desc, &sg, messagelen, out);
8724 + crypto_free_hash(tfm);
8725 +
8726 + return 1;
8727 +}
8728 +
8729 +#endif /* DWC_CRYPTOLIB */
8730 +
8731 +
8732 +/* Byte Ordering Conversions */
8733 +
8734 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
8735 +{
8736 +#ifdef __LITTLE_ENDIAN
8737 + return *p;
8738 +#else
8739 + uint8_t *u_p = (uint8_t *)p;
8740 +
8741 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8742 +#endif
8743 +}
8744 +
8745 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
8746 +{
8747 +#ifdef __BIG_ENDIAN
8748 + return *p;
8749 +#else
8750 + uint8_t *u_p = (uint8_t *)p;
8751 +
8752 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8753 +#endif
8754 +}
8755 +
8756 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
8757 +{
8758 +#ifdef __LITTLE_ENDIAN
8759 + return *p;
8760 +#else
8761 + uint8_t *u_p = (uint8_t *)p;
8762 +
8763 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8764 +#endif
8765 +}
8766 +
8767 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
8768 +{
8769 +#ifdef __BIG_ENDIAN
8770 + return *p;
8771 +#else
8772 + uint8_t *u_p = (uint8_t *)p;
8773 +
8774 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8775 +#endif
8776 +}
8777 +
8778 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
8779 +{
8780 +#ifdef __LITTLE_ENDIAN
8781 + return *p;
8782 +#else
8783 + uint8_t *u_p = (uint8_t *)p;
8784 + return (u_p[1] | (u_p[0] << 8));
8785 +#endif
8786 +}
8787 +
8788 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
8789 +{
8790 +#ifdef __BIG_ENDIAN
8791 + return *p;
8792 +#else
8793 + uint8_t *u_p = (uint8_t *)p;
8794 + return (u_p[1] | (u_p[0] << 8));
8795 +#endif
8796 +}
8797 +
8798 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
8799 +{
8800 +#ifdef __LITTLE_ENDIAN
8801 + return *p;
8802 +#else
8803 + uint8_t *u_p = (uint8_t *)p;
8804 + return (u_p[1] | (u_p[0] << 8));
8805 +#endif
8806 +}
8807 +
8808 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
8809 +{
8810 +#ifdef __BIG_ENDIAN
8811 + return *p;
8812 +#else
8813 + uint8_t *u_p = (uint8_t *)p;
8814 + return (u_p[1] | (u_p[0] << 8));
8815 +#endif
8816 +}
8817 +
8818 +
8819 +/* Registers */
8820 +
8821 +uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
8822 +{
8823 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8824 + bus_size_t ior = (bus_size_t)reg;
8825 +
8826 + return bus_space_read_4(io->iot, io->ioh, ior);
8827 +}
8828 +
8829 +#if 0
8830 +uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
8831 +{
8832 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8833 + bus_size_t ior = (bus_size_t)reg;
8834 +
8835 + return bus_space_read_8(io->iot, io->ioh, ior);
8836 +}
8837 +#endif
8838 +
8839 +void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
8840 +{
8841 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8842 + bus_size_t ior = (bus_size_t)reg;
8843 +
8844 + bus_space_write_4(io->iot, io->ioh, ior, value);
8845 +}
8846 +
8847 +#if 0
8848 +void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
8849 +{
8850 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8851 + bus_size_t ior = (bus_size_t)reg;
8852 +
8853 + bus_space_write_8(io->iot, io->ioh, ior, value);
8854 +}
8855 +#endif
8856 +
8857 +void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
8858 + uint32_t set_mask)
8859 +{
8860 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8861 + bus_size_t ior = (bus_size_t)reg;
8862 +
8863 + bus_space_write_4(io->iot, io->ioh, ior,
8864 + (bus_space_read_4(io->iot, io->ioh, ior) &
8865 + ~clear_mask) | set_mask);
8866 +}
8867 +
8868 +#if 0
8869 +void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
8870 + uint64_t set_mask)
8871 +{
8872 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8873 + bus_size_t ior = (bus_size_t)reg;
8874 +
8875 + bus_space_write_8(io->iot, io->ioh, ior,
8876 + (bus_space_read_8(io->iot, io->ioh, ior) &
8877 + ~clear_mask) | set_mask);
8878 +}
8879 +#endif
8880 +
8881 +
8882 +/* Locking */
8883 +
8884 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
8885 +{
8886 + struct simplelock *sl = DWC_ALLOC(sizeof(*sl));
8887 +
8888 + if (!sl) {
8889 + DWC_ERROR("Cannot allocate memory for spinlock");
8890 + return NULL;
8891 + }
8892 +
8893 + simple_lock_init(sl);
8894 + return (dwc_spinlock_t *)sl;
8895 +}
8896 +
8897 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
8898 +{
8899 + struct simplelock *sl = (struct simplelock *)lock;
8900 +
8901 + DWC_FREE(sl);
8902 +}
8903 +
8904 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
8905 +{
8906 + simple_lock((struct simplelock *)lock);
8907 +}
8908 +
8909 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
8910 +{
8911 + simple_unlock((struct simplelock *)lock);
8912 +}
8913 +
8914 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
8915 +{
8916 + simple_lock((struct simplelock *)lock);
8917 + *flags = splbio();
8918 +}
8919 +
8920 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
8921 +{
8922 + splx(flags);
8923 + simple_unlock((struct simplelock *)lock);
8924 +}
8925 +
8926 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
8927 +{
8928 + dwc_mutex_t *mutex = DWC_ALLOC(sizeof(struct lock));
8929 +
8930 + if (!mutex) {
8931 + DWC_ERROR("Cannot allocate memory for mutex");
8932 + return NULL;
8933 + }
8934 +
8935 + lockinit((struct lock *)mutex, 0, "dw3mtx", 0, 0);
8936 + return mutex;
8937 +}
8938 +
8939 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
8940 +#else
8941 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
8942 +{
8943 + DWC_FREE(mutex);
8944 +}
8945 +#endif
8946 +
8947 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
8948 +{
8949 + lockmgr((struct lock *)mutex, LK_EXCLUSIVE, NULL);
8950 +}
8951 +
8952 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
8953 +{
8954 + int status;
8955 +
8956 + status = lockmgr((struct lock *)mutex, LK_EXCLUSIVE | LK_NOWAIT, NULL);
8957 + return status == 0;
8958 +}
8959 +
8960 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
8961 +{
8962 + lockmgr((struct lock *)mutex, LK_RELEASE, NULL);
8963 +}
8964 +
8965 +
8966 +/* Timing */
8967 +
8968 +void DWC_UDELAY(uint32_t usecs)
8969 +{
8970 + DELAY(usecs);
8971 +}
8972 +
8973 +void DWC_MDELAY(uint32_t msecs)
8974 +{
8975 + do {
8976 + DELAY(1000);
8977 + } while (--msecs);
8978 +}
8979 +
8980 +void DWC_MSLEEP(uint32_t msecs)
8981 +{
8982 + struct timeval tv;
8983 +
8984 + tv.tv_sec = msecs / 1000;
8985 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
8986 + tsleep(&tv, 0, "dw3slp", tvtohz(&tv));
8987 +}
8988 +
8989 +uint32_t DWC_TIME(void)
8990 +{
8991 + struct timeval tv;
8992 +
8993 + microuptime(&tv); // or getmicrouptime? (less precise, but faster)
8994 + return tv.tv_sec * 1000 + tv.tv_usec / 1000;
8995 +}
8996 +
8997 +
8998 +/* Timers */
8999 +
9000 +struct dwc_timer {
9001 + struct callout t;
9002 + char *name;
9003 + dwc_spinlock_t *lock;
9004 + dwc_timer_callback_t cb;
9005 + void *data;
9006 +};
9007 +
9008 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
9009 +{
9010 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
9011 +
9012 + if (!t) {
9013 + DWC_ERROR("Cannot allocate memory for timer");
9014 + return NULL;
9015 + }
9016 +
9017 + callout_init(&t->t);
9018 +
9019 + t->name = DWC_STRDUP(name);
9020 + if (!t->name) {
9021 + DWC_ERROR("Cannot allocate memory for timer->name");
9022 + goto no_name;
9023 + }
9024 +
9025 + t->lock = DWC_SPINLOCK_ALLOC();
9026 + if (!t->lock) {
9027 + DWC_ERROR("Cannot allocate memory for timer->lock");
9028 + goto no_lock;
9029 + }
9030 +
9031 + t->cb = cb;
9032 + t->data = data;
9033 +
9034 + return t;
9035 +
9036 + no_lock:
9037 + DWC_FREE(t->name);
9038 + no_name:
9039 + DWC_FREE(t);
9040 +
9041 + return NULL;
9042 +}
9043 +
9044 +void DWC_TIMER_FREE(dwc_timer_t *timer)
9045 +{
9046 + callout_stop(&timer->t);
9047 + DWC_SPINLOCK_FREE(timer->lock);
9048 + DWC_FREE(timer->name);
9049 + DWC_FREE(timer);
9050 +}
9051 +
9052 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
9053 +{
9054 + struct timeval tv;
9055 +
9056 + tv.tv_sec = time / 1000;
9057 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
9058 + callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
9059 +}
9060 +
9061 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
9062 +{
9063 + callout_stop(&timer->t);
9064 +}
9065 +
9066 +
9067 +/* Wait Queues */
9068 +
9069 +struct dwc_waitq {
9070 + struct simplelock lock;
9071 + int abort;
9072 +};
9073 +
9074 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
9075 +{
9076 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
9077 +
9078 + if (!wq) {
9079 + DWC_ERROR("Cannot allocate memory for waitqueue");
9080 + return NULL;
9081 + }
9082 +
9083 + simple_lock_init(&wq->lock);
9084 + wq->abort = 0;
9085 +
9086 + return wq;
9087 +}
9088 +
9089 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
9090 +{
9091 + DWC_FREE(wq);
9092 +}
9093 +
9094 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
9095 +{
9096 + int ipl;
9097 + int result = 0;
9098 +
9099 + simple_lock(&wq->lock);
9100 + ipl = splbio();
9101 +
9102 + /* Skip the sleep if already aborted or triggered */
9103 + if (!wq->abort && !cond(data)) {
9104 + splx(ipl);
9105 + result = ltsleep(wq, PCATCH, "dw3wat", 0, &wq->lock); // infinite timeout
9106 + ipl = splbio();
9107 + }
9108 +
9109 + if (result == 0) { // awoken
9110 + if (wq->abort) {
9111 + wq->abort = 0;
9112 + result = -DWC_E_ABORT;
9113 + } else {
9114 + result = 0;
9115 + }
9116 +
9117 + splx(ipl);
9118 + simple_unlock(&wq->lock);
9119 + } else {
9120 + wq->abort = 0;
9121 + splx(ipl);
9122 + simple_unlock(&wq->lock);
9123 +
9124 + if (result == ERESTART) { // signaled - restart
9125 + result = -DWC_E_RESTART;
9126 + } else { // signaled - must be EINTR
9127 + result = -DWC_E_ABORT;
9128 + }
9129 + }
9130 +
9131 + return result;
9132 +}
9133 +
9134 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
9135 + void *data, int32_t msecs)
9136 +{
9137 + struct timeval tv, tv1, tv2;
9138 + int ipl;
9139 + int result = 0;
9140 +
9141 + tv.tv_sec = msecs / 1000;
9142 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
9143 +
9144 + simple_lock(&wq->lock);
9145 + ipl = splbio();
9146 +
9147 + /* Skip the sleep if already aborted or triggered */
9148 + if (!wq->abort && !cond(data)) {
9149 + splx(ipl);
9150 + getmicrouptime(&tv1);
9151 + result = ltsleep(wq, PCATCH, "dw3wto", tvtohz(&tv), &wq->lock);
9152 + getmicrouptime(&tv2);
9153 + ipl = splbio();
9154 + }
9155 +
9156 + if (result == 0) { // awoken
9157 + if (wq->abort) {
9158 + wq->abort = 0;
9159 + splx(ipl);
9160 + simple_unlock(&wq->lock);
9161 + result = -DWC_E_ABORT;
9162 + } else {
9163 + splx(ipl);
9164 + simple_unlock(&wq->lock);
9165 +
9166 + tv2.tv_usec -= tv1.tv_usec;
9167 + if (tv2.tv_usec < 0) {
9168 + tv2.tv_usec += 1000000;
9169 + tv2.tv_sec--;
9170 + }
9171 +
9172 + tv2.tv_sec -= tv1.tv_sec;
9173 + result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
9174 + result = msecs - result;
9175 + if (result <= 0)
9176 + result = 1;
9177 + }
9178 + } else {
9179 + wq->abort = 0;
9180 + splx(ipl);
9181 + simple_unlock(&wq->lock);
9182 +
9183 + if (result == ERESTART) { // signaled - restart
9184 + result = -DWC_E_RESTART;
9185 +
9186 + } else if (result == EINTR) { // signaled - interrupt
9187 + result = -DWC_E_ABORT;
9188 +
9189 + } else { // timed out
9190 + result = -DWC_E_TIMEOUT;
9191 + }
9192 + }
9193 +
9194 + return result;
9195 +}
9196 +
9197 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
9198 +{
9199 + wakeup(wq);
9200 +}
9201 +
9202 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
9203 +{
9204 + int ipl;
9205 +
9206 + simple_lock(&wq->lock);
9207 + ipl = splbio();
9208 + wq->abort = 1;
9209 + wakeup(wq);
9210 + splx(ipl);
9211 + simple_unlock(&wq->lock);
9212 +}
9213 +
9214 +
9215 +/* Threading */
9216 +
9217 +struct dwc_thread {
9218 + struct proc *proc;
9219 + int abort;
9220 +};
9221 +
9222 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
9223 +{
9224 + int retval;
9225 + dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
9226 +
9227 + if (!thread) {
9228 + return NULL;
9229 + }
9230 +
9231 + thread->abort = 0;
9232 + retval = kthread_create1((void (*)(void *))func, data, &thread->proc,
9233 + "%s", name);
9234 + if (retval) {
9235 + DWC_FREE(thread);
9236 + return NULL;
9237 + }
9238 +
9239 + return thread;
9240 +}
9241 +
9242 +int DWC_THREAD_STOP(dwc_thread_t *thread)
9243 +{
9244 + int retval;
9245 +
9246 + thread->abort = 1;
9247 + retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
9248 +
9249 + if (retval == 0) {
9250 + /* DWC_THREAD_EXIT() will free the thread struct */
9251 + return 0;
9252 + }
9253 +
9254 + /* NOTE: We leak the thread struct if thread doesn't die */
9255 +
9256 + if (retval == EWOULDBLOCK) {
9257 + return -DWC_E_TIMEOUT;
9258 + }
9259 +
9260 + return -DWC_E_UNKNOWN;
9261 +}
9262 +
9263 +dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
9264 +{
9265 + return thread->abort;
9266 +}
9267 +
9268 +void DWC_THREAD_EXIT(dwc_thread_t *thread)
9269 +{
9270 + wakeup(&thread->abort);
9271 + DWC_FREE(thread);
9272 + kthread_exit(0);
9273 +}
9274 +
9275 +/* tasklets
9276 + - Runs in interrupt context (cannot sleep)
9277 + - Each tasklet runs on a single CPU
9278 + - Different tasklets can be running simultaneously on different CPUs
9279 + [ On NetBSD there is no corresponding mechanism, drivers don't have bottom-
9280 + halves. So we just call the callback directly from DWC_TASK_SCHEDULE() ]
9281 + */
9282 +struct dwc_tasklet {
9283 + dwc_tasklet_callback_t cb;
9284 + void *data;
9285 +};
9286 +
9287 +static void tasklet_callback(void *data)
9288 +{
9289 + dwc_tasklet_t *task = (dwc_tasklet_t *)data;
9290 +
9291 + task->cb(task->data);
9292 +}
9293 +
9294 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
9295 +{
9296 + dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
9297 +
9298 + if (task) {
9299 + task->cb = cb;
9300 + task->data = data;
9301 + } else {
9302 + DWC_ERROR("Cannot allocate memory for tasklet");
9303 + }
9304 +
9305 + return task;
9306 +}
9307 +
9308 +void DWC_TASK_FREE(dwc_tasklet_t *task)
9309 +{
9310 + DWC_FREE(task);
9311 +}
9312 +
9313 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
9314 +{
9315 + tasklet_callback(task);
9316 +}
9317 +
9318 +
9319 +/* workqueues
9320 + - Runs in process context (can sleep)
9321 + */
9322 +typedef struct work_container {
9323 + dwc_work_callback_t cb;
9324 + void *data;
9325 + dwc_workq_t *wq;
9326 + char *name;
9327 + int hz;
9328 + struct work task;
9329 +} work_container_t;
9330 +
9331 +struct dwc_workq {
9332 + struct workqueue *taskq;
9333 + dwc_spinlock_t *lock;
9334 + dwc_waitq_t *waitq;
9335 + int pending;
9336 + struct work_container *container;
9337 +};
9338 +
9339 +static void do_work(struct work *task, void *data)
9340 +{
9341 + dwc_workq_t *wq = (dwc_workq_t *)data;
9342 + work_container_t *container = wq->container;
9343 + dwc_irqflags_t flags;
9344 +
9345 + if (container->hz) {
9346 + tsleep(container, 0, "dw3wrk", container->hz);
9347 + }
9348 +
9349 + container->cb(container->data);
9350 + DWC_DEBUG("Work done: %s, container=%p", container->name, container);
9351 +
9352 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9353 + if (container->name)
9354 + DWC_FREE(container->name);
9355 + DWC_FREE(container);
9356 + wq->pending--;
9357 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9358 + DWC_WAITQ_TRIGGER(wq->waitq);
9359 +}
9360 +
9361 +static int work_done(void *data)
9362 +{
9363 + dwc_workq_t *workq = (dwc_workq_t *)data;
9364 +
9365 + return workq->pending == 0;
9366 +}
9367 +
9368 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
9369 +{
9370 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
9371 +}
9372 +
9373 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
9374 +{
9375 + int result;
9376 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
9377 +
9378 + if (!wq) {
9379 + DWC_ERROR("Cannot allocate memory for workqueue");
9380 + return NULL;
9381 + }
9382 +
9383 + result = workqueue_create(&wq->taskq, name, do_work, wq, 0 /*PWAIT*/,
9384 + IPL_BIO, 0);
9385 + if (result) {
9386 + DWC_ERROR("Cannot create workqueue");
9387 + goto no_taskq;
9388 + }
9389 +
9390 + wq->pending = 0;
9391 +
9392 + wq->lock = DWC_SPINLOCK_ALLOC();
9393 + if (!wq->lock) {
9394 + DWC_ERROR("Cannot allocate memory for spinlock");
9395 + goto no_lock;
9396 + }
9397 +
9398 + wq->waitq = DWC_WAITQ_ALLOC();
9399 + if (!wq->waitq) {
9400 + DWC_ERROR("Cannot allocate memory for waitqueue");
9401 + goto no_waitq;
9402 + }
9403 +
9404 + return wq;
9405 +
9406 + no_waitq:
9407 + DWC_SPINLOCK_FREE(wq->lock);
9408 + no_lock:
9409 + workqueue_destroy(wq->taskq);
9410 + no_taskq:
9411 + DWC_FREE(wq);
9412 +
9413 + return NULL;
9414 +}
9415 +
9416 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
9417 +{
9418 +#ifdef DEBUG
9419 + dwc_irqflags_t flags;
9420 +
9421 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9422 +
9423 + if (wq->pending != 0) {
9424 + struct work_container *container = wq->container;
9425 +
9426 + DWC_ERROR("Destroying work queue with pending work");
9427 +
9428 + if (container && container->name) {
9429 + DWC_ERROR("Work %s still pending", container->name);
9430 + }
9431 + }
9432 +
9433 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9434 +#endif
9435 + DWC_WAITQ_FREE(wq->waitq);
9436 + DWC_SPINLOCK_FREE(wq->lock);
9437 + workqueue_destroy(wq->taskq);
9438 + DWC_FREE(wq);
9439 +}
9440 +
9441 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
9442 + char *format, ...)
9443 +{
9444 + dwc_irqflags_t flags;
9445 + work_container_t *container;
9446 + static char name[128];
9447 + va_list args;
9448 +
9449 + va_start(args, format);
9450 + DWC_VSNPRINTF(name, 128, format, args);
9451 + va_end(args);
9452 +
9453 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9454 + wq->pending++;
9455 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9456 + DWC_WAITQ_TRIGGER(wq->waitq);
9457 +
9458 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
9459 + if (!container) {
9460 + DWC_ERROR("Cannot allocate memory for container");
9461 + return;
9462 + }
9463 +
9464 + container->name = DWC_STRDUP(name);
9465 + if (!container->name) {
9466 + DWC_ERROR("Cannot allocate memory for container->name");
9467 + DWC_FREE(container);
9468 + return;
9469 + }
9470 +
9471 + container->cb = cb;
9472 + container->data = data;
9473 + container->wq = wq;
9474 + container->hz = 0;
9475 + wq->container = container;
9476 +
9477 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
9478 + workqueue_enqueue(wq->taskq, &container->task);
9479 +}
9480 +
9481 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
9482 + void *data, uint32_t time, char *format, ...)
9483 +{
9484 + dwc_irqflags_t flags;
9485 + work_container_t *container;
9486 + static char name[128];
9487 + struct timeval tv;
9488 + va_list args;
9489 +
9490 + va_start(args, format);
9491 + DWC_VSNPRINTF(name, 128, format, args);
9492 + va_end(args);
9493 +
9494 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9495 + wq->pending++;
9496 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9497 + DWC_WAITQ_TRIGGER(wq->waitq);
9498 +
9499 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
9500 + if (!container) {
9501 + DWC_ERROR("Cannot allocate memory for container");
9502 + return;
9503 + }
9504 +
9505 + container->name = DWC_STRDUP(name);
9506 + if (!container->name) {
9507 + DWC_ERROR("Cannot allocate memory for container->name");
9508 + DWC_FREE(container);
9509 + return;
9510 + }
9511 +
9512 + container->cb = cb;
9513 + container->data = data;
9514 + container->wq = wq;
9515 + tv.tv_sec = time / 1000;
9516 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
9517 + container->hz = tvtohz(&tv);
9518 + wq->container = container;
9519 +
9520 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
9521 + workqueue_enqueue(wq->taskq, &container->task);
9522 +}
9523 +
9524 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
9525 +{
9526 + return wq->pending;
9527 +}
9528 --- /dev/null
9529 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.c
9530 @@ -0,0 +1,308 @@
9531 +/* =========================================================================
9532 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $
9533 + * $Revision: #5 $
9534 + * $Date: 2010/09/28 $
9535 + * $Change: 1596182 $
9536 + *
9537 + * Synopsys Portability Library Software and documentation
9538 + * (hereinafter, "Software") is an Unsupported proprietary work of
9539 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9540 + * between Synopsys and you.
9541 + *
9542 + * The Software IS NOT an item of Licensed Software or Licensed Product
9543 + * under any End User Software License Agreement or Agreement for
9544 + * Licensed Product with Synopsys or any supplement thereto. You are
9545 + * permitted to use and redistribute this Software in source and binary
9546 + * forms, with or without modification, provided that redistributions
9547 + * of source code must retain this notice. You may not view, use,
9548 + * disclose, copy or distribute this file or any information contained
9549 + * herein except pursuant to this license grant from Synopsys. If you
9550 + * do not agree with this notice, including the disclaimer below, then
9551 + * you are not authorized to use the Software.
9552 + *
9553 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9554 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9555 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9556 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9557 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9558 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9559 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9560 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9561 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9562 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9563 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9564 + * DAMAGE.
9565 + * ========================================================================= */
9566 +
9567 +/** @file
9568 + * This file contains the WUSB cryptographic routines.
9569 + */
9570 +
9571 +#ifdef DWC_CRYPTOLIB
9572 +
9573 +#include "dwc_crypto.h"
9574 +#include "usb.h"
9575 +
9576 +#ifdef DEBUG
9577 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
9578 +{
9579 + int i;
9580 + DWC_PRINTF("%s: ", name);
9581 + for (i=0; i<len; i++) {
9582 + DWC_PRINTF("%02x ", bytes[i]);
9583 + }
9584 + DWC_PRINTF("\n");
9585 +}
9586 +#else
9587 +#define dump_bytes(x...)
9588 +#endif
9589 +
9590 +/* Display a block */
9591 +void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
9592 +{
9593 +#ifdef DWC_DEBUG_CRYPTO
9594 + int i, blksize = 16;
9595 +
9596 + DWC_DEBUG("%s", prefix);
9597 +
9598 + if (suffix == NULL) {
9599 + suffix = "\n";
9600 + blksize = a;
9601 + }
9602 +
9603 + for (i = 0; i < blksize; i++)
9604 + DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? " " : " ");
9605 + DWC_PRINT(suffix);
9606 +#endif
9607 +}
9608 +
9609 +/**
9610 + * Encrypts an array of bytes using the AES encryption engine.
9611 + * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
9612 + * in-place.
9613 + *
9614 + * @return 0 on success, negative error code on error.
9615 + */
9616 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
9617 +{
9618 + u8 block_t[16];
9619 + DWC_MEMSET(block_t, 0, 16);
9620 +
9621 + return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
9622 +}
9623 +
9624 +/**
9625 + * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
9626 + * This function takes a data string and returns the encrypted CBC
9627 + * Counter-mode MIC.
9628 + *
9629 + * @param key The 128-bit symmetric key.
9630 + * @param nonce The CCM nonce.
9631 + * @param label The unique 14-byte ASCII text label.
9632 + * @param bytes The byte array to be encrypted.
9633 + * @param len Length of the byte array.
9634 + * @param result Byte array to receive the 8-byte encrypted MIC.
9635 + */
9636 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
9637 + char *label, u8 *bytes, int len, u8 *result)
9638 +{
9639 + u8 block_m[16];
9640 + u8 block_x[16];
9641 + u8 block_t[8];
9642 + int idx, blkNum;
9643 + u16 la = (u16)(len + 14);
9644 +
9645 + /* Set the AES-128 key */
9646 + //dwc_aes_setkey(tfm, key, 16);
9647 +
9648 + /* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
9649 + block_m[0] = 0x59;
9650 + for (idx = 0; idx < 13; idx++)
9651 + block_m[idx + 1] = nonce[idx];
9652 + block_m[14] = 0;
9653 + block_m[15] = 0;
9654 +
9655 + /* Produce the CBC IV */
9656 + dwc_wusb_aes_encrypt(block_m, key, block_x);
9657 + show_block(block_m, "CBC IV in: ", "\n", 0);
9658 + show_block(block_x, "CBC IV out:", "\n", 0);
9659 +
9660 + /* Fill block B1 from l(a) = Blen + 14, and A */
9661 + block_x[0] ^= (u8)(la >> 8);
9662 + block_x[1] ^= (u8)la;
9663 + for (idx = 0; idx < 14; idx++)
9664 + block_x[idx + 2] ^= label[idx];
9665 + show_block(block_x, "After xor: ", "b1\n", 16);
9666 +
9667 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9668 + show_block(block_x, "After AES: ", "b1\n", 16);
9669 +
9670 + idx = 0;
9671 + blkNum = 0;
9672 +
9673 + /* Fill remaining blocks with B */
9674 + while (len-- > 0) {
9675 + block_x[idx] ^= *bytes++;
9676 + if (++idx >= 16) {
9677 + idx = 0;
9678 + show_block(block_x, "After xor: ", "\n", blkNum);
9679 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9680 + show_block(block_x, "After AES: ", "\n", blkNum);
9681 + blkNum++;
9682 + }
9683 + }
9684 +
9685 + /* Handle partial last block */
9686 + if (idx > 0) {
9687 + show_block(block_x, "After xor: ", "\n", blkNum);
9688 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9689 + show_block(block_x, "After AES: ", "\n", blkNum);
9690 + }
9691 +
9692 + /* Save the MIC tag */
9693 + DWC_MEMCPY(block_t, block_x, 8);
9694 + show_block(block_t, "MIC tag : ", NULL, 8);
9695 +
9696 + /* Fill block A0 from flags = 0x01, N, and counter = 0 */
9697 + block_m[0] = 0x01;
9698 + block_m[14] = 0;
9699 + block_m[15] = 0;
9700 +
9701 + /* Encrypt the counter */
9702 + dwc_wusb_aes_encrypt(block_m, key, block_x);
9703 + show_block(block_x, "CTR[MIC] : ", NULL, 8);
9704 +
9705 + /* XOR with MIC tag */
9706 + for (idx = 0; idx < 8; idx++) {
9707 + block_t[idx] ^= block_x[idx];
9708 + }
9709 +
9710 + /* Return result to caller */
9711 + DWC_MEMCPY(result, block_t, 8);
9712 + show_block(result, "CCM-MIC : ", NULL, 8);
9713 +
9714 +}
9715 +
9716 +/**
9717 + * The PRF function described in section 6.5 of the WUSB spec. This function
9718 + * concatenates MIC values returned from dwc_cmf() to create a value of
9719 + * the requested length.
9720 + *
9721 + * @param prf_len Length of the PRF function in bits (64, 128, or 256).
9722 + * @param key, nonce, label, bytes, len Same as for dwc_cmf().
9723 + * @param result Byte array to receive the result.
9724 + */
9725 +void dwc_wusb_prf(int prf_len, u8 *key,
9726 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
9727 +{
9728 + int i;
9729 +
9730 + nonce[0] = 0;
9731 + for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
9732 + dwc_wusb_cmf(key, nonce, label, bytes, len, result);
9733 + result += 8;
9734 + }
9735 +}
9736 +
9737 +/**
9738 + * Fills in CCM Nonce per the WUSB spec.
9739 + *
9740 + * @param[in] haddr Host address.
9741 + * @param[in] daddr Device address.
9742 + * @param[in] tkid Session Key(PTK) identifier.
9743 + * @param[out] nonce Pointer to where the CCM Nonce output is to be written.
9744 + */
9745 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
9746 + uint8_t *nonce)
9747 +{
9748 +
9749 + DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
9750 +
9751 + DWC_MEMSET(&nonce[0], 0, 16);
9752 +
9753 + DWC_MEMCPY(&nonce[6], tkid, 3);
9754 + nonce[9] = daddr & 0xFF;
9755 + nonce[10] = (daddr >> 8) & 0xFF;
9756 + nonce[11] = haddr & 0xFF;
9757 + nonce[12] = (haddr >> 8) & 0xFF;
9758 +
9759 + dump_bytes("CCM nonce", nonce, 16);
9760 +}
9761 +
9762 +/**
9763 + * Generates a 16-byte cryptographic-grade random number for the Host/Device
9764 + * Nonce.
9765 + */
9766 +void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
9767 +{
9768 + uint8_t inonce[16];
9769 + uint32_t temp[4];
9770 +
9771 + /* Fill in the Nonce */
9772 + DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
9773 + inonce[9] = addr & 0xFF;
9774 + inonce[10] = (addr >> 8) & 0xFF;
9775 + inonce[11] = inonce[9];
9776 + inonce[12] = inonce[10];
9777 +
9778 + /* Collect "randomness samples" */
9779 + DWC_RANDOM_BYTES((uint8_t *)temp, 16);
9780 +
9781 + dwc_wusb_prf_128((uint8_t *)temp, nonce,
9782 + "Random Numbers", (uint8_t *)temp, sizeof(temp),
9783 + nonce);
9784 +}
9785 +
9786 +/**
9787 + * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
9788 + * WUSB spec.
9789 + *
9790 + * @param[in] ccm_nonce Pointer to CCM Nonce.
9791 + * @param[in] mk Master Key to derive the session from
9792 + * @param[in] hnonce Pointer to Host Nonce.
9793 + * @param[in] dnonce Pointer to Device Nonce.
9794 + * @param[out] kck Pointer to where the KCK output is to be written.
9795 + * @param[out] ptk Pointer to where the PTK output is to be written.
9796 + */
9797 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
9798 + uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
9799 +{
9800 + uint8_t idata[32];
9801 + uint8_t odata[32];
9802 +
9803 + dump_bytes("ck", mk, 16);
9804 + dump_bytes("hnonce", hnonce, 16);
9805 + dump_bytes("dnonce", dnonce, 16);
9806 +
9807 + /* The data is the HNonce and DNonce concatenated */
9808 + DWC_MEMCPY(&idata[0], hnonce, 16);
9809 + DWC_MEMCPY(&idata[16], dnonce, 16);
9810 +
9811 + dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
9812 +
9813 + /* Low 16 bytes of the result is the KCK, high 16 is the PTK */
9814 + DWC_MEMCPY(kck, &odata[0], 16);
9815 + DWC_MEMCPY(ptk, &odata[16], 16);
9816 +
9817 + dump_bytes("kck", kck, 16);
9818 + dump_bytes("ptk", ptk, 16);
9819 +}
9820 +
9821 +/**
9822 + * Generates the Message Integrity Code over the Handshake data per the
9823 + * WUSB spec.
9824 + *
9825 + * @param ccm_nonce Pointer to CCM Nonce.
9826 + * @param kck Pointer to Key Confirmation Key.
9827 + * @param data Pointer to Handshake data to be checked.
9828 + * @param mic Pointer to where the MIC output is to be written.
9829 + */
9830 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
9831 + uint8_t *data, uint8_t *mic)
9832 +{
9833 +
9834 + dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
9835 + data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
9836 +}
9837 +
9838 +#endif /* DWC_CRYPTOLIB */
9839 --- /dev/null
9840 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.h
9841 @@ -0,0 +1,111 @@
9842 +/* =========================================================================
9843 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.h $
9844 + * $Revision: #3 $
9845 + * $Date: 2010/09/28 $
9846 + * $Change: 1596182 $
9847 + *
9848 + * Synopsys Portability Library Software and documentation
9849 + * (hereinafter, "Software") is an Unsupported proprietary work of
9850 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9851 + * between Synopsys and you.
9852 + *
9853 + * The Software IS NOT an item of Licensed Software or Licensed Product
9854 + * under any End User Software License Agreement or Agreement for
9855 + * Licensed Product with Synopsys or any supplement thereto. You are
9856 + * permitted to use and redistribute this Software in source and binary
9857 + * forms, with or without modification, provided that redistributions
9858 + * of source code must retain this notice. You may not view, use,
9859 + * disclose, copy or distribute this file or any information contained
9860 + * herein except pursuant to this license grant from Synopsys. If you
9861 + * do not agree with this notice, including the disclaimer below, then
9862 + * you are not authorized to use the Software.
9863 + *
9864 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9865 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9866 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9867 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9868 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9869 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9870 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9871 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9872 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9873 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9874 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9875 + * DAMAGE.
9876 + * ========================================================================= */
9877 +
9878 +#ifndef _DWC_CRYPTO_H_
9879 +#define _DWC_CRYPTO_H_
9880 +
9881 +#ifdef __cplusplus
9882 +extern "C" {
9883 +#endif
9884 +
9885 +/** @file
9886 + *
9887 + * This file contains declarations for the WUSB Cryptographic routines as
9888 + * defined in the WUSB spec. They are only to be used internally by the DWC UWB
9889 + * modules.
9890 + */
9891 +
9892 +#include "dwc_os.h"
9893 +
9894 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
9895 +
9896 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
9897 + char *label, u8 *bytes, int len, u8 *result);
9898 +void dwc_wusb_prf(int prf_len, u8 *key,
9899 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
9900 +
9901 +/**
9902 + * The PRF-64 function described in section 6.5 of the WUSB spec.
9903 + *
9904 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9905 + */
9906 +static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
9907 + char *label, u8 *bytes, int len, u8 *result)
9908 +{
9909 + dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
9910 +}
9911 +
9912 +/**
9913 + * The PRF-128 function described in section 6.5 of the WUSB spec.
9914 + *
9915 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9916 + */
9917 +static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
9918 + char *label, u8 *bytes, int len, u8 *result)
9919 +{
9920 + dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
9921 +}
9922 +
9923 +/**
9924 + * The PRF-256 function described in section 6.5 of the WUSB spec.
9925 + *
9926 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9927 + */
9928 +static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
9929 + char *label, u8 *bytes, int len, u8 *result)
9930 +{
9931 + dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
9932 +}
9933 +
9934 +
9935 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
9936 + uint8_t *nonce);
9937 +void dwc_wusb_gen_nonce(uint16_t addr,
9938 + uint8_t *nonce);
9939 +
9940 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
9941 + uint8_t *hnonce, uint8_t *dnonce,
9942 + uint8_t *kck, uint8_t *ptk);
9943 +
9944 +
9945 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
9946 + *kck, uint8_t *data, uint8_t *mic);
9947 +
9948 +#ifdef __cplusplus
9949 +}
9950 +#endif
9951 +
9952 +#endif /* _DWC_CRYPTO_H_ */
9953 --- /dev/null
9954 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.c
9955 @@ -0,0 +1,291 @@
9956 +/* =========================================================================
9957 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
9958 + * $Revision: #3 $
9959 + * $Date: 2010/09/28 $
9960 + * $Change: 1596182 $
9961 + *
9962 + * Synopsys Portability Library Software and documentation
9963 + * (hereinafter, "Software") is an Unsupported proprietary work of
9964 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9965 + * between Synopsys and you.
9966 + *
9967 + * The Software IS NOT an item of Licensed Software or Licensed Product
9968 + * under any End User Software License Agreement or Agreement for
9969 + * Licensed Product with Synopsys or any supplement thereto. You are
9970 + * permitted to use and redistribute this Software in source and binary
9971 + * forms, with or without modification, provided that redistributions
9972 + * of source code must retain this notice. You may not view, use,
9973 + * disclose, copy or distribute this file or any information contained
9974 + * herein except pursuant to this license grant from Synopsys. If you
9975 + * do not agree with this notice, including the disclaimer below, then
9976 + * you are not authorized to use the Software.
9977 + *
9978 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9979 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9980 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9981 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9982 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9983 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9984 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9985 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9986 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9987 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9988 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9989 + * DAMAGE.
9990 + * ========================================================================= */
9991 +#ifdef DWC_CRYPTOLIB
9992 +
9993 +#ifndef CONFIG_MACH_IPMATE
9994 +
9995 +#include "dwc_dh.h"
9996 +#include "dwc_modpow.h"
9997 +
9998 +#ifdef DEBUG
9999 +/* This function prints out a buffer in the format described in the Association
10000 + * Model specification. */
10001 +static void dh_dump(char *str, void *_num, int len)
10002 +{
10003 + uint8_t *num = _num;
10004 + int i;
10005 + DWC_PRINTF("%s\n", str);
10006 + for (i = 0; i < len; i ++) {
10007 + DWC_PRINTF("%02x", num[i]);
10008 + if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
10009 + if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
10010 + }
10011 +
10012 + DWC_PRINTF("\n");
10013 +}
10014 +#else
10015 +#define dh_dump(_x...) do {; } while(0)
10016 +#endif
10017 +
10018 +/* Constant g value */
10019 +static __u32 dh_g[] = {
10020 + 0x02000000,
10021 +};
10022 +
10023 +/* Constant p value */
10024 +static __u32 dh_p[] = {
10025 + 0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
10026 + 0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
10027 + 0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
10028 + 0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
10029 + 0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
10030 + 0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
10031 + 0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
10032 + 0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
10033 + 0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
10034 + 0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
10035 + 0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
10036 + 0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
10037 +};
10038 +
10039 +static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
10040 +{
10041 + uint8_t *in = _in;
10042 + uint8_t *out = _out;
10043 + int i;
10044 + for (i=0; i<len; i++) {
10045 + out[i] = in[len-1-i];
10046 + }
10047 +}
10048 +
10049 +/* Computes the modular exponentiation (num^exp % mod). num, exp, and mod are
10050 + * big endian numbers of size len, in bytes. Each len value must be a multiple
10051 + * of 4. */
10052 +int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
10053 + void *exp, uint32_t exp_len,
10054 + void *mod, uint32_t mod_len,
10055 + void *out)
10056 +{
10057 + /* modpow() takes little endian numbers. AM uses big-endian. This
10058 + * function swaps bytes of numbers before passing onto modpow. */
10059 +
10060 + int retval = 0;
10061 + uint32_t *result;
10062 +
10063 + uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
10064 + uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
10065 + uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
10066 +
10067 + dh_swap_bytes(num, &bignum_num[1], num_len);
10068 + bignum_num[0] = num_len / 4;
10069 +
10070 + dh_swap_bytes(exp, &bignum_exp[1], exp_len);
10071 + bignum_exp[0] = exp_len / 4;
10072 +
10073 + dh_swap_bytes(mod, &bignum_mod[1], mod_len);
10074 + bignum_mod[0] = mod_len / 4;
10075 +
10076 + result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
10077 + if (!result) {
10078 + retval = -1;
10079 + goto dh_modpow_nomem;
10080 + }
10081 +
10082 + dh_swap_bytes(&result[1], out, result[0] * 4);
10083 + dwc_free(mem_ctx, result);
10084 +
10085 + dh_modpow_nomem:
10086 + dwc_free(mem_ctx, bignum_num);
10087 + dwc_free(mem_ctx, bignum_exp);
10088 + dwc_free(mem_ctx, bignum_mod);
10089 + return retval;
10090 +}
10091 +
10092 +
10093 +int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
10094 +{
10095 + int retval;
10096 + uint8_t m3[385];
10097 +
10098 +#ifndef DH_TEST_VECTORS
10099 + DWC_RANDOM_BYTES(exp, 32);
10100 +#endif
10101 +
10102 + /* Compute the pkd */
10103 + if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
10104 + exp, 32,
10105 + dh_p, 384, pk))) {
10106 + return retval;
10107 + }
10108 +
10109 + m3[384] = nd;
10110 + DWC_MEMCPY(&m3[0], pk, 384);
10111 + DWC_SHA256(m3, 385, hash);
10112 +
10113 + dh_dump("PK", pk, 384);
10114 + dh_dump("SHA-256(M3)", hash, 32);
10115 + return 0;
10116 +}
10117 +
10118 +int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
10119 + uint8_t *exp, int is_host,
10120 + char *dd, uint8_t *ck, uint8_t *kdk)
10121 +{
10122 + int retval;
10123 + uint8_t mv[784];
10124 + uint8_t sha_result[32];
10125 + uint8_t dhkey[384];
10126 + uint8_t shared_secret[384];
10127 + char *message;
10128 + uint32_t vd;
10129 +
10130 + uint8_t *pk;
10131 +
10132 + if (is_host) {
10133 + pk = pkd;
10134 + }
10135 + else {
10136 + pk = pkh;
10137 + }
10138 +
10139 + if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
10140 + exp, 32,
10141 + dh_p, 384, shared_secret))) {
10142 + return retval;
10143 + }
10144 + dh_dump("Shared Secret", shared_secret, 384);
10145 +
10146 + DWC_SHA256(shared_secret, 384, dhkey);
10147 + dh_dump("DHKEY", dhkey, 384);
10148 +
10149 + DWC_MEMCPY(&mv[0], pkd, 384);
10150 + DWC_MEMCPY(&mv[384], pkh, 384);
10151 + DWC_MEMCPY(&mv[768], "displayed digest", 16);
10152 + dh_dump("MV", mv, 784);
10153 +
10154 + DWC_SHA256(mv, 784, sha_result);
10155 + dh_dump("SHA-256(MV)", sha_result, 32);
10156 + dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
10157 +
10158 + dh_swap_bytes(sha_result, &vd, 4);
10159 +#ifdef DEBUG
10160 + DWC_PRINTF("Vd (decimal) = %d\n", vd);
10161 +#endif
10162 +
10163 + switch (nd) {
10164 + case 2:
10165 + vd = vd % 100;
10166 + DWC_SPRINTF(dd, "%02d", vd);
10167 + break;
10168 + case 3:
10169 + vd = vd % 1000;
10170 + DWC_SPRINTF(dd, "%03d", vd);
10171 + break;
10172 + case 4:
10173 + vd = vd % 10000;
10174 + DWC_SPRINTF(dd, "%04d", vd);
10175 + break;
10176 + }
10177 +#ifdef DEBUG
10178 + DWC_PRINTF("Display Digits: %s\n", dd);
10179 +#endif
10180 +
10181 + message = "connection key";
10182 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
10183 + dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
10184 + DWC_MEMCPY(ck, sha_result, 16);
10185 +
10186 + message = "key derivation key";
10187 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
10188 + dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
10189 + DWC_MEMCPY(kdk, sha_result, 32);
10190 +
10191 + return 0;
10192 +}
10193 +
10194 +
10195 +#ifdef DH_TEST_VECTORS
10196 +
10197 +static __u8 dh_a[] = {
10198 + 0x44, 0x00, 0x51, 0xd6,
10199 + 0xf0, 0xb5, 0x5e, 0xa9,
10200 + 0x67, 0xab, 0x31, 0xc6,
10201 + 0x8a, 0x8b, 0x5e, 0x37,
10202 + 0xd9, 0x10, 0xda, 0xe0,
10203 + 0xe2, 0xd4, 0x59, 0xa4,
10204 + 0x86, 0x45, 0x9c, 0xaa,
10205 + 0xdf, 0x36, 0x75, 0x16,
10206 +};
10207 +
10208 +static __u8 dh_b[] = {
10209 + 0x5d, 0xae, 0xc7, 0x86,
10210 + 0x79, 0x80, 0xa3, 0x24,
10211 + 0x8c, 0xe3, 0x57, 0x8f,
10212 + 0xc7, 0x5f, 0x1b, 0x0f,
10213 + 0x2d, 0xf8, 0x9d, 0x30,
10214 + 0x6f, 0xa4, 0x52, 0xcd,
10215 + 0xe0, 0x7a, 0x04, 0x8a,
10216 + 0xde, 0xd9, 0x26, 0x56,
10217 +};
10218 +
10219 +void dwc_run_dh_test_vectors(void *mem_ctx)
10220 +{
10221 + uint8_t pkd[384];
10222 + uint8_t pkh[384];
10223 + uint8_t hashd[32];
10224 + uint8_t hashh[32];
10225 + uint8_t ck[16];
10226 + uint8_t kdk[32];
10227 + char dd[5];
10228 +
10229 + DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
10230 +
10231 + /* compute the PKd and SHA-256(PKd || Nd) */
10232 + DWC_PRINTF("Computing PKd\n");
10233 + dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
10234 +
10235 + /* compute the PKd and SHA-256(PKh || Nd) */
10236 + DWC_PRINTF("Computing PKh\n");
10237 + dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
10238 +
10239 + /* compute the dhkey */
10240 + dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
10241 +}
10242 +#endif /* DH_TEST_VECTORS */
10243 +
10244 +#endif /* !CONFIG_MACH_IPMATE */
10245 +
10246 +#endif /* DWC_CRYPTOLIB */
10247 --- /dev/null
10248 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.h
10249 @@ -0,0 +1,106 @@
10250 +/* =========================================================================
10251 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.h $
10252 + * $Revision: #4 $
10253 + * $Date: 2010/09/28 $
10254 + * $Change: 1596182 $
10255 + *
10256 + * Synopsys Portability Library Software and documentation
10257 + * (hereinafter, "Software") is an Unsupported proprietary work of
10258 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
10259 + * between Synopsys and you.
10260 + *
10261 + * The Software IS NOT an item of Licensed Software or Licensed Product
10262 + * under any End User Software License Agreement or Agreement for
10263 + * Licensed Product with Synopsys or any supplement thereto. You are
10264 + * permitted to use and redistribute this Software in source and binary
10265 + * forms, with or without modification, provided that redistributions
10266 + * of source code must retain this notice. You may not view, use,
10267 + * disclose, copy or distribute this file or any information contained
10268 + * herein except pursuant to this license grant from Synopsys. If you
10269 + * do not agree with this notice, including the disclaimer below, then
10270 + * you are not authorized to use the Software.
10271 + *
10272 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
10273 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10274 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
10275 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
10276 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
10277 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
10278 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
10279 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
10280 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10281 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
10282 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
10283 + * DAMAGE.
10284 + * ========================================================================= */
10285 +#ifndef _DWC_DH_H_
10286 +#define _DWC_DH_H_
10287 +
10288 +#ifdef __cplusplus
10289 +extern "C" {
10290 +#endif
10291 +
10292 +#include "dwc_os.h"
10293 +
10294 +/** @file
10295 + *
10296 + * This file defines the common functions on device and host for performing
10297 + * numeric association as defined in the WUSB spec. They are only to be
10298 + * used internally by the DWC UWB modules. */
10299 +
10300 +extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
10301 +extern int dwc_dh_hmac_sha256(uint8_t *message, uint32_t messagelen,
10302 + uint8_t *key, uint32_t keylen,
10303 + uint8_t *out);
10304 +extern int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
10305 + void *exp, uint32_t exp_len,
10306 + void *mod, uint32_t mod_len,
10307 + void *out);
10308 +
10309 +/** Computes PKD or PKH, and SHA-256(PKd || Nd)
10310 + *
10311 + * PK = g^exp mod p.
10312 + *
10313 + * Input:
10314 + * Nd = Number of digits on the device.
10315 + *
10316 + * Output:
10317 + * exp = A 32-byte buffer to be filled with a randomly generated number.
10318 + * used as either A or B.
10319 + * pk = A 384-byte buffer to be filled with the PKH or PKD.
10320 + * hash = A 32-byte buffer to be filled with SHA-256(PK || ND).
10321 + */
10322 +extern int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash);
10323 +
10324 +/** Computes the DHKEY, and VD.
10325 + *
10326 + * If called from host, then it will comput DHKEY=PKD^exp % p.
10327 + * If called from device, then it will comput DHKEY=PKH^exp % p.
10328 + *
10329 + * Input:
10330 + * pkd = The PKD value.
10331 + * pkh = The PKH value.
10332 + * exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk.
10333 + * is_host = Set to non zero if a WUSB host is calling this function.
10334 + *
10335 + * Output:
10336 +
10337 + * dd = A pointer to an buffer to be set to the displayed digits string to be shown
10338 + * to the user. This buffer should be at 5 bytes long to hold 4 digits plus a
10339 + * null termination character. This buffer can be used directly for display.
10340 + * ck = A 16-byte buffer to be filled with the CK.
10341 + * kdk = A 32-byte buffer to be filled with the KDK.
10342 + */
10343 +extern int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
10344 + uint8_t *exp, int is_host,
10345 + char *dd, uint8_t *ck, uint8_t *kdk);
10346 +
10347 +#ifdef DH_TEST_VECTORS
10348 +extern void dwc_run_dh_test_vectors(void);
10349 +#endif
10350 +
10351 +#ifdef __cplusplus
10352 +}
10353 +#endif
10354 +
10355 +#endif /* _DWC_DH_H_ */
10356 --- /dev/null
10357 +++ b/drivers/usb/host/dwc_common_port/dwc_list.h
10358 @@ -0,0 +1,594 @@
10359 +/* $OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $ */
10360 +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
10361 +
10362 +/*
10363 + * Copyright (c) 1991, 1993
10364 + * The Regents of the University of California. All rights reserved.
10365 + *
10366 + * Redistribution and use in source and binary forms, with or without
10367 + * modification, are permitted provided that the following conditions
10368 + * are met:
10369 + * 1. Redistributions of source code must retain the above copyright
10370 + * notice, this list of conditions and the following disclaimer.
10371 + * 2. Redistributions in binary form must reproduce the above copyright
10372 + * notice, this list of conditions and the following disclaimer in the
10373 + * documentation and/or other materials provided with the distribution.
10374 + * 3. Neither the name of the University nor the names of its contributors
10375 + * may be used to endorse or promote products derived from this software
10376 + * without specific prior written permission.
10377 + *
10378 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
10379 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10380 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10381 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
10382 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10383 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10384 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10385 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10386 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10387 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10388 + * SUCH DAMAGE.
10389 + *
10390 + * @(#)queue.h 8.5 (Berkeley) 8/20/94
10391 + */
10392 +
10393 +#ifndef _DWC_LIST_H_
10394 +#define _DWC_LIST_H_
10395 +
10396 +#ifdef __cplusplus
10397 +extern "C" {
10398 +#endif
10399 +
10400 +/** @file
10401 + *
10402 + * This file defines linked list operations. It is derived from BSD with
10403 + * only the MACRO names being prefixed with DWC_. This is because a few of
10404 + * these names conflict with those on Linux. For documentation on use, see the
10405 + * inline comments in the source code. The original license for this source
10406 + * code applies and is preserved in the dwc_list.h source file.
10407 + */
10408 +
10409 +/*
10410 + * This file defines five types of data structures: singly-linked lists,
10411 + * lists, simple queues, tail queues, and circular queues.
10412 + *
10413 + *
10414 + * A singly-linked list is headed by a single forward pointer. The elements
10415 + * are singly linked for minimum space and pointer manipulation overhead at
10416 + * the expense of O(n) removal for arbitrary elements. New elements can be
10417 + * added to the list after an existing element or at the head of the list.
10418 + * Elements being removed from the head of the list should use the explicit
10419 + * macro for this purpose for optimum efficiency. A singly-linked list may
10420 + * only be traversed in the forward direction. Singly-linked lists are ideal
10421 + * for applications with large datasets and few or no removals or for
10422 + * implementing a LIFO queue.
10423 + *
10424 + * A list is headed by a single forward pointer (or an array of forward
10425 + * pointers for a hash table header). The elements are doubly linked
10426 + * so that an arbitrary element can be removed without a need to
10427 + * traverse the list. New elements can be added to the list before
10428 + * or after an existing element or at the head of the list. A list
10429 + * may only be traversed in the forward direction.
10430 + *
10431 + * A simple queue is headed by a pair of pointers, one the head of the
10432 + * list and the other to the tail of the list. The elements are singly
10433 + * linked to save space, so elements can only be removed from the
10434 + * head of the list. New elements can be added to the list before or after
10435 + * an existing element, at the head of the list, or at the end of the
10436 + * list. A simple queue may only be traversed in the forward direction.
10437 + *
10438 + * A tail queue is headed by a pair of pointers, one to the head of the
10439 + * list and the other to the tail of the list. The elements are doubly
10440 + * linked so that an arbitrary element can be removed without a need to
10441 + * traverse the list. New elements can be added to the list before or
10442 + * after an existing element, at the head of the list, or at the end of
10443 + * the list. A tail queue may be traversed in either direction.
10444 + *
10445 + * A circle queue is headed by a pair of pointers, one to the head of the
10446 + * list and the other to the tail of the list. The elements are doubly
10447 + * linked so that an arbitrary element can be removed without a need to
10448 + * traverse the list. New elements can be added to the list before or after
10449 + * an existing element, at the head of the list, or at the end of the list.
10450 + * A circle queue may be traversed in either direction, but has a more
10451 + * complex end of list detection.
10452 + *
10453 + * For details on the use of these macros, see the queue(3) manual page.
10454 + */
10455 +
10456 +/*
10457 + * Double-linked List.
10458 + */
10459 +
10460 +typedef struct dwc_list_link {
10461 + struct dwc_list_link *next;
10462 + struct dwc_list_link *prev;
10463 +} dwc_list_link_t;
10464 +
10465 +#define DWC_LIST_INIT(link) do { \
10466 + (link)->next = (link); \
10467 + (link)->prev = (link); \
10468 +} while (0)
10469 +
10470 +#define DWC_LIST_FIRST(link) ((link)->next)
10471 +#define DWC_LIST_LAST(link) ((link)->prev)
10472 +#define DWC_LIST_END(link) (link)
10473 +#define DWC_LIST_NEXT(link) ((link)->next)
10474 +#define DWC_LIST_PREV(link) ((link)->prev)
10475 +#define DWC_LIST_EMPTY(link) \
10476 + (DWC_LIST_FIRST(link) == DWC_LIST_END(link))
10477 +#define DWC_LIST_ENTRY(link, type, field) \
10478 + (type *)((uint8_t *)(link) - (size_t)(&((type *)0)->field))
10479 +
10480 +#if 0
10481 +#define DWC_LIST_INSERT_HEAD(list, link) do { \
10482 + (link)->next = (list)->next; \
10483 + (link)->prev = (list); \
10484 + (list)->next->prev = (link); \
10485 + (list)->next = (link); \
10486 +} while (0)
10487 +
10488 +#define DWC_LIST_INSERT_TAIL(list, link) do { \
10489 + (link)->next = (list); \
10490 + (link)->prev = (list)->prev; \
10491 + (list)->prev->next = (link); \
10492 + (list)->prev = (link); \
10493 +} while (0)
10494 +#else
10495 +#define DWC_LIST_INSERT_HEAD(list, link) do { \
10496 + dwc_list_link_t *__next__ = (list)->next; \
10497 + __next__->prev = (link); \
10498 + (link)->next = __next__; \
10499 + (link)->prev = (list); \
10500 + (list)->next = (link); \
10501 +} while (0)
10502 +
10503 +#define DWC_LIST_INSERT_TAIL(list, link) do { \
10504 + dwc_list_link_t *__prev__ = (list)->prev; \
10505 + (list)->prev = (link); \
10506 + (link)->next = (list); \
10507 + (link)->prev = __prev__; \
10508 + __prev__->next = (link); \
10509 +} while (0)
10510 +#endif
10511 +
10512 +#if 0
10513 +static inline void __list_add(struct list_head *new,
10514 + struct list_head *prev,
10515 + struct list_head *next)
10516 +{
10517 + next->prev = new;
10518 + new->next = next;
10519 + new->prev = prev;
10520 + prev->next = new;
10521 +}
10522 +
10523 +static inline void list_add(struct list_head *new, struct list_head *head)
10524 +{
10525 + __list_add(new, head, head->next);
10526 +}
10527 +
10528 +static inline void list_add_tail(struct list_head *new, struct list_head *head)
10529 +{
10530 + __list_add(new, head->prev, head);
10531 +}
10532 +
10533 +static inline void __list_del(struct list_head * prev, struct list_head * next)
10534 +{
10535 + next->prev = prev;
10536 + prev->next = next;
10537 +}
10538 +
10539 +static inline void list_del(struct list_head *entry)
10540 +{
10541 + __list_del(entry->prev, entry->next);
10542 + entry->next = LIST_POISON1;
10543 + entry->prev = LIST_POISON2;
10544 +}
10545 +#endif
10546 +
10547 +#define DWC_LIST_REMOVE(link) do { \
10548 + (link)->next->prev = (link)->prev; \
10549 + (link)->prev->next = (link)->next; \
10550 +} while (0)
10551 +
10552 +#define DWC_LIST_REMOVE_INIT(link) do { \
10553 + DWC_LIST_REMOVE(link); \
10554 + DWC_LIST_INIT(link); \
10555 +} while (0)
10556 +
10557 +#define DWC_LIST_MOVE_HEAD(list, link) do { \
10558 + DWC_LIST_REMOVE(link); \
10559 + DWC_LIST_INSERT_HEAD(list, link); \
10560 +} while (0)
10561 +
10562 +#define DWC_LIST_MOVE_TAIL(list, link) do { \
10563 + DWC_LIST_REMOVE(link); \
10564 + DWC_LIST_INSERT_TAIL(list, link); \
10565 +} while (0)
10566 +
10567 +#define DWC_LIST_FOREACH(var, list) \
10568 + for((var) = DWC_LIST_FIRST(list); \
10569 + (var) != DWC_LIST_END(list); \
10570 + (var) = DWC_LIST_NEXT(var))
10571 +
10572 +#define DWC_LIST_FOREACH_SAFE(var, var2, list) \
10573 + for((var) = DWC_LIST_FIRST(list), (var2) = DWC_LIST_NEXT(var); \
10574 + (var) != DWC_LIST_END(list); \
10575 + (var) = (var2), (var2) = DWC_LIST_NEXT(var2))
10576 +
10577 +#define DWC_LIST_FOREACH_REVERSE(var, list) \
10578 + for((var) = DWC_LIST_LAST(list); \
10579 + (var) != DWC_LIST_END(list); \
10580 + (var) = DWC_LIST_PREV(var))
10581 +
10582 +/*
10583 + * Singly-linked List definitions.
10584 + */
10585 +#define DWC_SLIST_HEAD(name, type) \
10586 +struct name { \
10587 + struct type *slh_first; /* first element */ \
10588 +}
10589 +
10590 +#define DWC_SLIST_HEAD_INITIALIZER(head) \
10591 + { NULL }
10592 +
10593 +#define DWC_SLIST_ENTRY(type) \
10594 +struct { \
10595 + struct type *sle_next; /* next element */ \
10596 +}
10597 +
10598 +/*
10599 + * Singly-linked List access methods.
10600 + */
10601 +#define DWC_SLIST_FIRST(head) ((head)->slh_first)
10602 +#define DWC_SLIST_END(head) NULL
10603 +#define DWC_SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
10604 +#define DWC_SLIST_NEXT(elm, field) ((elm)->field.sle_next)
10605 +
10606 +#define DWC_SLIST_FOREACH(var, head, field) \
10607 + for((var) = SLIST_FIRST(head); \
10608 + (var) != SLIST_END(head); \
10609 + (var) = SLIST_NEXT(var, field))
10610 +
10611 +#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field) \
10612 + for((varp) = &SLIST_FIRST((head)); \
10613 + ((var) = *(varp)) != SLIST_END(head); \
10614 + (varp) = &SLIST_NEXT((var), field))
10615 +
10616 +/*
10617 + * Singly-linked List functions.
10618 + */
10619 +#define DWC_SLIST_INIT(head) { \
10620 + SLIST_FIRST(head) = SLIST_END(head); \
10621 +}
10622 +
10623 +#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do { \
10624 + (elm)->field.sle_next = (slistelm)->field.sle_next; \
10625 + (slistelm)->field.sle_next = (elm); \
10626 +} while (0)
10627 +
10628 +#define DWC_SLIST_INSERT_HEAD(head, elm, field) do { \
10629 + (elm)->field.sle_next = (head)->slh_first; \
10630 + (head)->slh_first = (elm); \
10631 +} while (0)
10632 +
10633 +#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do { \
10634 + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
10635 +} while (0)
10636 +
10637 +#define DWC_SLIST_REMOVE_HEAD(head, field) do { \
10638 + (head)->slh_first = (head)->slh_first->field.sle_next; \
10639 +} while (0)
10640 +
10641 +#define DWC_SLIST_REMOVE(head, elm, type, field) do { \
10642 + if ((head)->slh_first == (elm)) { \
10643 + SLIST_REMOVE_HEAD((head), field); \
10644 + } \
10645 + else { \
10646 + struct type *curelm = (head)->slh_first; \
10647 + while( curelm->field.sle_next != (elm) ) \
10648 + curelm = curelm->field.sle_next; \
10649 + curelm->field.sle_next = \
10650 + curelm->field.sle_next->field.sle_next; \
10651 + } \
10652 +} while (0)
10653 +
10654 +/*
10655 + * Simple queue definitions.
10656 + */
10657 +#define DWC_SIMPLEQ_HEAD(name, type) \
10658 +struct name { \
10659 + struct type *sqh_first; /* first element */ \
10660 + struct type **sqh_last; /* addr of last next element */ \
10661 +}
10662 +
10663 +#define DWC_SIMPLEQ_HEAD_INITIALIZER(head) \
10664 + { NULL, &(head).sqh_first }
10665 +
10666 +#define DWC_SIMPLEQ_ENTRY(type) \
10667 +struct { \
10668 + struct type *sqe_next; /* next element */ \
10669 +}
10670 +
10671 +/*
10672 + * Simple queue access methods.
10673 + */
10674 +#define DWC_SIMPLEQ_FIRST(head) ((head)->sqh_first)
10675 +#define DWC_SIMPLEQ_END(head) NULL
10676 +#define DWC_SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
10677 +#define DWC_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
10678 +
10679 +#define DWC_SIMPLEQ_FOREACH(var, head, field) \
10680 + for((var) = SIMPLEQ_FIRST(head); \
10681 + (var) != SIMPLEQ_END(head); \
10682 + (var) = SIMPLEQ_NEXT(var, field))
10683 +
10684 +/*
10685 + * Simple queue functions.
10686 + */
10687 +#define DWC_SIMPLEQ_INIT(head) do { \
10688 + (head)->sqh_first = NULL; \
10689 + (head)->sqh_last = &(head)->sqh_first; \
10690 +} while (0)
10691 +
10692 +#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
10693 + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
10694 + (head)->sqh_last = &(elm)->field.sqe_next; \
10695 + (head)->sqh_first = (elm); \
10696 +} while (0)
10697 +
10698 +#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
10699 + (elm)->field.sqe_next = NULL; \
10700 + *(head)->sqh_last = (elm); \
10701 + (head)->sqh_last = &(elm)->field.sqe_next; \
10702 +} while (0)
10703 +
10704 +#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
10705 + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
10706 + (head)->sqh_last = &(elm)->field.sqe_next; \
10707 + (listelm)->field.sqe_next = (elm); \
10708 +} while (0)
10709 +
10710 +#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do { \
10711 + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
10712 + (head)->sqh_last = &(head)->sqh_first; \
10713 +} while (0)
10714 +
10715 +/*
10716 + * Tail queue definitions.
10717 + */
10718 +#define DWC_TAILQ_HEAD(name, type) \
10719 +struct name { \
10720 + struct type *tqh_first; /* first element */ \
10721 + struct type **tqh_last; /* addr of last next element */ \
10722 +}
10723 +
10724 +#define DWC_TAILQ_HEAD_INITIALIZER(head) \
10725 + { NULL, &(head).tqh_first }
10726 +
10727 +#define DWC_TAILQ_ENTRY(type) \
10728 +struct { \
10729 + struct type *tqe_next; /* next element */ \
10730 + struct type **tqe_prev; /* address of previous next element */ \
10731 +}
10732 +
10733 +/*
10734 + * tail queue access methods
10735 + */
10736 +#define DWC_TAILQ_FIRST(head) ((head)->tqh_first)
10737 +#define DWC_TAILQ_END(head) NULL
10738 +#define DWC_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
10739 +#define DWC_TAILQ_LAST(head, headname) \
10740 + (*(((struct headname *)((head)->tqh_last))->tqh_last))
10741 +/* XXX */
10742 +#define DWC_TAILQ_PREV(elm, headname, field) \
10743 + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
10744 +#define DWC_TAILQ_EMPTY(head) \
10745 + (TAILQ_FIRST(head) == TAILQ_END(head))
10746 +
10747 +#define DWC_TAILQ_FOREACH(var, head, field) \
10748 + for((var) = TAILQ_FIRST(head); \
10749 + (var) != TAILQ_END(head); \
10750 + (var) = TAILQ_NEXT(var, field))
10751 +
10752 +#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
10753 + for((var) = TAILQ_LAST(head, headname); \
10754 + (var) != TAILQ_END(head); \
10755 + (var) = TAILQ_PREV(var, headname, field))
10756 +
10757 +/*
10758 + * Tail queue functions.
10759 + */
10760 +#define DWC_TAILQ_INIT(head) do { \
10761 + (head)->tqh_first = NULL; \
10762 + (head)->tqh_last = &(head)->tqh_first; \
10763 +} while (0)
10764 +
10765 +#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do { \
10766 + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
10767 + (head)->tqh_first->field.tqe_prev = \
10768 + &(elm)->field.tqe_next; \
10769 + else \
10770 + (head)->tqh_last = &(elm)->field.tqe_next; \
10771 + (head)->tqh_first = (elm); \
10772 + (elm)->field.tqe_prev = &(head)->tqh_first; \
10773 +} while (0)
10774 +
10775 +#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do { \
10776 + (elm)->field.tqe_next = NULL; \
10777 + (elm)->field.tqe_prev = (head)->tqh_last; \
10778 + *(head)->tqh_last = (elm); \
10779 + (head)->tqh_last = &(elm)->field.tqe_next; \
10780 +} while (0)
10781 +
10782 +#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
10783 + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
10784 + (elm)->field.tqe_next->field.tqe_prev = \
10785 + &(elm)->field.tqe_next; \
10786 + else \
10787 + (head)->tqh_last = &(elm)->field.tqe_next; \
10788 + (listelm)->field.tqe_next = (elm); \
10789 + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
10790 +} while (0)
10791 +
10792 +#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
10793 + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
10794 + (elm)->field.tqe_next = (listelm); \
10795 + *(listelm)->field.tqe_prev = (elm); \
10796 + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
10797 +} while (0)
10798 +
10799 +#define DWC_TAILQ_REMOVE(head, elm, field) do { \
10800 + if (((elm)->field.tqe_next) != NULL) \
10801 + (elm)->field.tqe_next->field.tqe_prev = \
10802 + (elm)->field.tqe_prev; \
10803 + else \
10804 + (head)->tqh_last = (elm)->field.tqe_prev; \
10805 + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
10806 +} while (0)
10807 +
10808 +#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do { \
10809 + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
10810 + (elm2)->field.tqe_next->field.tqe_prev = \
10811 + &(elm2)->field.tqe_next; \
10812 + else \
10813 + (head)->tqh_last = &(elm2)->field.tqe_next; \
10814 + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
10815 + *(elm2)->field.tqe_prev = (elm2); \
10816 +} while (0)
10817 +
10818 +/*
10819 + * Circular queue definitions.
10820 + */
10821 +#define DWC_CIRCLEQ_HEAD(name, type) \
10822 +struct name { \
10823 + struct type *cqh_first; /* first element */ \
10824 + struct type *cqh_last; /* last element */ \
10825 +}
10826 +
10827 +#define DWC_CIRCLEQ_HEAD_INITIALIZER(head) \
10828 + { DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
10829 +
10830 +#define DWC_CIRCLEQ_ENTRY(type) \
10831 +struct { \
10832 + struct type *cqe_next; /* next element */ \
10833 + struct type *cqe_prev; /* previous element */ \
10834 +}
10835 +
10836 +/*
10837 + * Circular queue access methods
10838 + */
10839 +#define DWC_CIRCLEQ_FIRST(head) ((head)->cqh_first)
10840 +#define DWC_CIRCLEQ_LAST(head) ((head)->cqh_last)
10841 +#define DWC_CIRCLEQ_END(head) ((void *)(head))
10842 +#define DWC_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
10843 +#define DWC_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
10844 +#define DWC_CIRCLEQ_EMPTY(head) \
10845 + (DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
10846 +
10847 +#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
10848 +
10849 +#define DWC_CIRCLEQ_FOREACH(var, head, field) \
10850 + for((var) = DWC_CIRCLEQ_FIRST(head); \
10851 + (var) != DWC_CIRCLEQ_END(head); \
10852 + (var) = DWC_CIRCLEQ_NEXT(var, field))
10853 +
10854 +#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field) \
10855 + for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
10856 + (var) != DWC_CIRCLEQ_END(head); \
10857 + (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
10858 +
10859 +#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field) \
10860 + for((var) = DWC_CIRCLEQ_LAST(head); \
10861 + (var) != DWC_CIRCLEQ_END(head); \
10862 + (var) = DWC_CIRCLEQ_PREV(var, field))
10863 +
10864 +/*
10865 + * Circular queue functions.
10866 + */
10867 +#define DWC_CIRCLEQ_INIT(head) do { \
10868 + (head)->cqh_first = DWC_CIRCLEQ_END(head); \
10869 + (head)->cqh_last = DWC_CIRCLEQ_END(head); \
10870 +} while (0)
10871 +
10872 +#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do { \
10873 + (elm)->field.cqe_next = NULL; \
10874 + (elm)->field.cqe_prev = NULL; \
10875 +} while (0)
10876 +
10877 +#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
10878 + (elm)->field.cqe_next = (listelm)->field.cqe_next; \
10879 + (elm)->field.cqe_prev = (listelm); \
10880 + if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
10881 + (head)->cqh_last = (elm); \
10882 + else \
10883 + (listelm)->field.cqe_next->field.cqe_prev = (elm); \
10884 + (listelm)->field.cqe_next = (elm); \
10885 +} while (0)
10886 +
10887 +#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
10888 + (elm)->field.cqe_next = (listelm); \
10889 + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
10890 + if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
10891 + (head)->cqh_first = (elm); \
10892 + else \
10893 + (listelm)->field.cqe_prev->field.cqe_next = (elm); \
10894 + (listelm)->field.cqe_prev = (elm); \
10895 +} while (0)
10896 +
10897 +#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
10898 + (elm)->field.cqe_next = (head)->cqh_first; \
10899 + (elm)->field.cqe_prev = DWC_CIRCLEQ_END(head); \
10900 + if ((head)->cqh_last == DWC_CIRCLEQ_END(head)) \
10901 + (head)->cqh_last = (elm); \
10902 + else \
10903 + (head)->cqh_first->field.cqe_prev = (elm); \
10904 + (head)->cqh_first = (elm); \
10905 +} while (0)
10906 +
10907 +#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
10908 + (elm)->field.cqe_next = DWC_CIRCLEQ_END(head); \
10909 + (elm)->field.cqe_prev = (head)->cqh_last; \
10910 + if ((head)->cqh_first == DWC_CIRCLEQ_END(head)) \
10911 + (head)->cqh_first = (elm); \
10912 + else \
10913 + (head)->cqh_last->field.cqe_next = (elm); \
10914 + (head)->cqh_last = (elm); \
10915 +} while (0)
10916 +
10917 +#define DWC_CIRCLEQ_REMOVE(head, elm, field) do { \
10918 + if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
10919 + (head)->cqh_last = (elm)->field.cqe_prev; \
10920 + else \
10921 + (elm)->field.cqe_next->field.cqe_prev = \
10922 + (elm)->field.cqe_prev; \
10923 + if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
10924 + (head)->cqh_first = (elm)->field.cqe_next; \
10925 + else \
10926 + (elm)->field.cqe_prev->field.cqe_next = \
10927 + (elm)->field.cqe_next; \
10928 +} while (0)
10929 +
10930 +#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do { \
10931 + DWC_CIRCLEQ_REMOVE(head, elm, field); \
10932 + DWC_CIRCLEQ_INIT_ENTRY(elm, field); \
10933 +} while (0)
10934 +
10935 +#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
10936 + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
10937 + DWC_CIRCLEQ_END(head)) \
10938 + (head).cqh_last = (elm2); \
10939 + else \
10940 + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
10941 + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
10942 + DWC_CIRCLEQ_END(head)) \
10943 + (head).cqh_first = (elm2); \
10944 + else \
10945 + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
10946 +} while (0)
10947 +
10948 +#ifdef __cplusplus
10949 +}
10950 +#endif
10951 +
10952 +#endif /* _DWC_LIST_H_ */
10953 --- /dev/null
10954 +++ b/drivers/usb/host/dwc_common_port/dwc_mem.c
10955 @@ -0,0 +1,245 @@
10956 +/* Memory Debugging */
10957 +#ifdef DWC_DEBUG_MEMORY
10958 +
10959 +#include "dwc_os.h"
10960 +#include "dwc_list.h"
10961 +
10962 +struct allocation {
10963 + void *addr;
10964 + void *ctx;
10965 + char *func;
10966 + int line;
10967 + uint32_t size;
10968 + int dma;
10969 + DWC_CIRCLEQ_ENTRY(allocation) entry;
10970 +};
10971 +
10972 +DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
10973 +
10974 +struct allocation_manager {
10975 + void *mem_ctx;
10976 + struct allocation_queue allocations;
10977 +
10978 + /* statistics */
10979 + int num;
10980 + int num_freed;
10981 + int num_active;
10982 + uint32_t total;
10983 + uint32_t cur;
10984 + uint32_t max;
10985 +};
10986 +
10987 +static struct allocation_manager *manager = NULL;
10988 +
10989 +static int add_allocation(void *ctx, uint32_t size, char const *func, int line, void *addr,
10990 + int dma)
10991 +{
10992 + struct allocation *a;
10993 +
10994 + DWC_ASSERT(manager != NULL, "manager not allocated");
10995 +
10996 + a = __DWC_ALLOC_ATOMIC(manager->mem_ctx, sizeof(*a));
10997 + if (!a) {
10998 + return -DWC_E_NO_MEMORY;
10999 + }
11000 +
11001 + a->func = __DWC_ALLOC_ATOMIC(manager->mem_ctx, DWC_STRLEN(func) + 1);
11002 + if (!a->func) {
11003 + __DWC_FREE(manager->mem_ctx, a);
11004 + return -DWC_E_NO_MEMORY;
11005 + }
11006 +
11007 + DWC_MEMCPY(a->func, func, DWC_STRLEN(func) + 1);
11008 + a->addr = addr;
11009 + a->ctx = ctx;
11010 + a->line = line;
11011 + a->size = size;
11012 + a->dma = dma;
11013 + DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
11014 +
11015 + /* Update stats */
11016 + manager->num++;
11017 + manager->num_active++;
11018 + manager->total += size;
11019 + manager->cur += size;
11020 +
11021 + if (manager->max < manager->cur) {
11022 + manager->max = manager->cur;
11023 + }
11024 +
11025 + return 0;
11026 +}
11027 +
11028 +static struct allocation *find_allocation(void *ctx, void *addr)
11029 +{
11030 + struct allocation *a;
11031 +
11032 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
11033 + if (a->ctx == ctx && a->addr == addr) {
11034 + return a;
11035 + }
11036 + }
11037 +
11038 + return NULL;
11039 +}
11040 +
11041 +static void free_allocation(void *ctx, void *addr, char const *func, int line)
11042 +{
11043 + struct allocation *a = find_allocation(ctx, addr);
11044 +
11045 + if (!a) {
11046 + DWC_ASSERT(0,
11047 + "Free of address %p that was never allocated or already freed %s:%d",
11048 + addr, func, line);
11049 + return;
11050 + }
11051 +
11052 + DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
11053 +
11054 + manager->num_active--;
11055 + manager->num_freed++;
11056 + manager->cur -= a->size;
11057 + __DWC_FREE(manager->mem_ctx, a->func);
11058 + __DWC_FREE(manager->mem_ctx, a);
11059 +}
11060 +
11061 +int dwc_memory_debug_start(void *mem_ctx)
11062 +{
11063 + DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
11064 +
11065 + if (manager) {
11066 + return -DWC_E_BUSY;
11067 + }
11068 +
11069 + manager = __DWC_ALLOC(mem_ctx, sizeof(*manager));
11070 + if (!manager) {
11071 + return -DWC_E_NO_MEMORY;
11072 + }
11073 +
11074 + DWC_CIRCLEQ_INIT(&manager->allocations);
11075 + manager->mem_ctx = mem_ctx;
11076 + manager->num = 0;
11077 + manager->num_freed = 0;
11078 + manager->num_active = 0;
11079 + manager->total = 0;
11080 + manager->cur = 0;
11081 + manager->max = 0;
11082 +
11083 + return 0;
11084 +}
11085 +
11086 +void dwc_memory_debug_stop(void)
11087 +{
11088 + struct allocation *a;
11089 +
11090 + dwc_memory_debug_report();
11091 +
11092 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
11093 + DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
11094 + free_allocation(a->ctx, a->addr, NULL, -1);
11095 + }
11096 +
11097 + __DWC_FREE(manager->mem_ctx, manager);
11098 +}
11099 +
11100 +void dwc_memory_debug_report(void)
11101 +{
11102 + struct allocation *a;
11103 +
11104 + DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
11105 + DWC_PRINTF("Num Allocations = %d\n", manager->num);
11106 + DWC_PRINTF("Freed = %d\n", manager->num_freed);
11107 + DWC_PRINTF("Active = %d\n", manager->num_active);
11108 + DWC_PRINTF("Current Memory Used = %d\n", manager->cur);
11109 + DWC_PRINTF("Total Memory Used = %d\n", manager->total);
11110 + DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
11111 + DWC_PRINTF("Unfreed allocations:\n");
11112 +
11113 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
11114 + DWC_PRINTF(" addr=%p, size=%d from %s:%d, DMA=%d\n",
11115 + a->addr, a->size, a->func, a->line, a->dma);
11116 + }
11117 +}
11118 +
11119 +/* The replacement functions */
11120 +void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line)
11121 +{
11122 + void *addr = __DWC_ALLOC(mem_ctx, size);
11123 +
11124 + if (!addr) {
11125 + return NULL;
11126 + }
11127 +
11128 + if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
11129 + __DWC_FREE(mem_ctx, addr);
11130 + return NULL;
11131 + }
11132 +
11133 + return addr;
11134 +}
11135 +
11136 +void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func,
11137 + int line)
11138 +{
11139 + void *addr = __DWC_ALLOC_ATOMIC(mem_ctx, size);
11140 +
11141 + if (!addr) {
11142 + return NULL;
11143 + }
11144 +
11145 + if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
11146 + __DWC_FREE(mem_ctx, addr);
11147 + return NULL;
11148 + }
11149 +
11150 + return addr;
11151 +}
11152 +
11153 +void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line)
11154 +{
11155 + free_allocation(mem_ctx, addr, func, line);
11156 + __DWC_FREE(mem_ctx, addr);
11157 +}
11158 +
11159 +void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
11160 + char const *func, int line)
11161 +{
11162 + void *addr = __DWC_DMA_ALLOC(dma_ctx, size, dma_addr);
11163 +
11164 + if (!addr) {
11165 + return NULL;
11166 + }
11167 +
11168 + if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
11169 + __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
11170 + return NULL;
11171 + }
11172 +
11173 + return addr;
11174 +}
11175 +
11176 +void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size,
11177 + dwc_dma_t *dma_addr, char const *func, int line)
11178 +{
11179 + void *addr = __DWC_DMA_ALLOC_ATOMIC(dma_ctx, size, dma_addr);
11180 +
11181 + if (!addr) {
11182 + return NULL;
11183 + }
11184 +
11185 + if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
11186 + __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
11187 + return NULL;
11188 + }
11189 +
11190 + return addr;
11191 +}
11192 +
11193 +void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
11194 + dwc_dma_t dma_addr, char const *func, int line)
11195 +{
11196 + free_allocation(dma_ctx, virt_addr, func, line);
11197 + __DWC_DMA_FREE(dma_ctx, size, virt_addr, dma_addr);
11198 +}
11199 +
11200 +#endif /* DWC_DEBUG_MEMORY */
11201 --- /dev/null
11202 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.c
11203 @@ -0,0 +1,636 @@
11204 +/* Bignum routines adapted from PUTTY sources. PuTTY copyright notice follows.
11205 + *
11206 + * PuTTY is copyright 1997-2007 Simon Tatham.
11207 + *
11208 + * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
11209 + * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
11210 + * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
11211 + * Kuhn, and CORE SDI S.A.
11212 + *
11213 + * Permission is hereby granted, free of charge, to any person
11214 + * obtaining a copy of this software and associated documentation files
11215 + * (the "Software"), to deal in the Software without restriction,
11216 + * including without limitation the rights to use, copy, modify, merge,
11217 + * publish, distribute, sublicense, and/or sell copies of the Software,
11218 + * and to permit persons to whom the Software is furnished to do so,
11219 + * subject to the following conditions:
11220 + *
11221 + * The above copyright notice and this permission notice shall be
11222 + * included in all copies or substantial portions of the Software.
11223 +
11224 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11225 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11226 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11227 + * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
11228 + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
11229 + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
11230 + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11231 + *
11232 + */
11233 +#ifdef DWC_CRYPTOLIB
11234 +
11235 +#ifndef CONFIG_MACH_IPMATE
11236 +
11237 +#include "dwc_modpow.h"
11238 +
11239 +#define BIGNUM_INT_MASK 0xFFFFFFFFUL
11240 +#define BIGNUM_TOP_BIT 0x80000000UL
11241 +#define BIGNUM_INT_BITS 32
11242 +
11243 +
11244 +static void *snmalloc(void *mem_ctx, size_t n, size_t size)
11245 +{
11246 + void *p;
11247 + size *= n;
11248 + if (size == 0) size = 1;
11249 + p = dwc_alloc(mem_ctx, size);
11250 + return p;
11251 +}
11252 +
11253 +#define snewn(ctx, n, type) ((type *)snmalloc((ctx), (n), sizeof(type)))
11254 +#define sfree dwc_free
11255 +
11256 +/*
11257 + * Usage notes:
11258 + * * Do not call the DIVMOD_WORD macro with expressions such as array
11259 + * subscripts, as some implementations object to this (see below).
11260 + * * Note that none of the division methods below will cope if the
11261 + * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
11262 + * to avoid this case.
11263 + * If this condition occurs, in the case of the x86 DIV instruction,
11264 + * an overflow exception will occur, which (according to a correspondent)
11265 + * will manifest on Windows as something like
11266 + * 0xC0000095: Integer overflow
11267 + * The C variant won't give the right answer, either.
11268 + */
11269 +
11270 +#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
11271 +
11272 +#if defined __GNUC__ && defined __i386__
11273 +#define DIVMOD_WORD(q, r, hi, lo, w) \
11274 + __asm__("div %2" : \
11275 + "=d" (r), "=a" (q) : \
11276 + "r" (w), "d" (hi), "a" (lo))
11277 +#else
11278 +#define DIVMOD_WORD(q, r, hi, lo, w) do { \
11279 + BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
11280 + q = n / w; \
11281 + r = n % w; \
11282 +} while (0)
11283 +#endif
11284 +
11285 +// q = n / w;
11286 +// r = n % w;
11287 +
11288 +#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
11289 +
11290 +#define BIGNUM_INTERNAL
11291 +
11292 +static Bignum newbn(void *mem_ctx, int length)
11293 +{
11294 + Bignum b = snewn(mem_ctx, length + 1, BignumInt);
11295 + //if (!b)
11296 + //abort(); /* FIXME */
11297 + DWC_MEMSET(b, 0, (length + 1) * sizeof(*b));
11298 + b[0] = length;
11299 + return b;
11300 +}
11301 +
11302 +void freebn(void *mem_ctx, Bignum b)
11303 +{
11304 + /*
11305 + * Burn the evidence, just in case.
11306 + */
11307 + DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1));
11308 + sfree(mem_ctx, b);
11309 +}
11310 +
11311 +/*
11312 + * Compute c = a * b.
11313 + * Input is in the first len words of a and b.
11314 + * Result is returned in the first 2*len words of c.
11315 + */
11316 +static void internal_mul(BignumInt *a, BignumInt *b,
11317 + BignumInt *c, int len)
11318 +{
11319 + int i, j;
11320 + BignumDblInt t;
11321 +
11322 + for (j = 0; j < 2 * len; j++)
11323 + c[j] = 0;
11324 +
11325 + for (i = len - 1; i >= 0; i--) {
11326 + t = 0;
11327 + for (j = len - 1; j >= 0; j--) {
11328 + t += MUL_WORD(a[i], (BignumDblInt) b[j]);
11329 + t += (BignumDblInt) c[i + j + 1];
11330 + c[i + j + 1] = (BignumInt) t;
11331 + t = t >> BIGNUM_INT_BITS;
11332 + }
11333 + c[i] = (BignumInt) t;
11334 + }
11335 +}
11336 +
11337 +static void internal_add_shifted(BignumInt *number,
11338 + unsigned n, int shift)
11339 +{
11340 + int word = 1 + (shift / BIGNUM_INT_BITS);
11341 + int bshift = shift % BIGNUM_INT_BITS;
11342 + BignumDblInt addend;
11343 +
11344 + addend = (BignumDblInt)n << bshift;
11345 +
11346 + while (addend) {
11347 + addend += number[word];
11348 + number[word] = (BignumInt) addend & BIGNUM_INT_MASK;
11349 + addend >>= BIGNUM_INT_BITS;
11350 + word++;
11351 + }
11352 +}
11353 +
11354 +/*
11355 + * Compute a = a % m.
11356 + * Input in first alen words of a and first mlen words of m.
11357 + * Output in first alen words of a
11358 + * (of which first alen-mlen words will be zero).
11359 + * The MSW of m MUST have its high bit set.
11360 + * Quotient is accumulated in the `quotient' array, which is a Bignum
11361 + * rather than the internal bigendian format. Quotient parts are shifted
11362 + * left by `qshift' before adding into quot.
11363 + */
11364 +static void internal_mod(BignumInt *a, int alen,
11365 + BignumInt *m, int mlen,
11366 + BignumInt *quot, int qshift)
11367 +{
11368 + BignumInt m0, m1;
11369 + unsigned int h;
11370 + int i, k;
11371 +
11372 + m0 = m[0];
11373 + if (mlen > 1)
11374 + m1 = m[1];
11375 + else
11376 + m1 = 0;
11377 +
11378 + for (i = 0; i <= alen - mlen; i++) {
11379 + BignumDblInt t;
11380 + unsigned int q, r, c, ai1;
11381 +
11382 + if (i == 0) {
11383 + h = 0;
11384 + } else {
11385 + h = a[i - 1];
11386 + a[i - 1] = 0;
11387 + }
11388 +
11389 + if (i == alen - 1)
11390 + ai1 = 0;
11391 + else
11392 + ai1 = a[i + 1];
11393 +
11394 + /* Find q = h:a[i] / m0 */
11395 + if (h >= m0) {
11396 + /*
11397 + * Special case.
11398 + *
11399 + * To illustrate it, suppose a BignumInt is 8 bits, and
11400 + * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then
11401 + * our initial division will be 0xA123 / 0xA1, which
11402 + * will give a quotient of 0x100 and a divide overflow.
11403 + * However, the invariants in this division algorithm
11404 + * are not violated, since the full number A1:23:... is
11405 + * _less_ than the quotient prefix A1:B2:... and so the
11406 + * following correction loop would have sorted it out.
11407 + *
11408 + * In this situation we set q to be the largest
11409 + * quotient we _can_ stomach (0xFF, of course).
11410 + */
11411 + q = BIGNUM_INT_MASK;
11412 + } else {
11413 + /* Macro doesn't want an array subscript expression passed
11414 + * into it (see definition), so use a temporary. */
11415 + BignumInt tmplo = a[i];
11416 + DIVMOD_WORD(q, r, h, tmplo, m0);
11417 +
11418 + /* Refine our estimate of q by looking at
11419 + h:a[i]:a[i+1] / m0:m1 */
11420 + t = MUL_WORD(m1, q);
11421 + if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
11422 + q--;
11423 + t -= m1;
11424 + r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */
11425 + if (r >= (BignumDblInt) m0 &&
11426 + t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
11427 + }
11428 + }
11429 +
11430 + /* Subtract q * m from a[i...] */
11431 + c = 0;
11432 + for (k = mlen - 1; k >= 0; k--) {
11433 + t = MUL_WORD(q, m[k]);
11434 + t += c;
11435 + c = (unsigned)(t >> BIGNUM_INT_BITS);
11436 + if ((BignumInt) t > a[i + k])
11437 + c++;
11438 + a[i + k] -= (BignumInt) t;
11439 + }
11440 +
11441 + /* Add back m in case of borrow */
11442 + if (c != h) {
11443 + t = 0;
11444 + for (k = mlen - 1; k >= 0; k--) {
11445 + t += m[k];
11446 + t += a[i + k];
11447 + a[i + k] = (BignumInt) t;
11448 + t = t >> BIGNUM_INT_BITS;
11449 + }
11450 + q--;
11451 + }
11452 + if (quot)
11453 + internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
11454 + }
11455 +}
11456 +
11457 +/*
11458 + * Compute p % mod.
11459 + * The most significant word of mod MUST be non-zero.
11460 + * We assume that the result array is the same size as the mod array.
11461 + * We optionally write out a quotient if `quotient' is non-NULL.
11462 + * We can avoid writing out the result if `result' is NULL.
11463 + */
11464 +void bigdivmod(void *mem_ctx, Bignum p, Bignum mod, Bignum result, Bignum quotient)
11465 +{
11466 + BignumInt *n, *m;
11467 + int mshift;
11468 + int plen, mlen, i, j;
11469 +
11470 + /* Allocate m of size mlen, copy mod to m */
11471 + /* We use big endian internally */
11472 + mlen = mod[0];
11473 + m = snewn(mem_ctx, mlen, BignumInt);
11474 + //if (!m)
11475 + //abort(); /* FIXME */
11476 + for (j = 0; j < mlen; j++)
11477 + m[j] = mod[mod[0] - j];
11478 +
11479 + /* Shift m left to make msb bit set */
11480 + for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
11481 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
11482 + break;
11483 + if (mshift) {
11484 + for (i = 0; i < mlen - 1; i++)
11485 + m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift));
11486 + m[mlen - 1] = m[mlen - 1] << mshift;
11487 + }
11488 +
11489 + plen = p[0];
11490 + /* Ensure plen > mlen */
11491 + if (plen <= mlen)
11492 + plen = mlen + 1;
11493 +
11494 + /* Allocate n of size plen, copy p to n */
11495 + n = snewn(mem_ctx, plen, BignumInt);
11496 + //if (!n)
11497 + //abort(); /* FIXME */
11498 + for (j = 0; j < plen; j++)
11499 + n[j] = 0;
11500 + for (j = 1; j <= (int)p[0]; j++)
11501 + n[plen - j] = p[j];
11502 +
11503 + /* Main computation */
11504 + internal_mod(n, plen, m, mlen, quotient, mshift);
11505 +
11506 + /* Fixup result in case the modulus was shifted */
11507 + if (mshift) {
11508 + for (i = plen - mlen - 1; i < plen - 1; i++)
11509 + n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift));
11510 + n[plen - 1] = n[plen - 1] << mshift;
11511 + internal_mod(n, plen, m, mlen, quotient, 0);
11512 + for (i = plen - 1; i >= plen - mlen; i--)
11513 + n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift));
11514 + }
11515 +
11516 + /* Copy result to buffer */
11517 + if (result) {
11518 + for (i = 1; i <= (int)result[0]; i++) {
11519 + int j = plen - i;
11520 + result[i] = j >= 0 ? n[j] : 0;
11521 + }
11522 + }
11523 +
11524 + /* Free temporary arrays */
11525 + for (i = 0; i < mlen; i++)
11526 + m[i] = 0;
11527 + sfree(mem_ctx, m);
11528 + for (i = 0; i < plen; i++)
11529 + n[i] = 0;
11530 + sfree(mem_ctx, n);
11531 +}
11532 +
11533 +/*
11534 + * Simple remainder.
11535 + */
11536 +Bignum bigmod(void *mem_ctx, Bignum a, Bignum b)
11537 +{
11538 + Bignum r = newbn(mem_ctx, b[0]);
11539 + bigdivmod(mem_ctx, a, b, r, NULL);
11540 + return r;
11541 +}
11542 +
11543 +/*
11544 + * Compute (base ^ exp) % mod.
11545 + */
11546 +Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod)
11547 +{
11548 + BignumInt *a, *b, *n, *m;
11549 + int mshift;
11550 + int mlen, i, j;
11551 + Bignum base, result;
11552 +
11553 + /*
11554 + * The most significant word of mod needs to be non-zero. It
11555 + * should already be, but let's make sure.
11556 + */
11557 + //assert(mod[mod[0]] != 0);
11558 +
11559 + /*
11560 + * Make sure the base is smaller than the modulus, by reducing
11561 + * it modulo the modulus if not.
11562 + */
11563 + base = bigmod(mem_ctx, base_in, mod);
11564 +
11565 + /* Allocate m of size mlen, copy mod to m */
11566 + /* We use big endian internally */
11567 + mlen = mod[0];
11568 + m = snewn(mem_ctx, mlen, BignumInt);
11569 + //if (!m)
11570 + //abort(); /* FIXME */
11571 + for (j = 0; j < mlen; j++)
11572 + m[j] = mod[mod[0] - j];
11573 +
11574 + /* Shift m left to make msb bit set */
11575 + for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
11576 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
11577 + break;
11578 + if (mshift) {
11579 + for (i = 0; i < mlen - 1; i++)
11580 + m[i] =
11581 + (m[i] << mshift) | (m[i + 1] >>
11582 + (BIGNUM_INT_BITS - mshift));
11583 + m[mlen - 1] = m[mlen - 1] << mshift;
11584 + }
11585 +
11586 + /* Allocate n of size mlen, copy base to n */
11587 + n = snewn(mem_ctx, mlen, BignumInt);
11588 + //if (!n)
11589 + //abort(); /* FIXME */
11590 + i = mlen - base[0];
11591 + for (j = 0; j < i; j++)
11592 + n[j] = 0;
11593 + for (j = 0; j < base[0]; j++)
11594 + n[i + j] = base[base[0] - j];
11595 +
11596 + /* Allocate a and b of size 2*mlen. Set a = 1 */
11597 + a = snewn(mem_ctx, 2 * mlen, BignumInt);
11598 + //if (!a)
11599 + //abort(); /* FIXME */
11600 + b = snewn(mem_ctx, 2 * mlen, BignumInt);
11601 + //if (!b)
11602 + //abort(); /* FIXME */
11603 + for (i = 0; i < 2 * mlen; i++)
11604 + a[i] = 0;
11605 + a[2 * mlen - 1] = 1;
11606 +
11607 + /* Skip leading zero bits of exp. */
11608 + i = 0;
11609 + j = BIGNUM_INT_BITS - 1;
11610 + while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
11611 + j--;
11612 + if (j < 0) {
11613 + i++;
11614 + j = BIGNUM_INT_BITS - 1;
11615 + }
11616 + }
11617 +
11618 + /* Main computation */
11619 + while (i < exp[0]) {
11620 + while (j >= 0) {
11621 + internal_mul(a + mlen, a + mlen, b, mlen);
11622 + internal_mod(b, mlen * 2, m, mlen, NULL, 0);
11623 + if ((exp[exp[0] - i] & (1 << j)) != 0) {
11624 + internal_mul(b + mlen, n, a, mlen);
11625 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
11626 + } else {
11627 + BignumInt *t;
11628 + t = a;
11629 + a = b;
11630 + b = t;
11631 + }
11632 + j--;
11633 + }
11634 + i++;
11635 + j = BIGNUM_INT_BITS - 1;
11636 + }
11637 +
11638 + /* Fixup result in case the modulus was shifted */
11639 + if (mshift) {
11640 + for (i = mlen - 1; i < 2 * mlen - 1; i++)
11641 + a[i] =
11642 + (a[i] << mshift) | (a[i + 1] >>
11643 + (BIGNUM_INT_BITS - mshift));
11644 + a[2 * mlen - 1] = a[2 * mlen - 1] << mshift;
11645 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
11646 + for (i = 2 * mlen - 1; i >= mlen; i--)
11647 + a[i] =
11648 + (a[i] >> mshift) | (a[i - 1] <<
11649 + (BIGNUM_INT_BITS - mshift));
11650 + }
11651 +
11652 + /* Copy result to buffer */
11653 + result = newbn(mem_ctx, mod[0]);
11654 + for (i = 0; i < mlen; i++)
11655 + result[result[0] - i] = a[i + mlen];
11656 + while (result[0] > 1 && result[result[0]] == 0)
11657 + result[0]--;
11658 +
11659 + /* Free temporary arrays */
11660 + for (i = 0; i < 2 * mlen; i++)
11661 + a[i] = 0;
11662 + sfree(mem_ctx, a);
11663 + for (i = 0; i < 2 * mlen; i++)
11664 + b[i] = 0;
11665 + sfree(mem_ctx, b);
11666 + for (i = 0; i < mlen; i++)
11667 + m[i] = 0;
11668 + sfree(mem_ctx, m);
11669 + for (i = 0; i < mlen; i++)
11670 + n[i] = 0;
11671 + sfree(mem_ctx, n);
11672 +
11673 + freebn(mem_ctx, base);
11674 +
11675 + return result;
11676 +}
11677 +
11678 +
11679 +#ifdef UNITTEST
11680 +
11681 +static __u32 dh_p[] = {
11682 + 96,
11683 + 0xFFFFFFFF,
11684 + 0xFFFFFFFF,
11685 + 0xA93AD2CA,
11686 + 0x4B82D120,
11687 + 0xE0FD108E,
11688 + 0x43DB5BFC,
11689 + 0x74E5AB31,
11690 + 0x08E24FA0,
11691 + 0xBAD946E2,
11692 + 0x770988C0,
11693 + 0x7A615D6C,
11694 + 0xBBE11757,
11695 + 0x177B200C,
11696 + 0x521F2B18,
11697 + 0x3EC86A64,
11698 + 0xD8760273,
11699 + 0xD98A0864,
11700 + 0xF12FFA06,
11701 + 0x1AD2EE6B,
11702 + 0xCEE3D226,
11703 + 0x4A25619D,
11704 + 0x1E8C94E0,
11705 + 0xDB0933D7,
11706 + 0xABF5AE8C,
11707 + 0xA6E1E4C7,
11708 + 0xB3970F85,
11709 + 0x5D060C7D,
11710 + 0x8AEA7157,
11711 + 0x58DBEF0A,
11712 + 0xECFB8504,
11713 + 0xDF1CBA64,
11714 + 0xA85521AB,
11715 + 0x04507A33,
11716 + 0xAD33170D,
11717 + 0x8AAAC42D,
11718 + 0x15728E5A,
11719 + 0x98FA0510,
11720 + 0x15D22618,
11721 + 0xEA956AE5,
11722 + 0x3995497C,
11723 + 0x95581718,
11724 + 0xDE2BCBF6,
11725 + 0x6F4C52C9,
11726 + 0xB5C55DF0,
11727 + 0xEC07A28F,
11728 + 0x9B2783A2,
11729 + 0x180E8603,
11730 + 0xE39E772C,
11731 + 0x2E36CE3B,
11732 + 0x32905E46,
11733 + 0xCA18217C,
11734 + 0xF1746C08,
11735 + 0x4ABC9804,
11736 + 0x670C354E,
11737 + 0x7096966D,
11738 + 0x9ED52907,
11739 + 0x208552BB,
11740 + 0x1C62F356,
11741 + 0xDCA3AD96,
11742 + 0x83655D23,
11743 + 0xFD24CF5F,
11744 + 0x69163FA8,
11745 + 0x1C55D39A,
11746 + 0x98DA4836,
11747 + 0xA163BF05,
11748 + 0xC2007CB8,
11749 + 0xECE45B3D,
11750 + 0x49286651,
11751 + 0x7C4B1FE6,
11752 + 0xAE9F2411,
11753 + 0x5A899FA5,
11754 + 0xEE386BFB,
11755 + 0xF406B7ED,
11756 + 0x0BFF5CB6,
11757 + 0xA637ED6B,
11758 + 0xF44C42E9,
11759 + 0x625E7EC6,
11760 + 0xE485B576,
11761 + 0x6D51C245,
11762 + 0x4FE1356D,
11763 + 0xF25F1437,
11764 + 0x302B0A6D,
11765 + 0xCD3A431B,
11766 + 0xEF9519B3,
11767 + 0x8E3404DD,
11768 + 0x514A0879,
11769 + 0x3B139B22,
11770 + 0x020BBEA6,
11771 + 0x8A67CC74,
11772 + 0x29024E08,
11773 + 0x80DC1CD1,
11774 + 0xC4C6628B,
11775 + 0x2168C234,
11776 + 0xC90FDAA2,
11777 + 0xFFFFFFFF,
11778 + 0xFFFFFFFF,
11779 +};
11780 +
11781 +static __u32 dh_a[] = {
11782 + 8,
11783 + 0xdf367516,
11784 + 0x86459caa,
11785 + 0xe2d459a4,
11786 + 0xd910dae0,
11787 + 0x8a8b5e37,
11788 + 0x67ab31c6,
11789 + 0xf0b55ea9,
11790 + 0x440051d6,
11791 +};
11792 +
11793 +static __u32 dh_b[] = {
11794 + 8,
11795 + 0xded92656,
11796 + 0xe07a048a,
11797 + 0x6fa452cd,
11798 + 0x2df89d30,
11799 + 0xc75f1b0f,
11800 + 0x8ce3578f,
11801 + 0x7980a324,
11802 + 0x5daec786,
11803 +};
11804 +
11805 +static __u32 dh_g[] = {
11806 + 1,
11807 + 2,
11808 +};
11809 +
11810 +int main(void)
11811 +{
11812 + int i;
11813 + __u32 *k;
11814 + k = dwc_modpow(NULL, dh_g, dh_a, dh_p);
11815 +
11816 + printf("\n\n");
11817 + for (i=0; i<k[0]; i++) {
11818 + __u32 word32 = k[k[0] - i];
11819 + __u16 l = word32 & 0xffff;
11820 + __u16 m = (word32 & 0xffff0000) >> 16;
11821 + printf("%04x %04x ", m, l);
11822 + if (!((i + 1)%13)) printf("\n");
11823 + }
11824 + printf("\n\n");
11825 +
11826 + if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) {
11827 + printf("PASS\n\n");
11828 + }
11829 + else {
11830 + printf("FAIL\n\n");
11831 + }
11832 +
11833 +}
11834 +
11835 +#endif /* UNITTEST */
11836 +
11837 +#endif /* CONFIG_MACH_IPMATE */
11838 +
11839 +#endif /*DWC_CRYPTOLIB */
11840 --- /dev/null
11841 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.h
11842 @@ -0,0 +1,34 @@
11843 +/*
11844 + * dwc_modpow.h
11845 + * See dwc_modpow.c for license and changes
11846 + */
11847 +#ifndef _DWC_MODPOW_H
11848 +#define _DWC_MODPOW_H
11849 +
11850 +#ifdef __cplusplus
11851 +extern "C" {
11852 +#endif
11853 +
11854 +#include "dwc_os.h"
11855 +
11856 +/** @file
11857 + *
11858 + * This file defines the module exponentiation function which is only used
11859 + * internally by the DWC UWB modules for calculation of PKs during numeric
11860 + * association. The routine is taken from the PUTTY, an open source terminal
11861 + * emulator. The PUTTY License is preserved in the dwc_modpow.c file.
11862 + *
11863 + */
11864 +
11865 +typedef uint32_t BignumInt;
11866 +typedef uint64_t BignumDblInt;
11867 +typedef BignumInt *Bignum;
11868 +
11869 +/* Compute modular exponentiaion */
11870 +extern Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod);
11871 +
11872 +#ifdef __cplusplus
11873 +}
11874 +#endif
11875 +
11876 +#endif /* _LINUX_BIGNUM_H */
11877 --- /dev/null
11878 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.c
11879 @@ -0,0 +1,319 @@
11880 +#ifdef DWC_NOTIFYLIB
11881 +
11882 +#include "dwc_notifier.h"
11883 +#include "dwc_list.h"
11884 +
11885 +typedef struct dwc_observer {
11886 + void *observer;
11887 + dwc_notifier_callback_t callback;
11888 + void *data;
11889 + char *notification;
11890 + DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
11891 +} observer_t;
11892 +
11893 +DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
11894 +
11895 +typedef struct dwc_notifier {
11896 + void *mem_ctx;
11897 + void *object;
11898 + struct observer_queue observers;
11899 + DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
11900 +} notifier_t;
11901 +
11902 +DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
11903 +
11904 +typedef struct manager {
11905 + void *mem_ctx;
11906 + void *wkq_ctx;
11907 + dwc_workq_t *wq;
11908 +// dwc_mutex_t *mutex;
11909 + struct notifier_queue notifiers;
11910 +} manager_t;
11911 +
11912 +static manager_t *manager = NULL;
11913 +
11914 +static int create_manager(void *mem_ctx, void *wkq_ctx)
11915 +{
11916 + manager = dwc_alloc(mem_ctx, sizeof(manager_t));
11917 + if (!manager) {
11918 + return -DWC_E_NO_MEMORY;
11919 + }
11920 +
11921 + DWC_CIRCLEQ_INIT(&manager->notifiers);
11922 +
11923 + manager->wq = dwc_workq_alloc(wkq_ctx, "DWC Notification WorkQ");
11924 + if (!manager->wq) {
11925 + return -DWC_E_NO_MEMORY;
11926 + }
11927 +
11928 + return 0;
11929 +}
11930 +
11931 +static void free_manager(void)
11932 +{
11933 + dwc_workq_free(manager->wq);
11934 +
11935 + /* All notifiers must have unregistered themselves before this module
11936 + * can be removed. Hitting this assertion indicates a programmer
11937 + * error. */
11938 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers),
11939 + "Notification manager being freed before all notifiers have been removed");
11940 + dwc_free(manager->mem_ctx, manager);
11941 +}
11942 +
11943 +#ifdef DEBUG
11944 +static void dump_manager(void)
11945 +{
11946 + notifier_t *n;
11947 + observer_t *o;
11948 +
11949 + DWC_ASSERT(manager, "Notification manager not found");
11950 +
11951 + DWC_DEBUG("List of all notifiers and observers:\n");
11952 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
11953 + DWC_DEBUG("Notifier %p has observers:\n", n->object);
11954 + DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
11955 + DWC_DEBUG(" %p watching %s\n", o->observer, o->notification);
11956 + }
11957 + }
11958 +}
11959 +#else
11960 +#define dump_manager(...)
11961 +#endif
11962 +
11963 +static observer_t *alloc_observer(void *mem_ctx, void *observer, char *notification,
11964 + dwc_notifier_callback_t callback, void *data)
11965 +{
11966 + observer_t *new_observer = dwc_alloc(mem_ctx, sizeof(observer_t));
11967 +
11968 + if (!new_observer) {
11969 + return NULL;
11970 + }
11971 +
11972 + DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
11973 + new_observer->observer = observer;
11974 + new_observer->notification = notification;
11975 + new_observer->callback = callback;
11976 + new_observer->data = data;
11977 + return new_observer;
11978 +}
11979 +
11980 +static void free_observer(void *mem_ctx, observer_t *observer)
11981 +{
11982 + dwc_free(mem_ctx, observer);
11983 +}
11984 +
11985 +static notifier_t *alloc_notifier(void *mem_ctx, void *object)
11986 +{
11987 + notifier_t *notifier;
11988 +
11989 + if (!object) {
11990 + return NULL;
11991 + }
11992 +
11993 + notifier = dwc_alloc(mem_ctx, sizeof(notifier_t));
11994 + if (!notifier) {
11995 + return NULL;
11996 + }
11997 +
11998 + DWC_CIRCLEQ_INIT(&notifier->observers);
11999 + DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
12000 +
12001 + notifier->mem_ctx = mem_ctx;
12002 + notifier->object = object;
12003 + return notifier;
12004 +}
12005 +
12006 +static void free_notifier(notifier_t *notifier)
12007 +{
12008 + observer_t *observer;
12009 +
12010 + DWC_CIRCLEQ_FOREACH(observer, &notifier->observers, list_entry) {
12011 + free_observer(notifier->mem_ctx, observer);
12012 + }
12013 +
12014 + dwc_free(notifier->mem_ctx, notifier);
12015 +}
12016 +
12017 +static notifier_t *find_notifier(void *object)
12018 +{
12019 + notifier_t *notifier;
12020 +
12021 + DWC_ASSERT(manager, "Notification manager not found");
12022 +
12023 + if (!object) {
12024 + return NULL;
12025 + }
12026 +
12027 + DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
12028 + if (notifier->object == object) {
12029 + return notifier;
12030 + }
12031 + }
12032 +
12033 + return NULL;
12034 +}
12035 +
12036 +int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx)
12037 +{
12038 + return create_manager(mem_ctx, wkq_ctx);
12039 +}
12040 +
12041 +void dwc_free_notification_manager(void)
12042 +{
12043 + free_manager();
12044 +}
12045 +
12046 +dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object)
12047 +{
12048 + notifier_t *notifier;
12049 +
12050 + DWC_ASSERT(manager, "Notification manager not found");
12051 +
12052 + notifier = find_notifier(object);
12053 + if (notifier) {
12054 + DWC_ERROR("Notifier %p is already registered\n", object);
12055 + return NULL;
12056 + }
12057 +
12058 + notifier = alloc_notifier(mem_ctx, object);
12059 + if (!notifier) {
12060 + return NULL;
12061 + }
12062 +
12063 + DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
12064 +
12065 + DWC_INFO("Notifier %p registered", object);
12066 + dump_manager();
12067 +
12068 + return notifier;
12069 +}
12070 +
12071 +void dwc_unregister_notifier(dwc_notifier_t *notifier)
12072 +{
12073 + DWC_ASSERT(manager, "Notification manager not found");
12074 +
12075 + if (!DWC_CIRCLEQ_EMPTY(&notifier->observers)) {
12076 + observer_t *o;
12077 +
12078 + DWC_ERROR("Notifier %p has active observers when removing\n", notifier->object);
12079 + DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
12080 + DWC_DEBUGC(" %p watching %s\n", o->observer, o->notification);
12081 + }
12082 +
12083 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&notifier->observers),
12084 + "Notifier %p has active observers when removing", notifier);
12085 + }
12086 +
12087 + DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
12088 + free_notifier(notifier);
12089 +
12090 + DWC_INFO("Notifier unregistered");
12091 + dump_manager();
12092 +}
12093 +
12094 +/* Add an observer to observe the notifier for a particular state, event, or notification. */
12095 +int dwc_add_observer(void *observer, void *object, char *notification,
12096 + dwc_notifier_callback_t callback, void *data)
12097 +{
12098 + notifier_t *notifier = find_notifier(object);
12099 + observer_t *new_observer;
12100 +
12101 + if (!notifier) {
12102 + DWC_ERROR("Notifier %p is not found when adding observer\n", object);
12103 + return -DWC_E_INVALID;
12104 + }
12105 +
12106 + new_observer = alloc_observer(notifier->mem_ctx, observer, notification, callback, data);
12107 + if (!new_observer) {
12108 + return -DWC_E_NO_MEMORY;
12109 + }
12110 +
12111 + DWC_CIRCLEQ_INSERT_TAIL(&notifier->observers, new_observer, list_entry);
12112 +
12113 + DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
12114 + observer, object, notification, callback, data);
12115 +
12116 + dump_manager();
12117 + return 0;
12118 +}
12119 +
12120 +int dwc_remove_observer(void *observer)
12121 +{
12122 + notifier_t *n;
12123 +
12124 + DWC_ASSERT(manager, "Notification manager not found");
12125 +
12126 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
12127 + observer_t *o;
12128 + observer_t *o2;
12129 +
12130 + DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
12131 + if (o->observer == observer) {
12132 + DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
12133 + DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
12134 + o->observer, n->object, o->notification);
12135 + free_observer(n->mem_ctx, o);
12136 + }
12137 + }
12138 + }
12139 +
12140 + dump_manager();
12141 + return 0;
12142 +}
12143 +
12144 +typedef struct callback_data {
12145 + void *mem_ctx;
12146 + dwc_notifier_callback_t cb;
12147 + void *observer;
12148 + void *data;
12149 + void *object;
12150 + char *notification;
12151 + void *notification_data;
12152 +} cb_data_t;
12153 +
12154 +static void cb_task(void *data)
12155 +{
12156 + cb_data_t *cb = (cb_data_t *)data;
12157 +
12158 + cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
12159 + dwc_free(cb->mem_ctx, cb);
12160 +}
12161 +
12162 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
12163 +{
12164 + observer_t *o;
12165 +
12166 + DWC_ASSERT(manager, "Notification manager not found");
12167 +
12168 + DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
12169 + int len = DWC_STRLEN(notification);
12170 +
12171 + if (DWC_STRLEN(o->notification) != len) {
12172 + continue;
12173 + }
12174 +
12175 + if (DWC_STRNCMP(o->notification, notification, len) == 0) {
12176 + cb_data_t *cb_data = dwc_alloc(notifier->mem_ctx, sizeof(cb_data_t));
12177 +
12178 + if (!cb_data) {
12179 + DWC_ERROR("Failed to allocate callback data\n");
12180 + return;
12181 + }
12182 +
12183 + cb_data->mem_ctx = notifier->mem_ctx;
12184 + cb_data->cb = o->callback;
12185 + cb_data->observer = o->observer;
12186 + cb_data->data = o->data;
12187 + cb_data->object = notifier->object;
12188 + cb_data->notification = notification;
12189 + cb_data->notification_data = notification_data;
12190 + DWC_DEBUGC("Observer found %p for notification %s\n", o->observer, notification);
12191 + DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
12192 + "Notify callback from %p for Notification %s, to observer %p",
12193 + cb_data->object, notification, cb_data->observer);
12194 + }
12195 + }
12196 +}
12197 +
12198 +#endif /* DWC_NOTIFYLIB */
12199 --- /dev/null
12200 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.h
12201 @@ -0,0 +1,122 @@
12202 +
12203 +#ifndef __DWC_NOTIFIER_H__
12204 +#define __DWC_NOTIFIER_H__
12205 +
12206 +#ifdef __cplusplus
12207 +extern "C" {
12208 +#endif
12209 +
12210 +#include "dwc_os.h"
12211 +
12212 +/** @file
12213 + *
12214 + * A simple implementation of the Observer pattern. Any "module" can
12215 + * register as an observer or notifier. The notion of "module" is abstract and
12216 + * can mean anything used to identify either an observer or notifier. Usually
12217 + * it will be a pointer to a data structure which contains some state, ie an
12218 + * object.
12219 + *
12220 + * Before any notifiers can be added, the global notification manager must be
12221 + * brought up with dwc_alloc_notification_manager().
12222 + * dwc_free_notification_manager() will bring it down and free all resources.
12223 + * These would typically be called upon module load and unload. The
12224 + * notification manager is a single global instance that handles all registered
12225 + * observable modules and observers so this should be done only once.
12226 + *
12227 + * A module can be observable by using Notifications to publicize some general
12228 + * information about it's state or operation. It does not care who listens, or
12229 + * even if anyone listens, or what they do with the information. The observable
12230 + * modules do not need to know any information about it's observers or their
12231 + * interface, or their state or data.
12232 + *
12233 + * Any module can register to emit Notifications. It should publish a list of
12234 + * notifications that it can emit and their behavior, such as when they will get
12235 + * triggered, and what information will be provided to the observer. Then it
12236 + * should register itself as an observable module. See dwc_register_notifier().
12237 + *
12238 + * Any module can observe any observable, registered module, provided it has a
12239 + * handle to the other module and knows what notifications to observe. See
12240 + * dwc_add_observer().
12241 + *
12242 + * A function of type dwc_notifier_callback_t is called whenever a notification
12243 + * is triggered with one or more observers observing it. This function is
12244 + * called in it's own process so it may sleep or block if needed. It is
12245 + * guaranteed to be called sometime after the notification has occurred and will
12246 + * be called once per each time the notification is triggered. It will NOT be
12247 + * called in the same process context used to trigger the notification.
12248 + *
12249 + * @section Limitiations
12250 + *
12251 + * Keep in mind that Notifications that can be triggered in rapid sucession may
12252 + * schedule too many processes too handle. Be aware of this limitation when
12253 + * designing to use notifications, and only add notifications for appropriate
12254 + * observable information.
12255 + *
12256 + * Also Notification callbacks are not synchronous. If you need to synchronize
12257 + * the behavior between module/observer you must use other means. And perhaps
12258 + * that will mean Notifications are not the proper solution.
12259 + */
12260 +
12261 +struct dwc_notifier;
12262 +typedef struct dwc_notifier dwc_notifier_t;
12263 +
12264 +/** The callback function must be of this type.
12265 + *
12266 + * @param object This is the object that is being observed.
12267 + * @param notification This is the notification that was triggered.
12268 + * @param observer This is the observer
12269 + * @param notification_data This is notification-specific data that the notifier
12270 + * has included in this notification. The value of this should be published in
12271 + * the documentation of the observable module with the notifications.
12272 + * @param user_data This is any custom data that the observer provided when
12273 + * adding itself as an observer to the notification. */
12274 +typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer,
12275 + void *notification_data, void *user_data);
12276 +
12277 +/** Brings up the notification manager. */
12278 +extern int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx);
12279 +/** Brings down the notification manager. */
12280 +extern void dwc_free_notification_manager(void);
12281 +
12282 +/** This function registers an observable module. A dwc_notifier_t object is
12283 + * returned to the observable module. This is an opaque object that is used by
12284 + * the observable module to trigger notifications. This object should only be
12285 + * accessible to functions that are authorized to trigger notifications for this
12286 + * module. Observers do not need this object. */
12287 +extern dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object);
12288 +
12289 +/** This function unregisters an observable module. All observers have to be
12290 + * removed prior to unregistration. */
12291 +extern void dwc_unregister_notifier(dwc_notifier_t *notifier);
12292 +
12293 +/** Add a module as an observer to the observable module. The observable module
12294 + * needs to have previously registered with the notification manager.
12295 + *
12296 + * @param observer The observer module
12297 + * @param object The module to observe
12298 + * @param notification The notification to observe
12299 + * @param callback The callback function to call
12300 + * @param user_data Any additional user data to pass into the callback function */
12301 +extern int dwc_add_observer(void *observer, void *object, char *notification,
12302 + dwc_notifier_callback_t callback, void *user_data);
12303 +
12304 +/** Removes the specified observer from all notifications that it is currently
12305 + * observing. */
12306 +extern int dwc_remove_observer(void *observer);
12307 +
12308 +/** This function triggers a Notification. It should be called by the
12309 + * observable module, or any module or library which the observable module
12310 + * allows to trigger notification on it's behalf. Such as the dwc_cc_t.
12311 + *
12312 + * dwc_notify is a non-blocking function. Callbacks are scheduled called in
12313 + * their own process context for each trigger. Callbacks can be blocking.
12314 + * dwc_notify can be called from interrupt context if needed.
12315 + *
12316 + */
12317 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data);
12318 +
12319 +#ifdef __cplusplus
12320 +}
12321 +#endif
12322 +
12323 +#endif /* __DWC_NOTIFIER_H__ */
12324 --- /dev/null
12325 +++ b/drivers/usb/host/dwc_common_port/dwc_os.h
12326 @@ -0,0 +1,1260 @@
12327 +/* =========================================================================
12328 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_os.h $
12329 + * $Revision: #14 $
12330 + * $Date: 2010/11/04 $
12331 + * $Change: 1621695 $
12332 + *
12333 + * Synopsys Portability Library Software and documentation
12334 + * (hereinafter, "Software") is an Unsupported proprietary work of
12335 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
12336 + * between Synopsys and you.
12337 + *
12338 + * The Software IS NOT an item of Licensed Software or Licensed Product
12339 + * under any End User Software License Agreement or Agreement for
12340 + * Licensed Product with Synopsys or any supplement thereto. You are
12341 + * permitted to use and redistribute this Software in source and binary
12342 + * forms, with or without modification, provided that redistributions
12343 + * of source code must retain this notice. You may not view, use,
12344 + * disclose, copy or distribute this file or any information contained
12345 + * herein except pursuant to this license grant from Synopsys. If you
12346 + * do not agree with this notice, including the disclaimer below, then
12347 + * you are not authorized to use the Software.
12348 + *
12349 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
12350 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
12351 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12352 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
12353 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
12354 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
12355 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
12356 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
12357 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12358 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
12359 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
12360 + * DAMAGE.
12361 + * ========================================================================= */
12362 +#ifndef _DWC_OS_H_
12363 +#define _DWC_OS_H_
12364 +
12365 +#ifdef __cplusplus
12366 +extern "C" {
12367 +#endif
12368 +
12369 +/** @file
12370 + *
12371 + * DWC portability library, low level os-wrapper functions
12372 + *
12373 + */
12374 +
12375 +/* These basic types need to be defined by some OS header file or custom header
12376 + * file for your specific target architecture.
12377 + *
12378 + * uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
12379 + *
12380 + * Any custom or alternate header file must be added and enabled here.
12381 + */
12382 +
12383 +#ifdef DWC_LINUX
12384 +# include <linux/types.h>
12385 +# ifdef CONFIG_DEBUG_MUTEXES
12386 +# include <linux/mutex.h>
12387 +# endif
12388 +# include <linux/errno.h>
12389 +# include <stdarg.h>
12390 +#endif
12391 +
12392 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12393 +# include <os_dep.h>
12394 +#endif
12395 +
12396 +
12397 +/** @name Primitive Types and Values */
12398 +
12399 +/** We define a boolean type for consistency. Can be either YES or NO */
12400 +typedef uint8_t dwc_bool_t;
12401 +#define YES 1
12402 +#define NO 0
12403 +
12404 +#ifdef DWC_LINUX
12405 +
12406 +/** @name Error Codes */
12407 +#define DWC_E_INVALID EINVAL
12408 +#define DWC_E_NO_MEMORY ENOMEM
12409 +#define DWC_E_NO_DEVICE ENODEV
12410 +#define DWC_E_NOT_SUPPORTED EOPNOTSUPP
12411 +#define DWC_E_TIMEOUT ETIMEDOUT
12412 +#define DWC_E_BUSY EBUSY
12413 +#define DWC_E_AGAIN EAGAIN
12414 +#define DWC_E_RESTART ERESTART
12415 +#define DWC_E_ABORT ECONNABORTED
12416 +#define DWC_E_SHUTDOWN ESHUTDOWN
12417 +#define DWC_E_NO_DATA ENODATA
12418 +#define DWC_E_DISCONNECT ECONNRESET
12419 +#define DWC_E_UNKNOWN EINVAL
12420 +#define DWC_E_NO_STREAM_RES ENOSR
12421 +#define DWC_E_COMMUNICATION ECOMM
12422 +#define DWC_E_OVERFLOW EOVERFLOW
12423 +#define DWC_E_PROTOCOL EPROTO
12424 +#define DWC_E_IN_PROGRESS EINPROGRESS
12425 +#define DWC_E_PIPE EPIPE
12426 +#define DWC_E_IO EIO
12427 +#define DWC_E_NO_SPACE ENOSPC
12428 +
12429 +#else
12430 +
12431 +/** @name Error Codes */
12432 +#define DWC_E_INVALID 1001
12433 +#define DWC_E_NO_MEMORY 1002
12434 +#define DWC_E_NO_DEVICE 1003
12435 +#define DWC_E_NOT_SUPPORTED 1004
12436 +#define DWC_E_TIMEOUT 1005
12437 +#define DWC_E_BUSY 1006
12438 +#define DWC_E_AGAIN 1007
12439 +#define DWC_E_RESTART 1008
12440 +#define DWC_E_ABORT 1009
12441 +#define DWC_E_SHUTDOWN 1010
12442 +#define DWC_E_NO_DATA 1011
12443 +#define DWC_E_DISCONNECT 2000
12444 +#define DWC_E_UNKNOWN 3000
12445 +#define DWC_E_NO_STREAM_RES 4001
12446 +#define DWC_E_COMMUNICATION 4002
12447 +#define DWC_E_OVERFLOW 4003
12448 +#define DWC_E_PROTOCOL 4004
12449 +#define DWC_E_IN_PROGRESS 4005
12450 +#define DWC_E_PIPE 4006
12451 +#define DWC_E_IO 4007
12452 +#define DWC_E_NO_SPACE 4008
12453 +
12454 +#endif
12455 +
12456 +
12457 +/** @name Tracing/Logging Functions
12458 + *
12459 + * These function provide the capability to add tracing, debugging, and error
12460 + * messages, as well exceptions as assertions. The WUDEV uses these
12461 + * extensively. These could be logged to the main console, the serial port, an
12462 + * internal buffer, etc. These functions could also be no-op if they are too
12463 + * expensive on your system. By default undefining the DEBUG macro already
12464 + * no-ops some of these functions. */
12465 +
12466 +/** Returns non-zero if in interrupt context. */
12467 +extern dwc_bool_t DWC_IN_IRQ(void);
12468 +#define dwc_in_irq DWC_IN_IRQ
12469 +
12470 +/** Returns "IRQ" if DWC_IN_IRQ is true. */
12471 +static inline char *dwc_irq(void) {
12472 + return DWC_IN_IRQ() ? "IRQ" : "";
12473 +}
12474 +
12475 +/** Returns non-zero if in bottom-half context. */
12476 +extern dwc_bool_t DWC_IN_BH(void);
12477 +#define dwc_in_bh DWC_IN_BH
12478 +
12479 +/** Returns "BH" if DWC_IN_BH is true. */
12480 +static inline char *dwc_bh(void) {
12481 + return DWC_IN_BH() ? "BH" : "";
12482 +}
12483 +
12484 +/**
12485 + * A vprintf() clone. Just call vprintf if you've got it.
12486 + */
12487 +extern void DWC_VPRINTF(char *format, va_list args);
12488 +#define dwc_vprintf DWC_VPRINTF
12489 +
12490 +/**
12491 + * A vsnprintf() clone. Just call vprintf if you've got it.
12492 + */
12493 +extern int DWC_VSNPRINTF(char *str, int size, char *format, va_list args);
12494 +#define dwc_vsnprintf DWC_VSNPRINTF
12495 +
12496 +/**
12497 + * printf() clone. Just call printf if you've go it.
12498 + */
12499 +extern void DWC_PRINTF(char *format, ...)
12500 +/* This provides compiler level static checking of the parameters if you're
12501 + * using GCC. */
12502 +#ifdef __GNUC__
12503 + __attribute__ ((format(printf, 1, 2)));
12504 +#else
12505 + ;
12506 +#endif
12507 +#define dwc_printf DWC_PRINTF
12508 +
12509 +/**
12510 + * sprintf() clone. Just call sprintf if you've got it.
12511 + */
12512 +extern int DWC_SPRINTF(char *string, char *format, ...)
12513 +#ifdef __GNUC__
12514 + __attribute__ ((format(printf, 2, 3)));
12515 +#else
12516 + ;
12517 +#endif
12518 +#define dwc_sprintf DWC_SPRINTF
12519 +
12520 +/**
12521 + * snprintf() clone. Just call snprintf if you've got it.
12522 + */
12523 +extern int DWC_SNPRINTF(char *string, int size, char *format, ...)
12524 +#ifdef __GNUC__
12525 + __attribute__ ((format(printf, 3, 4)));
12526 +#else
12527 + ;
12528 +#endif
12529 +#define dwc_snprintf DWC_SNPRINTF
12530 +
12531 +/**
12532 + * Prints a WARNING message. On systems that don't differentiate between
12533 + * warnings and regular log messages, just print it. Indicates that something
12534 + * may be wrong with the driver. Works like printf().
12535 + *
12536 + * Use the DWC_WARN macro to call this function.
12537 + */
12538 +extern void __DWC_WARN(char *format, ...)
12539 +#ifdef __GNUC__
12540 + __attribute__ ((format(printf, 1, 2)));
12541 +#else
12542 + ;
12543 +#endif
12544 +
12545 +/**
12546 + * Prints an error message. On systems that don't differentiate between errors
12547 + * and regular log messages, just print it. Indicates that something went wrong
12548 + * with the driver. Works like printf().
12549 + *
12550 + * Use the DWC_ERROR macro to call this function.
12551 + */
12552 +extern void __DWC_ERROR(char *format, ...)
12553 +#ifdef __GNUC__
12554 + __attribute__ ((format(printf, 1, 2)));
12555 +#else
12556 + ;
12557 +#endif
12558 +
12559 +/**
12560 + * Prints an exception error message and takes some user-defined action such as
12561 + * print out a backtrace or trigger a breakpoint. Indicates that something went
12562 + * abnormally wrong with the driver such as programmer error, or other
12563 + * exceptional condition. It should not be ignored so even on systems without
12564 + * printing capability, some action should be taken to notify the developer of
12565 + * it. Works like printf().
12566 + */
12567 +extern void DWC_EXCEPTION(char *format, ...)
12568 +#ifdef __GNUC__
12569 + __attribute__ ((format(printf, 1, 2)));
12570 +#else
12571 + ;
12572 +#endif
12573 +#define dwc_exception DWC_EXCEPTION
12574 +
12575 +#ifndef DWC_OTG_DEBUG_LEV
12576 +#define DWC_OTG_DEBUG_LEV 0
12577 +#endif
12578 +
12579 +#ifdef DEBUG
12580 +/**
12581 + * Prints out a debug message. Used for logging/trace messages.
12582 + *
12583 + * Use the DWC_DEBUG macro to call this function
12584 + */
12585 +extern void __DWC_DEBUG(char *format, ...)
12586 +#ifdef __GNUC__
12587 + __attribute__ ((format(printf, 1, 2)));
12588 +#else
12589 + ;
12590 +#endif
12591 +#else
12592 +#define __DWC_DEBUG printk
12593 +#endif
12594 +
12595 +/**
12596 + * Prints out a Debug message.
12597 + */
12598 +#define DWC_DEBUG(_format, _args...) __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", \
12599 + __func__, dwc_irq(), ## _args)
12600 +#define dwc_debug DWC_DEBUG
12601 +/**
12602 + * Prints out a Debug message if enabled at compile time.
12603 + */
12604 +#if DWC_OTG_DEBUG_LEV > 0
12605 +#define DWC_DEBUGC(_format, _args...) DWC_DEBUG(_format, ##_args )
12606 +#else
12607 +#define DWC_DEBUGC(_format, _args...)
12608 +#endif
12609 +#define dwc_debugc DWC_DEBUGC
12610 +/**
12611 + * Prints out an informative message.
12612 + */
12613 +#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", \
12614 + dwc_irq(), ## _args)
12615 +#define dwc_info DWC_INFO
12616 +/**
12617 + * Prints out an informative message if enabled at compile time.
12618 + */
12619 +#if DWC_OTG_DEBUG_LEV > 1
12620 +#define DWC_INFOC(_format, _args...) DWC_INFO(_format, ##_args )
12621 +#else
12622 +#define DWC_INFOC(_format, _args...)
12623 +#endif
12624 +#define dwc_infoc DWC_INFOC
12625 +/**
12626 + * Prints out a warning message.
12627 + */
12628 +#define DWC_WARN(_format, _args...) __DWC_WARN("WARN:%s:%s:%d: " _format "\n", \
12629 + dwc_irq(), __func__, __LINE__, ## _args)
12630 +#define dwc_warn DWC_WARN
12631 +/**
12632 + * Prints out an error message.
12633 + */
12634 +#define DWC_ERROR(_format, _args...) __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", \
12635 + dwc_irq(), __func__, __LINE__, ## _args)
12636 +#define dwc_error DWC_ERROR
12637 +
12638 +#define DWC_PROTO_ERROR(_format, _args...) __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", \
12639 + dwc_irq(), __func__, __LINE__, ## _args)
12640 +#define dwc_proto_error DWC_PROTO_ERROR
12641 +
12642 +#ifdef DEBUG
12643 +/** Prints out a exception error message if the _expr expression fails. Disabled
12644 + * if DEBUG is not enabled. */
12645 +#define DWC_ASSERT(_expr, _format, _args...) do { \
12646 + if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), \
12647 + __FILE__, __LINE__, ## _args); } \
12648 + } while (0)
12649 +#else
12650 +#define DWC_ASSERT(_x...)
12651 +#endif
12652 +#define dwc_assert DWC_ASSERT
12653 +
12654 +
12655 +/** @name Byte Ordering
12656 + * The following functions are for conversions between processor's byte ordering
12657 + * and specific ordering you want.
12658 + */
12659 +
12660 +/** Converts 32 bit data in CPU byte ordering to little endian. */
12661 +extern uint32_t DWC_CPU_TO_LE32(uint32_t *p);
12662 +#define dwc_cpu_to_le32 DWC_CPU_TO_LE32
12663 +
12664 +/** Converts 32 bit data in CPU byte orderint to big endian. */
12665 +extern uint32_t DWC_CPU_TO_BE32(uint32_t *p);
12666 +#define dwc_cpu_to_be32 DWC_CPU_TO_BE32
12667 +
12668 +/** Converts 32 bit little endian data to CPU byte ordering. */
12669 +extern uint32_t DWC_LE32_TO_CPU(uint32_t *p);
12670 +#define dwc_le32_to_cpu DWC_LE32_TO_CPU
12671 +
12672 +/** Converts 32 bit big endian data to CPU byte ordering. */
12673 +extern uint32_t DWC_BE32_TO_CPU(uint32_t *p);
12674 +#define dwc_be32_to_cpu DWC_BE32_TO_CPU
12675 +
12676 +/** Converts 16 bit data in CPU byte ordering to little endian. */
12677 +extern uint16_t DWC_CPU_TO_LE16(uint16_t *p);
12678 +#define dwc_cpu_to_le16 DWC_CPU_TO_LE16
12679 +
12680 +/** Converts 16 bit data in CPU byte orderint to big endian. */
12681 +extern uint16_t DWC_CPU_TO_BE16(uint16_t *p);
12682 +#define dwc_cpu_to_be16 DWC_CPU_TO_BE16
12683 +
12684 +/** Converts 16 bit little endian data to CPU byte ordering. */
12685 +extern uint16_t DWC_LE16_TO_CPU(uint16_t *p);
12686 +#define dwc_le16_to_cpu DWC_LE16_TO_CPU
12687 +
12688 +/** Converts 16 bit bi endian data to CPU byte ordering. */
12689 +extern uint16_t DWC_BE16_TO_CPU(uint16_t *p);
12690 +#define dwc_be16_to_cpu DWC_BE16_TO_CPU
12691 +
12692 +
12693 +/** @name Register Read/Write
12694 + *
12695 + * The following six functions should be implemented to read/write registers of
12696 + * 32-bit and 64-bit sizes. All modules use this to read/write register values.
12697 + * The reg value is a pointer to the register calculated from the void *base
12698 + * variable passed into the driver when it is started. */
12699 +
12700 +#ifdef DWC_LINUX
12701 +/* Linux doesn't need any extra parameters for register read/write, so we
12702 + * just throw away the IO context parameter.
12703 + */
12704 +/** Reads the content of a 32-bit register. */
12705 +extern uint32_t DWC_READ_REG32(uint32_t volatile *reg);
12706 +#define dwc_read_reg32(_ctx_,_reg_) DWC_READ_REG32(_reg_)
12707 +
12708 +/** Reads the content of a 64-bit register. */
12709 +extern uint64_t DWC_READ_REG64(uint64_t volatile *reg);
12710 +#define dwc_read_reg64(_ctx_,_reg_) DWC_READ_REG64(_reg_)
12711 +
12712 +/** Writes to a 32-bit register. */
12713 +extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value);
12714 +#define dwc_write_reg32(_ctx_,_reg_,_val_) DWC_WRITE_REG32(_reg_, _val_)
12715 +
12716 +/** Writes to a 64-bit register. */
12717 +extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value);
12718 +#define dwc_write_reg64(_ctx_,_reg_,_val_) DWC_WRITE_REG64(_reg_, _val_)
12719 +
12720 +/**
12721 + * Modify bit values in a register. Using the
12722 + * algorithm: (reg_contents & ~clear_mask) | set_mask.
12723 + */
12724 +extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
12725 +#define dwc_modify_reg32(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG32(_reg_,_cmsk_,_smsk_)
12726 +extern void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
12727 +#define dwc_modify_reg64(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG64(_reg_,_cmsk_,_smsk_)
12728 +
12729 +#endif /* DWC_LINUX */
12730 +
12731 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12732 +typedef struct dwc_ioctx {
12733 + struct device *dev;
12734 + bus_space_tag_t iot;
12735 + bus_space_handle_t ioh;
12736 +} dwc_ioctx_t;
12737 +
12738 +/** BSD needs two extra parameters for register read/write, so we pass
12739 + * them in using the IO context parameter.
12740 + */
12741 +/** Reads the content of a 32-bit register. */
12742 +extern uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg);
12743 +#define dwc_read_reg32 DWC_READ_REG32
12744 +
12745 +/** Reads the content of a 64-bit register. */
12746 +extern uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg);
12747 +#define dwc_read_reg64 DWC_READ_REG64
12748 +
12749 +/** Writes to a 32-bit register. */
12750 +extern void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value);
12751 +#define dwc_write_reg32 DWC_WRITE_REG32
12752 +
12753 +/** Writes to a 64-bit register. */
12754 +extern void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value);
12755 +#define dwc_write_reg64 DWC_WRITE_REG64
12756 +
12757 +/**
12758 + * Modify bit values in a register. Using the
12759 + * algorithm: (reg_contents & ~clear_mask) | set_mask.
12760 + */
12761 +extern void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
12762 +#define dwc_modify_reg32 DWC_MODIFY_REG32
12763 +extern void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
12764 +#define dwc_modify_reg64 DWC_MODIFY_REG64
12765 +
12766 +#endif /* DWC_FREEBSD || DWC_NETBSD */
12767 +
12768 +/** @cond */
12769 +
12770 +/** @name Some convenience MACROS used internally. Define DWC_DEBUG_REGS to log the
12771 + * register writes. */
12772 +
12773 +#ifdef DWC_LINUX
12774 +
12775 +# ifdef DWC_DEBUG_REGS
12776 +
12777 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12778 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
12779 + return DWC_READ_REG32(&container->regs->_reg[num]); \
12780 +} \
12781 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
12782 + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
12783 + &(((uint32_t*)container->regs->_reg)[num]), data); \
12784 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
12785 +}
12786 +
12787 +#define dwc_define_read_write_reg(_reg,_container_type) \
12788 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
12789 + return DWC_READ_REG32(&container->regs->_reg); \
12790 +} \
12791 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
12792 + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
12793 + DWC_WRITE_REG32(&container->regs->_reg, data); \
12794 +}
12795 +
12796 +# else /* DWC_DEBUG_REGS */
12797 +
12798 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12799 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
12800 + return DWC_READ_REG32(&container->regs->_reg[num]); \
12801 +} \
12802 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
12803 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
12804 +}
12805 +
12806 +#define dwc_define_read_write_reg(_reg,_container_type) \
12807 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
12808 + return DWC_READ_REG32(&container->regs->_reg); \
12809 +} \
12810 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
12811 + DWC_WRITE_REG32(&container->regs->_reg, data); \
12812 +}
12813 +
12814 +# endif /* DWC_DEBUG_REGS */
12815 +
12816 +#endif /* DWC_LINUX */
12817 +
12818 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12819 +
12820 +# ifdef DWC_DEBUG_REGS
12821 +
12822 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12823 +static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
12824 + return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
12825 +} \
12826 +static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
12827 + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
12828 + &(((uint32_t*)container->regs->_reg)[num]), data); \
12829 + DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
12830 +}
12831 +
12832 +#define dwc_define_read_write_reg(_reg,_container_type) \
12833 +static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
12834 + return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
12835 +} \
12836 +static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
12837 + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
12838 + DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
12839 +}
12840 +
12841 +# else /* DWC_DEBUG_REGS */
12842 +
12843 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12844 +static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
12845 + return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
12846 +} \
12847 +static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
12848 + DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
12849 +}
12850 +
12851 +#define dwc_define_read_write_reg(_reg,_container_type) \
12852 +static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
12853 + return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
12854 +} \
12855 +static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
12856 + DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
12857 +}
12858 +
12859 +# endif /* DWC_DEBUG_REGS */
12860 +
12861 +#endif /* DWC_FREEBSD || DWC_NETBSD */
12862 +
12863 +/** @endcond */
12864 +
12865 +
12866 +#ifdef DWC_CRYPTOLIB
12867 +/** @name Crypto Functions
12868 + *
12869 + * These are the low-level cryptographic functions used by the driver. */
12870 +
12871 +/** Perform AES CBC */
12872 +extern int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out);
12873 +#define dwc_aes_cbc DWC_AES_CBC
12874 +
12875 +/** Fill the provided buffer with random bytes. These should be cryptographic grade random numbers. */
12876 +extern void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length);
12877 +#define dwc_random_bytes DWC_RANDOM_BYTES
12878 +
12879 +/** Perform the SHA-256 hash function */
12880 +extern int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out);
12881 +#define dwc_sha256 DWC_SHA256
12882 +
12883 +/** Calculated the HMAC-SHA256 */
12884 +extern int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out);
12885 +#define dwc_hmac_sha256 DWC_HMAC_SHA256
12886 +
12887 +#endif /* DWC_CRYPTOLIB */
12888 +
12889 +
12890 +/** @name Memory Allocation
12891 + *
12892 + * These function provide access to memory allocation. There are only 2 DMA
12893 + * functions and 3 Regular memory functions that need to be implemented. None
12894 + * of the memory debugging routines need to be implemented. The allocation
12895 + * routines all ZERO the contents of the memory.
12896 + *
12897 + * Defining DWC_DEBUG_MEMORY turns on memory debugging and statistic gathering.
12898 + * This checks for memory leaks, keeping track of alloc/free pairs. It also
12899 + * keeps track of how much memory the driver is using at any given time. */
12900 +
12901 +#define DWC_PAGE_SIZE 4096
12902 +#define DWC_PAGE_OFFSET(addr) (((uint32_t)addr) & 0xfff)
12903 +#define DWC_PAGE_ALIGNED(addr) ((((uint32_t)addr) & 0xfff) == 0)
12904 +
12905 +#define DWC_INVALID_DMA_ADDR 0x0
12906 +
12907 +#ifdef DWC_LINUX
12908 +/** Type for a DMA address */
12909 +typedef dma_addr_t dwc_dma_t;
12910 +#endif
12911 +
12912 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12913 +typedef bus_addr_t dwc_dma_t;
12914 +#endif
12915 +
12916 +#ifdef DWC_FREEBSD
12917 +typedef struct dwc_dmactx {
12918 + struct device *dev;
12919 + bus_dma_tag_t dma_tag;
12920 + bus_dmamap_t dma_map;
12921 + bus_addr_t dma_paddr;
12922 + void *dma_vaddr;
12923 +} dwc_dmactx_t;
12924 +#endif
12925 +
12926 +#ifdef DWC_NETBSD
12927 +typedef struct dwc_dmactx {
12928 + struct device *dev;
12929 + bus_dma_tag_t dma_tag;
12930 + bus_dmamap_t dma_map;
12931 + bus_dma_segment_t segs[1];
12932 + int nsegs;
12933 + bus_addr_t dma_paddr;
12934 + void *dma_vaddr;
12935 +} dwc_dmactx_t;
12936 +#endif
12937 +
12938 +/* @todo these functions will be added in the future */
12939 +#if 0
12940 +/**
12941 + * Creates a DMA pool from which you can allocate DMA buffers. Buffers
12942 + * allocated from this pool will be guaranteed to meet the size, alignment, and
12943 + * boundary requirements specified.
12944 + *
12945 + * @param[in] size Specifies the size of the buffers that will be allocated from
12946 + * this pool.
12947 + * @param[in] align Specifies the byte alignment requirements of the buffers
12948 + * allocated from this pool. Must be a power of 2.
12949 + * @param[in] boundary Specifies the N-byte boundary that buffers allocated from
12950 + * this pool must not cross.
12951 + *
12952 + * @returns A pointer to an internal opaque structure which is not to be
12953 + * accessed outside of these library functions. Use this handle to specify
12954 + * which pools to allocate/free DMA buffers from and also to destroy the pool,
12955 + * when you are done with it.
12956 + */
12957 +extern dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t boundary);
12958 +
12959 +/**
12960 + * Destroy a DMA pool. All buffers allocated from that pool must be freed first.
12961 + */
12962 +extern void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool);
12963 +
12964 +/**
12965 + * Allocate a buffer from the specified DMA pool and zeros its contents.
12966 + */
12967 +extern void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr);
12968 +
12969 +/**
12970 + * Free a previously allocated buffer from the DMA pool.
12971 + */
12972 +extern void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr);
12973 +#endif
12974 +
12975 +/** Allocates a DMA capable buffer and zeroes its contents. */
12976 +extern void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
12977 +
12978 +/** Allocates a DMA capable buffer and zeroes its contents in atomic contest */
12979 +extern void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
12980 +
12981 +/** Frees a previously allocated buffer. */
12982 +extern void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr);
12983 +
12984 +/** Allocates a block of memory and zeroes its contents. */
12985 +extern void *__DWC_ALLOC(void *mem_ctx, uint32_t size);
12986 +
12987 +/** Allocates a block of memory and zeroes its contents, in an atomic manner
12988 + * which can be used inside interrupt context. The size should be sufficiently
12989 + * small, a few KB at most, such that failures are not likely to occur. Can just call
12990 + * __DWC_ALLOC if it is atomic. */
12991 +extern void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size);
12992 +
12993 +/** Frees a previously allocated buffer. */
12994 +extern void __DWC_FREE(void *mem_ctx, void *addr);
12995 +
12996 +#ifndef DWC_DEBUG_MEMORY
12997 +
12998 +#define DWC_ALLOC(_size_) __DWC_ALLOC(NULL, _size_)
12999 +#define DWC_ALLOC_ATOMIC(_size_) __DWC_ALLOC_ATOMIC(NULL, _size_)
13000 +#define DWC_FREE(_addr_) __DWC_FREE(NULL, _addr_)
13001 +
13002 +# ifdef DWC_LINUX
13003 +#define DWC_DMA_ALLOC(_size_,_dma_) __DWC_DMA_ALLOC(NULL, _size_, _dma_)
13004 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) __DWC_DMA_ALLOC_ATOMIC(NULL, _size_,_dma_)
13005 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) __DWC_DMA_FREE(NULL, _size_, _virt_, _dma_)
13006 +# endif
13007 +
13008 +# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13009 +#define DWC_DMA_ALLOC __DWC_DMA_ALLOC
13010 +#define DWC_DMA_FREE __DWC_DMA_FREE
13011 +# endif
13012 +extern void *dwc_dma_alloc_atomic_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line);
13013 +
13014 +#else /* DWC_DEBUG_MEMORY */
13015 +
13016 +extern void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line);
13017 +extern void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func, int line);
13018 +extern void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line);
13019 +extern void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
13020 + char const *func, int line);
13021 +extern void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
13022 + char const *func, int line);
13023 +extern void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
13024 + dwc_dma_t dma_addr, char const *func, int line);
13025 +
13026 +extern int dwc_memory_debug_start(void *mem_ctx);
13027 +extern void dwc_memory_debug_stop(void);
13028 +extern void dwc_memory_debug_report(void);
13029 +
13030 +#define DWC_ALLOC(_size_) dwc_alloc_debug(NULL, _size_, __func__, __LINE__)
13031 +#define DWC_ALLOC_ATOMIC(_size_) dwc_alloc_atomic_debug(NULL, _size_, \
13032 + __func__, __LINE__)
13033 +#define DWC_FREE(_addr_) dwc_free_debug(NULL, _addr_, __func__, __LINE__)
13034 +
13035 +# ifdef DWC_LINUX
13036 +#define DWC_DMA_ALLOC(_size_,_dma_) dwc_dma_alloc_debug(NULL, _size_, \
13037 + _dma_, __func__, __LINE__)
13038 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) dwc_dma_alloc_atomic_debug(NULL, _size_, \
13039 + _dma_, __func__, __LINE__)
13040 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) dwc_dma_free_debug(NULL, _size_, \
13041 + _virt_, _dma_, __func__, __LINE__)
13042 +# endif
13043 +
13044 +# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13045 +#define DWC_DMA_ALLOC(_ctx_,_size_,_dma_) dwc_dma_alloc_debug(_ctx_, _size_, \
13046 + _dma_, __func__, __LINE__)
13047 +#define DWC_DMA_FREE(_ctx_,_size_,_virt_,_dma_) dwc_dma_free_debug(_ctx_, _size_, \
13048 + _virt_, _dma_, __func__, __LINE__)
13049 +# endif
13050 +
13051 +#endif /* DWC_DEBUG_MEMORY */
13052 +
13053 +#define dwc_alloc(_ctx_,_size_) DWC_ALLOC(_size_)
13054 +#define dwc_alloc_atomic(_ctx_,_size_) DWC_ALLOC_ATOMIC(_size_)
13055 +#define dwc_free(_ctx_,_addr_) DWC_FREE(_addr_)
13056 +
13057 +#ifdef DWC_LINUX
13058 +/* Linux doesn't need any extra parameters for DMA buffer allocation, so we
13059 + * just throw away the DMA context parameter.
13060 + */
13061 +#define dwc_dma_alloc(_ctx_,_size_,_dma_) DWC_DMA_ALLOC(_size_, _dma_)
13062 +#define dwc_dma_alloc_atomic(_ctx_,_size_,_dma_) DWC_DMA_ALLOC_ATOMIC(_size_, _dma_)
13063 +#define dwc_dma_free(_ctx_,_size_,_virt_,_dma_) DWC_DMA_FREE(_size_, _virt_, _dma_)
13064 +#endif
13065 +
13066 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13067 +/** BSD needs several extra parameters for DMA buffer allocation, so we pass
13068 + * them in using the DMA context parameter.
13069 + */
13070 +#define dwc_dma_alloc DWC_DMA_ALLOC
13071 +#define dwc_dma_free DWC_DMA_FREE
13072 +#endif
13073 +
13074 +
13075 +/** @name Memory and String Processing */
13076 +
13077 +/** memset() clone */
13078 +extern void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size);
13079 +#define dwc_memset DWC_MEMSET
13080 +
13081 +/** memcpy() clone */
13082 +extern void *DWC_MEMCPY(void *dest, void const *src, uint32_t size);
13083 +#define dwc_memcpy DWC_MEMCPY
13084 +
13085 +/** memmove() clone */
13086 +extern void *DWC_MEMMOVE(void *dest, void *src, uint32_t size);
13087 +#define dwc_memmove DWC_MEMMOVE
13088 +
13089 +/** memcmp() clone */
13090 +extern int DWC_MEMCMP(void *m1, void *m2, uint32_t size);
13091 +#define dwc_memcmp DWC_MEMCMP
13092 +
13093 +/** strcmp() clone */
13094 +extern int DWC_STRCMP(void *s1, void *s2);
13095 +#define dwc_strcmp DWC_STRCMP
13096 +
13097 +/** strncmp() clone */
13098 +extern int DWC_STRNCMP(void *s1, void *s2, uint32_t size);
13099 +#define dwc_strncmp DWC_STRNCMP
13100 +
13101 +/** strlen() clone, for NULL terminated ASCII strings */
13102 +extern int DWC_STRLEN(char const *str);
13103 +#define dwc_strlen DWC_STRLEN
13104 +
13105 +/** strcpy() clone, for NULL terminated ASCII strings */
13106 +extern char *DWC_STRCPY(char *to, const char *from);
13107 +#define dwc_strcpy DWC_STRCPY
13108 +
13109 +/** strdup() clone. If you wish to use memory allocation debugging, this
13110 + * implementation of strdup should use the DWC_* memory routines instead of
13111 + * calling a predefined strdup. Otherwise the memory allocated by this routine
13112 + * will not be seen by the debugging routines. */
13113 +extern char *DWC_STRDUP(char const *str);
13114 +#define dwc_strdup(_ctx_,_str_) DWC_STRDUP(_str_)
13115 +
13116 +/** NOT an atoi() clone. Read the description carefully. Returns an integer
13117 + * converted from the string str in base 10 unless the string begins with a "0x"
13118 + * in which case it is base 16. String must be a NULL terminated sequence of
13119 + * ASCII characters and may optionally begin with whitespace, a + or -, and a
13120 + * "0x" prefix if base 16. The remaining characters must be valid digits for
13121 + * the number and end with a NULL character. If any invalid characters are
13122 + * encountered or it returns with a negative error code and the results of the
13123 + * conversion are undefined. On sucess it returns 0. Overflow conditions are
13124 + * undefined. An example implementation using atoi() can be referenced from the
13125 + * Linux implementation. */
13126 +extern int DWC_ATOI(const char *str, int32_t *value);
13127 +#define dwc_atoi DWC_ATOI
13128 +
13129 +/** Same as above but for unsigned. */
13130 +extern int DWC_ATOUI(const char *str, uint32_t *value);
13131 +#define dwc_atoui DWC_ATOUI
13132 +
13133 +#ifdef DWC_UTFLIB
13134 +/** This routine returns a UTF16LE unicode encoded string from a UTF8 string. */
13135 +extern int DWC_UTF8_TO_UTF16LE(uint8_t const *utf8string, uint16_t *utf16string, unsigned len);
13136 +#define dwc_utf8_to_utf16le DWC_UTF8_TO_UTF16LE
13137 +#endif
13138 +
13139 +
13140 +/** @name Wait queues
13141 + *
13142 + * Wait queues provide a means of synchronizing between threads or processes. A
13143 + * process can block on a waitq if some condition is not true, waiting for it to
13144 + * become true. When the waitq is triggered all waiting process will get
13145 + * unblocked and the condition will be check again. Waitqs should be triggered
13146 + * every time a condition can potentially change.*/
13147 +struct dwc_waitq;
13148 +
13149 +/** Type for a waitq */
13150 +typedef struct dwc_waitq dwc_waitq_t;
13151 +
13152 +/** The type of waitq condition callback function. This is called every time
13153 + * condition is evaluated. */
13154 +typedef int (*dwc_waitq_condition_t)(void *data);
13155 +
13156 +/** Allocate a waitq */
13157 +extern dwc_waitq_t *DWC_WAITQ_ALLOC(void);
13158 +#define dwc_waitq_alloc(_ctx_) DWC_WAITQ_ALLOC()
13159 +
13160 +/** Free a waitq */
13161 +extern void DWC_WAITQ_FREE(dwc_waitq_t *wq);
13162 +#define dwc_waitq_free DWC_WAITQ_FREE
13163 +
13164 +/** Check the condition and if it is false, block on the waitq. When unblocked, check the
13165 + * condition again. The function returns when the condition becomes true. The return value
13166 + * is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. */
13167 +extern int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data);
13168 +#define dwc_waitq_wait DWC_WAITQ_WAIT
13169 +
13170 +/** Check the condition and if it is false, block on the waitq. When unblocked,
13171 + * check the condition again. The function returns when the condition become
13172 + * true or the timeout has passed. The return value is 0 on condition true or
13173 + * DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on
13174 + * error. */
13175 +extern int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
13176 + void *data, int32_t msecs);
13177 +#define dwc_waitq_wait_timeout DWC_WAITQ_WAIT_TIMEOUT
13178 +
13179 +/** Trigger a waitq, unblocking all processes. This should be called whenever a condition
13180 + * has potentially changed. */
13181 +extern void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq);
13182 +#define dwc_waitq_trigger DWC_WAITQ_TRIGGER
13183 +
13184 +/** Unblock all processes waiting on the waitq with an ABORTED result. */
13185 +extern void DWC_WAITQ_ABORT(dwc_waitq_t *wq);
13186 +#define dwc_waitq_abort DWC_WAITQ_ABORT
13187 +
13188 +
13189 +/** @name Threads
13190 + *
13191 + * A thread must be explicitly stopped. It must check DWC_THREAD_SHOULD_STOP
13192 + * whenever it is woken up, and then return. The DWC_THREAD_STOP function
13193 + * returns the value from the thread.
13194 + */
13195 +
13196 +struct dwc_thread;
13197 +
13198 +/** Type for a thread */
13199 +typedef struct dwc_thread dwc_thread_t;
13200 +
13201 +/** The thread function */
13202 +typedef int (*dwc_thread_function_t)(void *data);
13203 +
13204 +/** Create a thread and start it running the thread_function. Returns a handle
13205 + * to the thread */
13206 +extern dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data);
13207 +#define dwc_thread_run(_ctx_,_func_,_name_,_data_) DWC_THREAD_RUN(_func_, _name_, _data_)
13208 +
13209 +/** Stops a thread. Return the value returned by the thread. Or will return
13210 + * DWC_ABORT if the thread never started. */
13211 +extern int DWC_THREAD_STOP(dwc_thread_t *thread);
13212 +#define dwc_thread_stop DWC_THREAD_STOP
13213 +
13214 +/** Signifies to the thread that it must stop. */
13215 +#ifdef DWC_LINUX
13216 +/* Linux doesn't need any parameters for kthread_should_stop() */
13217 +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(void);
13218 +#define dwc_thread_should_stop(_thrd_) DWC_THREAD_SHOULD_STOP()
13219 +
13220 +/* No thread_exit function in Linux */
13221 +#define dwc_thread_exit(_thrd_)
13222 +#endif
13223 +
13224 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13225 +/** BSD needs the thread pointer for kthread_suspend_check() */
13226 +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread);
13227 +#define dwc_thread_should_stop DWC_THREAD_SHOULD_STOP
13228 +
13229 +/** The thread must call this to exit. */
13230 +extern void DWC_THREAD_EXIT(dwc_thread_t *thread);
13231 +#define dwc_thread_exit DWC_THREAD_EXIT
13232 +#endif
13233 +
13234 +
13235 +/** @name Work queues
13236 + *
13237 + * Workqs are used to queue a callback function to be called at some later time,
13238 + * in another thread. */
13239 +struct dwc_workq;
13240 +
13241 +/** Type for a workq */
13242 +typedef struct dwc_workq dwc_workq_t;
13243 +
13244 +/** The type of the callback function to be called. */
13245 +typedef void (*dwc_work_callback_t)(void *data);
13246 +
13247 +/** Allocate a workq */
13248 +extern dwc_workq_t *DWC_WORKQ_ALLOC(char *name);
13249 +#define dwc_workq_alloc(_ctx_,_name_) DWC_WORKQ_ALLOC(_name_)
13250 +
13251 +/** Free a workq. All work must be completed before being freed. */
13252 +extern void DWC_WORKQ_FREE(dwc_workq_t *workq);
13253 +#define dwc_workq_free DWC_WORKQ_FREE
13254 +
13255 +/** Schedule a callback on the workq, passing in data. The function will be
13256 + * scheduled at some later time. */
13257 +extern void DWC_WORKQ_SCHEDULE(dwc_workq_t *workq, dwc_work_callback_t cb,
13258 + void *data, char *format, ...)
13259 +#ifdef __GNUC__
13260 + __attribute__ ((format(printf, 4, 5)));
13261 +#else
13262 + ;
13263 +#endif
13264 +#define dwc_workq_schedule DWC_WORKQ_SCHEDULE
13265 +
13266 +/** Schedule a callback on the workq, that will be called until at least
13267 + * given number miliseconds have passed. */
13268 +extern void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *workq, dwc_work_callback_t cb,
13269 + void *data, uint32_t time, char *format, ...)
13270 +#ifdef __GNUC__
13271 + __attribute__ ((format(printf, 5, 6)));
13272 +#else
13273 + ;
13274 +#endif
13275 +#define dwc_workq_schedule_delayed DWC_WORKQ_SCHEDULE_DELAYED
13276 +
13277 +/** The number of processes in the workq */
13278 +extern int DWC_WORKQ_PENDING(dwc_workq_t *workq);
13279 +#define dwc_workq_pending DWC_WORKQ_PENDING
13280 +
13281 +/** Blocks until all the work in the workq is complete or timed out. Returns <
13282 + * 0 on timeout. */
13283 +extern int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout);
13284 +#define dwc_workq_wait_work_done DWC_WORKQ_WAIT_WORK_DONE
13285 +
13286 +
13287 +/** @name Tasklets
13288 + *
13289 + */
13290 +struct dwc_tasklet;
13291 +
13292 +/** Type for a tasklet */
13293 +typedef struct dwc_tasklet dwc_tasklet_t;
13294 +
13295 +/** The type of the callback function to be called */
13296 +typedef void (*dwc_tasklet_callback_t)(void *data);
13297 +
13298 +/** Allocates a tasklet */
13299 +extern dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data);
13300 +#define dwc_task_alloc(_ctx_,_name_,_cb_,_data_) DWC_TASK_ALLOC(_name_, _cb_, _data_)
13301 +
13302 +/** Frees a tasklet */
13303 +extern void DWC_TASK_FREE(dwc_tasklet_t *task);
13304 +#define dwc_task_free DWC_TASK_FREE
13305 +
13306 +/** Schedules a tasklet to run */
13307 +extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
13308 +#define dwc_task_schedule DWC_TASK_SCHEDULE
13309 +
13310 +
13311 +/** @name Timer
13312 + *
13313 + * Callbacks must be small and atomic.
13314 + */
13315 +struct dwc_timer;
13316 +
13317 +/** Type for a timer */
13318 +typedef struct dwc_timer dwc_timer_t;
13319 +
13320 +/** The type of the callback function to be called */
13321 +typedef void (*dwc_timer_callback_t)(void *data);
13322 +
13323 +/** Allocates a timer */
13324 +extern dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data);
13325 +#define dwc_timer_alloc(_ctx_,_name_,_cb_,_data_) DWC_TIMER_ALLOC(_name_,_cb_,_data_)
13326 +
13327 +/** Frees a timer */
13328 +extern void DWC_TIMER_FREE(dwc_timer_t *timer);
13329 +#define dwc_timer_free DWC_TIMER_FREE
13330 +
13331 +/** Schedules the timer to run at time ms from now. And will repeat at every
13332 + * repeat_interval msec therafter
13333 + *
13334 + * Modifies a timer that is still awaiting execution to a new expiration time.
13335 + * The mod_time is added to the old time. */
13336 +extern void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time);
13337 +#define dwc_timer_schedule DWC_TIMER_SCHEDULE
13338 +
13339 +/** Disables the timer from execution. */
13340 +extern void DWC_TIMER_CANCEL(dwc_timer_t *timer);
13341 +#define dwc_timer_cancel DWC_TIMER_CANCEL
13342 +
13343 +
13344 +/** @name Spinlocks
13345 + *
13346 + * These locks are used when the work between the lock/unlock is atomic and
13347 + * short. Interrupts are also disabled during the lock/unlock and thus they are
13348 + * suitable to lock between interrupt/non-interrupt context. They also lock
13349 + * between processes if you have multiple CPUs or Preemption. If you don't have
13350 + * multiple CPUS or Preemption, then the you can simply implement the
13351 + * DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts. Because
13352 + * the work between the lock/unlock is atomic, the process context will never
13353 + * change, and so you never have to lock between processes. */
13354 +
13355 +struct dwc_spinlock;
13356 +
13357 +/** Type for a spinlock */
13358 +typedef struct dwc_spinlock dwc_spinlock_t;
13359 +
13360 +/** Type for the 'flags' argument to spinlock funtions */
13361 +typedef unsigned long dwc_irqflags_t;
13362 +
13363 +/** Returns an initialized lock variable. This function should allocate and
13364 + * initialize the OS-specific data structure used for locking. This data
13365 + * structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should
13366 + * be freed by the DWC_FREE_LOCK when it is no longer used. */
13367 +extern dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void);
13368 +#define dwc_spinlock_alloc(_ctx_) DWC_SPINLOCK_ALLOC()
13369 +
13370 +/** Frees an initialized lock variable. */
13371 +extern void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock);
13372 +#define dwc_spinlock_free(_ctx_,_lock_) DWC_SPINLOCK_FREE(_lock_)
13373 +
13374 +/** Disables interrupts and blocks until it acquires the lock.
13375 + *
13376 + * @param lock Pointer to the spinlock.
13377 + * @param flags Unsigned long for irq flags storage.
13378 + */
13379 +extern void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags);
13380 +#define dwc_spinlock_irqsave DWC_SPINLOCK_IRQSAVE
13381 +
13382 +/** Re-enables the interrupt and releases the lock.
13383 + *
13384 + * @param lock Pointer to the spinlock.
13385 + * @param flags Unsigned long for irq flags storage. Must be the same as was
13386 + * passed into DWC_LOCK.
13387 + */
13388 +extern void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags);
13389 +#define dwc_spinunlock_irqrestore DWC_SPINUNLOCK_IRQRESTORE
13390 +
13391 +/** Blocks until it acquires the lock.
13392 + *
13393 + * @param lock Pointer to the spinlock.
13394 + */
13395 +extern void DWC_SPINLOCK(dwc_spinlock_t *lock);
13396 +#define dwc_spinlock DWC_SPINLOCK
13397 +
13398 +/** Releases the lock.
13399 + *
13400 + * @param lock Pointer to the spinlock.
13401 + */
13402 +extern void DWC_SPINUNLOCK(dwc_spinlock_t *lock);
13403 +#define dwc_spinunlock DWC_SPINUNLOCK
13404 +
13405 +
13406 +/** @name Mutexes
13407 + *
13408 + * Unlike spinlocks Mutexes lock only between processes and the work between the
13409 + * lock/unlock CAN block, therefore it CANNOT be called from interrupt context.
13410 + */
13411 +
13412 +struct dwc_mutex;
13413 +
13414 +/** Type for a mutex */
13415 +typedef struct dwc_mutex dwc_mutex_t;
13416 +
13417 +/* For Linux Mutex Debugging make it inline because the debugging routines use
13418 + * the symbol to determine recursive locking. This makes it falsely think
13419 + * recursive locking occurs. */
13420 +#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
13421 +#define DWC_MUTEX_ALLOC_LINUX_DEBUG(__mutexp) ({ \
13422 + __mutexp = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); \
13423 + mutex_init((struct mutex *)__mutexp); \
13424 +})
13425 +#endif
13426 +
13427 +/** Allocate a mutex */
13428 +extern dwc_mutex_t *DWC_MUTEX_ALLOC(void);
13429 +#define dwc_mutex_alloc(_ctx_) DWC_MUTEX_ALLOC()
13430 +
13431 +/* For memory leak debugging when using Linux Mutex Debugging */
13432 +#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
13433 +#define DWC_MUTEX_FREE(__mutexp) do { \
13434 + mutex_destroy((struct mutex *)__mutexp); \
13435 + DWC_FREE(__mutexp); \
13436 +} while(0)
13437 +#else
13438 +/** Free a mutex */
13439 +extern void DWC_MUTEX_FREE(dwc_mutex_t *mutex);
13440 +#define dwc_mutex_free(_ctx_,_mutex_) DWC_MUTEX_FREE(_mutex_)
13441 +#endif
13442 +
13443 +/** Lock a mutex */
13444 +extern void DWC_MUTEX_LOCK(dwc_mutex_t *mutex);
13445 +#define dwc_mutex_lock DWC_MUTEX_LOCK
13446 +
13447 +/** Non-blocking lock returns 1 on successful lock. */
13448 +extern int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex);
13449 +#define dwc_mutex_trylock DWC_MUTEX_TRYLOCK
13450 +
13451 +/** Unlock a mutex */
13452 +extern void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex);
13453 +#define dwc_mutex_unlock DWC_MUTEX_UNLOCK
13454 +
13455 +
13456 +/** @name Time */
13457 +
13458 +/** Microsecond delay.
13459 + *
13460 + * @param usecs Microseconds to delay.
13461 + */
13462 +extern void DWC_UDELAY(uint32_t usecs);
13463 +#define dwc_udelay DWC_UDELAY
13464 +
13465 +/** Millisecond delay.
13466 + *
13467 + * @param msecs Milliseconds to delay.
13468 + */
13469 +extern void DWC_MDELAY(uint32_t msecs);
13470 +#define dwc_mdelay DWC_MDELAY
13471 +
13472 +/** Non-busy waiting.
13473 + * Sleeps for specified number of milliseconds.
13474 + *
13475 + * @param msecs Milliseconds to sleep.
13476 + */
13477 +extern void DWC_MSLEEP(uint32_t msecs);
13478 +#define dwc_msleep DWC_MSLEEP
13479 +
13480 +/**
13481 + * Returns number of milliseconds since boot.
13482 + */
13483 +extern uint32_t DWC_TIME(void);
13484 +#define dwc_time DWC_TIME
13485 +
13486 +
13487 +
13488 +
13489 +/* @mainpage DWC Portability and Common Library
13490 + *
13491 + * This is the documentation for the DWC Portability and Common Library.
13492 + *
13493 + * @section intro Introduction
13494 + *
13495 + * The DWC Portability library consists of wrapper calls and data structures to
13496 + * all low-level functions which are typically provided by the OS. The WUDEV
13497 + * driver uses only these functions. In order to port the WUDEV driver, only
13498 + * the functions in this library need to be re-implemented, with the same
13499 + * behavior as documented here.
13500 + *
13501 + * The Common library consists of higher level functions, which rely only on
13502 + * calling the functions from the DWC Portability library. These common
13503 + * routines are shared across modules. Some of the common libraries need to be
13504 + * used directly by the driver programmer when porting WUDEV. Such as the
13505 + * parameter and notification libraries.
13506 + *
13507 + * @section low Portability Library OS Wrapper Functions
13508 + *
13509 + * Any function starting with DWC and in all CAPS is a low-level OS-wrapper that
13510 + * needs to be implemented when porting, for example DWC_MUTEX_ALLOC(). All of
13511 + * these functions are included in the dwc_os.h file.
13512 + *
13513 + * There are many functions here covering a wide array of OS services. Please
13514 + * see dwc_os.h for details, and implementation notes for each function.
13515 + *
13516 + * @section common Common Library Functions
13517 + *
13518 + * Any function starting with dwc and in all lowercase is a common library
13519 + * routine. These functions have a portable implementation and do not need to
13520 + * be reimplemented when porting. The common routines can be used by any
13521 + * driver, and some must be used by the end user to control the drivers. For
13522 + * example, you must use the Parameter common library in order to set the
13523 + * parameters in the WUDEV module.
13524 + *
13525 + * The common libraries consist of the following:
13526 + *
13527 + * - Connection Contexts - Used internally and can be used by end-user. See dwc_cc.h
13528 + * - Parameters - Used internally and can be used by end-user. See dwc_params.h
13529 + * - Notifications - Used internally and can be used by end-user. See dwc_notifier.h
13530 + * - Lists - Used internally and can be used by end-user. See dwc_list.h
13531 + * - Memory Debugging - Used internally and can be used by end-user. See dwc_os.h
13532 + * - Modpow - Used internally only. See dwc_modpow.h
13533 + * - DH - Used internally only. See dwc_dh.h
13534 + * - Crypto - Used internally only. See dwc_crypto.h
13535 + *
13536 + *
13537 + * @section prereq Prerequistes For dwc_os.h
13538 + * @subsection types Data Types
13539 + *
13540 + * The dwc_os.h file assumes that several low-level data types are pre defined for the
13541 + * compilation environment. These data types are:
13542 + *
13543 + * - uint8_t - unsigned 8-bit data type
13544 + * - int8_t - signed 8-bit data type
13545 + * - uint16_t - unsigned 16-bit data type
13546 + * - int16_t - signed 16-bit data type
13547 + * - uint32_t - unsigned 32-bit data type
13548 + * - int32_t - signed 32-bit data type
13549 + * - uint64_t - unsigned 64-bit data type
13550 + * - int64_t - signed 64-bit data type
13551 + *
13552 + * Ensure that these are defined before using dwc_os.h. The easiest way to do
13553 + * that is to modify the top of the file to include the appropriate header.
13554 + * This is already done for the Linux environment. If the DWC_LINUX macro is
13555 + * defined, the correct header will be added. A standard header <stdint.h> is
13556 + * also used for environments where standard C headers are available.
13557 + *
13558 + * @subsection stdarg Variable Arguments
13559 + *
13560 + * Variable arguments are provided by a standard C header <stdarg.h>. it is
13561 + * available in Both the Linux and ANSI C enviornment. An equivalent must be
13562 + * provided in your enviornment in order to use dwc_os.h with the debug and
13563 + * tracing message functionality.
13564 + *
13565 + * @subsection thread Threading
13566 + *
13567 + * WUDEV Core must be run on an operating system that provides for multiple
13568 + * threads/processes. Threading can be implemented in many ways, even in
13569 + * embedded systems without an operating system. At the bare minimum, the
13570 + * system should be able to start any number of processes at any time to handle
13571 + * special work. It need not be a pre-emptive system. Process context can
13572 + * change upon a call to a blocking function. The hardware interrupt context
13573 + * that calls the module's ISR() function must be differentiable from process
13574 + * context, even if your processes are impemented via a hardware interrupt.
13575 + * Further locking mechanism between process must exist (or be implemented), and
13576 + * process context must have a way to disable interrupts for a period of time to
13577 + * lock them out. If all of this exists, the functions in dwc_os.h related to
13578 + * threading should be able to be implemented with the defined behavior.
13579 + *
13580 + */
13581 +
13582 +#ifdef __cplusplus
13583 +}
13584 +#endif
13585 +
13586 +#endif /* _DWC_OS_H_ */
13587 --- /dev/null
13588 +++ b/drivers/usb/host/dwc_common_port/usb.h
13589 @@ -0,0 +1,946 @@
13590 +/*
13591 + * Copyright (c) 1998 The NetBSD Foundation, Inc.
13592 + * All rights reserved.
13593 + *
13594 + * This code is derived from software contributed to The NetBSD Foundation
13595 + * by Lennart Augustsson (lennart@augustsson.net) at
13596 + * Carlstedt Research & Technology.
13597 + *
13598 + * Redistribution and use in source and binary forms, with or without
13599 + * modification, are permitted provided that the following conditions
13600 + * are met:
13601 + * 1. Redistributions of source code must retain the above copyright
13602 + * notice, this list of conditions and the following disclaimer.
13603 + * 2. Redistributions in binary form must reproduce the above copyright
13604 + * notice, this list of conditions and the following disclaimer in the
13605 + * documentation and/or other materials provided with the distribution.
13606 + * 3. All advertising materials mentioning features or use of this software
13607 + * must display the following acknowledgement:
13608 + * This product includes software developed by the NetBSD
13609 + * Foundation, Inc. and its contributors.
13610 + * 4. Neither the name of The NetBSD Foundation nor the names of its
13611 + * contributors may be used to endorse or promote products derived
13612 + * from this software without specific prior written permission.
13613 + *
13614 + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
13615 + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13616 + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
13617 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
13618 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
13619 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
13620 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
13621 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
13622 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
13623 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
13624 + * POSSIBILITY OF SUCH DAMAGE.
13625 + */
13626 +
13627 +/* Modified by Synopsys, Inc, 12/12/2007 */
13628 +
13629 +
13630 +#ifndef _USB_H_
13631 +#define _USB_H_
13632 +
13633 +#ifdef __cplusplus
13634 +extern "C" {
13635 +#endif
13636 +
13637 +/*
13638 + * The USB records contain some unaligned little-endian word
13639 + * components. The U[SG]ETW macros take care of both the alignment
13640 + * and endian problem and should always be used to access non-byte
13641 + * values.
13642 + */
13643 +typedef u_int8_t uByte;
13644 +typedef u_int8_t uWord[2];
13645 +typedef u_int8_t uDWord[4];
13646 +
13647 +#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
13648 +#define UCONSTW(x) { (x) & 0xff, ((x) >> 8) & 0xff }
13649 +#define UCONSTDW(x) { (x) & 0xff, ((x) >> 8) & 0xff, \
13650 + ((x) >> 16) & 0xff, ((x) >> 24) & 0xff }
13651 +
13652 +#if 1
13653 +#define UGETW(w) ((w)[0] | ((w)[1] << 8))
13654 +#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
13655 +#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
13656 +#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
13657 + (w)[1] = (u_int8_t)((v) >> 8), \
13658 + (w)[2] = (u_int8_t)((v) >> 16), \
13659 + (w)[3] = (u_int8_t)((v) >> 24))
13660 +#else
13661 +/*
13662 + * On little-endian machines that can handle unanliged accesses
13663 + * (e.g. i386) these macros can be replaced by the following.
13664 + */
13665 +#define UGETW(w) (*(u_int16_t *)(w))
13666 +#define USETW(w,v) (*(u_int16_t *)(w) = (v))
13667 +#define UGETDW(w) (*(u_int32_t *)(w))
13668 +#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
13669 +#endif
13670 +
13671 +/*
13672 + * Macros for accessing UAS IU fields, which are big-endian
13673 + */
13674 +#define IUSETW2(w,h,l) ((w)[0] = (u_int8_t)(h), (w)[1] = (u_int8_t)(l))
13675 +#define IUCONSTW(x) { ((x) >> 8) & 0xff, (x) & 0xff }
13676 +#define IUCONSTDW(x) { ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
13677 + ((x) >> 8) & 0xff, (x) & 0xff }
13678 +#define IUGETW(w) (((w)[0] << 8) | (w)[1])
13679 +#define IUSETW(w,v) ((w)[0] = (u_int8_t)((v) >> 8), (w)[1] = (u_int8_t)(v))
13680 +#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
13681 +#define IUSETDW(w,v) ((w)[0] = (u_int8_t)((v) >> 24), \
13682 + (w)[1] = (u_int8_t)((v) >> 16), \
13683 + (w)[2] = (u_int8_t)((v) >> 8), \
13684 + (w)[3] = (u_int8_t)(v))
13685 +
13686 +#define UPACKED __attribute__((__packed__))
13687 +
13688 +typedef struct {
13689 + uByte bmRequestType;
13690 + uByte bRequest;
13691 + uWord wValue;
13692 + uWord wIndex;
13693 + uWord wLength;
13694 +} UPACKED usb_device_request_t;
13695 +
13696 +#define UT_GET_DIR(a) ((a) & 0x80)
13697 +#define UT_WRITE 0x00
13698 +#define UT_READ 0x80
13699 +
13700 +#define UT_GET_TYPE(a) ((a) & 0x60)
13701 +#define UT_STANDARD 0x00
13702 +#define UT_CLASS 0x20
13703 +#define UT_VENDOR 0x40
13704 +
13705 +#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
13706 +#define UT_DEVICE 0x00
13707 +#define UT_INTERFACE 0x01
13708 +#define UT_ENDPOINT 0x02
13709 +#define UT_OTHER 0x03
13710 +
13711 +#define UT_READ_DEVICE (UT_READ | UT_STANDARD | UT_DEVICE)
13712 +#define UT_READ_INTERFACE (UT_READ | UT_STANDARD | UT_INTERFACE)
13713 +#define UT_READ_ENDPOINT (UT_READ | UT_STANDARD | UT_ENDPOINT)
13714 +#define UT_WRITE_DEVICE (UT_WRITE | UT_STANDARD | UT_DEVICE)
13715 +#define UT_WRITE_INTERFACE (UT_WRITE | UT_STANDARD | UT_INTERFACE)
13716 +#define UT_WRITE_ENDPOINT (UT_WRITE | UT_STANDARD | UT_ENDPOINT)
13717 +#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE)
13718 +#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE)
13719 +#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER)
13720 +#define UT_READ_CLASS_ENDPOINT (UT_READ | UT_CLASS | UT_ENDPOINT)
13721 +#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE)
13722 +#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
13723 +#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER)
13724 +#define UT_WRITE_CLASS_ENDPOINT (UT_WRITE | UT_CLASS | UT_ENDPOINT)
13725 +#define UT_READ_VENDOR_DEVICE (UT_READ | UT_VENDOR | UT_DEVICE)
13726 +#define UT_READ_VENDOR_INTERFACE (UT_READ | UT_VENDOR | UT_INTERFACE)
13727 +#define UT_READ_VENDOR_OTHER (UT_READ | UT_VENDOR | UT_OTHER)
13728 +#define UT_READ_VENDOR_ENDPOINT (UT_READ | UT_VENDOR | UT_ENDPOINT)
13729 +#define UT_WRITE_VENDOR_DEVICE (UT_WRITE | UT_VENDOR | UT_DEVICE)
13730 +#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
13731 +#define UT_WRITE_VENDOR_OTHER (UT_WRITE | UT_VENDOR | UT_OTHER)
13732 +#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
13733 +
13734 +/* Requests */
13735 +#define UR_GET_STATUS 0x00
13736 +#define USTAT_STANDARD_STATUS 0x00
13737 +#define WUSTAT_WUSB_FEATURE 0x01
13738 +#define WUSTAT_CHANNEL_INFO 0x02
13739 +#define WUSTAT_RECEIVED_DATA 0x03
13740 +#define WUSTAT_MAS_AVAILABILITY 0x04
13741 +#define WUSTAT_CURRENT_TRANSMIT_POWER 0x05
13742 +#define UR_CLEAR_FEATURE 0x01
13743 +#define UR_SET_FEATURE 0x03
13744 +#define UR_SET_AND_TEST_FEATURE 0x0c
13745 +#define UR_SET_ADDRESS 0x05
13746 +#define UR_GET_DESCRIPTOR 0x06
13747 +#define UDESC_DEVICE 0x01
13748 +#define UDESC_CONFIG 0x02
13749 +#define UDESC_STRING 0x03
13750 +#define UDESC_INTERFACE 0x04
13751 +#define UDESC_ENDPOINT 0x05
13752 +#define UDESC_SS_USB_COMPANION 0x30
13753 +#define UDESC_DEVICE_QUALIFIER 0x06
13754 +#define UDESC_OTHER_SPEED_CONFIGURATION 0x07
13755 +#define UDESC_INTERFACE_POWER 0x08
13756 +#define UDESC_OTG 0x09
13757 +#define WUDESC_SECURITY 0x0c
13758 +#define WUDESC_KEY 0x0d
13759 +#define WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
13760 +#define WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
13761 +#define WUD_KEY_TYPE_ASSOC 0x01
13762 +#define WUD_KEY_TYPE_GTK 0x02
13763 +#define WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
13764 +#define WUD_KEY_ORIGIN_HOST 0x00
13765 +#define WUD_KEY_ORIGIN_DEVICE 0x01
13766 +#define WUDESC_ENCRYPTION_TYPE 0x0e
13767 +#define WUDESC_BOS 0x0f
13768 +#define WUDESC_DEVICE_CAPABILITY 0x10
13769 +#define WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
13770 +#define UDESC_BOS 0x0f
13771 +#define UDESC_DEVICE_CAPABILITY 0x10
13772 +#define UDESC_CS_DEVICE 0x21 /* class specific */
13773 +#define UDESC_CS_CONFIG 0x22
13774 +#define UDESC_CS_STRING 0x23
13775 +#define UDESC_CS_INTERFACE 0x24
13776 +#define UDESC_CS_ENDPOINT 0x25
13777 +#define UDESC_HUB 0x29
13778 +#define UR_SET_DESCRIPTOR 0x07
13779 +#define UR_GET_CONFIG 0x08
13780 +#define UR_SET_CONFIG 0x09
13781 +#define UR_GET_INTERFACE 0x0a
13782 +#define UR_SET_INTERFACE 0x0b
13783 +#define UR_SYNCH_FRAME 0x0c
13784 +#define WUR_SET_ENCRYPTION 0x0d
13785 +#define WUR_GET_ENCRYPTION 0x0e
13786 +#define WUR_SET_HANDSHAKE 0x0f
13787 +#define WUR_GET_HANDSHAKE 0x10
13788 +#define WUR_SET_CONNECTION 0x11
13789 +#define WUR_SET_SECURITY_DATA 0x12
13790 +#define WUR_GET_SECURITY_DATA 0x13
13791 +#define WUR_SET_WUSB_DATA 0x14
13792 +#define WUDATA_DRPIE_INFO 0x01
13793 +#define WUDATA_TRANSMIT_DATA 0x02
13794 +#define WUDATA_TRANSMIT_PARAMS 0x03
13795 +#define WUDATA_RECEIVE_PARAMS 0x04
13796 +#define WUDATA_TRANSMIT_POWER 0x05
13797 +#define WUR_LOOPBACK_DATA_WRITE 0x15
13798 +#define WUR_LOOPBACK_DATA_READ 0x16
13799 +#define WUR_SET_INTERFACE_DS 0x17
13800 +
13801 +/* Feature numbers */
13802 +#define UF_ENDPOINT_HALT 0
13803 +#define UF_DEVICE_REMOTE_WAKEUP 1
13804 +#define UF_TEST_MODE 2
13805 +#define UF_DEVICE_B_HNP_ENABLE 3
13806 +#define UF_DEVICE_A_HNP_SUPPORT 4
13807 +#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
13808 +#define WUF_WUSB 3
13809 +#define WUF_TX_DRPIE 0x0
13810 +#define WUF_DEV_XMIT_PACKET 0x1
13811 +#define WUF_COUNT_PACKETS 0x2
13812 +#define WUF_CAPTURE_PACKETS 0x3
13813 +#define UF_FUNCTION_SUSPEND 0
13814 +#define UF_U1_ENABLE 48
13815 +#define UF_U2_ENABLE 49
13816 +#define UF_LTM_ENABLE 50
13817 +
13818 +/* Class requests from the USB 2.0 hub spec, table 11-15 */
13819 +#define UCR_CLEAR_HUB_FEATURE (0x2000 | UR_CLEAR_FEATURE)
13820 +#define UCR_CLEAR_PORT_FEATURE (0x2300 | UR_CLEAR_FEATURE)
13821 +#define UCR_GET_HUB_DESCRIPTOR (0xa000 | UR_GET_DESCRIPTOR)
13822 +#define UCR_GET_HUB_STATUS (0xa000 | UR_GET_STATUS)
13823 +#define UCR_GET_PORT_STATUS (0xa300 | UR_GET_STATUS)
13824 +#define UCR_SET_HUB_FEATURE (0x2000 | UR_SET_FEATURE)
13825 +#define UCR_SET_PORT_FEATURE (0x2300 | UR_SET_FEATURE)
13826 +#define UCR_SET_AND_TEST_PORT_FEATURE (0xa300 | UR_SET_AND_TEST_FEATURE)
13827 +
13828 +#ifdef _MSC_VER
13829 +#include <pshpack1.h>
13830 +#endif
13831 +
13832 +typedef struct {
13833 + uByte bLength;
13834 + uByte bDescriptorType;
13835 + uByte bDescriptorSubtype;
13836 +} UPACKED usb_descriptor_t;
13837 +
13838 +typedef struct {
13839 + uByte bLength;
13840 + uByte bDescriptorType;
13841 +} UPACKED usb_descriptor_header_t;
13842 +
13843 +typedef struct {
13844 + uByte bLength;
13845 + uByte bDescriptorType;
13846 + uWord bcdUSB;
13847 +#define UD_USB_2_0 0x0200
13848 +#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
13849 + uByte bDeviceClass;
13850 + uByte bDeviceSubClass;
13851 + uByte bDeviceProtocol;
13852 + uByte bMaxPacketSize;
13853 + /* The fields below are not part of the initial descriptor. */
13854 + uWord idVendor;
13855 + uWord idProduct;
13856 + uWord bcdDevice;
13857 + uByte iManufacturer;
13858 + uByte iProduct;
13859 + uByte iSerialNumber;
13860 + uByte bNumConfigurations;
13861 +} UPACKED usb_device_descriptor_t;
13862 +#define USB_DEVICE_DESCRIPTOR_SIZE 18
13863 +
13864 +typedef struct {
13865 + uByte bLength;
13866 + uByte bDescriptorType;
13867 + uWord wTotalLength;
13868 + uByte bNumInterface;
13869 + uByte bConfigurationValue;
13870 + uByte iConfiguration;
13871 +#define UC_ATT_ONE (1 << 7) /* must be set */
13872 +#define UC_ATT_SELFPOWER (1 << 6) /* self powered */
13873 +#define UC_ATT_WAKEUP (1 << 5) /* can wakeup */
13874 +#define UC_ATT_BATTERY (1 << 4) /* battery powered */
13875 + uByte bmAttributes;
13876 +#define UC_BUS_POWERED 0x80
13877 +#define UC_SELF_POWERED 0x40
13878 +#define UC_REMOTE_WAKEUP 0x20
13879 + uByte bMaxPower; /* max current in 2 mA units */
13880 +#define UC_POWER_FACTOR 2
13881 +} UPACKED usb_config_descriptor_t;
13882 +#define USB_CONFIG_DESCRIPTOR_SIZE 9
13883 +
13884 +typedef struct {
13885 + uByte bLength;
13886 + uByte bDescriptorType;
13887 + uByte bInterfaceNumber;
13888 + uByte bAlternateSetting;
13889 + uByte bNumEndpoints;
13890 + uByte bInterfaceClass;
13891 + uByte bInterfaceSubClass;
13892 + uByte bInterfaceProtocol;
13893 + uByte iInterface;
13894 +} UPACKED usb_interface_descriptor_t;
13895 +#define USB_INTERFACE_DESCRIPTOR_SIZE 9
13896 +
13897 +typedef struct {
13898 + uByte bLength;
13899 + uByte bDescriptorType;
13900 + uByte bEndpointAddress;
13901 +#define UE_GET_DIR(a) ((a) & 0x80)
13902 +#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7))
13903 +#define UE_DIR_IN 0x80
13904 +#define UE_DIR_OUT 0x00
13905 +#define UE_ADDR 0x0f
13906 +#define UE_GET_ADDR(a) ((a) & UE_ADDR)
13907 + uByte bmAttributes;
13908 +#define UE_XFERTYPE 0x03
13909 +#define UE_CONTROL 0x00
13910 +#define UE_ISOCHRONOUS 0x01
13911 +#define UE_BULK 0x02
13912 +#define UE_INTERRUPT 0x03
13913 +#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE)
13914 +#define UE_ISO_TYPE 0x0c
13915 +#define UE_ISO_ASYNC 0x04
13916 +#define UE_ISO_ADAPT 0x08
13917 +#define UE_ISO_SYNC 0x0c
13918 +#define UE_GET_ISO_TYPE(a) ((a) & UE_ISO_TYPE)
13919 + uWord wMaxPacketSize;
13920 + uByte bInterval;
13921 +} UPACKED usb_endpoint_descriptor_t;
13922 +#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
13923 +
13924 +typedef struct ss_endpoint_companion_descriptor {
13925 + uByte bLength;
13926 + uByte bDescriptorType;
13927 + uByte bMaxBurst;
13928 +#define USSE_GET_MAX_STREAMS(a) ((a) & 0x1f)
13929 +#define USSE_SET_MAX_STREAMS(a, b) ((a) | ((b) & 0x1f))
13930 +#define USSE_GET_MAX_PACKET_NUM(a) ((a) & 0x03)
13931 +#define USSE_SET_MAX_PACKET_NUM(a, b) ((a) | ((b) & 0x03))
13932 + uByte bmAttributes;
13933 + uWord wBytesPerInterval;
13934 +} UPACKED ss_endpoint_companion_descriptor_t;
13935 +#define USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE 6
13936 +
13937 +typedef struct {
13938 + uByte bLength;
13939 + uByte bDescriptorType;
13940 + uWord bString[127];
13941 +} UPACKED usb_string_descriptor_t;
13942 +#define USB_MAX_STRING_LEN 128
13943 +#define USB_LANGUAGE_TABLE 0 /* # of the string language id table */
13944 +
13945 +/* Hub specific request */
13946 +#define UR_GET_BUS_STATE 0x02
13947 +#define UR_CLEAR_TT_BUFFER 0x08
13948 +#define UR_RESET_TT 0x09
13949 +#define UR_GET_TT_STATE 0x0a
13950 +#define UR_STOP_TT 0x0b
13951 +
13952 +/* Hub features */
13953 +#define UHF_C_HUB_LOCAL_POWER 0
13954 +#define UHF_C_HUB_OVER_CURRENT 1
13955 +#define UHF_PORT_CONNECTION 0
13956 +#define UHF_PORT_ENABLE 1
13957 +#define UHF_PORT_SUSPEND 2
13958 +#define UHF_PORT_OVER_CURRENT 3
13959 +#define UHF_PORT_RESET 4
13960 +#define UHF_PORT_L1 5
13961 +#define UHF_PORT_POWER 8
13962 +#define UHF_PORT_LOW_SPEED 9
13963 +#define UHF_PORT_HIGH_SPEED 10
13964 +#define UHF_C_PORT_CONNECTION 16
13965 +#define UHF_C_PORT_ENABLE 17
13966 +#define UHF_C_PORT_SUSPEND 18
13967 +#define UHF_C_PORT_OVER_CURRENT 19
13968 +#define UHF_C_PORT_RESET 20
13969 +#define UHF_C_PORT_L1 23
13970 +#define UHF_PORT_TEST 21
13971 +#define UHF_PORT_INDICATOR 22
13972 +
13973 +typedef struct {
13974 + uByte bDescLength;
13975 + uByte bDescriptorType;
13976 + uByte bNbrPorts;
13977 + uWord wHubCharacteristics;
13978 +#define UHD_PWR 0x0003
13979 +#define UHD_PWR_GANGED 0x0000
13980 +#define UHD_PWR_INDIVIDUAL 0x0001
13981 +#define UHD_PWR_NO_SWITCH 0x0002
13982 +#define UHD_COMPOUND 0x0004
13983 +#define UHD_OC 0x0018
13984 +#define UHD_OC_GLOBAL 0x0000
13985 +#define UHD_OC_INDIVIDUAL 0x0008
13986 +#define UHD_OC_NONE 0x0010
13987 +#define UHD_TT_THINK 0x0060
13988 +#define UHD_TT_THINK_8 0x0000
13989 +#define UHD_TT_THINK_16 0x0020
13990 +#define UHD_TT_THINK_24 0x0040
13991 +#define UHD_TT_THINK_32 0x0060
13992 +#define UHD_PORT_IND 0x0080
13993 + uByte bPwrOn2PwrGood; /* delay in 2 ms units */
13994 +#define UHD_PWRON_FACTOR 2
13995 + uByte bHubContrCurrent;
13996 + uByte DeviceRemovable[32]; /* max 255 ports */
13997 +#define UHD_NOT_REMOV(desc, i) \
13998 + (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
13999 + /* deprecated */ uByte PortPowerCtrlMask[1];
14000 +} UPACKED usb_hub_descriptor_t;
14001 +#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
14002 +
14003 +typedef struct {
14004 + uByte bLength;
14005 + uByte bDescriptorType;
14006 + uWord bcdUSB;
14007 + uByte bDeviceClass;
14008 + uByte bDeviceSubClass;
14009 + uByte bDeviceProtocol;
14010 + uByte bMaxPacketSize0;
14011 + uByte bNumConfigurations;
14012 + uByte bReserved;
14013 +} UPACKED usb_device_qualifier_t;
14014 +#define USB_DEVICE_QUALIFIER_SIZE 10
14015 +
14016 +typedef struct {
14017 + uByte bLength;
14018 + uByte bDescriptorType;
14019 + uByte bmAttributes;
14020 +#define UOTG_SRP 0x01
14021 +#define UOTG_HNP 0x02
14022 +} UPACKED usb_otg_descriptor_t;
14023 +
14024 +/* OTG feature selectors */
14025 +#define UOTG_B_HNP_ENABLE 3
14026 +#define UOTG_A_HNP_SUPPORT 4
14027 +#define UOTG_A_ALT_HNP_SUPPORT 5
14028 +
14029 +typedef struct {
14030 + uWord wStatus;
14031 +/* Device status flags */
14032 +#define UDS_SELF_POWERED 0x0001
14033 +#define UDS_REMOTE_WAKEUP 0x0002
14034 +/* Endpoint status flags */
14035 +#define UES_HALT 0x0001
14036 +} UPACKED usb_status_t;
14037 +
14038 +typedef struct {
14039 + uWord wHubStatus;
14040 +#define UHS_LOCAL_POWER 0x0001
14041 +#define UHS_OVER_CURRENT 0x0002
14042 + uWord wHubChange;
14043 +} UPACKED usb_hub_status_t;
14044 +
14045 +typedef struct {
14046 + uWord wPortStatus;
14047 +#define UPS_CURRENT_CONNECT_STATUS 0x0001
14048 +#define UPS_PORT_ENABLED 0x0002
14049 +#define UPS_SUSPEND 0x0004
14050 +#define UPS_OVERCURRENT_INDICATOR 0x0008
14051 +#define UPS_RESET 0x0010
14052 +#define UPS_PORT_POWER 0x0100
14053 +#define UPS_LOW_SPEED 0x0200
14054 +#define UPS_HIGH_SPEED 0x0400
14055 +#define UPS_PORT_TEST 0x0800
14056 +#define UPS_PORT_INDICATOR 0x1000
14057 + uWord wPortChange;
14058 +#define UPS_C_CONNECT_STATUS 0x0001
14059 +#define UPS_C_PORT_ENABLED 0x0002
14060 +#define UPS_C_SUSPEND 0x0004
14061 +#define UPS_C_OVERCURRENT_INDICATOR 0x0008
14062 +#define UPS_C_PORT_RESET 0x0010
14063 +} UPACKED usb_port_status_t;
14064 +
14065 +#ifdef _MSC_VER
14066 +#include <poppack.h>
14067 +#endif
14068 +
14069 +/* Device class codes */
14070 +#define UDCLASS_IN_INTERFACE 0x00
14071 +#define UDCLASS_COMM 0x02
14072 +#define UDCLASS_HUB 0x09
14073 +#define UDSUBCLASS_HUB 0x00
14074 +#define UDPROTO_FSHUB 0x00
14075 +#define UDPROTO_HSHUBSTT 0x01
14076 +#define UDPROTO_HSHUBMTT 0x02
14077 +#define UDCLASS_DIAGNOSTIC 0xdc
14078 +#define UDCLASS_WIRELESS 0xe0
14079 +#define UDSUBCLASS_RF 0x01
14080 +#define UDPROTO_BLUETOOTH 0x01
14081 +#define UDCLASS_VENDOR 0xff
14082 +
14083 +/* Interface class codes */
14084 +#define UICLASS_UNSPEC 0x00
14085 +
14086 +#define UICLASS_AUDIO 0x01
14087 +#define UISUBCLASS_AUDIOCONTROL 1
14088 +#define UISUBCLASS_AUDIOSTREAM 2
14089 +#define UISUBCLASS_MIDISTREAM 3
14090 +
14091 +#define UICLASS_CDC 0x02 /* communication */
14092 +#define UISUBCLASS_DIRECT_LINE_CONTROL_MODEL 1
14093 +#define UISUBCLASS_ABSTRACT_CONTROL_MODEL 2
14094 +#define UISUBCLASS_TELEPHONE_CONTROL_MODEL 3
14095 +#define UISUBCLASS_MULTICHANNEL_CONTROL_MODEL 4
14096 +#define UISUBCLASS_CAPI_CONTROLMODEL 5
14097 +#define UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
14098 +#define UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
14099 +#define UIPROTO_CDC_AT 1
14100 +
14101 +#define UICLASS_HID 0x03
14102 +#define UISUBCLASS_BOOT 1
14103 +#define UIPROTO_BOOT_KEYBOARD 1
14104 +
14105 +#define UICLASS_PHYSICAL 0x05
14106 +
14107 +#define UICLASS_IMAGE 0x06
14108 +
14109 +#define UICLASS_PRINTER 0x07
14110 +#define UISUBCLASS_PRINTER 1
14111 +#define UIPROTO_PRINTER_UNI 1
14112 +#define UIPROTO_PRINTER_BI 2
14113 +#define UIPROTO_PRINTER_1284 3
14114 +
14115 +#define UICLASS_MASS 0x08
14116 +#define UISUBCLASS_RBC 1
14117 +#define UISUBCLASS_SFF8020I 2
14118 +#define UISUBCLASS_QIC157 3
14119 +#define UISUBCLASS_UFI 4
14120 +#define UISUBCLASS_SFF8070I 5
14121 +#define UISUBCLASS_SCSI 6
14122 +#define UIPROTO_MASS_CBI_I 0
14123 +#define UIPROTO_MASS_CBI 1
14124 +#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */
14125 +#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */
14126 +
14127 +#define UICLASS_HUB 0x09
14128 +#define UISUBCLASS_HUB 0
14129 +#define UIPROTO_FSHUB 0
14130 +#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */
14131 +#define UIPROTO_HSHUBMTT 1
14132 +
14133 +#define UICLASS_CDC_DATA 0x0a
14134 +#define UISUBCLASS_DATA 0
14135 +#define UIPROTO_DATA_ISDNBRI 0x30 /* Physical iface */
14136 +#define UIPROTO_DATA_HDLC 0x31 /* HDLC */
14137 +#define UIPROTO_DATA_TRANSPARENT 0x32 /* Transparent */
14138 +#define UIPROTO_DATA_Q921M 0x50 /* Management for Q921 */
14139 +#define UIPROTO_DATA_Q921 0x51 /* Data for Q921 */
14140 +#define UIPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */
14141 +#define UIPROTO_DATA_V42BIS 0x90 /* Data compression */
14142 +#define UIPROTO_DATA_Q931 0x91 /* Euro-ISDN */
14143 +#define UIPROTO_DATA_V120 0x92 /* V.24 rate adaption */
14144 +#define UIPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */
14145 +#define UIPROTO_DATA_HOST_BASED 0xfd /* Host based driver */
14146 +#define UIPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc.*/
14147 +#define UIPROTO_DATA_VENDOR 0xff /* Vendor specific */
14148 +
14149 +#define UICLASS_SMARTCARD 0x0b
14150 +
14151 +/*#define UICLASS_FIRM_UPD 0x0c*/
14152 +
14153 +#define UICLASS_SECURITY 0x0d
14154 +
14155 +#define UICLASS_DIAGNOSTIC 0xdc
14156 +
14157 +#define UICLASS_WIRELESS 0xe0
14158 +#define UISUBCLASS_RF 0x01
14159 +#define UIPROTO_BLUETOOTH 0x01
14160 +
14161 +#define UICLASS_APPL_SPEC 0xfe
14162 +#define UISUBCLASS_FIRMWARE_DOWNLOAD 1
14163 +#define UISUBCLASS_IRDA 2
14164 +#define UIPROTO_IRDA 0
14165 +
14166 +#define UICLASS_VENDOR 0xff
14167 +
14168 +#define USB_HUB_MAX_DEPTH 5
14169 +
14170 +/*
14171 + * Minimum time a device needs to be powered down to go through
14172 + * a power cycle. XXX Are these time in the spec?
14173 + */
14174 +#define USB_POWER_DOWN_TIME 200 /* ms */
14175 +#define USB_PORT_POWER_DOWN_TIME 100 /* ms */
14176 +
14177 +#if 0
14178 +/* These are the values from the spec. */
14179 +#define USB_PORT_RESET_DELAY 10 /* ms */
14180 +#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
14181 +#define USB_PORT_RESET_RECOVERY 10 /* ms */
14182 +#define USB_PORT_POWERUP_DELAY 100 /* ms */
14183 +#define USB_SET_ADDRESS_SETTLE 2 /* ms */
14184 +#define USB_RESUME_DELAY (20*5) /* ms */
14185 +#define USB_RESUME_WAIT 10 /* ms */
14186 +#define USB_RESUME_RECOVERY 10 /* ms */
14187 +#define USB_EXTRA_POWER_UP_TIME 0 /* ms */
14188 +#else
14189 +/* Allow for marginal (i.e. non-conforming) devices. */
14190 +#define USB_PORT_RESET_DELAY 50 /* ms */
14191 +#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
14192 +#define USB_PORT_RESET_RECOVERY 250 /* ms */
14193 +#define USB_PORT_POWERUP_DELAY 300 /* ms */
14194 +#define USB_SET_ADDRESS_SETTLE 10 /* ms */
14195 +#define USB_RESUME_DELAY (50*5) /* ms */
14196 +#define USB_RESUME_WAIT 50 /* ms */
14197 +#define USB_RESUME_RECOVERY 50 /* ms */
14198 +#define USB_EXTRA_POWER_UP_TIME 20 /* ms */
14199 +#endif
14200 +
14201 +#define USB_MIN_POWER 100 /* mA */
14202 +#define USB_MAX_POWER 500 /* mA */
14203 +
14204 +#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/
14205 +
14206 +#define USB_UNCONFIG_NO 0
14207 +#define USB_UNCONFIG_INDEX (-1)
14208 +
14209 +/*** ioctl() related stuff ***/
14210 +
14211 +struct usb_ctl_request {
14212 + int ucr_addr;
14213 + usb_device_request_t ucr_request;
14214 + void *ucr_data;
14215 + int ucr_flags;
14216 +#define USBD_SHORT_XFER_OK 0x04 /* allow short reads */
14217 + int ucr_actlen; /* actual length transferred */
14218 +};
14219 +
14220 +struct usb_alt_interface {
14221 + int uai_config_index;
14222 + int uai_interface_index;
14223 + int uai_alt_no;
14224 +};
14225 +
14226 +#define USB_CURRENT_CONFIG_INDEX (-1)
14227 +#define USB_CURRENT_ALT_INDEX (-1)
14228 +
14229 +struct usb_config_desc {
14230 + int ucd_config_index;
14231 + usb_config_descriptor_t ucd_desc;
14232 +};
14233 +
14234 +struct usb_interface_desc {
14235 + int uid_config_index;
14236 + int uid_interface_index;
14237 + int uid_alt_index;
14238 + usb_interface_descriptor_t uid_desc;
14239 +};
14240 +
14241 +struct usb_endpoint_desc {
14242 + int ued_config_index;
14243 + int ued_interface_index;
14244 + int ued_alt_index;
14245 + int ued_endpoint_index;
14246 + usb_endpoint_descriptor_t ued_desc;
14247 +};
14248 +
14249 +struct usb_full_desc {
14250 + int ufd_config_index;
14251 + u_int ufd_size;
14252 + u_char *ufd_data;
14253 +};
14254 +
14255 +struct usb_string_desc {
14256 + int usd_string_index;
14257 + int usd_language_id;
14258 + usb_string_descriptor_t usd_desc;
14259 +};
14260 +
14261 +struct usb_ctl_report_desc {
14262 + int ucrd_size;
14263 + u_char ucrd_data[1024]; /* filled data size will vary */
14264 +};
14265 +
14266 +typedef struct { u_int32_t cookie; } usb_event_cookie_t;
14267 +
14268 +#define USB_MAX_DEVNAMES 4
14269 +#define USB_MAX_DEVNAMELEN 16
14270 +struct usb_device_info {
14271 + u_int8_t udi_bus;
14272 + u_int8_t udi_addr; /* device address */
14273 + usb_event_cookie_t udi_cookie;
14274 + char udi_product[USB_MAX_STRING_LEN];
14275 + char udi_vendor[USB_MAX_STRING_LEN];
14276 + char udi_release[8];
14277 + u_int16_t udi_productNo;
14278 + u_int16_t udi_vendorNo;
14279 + u_int16_t udi_releaseNo;
14280 + u_int8_t udi_class;
14281 + u_int8_t udi_subclass;
14282 + u_int8_t udi_protocol;
14283 + u_int8_t udi_config;
14284 + u_int8_t udi_speed;
14285 +#define USB_SPEED_UNKNOWN 0
14286 +#define USB_SPEED_LOW 1
14287 +#define USB_SPEED_FULL 2
14288 +#define USB_SPEED_HIGH 3
14289 +#define USB_SPEED_VARIABLE 4
14290 +#define USB_SPEED_SUPER 5
14291 + int udi_power; /* power consumption in mA, 0 if selfpowered */
14292 + int udi_nports;
14293 + char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
14294 + u_int8_t udi_ports[16];/* hub only: addresses of devices on ports */
14295 +#define USB_PORT_ENABLED 0xff
14296 +#define USB_PORT_SUSPENDED 0xfe
14297 +#define USB_PORT_POWERED 0xfd
14298 +#define USB_PORT_DISABLED 0xfc
14299 +};
14300 +
14301 +struct usb_ctl_report {
14302 + int ucr_report;
14303 + u_char ucr_data[1024]; /* filled data size will vary */
14304 +};
14305 +
14306 +struct usb_device_stats {
14307 + u_long uds_requests[4]; /* indexed by transfer type UE_* */
14308 +};
14309 +
14310 +#define WUSB_MIN_IE 0x80
14311 +#define WUSB_WCTA_IE 0x80
14312 +#define WUSB_WCONNECTACK_IE 0x81
14313 +#define WUSB_WHOSTINFO_IE 0x82
14314 +#define WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
14315 +#define WUHI_CA_RECONN 0x00
14316 +#define WUHI_CA_LIMITED 0x01
14317 +#define WUHI_CA_ALL 0x03
14318 +#define WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
14319 +#define WUSB_WCHCHANGEANNOUNCE_IE 0x83
14320 +#define WUSB_WDEV_DISCONNECT_IE 0x84
14321 +#define WUSB_WHOST_DISCONNECT_IE 0x85
14322 +#define WUSB_WRELEASE_CHANNEL_IE 0x86
14323 +#define WUSB_WWORK_IE 0x87
14324 +#define WUSB_WCHANNEL_STOP_IE 0x88
14325 +#define WUSB_WDEV_KEEPALIVE_IE 0x89
14326 +#define WUSB_WISOCH_DISCARD_IE 0x8A
14327 +#define WUSB_WRESETDEVICE_IE 0x8B
14328 +#define WUSB_WXMIT_PACKET_ADJUST_IE 0x8C
14329 +#define WUSB_MAX_IE 0x8C
14330 +
14331 +/* Device Notification Types */
14332 +
14333 +#define WUSB_DN_MIN 0x01
14334 +#define WUSB_DN_CONNECT 0x01
14335 +# define WUSB_DA_OLDCONN 0x00
14336 +# define WUSB_DA_NEWCONN 0x01
14337 +# define WUSB_DA_SELF_BEACON 0x02
14338 +# define WUSB_DA_DIR_BEACON 0x04
14339 +# define WUSB_DA_NO_BEACON 0x06
14340 +#define WUSB_DN_DISCONNECT 0x02
14341 +#define WUSB_DN_EPRDY 0x03
14342 +#define WUSB_DN_MASAVAILCHANGED 0x04
14343 +#define WUSB_DN_REMOTEWAKEUP 0x05
14344 +#define WUSB_DN_SLEEP 0x06
14345 +#define WUSB_DN_ALIVE 0x07
14346 +#define WUSB_DN_MAX 0x07
14347 +
14348 +#ifdef _MSC_VER
14349 +#include <pshpack1.h>
14350 +#endif
14351 +
14352 +/* WUSB Handshake Data. Used during the SET/GET HANDSHAKE requests */
14353 +typedef struct wusb_hndshk_data {
14354 + uByte bMessageNumber;
14355 + uByte bStatus;
14356 + uByte tTKID[3];
14357 + uByte bReserved;
14358 + uByte CDID[16];
14359 + uByte Nonce[16];
14360 + uByte MIC[8];
14361 +} UPACKED wusb_hndshk_data_t;
14362 +#define WUSB_HANDSHAKE_LEN_FOR_MIC 38
14363 +
14364 +/* WUSB Connection Context */
14365 +typedef struct wusb_conn_context {
14366 + uByte CHID [16];
14367 + uByte CDID [16];
14368 + uByte CK [16];
14369 +} UPACKED wusb_conn_context_t;
14370 +
14371 +/* WUSB Security Descriptor */
14372 +typedef struct wusb_security_desc {
14373 + uByte bLength;
14374 + uByte bDescriptorType;
14375 + uWord wTotalLength;
14376 + uByte bNumEncryptionTypes;
14377 +} UPACKED wusb_security_desc_t;
14378 +
14379 +/* WUSB Encryption Type Descriptor */
14380 +typedef struct wusb_encrypt_type_desc {
14381 + uByte bLength;
14382 + uByte bDescriptorType;
14383 +
14384 + uByte bEncryptionType;
14385 +#define WUETD_UNSECURE 0
14386 +#define WUETD_WIRED 1
14387 +#define WUETD_CCM_1 2
14388 +#define WUETD_RSA_1 3
14389 +
14390 + uByte bEncryptionValue;
14391 + uByte bAuthKeyIndex;
14392 +} UPACKED wusb_encrypt_type_desc_t;
14393 +
14394 +/* WUSB Key Descriptor */
14395 +typedef struct wusb_key_desc {
14396 + uByte bLength;
14397 + uByte bDescriptorType;
14398 + uByte tTKID[3];
14399 + uByte bReserved;
14400 + uByte KeyData[1]; /* variable length */
14401 +} UPACKED wusb_key_desc_t;
14402 +
14403 +/* WUSB BOS Descriptor (Binary device Object Store) */
14404 +typedef struct wusb_bos_desc {
14405 + uByte bLength;
14406 + uByte bDescriptorType;
14407 + uWord wTotalLength;
14408 + uByte bNumDeviceCaps;
14409 +} UPACKED wusb_bos_desc_t;
14410 +
14411 +#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02
14412 +typedef struct usb_dev_cap_20_ext_desc {
14413 + uByte bLength;
14414 + uByte bDescriptorType;
14415 + uByte bDevCapabilityType;
14416 +#define USB_20_EXT_LPM 0x02
14417 + uDWord bmAttributes;
14418 +} UPACKED usb_dev_cap_20_ext_desc_t;
14419 +
14420 +#define USB_DEVICE_CAPABILITY_SS_USB 0x03
14421 +typedef struct usb_dev_cap_ss_usb {
14422 + uByte bLength;
14423 + uByte bDescriptorType;
14424 + uByte bDevCapabilityType;
14425 +#define USB_DC_SS_USB_LTM_CAPABLE 0x02
14426 + uByte bmAttributes;
14427 +#define USB_DC_SS_USB_SPEED_SUPPORT_LOW 0x01
14428 +#define USB_DC_SS_USB_SPEED_SUPPORT_FULL 0x02
14429 +#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH 0x04
14430 +#define USB_DC_SS_USB_SPEED_SUPPORT_SS 0x08
14431 + uWord wSpeedsSupported;
14432 + uByte bFunctionalitySupport;
14433 + uByte bU1DevExitLat;
14434 + uWord wU2DevExitLat;
14435 +} UPACKED usb_dev_cap_ss_usb_t;
14436 +
14437 +#define USB_DEVICE_CAPABILITY_CONTAINER_ID 0x04
14438 +typedef struct usb_dev_cap_container_id {
14439 + uByte bLength;
14440 + uByte bDescriptorType;
14441 + uByte bDevCapabilityType;
14442 + uByte bReserved;
14443 + uByte containerID[16];
14444 +} UPACKED usb_dev_cap_container_id_t;
14445 +
14446 +/* Device Capability Type Codes */
14447 +#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
14448 +
14449 +/* Device Capability Descriptor */
14450 +typedef struct wusb_dev_cap_desc {
14451 + uByte bLength;
14452 + uByte bDescriptorType;
14453 + uByte bDevCapabilityType;
14454 + uByte caps[1]; /* Variable length */
14455 +} UPACKED wusb_dev_cap_desc_t;
14456 +
14457 +/* Device Capability Descriptor */
14458 +typedef struct wusb_dev_cap_uwb_desc {
14459 + uByte bLength;
14460 + uByte bDescriptorType;
14461 + uByte bDevCapabilityType;
14462 + uByte bmAttributes;
14463 + uWord wPHYRates; /* Bitmap */
14464 + uByte bmTFITXPowerInfo;
14465 + uByte bmFFITXPowerInfo;
14466 + uWord bmBandGroup;
14467 + uByte bReserved;
14468 +} UPACKED wusb_dev_cap_uwb_desc_t;
14469 +
14470 +/* Wireless USB Endpoint Companion Descriptor */
14471 +typedef struct wusb_endpoint_companion_desc {
14472 + uByte bLength;
14473 + uByte bDescriptorType;
14474 + uByte bMaxBurst;
14475 + uByte bMaxSequence;
14476 + uWord wMaxStreamDelay;
14477 + uWord wOverTheAirPacketSize;
14478 + uByte bOverTheAirInterval;
14479 + uByte bmCompAttributes;
14480 +} UPACKED wusb_endpoint_companion_desc_t;
14481 +
14482 +/* Wireless USB Numeric Association M1 Data Structure */
14483 +typedef struct wusb_m1_data {
14484 + uByte version;
14485 + uWord langId;
14486 + uByte deviceFriendlyNameLength;
14487 + uByte sha_256_m3[32];
14488 + uByte deviceFriendlyName[256];
14489 +} UPACKED wusb_m1_data_t;
14490 +
14491 +typedef struct wusb_m2_data {
14492 + uByte version;
14493 + uWord langId;
14494 + uByte hostFriendlyNameLength;
14495 + uByte pkh[384];
14496 + uByte hostFriendlyName[256];
14497 +} UPACKED wusb_m2_data_t;
14498 +
14499 +typedef struct wusb_m3_data {
14500 + uByte pkd[384];
14501 + uByte nd;
14502 +} UPACKED wusb_m3_data_t;
14503 +
14504 +typedef struct wusb_m4_data {
14505 + uDWord _attributeTypeIdAndLength_1;
14506 + uWord associationTypeId;
14507 +
14508 + uDWord _attributeTypeIdAndLength_2;
14509 + uWord associationSubTypeId;
14510 +
14511 + uDWord _attributeTypeIdAndLength_3;
14512 + uDWord length;
14513 +
14514 + uDWord _attributeTypeIdAndLength_4;
14515 + uDWord associationStatus;
14516 +
14517 + uDWord _attributeTypeIdAndLength_5;
14518 + uByte chid[16];
14519 +
14520 + uDWord _attributeTypeIdAndLength_6;
14521 + uByte cdid[16];
14522 +
14523 + uDWord _attributeTypeIdAndLength_7;
14524 + uByte bandGroups[2];
14525 +} UPACKED wusb_m4_data_t;
14526 +
14527 +#ifdef _MSC_VER
14528 +#include <poppack.h>
14529 +#endif
14530 +
14531 +#ifdef __cplusplus
14532 +}
14533 +#endif
14534 +
14535 +#endif /* _USB_H_ */
14536 --- /dev/null
14537 +++ b/drivers/usb/host/dwc_otg/Makefile
14538 @@ -0,0 +1,80 @@
14539 +#
14540 +# Makefile for DWC_otg Highspeed USB controller driver
14541 +#
14542 +
14543 +ifneq ($(KERNELRELEASE),)
14544 +
14545 +# Use the BUS_INTERFACE variable to compile the software for either
14546 +# PCI(PCI_INTERFACE) or LM(LM_INTERFACE) bus.
14547 +ifeq ($(BUS_INTERFACE),)
14548 +# BUS_INTERFACE = -DPCI_INTERFACE
14549 +# BUS_INTERFACE = -DLM_INTERFACE
14550 + BUS_INTERFACE = -DPLATFORM_INTERFACE
14551 +endif
14552 +
14553 +#EXTRA_CFLAGS += -DDEBUG
14554 +#EXTRA_CFLAGS += -DDWC_OTG_DEBUGLEV=1 # reduce common debug msgs
14555 +
14556 +# Use one of the following flags to compile the software in host-only or
14557 +# device-only mode.
14558 +#EXTRA_CFLAGS += -DDWC_HOST_ONLY
14559 +#EXTRA_CFLAGS += -DDWC_DEVICE_ONLY
14560 +
14561 +EXTRA_CFLAGS += -Dlinux -DDWC_HS_ELECT_TST
14562 +#EXTRA_CFLAGS += -DDWC_EN_ISOC
14563 +EXTRA_CFLAGS += -I$(obj)/../dwc_common_port
14564 +#EXTRA_CFLAGS += -I$(PORTLIB)
14565 +EXTRA_CFLAGS += -DDWC_LINUX
14566 +EXTRA_CFLAGS += $(CFI)
14567 +EXTRA_CFLAGS += $(BUS_INTERFACE)
14568 +#EXTRA_CFLAGS += -DDWC_DEV_SRPCAP
14569 +
14570 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o
14571 +
14572 +dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o
14573 +dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
14574 +dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o
14575 +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
14576 +dwc_otg-objs += dwc_otg_adp.o
14577 +ifneq ($(CFI),)
14578 +dwc_otg-objs += dwc_otg_cfi.o
14579 +endif
14580 +
14581 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
14582 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
14583 +
14584 +ifneq ($(kernrel3),2.6.20)
14585 +EXTRA_CFLAGS += $(CPPFLAGS)
14586 +endif
14587 +
14588 +else
14589 +
14590 +PWD := $(shell pwd)
14591 +PORTLIB := $(PWD)/../dwc_common_port
14592 +
14593 +# Command paths
14594 +CTAGS := $(CTAGS)
14595 +DOXYGEN := $(DOXYGEN)
14596 +
14597 +default: portlib
14598 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
14599 +
14600 +install: default
14601 + $(MAKE) -C$(KDIR) M=$(PORTLIB) modules_install
14602 + $(MAKE) -C$(KDIR) M=$(PWD) modules_install
14603 +
14604 +portlib:
14605 + $(MAKE) -C$(KDIR) M=$(PORTLIB) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
14606 + cp $(PORTLIB)/Module.symvers $(PWD)/
14607 +
14608 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
14609 + $(DOXYGEN) doc/doxygen.cfg
14610 +
14611 +tags: $(wildcard *.[hc])
14612 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
14613 +
14614 +
14615 +clean:
14616 + rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers
14617 +
14618 +endif
14619 --- /dev/null
14620 +++ b/drivers/usb/host/dwc_otg/doc/doxygen.cfg
14621 @@ -0,0 +1,224 @@
14622 +# Doxyfile 1.3.9.1
14623 +
14624 +#---------------------------------------------------------------------------
14625 +# Project related configuration options
14626 +#---------------------------------------------------------------------------
14627 +PROJECT_NAME = "DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver"
14628 +PROJECT_NUMBER = v3.00a
14629 +OUTPUT_DIRECTORY = ./doc/
14630 +CREATE_SUBDIRS = NO
14631 +OUTPUT_LANGUAGE = English
14632 +BRIEF_MEMBER_DESC = YES
14633 +REPEAT_BRIEF = YES
14634 +ABBREVIATE_BRIEF = "The $name class" \
14635 + "The $name widget" \
14636 + "The $name file" \
14637 + is \
14638 + provides \
14639 + specifies \
14640 + contains \
14641 + represents \
14642 + a \
14643 + an \
14644 + the
14645 +ALWAYS_DETAILED_SEC = NO
14646 +INLINE_INHERITED_MEMB = NO
14647 +FULL_PATH_NAMES = NO
14648 +STRIP_FROM_PATH =
14649 +STRIP_FROM_INC_PATH =
14650 +SHORT_NAMES = NO
14651 +JAVADOC_AUTOBRIEF = YES
14652 +MULTILINE_CPP_IS_BRIEF = NO
14653 +INHERIT_DOCS = YES
14654 +DISTRIBUTE_GROUP_DOC = NO
14655 +TAB_SIZE = 8
14656 +ALIASES =
14657 +OPTIMIZE_OUTPUT_FOR_C = YES
14658 +OPTIMIZE_OUTPUT_JAVA = NO
14659 +SUBGROUPING = YES
14660 +#---------------------------------------------------------------------------
14661 +# Build related configuration options
14662 +#---------------------------------------------------------------------------
14663 +EXTRACT_ALL = NO
14664 +EXTRACT_PRIVATE = YES
14665 +EXTRACT_STATIC = YES
14666 +EXTRACT_LOCAL_CLASSES = YES
14667 +EXTRACT_LOCAL_METHODS = NO
14668 +HIDE_UNDOC_MEMBERS = NO
14669 +HIDE_UNDOC_CLASSES = NO
14670 +HIDE_FRIEND_COMPOUNDS = NO
14671 +HIDE_IN_BODY_DOCS = NO
14672 +INTERNAL_DOCS = NO
14673 +CASE_SENSE_NAMES = NO
14674 +HIDE_SCOPE_NAMES = NO
14675 +SHOW_INCLUDE_FILES = YES
14676 +INLINE_INFO = YES
14677 +SORT_MEMBER_DOCS = NO
14678 +SORT_BRIEF_DOCS = NO
14679 +SORT_BY_SCOPE_NAME = NO
14680 +GENERATE_TODOLIST = YES
14681 +GENERATE_TESTLIST = YES
14682 +GENERATE_BUGLIST = YES
14683 +GENERATE_DEPRECATEDLIST= YES
14684 +ENABLED_SECTIONS =
14685 +MAX_INITIALIZER_LINES = 30
14686 +SHOW_USED_FILES = YES
14687 +SHOW_DIRECTORIES = YES
14688 +#---------------------------------------------------------------------------
14689 +# configuration options related to warning and progress messages
14690 +#---------------------------------------------------------------------------
14691 +QUIET = YES
14692 +WARNINGS = YES
14693 +WARN_IF_UNDOCUMENTED = NO
14694 +WARN_IF_DOC_ERROR = YES
14695 +WARN_FORMAT = "$file:$line: $text"
14696 +WARN_LOGFILE =
14697 +#---------------------------------------------------------------------------
14698 +# configuration options related to the input files
14699 +#---------------------------------------------------------------------------
14700 +INPUT = .
14701 +FILE_PATTERNS = *.c \
14702 + *.h \
14703 + ./linux/*.c \
14704 + ./linux/*.h
14705 +RECURSIVE = NO
14706 +EXCLUDE = ./test/ \
14707 + ./dwc_otg/.AppleDouble/
14708 +EXCLUDE_SYMLINKS = YES
14709 +EXCLUDE_PATTERNS = *.mod.*
14710 +EXAMPLE_PATH =
14711 +EXAMPLE_PATTERNS = *
14712 +EXAMPLE_RECURSIVE = NO
14713 +IMAGE_PATH =
14714 +INPUT_FILTER =
14715 +FILTER_PATTERNS =
14716 +FILTER_SOURCE_FILES = NO
14717 +#---------------------------------------------------------------------------
14718 +# configuration options related to source browsing
14719 +#---------------------------------------------------------------------------
14720 +SOURCE_BROWSER = YES
14721 +INLINE_SOURCES = NO
14722 +STRIP_CODE_COMMENTS = YES
14723 +REFERENCED_BY_RELATION = NO
14724 +REFERENCES_RELATION = NO
14725 +VERBATIM_HEADERS = NO
14726 +#---------------------------------------------------------------------------
14727 +# configuration options related to the alphabetical class index
14728 +#---------------------------------------------------------------------------
14729 +ALPHABETICAL_INDEX = NO
14730 +COLS_IN_ALPHA_INDEX = 5
14731 +IGNORE_PREFIX =
14732 +#---------------------------------------------------------------------------
14733 +# configuration options related to the HTML output
14734 +#---------------------------------------------------------------------------
14735 +GENERATE_HTML = YES
14736 +HTML_OUTPUT = html
14737 +HTML_FILE_EXTENSION = .html
14738 +HTML_HEADER =
14739 +HTML_FOOTER =
14740 +HTML_STYLESHEET =
14741 +HTML_ALIGN_MEMBERS = YES
14742 +GENERATE_HTMLHELP = NO
14743 +CHM_FILE =
14744 +HHC_LOCATION =
14745 +GENERATE_CHI = NO
14746 +BINARY_TOC = NO
14747 +TOC_EXPAND = NO
14748 +DISABLE_INDEX = NO
14749 +ENUM_VALUES_PER_LINE = 4
14750 +GENERATE_TREEVIEW = YES
14751 +TREEVIEW_WIDTH = 250
14752 +#---------------------------------------------------------------------------
14753 +# configuration options related to the LaTeX output
14754 +#---------------------------------------------------------------------------
14755 +GENERATE_LATEX = NO
14756 +LATEX_OUTPUT = latex
14757 +LATEX_CMD_NAME = latex
14758 +MAKEINDEX_CMD_NAME = makeindex
14759 +COMPACT_LATEX = NO
14760 +PAPER_TYPE = a4wide
14761 +EXTRA_PACKAGES =
14762 +LATEX_HEADER =
14763 +PDF_HYPERLINKS = NO
14764 +USE_PDFLATEX = NO
14765 +LATEX_BATCHMODE = NO
14766 +LATEX_HIDE_INDICES = NO
14767 +#---------------------------------------------------------------------------
14768 +# configuration options related to the RTF output
14769 +#---------------------------------------------------------------------------
14770 +GENERATE_RTF = NO
14771 +RTF_OUTPUT = rtf
14772 +COMPACT_RTF = NO
14773 +RTF_HYPERLINKS = NO
14774 +RTF_STYLESHEET_FILE =
14775 +RTF_EXTENSIONS_FILE =
14776 +#---------------------------------------------------------------------------
14777 +# configuration options related to the man page output
14778 +#---------------------------------------------------------------------------
14779 +GENERATE_MAN = NO
14780 +MAN_OUTPUT = man
14781 +MAN_EXTENSION = .3
14782 +MAN_LINKS = NO
14783 +#---------------------------------------------------------------------------
14784 +# configuration options related to the XML output
14785 +#---------------------------------------------------------------------------
14786 +GENERATE_XML = NO
14787 +XML_OUTPUT = xml
14788 +XML_SCHEMA =
14789 +XML_DTD =
14790 +XML_PROGRAMLISTING = YES
14791 +#---------------------------------------------------------------------------
14792 +# configuration options for the AutoGen Definitions output
14793 +#---------------------------------------------------------------------------
14794 +GENERATE_AUTOGEN_DEF = NO
14795 +#---------------------------------------------------------------------------
14796 +# configuration options related to the Perl module output
14797 +#---------------------------------------------------------------------------
14798 +GENERATE_PERLMOD = NO
14799 +PERLMOD_LATEX = NO
14800 +PERLMOD_PRETTY = YES
14801 +PERLMOD_MAKEVAR_PREFIX =
14802 +#---------------------------------------------------------------------------
14803 +# Configuration options related to the preprocessor
14804 +#---------------------------------------------------------------------------
14805 +ENABLE_PREPROCESSING = YES
14806 +MACRO_EXPANSION = YES
14807 +EXPAND_ONLY_PREDEF = YES
14808 +SEARCH_INCLUDES = YES
14809 +INCLUDE_PATH =
14810 +INCLUDE_FILE_PATTERNS =
14811 +PREDEFINED = DEVICE_ATTR DWC_EN_ISOC
14812 +EXPAND_AS_DEFINED = DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW DWC_OTG_DEVICE_ATTR_BITFIELD_STORE DWC_OTG_DEVICE_ATTR_BITFIELD_RW DWC_OTG_DEVICE_ATTR_BITFIELD_RO DWC_OTG_DEVICE_ATTR_REG_SHOW DWC_OTG_DEVICE_ATTR_REG_STORE DWC_OTG_DEVICE_ATTR_REG32_RW DWC_OTG_DEVICE_ATTR_REG32_RO DWC_EN_ISOC
14813 +SKIP_FUNCTION_MACROS = NO
14814 +#---------------------------------------------------------------------------
14815 +# Configuration::additions related to external references
14816 +#---------------------------------------------------------------------------
14817 +TAGFILES =
14818 +GENERATE_TAGFILE =
14819 +ALLEXTERNALS = NO
14820 +EXTERNAL_GROUPS = YES
14821 +PERL_PATH = /usr/bin/perl
14822 +#---------------------------------------------------------------------------
14823 +# Configuration options related to the dot tool
14824 +#---------------------------------------------------------------------------
14825 +CLASS_DIAGRAMS = YES
14826 +HIDE_UNDOC_RELATIONS = YES
14827 +HAVE_DOT = NO
14828 +CLASS_GRAPH = YES
14829 +COLLABORATION_GRAPH = YES
14830 +UML_LOOK = NO
14831 +TEMPLATE_RELATIONS = NO
14832 +INCLUDE_GRAPH = YES
14833 +INCLUDED_BY_GRAPH = YES
14834 +CALL_GRAPH = NO
14835 +GRAPHICAL_HIERARCHY = YES
14836 +DOT_IMAGE_FORMAT = png
14837 +DOT_PATH =
14838 +DOTFILE_DIRS =
14839 +MAX_DOT_GRAPH_DEPTH = 1000
14840 +GENERATE_LEGEND = YES
14841 +DOT_CLEANUP = YES
14842 +#---------------------------------------------------------------------------
14843 +# Configuration::additions related to the search engine
14844 +#---------------------------------------------------------------------------
14845 +SEARCHENGINE = NO
14846 --- /dev/null
14847 +++ b/drivers/usb/host/dwc_otg/dummy_audio.c
14848 @@ -0,0 +1,1575 @@
14849 +/*
14850 + * zero.c -- Gadget Zero, for USB development
14851 + *
14852 + * Copyright (C) 2003-2004 David Brownell
14853 + * All rights reserved.
14854 + *
14855 + * Redistribution and use in source and binary forms, with or without
14856 + * modification, are permitted provided that the following conditions
14857 + * are met:
14858 + * 1. Redistributions of source code must retain the above copyright
14859 + * notice, this list of conditions, and the following disclaimer,
14860 + * without modification.
14861 + * 2. Redistributions in binary form must reproduce the above copyright
14862 + * notice, this list of conditions and the following disclaimer in the
14863 + * documentation and/or other materials provided with the distribution.
14864 + * 3. The names of the above-listed copyright holders may not be used
14865 + * to endorse or promote products derived from this software without
14866 + * specific prior written permission.
14867 + *
14868 + * ALTERNATIVELY, this software may be distributed under the terms of the
14869 + * GNU General Public License ("GPL") as published by the Free Software
14870 + * Foundation, either version 2 of that License or (at your option) any
14871 + * later version.
14872 + *
14873 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
14874 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14875 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14876 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
14877 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
14878 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
14879 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
14880 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
14881 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
14882 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
14883 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14884 + */
14885 +
14886 +
14887 +/*
14888 + * Gadget Zero only needs two bulk endpoints, and is an example of how you
14889 + * can write a hardware-agnostic gadget driver running inside a USB device.
14890 + *
14891 + * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
14892 + * affect most of the driver.
14893 + *
14894 + * Use it with the Linux host/master side "usbtest" driver to get a basic
14895 + * functional test of your device-side usb stack, or with "usb-skeleton".
14896 + *
14897 + * It supports two similar configurations. One sinks whatever the usb host
14898 + * writes, and in return sources zeroes. The other loops whatever the host
14899 + * writes back, so the host can read it. Module options include:
14900 + *
14901 + * buflen=N default N=4096, buffer size used
14902 + * qlen=N default N=32, how many buffers in the loopback queue
14903 + * loopdefault default false, list loopback config first
14904 + *
14905 + * Many drivers will only have one configuration, letting them be much
14906 + * simpler if they also don't support high speed operation (like this
14907 + * driver does).
14908 + */
14909 +
14910 +#include <linux/config.h>
14911 +#include <linux/module.h>
14912 +#include <linux/kernel.h>
14913 +#include <linux/delay.h>
14914 +#include <linux/ioport.h>
14915 +#include <linux/sched.h>
14916 +#include <linux/slab.h>
14917 +#include <linux/smp_lock.h>
14918 +#include <linux/errno.h>
14919 +#include <linux/init.h>
14920 +#include <linux/timer.h>
14921 +#include <linux/list.h>
14922 +#include <linux/interrupt.h>
14923 +#include <linux/uts.h>
14924 +#include <linux/version.h>
14925 +#include <linux/device.h>
14926 +#include <linux/moduleparam.h>
14927 +#include <linux/proc_fs.h>
14928 +
14929 +#include <asm/byteorder.h>
14930 +#include <asm/io.h>
14931 +#include <asm/irq.h>
14932 +#include <asm/system.h>
14933 +#include <asm/unaligned.h>
14934 +
14935 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
14936 +# include <linux/usb/ch9.h>
14937 +#else
14938 +# include <linux/usb_ch9.h>
14939 +#endif
14940 +
14941 +#include <linux/usb_gadget.h>
14942 +
14943 +
14944 +/*-------------------------------------------------------------------------*/
14945 +/*-------------------------------------------------------------------------*/
14946 +
14947 +
14948 +static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
14949 +{
14950 + int count = 0;
14951 + u8 c;
14952 + u16 uchar;
14953 +
14954 + /* this insists on correct encodings, though not minimal ones.
14955 + * BUT it currently rejects legit 4-byte UTF-8 code points,
14956 + * which need surrogate pairs. (Unicode 3.1 can use them.)
14957 + */
14958 + while (len != 0 && (c = (u8) *s++) != 0) {
14959 + if (unlikely(c & 0x80)) {
14960 + // 2-byte sequence:
14961 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
14962 + if ((c & 0xe0) == 0xc0) {
14963 + uchar = (c & 0x1f) << 6;
14964 +
14965 + c = (u8) *s++;
14966 + if ((c & 0xc0) != 0xc0)
14967 + goto fail;
14968 + c &= 0x3f;
14969 + uchar |= c;
14970 +
14971 + // 3-byte sequence (most CJKV characters):
14972 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
14973 + } else if ((c & 0xf0) == 0xe0) {
14974 + uchar = (c & 0x0f) << 12;
14975 +
14976 + c = (u8) *s++;
14977 + if ((c & 0xc0) != 0xc0)
14978 + goto fail;
14979 + c &= 0x3f;
14980 + uchar |= c << 6;
14981 +
14982 + c = (u8) *s++;
14983 + if ((c & 0xc0) != 0xc0)
14984 + goto fail;
14985 + c &= 0x3f;
14986 + uchar |= c;
14987 +
14988 + /* no bogus surrogates */
14989 + if (0xd800 <= uchar && uchar <= 0xdfff)
14990 + goto fail;
14991 +
14992 + // 4-byte sequence (surrogate pairs, currently rare):
14993 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
14994 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
14995 + // (uuuuu = wwww + 1)
14996 + // FIXME accept the surrogate code points (only)
14997 +
14998 + } else
14999 + goto fail;
15000 + } else
15001 + uchar = c;
15002 + put_unaligned (cpu_to_le16 (uchar), cp++);
15003 + count++;
15004 + len--;
15005 + }
15006 + return count;
15007 +fail:
15008 + return -1;
15009 +}
15010 +
15011 +
15012 +/**
15013 + * usb_gadget_get_string - fill out a string descriptor
15014 + * @table: of c strings encoded using UTF-8
15015 + * @id: string id, from low byte of wValue in get string descriptor
15016 + * @buf: at least 256 bytes
15017 + *
15018 + * Finds the UTF-8 string matching the ID, and converts it into a
15019 + * string descriptor in utf16-le.
15020 + * Returns length of descriptor (always even) or negative errno
15021 + *
15022 + * If your driver needs stings in multiple languages, you'll probably
15023 + * "switch (wIndex) { ... }" in your ep0 string descriptor logic,
15024 + * using this routine after choosing which set of UTF-8 strings to use.
15025 + * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
15026 + * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
15027 + * characters (which are also widely used in C strings).
15028 + */
15029 +int
15030 +usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
15031 +{
15032 + struct usb_string *s;
15033 + int len;
15034 +
15035 + /* descriptor 0 has the language id */
15036 + if (id == 0) {
15037 + buf [0] = 4;
15038 + buf [1] = USB_DT_STRING;
15039 + buf [2] = (u8) table->language;
15040 + buf [3] = (u8) (table->language >> 8);
15041 + return 4;
15042 + }
15043 + for (s = table->strings; s && s->s; s++)
15044 + if (s->id == id)
15045 + break;
15046 +
15047 + /* unrecognized: stall. */
15048 + if (!s || !s->s)
15049 + return -EINVAL;
15050 +
15051 + /* string descriptors have length, tag, then UTF16-LE text */
15052 + len = min ((size_t) 126, strlen (s->s));
15053 + memset (buf + 2, 0, 2 * len); /* zero all the bytes */
15054 + len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
15055 + if (len < 0)
15056 + return -EINVAL;
15057 + buf [0] = (len + 1) * 2;
15058 + buf [1] = USB_DT_STRING;
15059 + return buf [0];
15060 +}
15061 +
15062 +
15063 +/*-------------------------------------------------------------------------*/
15064 +/*-------------------------------------------------------------------------*/
15065 +
15066 +
15067 +/**
15068 + * usb_descriptor_fillbuf - fill buffer with descriptors
15069 + * @buf: Buffer to be filled
15070 + * @buflen: Size of buf
15071 + * @src: Array of descriptor pointers, terminated by null pointer.
15072 + *
15073 + * Copies descriptors into the buffer, returning the length or a
15074 + * negative error code if they can't all be copied. Useful when
15075 + * assembling descriptors for an associated set of interfaces used
15076 + * as part of configuring a composite device; or in other cases where
15077 + * sets of descriptors need to be marshaled.
15078 + */
15079 +int
15080 +usb_descriptor_fillbuf(void *buf, unsigned buflen,
15081 + const struct usb_descriptor_header **src)
15082 +{
15083 + u8 *dest = buf;
15084 +
15085 + if (!src)
15086 + return -EINVAL;
15087 +
15088 + /* fill buffer from src[] until null descriptor ptr */
15089 + for (; 0 != *src; src++) {
15090 + unsigned len = (*src)->bLength;
15091 +
15092 + if (len > buflen)
15093 + return -EINVAL;
15094 + memcpy(dest, *src, len);
15095 + buflen -= len;
15096 + dest += len;
15097 + }
15098 + return dest - (u8 *)buf;
15099 +}
15100 +
15101 +
15102 +/**
15103 + * usb_gadget_config_buf - builts a complete configuration descriptor
15104 + * @config: Header for the descriptor, including characteristics such
15105 + * as power requirements and number of interfaces.
15106 + * @desc: Null-terminated vector of pointers to the descriptors (interface,
15107 + * endpoint, etc) defining all functions in this device configuration.
15108 + * @buf: Buffer for the resulting configuration descriptor.
15109 + * @length: Length of buffer. If this is not big enough to hold the
15110 + * entire configuration descriptor, an error code will be returned.
15111 + *
15112 + * This copies descriptors into the response buffer, building a descriptor
15113 + * for that configuration. It returns the buffer length or a negative
15114 + * status code. The config.wTotalLength field is set to match the length
15115 + * of the result, but other descriptor fields (including power usage and
15116 + * interface count) must be set by the caller.
15117 + *
15118 + * Gadget drivers could use this when constructing a config descriptor
15119 + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
15120 + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
15121 + */
15122 +int usb_gadget_config_buf(
15123 + const struct usb_config_descriptor *config,
15124 + void *buf,
15125 + unsigned length,
15126 + const struct usb_descriptor_header **desc
15127 +)
15128 +{
15129 + struct usb_config_descriptor *cp = buf;
15130 + int len;
15131 +
15132 + /* config descriptor first */
15133 + if (length < USB_DT_CONFIG_SIZE || !desc)
15134 + return -EINVAL;
15135 + *cp = *config;
15136 +
15137 + /* then interface/endpoint/class/vendor/... */
15138 + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
15139 + length - USB_DT_CONFIG_SIZE, desc);
15140 + if (len < 0)
15141 + return len;
15142 + len += USB_DT_CONFIG_SIZE;
15143 + if (len > 0xffff)
15144 + return -EINVAL;
15145 +
15146 + /* patch up the config descriptor */
15147 + cp->bLength = USB_DT_CONFIG_SIZE;
15148 + cp->bDescriptorType = USB_DT_CONFIG;
15149 + cp->wTotalLength = cpu_to_le16(len);
15150 + cp->bmAttributes |= USB_CONFIG_ATT_ONE;
15151 + return len;
15152 +}
15153 +
15154 +/*-------------------------------------------------------------------------*/
15155 +/*-------------------------------------------------------------------------*/
15156 +
15157 +
15158 +#define RBUF_LEN (1024*1024)
15159 +static int rbuf_start;
15160 +static int rbuf_len;
15161 +static __u8 rbuf[RBUF_LEN];
15162 +
15163 +/*-------------------------------------------------------------------------*/
15164 +
15165 +#define DRIVER_VERSION "St Patrick's Day 2004"
15166 +
15167 +static const char shortname [] = "zero";
15168 +static const char longname [] = "YAMAHA YST-MS35D USB Speaker ";
15169 +
15170 +static const char source_sink [] = "source and sink data";
15171 +static const char loopback [] = "loop input to output";
15172 +
15173 +/*-------------------------------------------------------------------------*/
15174 +
15175 +/*
15176 + * driver assumes self-powered hardware, and
15177 + * has no way for users to trigger remote wakeup.
15178 + *
15179 + * this version autoconfigures as much as possible,
15180 + * which is reasonable for most "bulk-only" drivers.
15181 + */
15182 +static const char *EP_IN_NAME; /* source */
15183 +static const char *EP_OUT_NAME; /* sink */
15184 +
15185 +/*-------------------------------------------------------------------------*/
15186 +
15187 +/* big enough to hold our biggest descriptor */
15188 +#define USB_BUFSIZ 512
15189 +
15190 +struct zero_dev {
15191 + spinlock_t lock;
15192 + struct usb_gadget *gadget;
15193 + struct usb_request *req; /* for control responses */
15194 +
15195 + /* when configured, we have one of two configs:
15196 + * - source data (in to host) and sink it (out from host)
15197 + * - or loop it back (out from host back in to host)
15198 + */
15199 + u8 config;
15200 + struct usb_ep *in_ep, *out_ep;
15201 +
15202 + /* autoresume timer */
15203 + struct timer_list resume;
15204 +};
15205 +
15206 +#define xprintk(d,level,fmt,args...) \
15207 + dev_printk(level , &(d)->gadget->dev , fmt , ## args)
15208 +
15209 +#ifdef DEBUG
15210 +#define DBG(dev,fmt,args...) \
15211 + xprintk(dev , KERN_DEBUG , fmt , ## args)
15212 +#else
15213 +#define DBG(dev,fmt,args...) \
15214 + do { } while (0)
15215 +#endif /* DEBUG */
15216 +
15217 +#ifdef VERBOSE
15218 +#define VDBG DBG
15219 +#else
15220 +#define VDBG(dev,fmt,args...) \
15221 + do { } while (0)
15222 +#endif /* VERBOSE */
15223 +
15224 +#define ERROR(dev,fmt,args...) \
15225 + xprintk(dev , KERN_ERR , fmt , ## args)
15226 +#define WARN(dev,fmt,args...) \
15227 + xprintk(dev , KERN_WARNING , fmt , ## args)
15228 +#define INFO(dev,fmt,args...) \
15229 + xprintk(dev , KERN_INFO , fmt , ## args)
15230 +
15231 +/*-------------------------------------------------------------------------*/
15232 +
15233 +static unsigned buflen = 4096;
15234 +static unsigned qlen = 32;
15235 +static unsigned pattern = 0;
15236 +
15237 +module_param (buflen, uint, S_IRUGO|S_IWUSR);
15238 +module_param (qlen, uint, S_IRUGO|S_IWUSR);
15239 +module_param (pattern, uint, S_IRUGO|S_IWUSR);
15240 +
15241 +/*
15242 + * if it's nonzero, autoresume says how many seconds to wait
15243 + * before trying to wake up the host after suspend.
15244 + */
15245 +static unsigned autoresume = 0;
15246 +module_param (autoresume, uint, 0);
15247 +
15248 +/*
15249 + * Normally the "loopback" configuration is second (index 1) so
15250 + * it's not the default. Here's where to change that order, to
15251 + * work better with hosts where config changes are problematic.
15252 + * Or controllers (like superh) that only support one config.
15253 + */
15254 +static int loopdefault = 0;
15255 +
15256 +module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
15257 +
15258 +/*-------------------------------------------------------------------------*/
15259 +
15260 +/* Thanks to NetChip Technologies for donating this product ID.
15261 + *
15262 + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
15263 + * Instead: allocate your own, using normal USB-IF procedures.
15264 + */
15265 +#ifndef CONFIG_USB_ZERO_HNPTEST
15266 +#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
15267 +#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
15268 +#else
15269 +#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
15270 +#define DRIVER_PRODUCT_NUM 0xbadd
15271 +#endif
15272 +
15273 +/*-------------------------------------------------------------------------*/
15274 +
15275 +/*
15276 + * DESCRIPTORS ... most are static, but strings and (full)
15277 + * configuration descriptors are built on demand.
15278 + */
15279 +
15280 +/*
15281 +#define STRING_MANUFACTURER 25
15282 +#define STRING_PRODUCT 42
15283 +#define STRING_SERIAL 101
15284 +*/
15285 +#define STRING_MANUFACTURER 1
15286 +#define STRING_PRODUCT 2
15287 +#define STRING_SERIAL 3
15288 +
15289 +#define STRING_SOURCE_SINK 250
15290 +#define STRING_LOOPBACK 251
15291 +
15292 +/*
15293 + * This device advertises two configurations; these numbers work
15294 + * on a pxa250 as well as more flexible hardware.
15295 + */
15296 +#define CONFIG_SOURCE_SINK 3
15297 +#define CONFIG_LOOPBACK 2
15298 +
15299 +/*
15300 +static struct usb_device_descriptor
15301 +device_desc = {
15302 + .bLength = sizeof device_desc,
15303 + .bDescriptorType = USB_DT_DEVICE,
15304 +
15305 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
15306 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
15307 +
15308 + .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
15309 + .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
15310 + .iManufacturer = STRING_MANUFACTURER,
15311 + .iProduct = STRING_PRODUCT,
15312 + .iSerialNumber = STRING_SERIAL,
15313 + .bNumConfigurations = 2,
15314 +};
15315 +*/
15316 +static struct usb_device_descriptor
15317 +device_desc = {
15318 + .bLength = sizeof device_desc,
15319 + .bDescriptorType = USB_DT_DEVICE,
15320 + .bcdUSB = __constant_cpu_to_le16 (0x0100),
15321 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
15322 + .bDeviceSubClass = 0,
15323 + .bDeviceProtocol = 0,
15324 + .bMaxPacketSize0 = 64,
15325 + .bcdDevice = __constant_cpu_to_le16 (0x0100),
15326 + .idVendor = __constant_cpu_to_le16 (0x0499),
15327 + .idProduct = __constant_cpu_to_le16 (0x3002),
15328 + .iManufacturer = STRING_MANUFACTURER,
15329 + .iProduct = STRING_PRODUCT,
15330 + .iSerialNumber = STRING_SERIAL,
15331 + .bNumConfigurations = 1,
15332 +};
15333 +
15334 +static struct usb_config_descriptor
15335 +z_config = {
15336 + .bLength = sizeof z_config,
15337 + .bDescriptorType = USB_DT_CONFIG,
15338 +
15339 + /* compute wTotalLength on the fly */
15340 + .bNumInterfaces = 2,
15341 + .bConfigurationValue = 1,
15342 + .iConfiguration = 0,
15343 + .bmAttributes = 0x40,
15344 + .bMaxPower = 0, /* self-powered */
15345 +};
15346 +
15347 +
15348 +static struct usb_otg_descriptor
15349 +otg_descriptor = {
15350 + .bLength = sizeof otg_descriptor,
15351 + .bDescriptorType = USB_DT_OTG,
15352 +
15353 + .bmAttributes = USB_OTG_SRP,
15354 +};
15355 +
15356 +/* one interface in each configuration */
15357 +#ifdef CONFIG_USB_GADGET_DUALSPEED
15358 +
15359 +/*
15360 + * usb 2.0 devices need to expose both high speed and full speed
15361 + * descriptors, unless they only run at full speed.
15362 + *
15363 + * that means alternate endpoint descriptors (bigger packets)
15364 + * and a "device qualifier" ... plus more construction options
15365 + * for the config descriptor.
15366 + */
15367 +
15368 +static struct usb_qualifier_descriptor
15369 +dev_qualifier = {
15370 + .bLength = sizeof dev_qualifier,
15371 + .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
15372 +
15373 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
15374 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
15375 +
15376 + .bNumConfigurations = 2,
15377 +};
15378 +
15379 +
15380 +struct usb_cs_as_general_descriptor {
15381 + __u8 bLength;
15382 + __u8 bDescriptorType;
15383 +
15384 + __u8 bDescriptorSubType;
15385 + __u8 bTerminalLink;
15386 + __u8 bDelay;
15387 + __u16 wFormatTag;
15388 +} __attribute__ ((packed));
15389 +
15390 +struct usb_cs_as_format_descriptor {
15391 + __u8 bLength;
15392 + __u8 bDescriptorType;
15393 +
15394 + __u8 bDescriptorSubType;
15395 + __u8 bFormatType;
15396 + __u8 bNrChannels;
15397 + __u8 bSubframeSize;
15398 + __u8 bBitResolution;
15399 + __u8 bSamfreqType;
15400 + __u8 tLowerSamFreq[3];
15401 + __u8 tUpperSamFreq[3];
15402 +} __attribute__ ((packed));
15403 +
15404 +static const struct usb_interface_descriptor
15405 +z_audio_control_if_desc = {
15406 + .bLength = sizeof z_audio_control_if_desc,
15407 + .bDescriptorType = USB_DT_INTERFACE,
15408 + .bInterfaceNumber = 0,
15409 + .bAlternateSetting = 0,
15410 + .bNumEndpoints = 0,
15411 + .bInterfaceClass = USB_CLASS_AUDIO,
15412 + .bInterfaceSubClass = 0x1,
15413 + .bInterfaceProtocol = 0,
15414 + .iInterface = 0,
15415 +};
15416 +
15417 +static const struct usb_interface_descriptor
15418 +z_audio_if_desc = {
15419 + .bLength = sizeof z_audio_if_desc,
15420 + .bDescriptorType = USB_DT_INTERFACE,
15421 + .bInterfaceNumber = 1,
15422 + .bAlternateSetting = 0,
15423 + .bNumEndpoints = 0,
15424 + .bInterfaceClass = USB_CLASS_AUDIO,
15425 + .bInterfaceSubClass = 0x2,
15426 + .bInterfaceProtocol = 0,
15427 + .iInterface = 0,
15428 +};
15429 +
15430 +static const struct usb_interface_descriptor
15431 +z_audio_if_desc2 = {
15432 + .bLength = sizeof z_audio_if_desc,
15433 + .bDescriptorType = USB_DT_INTERFACE,
15434 + .bInterfaceNumber = 1,
15435 + .bAlternateSetting = 1,
15436 + .bNumEndpoints = 1,
15437 + .bInterfaceClass = USB_CLASS_AUDIO,
15438 + .bInterfaceSubClass = 0x2,
15439 + .bInterfaceProtocol = 0,
15440 + .iInterface = 0,
15441 +};
15442 +
15443 +static const struct usb_cs_as_general_descriptor
15444 +z_audio_cs_as_if_desc = {
15445 + .bLength = 7,
15446 + .bDescriptorType = 0x24,
15447 +
15448 + .bDescriptorSubType = 0x01,
15449 + .bTerminalLink = 0x01,
15450 + .bDelay = 0x0,
15451 + .wFormatTag = __constant_cpu_to_le16 (0x0001)
15452 +};
15453 +
15454 +
15455 +static const struct usb_cs_as_format_descriptor
15456 +z_audio_cs_as_format_desc = {
15457 + .bLength = 0xe,
15458 + .bDescriptorType = 0x24,
15459 +
15460 + .bDescriptorSubType = 2,
15461 + .bFormatType = 1,
15462 + .bNrChannels = 1,
15463 + .bSubframeSize = 1,
15464 + .bBitResolution = 8,
15465 + .bSamfreqType = 0,
15466 + .tLowerSamFreq = {0x7e, 0x13, 0x00},
15467 + .tUpperSamFreq = {0xe2, 0xd6, 0x00},
15468 +};
15469 +
15470 +static const struct usb_endpoint_descriptor
15471 +z_iso_ep = {
15472 + .bLength = 0x09,
15473 + .bDescriptorType = 0x05,
15474 + .bEndpointAddress = 0x04,
15475 + .bmAttributes = 0x09,
15476 + .wMaxPacketSize = 0x0038,
15477 + .bInterval = 0x01,
15478 + .bRefresh = 0x00,
15479 + .bSynchAddress = 0x00,
15480 +};
15481 +
15482 +static char z_iso_ep2[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15483 +
15484 +// 9 bytes
15485 +static char z_ac_interface_header_desc[] =
15486 +{ 0x09, 0x24, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x01, 0x01 };
15487 +
15488 +// 12 bytes
15489 +static char z_0[] = {0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
15490 + 0x03, 0x00, 0x00, 0x00};
15491 +// 13 bytes
15492 +static char z_1[] = {0x0d, 0x24, 0x06, 0x02, 0x01, 0x02, 0x15, 0x00,
15493 + 0x02, 0x00, 0x02, 0x00, 0x00};
15494 +// 9 bytes
15495 +static char z_2[] = {0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x02,
15496 + 0x00};
15497 +
15498 +static char za_0[] = {0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00,
15499 + 0x00};
15500 +
15501 +static char za_1[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15502 +
15503 +static char za_2[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x01, 0x08, 0x00,
15504 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15505 +
15506 +static char za_3[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
15507 + 0x00};
15508 +
15509 +static char za_4[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15510 +
15511 +static char za_5[] = {0x09, 0x04, 0x01, 0x03, 0x01, 0x01, 0x02, 0x00,
15512 + 0x00};
15513 +
15514 +static char za_6[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15515 +
15516 +static char za_7[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x00,
15517 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15518 +
15519 +static char za_8[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
15520 + 0x00};
15521 +
15522 +static char za_9[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15523 +
15524 +static char za_10[] = {0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00,
15525 + 0x00};
15526 +
15527 +static char za_11[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15528 +
15529 +static char za_12[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00,
15530 + 0x73, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15531 +
15532 +static char za_13[] = {0x09, 0x05, 0x04, 0x09, 0xe0, 0x00, 0x01, 0x00,
15533 + 0x00};
15534 +
15535 +static char za_14[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15536 +
15537 +static char za_15[] = {0x09, 0x04, 0x01, 0x05, 0x01, 0x01, 0x02, 0x00,
15538 + 0x00};
15539 +
15540 +static char za_16[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15541 +
15542 +static char za_17[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x03, 0x14, 0x00,
15543 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15544 +
15545 +static char za_18[] = {0x09, 0x05, 0x04, 0x09, 0xa8, 0x00, 0x01, 0x00,
15546 + 0x00};
15547 +
15548 +static char za_19[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15549 +
15550 +static char za_20[] = {0x09, 0x04, 0x01, 0x06, 0x01, 0x01, 0x02, 0x00,
15551 + 0x00};
15552 +
15553 +static char za_21[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15554 +
15555 +static char za_22[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x03, 0x14, 0x00,
15556 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15557 +
15558 +static char za_23[] = {0x09, 0x05, 0x04, 0x09, 0x50, 0x01, 0x01, 0x00,
15559 + 0x00};
15560 +
15561 +static char za_24[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15562 +
15563 +
15564 +
15565 +static const struct usb_descriptor_header *z_function [] = {
15566 + (struct usb_descriptor_header *) &z_audio_control_if_desc,
15567 + (struct usb_descriptor_header *) &z_ac_interface_header_desc,
15568 + (struct usb_descriptor_header *) &z_0,
15569 + (struct usb_descriptor_header *) &z_1,
15570 + (struct usb_descriptor_header *) &z_2,
15571 + (struct usb_descriptor_header *) &z_audio_if_desc,
15572 + (struct usb_descriptor_header *) &z_audio_if_desc2,
15573 + (struct usb_descriptor_header *) &z_audio_cs_as_if_desc,
15574 + (struct usb_descriptor_header *) &z_audio_cs_as_format_desc,
15575 + (struct usb_descriptor_header *) &z_iso_ep,
15576 + (struct usb_descriptor_header *) &z_iso_ep2,
15577 + (struct usb_descriptor_header *) &za_0,
15578 + (struct usb_descriptor_header *) &za_1,
15579 + (struct usb_descriptor_header *) &za_2,
15580 + (struct usb_descriptor_header *) &za_3,
15581 + (struct usb_descriptor_header *) &za_4,
15582 + (struct usb_descriptor_header *) &za_5,
15583 + (struct usb_descriptor_header *) &za_6,
15584 + (struct usb_descriptor_header *) &za_7,
15585 + (struct usb_descriptor_header *) &za_8,
15586 + (struct usb_descriptor_header *) &za_9,
15587 + (struct usb_descriptor_header *) &za_10,
15588 + (struct usb_descriptor_header *) &za_11,
15589 + (struct usb_descriptor_header *) &za_12,
15590 + (struct usb_descriptor_header *) &za_13,
15591 + (struct usb_descriptor_header *) &za_14,
15592 + (struct usb_descriptor_header *) &za_15,
15593 + (struct usb_descriptor_header *) &za_16,
15594 + (struct usb_descriptor_header *) &za_17,
15595 + (struct usb_descriptor_header *) &za_18,
15596 + (struct usb_descriptor_header *) &za_19,
15597 + (struct usb_descriptor_header *) &za_20,
15598 + (struct usb_descriptor_header *) &za_21,
15599 + (struct usb_descriptor_header *) &za_22,
15600 + (struct usb_descriptor_header *) &za_23,
15601 + (struct usb_descriptor_header *) &za_24,
15602 + NULL,
15603 +};
15604 +
15605 +/* maxpacket and other transfer characteristics vary by speed. */
15606 +#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
15607 +
15608 +#else
15609 +
15610 +/* if there's no high speed support, maxpacket doesn't change. */
15611 +#define ep_desc(g,hs,fs) fs
15612 +
15613 +#endif /* !CONFIG_USB_GADGET_DUALSPEED */
15614 +
15615 +static char manufacturer [40];
15616 +//static char serial [40];
15617 +static char serial [] = "Ser 00 em";
15618 +
15619 +/* static strings, in UTF-8 */
15620 +static struct usb_string strings [] = {
15621 + { STRING_MANUFACTURER, manufacturer, },
15622 + { STRING_PRODUCT, longname, },
15623 + { STRING_SERIAL, serial, },
15624 + { STRING_LOOPBACK, loopback, },
15625 + { STRING_SOURCE_SINK, source_sink, },
15626 + { } /* end of list */
15627 +};
15628 +
15629 +static struct usb_gadget_strings stringtab = {
15630 + .language = 0x0409, /* en-us */
15631 + .strings = strings,
15632 +};
15633 +
15634 +/*
15635 + * config descriptors are also handcrafted. these must agree with code
15636 + * that sets configurations, and with code managing interfaces and their
15637 + * altsettings. other complexity may come from:
15638 + *
15639 + * - high speed support, including "other speed config" rules
15640 + * - multiple configurations
15641 + * - interfaces with alternate settings
15642 + * - embedded class or vendor-specific descriptors
15643 + *
15644 + * this handles high speed, and has a second config that could as easily
15645 + * have been an alternate interface setting (on most hardware).
15646 + *
15647 + * NOTE: to demonstrate (and test) more USB capabilities, this driver
15648 + * should include an altsetting to test interrupt transfers, including
15649 + * high bandwidth modes at high speed. (Maybe work like Intel's test
15650 + * device?)
15651 + */
15652 +static int
15653 +config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index)
15654 +{
15655 + int len;
15656 + const struct usb_descriptor_header **function;
15657 +
15658 + function = z_function;
15659 + len = usb_gadget_config_buf (&z_config, buf, USB_BUFSIZ, function);
15660 + if (len < 0)
15661 + return len;
15662 + ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
15663 + return len;
15664 +}
15665 +
15666 +/*-------------------------------------------------------------------------*/
15667 +
15668 +static struct usb_request *
15669 +alloc_ep_req (struct usb_ep *ep, unsigned length)
15670 +{
15671 + struct usb_request *req;
15672 +
15673 + req = usb_ep_alloc_request (ep, GFP_ATOMIC);
15674 + if (req) {
15675 + req->length = length;
15676 + req->buf = usb_ep_alloc_buffer (ep, length,
15677 + &req->dma, GFP_ATOMIC);
15678 + if (!req->buf) {
15679 + usb_ep_free_request (ep, req);
15680 + req = NULL;
15681 + }
15682 + }
15683 + return req;
15684 +}
15685 +
15686 +static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
15687 +{
15688 + if (req->buf)
15689 + usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
15690 + usb_ep_free_request (ep, req);
15691 +}
15692 +
15693 +/*-------------------------------------------------------------------------*/
15694 +
15695 +/* optionally require specific source/sink data patterns */
15696 +
15697 +static int
15698 +check_read_data (
15699 + struct zero_dev *dev,
15700 + struct usb_ep *ep,
15701 + struct usb_request *req
15702 +)
15703 +{
15704 + unsigned i;
15705 + u8 *buf = req->buf;
15706 +
15707 + for (i = 0; i < req->actual; i++, buf++) {
15708 + switch (pattern) {
15709 + /* all-zeroes has no synchronization issues */
15710 + case 0:
15711 + if (*buf == 0)
15712 + continue;
15713 + break;
15714 + /* mod63 stays in sync with short-terminated transfers,
15715 + * or otherwise when host and gadget agree on how large
15716 + * each usb transfer request should be. resync is done
15717 + * with set_interface or set_config.
15718 + */
15719 + case 1:
15720 + if (*buf == (u8)(i % 63))
15721 + continue;
15722 + break;
15723 + }
15724 + ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
15725 + usb_ep_set_halt (ep);
15726 + return -EINVAL;
15727 + }
15728 + return 0;
15729 +}
15730 +
15731 +/*-------------------------------------------------------------------------*/
15732 +
15733 +static void zero_reset_config (struct zero_dev *dev)
15734 +{
15735 + if (dev->config == 0)
15736 + return;
15737 +
15738 + DBG (dev, "reset config\n");
15739 +
15740 + /* just disable endpoints, forcing completion of pending i/o.
15741 + * all our completion handlers free their requests in this case.
15742 + */
15743 + if (dev->in_ep) {
15744 + usb_ep_disable (dev->in_ep);
15745 + dev->in_ep = NULL;
15746 + }
15747 + if (dev->out_ep) {
15748 + usb_ep_disable (dev->out_ep);
15749 + dev->out_ep = NULL;
15750 + }
15751 + dev->config = 0;
15752 + del_timer (&dev->resume);
15753 +}
15754 +
15755 +#define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
15756 +
15757 +static void
15758 +zero_isoc_complete (struct usb_ep *ep, struct usb_request *req)
15759 +{
15760 + struct zero_dev *dev = ep->driver_data;
15761 + int status = req->status;
15762 + int i, j;
15763 +
15764 + switch (status) {
15765 +
15766 + case 0: /* normal completion? */
15767 + //printk ("\nzero ---------------> isoc normal completion %d bytes\n", req->actual);
15768 + for (i=0, j=rbuf_start; i<req->actual; i++) {
15769 + //printk ("%02x ", ((__u8*)req->buf)[i]);
15770 + rbuf[j] = ((__u8*)req->buf)[i];
15771 + j++;
15772 + if (j >= RBUF_LEN) j=0;
15773 + }
15774 + rbuf_start = j;
15775 + //printk ("\n\n");
15776 +
15777 + if (rbuf_len < RBUF_LEN) {
15778 + rbuf_len += req->actual;
15779 + if (rbuf_len > RBUF_LEN) {
15780 + rbuf_len = RBUF_LEN;
15781 + }
15782 + }
15783 +
15784 + break;
15785 +
15786 + /* this endpoint is normally active while we're configured */
15787 + case -ECONNABORTED: /* hardware forced ep reset */
15788 + case -ECONNRESET: /* request dequeued */
15789 + case -ESHUTDOWN: /* disconnect from host */
15790 + VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
15791 + req->actual, req->length);
15792 + if (ep == dev->out_ep)
15793 + check_read_data (dev, ep, req);
15794 + free_ep_req (ep, req);
15795 + return;
15796 +
15797 + case -EOVERFLOW: /* buffer overrun on read means that
15798 + * we didn't provide a big enough
15799 + * buffer.
15800 + */
15801 + default:
15802 +#if 1
15803 + DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
15804 + status, req->actual, req->length);
15805 +#endif
15806 + case -EREMOTEIO: /* short read */
15807 + break;
15808 + }
15809 +
15810 + status = usb_ep_queue (ep, req, GFP_ATOMIC);
15811 + if (status) {
15812 + ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
15813 + ep->name, req->length, status);
15814 + usb_ep_set_halt (ep);
15815 + /* FIXME recover later ... somehow */
15816 + }
15817 +}
15818 +
15819 +static struct usb_request *
15820 +zero_start_isoc_ep (struct usb_ep *ep, int gfp_flags)
15821 +{
15822 + struct usb_request *req;
15823 + int status;
15824 +
15825 + req = alloc_ep_req (ep, 512);
15826 + if (!req)
15827 + return NULL;
15828 +
15829 + req->complete = zero_isoc_complete;
15830 +
15831 + status = usb_ep_queue (ep, req, gfp_flags);
15832 + if (status) {
15833 + struct zero_dev *dev = ep->driver_data;
15834 +
15835 + ERROR (dev, "start %s --> %d\n", ep->name, status);
15836 + free_ep_req (ep, req);
15837 + req = NULL;
15838 + }
15839 +
15840 + return req;
15841 +}
15842 +
15843 +/* change our operational config. this code must agree with the code
15844 + * that returns config descriptors, and altsetting code.
15845 + *
15846 + * it's also responsible for power management interactions. some
15847 + * configurations might not work with our current power sources.
15848 + *
15849 + * note that some device controller hardware will constrain what this
15850 + * code can do, perhaps by disallowing more than one configuration or
15851 + * by limiting configuration choices (like the pxa2xx).
15852 + */
15853 +static int
15854 +zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
15855 +{
15856 + int result = 0;
15857 + struct usb_gadget *gadget = dev->gadget;
15858 + const struct usb_endpoint_descriptor *d;
15859 + struct usb_ep *ep;
15860 +
15861 + if (number == dev->config)
15862 + return 0;
15863 +
15864 + zero_reset_config (dev);
15865 +
15866 + gadget_for_each_ep (ep, gadget) {
15867 +
15868 + if (strcmp (ep->name, "ep4") == 0) {
15869 +
15870 + d = (struct usb_endpoint_descripter *)&za_23; // isoc ep desc for audio i/f alt setting 6
15871 + result = usb_ep_enable (ep, d);
15872 +
15873 + if (result == 0) {
15874 + ep->driver_data = dev;
15875 + dev->in_ep = ep;
15876 +
15877 + if (zero_start_isoc_ep (ep, gfp_flags) != 0) {
15878 +
15879 + dev->in_ep = ep;
15880 + continue;
15881 + }
15882 +
15883 + usb_ep_disable (ep);
15884 + result = -EIO;
15885 + }
15886 + }
15887 +
15888 + }
15889 +
15890 + dev->config = number;
15891 + return result;
15892 +}
15893 +
15894 +/*-------------------------------------------------------------------------*/
15895 +
15896 +static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
15897 +{
15898 + if (req->status || req->actual != req->length)
15899 + DBG ((struct zero_dev *) ep->driver_data,
15900 + "setup complete --> %d, %d/%d\n",
15901 + req->status, req->actual, req->length);
15902 +}
15903 +
15904 +/*
15905 + * The setup() callback implements all the ep0 functionality that's
15906 + * not handled lower down, in hardware or the hardware driver (like
15907 + * device and endpoint feature flags, and their status). It's all
15908 + * housekeeping for the gadget function we're implementing. Most of
15909 + * the work is in config-specific setup.
15910 + */
15911 +static int
15912 +zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
15913 +{
15914 + struct zero_dev *dev = get_gadget_data (gadget);
15915 + struct usb_request *req = dev->req;
15916 + int value = -EOPNOTSUPP;
15917 +
15918 + /* usually this stores reply data in the pre-allocated ep0 buffer,
15919 + * but config change events will reconfigure hardware.
15920 + */
15921 + req->zero = 0;
15922 + switch (ctrl->bRequest) {
15923 +
15924 + case USB_REQ_GET_DESCRIPTOR:
15925 +
15926 + switch (ctrl->wValue >> 8) {
15927 +
15928 + case USB_DT_DEVICE:
15929 + value = min (ctrl->wLength, (u16) sizeof device_desc);
15930 + memcpy (req->buf, &device_desc, value);
15931 + break;
15932 +#ifdef CONFIG_USB_GADGET_DUALSPEED
15933 + case USB_DT_DEVICE_QUALIFIER:
15934 + if (!gadget->is_dualspeed)
15935 + break;
15936 + value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
15937 + memcpy (req->buf, &dev_qualifier, value);
15938 + break;
15939 +
15940 + case USB_DT_OTHER_SPEED_CONFIG:
15941 + if (!gadget->is_dualspeed)
15942 + break;
15943 + // FALLTHROUGH
15944 +#endif /* CONFIG_USB_GADGET_DUALSPEED */
15945 + case USB_DT_CONFIG:
15946 + value = config_buf (gadget, req->buf,
15947 + ctrl->wValue >> 8,
15948 + ctrl->wValue & 0xff);
15949 + if (value >= 0)
15950 + value = min (ctrl->wLength, (u16) value);
15951 + break;
15952 +
15953 + case USB_DT_STRING:
15954 + /* wIndex == language code.
15955 + * this driver only handles one language, you can
15956 + * add string tables for other languages, using
15957 + * any UTF-8 characters
15958 + */
15959 + value = usb_gadget_get_string (&stringtab,
15960 + ctrl->wValue & 0xff, req->buf);
15961 + if (value >= 0) {
15962 + value = min (ctrl->wLength, (u16) value);
15963 + }
15964 + break;
15965 + }
15966 + break;
15967 +
15968 + /* currently two configs, two speeds */
15969 + case USB_REQ_SET_CONFIGURATION:
15970 + if (ctrl->bRequestType != 0)
15971 + goto unknown;
15972 +
15973 + spin_lock (&dev->lock);
15974 + value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
15975 + spin_unlock (&dev->lock);
15976 + break;
15977 + case USB_REQ_GET_CONFIGURATION:
15978 + if (ctrl->bRequestType != USB_DIR_IN)
15979 + goto unknown;
15980 + *(u8 *)req->buf = dev->config;
15981 + value = min (ctrl->wLength, (u16) 1);
15982 + break;
15983 +
15984 + /* until we add altsetting support, or other interfaces,
15985 + * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
15986 + * and already killed pending endpoint I/O.
15987 + */
15988 + case USB_REQ_SET_INTERFACE:
15989 +
15990 + if (ctrl->bRequestType != USB_RECIP_INTERFACE)
15991 + goto unknown;
15992 + spin_lock (&dev->lock);
15993 + if (dev->config) {
15994 + u8 config = dev->config;
15995 +
15996 + /* resets interface configuration, forgets about
15997 + * previous transaction state (queued bufs, etc)
15998 + * and re-inits endpoint state (toggle etc)
15999 + * no response queued, just zero status == success.
16000 + * if we had more than one interface we couldn't
16001 + * use this "reset the config" shortcut.
16002 + */
16003 + zero_reset_config (dev);
16004 + zero_set_config (dev, config, GFP_ATOMIC);
16005 + value = 0;
16006 + }
16007 + spin_unlock (&dev->lock);
16008 + break;
16009 + case USB_REQ_GET_INTERFACE:
16010 + if ((ctrl->bRequestType == 0x21) && (ctrl->wIndex == 0x02)) {
16011 + value = ctrl->wLength;
16012 + break;
16013 + }
16014 + else {
16015 + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
16016 + goto unknown;
16017 + if (!dev->config)
16018 + break;
16019 + if (ctrl->wIndex != 0) {
16020 + value = -EDOM;
16021 + break;
16022 + }
16023 + *(u8 *)req->buf = 0;
16024 + value = min (ctrl->wLength, (u16) 1);
16025 + }
16026 + break;
16027 +
16028 + /*
16029 + * These are the same vendor-specific requests supported by
16030 + * Intel's USB 2.0 compliance test devices. We exceed that
16031 + * device spec by allowing multiple-packet requests.
16032 + */
16033 + case 0x5b: /* control WRITE test -- fill the buffer */
16034 + if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
16035 + goto unknown;
16036 + if (ctrl->wValue || ctrl->wIndex)
16037 + break;
16038 + /* just read that many bytes into the buffer */
16039 + if (ctrl->wLength > USB_BUFSIZ)
16040 + break;
16041 + value = ctrl->wLength;
16042 + break;
16043 + case 0x5c: /* control READ test -- return the buffer */
16044 + if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
16045 + goto unknown;
16046 + if (ctrl->wValue || ctrl->wIndex)
16047 + break;
16048 + /* expect those bytes are still in the buffer; send back */
16049 + if (ctrl->wLength > USB_BUFSIZ
16050 + || ctrl->wLength != req->length)
16051 + break;
16052 + value = ctrl->wLength;
16053 + break;
16054 +
16055 + case 0x01: // SET_CUR
16056 + case 0x02:
16057 + case 0x03:
16058 + case 0x04:
16059 + case 0x05:
16060 + value = ctrl->wLength;
16061 + break;
16062 + case 0x81:
16063 + switch (ctrl->wValue) {
16064 + case 0x0201:
16065 + case 0x0202:
16066 + ((u8*)req->buf)[0] = 0x00;
16067 + ((u8*)req->buf)[1] = 0xe3;
16068 + break;
16069 + case 0x0300:
16070 + case 0x0500:
16071 + ((u8*)req->buf)[0] = 0x00;
16072 + break;
16073 + }
16074 + //((u8*)req->buf)[0] = 0x81;
16075 + //((u8*)req->buf)[1] = 0x81;
16076 + value = ctrl->wLength;
16077 + break;
16078 + case 0x82:
16079 + switch (ctrl->wValue) {
16080 + case 0x0201:
16081 + case 0x0202:
16082 + ((u8*)req->buf)[0] = 0x00;
16083 + ((u8*)req->buf)[1] = 0xc3;
16084 + break;
16085 + case 0x0300:
16086 + case 0x0500:
16087 + ((u8*)req->buf)[0] = 0x00;
16088 + break;
16089 + }
16090 + //((u8*)req->buf)[0] = 0x82;
16091 + //((u8*)req->buf)[1] = 0x82;
16092 + value = ctrl->wLength;
16093 + break;
16094 + case 0x83:
16095 + switch (ctrl->wValue) {
16096 + case 0x0201:
16097 + case 0x0202:
16098 + ((u8*)req->buf)[0] = 0x00;
16099 + ((u8*)req->buf)[1] = 0x00;
16100 + break;
16101 + case 0x0300:
16102 + ((u8*)req->buf)[0] = 0x60;
16103 + break;
16104 + case 0x0500:
16105 + ((u8*)req->buf)[0] = 0x18;
16106 + break;
16107 + }
16108 + //((u8*)req->buf)[0] = 0x83;
16109 + //((u8*)req->buf)[1] = 0x83;
16110 + value = ctrl->wLength;
16111 + break;
16112 + case 0x84:
16113 + switch (ctrl->wValue) {
16114 + case 0x0201:
16115 + case 0x0202:
16116 + ((u8*)req->buf)[0] = 0x00;
16117 + ((u8*)req->buf)[1] = 0x01;
16118 + break;
16119 + case 0x0300:
16120 + case 0x0500:
16121 + ((u8*)req->buf)[0] = 0x08;
16122 + break;
16123 + }
16124 + //((u8*)req->buf)[0] = 0x84;
16125 + //((u8*)req->buf)[1] = 0x84;
16126 + value = ctrl->wLength;
16127 + break;
16128 + case 0x85:
16129 + ((u8*)req->buf)[0] = 0x85;
16130 + ((u8*)req->buf)[1] = 0x85;
16131 + value = ctrl->wLength;
16132 + break;
16133 +
16134 +
16135 + default:
16136 +unknown:
16137 + printk("unknown control req%02x.%02x v%04x i%04x l%d\n",
16138 + ctrl->bRequestType, ctrl->bRequest,
16139 + ctrl->wValue, ctrl->wIndex, ctrl->wLength);
16140 + }
16141 +
16142 + /* respond with data transfer before status phase? */
16143 + if (value >= 0) {
16144 + req->length = value;
16145 + req->zero = value < ctrl->wLength
16146 + && (value % gadget->ep0->maxpacket) == 0;
16147 + value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
16148 + if (value < 0) {
16149 + DBG (dev, "ep_queue < 0 --> %d\n", value);
16150 + req->status = 0;
16151 + zero_setup_complete (gadget->ep0, req);
16152 + }
16153 + }
16154 +
16155 + /* device either stalls (value < 0) or reports success */
16156 + return value;
16157 +}
16158 +
16159 +static void
16160 +zero_disconnect (struct usb_gadget *gadget)
16161 +{
16162 + struct zero_dev *dev = get_gadget_data (gadget);
16163 + unsigned long flags;
16164 +
16165 + spin_lock_irqsave (&dev->lock, flags);
16166 + zero_reset_config (dev);
16167 +
16168 + /* a more significant application might have some non-usb
16169 + * activities to quiesce here, saving resources like power
16170 + * or pushing the notification up a network stack.
16171 + */
16172 + spin_unlock_irqrestore (&dev->lock, flags);
16173 +
16174 + /* next we may get setup() calls to enumerate new connections;
16175 + * or an unbind() during shutdown (including removing module).
16176 + */
16177 +}
16178 +
16179 +static void
16180 +zero_autoresume (unsigned long _dev)
16181 +{
16182 + struct zero_dev *dev = (struct zero_dev *) _dev;
16183 + int status;
16184 +
16185 + /* normally the host would be woken up for something
16186 + * more significant than just a timer firing...
16187 + */
16188 + if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
16189 + status = usb_gadget_wakeup (dev->gadget);
16190 + DBG (dev, "wakeup --> %d\n", status);
16191 + }
16192 +}
16193 +
16194 +/*-------------------------------------------------------------------------*/
16195 +
16196 +static void
16197 +zero_unbind (struct usb_gadget *gadget)
16198 +{
16199 + struct zero_dev *dev = get_gadget_data (gadget);
16200 +
16201 + DBG (dev, "unbind\n");
16202 +
16203 + /* we've already been disconnected ... no i/o is active */
16204 + if (dev->req)
16205 + free_ep_req (gadget->ep0, dev->req);
16206 + del_timer_sync (&dev->resume);
16207 + kfree (dev);
16208 + set_gadget_data (gadget, NULL);
16209 +}
16210 +
16211 +static int
16212 +zero_bind (struct usb_gadget *gadget)
16213 +{
16214 + struct zero_dev *dev;
16215 + //struct usb_ep *ep;
16216 +
16217 + printk("binding\n");
16218 + /*
16219 + * DRIVER POLICY CHOICE: you may want to do this differently.
16220 + * One thing to avoid is reusing a bcdDevice revision code
16221 + * with different host-visible configurations or behavior
16222 + * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
16223 + */
16224 + //device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
16225 +
16226 +
16227 + /* ok, we made sense of the hardware ... */
16228 + dev = kmalloc (sizeof *dev, SLAB_KERNEL);
16229 + if (!dev)
16230 + return -ENOMEM;
16231 + memset (dev, 0, sizeof *dev);
16232 + spin_lock_init (&dev->lock);
16233 + dev->gadget = gadget;
16234 + set_gadget_data (gadget, dev);
16235 +
16236 + /* preallocate control response and buffer */
16237 + dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
16238 + if (!dev->req)
16239 + goto enomem;
16240 + dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
16241 + &dev->req->dma, GFP_KERNEL);
16242 + if (!dev->req->buf)
16243 + goto enomem;
16244 +
16245 + dev->req->complete = zero_setup_complete;
16246 +
16247 + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
16248 +
16249 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16250 + /* assume ep0 uses the same value for both speeds ... */
16251 + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
16252 +
16253 + /* and that all endpoints are dual-speed */
16254 + //hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
16255 + //hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
16256 +#endif
16257 +
16258 + usb_gadget_set_selfpowered (gadget);
16259 +
16260 + init_timer (&dev->resume);
16261 + dev->resume.function = zero_autoresume;
16262 + dev->resume.data = (unsigned long) dev;
16263 +
16264 + gadget->ep0->driver_data = dev;
16265 +
16266 + INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
16267 + INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
16268 + EP_OUT_NAME, EP_IN_NAME);
16269 +
16270 + snprintf (manufacturer, sizeof manufacturer,
16271 + UTS_SYSNAME " " UTS_RELEASE " with %s",
16272 + gadget->name);
16273 +
16274 + return 0;
16275 +
16276 +enomem:
16277 + zero_unbind (gadget);
16278 + return -ENOMEM;
16279 +}
16280 +
16281 +/*-------------------------------------------------------------------------*/
16282 +
16283 +static void
16284 +zero_suspend (struct usb_gadget *gadget)
16285 +{
16286 + struct zero_dev *dev = get_gadget_data (gadget);
16287 +
16288 + if (gadget->speed == USB_SPEED_UNKNOWN)
16289 + return;
16290 +
16291 + if (autoresume) {
16292 + mod_timer (&dev->resume, jiffies + (HZ * autoresume));
16293 + DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
16294 + } else
16295 + DBG (dev, "suspend\n");
16296 +}
16297 +
16298 +static void
16299 +zero_resume (struct usb_gadget *gadget)
16300 +{
16301 + struct zero_dev *dev = get_gadget_data (gadget);
16302 +
16303 + DBG (dev, "resume\n");
16304 + del_timer (&dev->resume);
16305 +}
16306 +
16307 +
16308 +/*-------------------------------------------------------------------------*/
16309 +
16310 +static struct usb_gadget_driver zero_driver = {
16311 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16312 + .speed = USB_SPEED_HIGH,
16313 +#else
16314 + .speed = USB_SPEED_FULL,
16315 +#endif
16316 + .function = (char *) longname,
16317 + .bind = zero_bind,
16318 + .unbind = zero_unbind,
16319 +
16320 + .setup = zero_setup,
16321 + .disconnect = zero_disconnect,
16322 +
16323 + .suspend = zero_suspend,
16324 + .resume = zero_resume,
16325 +
16326 + .driver = {
16327 + .name = (char *) shortname,
16328 + // .shutdown = ...
16329 + // .suspend = ...
16330 + // .resume = ...
16331 + },
16332 +};
16333 +
16334 +MODULE_AUTHOR ("David Brownell");
16335 +MODULE_LICENSE ("Dual BSD/GPL");
16336 +
16337 +static struct proc_dir_entry *pdir, *pfile;
16338 +
16339 +static int isoc_read_data (char *page, char **start,
16340 + off_t off, int count,
16341 + int *eof, void *data)
16342 +{
16343 + int i;
16344 + static int c = 0;
16345 + static int done = 0;
16346 + static int s = 0;
16347 +
16348 +/*
16349 + printk ("\ncount: %d\n", count);
16350 + printk ("rbuf_start: %d\n", rbuf_start);
16351 + printk ("rbuf_len: %d\n", rbuf_len);
16352 + printk ("off: %d\n", off);
16353 + printk ("start: %p\n\n", *start);
16354 +*/
16355 + if (done) {
16356 + c = 0;
16357 + done = 0;
16358 + *eof = 1;
16359 + return 0;
16360 + }
16361 +
16362 + if (c == 0) {
16363 + if (rbuf_len == RBUF_LEN)
16364 + s = rbuf_start;
16365 + else s = 0;
16366 + }
16367 +
16368 + for (i=0; i<count && c<rbuf_len; i++, c++) {
16369 + page[i] = rbuf[(c+s) % RBUF_LEN];
16370 + }
16371 + *start = page;
16372 +
16373 + if (c >= rbuf_len) {
16374 + *eof = 1;
16375 + done = 1;
16376 + }
16377 +
16378 +
16379 + return i;
16380 +}
16381 +
16382 +static int __init init (void)
16383 +{
16384 +
16385 + int retval = 0;
16386 +
16387 + pdir = proc_mkdir("isoc_test", NULL);
16388 + if(pdir == NULL) {
16389 + retval = -ENOMEM;
16390 + printk("Error creating dir\n");
16391 + goto done;
16392 + }
16393 + pdir->owner = THIS_MODULE;
16394 +
16395 + pfile = create_proc_read_entry("isoc_data",
16396 + 0444, pdir,
16397 + isoc_read_data,
16398 + NULL);
16399 + if (pfile == NULL) {
16400 + retval = -ENOMEM;
16401 + printk("Error creating file\n");
16402 + goto no_file;
16403 + }
16404 + pfile->owner = THIS_MODULE;
16405 +
16406 + return usb_gadget_register_driver (&zero_driver);
16407 +
16408 + no_file:
16409 + remove_proc_entry("isoc_data", NULL);
16410 + done:
16411 + return retval;
16412 +}
16413 +module_init (init);
16414 +
16415 +static void __exit cleanup (void)
16416 +{
16417 +
16418 + usb_gadget_unregister_driver (&zero_driver);
16419 +
16420 + remove_proc_entry("isoc_data", pdir);
16421 + remove_proc_entry("isoc_test", NULL);
16422 +}
16423 +module_exit (cleanup);
16424 --- /dev/null
16425 +++ b/drivers/usb/host/dwc_otg/dwc_cfi_common.h
16426 @@ -0,0 +1,142 @@
16427 +/* ==========================================================================
16428 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
16429 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
16430 + * otherwise expressly agreed to in writing between Synopsys and you.
16431 + *
16432 + * The Software IS NOT an item of Licensed Software or Licensed Product under
16433 + * any End User Software License Agreement or Agreement for Licensed Product
16434 + * with Synopsys or any supplement thereto. You are permitted to use and
16435 + * redistribute this Software in source and binary forms, with or without
16436 + * modification, provided that redistributions of source code must retain this
16437 + * notice. You may not view, use, disclose, copy or distribute this file or
16438 + * any information contained herein except pursuant to this license grant from
16439 + * Synopsys. If you do not agree with this notice, including the disclaimer
16440 + * below, then you are not authorized to use the Software.
16441 + *
16442 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
16443 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16444 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16445 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
16446 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16447 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16448 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
16449 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16450 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16451 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
16452 + * DAMAGE.
16453 + * ========================================================================== */
16454 +
16455 +#if !defined(__DWC_CFI_COMMON_H__)
16456 +#define __DWC_CFI_COMMON_H__
16457 +
16458 +//#include <linux/types.h>
16459 +
16460 +/**
16461 + * @file
16462 + *
16463 + * This file contains the CFI specific common constants, interfaces
16464 + * (functions and macros) and structures for Linux. No PCD specific
16465 + * data structure or definition is to be included in this file.
16466 + *
16467 + */
16468 +
16469 +/** This is a request for all Core Features */
16470 +#define VEN_CORE_GET_FEATURES 0xB1
16471 +
16472 +/** This is a request to get the value of a specific Core Feature */
16473 +#define VEN_CORE_GET_FEATURE 0xB2
16474 +
16475 +/** This command allows the host to set the value of a specific Core Feature */
16476 +#define VEN_CORE_SET_FEATURE 0xB3
16477 +
16478 +/** This command allows the host to set the default values of
16479 + * either all or any specific Core Feature
16480 + */
16481 +#define VEN_CORE_RESET_FEATURES 0xB4
16482 +
16483 +/** This command forces the PCD to write the deferred values of a Core Features */
16484 +#define VEN_CORE_ACTIVATE_FEATURES 0xB5
16485 +
16486 +/** This request reads a DWORD value from a register at the specified offset */
16487 +#define VEN_CORE_READ_REGISTER 0xB6
16488 +
16489 +/** This request writes a DWORD value into a register at the specified offset */
16490 +#define VEN_CORE_WRITE_REGISTER 0xB7
16491 +
16492 +/** This structure is the header of the Core Features dataset returned to
16493 + * the Host
16494 + */
16495 +struct cfi_all_features_header {
16496 +/** The features header structure length is */
16497 +#define CFI_ALL_FEATURES_HDR_LEN 8
16498 + /**
16499 + * The total length of the features dataset returned to the Host
16500 + */
16501 + uint16_t wTotalLen;
16502 +
16503 + /**
16504 + * CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H).
16505 + * This field identifies the version of the CFI Specification with which
16506 + * the device is compliant.
16507 + */
16508 + uint16_t wVersion;
16509 +
16510 + /** The ID of the Core */
16511 + uint16_t wCoreID;
16512 +#define CFI_CORE_ID_UDC 1
16513 +#define CFI_CORE_ID_OTG 2
16514 +#define CFI_CORE_ID_WUDEV 3
16515 +
16516 + /** Number of features returned by VEN_CORE_GET_FEATURES request */
16517 + uint16_t wNumFeatures;
16518 +} UPACKED;
16519 +
16520 +typedef struct cfi_all_features_header cfi_all_features_header_t;
16521 +
16522 +/** This structure is a header of the Core Feature descriptor dataset returned to
16523 + * the Host after the VEN_CORE_GET_FEATURES request
16524 + */
16525 +struct cfi_feature_desc_header {
16526 +#define CFI_FEATURE_DESC_HDR_LEN 8
16527 +
16528 + /** The feature ID */
16529 + uint16_t wFeatureID;
16530 +
16531 + /** Length of this feature descriptor in bytes - including the
16532 + * length of the feature name string
16533 + */
16534 + uint16_t wLength;
16535 +
16536 + /** The data length of this feature in bytes */
16537 + uint16_t wDataLength;
16538 +
16539 + /**
16540 + * Attributes of this features
16541 + * D0: Access rights
16542 + * 0 - Read/Write
16543 + * 1 - Read only
16544 + */
16545 + uint8_t bmAttributes;
16546 +#define CFI_FEATURE_ATTR_RO 1
16547 +#define CFI_FEATURE_ATTR_RW 0
16548 +
16549 + /** Length of the feature name in bytes */
16550 + uint8_t bNameLen;
16551 +
16552 + /** The feature name buffer */
16553 + //uint8_t *name;
16554 +} UPACKED;
16555 +
16556 +typedef struct cfi_feature_desc_header cfi_feature_desc_header_t;
16557 +
16558 +/**
16559 + * This structure describes a NULL terminated string referenced by its id field.
16560 + * It is very similar to usb_string structure but has the id field type set to 16-bit.
16561 + */
16562 +struct cfi_string {
16563 + uint16_t id;
16564 + const uint8_t *s;
16565 +};
16566 +typedef struct cfi_string cfi_string_t;
16567 +
16568 +#endif
16569 --- /dev/null
16570 +++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.c
16571 @@ -0,0 +1,854 @@
16572 +/* ==========================================================================
16573 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.c $
16574 + * $Revision: #12 $
16575 + * $Date: 2011/10/26 $
16576 + * $Change: 1873028 $
16577 + *
16578 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
16579 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
16580 + * otherwise expressly agreed to in writing between Synopsys and you.
16581 + *
16582 + * The Software IS NOT an item of Licensed Software or Licensed Product under
16583 + * any End User Software License Agreement or Agreement for Licensed Product
16584 + * with Synopsys or any supplement thereto. You are permitted to use and
16585 + * redistribute this Software in source and binary forms, with or without
16586 + * modification, provided that redistributions of source code must retain this
16587 + * notice. You may not view, use, disclose, copy or distribute this file or
16588 + * any information contained herein except pursuant to this license grant from
16589 + * Synopsys. If you do not agree with this notice, including the disclaimer
16590 + * below, then you are not authorized to use the Software.
16591 + *
16592 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
16593 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16594 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16595 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
16596 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16597 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16598 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
16599 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16600 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16601 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
16602 + * DAMAGE.
16603 + * ========================================================================== */
16604 +
16605 +#include "dwc_os.h"
16606 +#include "dwc_otg_regs.h"
16607 +#include "dwc_otg_cil.h"
16608 +#include "dwc_otg_adp.h"
16609 +
16610 +/** @file
16611 + *
16612 + * This file contains the most of the Attach Detect Protocol implementation for
16613 + * the driver to support OTG Rev2.0.
16614 + *
16615 + */
16616 +
16617 +void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value)
16618 +{
16619 + adpctl_data_t adpctl;
16620 +
16621 + adpctl.d32 = value;
16622 + adpctl.b.ar = 0x2;
16623 +
16624 + DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
16625 +
16626 + while (adpctl.b.ar) {
16627 + adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
16628 + }
16629 +
16630 +}
16631 +
16632 +/**
16633 + * Function is called to read ADP registers
16634 + */
16635 +uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if)
16636 +{
16637 + adpctl_data_t adpctl;
16638 +
16639 + adpctl.d32 = 0;
16640 + adpctl.b.ar = 0x1;
16641 +
16642 + DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
16643 +
16644 + while (adpctl.b.ar) {
16645 + adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
16646 + }
16647 +
16648 + return adpctl.d32;
16649 +}
16650 +
16651 +/**
16652 + * Function is called to read ADPCTL register and filter Write-clear bits
16653 + */
16654 +uint32_t dwc_otg_adp_read_reg_filter(dwc_otg_core_if_t * core_if)
16655 +{
16656 + adpctl_data_t adpctl;
16657 +
16658 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16659 + adpctl.b.adp_tmout_int = 0;
16660 + adpctl.b.adp_prb_int = 0;
16661 + adpctl.b.adp_tmout_int = 0;
16662 +
16663 + return adpctl.d32;
16664 +}
16665 +
16666 +/**
16667 + * Function is called to write ADP registers
16668 + */
16669 +void dwc_otg_adp_modify_reg(dwc_otg_core_if_t * core_if, uint32_t clr,
16670 + uint32_t set)
16671 +{
16672 + dwc_otg_adp_write_reg(core_if,
16673 + (dwc_otg_adp_read_reg(core_if) & (~clr)) | set);
16674 +}
16675 +
16676 +static void adp_sense_timeout(void *ptr)
16677 +{
16678 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
16679 + core_if->adp.sense_timer_started = 0;
16680 + DWC_PRINTF("ADP SENSE TIMEOUT\n");
16681 + if (core_if->adp_enable) {
16682 + dwc_otg_adp_sense_stop(core_if);
16683 + dwc_otg_adp_probe_start(core_if);
16684 + }
16685 +}
16686 +
16687 +/**
16688 + * This function is called when the ADP vbus timer expires. Timeout is 1.1s.
16689 + */
16690 +static void adp_vbuson_timeout(void *ptr)
16691 +{
16692 + gpwrdn_data_t gpwrdn;
16693 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
16694 + hprt0_data_t hprt0 = {.d32 = 0 };
16695 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
16696 + DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
16697 + if (core_if) {
16698 + core_if->adp.vbuson_timer_started = 0;
16699 + /* Turn off vbus */
16700 + hprt0.b.prtpwr = 1;
16701 + DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
16702 + gpwrdn.d32 = 0;
16703 +
16704 + /* Power off the core */
16705 + if (core_if->power_down == 2) {
16706 + /* Enable Wakeup Logic */
16707 +// gpwrdn.b.wkupactiv = 1;
16708 + gpwrdn.b.pmuactv = 0;
16709 + gpwrdn.b.pwrdnrstn = 1;
16710 + gpwrdn.b.pwrdnclmp = 1;
16711 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
16712 + gpwrdn.d32);
16713 +
16714 + /* Suspend the Phy Clock */
16715 + pcgcctl.b.stoppclk = 1;
16716 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
16717 +
16718 + /* Switch on VDD */
16719 +// gpwrdn.b.wkupactiv = 1;
16720 + gpwrdn.b.pmuactv = 1;
16721 + gpwrdn.b.pwrdnrstn = 1;
16722 + gpwrdn.b.pwrdnclmp = 1;
16723 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
16724 + gpwrdn.d32);
16725 + } else {
16726 + /* Enable Power Down Logic */
16727 + gpwrdn.b.pmuintsel = 1;
16728 + gpwrdn.b.pmuactv = 1;
16729 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16730 + }
16731 +
16732 + /* Power off the core */
16733 + if (core_if->power_down == 2) {
16734 + gpwrdn.d32 = 0;
16735 + gpwrdn.b.pwrdnswtch = 1;
16736 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
16737 + gpwrdn.d32, 0);
16738 + }
16739 +
16740 + /* Unmask SRP detected interrupt from Power Down Logic */
16741 + gpwrdn.d32 = 0;
16742 + gpwrdn.b.srp_det_msk = 1;
16743 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16744 +
16745 + dwc_otg_adp_probe_start(core_if);
16746 + dwc_otg_dump_global_registers(core_if);
16747 + dwc_otg_dump_host_registers(core_if);
16748 + }
16749 +
16750 +}
16751 +
16752 +/**
16753 + * Start the ADP Initial Probe timer to detect if Port Connected interrupt is
16754 + * not asserted within 1.1 seconds.
16755 + *
16756 + * @param core_if the pointer to core_if strucure.
16757 + */
16758 +void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
16759 +{
16760 + core_if->adp.vbuson_timer_started = 1;
16761 + if (core_if->adp.vbuson_timer)
16762 + {
16763 + DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
16764 + /* 1.1 secs + 60ms necessary for cil_hcd_start*/
16765 + DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
16766 + } else {
16767 + DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
16768 + }
16769 +}
16770 +
16771 +#if 0
16772 +/**
16773 + * Masks all DWC OTG core interrupts
16774 + *
16775 + */
16776 +static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
16777 +{
16778 + int i;
16779 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
16780 +
16781 + /* Mask Host Interrupts */
16782 +
16783 + /* Clear and disable HCINTs */
16784 + for (i = 0; i < core_if->core_params->host_channels; i++) {
16785 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
16786 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);
16787 +
16788 + }
16789 +
16790 + /* Clear and disable HAINT */
16791 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
16792 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);
16793 +
16794 + /* Mask Device Interrupts */
16795 + if (!core_if->multiproc_int_enable) {
16796 + /* Clear and disable IN Endpoint interrupts */
16797 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
16798 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
16799 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
16800 + diepint, 0xFFFFFFFF);
16801 + }
16802 +
16803 + /* Clear and disable OUT Endpoint interrupts */
16804 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
16805 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
16806 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
16807 + doepint, 0xFFFFFFFF);
16808 + }
16809 +
16810 + /* Clear and disable DAINT */
16811 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
16812 + 0xFFFFFFFF);
16813 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
16814 + } else {
16815 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
16816 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
16817 + diepeachintmsk[i], 0);
16818 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
16819 + diepint, 0xFFFFFFFF);
16820 + }
16821 +
16822 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
16823 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
16824 + doepeachintmsk[i], 0);
16825 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
16826 + doepint, 0xFFFFFFFF);
16827 + }
16828 +
16829 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
16830 + 0);
16831 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
16832 + 0xFFFFFFFF);
16833 +
16834 + }
16835 +
16836 + /* Disable interrupts */
16837 + ahbcfg.b.glblintrmsk = 1;
16838 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
16839 +
16840 + /* Disable all interrupts. */
16841 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
16842 +
16843 + /* Clear any pending interrupts */
16844 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
16845 +
16846 + /* Clear any pending OTG Interrupts */
16847 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);
16848 +}
16849 +
16850 +/**
16851 + * Unmask Port Connection Detected interrupt
16852 + *
16853 + */
16854 +static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
16855 +{
16856 + gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };
16857 +
16858 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
16859 +}
16860 +#endif
16861 +
16862 +/**
16863 + * Starts the ADP Probing
16864 + *
16865 + * @param core_if the pointer to core_if structure.
16866 + */
16867 +uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
16868 +{
16869 +
16870 + adpctl_data_t adpctl = {.d32 = 0};
16871 + gpwrdn_data_t gpwrdn;
16872 +#if 0
16873 + adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
16874 + .b.adp_sns_int = 1, b.adp_tmout_int};
16875 +#endif
16876 + dwc_otg_disable_global_interrupts(core_if);
16877 + DWC_PRINTF("ADP Probe Start\n");
16878 + core_if->adp.probe_enabled = 1;
16879 +
16880 + adpctl.b.adpres = 1;
16881 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16882 +
16883 + while (adpctl.b.adpres) {
16884 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16885 + }
16886 +
16887 + adpctl.d32 = 0;
16888 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
16889 +
16890 + /* In Host mode unmask SRP detected interrupt */
16891 + gpwrdn.d32 = 0;
16892 + gpwrdn.b.sts_chngint_msk = 1;
16893 + if (!gpwrdn.b.idsts) {
16894 + gpwrdn.b.srp_det_msk = 1;
16895 + }
16896 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16897 +
16898 + adpctl.b.adp_tmout_int_msk = 1;
16899 + adpctl.b.adp_prb_int_msk = 1;
16900 + adpctl.b.prb_dschg = 1;
16901 + adpctl.b.prb_delta = 1;
16902 + adpctl.b.prb_per = 1;
16903 + adpctl.b.adpen = 1;
16904 + adpctl.b.enaprb = 1;
16905 +
16906 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16907 + DWC_PRINTF("ADP Probe Finish\n");
16908 + return 0;
16909 +}
16910 +
16911 +/**
16912 + * Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted
16913 + * within 3 seconds.
16914 + *
16915 + * @param core_if the pointer to core_if strucure.
16916 + */
16917 +void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
16918 +{
16919 + core_if->adp.sense_timer_started = 1;
16920 + DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3000 /* 3 secs */ );
16921 +}
16922 +
16923 +/**
16924 + * Starts the ADP Sense
16925 + *
16926 + * @param core_if the pointer to core_if strucure.
16927 + */
16928 +uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
16929 +{
16930 + adpctl_data_t adpctl;
16931 +
16932 + DWC_PRINTF("ADP Sense Start\n");
16933 +
16934 + /* Unmask ADP sense interrupt and mask all other from the core */
16935 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
16936 + adpctl.b.adp_sns_int_msk = 1;
16937 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16938 + dwc_otg_disable_global_interrupts(core_if); // vahrama
16939 +
16940 + /* Set ADP reset bit*/
16941 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
16942 + adpctl.b.adpres = 1;
16943 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16944 +
16945 + while (adpctl.b.adpres) {
16946 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16947 + }
16948 +
16949 + adpctl.b.adpres = 0;
16950 + adpctl.b.adpen = 1;
16951 + adpctl.b.enasns = 1;
16952 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16953 +
16954 + dwc_otg_adp_sense_timer_start(core_if);
16955 +
16956 + return 0;
16957 +}
16958 +
16959 +/**
16960 + * Stops the ADP Probing
16961 + *
16962 + * @param core_if the pointer to core_if strucure.
16963 + */
16964 +uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if)
16965 +{
16966 +
16967 + adpctl_data_t adpctl;
16968 + DWC_PRINTF("Stop ADP probe\n");
16969 + core_if->adp.probe_enabled = 0;
16970 + core_if->adp.probe_counter = 0;
16971 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16972 +
16973 + adpctl.b.adpen = 0;
16974 + adpctl.b.adp_prb_int = 1;
16975 + adpctl.b.adp_tmout_int = 1;
16976 + adpctl.b.adp_sns_int = 1;
16977 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16978 +
16979 + return 0;
16980 +}
16981 +
16982 +/**
16983 + * Stops the ADP Sensing
16984 + *
16985 + * @param core_if the pointer to core_if strucure.
16986 + */
16987 +uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if)
16988 +{
16989 + adpctl_data_t adpctl;
16990 +
16991 + core_if->adp.sense_enabled = 0;
16992 +
16993 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
16994 + adpctl.b.enasns = 0;
16995 + adpctl.b.adp_sns_int = 1;
16996 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16997 +
16998 + return 0;
16999 +}
17000 +
17001 +/**
17002 + * Called to turn on the VBUS after initial ADP probe in host mode.
17003 + * If port power was already enabled in cil_hcd_start function then
17004 + * only schedule a timer.
17005 + *
17006 + * @param core_if the pointer to core_if structure.
17007 + */
17008 +void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
17009 +{
17010 + hprt0_data_t hprt0 = {.d32 = 0 };
17011 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
17012 + DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);
17013 +
17014 + if (hprt0.b.prtpwr == 0) {
17015 + hprt0.b.prtpwr = 1;
17016 + //DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
17017 + }
17018 +
17019 + dwc_otg_adp_vbuson_timer_start(core_if);
17020 +}
17021 +
17022 +/**
17023 + * Called right after driver is loaded
17024 + * to perform initial actions for ADP
17025 + *
17026 + * @param core_if the pointer to core_if structure.
17027 + * @param is_host - flag for current mode of operation either from GINTSTS or GPWRDN
17028 + */
17029 +void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host)
17030 +{
17031 + gpwrdn_data_t gpwrdn;
17032 +
17033 + DWC_PRINTF("ADP Initial Start\n");
17034 + core_if->adp.adp_started = 1;
17035 +
17036 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
17037 + dwc_otg_disable_global_interrupts(core_if);
17038 + if (is_host) {
17039 + DWC_PRINTF("HOST MODE\n");
17040 + /* Enable Power Down Logic Interrupt*/
17041 + gpwrdn.d32 = 0;
17042 + gpwrdn.b.pmuintsel = 1;
17043 + gpwrdn.b.pmuactv = 1;
17044 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
17045 + /* Initialize first ADP probe to obtain Ramp Time value */
17046 + core_if->adp.initial_probe = 1;
17047 + dwc_otg_adp_probe_start(core_if);
17048 + } else {
17049 + gotgctl_data_t gotgctl;
17050 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
17051 + DWC_PRINTF("DEVICE MODE\n");
17052 + if (gotgctl.b.bsesvld == 0) {
17053 + /* Enable Power Down Logic Interrupt*/
17054 + gpwrdn.d32 = 0;
17055 + DWC_PRINTF("VBUS is not valid - start ADP probe\n");
17056 + gpwrdn.b.pmuintsel = 1;
17057 + gpwrdn.b.pmuactv = 1;
17058 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
17059 + core_if->adp.initial_probe = 1;
17060 + dwc_otg_adp_probe_start(core_if);
17061 + } else {
17062 + DWC_PRINTF("VBUS is valid - initialize core as a Device\n");
17063 + core_if->op_state = B_PERIPHERAL;
17064 + dwc_otg_core_init(core_if);
17065 + dwc_otg_enable_global_interrupts(core_if);
17066 + cil_pcd_start(core_if);
17067 + dwc_otg_dump_global_registers(core_if);
17068 + dwc_otg_dump_dev_registers(core_if);
17069 + }
17070 + }
17071 +}
17072 +
17073 +void dwc_otg_adp_init(dwc_otg_core_if_t * core_if)
17074 +{
17075 + core_if->adp.adp_started = 0;
17076 + core_if->adp.initial_probe = 0;
17077 + core_if->adp.probe_timer_values[0] = -1;
17078 + core_if->adp.probe_timer_values[1] = -1;
17079 + core_if->adp.probe_enabled = 0;
17080 + core_if->adp.sense_enabled = 0;
17081 + core_if->adp.sense_timer_started = 0;
17082 + core_if->adp.vbuson_timer_started = 0;
17083 + core_if->adp.probe_counter = 0;
17084 + core_if->adp.gpwrdn = 0;
17085 + core_if->adp.attached = DWC_OTG_ADP_UNKOWN;
17086 + /* Initialize timers */
17087 + core_if->adp.sense_timer =
17088 + DWC_TIMER_ALLOC("ADP SENSE TIMER", adp_sense_timeout, core_if);
17089 + core_if->adp.vbuson_timer =
17090 + DWC_TIMER_ALLOC("ADP VBUS ON TIMER", adp_vbuson_timeout, core_if);
17091 + if (!core_if->adp.sense_timer || !core_if->adp.vbuson_timer)
17092 + {
17093 + DWC_ERROR("Could not allocate memory for ADP timers\n");
17094 + }
17095 +}
17096 +
17097 +void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if)
17098 +{
17099 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
17100 + gpwrdn.b.pmuintsel = 1;
17101 + gpwrdn.b.pmuactv = 1;
17102 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17103 +
17104 + if (core_if->adp.probe_enabled)
17105 + dwc_otg_adp_probe_stop(core_if);
17106 + if (core_if->adp.sense_enabled)
17107 + dwc_otg_adp_sense_stop(core_if);
17108 + if (core_if->adp.sense_timer_started)
17109 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
17110 + if (core_if->adp.vbuson_timer_started)
17111 + DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
17112 + DWC_TIMER_FREE(core_if->adp.sense_timer);
17113 + DWC_TIMER_FREE(core_if->adp.vbuson_timer);
17114 +}
17115 +
17116 +/////////////////////////////////////////////////////////////////////
17117 +////////////// ADP Interrupt Handlers ///////////////////////////////
17118 +/////////////////////////////////////////////////////////////////////
17119 +/**
17120 + * This function sets Ramp Timer values
17121 + */
17122 +static uint32_t set_timer_value(dwc_otg_core_if_t * core_if, uint32_t val)
17123 +{
17124 + if (core_if->adp.probe_timer_values[0] == -1) {
17125 + core_if->adp.probe_timer_values[0] = val;
17126 + core_if->adp.probe_timer_values[1] = -1;
17127 + return 1;
17128 + } else {
17129 + core_if->adp.probe_timer_values[1] =
17130 + core_if->adp.probe_timer_values[0];
17131 + core_if->adp.probe_timer_values[0] = val;
17132 + return 0;
17133 + }
17134 +}
17135 +
17136 +/**
17137 + * This function compares Ramp Timer values
17138 + */
17139 +static uint32_t compare_timer_values(dwc_otg_core_if_t * core_if)
17140 +{
17141 + uint32_t diff;
17142 + if (core_if->adp.probe_timer_values[0]>=core_if->adp.probe_timer_values[1])
17143 + diff = core_if->adp.probe_timer_values[0]-core_if->adp.probe_timer_values[1];
17144 + else
17145 + diff = core_if->adp.probe_timer_values[1]-core_if->adp.probe_timer_values[0];
17146 + if(diff < 2) {
17147 + return 0;
17148 + } else {
17149 + return 1;
17150 + }
17151 +}
17152 +
17153 +/**
17154 + * This function handles ADP Probe Interrupts
17155 + */
17156 +static int32_t dwc_otg_adp_handle_prb_intr(dwc_otg_core_if_t * core_if,
17157 + uint32_t val)
17158 +{
17159 + adpctl_data_t adpctl = {.d32 = 0 };
17160 + gpwrdn_data_t gpwrdn, temp;
17161 + adpctl.d32 = val;
17162 +
17163 + temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17164 + core_if->adp.probe_counter++;
17165 + core_if->adp.gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17166 + if (adpctl.b.rtim == 0 && !temp.b.idsts){
17167 + DWC_PRINTF("RTIM value is 0\n");
17168 + goto exit;
17169 + }
17170 + if (set_timer_value(core_if, adpctl.b.rtim) &&
17171 + core_if->adp.initial_probe) {
17172 + core_if->adp.initial_probe = 0;
17173 + dwc_otg_adp_probe_stop(core_if);
17174 + gpwrdn.d32 = 0;
17175 + gpwrdn.b.pmuactv = 1;
17176 + gpwrdn.b.pmuintsel = 1;
17177 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17178 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
17179 +
17180 + /* check which value is for device mode and which for Host mode */
17181 + if (!temp.b.idsts) { /* considered host mode value is 0 */
17182 + /*
17183 + * Turn on VBUS after initial ADP probe.
17184 + */
17185 + core_if->op_state = A_HOST;
17186 + dwc_otg_enable_global_interrupts(core_if);
17187 + DWC_SPINUNLOCK(core_if->lock);
17188 + cil_hcd_start(core_if);
17189 + dwc_otg_adp_turnon_vbus(core_if);
17190 + DWC_SPINLOCK(core_if->lock);
17191 + } else {
17192 + /*
17193 + * Initiate SRP after initial ADP probe.
17194 + */
17195 + dwc_otg_enable_global_interrupts(core_if);
17196 + dwc_otg_initiate_srp(core_if);
17197 + }
17198 + } else if (core_if->adp.probe_counter > 2){
17199 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17200 + if (compare_timer_values(core_if)) {
17201 + DWC_PRINTF("Difference in timer values !!! \n");
17202 +// core_if->adp.attached = DWC_OTG_ADP_ATTACHED;
17203 + dwc_otg_adp_probe_stop(core_if);
17204 +
17205 + /* Power on the core */
17206 + if (core_if->power_down == 2) {
17207 + gpwrdn.b.pwrdnswtch = 1;
17208 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17209 + gpwrdn, 0, gpwrdn.d32);
17210 + }
17211 +
17212 + /* check which value is for device mode and which for Host mode */
17213 + if (!temp.b.idsts) { /* considered host mode value is 0 */
17214 + /* Disable Interrupt from Power Down Logic */
17215 + gpwrdn.d32 = 0;
17216 + gpwrdn.b.pmuintsel = 1;
17217 + gpwrdn.b.pmuactv = 1;
17218 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17219 + gpwrdn, gpwrdn.d32, 0);
17220 +
17221 + /*
17222 + * Initialize the Core for Host mode.
17223 + */
17224 + core_if->op_state = A_HOST;
17225 + dwc_otg_core_init(core_if);
17226 + dwc_otg_enable_global_interrupts(core_if);
17227 + cil_hcd_start(core_if);
17228 + } else {
17229 + gotgctl_data_t gotgctl;
17230 + /* Mask SRP detected interrupt from Power Down Logic */
17231 + gpwrdn.d32 = 0;
17232 + gpwrdn.b.srp_det_msk = 1;
17233 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17234 + gpwrdn, gpwrdn.d32, 0);
17235 +
17236 + /* Disable Power Down Logic */
17237 + gpwrdn.d32 = 0;
17238 + gpwrdn.b.pmuintsel = 1;
17239 + gpwrdn.b.pmuactv = 1;
17240 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17241 + gpwrdn, gpwrdn.d32, 0);
17242 +
17243 + /*
17244 + * Initialize the Core for Device mode.
17245 + */
17246 + core_if->op_state = B_PERIPHERAL;
17247 + dwc_otg_core_init(core_if);
17248 + dwc_otg_enable_global_interrupts(core_if);
17249 + cil_pcd_start(core_if);
17250 +
17251 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
17252 + if (!gotgctl.b.bsesvld) {
17253 + dwc_otg_initiate_srp(core_if);
17254 + }
17255 + }
17256 + }
17257 + if (core_if->power_down == 2) {
17258 + if (gpwrdn.b.bsessvld) {
17259 + /* Mask SRP detected interrupt from Power Down Logic */
17260 + gpwrdn.d32 = 0;
17261 + gpwrdn.b.srp_det_msk = 1;
17262 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17263 +
17264 + /* Disable Power Down Logic */
17265 + gpwrdn.d32 = 0;
17266 + gpwrdn.b.pmuactv = 1;
17267 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17268 +
17269 + /*
17270 + * Initialize the Core for Device mode.
17271 + */
17272 + core_if->op_state = B_PERIPHERAL;
17273 + dwc_otg_core_init(core_if);
17274 + dwc_otg_enable_global_interrupts(core_if);
17275 + cil_pcd_start(core_if);
17276 + }
17277 + }
17278 + }
17279 +exit:
17280 + /* Clear interrupt */
17281 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17282 + adpctl.b.adp_prb_int = 1;
17283 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17284 +
17285 + return 0;
17286 +}
17287 +
17288 +/**
17289 + * This function hadles ADP Sense Interrupt
17290 + */
17291 +static int32_t dwc_otg_adp_handle_sns_intr(dwc_otg_core_if_t * core_if)
17292 +{
17293 + adpctl_data_t adpctl;
17294 + /* Stop ADP Sense timer */
17295 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
17296 +
17297 + /* Restart ADP Sense timer */
17298 + dwc_otg_adp_sense_timer_start(core_if);
17299 +
17300 + /* Clear interrupt */
17301 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17302 + adpctl.b.adp_sns_int = 1;
17303 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17304 +
17305 + return 0;
17306 +}
17307 +
17308 +/**
17309 + * This function handles ADP Probe Interrupts
17310 + */
17311 +static int32_t dwc_otg_adp_handle_prb_tmout_intr(dwc_otg_core_if_t * core_if,
17312 + uint32_t val)
17313 +{
17314 + adpctl_data_t adpctl = {.d32 = 0 };
17315 + adpctl.d32 = val;
17316 + set_timer_value(core_if, adpctl.b.rtim);
17317 +
17318 + /* Clear interrupt */
17319 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17320 + adpctl.b.adp_tmout_int = 1;
17321 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17322 +
17323 + return 0;
17324 +}
17325 +
17326 +/**
17327 + * ADP Interrupt handler.
17328 + *
17329 + */
17330 +int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if)
17331 +{
17332 + int retval = 0;
17333 + adpctl_data_t adpctl = {.d32 = 0};
17334 +
17335 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17336 + DWC_PRINTF("ADPCTL = %08x\n",adpctl.d32);
17337 +
17338 + if (adpctl.b.adp_sns_int & adpctl.b.adp_sns_int_msk) {
17339 + DWC_PRINTF("ADP Sense interrupt\n");
17340 + retval |= dwc_otg_adp_handle_sns_intr(core_if);
17341 + }
17342 + if (adpctl.b.adp_tmout_int & adpctl.b.adp_tmout_int_msk) {
17343 + DWC_PRINTF("ADP timeout interrupt\n");
17344 + retval |= dwc_otg_adp_handle_prb_tmout_intr(core_if, adpctl.d32);
17345 + }
17346 + if (adpctl.b.adp_prb_int & adpctl.b.adp_prb_int_msk) {
17347 + DWC_PRINTF("ADP Probe interrupt\n");
17348 + adpctl.b.adp_prb_int = 1;
17349 + retval |= dwc_otg_adp_handle_prb_intr(core_if, adpctl.d32);
17350 + }
17351 +
17352 +// dwc_otg_adp_modify_reg(core_if, adpctl.d32, 0);
17353 + //dwc_otg_adp_write_reg(core_if, adpctl.d32);
17354 + DWC_PRINTF("RETURN FROM ADP ISR\n");
17355 +
17356 + return retval;
17357 +}
17358 +
17359 +/**
17360 + *
17361 + * @param core_if Programming view of DWC_otg controller.
17362 + */
17363 +int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if)
17364 +{
17365 +
17366 +#ifndef DWC_HOST_ONLY
17367 + hprt0_data_t hprt0;
17368 + gpwrdn_data_t gpwrdn;
17369 + DWC_DEBUGPL(DBG_ANY, "++ Power Down Logic Session Request Interrupt++\n");
17370 +
17371 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17372 + /* check which value is for device mode and which for Host mode */
17373 + if (!gpwrdn.b.idsts) { /* considered host mode value is 0 */
17374 + DWC_PRINTF("SRP: Host mode\n");
17375 +
17376 + if (core_if->adp_enable) {
17377 + dwc_otg_adp_probe_stop(core_if);
17378 +
17379 + /* Power on the core */
17380 + if (core_if->power_down == 2) {
17381 + gpwrdn.b.pwrdnswtch = 1;
17382 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17383 + gpwrdn, 0, gpwrdn.d32);
17384 + }
17385 +
17386 + core_if->op_state = A_HOST;
17387 + dwc_otg_core_init(core_if);
17388 + dwc_otg_enable_global_interrupts(core_if);
17389 + cil_hcd_start(core_if);
17390 + }
17391 +
17392 + /* Turn on the port power bit. */
17393 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
17394 + hprt0.b.prtpwr = 1;
17395 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
17396 +
17397 + /* Start the Connection timer. So a message can be displayed
17398 + * if connect does not occur within 10 seconds. */
17399 + cil_hcd_session_start(core_if);
17400 + } else {
17401 + DWC_PRINTF("SRP: Device mode %s\n", __FUNCTION__);
17402 + if (core_if->adp_enable) {
17403 + dwc_otg_adp_probe_stop(core_if);
17404 +
17405 + /* Power on the core */
17406 + if (core_if->power_down == 2) {
17407 + gpwrdn.b.pwrdnswtch = 1;
17408 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17409 + gpwrdn, 0, gpwrdn.d32);
17410 + }
17411 +
17412 + gpwrdn.d32 = 0;
17413 + gpwrdn.b.pmuactv = 0;
17414 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
17415 + gpwrdn.d32);
17416 +
17417 + core_if->op_state = B_PERIPHERAL;
17418 + dwc_otg_core_init(core_if);
17419 + dwc_otg_enable_global_interrupts(core_if);
17420 + cil_pcd_start(core_if);
17421 + }
17422 + }
17423 +#endif
17424 + return 1;
17425 +}
17426 --- /dev/null
17427 +++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.h
17428 @@ -0,0 +1,80 @@
17429 +/* ==========================================================================
17430 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.h $
17431 + * $Revision: #7 $
17432 + * $Date: 2011/10/24 $
17433 + * $Change: 1871159 $
17434 + *
17435 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
17436 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
17437 + * otherwise expressly agreed to in writing between Synopsys and you.
17438 + *
17439 + * The Software IS NOT an item of Licensed Software or Licensed Product under
17440 + * any End User Software License Agreement or Agreement for Licensed Product
17441 + * with Synopsys or any supplement thereto. You are permitted to use and
17442 + * redistribute this Software in source and binary forms, with or without
17443 + * modification, provided that redistributions of source code must retain this
17444 + * notice. You may not view, use, disclose, copy or distribute this file or
17445 + * any information contained herein except pursuant to this license grant from
17446 + * Synopsys. If you do not agree with this notice, including the disclaimer
17447 + * below, then you are not authorized to use the Software.
17448 + *
17449 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
17450 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17451 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17452 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
17453 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17454 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17455 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17456 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17457 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17458 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
17459 + * DAMAGE.
17460 + * ========================================================================== */
17461 +
17462 +#ifndef __DWC_OTG_ADP_H__
17463 +#define __DWC_OTG_ADP_H__
17464 +
17465 +/**
17466 + * @file
17467 + *
17468 + * This file contains the Attach Detect Protocol interfaces and defines
17469 + * (functions) and structures for Linux.
17470 + *
17471 + */
17472 +
17473 +#define DWC_OTG_ADP_UNATTACHED 0
17474 +#define DWC_OTG_ADP_ATTACHED 1
17475 +#define DWC_OTG_ADP_UNKOWN 2
17476 +
17477 +typedef struct dwc_otg_adp {
17478 + uint32_t adp_started;
17479 + uint32_t initial_probe;
17480 + int32_t probe_timer_values[2];
17481 + uint32_t probe_enabled;
17482 + uint32_t sense_enabled;
17483 + dwc_timer_t *sense_timer;
17484 + uint32_t sense_timer_started;
17485 + dwc_timer_t *vbuson_timer;
17486 + uint32_t vbuson_timer_started;
17487 + uint32_t attached;
17488 + uint32_t probe_counter;
17489 + uint32_t gpwrdn;
17490 +} dwc_otg_adp_t;
17491 +
17492 +/**
17493 + * Attach Detect Protocol functions
17494 + */
17495 +
17496 +extern void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value);
17497 +extern uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if);
17498 +extern uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if);
17499 +extern uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if);
17500 +extern uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if);
17501 +extern uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if);
17502 +extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
17503 +extern void dwc_otg_adp_init(dwc_otg_core_if_t * core_if);
17504 +extern void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if);
17505 +extern int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if);
17506 +extern int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if);
17507 +
17508 +#endif //__DWC_OTG_ADP_H__
17509 --- /dev/null
17510 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
17511 @@ -0,0 +1,1210 @@
17512 +/* ==========================================================================
17513 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $
17514 + * $Revision: #44 $
17515 + * $Date: 2010/11/29 $
17516 + * $Change: 1636033 $
17517 + *
17518 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
17519 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
17520 + * otherwise expressly agreed to in writing between Synopsys and you.
17521 + *
17522 + * The Software IS NOT an item of Licensed Software or Licensed Product under
17523 + * any End User Software License Agreement or Agreement for Licensed Product
17524 + * with Synopsys or any supplement thereto. You are permitted to use and
17525 + * redistribute this Software in source and binary forms, with or without
17526 + * modification, provided that redistributions of source code must retain this
17527 + * notice. You may not view, use, disclose, copy or distribute this file or
17528 + * any information contained herein except pursuant to this license grant from
17529 + * Synopsys. If you do not agree with this notice, including the disclaimer
17530 + * below, then you are not authorized to use the Software.
17531 + *
17532 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
17533 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17534 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17535 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
17536 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17537 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17538 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17539 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17540 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17541 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
17542 + * DAMAGE.
17543 + * ========================================================================== */
17544 +
17545 +/** @file
17546 + *
17547 + * The diagnostic interface will provide access to the controller for
17548 + * bringing up the hardware and testing. The Linux driver attributes
17549 + * feature will be used to provide the Linux Diagnostic
17550 + * Interface. These attributes are accessed through sysfs.
17551 + */
17552 +
17553 +/** @page "Linux Module Attributes"
17554 + *
17555 + * The Linux module attributes feature is used to provide the Linux
17556 + * Diagnostic Interface. These attributes are accessed through sysfs.
17557 + * The diagnostic interface will provide access to the controller for
17558 + * bringing up the hardware and testing.
17559 +
17560 + The following table shows the attributes.
17561 + <table>
17562 + <tr>
17563 + <td><b> Name</b></td>
17564 + <td><b> Description</b></td>
17565 + <td><b> Access</b></td>
17566 + </tr>
17567 +
17568 + <tr>
17569 + <td> mode </td>
17570 + <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
17571 + <td> Read</td>
17572 + </tr>
17573 +
17574 + <tr>
17575 + <td> hnpcapable </td>
17576 + <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
17577 + Read returns the current value.</td>
17578 + <td> Read/Write</td>
17579 + </tr>
17580 +
17581 + <tr>
17582 + <td> srpcapable </td>
17583 + <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
17584 + Read returns the current value.</td>
17585 + <td> Read/Write</td>
17586 + </tr>
17587 +
17588 + <tr>
17589 + <td> hsic_connect </td>
17590 + <td> Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register.
17591 + Read returns the current value.</td>
17592 + <td> Read/Write</td>
17593 + </tr>
17594 +
17595 + <tr>
17596 + <td> inv_sel_hsic </td>
17597 + <td> Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register.
17598 + Read returns the current value.</td>
17599 + <td> Read/Write</td>
17600 + </tr>
17601 +
17602 + <tr>
17603 + <td> hnp </td>
17604 + <td> Initiates the Host Negotiation Protocol. Read returns the status.</td>
17605 + <td> Read/Write</td>
17606 + </tr>
17607 +
17608 + <tr>
17609 + <td> srp </td>
17610 + <td> Initiates the Session Request Protocol. Read returns the status.</td>
17611 + <td> Read/Write</td>
17612 + </tr>
17613 +
17614 + <tr>
17615 + <td> buspower </td>
17616 + <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
17617 + <td> Read/Write</td>
17618 + </tr>
17619 +
17620 + <tr>
17621 + <td> bussuspend </td>
17622 + <td> Suspends the USB bus.</td>
17623 + <td> Read/Write</td>
17624 + </tr>
17625 +
17626 + <tr>
17627 + <td> busconnected </td>
17628 + <td> Gets the connection status of the bus</td>
17629 + <td> Read</td>
17630 + </tr>
17631 +
17632 + <tr>
17633 + <td> gotgctl </td>
17634 + <td> Gets or sets the Core Control Status Register.</td>
17635 + <td> Read/Write</td>
17636 + </tr>
17637 +
17638 + <tr>
17639 + <td> gusbcfg </td>
17640 + <td> Gets or sets the Core USB Configuration Register</td>
17641 + <td> Read/Write</td>
17642 + </tr>
17643 +
17644 + <tr>
17645 + <td> grxfsiz </td>
17646 + <td> Gets or sets the Receive FIFO Size Register</td>
17647 + <td> Read/Write</td>
17648 + </tr>
17649 +
17650 + <tr>
17651 + <td> gnptxfsiz </td>
17652 + <td> Gets or sets the non-periodic Transmit Size Register</td>
17653 + <td> Read/Write</td>
17654 + </tr>
17655 +
17656 + <tr>
17657 + <td> gpvndctl </td>
17658 + <td> Gets or sets the PHY Vendor Control Register</td>
17659 + <td> Read/Write</td>
17660 + </tr>
17661 +
17662 + <tr>
17663 + <td> ggpio </td>
17664 + <td> Gets the value in the lower 16-bits of the General Purpose IO Register
17665 + or sets the upper 16 bits.</td>
17666 + <td> Read/Write</td>
17667 + </tr>
17668 +
17669 + <tr>
17670 + <td> guid </td>
17671 + <td> Gets or sets the value of the User ID Register</td>
17672 + <td> Read/Write</td>
17673 + </tr>
17674 +
17675 + <tr>
17676 + <td> gsnpsid </td>
17677 + <td> Gets the value of the Synopsys ID Regester</td>
17678 + <td> Read</td>
17679 + </tr>
17680 +
17681 + <tr>
17682 + <td> devspeed </td>
17683 + <td> Gets or sets the device speed setting in the DCFG register</td>
17684 + <td> Read/Write</td>
17685 + </tr>
17686 +
17687 + <tr>
17688 + <td> enumspeed </td>
17689 + <td> Gets the device enumeration Speed.</td>
17690 + <td> Read</td>
17691 + </tr>
17692 +
17693 + <tr>
17694 + <td> hptxfsiz </td>
17695 + <td> Gets the value of the Host Periodic Transmit FIFO</td>
17696 + <td> Read</td>
17697 + </tr>
17698 +
17699 + <tr>
17700 + <td> hprt0 </td>
17701 + <td> Gets or sets the value in the Host Port Control and Status Register</td>
17702 + <td> Read/Write</td>
17703 + </tr>
17704 +
17705 + <tr>
17706 + <td> regoffset </td>
17707 + <td> Sets the register offset for the next Register Access</td>
17708 + <td> Read/Write</td>
17709 + </tr>
17710 +
17711 + <tr>
17712 + <td> regvalue </td>
17713 + <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
17714 + <td> Read/Write</td>
17715 + </tr>
17716 +
17717 + <tr>
17718 + <td> remote_wakeup </td>
17719 + <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
17720 + wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
17721 + Wakeup signalling bit in the Device Control Register is set for 1
17722 + milli-second.</td>
17723 + <td> Read/Write</td>
17724 + </tr>
17725 +
17726 + <tr>
17727 + <td> rem_wakeup_pwrdn </td>
17728 + <td> On read, shows the status core - hibernated or not. On write, initiates
17729 + a remote wakeup of the device from Hibernation. </td>
17730 + <td> Read/Write</td>
17731 + </tr>
17732 +
17733 + <tr>
17734 + <td> mode_ch_tim_en </td>
17735 + <td> This bit is used to enable or disable the host core to wait for 200 PHY
17736 + clock cycles at the end of Resume to change the opmode signal to the PHY to 00
17737 + after Suspend or LPM. </td>
17738 + <td> Read/Write</td>
17739 + </tr>
17740 +
17741 + <tr>
17742 + <td> fr_interval </td>
17743 + <td> On read, shows the value of HFIR Frame Interval. On write, dynamically
17744 + reload HFIR register during runtime. The application can write a value to this
17745 + register only after the Port Enable bit of the Host Port Control and Status
17746 + register (HPRT.PrtEnaPort) has been set </td>
17747 + <td> Read/Write</td>
17748 + </tr>
17749 +
17750 + <tr>
17751 + <td> disconnect_us </td>
17752 + <td> On read, shows the status of disconnect_device_us. On write, sets disconnect_us
17753 + which causes soft disconnect for 100us. Applicable only for device mode of operation.</td>
17754 + <td> Read/Write</td>
17755 + </tr>
17756 +
17757 + <tr>
17758 + <td> regdump </td>
17759 + <td> Dumps the contents of core registers.</td>
17760 + <td> Read</td>
17761 + </tr>
17762 +
17763 + <tr>
17764 + <td> spramdump </td>
17765 + <td> Dumps the contents of core registers.</td>
17766 + <td> Read</td>
17767 + </tr>
17768 +
17769 + <tr>
17770 + <td> hcddump </td>
17771 + <td> Dumps the current HCD state.</td>
17772 + <td> Read</td>
17773 + </tr>
17774 +
17775 + <tr>
17776 + <td> hcd_frrem </td>
17777 + <td> Shows the average value of the Frame Remaining
17778 + field in the Host Frame Number/Frame Remaining register when an SOF interrupt
17779 + occurs. This can be used to determine the average interrupt latency. Also
17780 + shows the average Frame Remaining value for start_transfer and the "a" and
17781 + "b" sample points. The "a" and "b" sample points may be used during debugging
17782 + bto determine how long it takes to execute a section of the HCD code.</td>
17783 + <td> Read</td>
17784 + </tr>
17785 +
17786 + <tr>
17787 + <td> rd_reg_test </td>
17788 + <td> Displays the time required to read the GNPTXFSIZ register many times
17789 + (the output shows the number of times the register is read).
17790 + <td> Read</td>
17791 + </tr>
17792 +
17793 + <tr>
17794 + <td> wr_reg_test </td>
17795 + <td> Displays the time required to write the GNPTXFSIZ register many times
17796 + (the output shows the number of times the register is written).
17797 + <td> Read</td>
17798 + </tr>
17799 +
17800 + <tr>
17801 + <td> lpm_response </td>
17802 + <td> Gets or sets lpm_response mode. Applicable only in device mode.
17803 + <td> Write</td>
17804 + </tr>
17805 +
17806 + <tr>
17807 + <td> sleep_status </td>
17808 + <td> Shows sleep status of device.
17809 + <td> Read</td>
17810 + </tr>
17811 +
17812 + </table>
17813 +
17814 + Example usage:
17815 + To get the current mode:
17816 + cat /sys/devices/lm0/mode
17817 +
17818 + To power down the USB:
17819 + echo 0 > /sys/devices/lm0/buspower
17820 + */
17821 +
17822 +#include "dwc_otg_os_dep.h"
17823 +#include "dwc_os.h"
17824 +#include "dwc_otg_driver.h"
17825 +#include "dwc_otg_attr.h"
17826 +#include "dwc_otg_core_if.h"
17827 +#include "dwc_otg_pcd_if.h"
17828 +#include "dwc_otg_hcd_if.h"
17829 +
17830 +/*
17831 + * MACROs for defining sysfs attribute
17832 + */
17833 +#ifdef LM_INTERFACE
17834 +
17835 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17836 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17837 +{ \
17838 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17839 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17840 + uint32_t val; \
17841 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17842 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17843 +}
17844 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17845 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17846 + const char *buf, size_t count) \
17847 +{ \
17848 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17849 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17850 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17851 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17852 + return count; \
17853 +}
17854 +
17855 +#elif defined(PCI_INTERFACE)
17856 +
17857 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17858 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17859 +{ \
17860 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17861 + uint32_t val; \
17862 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17863 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17864 +}
17865 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17866 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17867 + const char *buf, size_t count) \
17868 +{ \
17869 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17870 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17871 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17872 + return count; \
17873 +}
17874 +
17875 +#elif defined(PLATFORM_INTERFACE)
17876 +
17877 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17878 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17879 +{ \
17880 + struct platform_device *platform_dev = \
17881 + container_of(_dev, struct platform_device, dev); \
17882 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17883 + uint32_t val; \
17884 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
17885 + __func__, _dev, platform_dev, otg_dev); \
17886 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17887 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17888 +}
17889 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17890 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17891 + const char *buf, size_t count) \
17892 +{ \
17893 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
17894 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17895 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17896 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17897 + return count; \
17898 +}
17899 +#endif
17900 +
17901 +/*
17902 + * MACROs for defining sysfs attribute for 32-bit registers
17903 + */
17904 +#ifdef LM_INTERFACE
17905 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17906 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17907 +{ \
17908 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17909 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17910 + uint32_t val; \
17911 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17912 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
17913 +}
17914 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17915 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17916 + const char *buf, size_t count) \
17917 +{ \
17918 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17919 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17920 + uint32_t val = simple_strtoul(buf, NULL, 16); \
17921 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
17922 + return count; \
17923 +}
17924 +#elif defined(PCI_INTERFACE)
17925 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17926 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17927 +{ \
17928 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17929 + uint32_t val; \
17930 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17931 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
17932 +}
17933 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17934 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17935 + const char *buf, size_t count) \
17936 +{ \
17937 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17938 + uint32_t val = simple_strtoul(buf, NULL, 16); \
17939 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
17940 + return count; \
17941 +}
17942 +
17943 +#elif defined(PLATFORM_INTERFACE)
17944 +#include "dwc_otg_dbg.h"
17945 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17946 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17947 +{ \
17948 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
17949 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17950 + uint32_t val; \
17951 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
17952 + __func__, _dev, platform_dev, otg_dev); \
17953 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17954 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
17955 +}
17956 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17957 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17958 + const char *buf, size_t count) \
17959 +{ \
17960 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
17961 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17962 + uint32_t val = simple_strtoul(buf, NULL, 16); \
17963 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
17964 + return count; \
17965 +}
17966 +
17967 +#endif
17968 +
17969 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \
17970 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17971 +DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17972 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
17973 +
17974 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \
17975 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17976 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
17977 +
17978 +#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
17979 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17980 +DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17981 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
17982 +
17983 +#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
17984 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17985 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
17986 +
17987 +/** @name Functions for Show/Store of Attributes */
17988 +/**@{*/
17989 +
17990 +/**
17991 + * Helper function returning the otg_device structure of the given device
17992 + */
17993 +static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
17994 +{
17995 + dwc_otg_device_t *otg_dev;
17996 + DWC_OTG_GETDRVDEV(otg_dev, _dev);
17997 + return otg_dev;
17998 +}
17999 +
18000 +/**
18001 + * Show the register offset of the Register Access.
18002 + */
18003 +static ssize_t regoffset_show(struct device *_dev,
18004 + struct device_attribute *attr, char *buf)
18005 +{
18006 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18007 + return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
18008 + otg_dev->os_dep.reg_offset);
18009 +}
18010 +
18011 +/**
18012 + * Set the register offset for the next Register Access Read/Write
18013 + */
18014 +static ssize_t regoffset_store(struct device *_dev,
18015 + struct device_attribute *attr,
18016 + const char *buf, size_t count)
18017 +{
18018 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18019 + uint32_t offset = simple_strtoul(buf, NULL, 16);
18020 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
18021 + if (offset < SZ_256K) {
18022 +#elif defined(PCI_INTERFACE)
18023 + if (offset < 0x00040000) {
18024 +#endif
18025 + otg_dev->os_dep.reg_offset = offset;
18026 + } else {
18027 + dev_err(_dev, "invalid offset\n");
18028 + }
18029 +
18030 + return count;
18031 +}
18032 +
18033 +DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
18034 +
18035 +/**
18036 + * Show the value of the register at the offset in the reg_offset
18037 + * attribute.
18038 + */
18039 +static ssize_t regvalue_show(struct device *_dev,
18040 + struct device_attribute *attr, char *buf)
18041 +{
18042 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18043 + uint32_t val;
18044 + volatile uint32_t *addr;
18045 +
18046 + if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
18047 + /* Calculate the address */
18048 + addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
18049 + (uint8_t *) otg_dev->os_dep.base);
18050 + val = DWC_READ_REG32(addr);
18051 + return snprintf(buf,
18052 + sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
18053 + "Reg@0x%06x = 0x%08x\n", otg_dev->os_dep.reg_offset,
18054 + val);
18055 + } else {
18056 + dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->os_dep.reg_offset);
18057 + return sprintf(buf, "invalid offset\n");
18058 + }
18059 +}
18060 +
18061 +/**
18062 + * Store the value in the register at the offset in the reg_offset
18063 + * attribute.
18064 + *
18065 + */
18066 +static ssize_t regvalue_store(struct device *_dev,
18067 + struct device_attribute *attr,
18068 + const char *buf, size_t count)
18069 +{
18070 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18071 + volatile uint32_t *addr;
18072 + uint32_t val = simple_strtoul(buf, NULL, 16);
18073 + //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
18074 + if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
18075 + /* Calculate the address */
18076 + addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
18077 + (uint8_t *) otg_dev->os_dep.base);
18078 + DWC_WRITE_REG32(addr, val);
18079 + } else {
18080 + dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
18081 + otg_dev->os_dep.reg_offset);
18082 + }
18083 + return count;
18084 +}
18085 +
18086 +DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
18087 +
18088 +/*
18089 + * Attributes
18090 + */
18091 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
18092 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
18093 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "SRPCapable");
18094 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
18095 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");
18096 +
18097 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
18098 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
18099 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");
18100 +
18101 +DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
18102 +DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
18103 + &(otg_dev->core_if->core_global_regs->gusbcfg),
18104 + "GUSBCFG");
18105 +DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
18106 + &(otg_dev->core_if->core_global_regs->grxfsiz),
18107 + "GRXFSIZ");
18108 +DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
18109 + &(otg_dev->core_if->core_global_regs->gnptxfsiz),
18110 + "GNPTXFSIZ");
18111 +DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
18112 + &(otg_dev->core_if->core_global_regs->gpvndctl),
18113 + "GPVNDCTL");
18114 +DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
18115 + &(otg_dev->core_if->core_global_regs->ggpio),
18116 + "GGPIO");
18117 +DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
18118 + "GUID");
18119 +DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
18120 + &(otg_dev->core_if->core_global_regs->gsnpsid),
18121 + "GSNPSID");
18122 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
18123 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");
18124 +
18125 +DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
18126 + &(otg_dev->core_if->core_global_regs->hptxfsiz),
18127 + "HPTXFSIZ");
18128 +DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
18129 +
18130 +/**
18131 + * @todo Add code to initiate the HNP.
18132 + */
18133 +/**
18134 + * Show the HNP status bit
18135 + */
18136 +static ssize_t hnp_show(struct device *_dev,
18137 + struct device_attribute *attr, char *buf)
18138 +{
18139 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18140 + return sprintf(buf, "HstNegScs = 0x%x\n",
18141 + dwc_otg_get_hnpstatus(otg_dev->core_if));
18142 +}
18143 +
18144 +/**
18145 + * Set the HNP Request bit
18146 + */
18147 +static ssize_t hnp_store(struct device *_dev,
18148 + struct device_attribute *attr,
18149 + const char *buf, size_t count)
18150 +{
18151 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18152 + uint32_t in = simple_strtoul(buf, NULL, 16);
18153 + dwc_otg_set_hnpreq(otg_dev->core_if, in);
18154 + return count;
18155 +}
18156 +
18157 +DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
18158 +
18159 +/**
18160 + * @todo Add code to initiate the SRP.
18161 + */
18162 +/**
18163 + * Show the SRP status bit
18164 + */
18165 +static ssize_t srp_show(struct device *_dev,
18166 + struct device_attribute *attr, char *buf)
18167 +{
18168 +#ifndef DWC_HOST_ONLY
18169 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18170 + return sprintf(buf, "SesReqScs = 0x%x\n",
18171 + dwc_otg_get_srpstatus(otg_dev->core_if));
18172 +#else
18173 + return sprintf(buf, "Host Only Mode!\n");
18174 +#endif
18175 +}
18176 +
18177 +/**
18178 + * Set the SRP Request bit
18179 + */
18180 +static ssize_t srp_store(struct device *_dev,
18181 + struct device_attribute *attr,
18182 + const char *buf, size_t count)
18183 +{
18184 +#ifndef DWC_HOST_ONLY
18185 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18186 + dwc_otg_pcd_initiate_srp(otg_dev->pcd);
18187 +#endif
18188 + return count;
18189 +}
18190 +
18191 +DEVICE_ATTR(srp, 0644, srp_show, srp_store);
18192 +
18193 +/**
18194 + * @todo Need to do more for power on/off?
18195 + */
18196 +/**
18197 + * Show the Bus Power status
18198 + */
18199 +static ssize_t buspower_show(struct device *_dev,
18200 + struct device_attribute *attr, char *buf)
18201 +{
18202 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18203 + return sprintf(buf, "Bus Power = 0x%x\n",
18204 + dwc_otg_get_prtpower(otg_dev->core_if));
18205 +}
18206 +
18207 +/**
18208 + * Set the Bus Power status
18209 + */
18210 +static ssize_t buspower_store(struct device *_dev,
18211 + struct device_attribute *attr,
18212 + const char *buf, size_t count)
18213 +{
18214 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18215 + uint32_t on = simple_strtoul(buf, NULL, 16);
18216 + dwc_otg_set_prtpower(otg_dev->core_if, on);
18217 + return count;
18218 +}
18219 +
18220 +DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
18221 +
18222 +/**
18223 + * @todo Need to do more for suspend?
18224 + */
18225 +/**
18226 + * Show the Bus Suspend status
18227 + */
18228 +static ssize_t bussuspend_show(struct device *_dev,
18229 + struct device_attribute *attr, char *buf)
18230 +{
18231 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18232 + return sprintf(buf, "Bus Suspend = 0x%x\n",
18233 + dwc_otg_get_prtsuspend(otg_dev->core_if));
18234 +}
18235 +
18236 +/**
18237 + * Set the Bus Suspend status
18238 + */
18239 +static ssize_t bussuspend_store(struct device *_dev,
18240 + struct device_attribute *attr,
18241 + const char *buf, size_t count)
18242 +{
18243 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18244 + uint32_t in = simple_strtoul(buf, NULL, 16);
18245 + dwc_otg_set_prtsuspend(otg_dev->core_if, in);
18246 + return count;
18247 +}
18248 +
18249 +DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
18250 +
18251 +/**
18252 + * Show the Mode Change Ready Timer status
18253 + */
18254 +static ssize_t mode_ch_tim_en_show(struct device *_dev,
18255 + struct device_attribute *attr, char *buf)
18256 +{
18257 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18258 + return sprintf(buf, "Mode Change Ready Timer Enable = 0x%x\n",
18259 + dwc_otg_get_mode_ch_tim(otg_dev->core_if));
18260 +}
18261 +
18262 +/**
18263 + * Set the Mode Change Ready Timer status
18264 + */
18265 +static ssize_t mode_ch_tim_en_store(struct device *_dev,
18266 + struct device_attribute *attr,
18267 + const char *buf, size_t count)
18268 +{
18269 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18270 + uint32_t in = simple_strtoul(buf, NULL, 16);
18271 + dwc_otg_set_mode_ch_tim(otg_dev->core_if, in);
18272 + return count;
18273 +}
18274 +
18275 +DEVICE_ATTR(mode_ch_tim_en, 0644, mode_ch_tim_en_show, mode_ch_tim_en_store);
18276 +
18277 +/**
18278 + * Show the value of HFIR Frame Interval bitfield
18279 + */
18280 +static ssize_t fr_interval_show(struct device *_dev,
18281 + struct device_attribute *attr, char *buf)
18282 +{
18283 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18284 + return sprintf(buf, "Frame Interval = 0x%x\n",
18285 + dwc_otg_get_fr_interval(otg_dev->core_if));
18286 +}
18287 +
18288 +/**
18289 + * Set the HFIR Frame Interval value
18290 + */
18291 +static ssize_t fr_interval_store(struct device *_dev,
18292 + struct device_attribute *attr,
18293 + const char *buf, size_t count)
18294 +{
18295 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18296 + uint32_t in = simple_strtoul(buf, NULL, 10);
18297 + dwc_otg_set_fr_interval(otg_dev->core_if, in);
18298 + return count;
18299 +}
18300 +
18301 +DEVICE_ATTR(fr_interval, 0644, fr_interval_show, fr_interval_store);
18302 +
18303 +/**
18304 + * Show the status of Remote Wakeup.
18305 + */
18306 +static ssize_t remote_wakeup_show(struct device *_dev,
18307 + struct device_attribute *attr, char *buf)
18308 +{
18309 +#ifndef DWC_HOST_ONLY
18310 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18311 +
18312 + return sprintf(buf,
18313 + "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
18314 + dwc_otg_get_remotewakesig(otg_dev->core_if),
18315 + dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
18316 + dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
18317 +#else
18318 + return sprintf(buf, "Host Only Mode!\n");
18319 +#endif /* DWC_HOST_ONLY */
18320 +}
18321 +
18322 +/**
18323 + * Initiate a remote wakeup of the host. The Device control register
18324 + * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
18325 + * flag is set.
18326 + *
18327 + */
18328 +static ssize_t remote_wakeup_store(struct device *_dev,
18329 + struct device_attribute *attr,
18330 + const char *buf, size_t count)
18331 +{
18332 +#ifndef DWC_HOST_ONLY
18333 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18334 + uint32_t val = simple_strtoul(buf, NULL, 16);
18335 +
18336 + if (val & 1) {
18337 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
18338 + } else {
18339 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
18340 + }
18341 +#endif /* DWC_HOST_ONLY */
18342 + return count;
18343 +}
18344 +
18345 +DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
18346 + remote_wakeup_store);
18347 +
18348 +/**
18349 + * Show the whether core is hibernated or not.
18350 + */
18351 +static ssize_t rem_wakeup_pwrdn_show(struct device *_dev,
18352 + struct device_attribute *attr, char *buf)
18353 +{
18354 +#ifndef DWC_HOST_ONLY
18355 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18356 +
18357 + if (dwc_otg_get_core_state(otg_dev->core_if)) {
18358 + DWC_PRINTF("Core is in hibernation\n");
18359 + } else {
18360 + DWC_PRINTF("Core is not in hibernation\n");
18361 + }
18362 +#endif /* DWC_HOST_ONLY */
18363 + return 0;
18364 +}
18365 +
18366 +extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
18367 + int rem_wakeup, int reset);
18368 +
18369 +/**
18370 + * Initiate a remote wakeup of the device to exit from hibernation.
18371 + */
18372 +static ssize_t rem_wakeup_pwrdn_store(struct device *_dev,
18373 + struct device_attribute *attr,
18374 + const char *buf, size_t count)
18375 +{
18376 +#ifndef DWC_HOST_ONLY
18377 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18378 + dwc_otg_device_hibernation_restore(otg_dev->core_if, 1, 0);
18379 +#endif
18380 + return count;
18381 +}
18382 +
18383 +DEVICE_ATTR(rem_wakeup_pwrdn, S_IRUGO | S_IWUSR, rem_wakeup_pwrdn_show,
18384 + rem_wakeup_pwrdn_store);
18385 +
18386 +static ssize_t disconnect_us(struct device *_dev,
18387 + struct device_attribute *attr,
18388 + const char *buf, size_t count)
18389 +{
18390 +
18391 +#ifndef DWC_HOST_ONLY
18392 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18393 + uint32_t val = simple_strtoul(buf, NULL, 16);
18394 + DWC_PRINTF("The Passed value is %04x\n", val);
18395 +
18396 + dwc_otg_pcd_disconnect_us(otg_dev->pcd, 50);
18397 +
18398 +#endif /* DWC_HOST_ONLY */
18399 + return count;
18400 +}
18401 +
18402 +DEVICE_ATTR(disconnect_us, S_IWUSR, 0, disconnect_us);
18403 +
18404 +/**
18405 + * Dump global registers and either host or device registers (depending on the
18406 + * current mode of the core).
18407 + */
18408 +static ssize_t regdump_show(struct device *_dev,
18409 + struct device_attribute *attr, char *buf)
18410 +{
18411 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18412 +
18413 + dwc_otg_dump_global_registers(otg_dev->core_if);
18414 + if (dwc_otg_is_host_mode(otg_dev->core_if)) {
18415 + dwc_otg_dump_host_registers(otg_dev->core_if);
18416 + } else {
18417 + dwc_otg_dump_dev_registers(otg_dev->core_if);
18418 +
18419 + }
18420 + return sprintf(buf, "Register Dump\n");
18421 +}
18422 +
18423 +DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);
18424 +
18425 +/**
18426 + * Dump global registers and either host or device registers (depending on the
18427 + * current mode of the core).
18428 + */
18429 +static ssize_t spramdump_show(struct device *_dev,
18430 + struct device_attribute *attr, char *buf)
18431 +{
18432 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18433 +
18434 + dwc_otg_dump_spram(otg_dev->core_if);
18435 +
18436 + return sprintf(buf, "SPRAM Dump\n");
18437 +}
18438 +
18439 +DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);
18440 +
18441 +/**
18442 + * Dump the current hcd state.
18443 + */
18444 +static ssize_t hcddump_show(struct device *_dev,
18445 + struct device_attribute *attr, char *buf)
18446 +{
18447 +#ifndef DWC_DEVICE_ONLY
18448 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18449 + dwc_otg_hcd_dump_state(otg_dev->hcd);
18450 +#endif /* DWC_DEVICE_ONLY */
18451 + return sprintf(buf, "HCD Dump\n");
18452 +}
18453 +
18454 +DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);
18455 +
18456 +/**
18457 + * Dump the average frame remaining at SOF. This can be used to
18458 + * determine average interrupt latency. Frame remaining is also shown for
18459 + * start transfer and two additional sample points.
18460 + */
18461 +static ssize_t hcd_frrem_show(struct device *_dev,
18462 + struct device_attribute *attr, char *buf)
18463 +{
18464 +#ifndef DWC_DEVICE_ONLY
18465 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18466 +
18467 + dwc_otg_hcd_dump_frrem(otg_dev->hcd);
18468 +#endif /* DWC_DEVICE_ONLY */
18469 + return sprintf(buf, "HCD Dump Frame Remaining\n");
18470 +}
18471 +
18472 +DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);
18473 +
18474 +/**
18475 + * Displays the time required to read the GNPTXFSIZ register many times (the
18476 + * output shows the number of times the register is read).
18477 + */
18478 +#define RW_REG_COUNT 10000000
18479 +#define MSEC_PER_JIFFIE 1000/HZ
18480 +static ssize_t rd_reg_test_show(struct device *_dev,
18481 + struct device_attribute *attr, char *buf)
18482 +{
18483 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18484 + int i;
18485 + int time;
18486 + int start_jiffies;
18487 +
18488 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
18489 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
18490 + start_jiffies = jiffies;
18491 + for (i = 0; i < RW_REG_COUNT; i++) {
18492 + dwc_otg_get_gnptxfsiz(otg_dev->core_if);
18493 + }
18494 + time = jiffies - start_jiffies;
18495 + return sprintf(buf,
18496 + "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
18497 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
18498 +}
18499 +
18500 +DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);
18501 +
18502 +/**
18503 + * Displays the time required to write the GNPTXFSIZ register many times (the
18504 + * output shows the number of times the register is written).
18505 + */
18506 +static ssize_t wr_reg_test_show(struct device *_dev,
18507 + struct device_attribute *attr, char *buf)
18508 +{
18509 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18510 + uint32_t reg_val;
18511 + int i;
18512 + int time;
18513 + int start_jiffies;
18514 +
18515 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
18516 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
18517 + reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
18518 + start_jiffies = jiffies;
18519 + for (i = 0; i < RW_REG_COUNT; i++) {
18520 + dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);
18521 + }
18522 + time = jiffies - start_jiffies;
18523 + return sprintf(buf,
18524 + "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
18525 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
18526 +}
18527 +
18528 +DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);
18529 +
18530 +#ifdef CONFIG_USB_DWC_OTG_LPM
18531 +
18532 +/**
18533 +* Show the lpm_response attribute.
18534 +*/
18535 +static ssize_t lpmresp_show(struct device *_dev,
18536 + struct device_attribute *attr, char *buf)
18537 +{
18538 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18539 +
18540 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
18541 + return sprintf(buf, "** LPM is DISABLED **\n");
18542 +
18543 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
18544 + return sprintf(buf, "** Current mode is not device mode\n");
18545 + }
18546 + return sprintf(buf, "lpm_response = %d\n",
18547 + dwc_otg_get_lpmresponse(otg_dev->core_if));
18548 +}
18549 +
18550 +/**
18551 +* Store the lpm_response attribute.
18552 +*/
18553 +static ssize_t lpmresp_store(struct device *_dev,
18554 + struct device_attribute *attr,
18555 + const char *buf, size_t count)
18556 +{
18557 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18558 + uint32_t val = simple_strtoul(buf, NULL, 16);
18559 +
18560 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
18561 + return 0;
18562 + }
18563 +
18564 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
18565 + return 0;
18566 + }
18567 +
18568 + dwc_otg_set_lpmresponse(otg_dev->core_if, val);
18569 + return count;
18570 +}
18571 +
18572 +DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);
18573 +
18574 +/**
18575 +* Show the sleep_status attribute.
18576 +*/
18577 +static ssize_t sleepstatus_show(struct device *_dev,
18578 + struct device_attribute *attr, char *buf)
18579 +{
18580 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18581 + return sprintf(buf, "Sleep Status = %d\n",
18582 + dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
18583 +}
18584 +
18585 +/**
18586 + * Store the sleep_status attribure.
18587 + */
18588 +static ssize_t sleepstatus_store(struct device *_dev,
18589 + struct device_attribute *attr,
18590 + const char *buf, size_t count)
18591 +{
18592 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18593 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
18594 +
18595 + if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
18596 + if (dwc_otg_is_host_mode(core_if)) {
18597 +
18598 + DWC_PRINTF("Host initiated resume\n");
18599 + dwc_otg_set_prtresume(otg_dev->core_if, 1);
18600 + }
18601 + }
18602 +
18603 + return count;
18604 +}
18605 +
18606 +DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
18607 + sleepstatus_store);
18608 +
18609 +#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */
18610 +
18611 +/**@}*/
18612 +
18613 +/**
18614 + * Create the device files
18615 + */
18616 +void dwc_otg_attr_create(
18617 +#ifdef LM_INTERFACE
18618 + struct lm_device *dev
18619 +#elif defined(PCI_INTERFACE)
18620 + struct pci_dev *dev
18621 +#elif defined(PLATFORM_INTERFACE)
18622 + struct platform_device *dev
18623 +#endif
18624 + )
18625 +{
18626 + int error;
18627 +
18628 + error = device_create_file(&dev->dev, &dev_attr_regoffset);
18629 + error = device_create_file(&dev->dev, &dev_attr_regvalue);
18630 + error = device_create_file(&dev->dev, &dev_attr_mode);
18631 + error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
18632 + error = device_create_file(&dev->dev, &dev_attr_srpcapable);
18633 + error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
18634 + error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
18635 + error = device_create_file(&dev->dev, &dev_attr_hnp);
18636 + error = device_create_file(&dev->dev, &dev_attr_srp);
18637 + error = device_create_file(&dev->dev, &dev_attr_buspower);
18638 + error = device_create_file(&dev->dev, &dev_attr_bussuspend);
18639 + error = device_create_file(&dev->dev, &dev_attr_mode_ch_tim_en);
18640 + error = device_create_file(&dev->dev, &dev_attr_fr_interval);
18641 + error = device_create_file(&dev->dev, &dev_attr_busconnected);
18642 + error = device_create_file(&dev->dev, &dev_attr_gotgctl);
18643 + error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
18644 + error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
18645 + error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
18646 + error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
18647 + error = device_create_file(&dev->dev, &dev_attr_ggpio);
18648 + error = device_create_file(&dev->dev, &dev_attr_guid);
18649 + error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
18650 + error = device_create_file(&dev->dev, &dev_attr_devspeed);
18651 + error = device_create_file(&dev->dev, &dev_attr_enumspeed);
18652 + error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
18653 + error = device_create_file(&dev->dev, &dev_attr_hprt0);
18654 + error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
18655 + error = device_create_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
18656 + error = device_create_file(&dev->dev, &dev_attr_disconnect_us);
18657 + error = device_create_file(&dev->dev, &dev_attr_regdump);
18658 + error = device_create_file(&dev->dev, &dev_attr_spramdump);
18659 + error = device_create_file(&dev->dev, &dev_attr_hcddump);
18660 + error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
18661 + error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
18662 + error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
18663 +#ifdef CONFIG_USB_DWC_OTG_LPM
18664 + error = device_create_file(&dev->dev, &dev_attr_lpm_response);
18665 + error = device_create_file(&dev->dev, &dev_attr_sleep_status);
18666 +#endif
18667 +}
18668 +
18669 +/**
18670 + * Remove the device files
18671 + */
18672 +void dwc_otg_attr_remove(
18673 +#ifdef LM_INTERFACE
18674 + struct lm_device *dev
18675 +#elif defined(PCI_INTERFACE)
18676 + struct pci_dev *dev
18677 +#elif defined(PLATFORM_INTERFACE)
18678 + struct platform_device *dev
18679 +#endif
18680 + )
18681 +{
18682 + device_remove_file(&dev->dev, &dev_attr_regoffset);
18683 + device_remove_file(&dev->dev, &dev_attr_regvalue);
18684 + device_remove_file(&dev->dev, &dev_attr_mode);
18685 + device_remove_file(&dev->dev, &dev_attr_hnpcapable);
18686 + device_remove_file(&dev->dev, &dev_attr_srpcapable);
18687 + device_remove_file(&dev->dev, &dev_attr_hsic_connect);
18688 + device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
18689 + device_remove_file(&dev->dev, &dev_attr_hnp);
18690 + device_remove_file(&dev->dev, &dev_attr_srp);
18691 + device_remove_file(&dev->dev, &dev_attr_buspower);
18692 + device_remove_file(&dev->dev, &dev_attr_bussuspend);
18693 + device_remove_file(&dev->dev, &dev_attr_mode_ch_tim_en);
18694 + device_remove_file(&dev->dev, &dev_attr_fr_interval);
18695 + device_remove_file(&dev->dev, &dev_attr_busconnected);
18696 + device_remove_file(&dev->dev, &dev_attr_gotgctl);
18697 + device_remove_file(&dev->dev, &dev_attr_gusbcfg);
18698 + device_remove_file(&dev->dev, &dev_attr_grxfsiz);
18699 + device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
18700 + device_remove_file(&dev->dev, &dev_attr_gpvndctl);
18701 + device_remove_file(&dev->dev, &dev_attr_ggpio);
18702 + device_remove_file(&dev->dev, &dev_attr_guid);
18703 + device_remove_file(&dev->dev, &dev_attr_gsnpsid);
18704 + device_remove_file(&dev->dev, &dev_attr_devspeed);
18705 + device_remove_file(&dev->dev, &dev_attr_enumspeed);
18706 + device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
18707 + device_remove_file(&dev->dev, &dev_attr_hprt0);
18708 + device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
18709 + device_remove_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
18710 + device_remove_file(&dev->dev, &dev_attr_disconnect_us);
18711 + device_remove_file(&dev->dev, &dev_attr_regdump);
18712 + device_remove_file(&dev->dev, &dev_attr_spramdump);
18713 + device_remove_file(&dev->dev, &dev_attr_hcddump);
18714 + device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
18715 + device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
18716 + device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
18717 +#ifdef CONFIG_USB_DWC_OTG_LPM
18718 + device_remove_file(&dev->dev, &dev_attr_lpm_response);
18719 + device_remove_file(&dev->dev, &dev_attr_sleep_status);
18720 +#endif
18721 +}
18722 --- /dev/null
18723 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
18724 @@ -0,0 +1,89 @@
18725 +/* ==========================================================================
18726 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
18727 + * $Revision: #13 $
18728 + * $Date: 2010/06/21 $
18729 + * $Change: 1532021 $
18730 + *
18731 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
18732 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
18733 + * otherwise expressly agreed to in writing between Synopsys and you.
18734 + *
18735 + * The Software IS NOT an item of Licensed Software or Licensed Product under
18736 + * any End User Software License Agreement or Agreement for Licensed Product
18737 + * with Synopsys or any supplement thereto. You are permitted to use and
18738 + * redistribute this Software in source and binary forms, with or without
18739 + * modification, provided that redistributions of source code must retain this
18740 + * notice. You may not view, use, disclose, copy or distribute this file or
18741 + * any information contained herein except pursuant to this license grant from
18742 + * Synopsys. If you do not agree with this notice, including the disclaimer
18743 + * below, then you are not authorized to use the Software.
18744 + *
18745 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
18746 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18747 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18748 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
18749 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18750 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18751 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18752 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18753 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18754 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
18755 + * DAMAGE.
18756 + * ========================================================================== */
18757 +
18758 +#if !defined(__DWC_OTG_ATTR_H__)
18759 +#define __DWC_OTG_ATTR_H__
18760 +
18761 +/** @file
18762 + * This file contains the interface to the Linux device attributes.
18763 + */
18764 +extern struct device_attribute dev_attr_regoffset;
18765 +extern struct device_attribute dev_attr_regvalue;
18766 +
18767 +extern struct device_attribute dev_attr_mode;
18768 +extern struct device_attribute dev_attr_hnpcapable;
18769 +extern struct device_attribute dev_attr_srpcapable;
18770 +extern struct device_attribute dev_attr_hnp;
18771 +extern struct device_attribute dev_attr_srp;
18772 +extern struct device_attribute dev_attr_buspower;
18773 +extern struct device_attribute dev_attr_bussuspend;
18774 +extern struct device_attribute dev_attr_mode_ch_tim_en;
18775 +extern struct device_attribute dev_attr_fr_interval;
18776 +extern struct device_attribute dev_attr_busconnected;
18777 +extern struct device_attribute dev_attr_gotgctl;
18778 +extern struct device_attribute dev_attr_gusbcfg;
18779 +extern struct device_attribute dev_attr_grxfsiz;
18780 +extern struct device_attribute dev_attr_gnptxfsiz;
18781 +extern struct device_attribute dev_attr_gpvndctl;
18782 +extern struct device_attribute dev_attr_ggpio;
18783 +extern struct device_attribute dev_attr_guid;
18784 +extern struct device_attribute dev_attr_gsnpsid;
18785 +extern struct device_attribute dev_attr_devspeed;
18786 +extern struct device_attribute dev_attr_enumspeed;
18787 +extern struct device_attribute dev_attr_hptxfsiz;
18788 +extern struct device_attribute dev_attr_hprt0;
18789 +#ifdef CONFIG_USB_DWC_OTG_LPM
18790 +extern struct device_attribute dev_attr_lpm_response;
18791 +extern struct device_attribute devi_attr_sleep_status;
18792 +#endif
18793 +
18794 +void dwc_otg_attr_create(
18795 +#ifdef LM_INTERFACE
18796 + struct lm_device *dev
18797 +#elif defined(PCI_INTERFACE)
18798 + struct pci_dev *dev
18799 +#elif defined(PLATFORM_INTERFACE)
18800 + struct platform_device *dev
18801 +#endif
18802 + );
18803 +
18804 +void dwc_otg_attr_remove(
18805 +#ifdef LM_INTERFACE
18806 + struct lm_device *dev
18807 +#elif defined(PCI_INTERFACE)
18808 + struct pci_dev *dev
18809 +#elif defined(PLATFORM_INTERFACE)
18810 + struct platform_device *dev
18811 +#endif
18812 + );
18813 +#endif
18814 --- /dev/null
18815 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.c
18816 @@ -0,0 +1,1876 @@
18817 +/* ==========================================================================
18818 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
18819 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
18820 + * otherwise expressly agreed to in writing between Synopsys and you.
18821 + *
18822 + * The Software IS NOT an item of Licensed Software or Licensed Product under
18823 + * any End User Software License Agreement or Agreement for Licensed Product
18824 + * with Synopsys or any supplement thereto. You are permitted to use and
18825 + * redistribute this Software in source and binary forms, with or without
18826 + * modification, provided that redistributions of source code must retain this
18827 + * notice. You may not view, use, disclose, copy or distribute this file or
18828 + * any information contained herein except pursuant to this license grant from
18829 + * Synopsys. If you do not agree with this notice, including the disclaimer
18830 + * below, then you are not authorized to use the Software.
18831 + *
18832 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
18833 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18834 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18835 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
18836 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18837 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18838 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18839 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18840 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18841 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
18842 + * DAMAGE.
18843 + * ========================================================================== */
18844 +
18845 +/** @file
18846 + *
18847 + * This file contains the most of the CFI(Core Feature Interface)
18848 + * implementation for the OTG.
18849 + */
18850 +
18851 +#ifdef DWC_UTE_CFI
18852 +
18853 +#include "dwc_otg_pcd.h"
18854 +#include "dwc_otg_cfi.h"
18855 +
18856 +/** This definition should actually migrate to the Portability Library */
18857 +#define DWC_CONSTANT_CPU_TO_LE16(x) (x)
18858 +
18859 +extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex);
18860 +
18861 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen);
18862 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
18863 + struct dwc_otg_pcd *pcd,
18864 + struct cfi_usb_ctrlrequest *ctrl_req);
18865 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd);
18866 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18867 + struct cfi_usb_ctrlrequest *req);
18868 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18869 + struct cfi_usb_ctrlrequest *req);
18870 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18871 + struct cfi_usb_ctrlrequest *req);
18872 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
18873 + struct cfi_usb_ctrlrequest *req);
18874 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep);
18875 +
18876 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if);
18877 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue);
18878 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue);
18879 +
18880 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if);
18881 +
18882 +/** This is the header of the all features descriptor */
18883 +static cfi_all_features_header_t all_props_desc_header = {
18884 + .wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100),
18885 + .wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG),
18886 + .wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9),
18887 +};
18888 +
18889 +/** This is an array of statically allocated feature descriptors */
18890 +static cfi_feature_desc_header_t prop_descs[] = {
18891 +
18892 + /* FT_ID_DMA_MODE */
18893 + {
18894 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE),
18895 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18896 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1),
18897 + },
18898 +
18899 + /* FT_ID_DMA_BUFFER_SETUP */
18900 + {
18901 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP),
18902 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18903 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18904 + },
18905 +
18906 + /* FT_ID_DMA_BUFF_ALIGN */
18907 + {
18908 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN),
18909 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18910 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18911 + },
18912 +
18913 + /* FT_ID_DMA_CONCAT_SETUP */
18914 + {
18915 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP),
18916 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18917 + //.wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18918 + },
18919 +
18920 + /* FT_ID_DMA_CIRCULAR */
18921 + {
18922 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR),
18923 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18924 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18925 + },
18926 +
18927 + /* FT_ID_THRESHOLD_SETUP */
18928 + {
18929 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP),
18930 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18931 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18932 + },
18933 +
18934 + /* FT_ID_DFIFO_DEPTH */
18935 + {
18936 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH),
18937 + .bmAttributes = CFI_FEATURE_ATTR_RO,
18938 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18939 + },
18940 +
18941 + /* FT_ID_TX_FIFO_DEPTH */
18942 + {
18943 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH),
18944 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18945 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18946 + },
18947 +
18948 + /* FT_ID_RX_FIFO_DEPTH */
18949 + {
18950 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH),
18951 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18952 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18953 + }
18954 +};
18955 +
18956 +/** The table of feature names */
18957 +cfi_string_t prop_name_table[] = {
18958 + {FT_ID_DMA_MODE, "dma_mode"},
18959 + {FT_ID_DMA_BUFFER_SETUP, "buffer_setup"},
18960 + {FT_ID_DMA_BUFF_ALIGN, "buffer_align"},
18961 + {FT_ID_DMA_CONCAT_SETUP, "concat_setup"},
18962 + {FT_ID_DMA_CIRCULAR, "buffer_circular"},
18963 + {FT_ID_THRESHOLD_SETUP, "threshold_setup"},
18964 + {FT_ID_DFIFO_DEPTH, "dfifo_depth"},
18965 + {FT_ID_TX_FIFO_DEPTH, "txfifo_depth"},
18966 + {FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"},
18967 + {}
18968 +};
18969 +
18970 +/************************************************************************/
18971 +
18972 +/**
18973 + * Returns the name of the feature by its ID
18974 + * or NULL if no featute ID matches.
18975 + *
18976 + */
18977 +const uint8_t *get_prop_name(uint16_t prop_id, int *len)
18978 +{
18979 + cfi_string_t *pstr;
18980 + *len = 0;
18981 +
18982 + for (pstr = prop_name_table; pstr && pstr->s; pstr++) {
18983 + if (pstr->id == prop_id) {
18984 + *len = DWC_STRLEN(pstr->s);
18985 + return pstr->s;
18986 + }
18987 + }
18988 + return NULL;
18989 +}
18990 +
18991 +/**
18992 + * This function handles all CFI specific control requests.
18993 + *
18994 + * Return a negative value to stall the DCE.
18995 + */
18996 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)
18997 +{
18998 + int retval = 0;
18999 + dwc_otg_pcd_ep_t *ep = NULL;
19000 + cfiobject_t *cfi = pcd->cfi;
19001 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
19002 + uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength);
19003 + uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue);
19004 + uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex);
19005 + uint32_t regaddr = 0;
19006 + uint32_t regval = 0;
19007 +
19008 + /* Save this Control Request in the CFI object.
19009 + * The data field will be assigned in the data stage completion CB function.
19010 + */
19011 + cfi->ctrl_req = *ctrl;
19012 + cfi->ctrl_req.data = NULL;
19013 +
19014 + cfi->need_gadget_att = 0;
19015 + cfi->need_status_in_complete = 0;
19016 +
19017 + switch (ctrl->bRequest) {
19018 + case VEN_CORE_GET_FEATURES:
19019 + retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN);
19020 + if (retval >= 0) {
19021 + //dump_msg(cfi->buf_in.buf, retval);
19022 + ep = &pcd->ep0;
19023 +
19024 + retval = min((uint16_t) retval, wLen);
19025 + /* Transfer this buffer to the host through the EP0-IN EP */
19026 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
19027 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
19028 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
19029 + ep->dwc_ep.xfer_len = retval;
19030 + ep->dwc_ep.xfer_count = 0;
19031 + ep->dwc_ep.sent_zlp = 0;
19032 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19033 +
19034 + pcd->ep0_pending = 1;
19035 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19036 + }
19037 + retval = 0;
19038 + break;
19039 +
19040 + case VEN_CORE_GET_FEATURE:
19041 + CFI_INFO("VEN_CORE_GET_FEATURE\n");
19042 + retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN,
19043 + pcd, ctrl);
19044 + if (retval >= 0) {
19045 + ep = &pcd->ep0;
19046 +
19047 + retval = min((uint16_t) retval, wLen);
19048 + /* Transfer this buffer to the host through the EP0-IN EP */
19049 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
19050 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
19051 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
19052 + ep->dwc_ep.xfer_len = retval;
19053 + ep->dwc_ep.xfer_count = 0;
19054 + ep->dwc_ep.sent_zlp = 0;
19055 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19056 +
19057 + pcd->ep0_pending = 1;
19058 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19059 + }
19060 + CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval);
19061 + dump_msg(cfi->buf_in.buf, retval);
19062 + break;
19063 +
19064 + case VEN_CORE_SET_FEATURE:
19065 + CFI_INFO("VEN_CORE_SET_FEATURE\n");
19066 + /* Set up an XFER to get the data stage of the control request,
19067 + * which is the new value of the feature to be modified.
19068 + */
19069 + ep = &pcd->ep0;
19070 + ep->dwc_ep.is_in = 0;
19071 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
19072 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
19073 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
19074 + ep->dwc_ep.xfer_len = wLen;
19075 + ep->dwc_ep.xfer_count = 0;
19076 + ep->dwc_ep.sent_zlp = 0;
19077 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19078 +
19079 + pcd->ep0_pending = 1;
19080 + /* Read the control write's data stage */
19081 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19082 + retval = 0;
19083 + break;
19084 +
19085 + case VEN_CORE_RESET_FEATURES:
19086 + CFI_INFO("VEN_CORE_RESET_FEATURES\n");
19087 + cfi->need_gadget_att = 1;
19088 + cfi->need_status_in_complete = 1;
19089 + retval = cfi_preproc_reset(pcd, ctrl);
19090 + CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval);
19091 + break;
19092 +
19093 + case VEN_CORE_ACTIVATE_FEATURES:
19094 + CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n");
19095 + break;
19096 +
19097 + case VEN_CORE_READ_REGISTER:
19098 + CFI_INFO("VEN_CORE_READ_REGISTER\n");
19099 + /* wValue optionally contains the HI WORD of the register offset and
19100 + * wIndex contains the LOW WORD of the register offset
19101 + */
19102 + if (wValue == 0) {
19103 + /* @TODO - MAS - fix the access to the base field */
19104 + regaddr = 0;
19105 + //regaddr = (uint32_t) pcd->otg_dev->os_dep.base;
19106 + //GET_CORE_IF(pcd)->co
19107 + regaddr |= wIndex;
19108 + } else {
19109 + regaddr = (wValue << 16) | wIndex;
19110 + }
19111 +
19112 + /* Read a 32-bit value of the memory at the regaddr */
19113 + regval = DWC_READ_REG32((uint32_t *) regaddr);
19114 +
19115 + ep = &pcd->ep0;
19116 + dwc_memcpy(cfi->buf_in.buf, &regval, sizeof(uint32_t));
19117 + ep->dwc_ep.is_in = 1;
19118 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
19119 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
19120 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
19121 + ep->dwc_ep.xfer_len = wLen;
19122 + ep->dwc_ep.xfer_count = 0;
19123 + ep->dwc_ep.sent_zlp = 0;
19124 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19125 +
19126 + pcd->ep0_pending = 1;
19127 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19128 + cfi->need_gadget_att = 0;
19129 + retval = 0;
19130 + break;
19131 +
19132 + case VEN_CORE_WRITE_REGISTER:
19133 + CFI_INFO("VEN_CORE_WRITE_REGISTER\n");
19134 + /* Set up an XFER to get the data stage of the control request,
19135 + * which is the new value of the register to be modified.
19136 + */
19137 + ep = &pcd->ep0;
19138 + ep->dwc_ep.is_in = 0;
19139 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
19140 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
19141 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
19142 + ep->dwc_ep.xfer_len = wLen;
19143 + ep->dwc_ep.xfer_count = 0;
19144 + ep->dwc_ep.sent_zlp = 0;
19145 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19146 +
19147 + pcd->ep0_pending = 1;
19148 + /* Read the control write's data stage */
19149 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19150 + retval = 0;
19151 + break;
19152 +
19153 + default:
19154 + retval = -DWC_E_NOT_SUPPORTED;
19155 + break;
19156 + }
19157 +
19158 + return retval;
19159 +}
19160 +
19161 +/**
19162 + * This function prepares the core features descriptors and copies its
19163 + * raw representation into the buffer <buf>.
19164 + *
19165 + * The buffer structure is as follows:
19166 + * all_features_header (8 bytes)
19167 + * features_#1 (8 bytes + feature name string length)
19168 + * features_#2 (8 bytes + feature name string length)
19169 + * .....
19170 + * features_#n - where n=the total count of feature descriptors
19171 + */
19172 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen)
19173 +{
19174 + cfi_feature_desc_header_t *prop_hdr = prop_descs;
19175 + cfi_feature_desc_header_t *prop;
19176 + cfi_all_features_header_t *all_props_hdr = &all_props_desc_header;
19177 + cfi_all_features_header_t *tmp;
19178 + uint8_t *tmpbuf = buf;
19179 + const uint8_t *pname = NULL;
19180 + int i, j, namelen = 0, totlen;
19181 +
19182 + /* Prepare and copy the core features into the buffer */
19183 + CFI_INFO("%s:\n", __func__);
19184 +
19185 + tmp = (cfi_all_features_header_t *) tmpbuf;
19186 + *tmp = *all_props_hdr;
19187 + tmpbuf += CFI_ALL_FEATURES_HDR_LEN;
19188 +
19189 + j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t);
19190 + for (i = 0; i < j; i++, prop_hdr++) {
19191 + pname = get_prop_name(prop_hdr->wFeatureID, &namelen);
19192 + prop = (cfi_feature_desc_header_t *) tmpbuf;
19193 + *prop = *prop_hdr;
19194 +
19195 + prop->bNameLen = namelen;
19196 + prop->wLength =
19197 + DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN +
19198 + namelen);
19199 +
19200 + tmpbuf += CFI_FEATURE_DESC_HDR_LEN;
19201 + dwc_memcpy(tmpbuf, pname, namelen);
19202 + tmpbuf += namelen;
19203 + }
19204 +
19205 + totlen = tmpbuf - buf;
19206 +
19207 + if (totlen > 0) {
19208 + tmp = (cfi_all_features_header_t *) buf;
19209 + tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen);
19210 + }
19211 +
19212 + return totlen;
19213 +}
19214 +
19215 +/**
19216 + * This function releases all the dynamic memory in the CFI object.
19217 + */
19218 +static void cfi_release(cfiobject_t * cfiobj)
19219 +{
19220 + cfi_ep_t *cfiep;
19221 + dwc_list_link_t *tmp;
19222 +
19223 + CFI_INFO("%s\n", __func__);
19224 +
19225 + if (cfiobj->buf_in.buf) {
19226 + DWC_DMA_FREE(CFI_IN_BUF_LEN, cfiobj->buf_in.buf,
19227 + cfiobj->buf_in.addr);
19228 + cfiobj->buf_in.buf = NULL;
19229 + }
19230 +
19231 + if (cfiobj->buf_out.buf) {
19232 + DWC_DMA_FREE(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf,
19233 + cfiobj->buf_out.addr);
19234 + cfiobj->buf_out.buf = NULL;
19235 + }
19236 +
19237 + /* Free the Buffer Setup values for each EP */
19238 + //list_for_each_entry(cfiep, &cfiobj->active_eps, lh) {
19239 + DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) {
19240 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19241 + cfi_free_ep_bs_dyn_data(cfiep);
19242 + }
19243 +}
19244 +
19245 +/**
19246 + * This function frees the dynamically allocated EP buffer setup data.
19247 + */
19248 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep)
19249 +{
19250 + if (cfiep->bm_sg) {
19251 + DWC_FREE(cfiep->bm_sg);
19252 + cfiep->bm_sg = NULL;
19253 + }
19254 +
19255 + if (cfiep->bm_align) {
19256 + DWC_FREE(cfiep->bm_align);
19257 + cfiep->bm_align = NULL;
19258 + }
19259 +
19260 + if (cfiep->bm_concat) {
19261 + if (NULL != cfiep->bm_concat->wTxBytes) {
19262 + DWC_FREE(cfiep->bm_concat->wTxBytes);
19263 + cfiep->bm_concat->wTxBytes = NULL;
19264 + }
19265 + DWC_FREE(cfiep->bm_concat);
19266 + cfiep->bm_concat = NULL;
19267 + }
19268 +}
19269 +
19270 +/**
19271 + * This function initializes the default values of the features
19272 + * for a specific endpoint and should be called only once when
19273 + * the EP is enabled first time.
19274 + */
19275 +static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep)
19276 +{
19277 + int retval = 0;
19278 +
19279 + cfiep->bm_sg = DWC_ALLOC(sizeof(ddma_sg_buffer_setup_t));
19280 + if (NULL == cfiep->bm_sg) {
19281 + CFI_INFO("Failed to allocate memory for SG feature value\n");
19282 + return -DWC_E_NO_MEMORY;
19283 + }
19284 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19285 +
19286 + /* For the Concatenation feature's default value we do not allocate
19287 + * memory for the wTxBytes field - it will be done in the set_feature_value
19288 + * request handler.
19289 + */
19290 + cfiep->bm_concat = DWC_ALLOC(sizeof(ddma_concat_buffer_setup_t));
19291 + if (NULL == cfiep->bm_concat) {
19292 + CFI_INFO
19293 + ("Failed to allocate memory for CONCATENATION feature value\n");
19294 + DWC_FREE(cfiep->bm_sg);
19295 + return -DWC_E_NO_MEMORY;
19296 + }
19297 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
19298 +
19299 + cfiep->bm_align = DWC_ALLOC(sizeof(ddma_align_buffer_setup_t));
19300 + if (NULL == cfiep->bm_align) {
19301 + CFI_INFO
19302 + ("Failed to allocate memory for Alignment feature value\n");
19303 + DWC_FREE(cfiep->bm_sg);
19304 + DWC_FREE(cfiep->bm_concat);
19305 + return -DWC_E_NO_MEMORY;
19306 + }
19307 + dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t));
19308 +
19309 + return retval;
19310 +}
19311 +
19312 +/**
19313 + * The callback function that notifies the CFI on the activation of
19314 + * an endpoint in the PCD. The following steps are done in this function:
19315 + *
19316 + * Create a dynamically allocated cfi_ep_t object (a CFI wrapper to the PCD's
19317 + * active endpoint)
19318 + * Create MAX_DMA_DESCS_PER_EP count DMA Descriptors for the EP
19319 + * Set the Buffer Mode to standard
19320 + * Initialize the default values for all EP modes (SG, Circular, Concat, Align)
19321 + * Add the cfi_ep_t object to the list of active endpoints in the CFI object
19322 + */
19323 +static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
19324 + struct dwc_otg_pcd_ep *ep)
19325 +{
19326 + cfi_ep_t *cfiep;
19327 + int retval = -DWC_E_NOT_SUPPORTED;
19328 +
19329 + CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__,
19330 + "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress);
19331 + /* MAS - Check whether this endpoint already is in the list */
19332 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
19333 +
19334 + if (NULL == cfiep) {
19335 + /* Allocate a cfi_ep_t object */
19336 + cfiep = DWC_ALLOC(sizeof(cfi_ep_t));
19337 + if (NULL == cfiep) {
19338 + CFI_INFO
19339 + ("Unable to allocate memory for <cfiep> in function %s\n",
19340 + __func__);
19341 + return -DWC_E_NO_MEMORY;
19342 + }
19343 + dwc_memset(cfiep, 0, sizeof(cfi_ep_t));
19344 +
19345 + /* Save the dwc_otg_pcd_ep pointer in the cfiep object */
19346 + cfiep->ep = ep;
19347 +
19348 + /* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */
19349 + ep->dwc_ep.descs =
19350 + DWC_DMA_ALLOC(MAX_DMA_DESCS_PER_EP *
19351 + sizeof(dwc_otg_dma_desc_t),
19352 + &ep->dwc_ep.descs_dma_addr);
19353 +
19354 + if (NULL == ep->dwc_ep.descs) {
19355 + DWC_FREE(cfiep);
19356 + return -DWC_E_NO_MEMORY;
19357 + }
19358 +
19359 + DWC_LIST_INIT(&cfiep->lh);
19360 +
19361 + /* Set the buffer mode to BM_STANDARD. It will be modified
19362 + * when building descriptors for a specific buffer mode */
19363 + ep->dwc_ep.buff_mode = BM_STANDARD;
19364 +
19365 + /* Create and initialize the default values for this EP's Buffer modes */
19366 + if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0)
19367 + return retval;
19368 +
19369 + /* Add the cfi_ep_t object to the CFI object's list of active endpoints */
19370 + DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh);
19371 + retval = 0;
19372 + } else { /* The sought EP already is in the list */
19373 + CFI_INFO("%s: The sought EP already is in the list\n",
19374 + __func__);
19375 + }
19376 +
19377 + return retval;
19378 +}
19379 +
19380 +/**
19381 + * This function is called when the data stage of a 3-stage Control Write request
19382 + * is complete.
19383 + *
19384 + */
19385 +static int cfi_ctrl_write_complete(struct cfiobject *cfi,
19386 + struct dwc_otg_pcd *pcd)
19387 +{
19388 + uint32_t addr, reg_value;
19389 + uint16_t wIndex, wValue;
19390 + uint8_t bRequest;
19391 + uint8_t *buf = cfi->buf_out.buf;
19392 + //struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved;
19393 + struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req;
19394 + int retval = -DWC_E_NOT_SUPPORTED;
19395 +
19396 + CFI_INFO("%s\n", __func__);
19397 +
19398 + bRequest = ctrl_req->bRequest;
19399 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
19400 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
19401 +
19402 + /*
19403 + * Save the pointer to the data stage in the ctrl_req's <data> field.
19404 + * The request should be already saved in the command stage by now.
19405 + */
19406 + ctrl_req->data = cfi->buf_out.buf;
19407 + cfi->need_status_in_complete = 0;
19408 + cfi->need_gadget_att = 0;
19409 +
19410 + switch (bRequest) {
19411 + case VEN_CORE_WRITE_REGISTER:
19412 + /* The buffer contains raw data of the new value for the register */
19413 + reg_value = *((uint32_t *) buf);
19414 + if (wValue == 0) {
19415 + addr = 0;
19416 + //addr = (uint32_t) pcd->otg_dev->os_dep.base;
19417 + addr += wIndex;
19418 + } else {
19419 + addr = (wValue << 16) | wIndex;
19420 + }
19421 +
19422 + //writel(reg_value, addr);
19423 +
19424 + retval = 0;
19425 + cfi->need_status_in_complete = 1;
19426 + break;
19427 +
19428 + case VEN_CORE_SET_FEATURE:
19429 + /* The buffer contains raw data of the new value of the feature */
19430 + retval = cfi_set_feature_value(pcd);
19431 + if (retval < 0)
19432 + return retval;
19433 +
19434 + cfi->need_status_in_complete = 1;
19435 + break;
19436 +
19437 + default:
19438 + break;
19439 + }
19440 +
19441 + return retval;
19442 +}
19443 +
19444 +/**
19445 + * This function builds the DMA descriptors for the SG buffer mode.
19446 + */
19447 +static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19448 + dwc_otg_pcd_request_t * req)
19449 +{
19450 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19451 + ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg;
19452 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19453 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
19454 + dma_addr_t buff_addr = req->dma;
19455 + int i;
19456 + uint32_t txsize, off;
19457 +
19458 + txsize = sgval->wSize;
19459 + off = sgval->bOffset;
19460 +
19461 +// CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n",
19462 +// __func__, cfiep->ep->ep.name, txsize, off);
19463 +
19464 + for (i = 0; i < sgval->bCount; i++) {
19465 + desc->status.b.bs = BS_HOST_BUSY;
19466 + desc->buf = buff_addr;
19467 + desc->status.b.l = 0;
19468 + desc->status.b.ioc = 0;
19469 + desc->status.b.sp = 0;
19470 + desc->status.b.bytes = txsize;
19471 + desc->status.b.bs = BS_HOST_READY;
19472 +
19473 + /* Set the next address of the buffer */
19474 + buff_addr += txsize + off;
19475 + desc_last = desc;
19476 + desc++;
19477 + }
19478 +
19479 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
19480 + desc_last->status.b.l = 1;
19481 + desc_last->status.b.ioc = 1;
19482 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
19483 + /* Save the last DMA descriptor pointer */
19484 + cfiep->dma_desc_last = desc_last;
19485 + cfiep->desc_count = sgval->bCount;
19486 +}
19487 +
19488 +/**
19489 + * This function builds the DMA descriptors for the Concatenation buffer mode.
19490 + */
19491 +static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19492 + dwc_otg_pcd_request_t * req)
19493 +{
19494 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19495 + ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat;
19496 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19497 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
19498 + dma_addr_t buff_addr = req->dma;
19499 + int i;
19500 + uint16_t *txsize;
19501 +
19502 + txsize = concatval->wTxBytes;
19503 +
19504 + for (i = 0; i < concatval->hdr.bDescCount; i++) {
19505 + desc->buf = buff_addr;
19506 + desc->status.b.bs = BS_HOST_BUSY;
19507 + desc->status.b.l = 0;
19508 + desc->status.b.ioc = 0;
19509 + desc->status.b.sp = 0;
19510 + desc->status.b.bytes = *txsize;
19511 + desc->status.b.bs = BS_HOST_READY;
19512 +
19513 + txsize++;
19514 + /* Set the next address of the buffer */
19515 + buff_addr += UGETW(ep->desc->wMaxPacketSize);
19516 + desc_last = desc;
19517 + desc++;
19518 + }
19519 +
19520 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
19521 + desc_last->status.b.l = 1;
19522 + desc_last->status.b.ioc = 1;
19523 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
19524 + cfiep->dma_desc_last = desc_last;
19525 + cfiep->desc_count = concatval->hdr.bDescCount;
19526 +}
19527 +
19528 +/**
19529 + * This function builds the DMA descriptors for the Circular buffer mode
19530 + */
19531 +static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19532 + dwc_otg_pcd_request_t * req)
19533 +{
19534 + /* @todo: MAS - add implementation when this feature needs to be tested */
19535 +}
19536 +
19537 +/**
19538 + * This function builds the DMA descriptors for the Alignment buffer mode
19539 + */
19540 +static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19541 + dwc_otg_pcd_request_t * req)
19542 +{
19543 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19544 + ddma_align_buffer_setup_t *alignval = cfiep->bm_align;
19545 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19546 + dma_addr_t buff_addr = req->dma;
19547 +
19548 + desc->status.b.bs = BS_HOST_BUSY;
19549 + desc->status.b.l = 1;
19550 + desc->status.b.ioc = 1;
19551 + desc->status.b.sp = ep->dwc_ep.sent_zlp;
19552 + desc->status.b.bytes = req->length;
19553 + /* Adjust the buffer alignment */
19554 + desc->buf = (buff_addr + alignval->bAlign);
19555 + desc->status.b.bs = BS_HOST_READY;
19556 + cfiep->dma_desc_last = desc;
19557 + cfiep->desc_count = 1;
19558 +}
19559 +
19560 +/**
19561 + * This function builds the DMA descriptors chain for different modes of the
19562 + * buffer setup of an endpoint.
19563 + */
19564 +static void cfi_build_descriptors(struct cfiobject *cfi,
19565 + struct dwc_otg_pcd *pcd,
19566 + struct dwc_otg_pcd_ep *ep,
19567 + dwc_otg_pcd_request_t * req)
19568 +{
19569 + cfi_ep_t *cfiep;
19570 +
19571 + /* Get the cfiep by the dwc_otg_pcd_ep */
19572 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
19573 + if (NULL == cfiep) {
19574 + CFI_INFO("%s: Unable to find a matching active endpoint\n",
19575 + __func__);
19576 + return;
19577 + }
19578 +
19579 + cfiep->xfer_len = req->length;
19580 +
19581 + /* Iterate through all the DMA descriptors */
19582 + switch (cfiep->ep->dwc_ep.buff_mode) {
19583 + case BM_SG:
19584 + cfi_build_sg_descs(cfi, cfiep, req);
19585 + break;
19586 +
19587 + case BM_CONCAT:
19588 + cfi_build_concat_descs(cfi, cfiep, req);
19589 + break;
19590 +
19591 + case BM_CIRCULAR:
19592 + cfi_build_circ_descs(cfi, cfiep, req);
19593 + break;
19594 +
19595 + case BM_ALIGN:
19596 + cfi_build_align_descs(cfi, cfiep, req);
19597 + break;
19598 +
19599 + default:
19600 + break;
19601 + }
19602 +}
19603 +
19604 +/**
19605 + * Allocate DMA buffer for different Buffer modes.
19606 + */
19607 +static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
19608 + struct dwc_otg_pcd_ep *ep, dma_addr_t * dma,
19609 + unsigned size, gfp_t flags)
19610 +{
19611 + return DWC_DMA_ALLOC(size, dma);
19612 +}
19613 +
19614 +/**
19615 + * This function initializes the CFI object.
19616 + */
19617 +int init_cfi(cfiobject_t * cfiobj)
19618 +{
19619 + CFI_INFO("%s\n", __func__);
19620 +
19621 + /* Allocate a buffer for IN XFERs */
19622 + cfiobj->buf_in.buf =
19623 + DWC_DMA_ALLOC(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr);
19624 + if (NULL == cfiobj->buf_in.buf) {
19625 + CFI_INFO("Unable to allocate buffer for INs\n");
19626 + return -DWC_E_NO_MEMORY;
19627 + }
19628 +
19629 + /* Allocate a buffer for OUT XFERs */
19630 + cfiobj->buf_out.buf =
19631 + DWC_DMA_ALLOC(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr);
19632 + if (NULL == cfiobj->buf_out.buf) {
19633 + CFI_INFO("Unable to allocate buffer for OUT\n");
19634 + return -DWC_E_NO_MEMORY;
19635 + }
19636 +
19637 + /* Initialize the callback function pointers */
19638 + cfiobj->ops.release = cfi_release;
19639 + cfiobj->ops.ep_enable = cfi_ep_enable;
19640 + cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete;
19641 + cfiobj->ops.build_descriptors = cfi_build_descriptors;
19642 + cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf;
19643 +
19644 + /* Initialize the list of active endpoints in the CFI object */
19645 + DWC_LIST_INIT(&cfiobj->active_eps);
19646 +
19647 + return 0;
19648 +}
19649 +
19650 +/**
19651 + * This function reads the required feature's current value into the buffer
19652 + *
19653 + * @retval: Returns negative as error, or the data length of the feature
19654 + */
19655 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
19656 + struct dwc_otg_pcd *pcd,
19657 + struct cfi_usb_ctrlrequest *ctrl_req)
19658 +{
19659 + int retval = -DWC_E_NOT_SUPPORTED;
19660 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
19661 + uint16_t dfifo, rxfifo, txfifo;
19662 +
19663 + switch (ctrl_req->wIndex) {
19664 + /* Whether the DDMA is enabled or not */
19665 + case FT_ID_DMA_MODE:
19666 + *buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0;
19667 + retval = 1;
19668 + break;
19669 +
19670 + case FT_ID_DMA_BUFFER_SETUP:
19671 + retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req);
19672 + break;
19673 +
19674 + case FT_ID_DMA_BUFF_ALIGN:
19675 + retval = cfi_ep_get_align_val(buf, pcd, ctrl_req);
19676 + break;
19677 +
19678 + case FT_ID_DMA_CONCAT_SETUP:
19679 + retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req);
19680 + break;
19681 +
19682 + case FT_ID_DMA_CIRCULAR:
19683 + CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n");
19684 + break;
19685 +
19686 + case FT_ID_THRESHOLD_SETUP:
19687 + CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n");
19688 + break;
19689 +
19690 + case FT_ID_DFIFO_DEPTH:
19691 + dfifo = get_dfifo_size(coreif);
19692 + *((uint16_t *) buf) = dfifo;
19693 + retval = sizeof(uint16_t);
19694 + break;
19695 +
19696 + case FT_ID_TX_FIFO_DEPTH:
19697 + retval = get_txfifo_size(pcd, ctrl_req->wValue);
19698 + if (retval >= 0) {
19699 + txfifo = retval;
19700 + *((uint16_t *) buf) = txfifo;
19701 + retval = sizeof(uint16_t);
19702 + }
19703 + break;
19704 +
19705 + case FT_ID_RX_FIFO_DEPTH:
19706 + retval = get_rxfifo_size(coreif, ctrl_req->wValue);
19707 + if (retval >= 0) {
19708 + rxfifo = retval;
19709 + *((uint16_t *) buf) = rxfifo;
19710 + retval = sizeof(uint16_t);
19711 + }
19712 + break;
19713 + }
19714 +
19715 + return retval;
19716 +}
19717 +
19718 +/**
19719 + * This function resets the SG for the specified EP to its default value
19720 + */
19721 +static int cfi_reset_sg_val(cfi_ep_t * cfiep)
19722 +{
19723 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19724 + return 0;
19725 +}
19726 +
19727 +/**
19728 + * This function resets the Alignment for the specified EP to its default value
19729 + */
19730 +static int cfi_reset_align_val(cfi_ep_t * cfiep)
19731 +{
19732 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19733 + return 0;
19734 +}
19735 +
19736 +/**
19737 + * This function resets the Concatenation for the specified EP to its default value
19738 + * This function will also set the value of the wTxBytes field to NULL after
19739 + * freeing the memory previously allocated for this field.
19740 + */
19741 +static int cfi_reset_concat_val(cfi_ep_t * cfiep)
19742 +{
19743 + /* First we need to free the wTxBytes field */
19744 + if (cfiep->bm_concat->wTxBytes) {
19745 + DWC_FREE(cfiep->bm_concat->wTxBytes);
19746 + cfiep->bm_concat->wTxBytes = NULL;
19747 + }
19748 +
19749 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
19750 + return 0;
19751 +}
19752 +
19753 +/**
19754 + * This function resets all the buffer setups of the specified endpoint
19755 + */
19756 +static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep)
19757 +{
19758 + cfi_reset_sg_val(cfiep);
19759 + cfi_reset_align_val(cfiep);
19760 + cfi_reset_concat_val(cfiep);
19761 + return 0;
19762 +}
19763 +
19764 +static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr,
19765 + uint8_t rx_rst, uint8_t tx_rst)
19766 +{
19767 + int retval = -DWC_E_INVALID;
19768 + uint16_t tx_siz[15];
19769 + uint16_t rx_siz = 0;
19770 + dwc_otg_pcd_ep_t *ep = NULL;
19771 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
19772 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
19773 +
19774 + if (rx_rst) {
19775 + rx_siz = params->dev_rx_fifo_size;
19776 + params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz;
19777 + }
19778 +
19779 + if (tx_rst) {
19780 + if (ep_addr == 0) {
19781 + int i;
19782 +
19783 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
19784 + tx_siz[i] =
19785 + core_if->core_params->dev_tx_fifo_size[i];
19786 + core_if->core_params->dev_tx_fifo_size[i] =
19787 + core_if->init_txfsiz[i];
19788 + }
19789 + } else {
19790 +
19791 + ep = get_ep_by_addr(pcd, ep_addr);
19792 +
19793 + if (NULL == ep) {
19794 + CFI_INFO
19795 + ("%s: Unable to get the endpoint addr=0x%02x\n",
19796 + __func__, ep_addr);
19797 + return -DWC_E_INVALID;
19798 + }
19799 +
19800 + tx_siz[0] =
19801 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num -
19802 + 1];
19803 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] =
19804 + GET_CORE_IF(pcd)->init_txfsiz[ep->
19805 + dwc_ep.tx_fifo_num -
19806 + 1];
19807 + }
19808 + }
19809 +
19810 + if (resize_fifos(GET_CORE_IF(pcd))) {
19811 + retval = 0;
19812 + } else {
19813 + CFI_INFO
19814 + ("%s: Error resetting the feature Reset All(FIFO size)\n",
19815 + __func__);
19816 + if (rx_rst) {
19817 + params->dev_rx_fifo_size = rx_siz;
19818 + }
19819 +
19820 + if (tx_rst) {
19821 + if (ep_addr == 0) {
19822 + int i;
19823 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps;
19824 + i++) {
19825 + core_if->
19826 + core_params->dev_tx_fifo_size[i] =
19827 + tx_siz[i];
19828 + }
19829 + } else {
19830 + params->dev_tx_fifo_size[ep->
19831 + dwc_ep.tx_fifo_num -
19832 + 1] = tx_siz[0];
19833 + }
19834 + }
19835 + retval = -DWC_E_INVALID;
19836 + }
19837 + return retval;
19838 +}
19839 +
19840 +static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr)
19841 +{
19842 + int retval = 0;
19843 + cfi_ep_t *cfiep;
19844 + cfiobject_t *cfi = pcd->cfi;
19845 + dwc_list_link_t *tmp;
19846 +
19847 + retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1);
19848 + if (retval < 0) {
19849 + return retval;
19850 + }
19851 +
19852 + /* If the EP address is known then reset the features for only that EP */
19853 + if (addr) {
19854 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19855 + if (NULL == cfiep) {
19856 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19857 + __func__, addr);
19858 + return -DWC_E_INVALID;
19859 + }
19860 + retval = cfi_ep_reset_all_setup_vals(cfiep);
19861 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
19862 + }
19863 + /* Otherwise (wValue == 0), reset all features of all EP's */
19864 + else {
19865 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19866 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19867 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19868 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19869 + retval = cfi_ep_reset_all_setup_vals(cfiep);
19870 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
19871 + if (retval < 0) {
19872 + CFI_INFO
19873 + ("%s: Error resetting the feature Reset All\n",
19874 + __func__);
19875 + return retval;
19876 + }
19877 + }
19878 + }
19879 + return retval;
19880 +}
19881 +
19882 +static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd,
19883 + uint8_t addr)
19884 +{
19885 + int retval = 0;
19886 + cfi_ep_t *cfiep;
19887 + cfiobject_t *cfi = pcd->cfi;
19888 + dwc_list_link_t *tmp;
19889 +
19890 + /* If the EP address is known then reset the features for only that EP */
19891 + if (addr) {
19892 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19893 + if (NULL == cfiep) {
19894 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19895 + __func__, addr);
19896 + return -DWC_E_INVALID;
19897 + }
19898 + retval = cfi_reset_sg_val(cfiep);
19899 + }
19900 + /* Otherwise (wValue == 0), reset all features of all EP's */
19901 + else {
19902 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19903 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19904 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19905 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19906 + retval = cfi_reset_sg_val(cfiep);
19907 + if (retval < 0) {
19908 + CFI_INFO
19909 + ("%s: Error resetting the feature Buffer Setup\n",
19910 + __func__);
19911 + return retval;
19912 + }
19913 + }
19914 + }
19915 + return retval;
19916 +}
19917 +
19918 +static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr)
19919 +{
19920 + int retval = 0;
19921 + cfi_ep_t *cfiep;
19922 + cfiobject_t *cfi = pcd->cfi;
19923 + dwc_list_link_t *tmp;
19924 +
19925 + /* If the EP address is known then reset the features for only that EP */
19926 + if (addr) {
19927 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19928 + if (NULL == cfiep) {
19929 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19930 + __func__, addr);
19931 + return -DWC_E_INVALID;
19932 + }
19933 + retval = cfi_reset_concat_val(cfiep);
19934 + }
19935 + /* Otherwise (wValue == 0), reset all features of all EP's */
19936 + else {
19937 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19938 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19939 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19940 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19941 + retval = cfi_reset_concat_val(cfiep);
19942 + if (retval < 0) {
19943 + CFI_INFO
19944 + ("%s: Error resetting the feature Concatenation Value\n",
19945 + __func__);
19946 + return retval;
19947 + }
19948 + }
19949 + }
19950 + return retval;
19951 +}
19952 +
19953 +static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr)
19954 +{
19955 + int retval = 0;
19956 + cfi_ep_t *cfiep;
19957 + cfiobject_t *cfi = pcd->cfi;
19958 + dwc_list_link_t *tmp;
19959 +
19960 + /* If the EP address is known then reset the features for only that EP */
19961 + if (addr) {
19962 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19963 + if (NULL == cfiep) {
19964 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19965 + __func__, addr);
19966 + return -DWC_E_INVALID;
19967 + }
19968 + retval = cfi_reset_align_val(cfiep);
19969 + }
19970 + /* Otherwise (wValue == 0), reset all features of all EP's */
19971 + else {
19972 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19973 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19974 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19975 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19976 + retval = cfi_reset_align_val(cfiep);
19977 + if (retval < 0) {
19978 + CFI_INFO
19979 + ("%s: Error resetting the feature Aliignment Value\n",
19980 + __func__);
19981 + return retval;
19982 + }
19983 + }
19984 + }
19985 + return retval;
19986 +
19987 +}
19988 +
19989 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
19990 + struct cfi_usb_ctrlrequest *req)
19991 +{
19992 + int retval = 0;
19993 +
19994 + switch (req->wIndex) {
19995 + case 0:
19996 + /* Reset all features */
19997 + retval = cfi_handle_reset_all(pcd, req->wValue & 0xff);
19998 + break;
19999 +
20000 + case FT_ID_DMA_BUFFER_SETUP:
20001 + /* Reset the SG buffer setup */
20002 + retval =
20003 + cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff);
20004 + break;
20005 +
20006 + case FT_ID_DMA_CONCAT_SETUP:
20007 + /* Reset the Concatenation buffer setup */
20008 + retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff);
20009 + break;
20010 +
20011 + case FT_ID_DMA_BUFF_ALIGN:
20012 + /* Reset the Alignment buffer setup */
20013 + retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff);
20014 + break;
20015 +
20016 + case FT_ID_TX_FIFO_DEPTH:
20017 + retval =
20018 + cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1);
20019 + pcd->cfi->need_gadget_att = 0;
20020 + break;
20021 +
20022 + case FT_ID_RX_FIFO_DEPTH:
20023 + retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0);
20024 + pcd->cfi->need_gadget_att = 0;
20025 + break;
20026 + default:
20027 + break;
20028 + }
20029 + return retval;
20030 +}
20031 +
20032 +/**
20033 + * This function sets a new value for the SG buffer setup.
20034 + */
20035 +static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20036 +{
20037 + uint8_t inaddr, outaddr;
20038 + cfi_ep_t *epin, *epout;
20039 + ddma_sg_buffer_setup_t *psgval;
20040 + uint32_t desccount, size;
20041 +
20042 + CFI_INFO("%s\n", __func__);
20043 +
20044 + psgval = (ddma_sg_buffer_setup_t *) buf;
20045 + desccount = (uint32_t) psgval->bCount;
20046 + size = (uint32_t) psgval->wSize;
20047 +
20048 + /* Check the DMA descriptor count */
20049 + if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) {
20050 + CFI_INFO
20051 + ("%s: The count of DMA Descriptors should be between 1 and %d\n",
20052 + __func__, MAX_DMA_DESCS_PER_EP);
20053 + return -DWC_E_INVALID;
20054 + }
20055 +
20056 + /* Check the DMA descriptor count */
20057 +
20058 + if (size == 0) {
20059 +
20060 + CFI_INFO("%s: The transfer size should be at least 1 byte\n",
20061 + __func__);
20062 +
20063 + return -DWC_E_INVALID;
20064 +
20065 + }
20066 +
20067 + inaddr = psgval->bInEndpointAddress;
20068 + outaddr = psgval->bOutEndpointAddress;
20069 +
20070 + epin = get_cfi_ep_by_addr(pcd->cfi, inaddr);
20071 + epout = get_cfi_ep_by_addr(pcd->cfi, outaddr);
20072 +
20073 + if (NULL == epin || NULL == epout) {
20074 + CFI_INFO
20075 + ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n",
20076 + __func__, inaddr, outaddr);
20077 + return -DWC_E_INVALID;
20078 + }
20079 +
20080 + epin->ep->dwc_ep.buff_mode = BM_SG;
20081 + dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
20082 +
20083 + epout->ep->dwc_ep.buff_mode = BM_SG;
20084 + dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
20085 +
20086 + return 0;
20087 +}
20088 +
20089 +/**
20090 + * This function sets a new value for the buffer Alignment setup.
20091 + */
20092 +static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20093 +{
20094 + cfi_ep_t *ep;
20095 + uint8_t addr;
20096 + ddma_align_buffer_setup_t *palignval;
20097 +
20098 + palignval = (ddma_align_buffer_setup_t *) buf;
20099 + addr = palignval->bEndpointAddress;
20100 +
20101 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20102 +
20103 + if (NULL == ep) {
20104 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20105 + __func__, addr);
20106 + return -DWC_E_INVALID;
20107 + }
20108 +
20109 + ep->ep->dwc_ep.buff_mode = BM_ALIGN;
20110 + dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t));
20111 +
20112 + return 0;
20113 +}
20114 +
20115 +/**
20116 + * This function sets a new value for the Concatenation buffer setup.
20117 + */
20118 +static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20119 +{
20120 + uint8_t addr;
20121 + cfi_ep_t *ep;
20122 + struct _ddma_concat_buffer_setup_hdr *pConcatValHdr;
20123 + uint16_t *pVals;
20124 + uint32_t desccount;
20125 + int i;
20126 + uint16_t mps;
20127 +
20128 + pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf;
20129 + desccount = (uint32_t) pConcatValHdr->bDescCount;
20130 + pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN);
20131 +
20132 + /* Check the DMA descriptor count */
20133 + if (desccount > MAX_DMA_DESCS_PER_EP) {
20134 + CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n",
20135 + __func__, MAX_DMA_DESCS_PER_EP);
20136 + return -DWC_E_INVALID;
20137 + }
20138 +
20139 + addr = pConcatValHdr->bEndpointAddress;
20140 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20141 + if (NULL == ep) {
20142 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20143 + __func__, addr);
20144 + return -DWC_E_INVALID;
20145 + }
20146 +
20147 + mps = UGETW(ep->ep->desc->wMaxPacketSize);
20148 +
20149 +#if 0
20150 + for (i = 0; i < desccount; i++) {
20151 + CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]);
20152 + }
20153 + CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps);
20154 +#endif
20155 +
20156 + /* Check the wTxSizes to be less than or equal to the mps */
20157 + for (i = 0; i < desccount; i++) {
20158 + if (pVals[i] > mps) {
20159 + CFI_INFO
20160 + ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n",
20161 + __func__, i, pVals[i]);
20162 + return -DWC_E_INVALID;
20163 + }
20164 + }
20165 +
20166 + ep->ep->dwc_ep.buff_mode = BM_CONCAT;
20167 + dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN);
20168 +
20169 + /* Free the previously allocated storage for the wTxBytes */
20170 + if (ep->bm_concat->wTxBytes) {
20171 + DWC_FREE(ep->bm_concat->wTxBytes);
20172 + }
20173 +
20174 + /* Allocate a new storage for the wTxBytes field */
20175 + ep->bm_concat->wTxBytes =
20176 + DWC_ALLOC(sizeof(uint16_t) * pConcatValHdr->bDescCount);
20177 + if (NULL == ep->bm_concat->wTxBytes) {
20178 + CFI_INFO("%s: Unable to allocate memory\n", __func__);
20179 + return -DWC_E_NO_MEMORY;
20180 + }
20181 +
20182 + /* Copy the new values into the wTxBytes filed */
20183 + dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN,
20184 + sizeof(uint16_t) * pConcatValHdr->bDescCount);
20185 +
20186 + return 0;
20187 +}
20188 +
20189 +/**
20190 + * This function calculates the total of all FIFO sizes
20191 + *
20192 + * @param core_if Programming view of DWC_otg controller
20193 + *
20194 + * @return The total of data FIFO sizes.
20195 + *
20196 + */
20197 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if)
20198 +{
20199 + dwc_otg_core_params_t *params = core_if->core_params;
20200 + uint16_t dfifo_total = 0;
20201 + int i;
20202 +
20203 + /* The shared RxFIFO size */
20204 + dfifo_total =
20205 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
20206 +
20207 + /* Add up each TxFIFO size to the total */
20208 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20209 + dfifo_total += params->dev_tx_fifo_size[i];
20210 + }
20211 +
20212 + return dfifo_total;
20213 +}
20214 +
20215 +/**
20216 + * This function returns Rx FIFO size
20217 + *
20218 + * @param core_if Programming view of DWC_otg controller
20219 + *
20220 + * @return The total of data FIFO sizes.
20221 + *
20222 + */
20223 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue)
20224 +{
20225 + switch (wValue >> 8) {
20226 + case 0:
20227 + return (core_if->pwron_rxfsiz <
20228 + 32768) ? core_if->pwron_rxfsiz : 32768;
20229 + break;
20230 + case 1:
20231 + return core_if->core_params->dev_rx_fifo_size;
20232 + break;
20233 + default:
20234 + return -DWC_E_INVALID;
20235 + break;
20236 + }
20237 +}
20238 +
20239 +/**
20240 + * This function returns Tx FIFO size for IN EP
20241 + *
20242 + * @param core_if Programming view of DWC_otg controller
20243 + *
20244 + * @return The total of data FIFO sizes.
20245 + *
20246 + */
20247 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue)
20248 +{
20249 + dwc_otg_pcd_ep_t *ep;
20250 +
20251 + ep = get_ep_by_addr(pcd, wValue & 0xff);
20252 +
20253 + if (NULL == ep) {
20254 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20255 + __func__, wValue & 0xff);
20256 + return -DWC_E_INVALID;
20257 + }
20258 +
20259 + if (!ep->dwc_ep.is_in) {
20260 + CFI_INFO
20261 + ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n",
20262 + __func__, wValue & 0xff);
20263 + return -DWC_E_INVALID;
20264 + }
20265 +
20266 + switch (wValue >> 8) {
20267 + case 0:
20268 + return (GET_CORE_IF(pcd)->pwron_txfsiz
20269 + [ep->dwc_ep.tx_fifo_num - 1] <
20270 + 768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->
20271 + dwc_ep.tx_fifo_num
20272 + - 1] : 32768;
20273 + break;
20274 + case 1:
20275 + return GET_CORE_IF(pcd)->core_params->
20276 + dev_tx_fifo_size[ep->dwc_ep.num - 1];
20277 + break;
20278 + default:
20279 + return -DWC_E_INVALID;
20280 + break;
20281 + }
20282 +}
20283 +
20284 +/**
20285 + * This function checks if the submitted combination of
20286 + * device mode FIFO sizes is possible or not.
20287 + *
20288 + * @param core_if Programming view of DWC_otg controller
20289 + *
20290 + * @return 1 if possible, 0 otherwise.
20291 + *
20292 + */
20293 +static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if)
20294 +{
20295 + uint16_t dfifo_actual = 0;
20296 + dwc_otg_core_params_t *params = core_if->core_params;
20297 + uint16_t start_addr = 0;
20298 + int i;
20299 +
20300 + dfifo_actual =
20301 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
20302 +
20303 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20304 + dfifo_actual += params->dev_tx_fifo_size[i];
20305 + }
20306 +
20307 + if (dfifo_actual > core_if->total_fifo_size) {
20308 + return 0;
20309 + }
20310 +
20311 + if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16)
20312 + return 0;
20313 +
20314 + if (params->dev_nperio_tx_fifo_size > 32768
20315 + || params->dev_nperio_tx_fifo_size < 16)
20316 + return 0;
20317 +
20318 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20319 +
20320 + if (params->dev_tx_fifo_size[i] > 768
20321 + || params->dev_tx_fifo_size[i] < 4)
20322 + return 0;
20323 + }
20324 +
20325 + if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz)
20326 + return 0;
20327 + start_addr = params->dev_rx_fifo_size;
20328 +
20329 + if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz)
20330 + return 0;
20331 + start_addr += params->dev_nperio_tx_fifo_size;
20332 +
20333 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20334 +
20335 + if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i])
20336 + return 0;
20337 + start_addr += params->dev_tx_fifo_size[i];
20338 + }
20339 +
20340 + return 1;
20341 +}
20342 +
20343 +/**
20344 + * This function resizes Device mode FIFOs
20345 + *
20346 + * @param core_if Programming view of DWC_otg controller
20347 + *
20348 + * @return 1 if successful, 0 otherwise
20349 + *
20350 + */
20351 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if)
20352 +{
20353 + int i = 0;
20354 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
20355 + dwc_otg_core_params_t *params = core_if->core_params;
20356 + uint32_t rx_fifo_size;
20357 + fifosize_data_t nptxfifosize;
20358 + fifosize_data_t txfifosize[15];
20359 +
20360 + uint32_t rx_fsz_bak;
20361 + uint32_t nptxfsz_bak;
20362 + uint32_t txfsz_bak[15];
20363 +
20364 + uint16_t start_address;
20365 + uint8_t retval = 1;
20366 +
20367 + if (!check_fifo_sizes(core_if)) {
20368 + return 0;
20369 + }
20370 +
20371 + /* Configure data FIFO sizes */
20372 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
20373 + rx_fsz_bak = DWC_READ_REG32(&global_regs->grxfsiz);
20374 + rx_fifo_size = params->dev_rx_fifo_size;
20375 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
20376 +
20377 + /*
20378 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
20379 + * Indexes of the FIFO size module parameters in the
20380 + * dev_tx_fifo_size array and the FIFO size registers in
20381 + * the dtxfsiz array run from 0 to 14.
20382 + */
20383 +
20384 + /* Non-periodic Tx FIFO */
20385 + nptxfsz_bak = DWC_READ_REG32(&global_regs->gnptxfsiz);
20386 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
20387 + start_address = params->dev_rx_fifo_size;
20388 + nptxfifosize.b.startaddr = start_address;
20389 +
20390 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
20391 +
20392 + start_address += nptxfifosize.b.depth;
20393 +
20394 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20395 + txfsz_bak[i] = DWC_READ_REG32(&global_regs->dtxfsiz[i]);
20396 +
20397 + txfifosize[i].b.depth = params->dev_tx_fifo_size[i];
20398 + txfifosize[i].b.startaddr = start_address;
20399 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
20400 + txfifosize[i].d32);
20401 +
20402 + start_address += txfifosize[i].b.depth;
20403 + }
20404 +
20405 + /** Check if register values are set correctly */
20406 + if (rx_fifo_size != DWC_READ_REG32(&global_regs->grxfsiz)) {
20407 + retval = 0;
20408 + }
20409 +
20410 + if (nptxfifosize.d32 != DWC_READ_REG32(&global_regs->gnptxfsiz)) {
20411 + retval = 0;
20412 + }
20413 +
20414 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20415 + if (txfifosize[i].d32 !=
20416 + DWC_READ_REG32(&global_regs->dtxfsiz[i])) {
20417 + retval = 0;
20418 + }
20419 + }
20420 +
20421 + /** If register values are not set correctly, reset old values */
20422 + if (retval == 0) {
20423 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fsz_bak);
20424 +
20425 + /* Non-periodic Tx FIFO */
20426 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfsz_bak);
20427 +
20428 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20429 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
20430 + txfsz_bak[i]);
20431 + }
20432 + }
20433 + } else {
20434 + return 0;
20435 + }
20436 +
20437 + /* Flush the FIFOs */
20438 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
20439 + dwc_otg_flush_rx_fifo(core_if);
20440 +
20441 + return retval;
20442 +}
20443 +
20444 +/**
20445 + * This function sets a new value for the buffer Alignment setup.
20446 + */
20447 +static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
20448 +{
20449 + int retval;
20450 + uint32_t fsiz;
20451 + uint16_t size;
20452 + uint16_t ep_addr;
20453 + dwc_otg_pcd_ep_t *ep;
20454 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
20455 + tx_fifo_size_setup_t *ptxfifoval;
20456 +
20457 + ptxfifoval = (tx_fifo_size_setup_t *) buf;
20458 + ep_addr = ptxfifoval->bEndpointAddress;
20459 + size = ptxfifoval->wDepth;
20460 +
20461 + ep = get_ep_by_addr(pcd, ep_addr);
20462 +
20463 + CFI_INFO
20464 + ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n",
20465 + __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num);
20466 +
20467 + if (NULL == ep) {
20468 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20469 + __func__, ep_addr);
20470 + return -DWC_E_INVALID;
20471 + }
20472 +
20473 + fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1];
20474 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size;
20475 +
20476 + if (resize_fifos(GET_CORE_IF(pcd))) {
20477 + retval = 0;
20478 + } else {
20479 + CFI_INFO
20480 + ("%s: Error setting the feature Tx FIFO Size for EP%d\n",
20481 + __func__, ep_addr);
20482 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz;
20483 + retval = -DWC_E_INVALID;
20484 + }
20485 +
20486 + return retval;
20487 +}
20488 +
20489 +/**
20490 + * This function sets a new value for the buffer Alignment setup.
20491 + */
20492 +static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
20493 +{
20494 + int retval;
20495 + uint32_t fsiz;
20496 + uint16_t size;
20497 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
20498 + rx_fifo_size_setup_t *prxfifoval;
20499 +
20500 + prxfifoval = (rx_fifo_size_setup_t *) buf;
20501 + size = prxfifoval->wDepth;
20502 +
20503 + fsiz = params->dev_rx_fifo_size;
20504 + params->dev_rx_fifo_size = size;
20505 +
20506 + if (resize_fifos(GET_CORE_IF(pcd))) {
20507 + retval = 0;
20508 + } else {
20509 + CFI_INFO("%s: Error setting the feature Rx FIFO Size\n",
20510 + __func__);
20511 + params->dev_rx_fifo_size = fsiz;
20512 + retval = -DWC_E_INVALID;
20513 + }
20514 +
20515 + return retval;
20516 +}
20517 +
20518 +/**
20519 + * This function reads the SG of an EP's buffer setup into the buffer buf
20520 + */
20521 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20522 + struct cfi_usb_ctrlrequest *req)
20523 +{
20524 + int retval = -DWC_E_INVALID;
20525 + uint8_t addr;
20526 + cfi_ep_t *ep;
20527 +
20528 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20529 + addr = req->wValue & 0xFF;
20530 + if (addr == 0) /* The address should be non-zero */
20531 + return retval;
20532 +
20533 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20534 + if (NULL == ep) {
20535 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20536 + __func__, addr);
20537 + return retval;
20538 + }
20539 +
20540 + dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN);
20541 + retval = BS_SG_VAL_DESC_LEN;
20542 + return retval;
20543 +}
20544 +
20545 +/**
20546 + * This function reads the Concatenation value of an EP's buffer mode into
20547 + * the buffer buf
20548 + */
20549 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20550 + struct cfi_usb_ctrlrequest *req)
20551 +{
20552 + int retval = -DWC_E_INVALID;
20553 + uint8_t addr;
20554 + cfi_ep_t *ep;
20555 + uint8_t desc_count;
20556 +
20557 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20558 + addr = req->wValue & 0xFF;
20559 + if (addr == 0) /* The address should be non-zero */
20560 + return retval;
20561 +
20562 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20563 + if (NULL == ep) {
20564 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20565 + __func__, addr);
20566 + return retval;
20567 + }
20568 +
20569 + /* Copy the header to the buffer */
20570 + dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN);
20571 + /* Advance the buffer pointer by the header size */
20572 + buf += BS_CONCAT_VAL_HDR_LEN;
20573 +
20574 + desc_count = ep->bm_concat->hdr.bDescCount;
20575 + /* Copy alll the wTxBytes to the buffer */
20576 + dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count);
20577 +
20578 + retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count;
20579 + return retval;
20580 +}
20581 +
20582 +/**
20583 + * This function reads the buffer Alignment value of an EP's buffer mode into
20584 + * the buffer buf
20585 + *
20586 + * @return The total number of bytes copied to the buffer or negative error code.
20587 + */
20588 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20589 + struct cfi_usb_ctrlrequest *req)
20590 +{
20591 + int retval = -DWC_E_INVALID;
20592 + uint8_t addr;
20593 + cfi_ep_t *ep;
20594 +
20595 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20596 + addr = req->wValue & 0xFF;
20597 + if (addr == 0) /* The address should be non-zero */
20598 + return retval;
20599 +
20600 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20601 + if (NULL == ep) {
20602 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20603 + __func__, addr);
20604 + return retval;
20605 + }
20606 +
20607 + dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN);
20608 + retval = BS_ALIGN_VAL_HDR_LEN;
20609 +
20610 + return retval;
20611 +}
20612 +
20613 +/**
20614 + * This function sets a new value for the specified feature
20615 + *
20616 + * @param pcd A pointer to the PCD object
20617 + *
20618 + * @return 0 if successful, negative error code otherwise to stall the DCE.
20619 + */
20620 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd)
20621 +{
20622 + int retval = -DWC_E_NOT_SUPPORTED;
20623 + uint16_t wIndex, wValue;
20624 + uint8_t bRequest;
20625 + struct dwc_otg_core_if *coreif;
20626 + cfiobject_t *cfi = pcd->cfi;
20627 + struct cfi_usb_ctrlrequest *ctrl_req;
20628 + uint8_t *buf;
20629 + ctrl_req = &cfi->ctrl_req;
20630 +
20631 + buf = pcd->cfi->ctrl_req.data;
20632 +
20633 + coreif = GET_CORE_IF(pcd);
20634 + bRequest = ctrl_req->bRequest;
20635 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
20636 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
20637 +
20638 + /* See which feature is to be modified */
20639 + switch (wIndex) {
20640 + case FT_ID_DMA_BUFFER_SETUP:
20641 + /* Modify the feature */
20642 + if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0)
20643 + return retval;
20644 +
20645 + /* And send this request to the gadget */
20646 + cfi->need_gadget_att = 1;
20647 + break;
20648 +
20649 + case FT_ID_DMA_BUFF_ALIGN:
20650 + if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0)
20651 + return retval;
20652 + cfi->need_gadget_att = 1;
20653 + break;
20654 +
20655 + case FT_ID_DMA_CONCAT_SETUP:
20656 + /* Modify the feature */
20657 + if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0)
20658 + return retval;
20659 + cfi->need_gadget_att = 1;
20660 + break;
20661 +
20662 + case FT_ID_DMA_CIRCULAR:
20663 + CFI_INFO("FT_ID_DMA_CIRCULAR\n");
20664 + break;
20665 +
20666 + case FT_ID_THRESHOLD_SETUP:
20667 + CFI_INFO("FT_ID_THRESHOLD_SETUP\n");
20668 + break;
20669 +
20670 + case FT_ID_DFIFO_DEPTH:
20671 + CFI_INFO("FT_ID_DFIFO_DEPTH\n");
20672 + break;
20673 +
20674 + case FT_ID_TX_FIFO_DEPTH:
20675 + CFI_INFO("FT_ID_TX_FIFO_DEPTH\n");
20676 + if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0)
20677 + return retval;
20678 + cfi->need_gadget_att = 0;
20679 + break;
20680 +
20681 + case FT_ID_RX_FIFO_DEPTH:
20682 + CFI_INFO("FT_ID_RX_FIFO_DEPTH\n");
20683 + if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0)
20684 + return retval;
20685 + cfi->need_gadget_att = 0;
20686 + break;
20687 + }
20688 +
20689 + return retval;
20690 +}
20691 +
20692 +#endif //DWC_UTE_CFI
20693 --- /dev/null
20694 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h
20695 @@ -0,0 +1,320 @@
20696 +/* ==========================================================================
20697 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
20698 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
20699 + * otherwise expressly agreed to in writing between Synopsys and you.
20700 + *
20701 + * The Software IS NOT an item of Licensed Software or Licensed Product under
20702 + * any End User Software License Agreement or Agreement for Licensed Product
20703 + * with Synopsys or any supplement thereto. You are permitted to use and
20704 + * redistribute this Software in source and binary forms, with or without
20705 + * modification, provided that redistributions of source code must retain this
20706 + * notice. You may not view, use, disclose, copy or distribute this file or
20707 + * any information contained herein except pursuant to this license grant from
20708 + * Synopsys. If you do not agree with this notice, including the disclaimer
20709 + * below, then you are not authorized to use the Software.
20710 + *
20711 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
20712 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20713 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20714 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
20715 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20716 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20717 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20718 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20719 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20720 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
20721 + * DAMAGE.
20722 + * ========================================================================== */
20723 +
20724 +#if !defined(__DWC_OTG_CFI_H__)
20725 +#define __DWC_OTG_CFI_H__
20726 +
20727 +#include "dwc_otg_pcd.h"
20728 +#include "dwc_cfi_common.h"
20729 +
20730 +/**
20731 + * @file
20732 + * This file contains the CFI related OTG PCD specific common constants,
20733 + * interfaces(functions and macros) and data structures.The CFI Protocol is an
20734 + * optional interface for internal testing purposes that a DUT may implement to
20735 + * support testing of configurable features.
20736 + *
20737 + */
20738 +
20739 +struct dwc_otg_pcd;
20740 +struct dwc_otg_pcd_ep;
20741 +
20742 +/** OTG CFI Features (properties) ID constants */
20743 +/** This is a request for all Core Features */
20744 +#define FT_ID_DMA_MODE 0x0001
20745 +#define FT_ID_DMA_BUFFER_SETUP 0x0002
20746 +#define FT_ID_DMA_BUFF_ALIGN 0x0003
20747 +#define FT_ID_DMA_CONCAT_SETUP 0x0004
20748 +#define FT_ID_DMA_CIRCULAR 0x0005
20749 +#define FT_ID_THRESHOLD_SETUP 0x0006
20750 +#define FT_ID_DFIFO_DEPTH 0x0007
20751 +#define FT_ID_TX_FIFO_DEPTH 0x0008
20752 +#define FT_ID_RX_FIFO_DEPTH 0x0009
20753 +
20754 +/**********************************************************/
20755 +#define CFI_INFO_DEF
20756 +
20757 +#ifdef CFI_INFO_DEF
20758 +#define CFI_INFO(fmt...) DWC_PRINTF("CFI: " fmt);
20759 +#else
20760 +#define CFI_INFO(fmt...)
20761 +#endif
20762 +
20763 +#define min(x,y) ({ \
20764 + x < y ? x : y; })
20765 +
20766 +#define max(x,y) ({ \
20767 + x > y ? x : y; })
20768 +
20769 +/**
20770 + * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is
20771 + * also used for setting up a buffer for Circular DDMA.
20772 + */
20773 +struct _ddma_sg_buffer_setup {
20774 +#define BS_SG_VAL_DESC_LEN 6
20775 + /* The OUT EP address */
20776 + uint8_t bOutEndpointAddress;
20777 + /* The IN EP address */
20778 + uint8_t bInEndpointAddress;
20779 + /* Number of bytes to put between transfer segments (must be DWORD boundaries) */
20780 + uint8_t bOffset;
20781 + /* The number of transfer segments (a DMA descriptors per each segment) */
20782 + uint8_t bCount;
20783 + /* Size (in byte) of each transfer segment */
20784 + uint16_t wSize;
20785 +} __attribute__ ((packed));
20786 +typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
20787 +
20788 +/** Descriptor DMA Concatenation Buffer setup structure */
20789 +struct _ddma_concat_buffer_setup_hdr {
20790 +#define BS_CONCAT_VAL_HDR_LEN 4
20791 + /* The endpoint for which the buffer is to be set up */
20792 + uint8_t bEndpointAddress;
20793 + /* The count of descriptors to be used */
20794 + uint8_t bDescCount;
20795 + /* The total size of the transfer */
20796 + uint16_t wSize;
20797 +} __attribute__ ((packed));
20798 +typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
20799 +
20800 +/** Descriptor DMA Concatenation Buffer setup structure */
20801 +struct _ddma_concat_buffer_setup {
20802 + /* The SG header */
20803 + ddma_concat_buffer_setup_hdr_t hdr;
20804 +
20805 + /* The XFER sizes pointer (allocated dynamically) */
20806 + uint16_t *wTxBytes;
20807 +} __attribute__ ((packed));
20808 +typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
20809 +
20810 +/** Descriptor DMA Alignment Buffer setup structure */
20811 +struct _ddma_align_buffer_setup {
20812 +#define BS_ALIGN_VAL_HDR_LEN 2
20813 + uint8_t bEndpointAddress;
20814 + uint8_t bAlign;
20815 +} __attribute__ ((packed));
20816 +typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
20817 +
20818 +/** Transmit FIFO Size setup structure */
20819 +struct _tx_fifo_size_setup {
20820 + uint8_t bEndpointAddress;
20821 + uint16_t wDepth;
20822 +} __attribute__ ((packed));
20823 +typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
20824 +
20825 +/** Transmit FIFO Size setup structure */
20826 +struct _rx_fifo_size_setup {
20827 + uint16_t wDepth;
20828 +} __attribute__ ((packed));
20829 +typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
20830 +
20831 +/**
20832 + * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest
20833 + * This structure encapsulates the standard usb_ctrlrequest and adds a pointer
20834 + * to the data returned in the data stage of a 3-stage Control Write requests.
20835 + */
20836 +struct cfi_usb_ctrlrequest {
20837 + uint8_t bRequestType;
20838 + uint8_t bRequest;
20839 + uint16_t wValue;
20840 + uint16_t wIndex;
20841 + uint16_t wLength;
20842 + uint8_t *data;
20843 +} UPACKED;
20844 +
20845 +/*---------------------------------------------------------------------------*/
20846 +
20847 +/**
20848 + * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures.
20849 + * This structure is used to store the buffer setup data for any
20850 + * enabled endpoint in the PCD.
20851 + */
20852 +struct cfi_ep {
20853 + /* Entry for the list container */
20854 + dwc_list_link_t lh;
20855 + /* Pointer to the active PCD endpoint structure */
20856 + struct dwc_otg_pcd_ep *ep;
20857 + /* The last descriptor in the chain of DMA descriptors of the endpoint */
20858 + struct dwc_otg_dma_desc *dma_desc_last;
20859 + /* The SG feature value */
20860 + ddma_sg_buffer_setup_t *bm_sg;
20861 + /* The Circular feature value */
20862 + ddma_sg_buffer_setup_t *bm_circ;
20863 + /* The Concatenation feature value */
20864 + ddma_concat_buffer_setup_t *bm_concat;
20865 + /* The Alignment feature value */
20866 + ddma_align_buffer_setup_t *bm_align;
20867 + /* XFER length */
20868 + uint32_t xfer_len;
20869 + /*
20870 + * Count of DMA descriptors currently used.
20871 + * The total should not exceed the MAX_DMA_DESCS_PER_EP value
20872 + * defined in the dwc_otg_cil.h
20873 + */
20874 + uint32_t desc_count;
20875 +};
20876 +typedef struct cfi_ep cfi_ep_t;
20877 +
20878 +typedef struct cfi_dma_buff {
20879 +#define CFI_IN_BUF_LEN 1024
20880 +#define CFI_OUT_BUF_LEN 1024
20881 + dma_addr_t addr;
20882 + uint8_t *buf;
20883 +} cfi_dma_buff_t;
20884 +
20885 +struct cfiobject;
20886 +
20887 +/**
20888 + * This is the interface for the CFI operations.
20889 + *
20890 + * @param ep_enable Called when any endpoint is enabled and activated.
20891 + * @param release Called when the CFI object is released and it needs to correctly
20892 + * deallocate the dynamic memory
20893 + * @param ctrl_write_complete Called when the data stage of the request is complete
20894 + */
20895 +typedef struct cfi_ops {
20896 + int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
20897 + struct dwc_otg_pcd_ep * ep);
20898 + void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
20899 + struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
20900 + unsigned size, gfp_t flags);
20901 + void (*release) (struct cfiobject * cfi);
20902 + int (*ctrl_write_complete) (struct cfiobject * cfi,
20903 + struct dwc_otg_pcd * pcd);
20904 + void (*build_descriptors) (struct cfiobject * cfi,
20905 + struct dwc_otg_pcd * pcd,
20906 + struct dwc_otg_pcd_ep * ep,
20907 + dwc_otg_pcd_request_t * req);
20908 +} cfi_ops_t;
20909 +
20910 +struct cfiobject {
20911 + cfi_ops_t ops;
20912 + struct dwc_otg_pcd *pcd;
20913 + struct usb_gadget *gadget;
20914 +
20915 + /* Buffers used to send/receive CFI-related request data */
20916 + cfi_dma_buff_t buf_in;
20917 + cfi_dma_buff_t buf_out;
20918 +
20919 + /* CFI specific Control request wrapper */
20920 + struct cfi_usb_ctrlrequest ctrl_req;
20921 +
20922 + /* The list of active EP's in the PCD of type cfi_ep_t */
20923 + dwc_list_link_t active_eps;
20924 +
20925 + /* This flag shall control the propagation of a specific request
20926 + * to the gadget's processing routines.
20927 + * 0 - no gadget handling
20928 + * 1 - the gadget needs to know about this request (w/o completing a status
20929 + * phase - just return a 0 to the _setup callback)
20930 + */
20931 + uint8_t need_gadget_att;
20932 +
20933 + /* Flag indicating whether the status IN phase needs to be
20934 + * completed by the PCD
20935 + */
20936 + uint8_t need_status_in_complete;
20937 +};
20938 +typedef struct cfiobject cfiobject_t;
20939 +
20940 +#define DUMP_MSG
20941 +
20942 +#if defined(DUMP_MSG)
20943 +static inline void dump_msg(const u8 * buf, unsigned int length)
20944 +{
20945 + unsigned int start, num, i;
20946 + char line[52], *p;
20947 +
20948 + if (length >= 512)
20949 + return;
20950 +
20951 + start = 0;
20952 + while (length > 0) {
20953 + num = min(length, 16u);
20954 + p = line;
20955 + for (i = 0; i < num; ++i) {
20956 + if (i == 8)
20957 + *p++ = ' ';
20958 + DWC_SPRINTF(p, " %02x", buf[i]);
20959 + p += 3;
20960 + }
20961 + *p = 0;
20962 + DWC_DEBUG("%6x: %s\n", start, line);
20963 + buf += num;
20964 + start += num;
20965 + length -= num;
20966 + }
20967 +}
20968 +#else
20969 +static inline void dump_msg(const u8 * buf, unsigned int length)
20970 +{
20971 +}
20972 +#endif
20973 +
20974 +/**
20975 + * This function returns a pointer to cfi_ep_t object with the addr address.
20976 + */
20977 +static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
20978 + uint8_t addr)
20979 +{
20980 + struct cfi_ep *pcfiep;
20981 + dwc_list_link_t *tmp;
20982 +
20983 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
20984 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
20985 +
20986 + if (pcfiep->ep->desc->bEndpointAddress == addr) {
20987 + return pcfiep;
20988 + }
20989 + }
20990 +
20991 + return NULL;
20992 +}
20993 +
20994 +/**
20995 + * This function returns a pointer to cfi_ep_t object that matches
20996 + * the dwc_otg_pcd_ep object.
20997 + */
20998 +static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
20999 + struct dwc_otg_pcd_ep *ep)
21000 +{
21001 + struct cfi_ep *pcfiep = NULL;
21002 + dwc_list_link_t *tmp;
21003 +
21004 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
21005 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
21006 + if (pcfiep->ep == ep) {
21007 + return pcfiep;
21008 + }
21009 + }
21010 + return NULL;
21011 +}
21012 +
21013 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
21014 +
21015 +#endif /* (__DWC_OTG_CFI_H__) */
21016 --- /dev/null
21017 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
21018 @@ -0,0 +1,7151 @@
21019 +/* ==========================================================================
21020 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $
21021 + * $Revision: #191 $
21022 + * $Date: 2012/08/10 $
21023 + * $Change: 2047372 $
21024 + *
21025 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
21026 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
21027 + * otherwise expressly agreed to in writing between Synopsys and you.
21028 + *
21029 + * The Software IS NOT an item of Licensed Software or Licensed Product under
21030 + * any End User Software License Agreement or Agreement for Licensed Product
21031 + * with Synopsys or any supplement thereto. You are permitted to use and
21032 + * redistribute this Software in source and binary forms, with or without
21033 + * modification, provided that redistributions of source code must retain this
21034 + * notice. You may not view, use, disclose, copy or distribute this file or
21035 + * any information contained herein except pursuant to this license grant from
21036 + * Synopsys. If you do not agree with this notice, including the disclaimer
21037 + * below, then you are not authorized to use the Software.
21038 + *
21039 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
21040 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21041 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21042 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
21043 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21044 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21045 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21046 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21047 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21048 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
21049 + * DAMAGE.
21050 + * ========================================================================== */
21051 +
21052 +/** @file
21053 + *
21054 + * The Core Interface Layer provides basic services for accessing and
21055 + * managing the DWC_otg hardware. These services are used by both the
21056 + * Host Controller Driver and the Peripheral Controller Driver.
21057 + *
21058 + * The CIL manages the memory map for the core so that the HCD and PCD
21059 + * don't have to do this separately. It also handles basic tasks like
21060 + * reading/writing the registers and data FIFOs in the controller.
21061 + * Some of the data access functions provide encapsulation of several
21062 + * operations required to perform a task, such as writing multiple
21063 + * registers to start a transfer. Finally, the CIL performs basic
21064 + * services that are not specific to either the host or device modes
21065 + * of operation. These services include management of the OTG Host
21066 + * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
21067 + * Diagnostic API is also provided to allow testing of the controller
21068 + * hardware.
21069 + *
21070 + * The Core Interface Layer has the following requirements:
21071 + * - Provides basic controller operations.
21072 + * - Minimal use of OS services.
21073 + * - The OS services used will be abstracted by using inline functions
21074 + * or macros.
21075 + *
21076 + */
21077 +
21078 +#include "dwc_os.h"
21079 +#include "dwc_otg_regs.h"
21080 +#include "dwc_otg_cil.h"
21081 +
21082 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if);
21083 +
21084 +/**
21085 + * This function is called to initialize the DWC_otg CSR data
21086 + * structures. The register addresses in the device and host
21087 + * structures are initialized from the base address supplied by the
21088 + * caller. The calling function must make the OS calls to get the
21089 + * base address of the DWC_otg controller registers. The core_params
21090 + * argument holds the parameters that specify how the core should be
21091 + * configured.
21092 + *
21093 + * @param reg_base_addr Base address of DWC_otg core registers
21094 + *
21095 + */
21096 +dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr)
21097 +{
21098 + dwc_otg_core_if_t *core_if = 0;
21099 + dwc_otg_dev_if_t *dev_if = 0;
21100 + dwc_otg_host_if_t *host_if = 0;
21101 + uint8_t *reg_base = (uint8_t *) reg_base_addr;
21102 + int i = 0;
21103 +
21104 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr);
21105 +
21106 + core_if = DWC_ALLOC(sizeof(dwc_otg_core_if_t));
21107 +
21108 + if (core_if == NULL) {
21109 + DWC_DEBUGPL(DBG_CIL,
21110 + "Allocation of dwc_otg_core_if_t failed\n");
21111 + return 0;
21112 + }
21113 + core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base;
21114 +
21115 + /*
21116 + * Allocate the Device Mode structures.
21117 + */
21118 + dev_if = DWC_ALLOC(sizeof(dwc_otg_dev_if_t));
21119 +
21120 + if (dev_if == NULL) {
21121 + DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
21122 + DWC_FREE(core_if);
21123 + return 0;
21124 + }
21125 +
21126 + dev_if->dev_global_regs =
21127 + (dwc_otg_device_global_regs_t *) (reg_base +
21128 + DWC_DEV_GLOBAL_REG_OFFSET);
21129 +
21130 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21131 + dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
21132 + (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
21133 + (i * DWC_EP_REG_OFFSET));
21134 +
21135 + dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
21136 + (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
21137 + (i * DWC_EP_REG_OFFSET));
21138 + DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
21139 + i, &dev_if->in_ep_regs[i]->diepctl);
21140 + DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
21141 + i, &dev_if->out_ep_regs[i]->doepctl);
21142 + }
21143 +
21144 + dev_if->speed = 0; // unknown
21145 +
21146 + core_if->dev_if = dev_if;
21147 +
21148 + /*
21149 + * Allocate the Host Mode structures.
21150 + */
21151 + host_if = DWC_ALLOC(sizeof(dwc_otg_host_if_t));
21152 +
21153 + if (host_if == NULL) {
21154 + DWC_DEBUGPL(DBG_CIL,
21155 + "Allocation of dwc_otg_host_if_t failed\n");
21156 + DWC_FREE(dev_if);
21157 + DWC_FREE(core_if);
21158 + return 0;
21159 + }
21160 +
21161 + host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
21162 + (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
21163 +
21164 + host_if->hprt0 =
21165 + (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
21166 +
21167 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21168 + host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
21169 + (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
21170 + (i * DWC_OTG_CHAN_REGS_OFFSET));
21171 + DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
21172 + i, &host_if->hc_regs[i]->hcchar);
21173 + }
21174 +
21175 + host_if->num_host_channels = MAX_EPS_CHANNELS;
21176 + core_if->host_if = host_if;
21177 +
21178 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21179 + core_if->data_fifo[i] =
21180 + (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
21181 + (i * DWC_OTG_DATA_FIFO_SIZE));
21182 + DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08lx\n",
21183 + i, (unsigned long)core_if->data_fifo[i]);
21184 + }
21185 +
21186 + core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
21187 +
21188 + /* Initiate lx_state to L3 disconnected state */
21189 + core_if->lx_state = DWC_OTG_L3;
21190 + /*
21191 + * Store the contents of the hardware configuration registers here for
21192 + * easy access later.
21193 + */
21194 + core_if->hwcfg1.d32 =
21195 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg1);
21196 + core_if->hwcfg2.d32 =
21197 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
21198 + core_if->hwcfg3.d32 =
21199 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg3);
21200 + core_if->hwcfg4.d32 =
21201 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
21202 +
21203 + /* Force host mode to get HPTXFSIZ exact power on value */
21204 + {
21205 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
21206 + gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21207 + gusbcfg.b.force_host_mode = 1;
21208 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
21209 + dwc_mdelay(100);
21210 + core_if->hptxfsiz.d32 =
21211 + DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
21212 + gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21213 + gusbcfg.b.force_host_mode = 0;
21214 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
21215 + dwc_mdelay(100);
21216 + }
21217 +
21218 + DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
21219 + DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
21220 + DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
21221 + DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
21222 +
21223 + core_if->hcfg.d32 =
21224 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
21225 + core_if->dcfg.d32 =
21226 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
21227 +
21228 + DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32);
21229 + DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32);
21230 +
21231 + DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
21232 + DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
21233 + DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
21234 + DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
21235 + core_if->hwcfg2.b.num_host_chan);
21236 + DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
21237 + core_if->hwcfg2.b.nonperio_tx_q_depth);
21238 + DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
21239 + core_if->hwcfg2.b.host_perio_tx_q_depth);
21240 + DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
21241 + core_if->hwcfg2.b.dev_token_q_depth);
21242 +
21243 + DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
21244 + core_if->hwcfg3.b.dfifo_depth);
21245 + DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
21246 + core_if->hwcfg3.b.xfer_size_cntr_width);
21247 +
21248 + /*
21249 + * Set the SRP sucess bit for FS-I2c
21250 + */
21251 + core_if->srp_success = 0;
21252 + core_if->srp_timer_started = 0;
21253 +
21254 + /*
21255 + * Create new workqueue and init works
21256 + */
21257 + core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg");
21258 + if (core_if->wq_otg == 0) {
21259 + DWC_WARN("DWC_WORKQ_ALLOC failed\n");
21260 + DWC_FREE(host_if);
21261 + DWC_FREE(dev_if);
21262 + DWC_FREE(core_if);
21263 + return 0;
21264 + }
21265 +
21266 + core_if->snpsid = DWC_READ_REG32(&core_if->core_global_regs->gsnpsid);
21267 +
21268 + DWC_PRINTF("Core Release: %x.%x%x%x\n",
21269 + (core_if->snpsid >> 12 & 0xF),
21270 + (core_if->snpsid >> 8 & 0xF),
21271 + (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF));
21272 +
21273 + core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer",
21274 + w_wakeup_detected, core_if);
21275 + if (core_if->wkp_timer == 0) {
21276 + DWC_WARN("DWC_TIMER_ALLOC failed\n");
21277 + DWC_FREE(host_if);
21278 + DWC_FREE(dev_if);
21279 + DWC_WORKQ_FREE(core_if->wq_otg);
21280 + DWC_FREE(core_if);
21281 + return 0;
21282 + }
21283 +
21284 + if (dwc_otg_setup_params(core_if)) {
21285 + DWC_WARN("Error while setting core params\n");
21286 + }
21287 +
21288 + core_if->hibernation_suspend = 0;
21289 +
21290 + /** ADP initialization */
21291 + dwc_otg_adp_init(core_if);
21292 +
21293 + return core_if;
21294 +}
21295 +
21296 +/**
21297 + * This function frees the structures allocated by dwc_otg_cil_init().
21298 + *
21299 + * @param core_if The core interface pointer returned from
21300 + * dwc_otg_cil_init().
21301 + *
21302 + */
21303 +void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if)
21304 +{
21305 + dctl_data_t dctl = {.d32 = 0 };
21306 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
21307 +
21308 + /* Disable all interrupts */
21309 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 1, 0);
21310 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
21311 +
21312 + dctl.b.sftdiscon = 1;
21313 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
21314 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0,
21315 + dctl.d32);
21316 + }
21317 +
21318 + if (core_if->wq_otg) {
21319 + DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500);
21320 + DWC_WORKQ_FREE(core_if->wq_otg);
21321 + }
21322 + if (core_if->dev_if) {
21323 + DWC_FREE(core_if->dev_if);
21324 + }
21325 + if (core_if->host_if) {
21326 + DWC_FREE(core_if->host_if);
21327 + }
21328 +
21329 + /** Remove ADP Stuff */
21330 + dwc_otg_adp_remove(core_if);
21331 + if (core_if->core_params) {
21332 + DWC_FREE(core_if->core_params);
21333 + }
21334 + if (core_if->wkp_timer) {
21335 + DWC_TIMER_FREE(core_if->wkp_timer);
21336 + }
21337 + if (core_if->srp_timer) {
21338 + DWC_TIMER_FREE(core_if->srp_timer);
21339 + }
21340 + DWC_FREE(core_if);
21341 +}
21342 +
21343 +/**
21344 + * This function enables the controller's Global Interrupt in the AHB Config
21345 + * register.
21346 + *
21347 + * @param core_if Programming view of DWC_otg controller.
21348 + */
21349 +void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if)
21350 +{
21351 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
21352 + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */
21353 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
21354 +}
21355 +
21356 +/**
21357 + * This function disables the controller's Global Interrupt in the AHB Config
21358 + * register.
21359 + *
21360 + * @param core_if Programming view of DWC_otg controller.
21361 + */
21362 +void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if)
21363 +{
21364 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
21365 + ahbcfg.b.glblintrmsk = 1; /* Disable interrupts */
21366 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
21367 +}
21368 +
21369 +/**
21370 + * This function initializes the commmon interrupts, used in both
21371 + * device and host modes.
21372 + *
21373 + * @param core_if Programming view of the DWC_otg controller
21374 + *
21375 + */
21376 +static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if)
21377 +{
21378 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
21379 + gintmsk_data_t intr_mask = {.d32 = 0 };
21380 +
21381 + /* Clear any pending OTG Interrupts */
21382 + DWC_WRITE_REG32(&global_regs->gotgint, 0xFFFFFFFF);
21383 +
21384 + /* Clear any pending interrupts */
21385 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
21386 +
21387 + /*
21388 + * Enable the interrupts in the GINTMSK.
21389 + */
21390 + intr_mask.b.modemismatch = 1;
21391 + intr_mask.b.otgintr = 1;
21392 +
21393 + if (!core_if->dma_enable) {
21394 + intr_mask.b.rxstsqlvl = 1;
21395 + }
21396 +
21397 + intr_mask.b.conidstschng = 1;
21398 + intr_mask.b.wkupintr = 1;
21399 + intr_mask.b.disconnect = 0;
21400 + intr_mask.b.usbsuspend = 1;
21401 + intr_mask.b.sessreqintr = 1;
21402 +#ifdef CONFIG_USB_DWC_OTG_LPM
21403 + if (core_if->core_params->lpm_enable) {
21404 + intr_mask.b.lpmtranrcvd = 1;
21405 + }
21406 +#endif
21407 + DWC_WRITE_REG32(&global_regs->gintmsk, intr_mask.d32);
21408 +}
21409 +
21410 +/*
21411 + * The restore operation is modified to support Synopsys Emulated Powerdown and
21412 + * Hibernation. This function is for exiting from Device mode hibernation by
21413 + * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
21414 + * @param core_if Programming view of DWC_otg controller.
21415 + * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
21416 + * @param reset - indicates whether resume is initiated by Reset.
21417 + */
21418 +int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
21419 + int rem_wakeup, int reset)
21420 +{
21421 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
21422 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
21423 + dctl_data_t dctl = {.d32 = 0 };
21424 +
21425 + int timeout = 2000;
21426 +
21427 + if (!core_if->hibernation_suspend) {
21428 + DWC_PRINTF("Already exited from Hibernation\n");
21429 + return 1;
21430 + }
21431 +
21432 + DWC_DEBUGPL(DBG_PCD, "%s called\n", __FUNCTION__);
21433 + /* Switch-on voltage to the core */
21434 + gpwrdn.b.pwrdnswtch = 1;
21435 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21436 + dwc_udelay(10);
21437 +
21438 + /* Reset core */
21439 + gpwrdn.d32 = 0;
21440 + gpwrdn.b.pwrdnrstn = 1;
21441 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21442 + dwc_udelay(10);
21443 +
21444 + /* Assert Restore signal */
21445 + gpwrdn.d32 = 0;
21446 + gpwrdn.b.restore = 1;
21447 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21448 + dwc_udelay(10);
21449 +
21450 + /* Disable power clamps */
21451 + gpwrdn.d32 = 0;
21452 + gpwrdn.b.pwrdnclmp = 1;
21453 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21454 +
21455 + if (rem_wakeup) {
21456 + dwc_udelay(70);
21457 + }
21458 +
21459 + /* Deassert Reset core */
21460 + gpwrdn.d32 = 0;
21461 + gpwrdn.b.pwrdnrstn = 1;
21462 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21463 + dwc_udelay(10);
21464 +
21465 + /* Disable PMU interrupt */
21466 + gpwrdn.d32 = 0;
21467 + gpwrdn.b.pmuintsel = 1;
21468 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21469 +
21470 + /* Mask interrupts from gpwrdn */
21471 + gpwrdn.d32 = 0;
21472 + gpwrdn.b.connect_det_msk = 1;
21473 + gpwrdn.b.srp_det_msk = 1;
21474 + gpwrdn.b.disconn_det_msk = 1;
21475 + gpwrdn.b.rst_det_msk = 1;
21476 + gpwrdn.b.lnstchng_msk = 1;
21477 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21478 +
21479 + /* Indicates that we are going out from hibernation */
21480 + core_if->hibernation_suspend = 0;
21481 +
21482 + /*
21483 + * Set Restore Essential Regs bit in PCGCCTL register, restore_mode = 1
21484 + * indicates restore from remote_wakeup
21485 + */
21486 + restore_essential_regs(core_if, rem_wakeup, 0);
21487 +
21488 + /*
21489 + * Wait a little for seeing new value of variable hibernation_suspend if
21490 + * Restore done interrupt received before polling
21491 + */
21492 + dwc_udelay(10);
21493 +
21494 + if (core_if->hibernation_suspend == 0) {
21495 + /*
21496 + * Wait For Restore_done Interrupt. This mechanism of polling the
21497 + * interrupt is introduced to avoid any possible race conditions
21498 + */
21499 + do {
21500 + gintsts_data_t gintsts;
21501 + gintsts.d32 =
21502 + DWC_READ_REG32(&core_if->core_global_regs->gintsts);
21503 + if (gintsts.b.restoredone) {
21504 + gintsts.d32 = 0;
21505 + gintsts.b.restoredone = 1;
21506 + DWC_WRITE_REG32(&core_if->core_global_regs->
21507 + gintsts, gintsts.d32);
21508 + DWC_PRINTF("Restore Done Interrupt seen\n");
21509 + break;
21510 + }
21511 + dwc_udelay(10);
21512 + } while (--timeout);
21513 + if (!timeout) {
21514 + DWC_PRINTF("Restore Done interrupt wasn't generated here\n");
21515 + }
21516 + }
21517 + /* Clear all pending interupts */
21518 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21519 +
21520 + /* De-assert Restore */
21521 + gpwrdn.d32 = 0;
21522 + gpwrdn.b.restore = 1;
21523 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21524 + dwc_udelay(10);
21525 +
21526 + if (!rem_wakeup) {
21527 + pcgcctl.d32 = 0;
21528 + pcgcctl.b.rstpdwnmodule = 1;
21529 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
21530 + }
21531 +
21532 + /* Restore GUSBCFG and DCFG */
21533 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
21534 + core_if->gr_backup->gusbcfg_local);
21535 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
21536 + core_if->dr_backup->dcfg);
21537 +
21538 + /* De-assert Wakeup Logic */
21539 + gpwrdn.d32 = 0;
21540 + gpwrdn.b.pmuactv = 1;
21541 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21542 + dwc_udelay(10);
21543 +
21544 + if (!rem_wakeup) {
21545 + /* Set Device programming done bit */
21546 + dctl.b.pwronprgdone = 1;
21547 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
21548 + } else {
21549 + /* Start Remote Wakeup Signaling */
21550 + dctl.d32 = core_if->dr_backup->dctl;
21551 + dctl.b.rmtwkupsig = 1;
21552 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
21553 + }
21554 +
21555 + dwc_mdelay(2);
21556 + /* Clear all pending interupts */
21557 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21558 +
21559 + /* Restore global registers */
21560 + dwc_otg_restore_global_regs(core_if);
21561 + /* Restore device global registers */
21562 + dwc_otg_restore_dev_regs(core_if, rem_wakeup);
21563 +
21564 + if (rem_wakeup) {
21565 + dwc_mdelay(7);
21566 + dctl.d32 = 0;
21567 + dctl.b.rmtwkupsig = 1;
21568 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
21569 + }
21570 +
21571 + core_if->hibernation_suspend = 0;
21572 + /* The core will be in ON STATE */
21573 + core_if->lx_state = DWC_OTG_L0;
21574 + DWC_PRINTF("Hibernation recovery completes here\n");
21575 +
21576 + return 1;
21577 +}
21578 +
21579 +/*
21580 + * The restore operation is modified to support Synopsys Emulated Powerdown and
21581 + * Hibernation. This function is for exiting from Host mode hibernation by
21582 + * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
21583 + * @param core_if Programming view of DWC_otg controller.
21584 + * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
21585 + * @param reset - indicates whether resume is initiated by Reset.
21586 + */
21587 +int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
21588 + int rem_wakeup, int reset)
21589 +{
21590 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
21591 + hprt0_data_t hprt0 = {.d32 = 0 };
21592 +
21593 + int timeout = 2000;
21594 +
21595 + DWC_DEBUGPL(DBG_HCD, "%s called\n", __FUNCTION__);
21596 + /* Switch-on voltage to the core */
21597 + gpwrdn.b.pwrdnswtch = 1;
21598 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21599 + dwc_udelay(10);
21600 +
21601 + /* Reset core */
21602 + gpwrdn.d32 = 0;
21603 + gpwrdn.b.pwrdnrstn = 1;
21604 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21605 + dwc_udelay(10);
21606 +
21607 + /* Assert Restore signal */
21608 + gpwrdn.d32 = 0;
21609 + gpwrdn.b.restore = 1;
21610 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21611 + dwc_udelay(10);
21612 +
21613 + /* Disable power clamps */
21614 + gpwrdn.d32 = 0;
21615 + gpwrdn.b.pwrdnclmp = 1;
21616 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21617 +
21618 + if (!rem_wakeup) {
21619 + dwc_udelay(50);
21620 + }
21621 +
21622 + /* Deassert Reset core */
21623 + gpwrdn.d32 = 0;
21624 + gpwrdn.b.pwrdnrstn = 1;
21625 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21626 + dwc_udelay(10);
21627 +
21628 + /* Disable PMU interrupt */
21629 + gpwrdn.d32 = 0;
21630 + gpwrdn.b.pmuintsel = 1;
21631 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21632 +
21633 + gpwrdn.d32 = 0;
21634 + gpwrdn.b.connect_det_msk = 1;
21635 + gpwrdn.b.srp_det_msk = 1;
21636 + gpwrdn.b.disconn_det_msk = 1;
21637 + gpwrdn.b.rst_det_msk = 1;
21638 + gpwrdn.b.lnstchng_msk = 1;
21639 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21640 +
21641 + /* Indicates that we are going out from hibernation */
21642 + core_if->hibernation_suspend = 0;
21643 +
21644 + /* Set Restore Essential Regs bit in PCGCCTL register */
21645 + restore_essential_regs(core_if, rem_wakeup, 1);
21646 +
21647 + /* Wait a little for seeing new value of variable hibernation_suspend if
21648 + * Restore done interrupt received before polling */
21649 + dwc_udelay(10);
21650 +
21651 + if (core_if->hibernation_suspend == 0) {
21652 + /* Wait For Restore_done Interrupt. This mechanism of polling the
21653 + * interrupt is introduced to avoid any possible race conditions
21654 + */
21655 + do {
21656 + gintsts_data_t gintsts;
21657 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
21658 + if (gintsts.b.restoredone) {
21659 + gintsts.d32 = 0;
21660 + gintsts.b.restoredone = 1;
21661 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
21662 + DWC_DEBUGPL(DBG_HCD,"Restore Done Interrupt seen\n");
21663 + break;
21664 + }
21665 + dwc_udelay(10);
21666 + } while (--timeout);
21667 + if (!timeout) {
21668 + DWC_WARN("Restore Done interrupt wasn't generated\n");
21669 + }
21670 + }
21671 +
21672 + /* Set the flag's value to 0 again after receiving restore done interrupt */
21673 + core_if->hibernation_suspend = 0;
21674 +
21675 + /* This step is not described in functional spec but if not wait for this
21676 + * delay, mismatch interrupts occurred because just after restore core is
21677 + * in Device mode(gintsts.curmode == 0) */
21678 + dwc_mdelay(100);
21679 +
21680 + /* Clear all pending interrupts */
21681 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21682 +
21683 + /* De-assert Restore */
21684 + gpwrdn.d32 = 0;
21685 + gpwrdn.b.restore = 1;
21686 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21687 + dwc_udelay(10);
21688 +
21689 + /* Restore GUSBCFG and HCFG */
21690 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
21691 + core_if->gr_backup->gusbcfg_local);
21692 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
21693 + core_if->hr_backup->hcfg_local);
21694 +
21695 + /* De-assert Wakeup Logic */
21696 + gpwrdn.d32 = 0;
21697 + gpwrdn.b.pmuactv = 1;
21698 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21699 + dwc_udelay(10);
21700 +
21701 + /* Start the Resume operation by programming HPRT0 */
21702 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21703 + hprt0.b.prtpwr = 1;
21704 + hprt0.b.prtena = 0;
21705 + hprt0.b.prtsusp = 0;
21706 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21707 +
21708 + DWC_PRINTF("Resume Starts Now\n");
21709 + if (!reset) { // Indicates it is Resume Operation
21710 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21711 + hprt0.b.prtres = 1;
21712 + hprt0.b.prtpwr = 1;
21713 + hprt0.b.prtena = 0;
21714 + hprt0.b.prtsusp = 0;
21715 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21716 +
21717 + if (!rem_wakeup)
21718 + hprt0.b.prtres = 0;
21719 + /* Wait for Resume time and then program HPRT again */
21720 + dwc_mdelay(100);
21721 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21722 +
21723 + } else { // Indicates it is Reset Operation
21724 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21725 + hprt0.b.prtrst = 1;
21726 + hprt0.b.prtpwr = 1;
21727 + hprt0.b.prtena = 0;
21728 + hprt0.b.prtsusp = 0;
21729 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21730 + /* Wait for Reset time and then program HPRT again */
21731 + dwc_mdelay(60);
21732 + hprt0.b.prtrst = 0;
21733 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21734 + }
21735 + /* Clear all interrupt status */
21736 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
21737 + hprt0.b.prtconndet = 1;
21738 + hprt0.b.prtenchng = 1;
21739 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21740 +
21741 + /* Clear all pending interupts */
21742 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21743 +
21744 + /* Restore global registers */
21745 + dwc_otg_restore_global_regs(core_if);
21746 + /* Restore host global registers */
21747 + dwc_otg_restore_host_regs(core_if, reset);
21748 +
21749 + /* The core will be in ON STATE */
21750 + core_if->lx_state = DWC_OTG_L0;
21751 + DWC_PRINTF("Hibernation recovery is complete here\n");
21752 + return 0;
21753 +}
21754 +
21755 +/** Saves some register values into system memory. */
21756 +int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if)
21757 +{
21758 + struct dwc_otg_global_regs_backup *gr;
21759 + int i;
21760 +
21761 + gr = core_if->gr_backup;
21762 + if (!gr) {
21763 + gr = DWC_ALLOC(sizeof(*gr));
21764 + if (!gr) {
21765 + return -DWC_E_NO_MEMORY;
21766 + }
21767 + core_if->gr_backup = gr;
21768 + }
21769 +
21770 + gr->gotgctl_local = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
21771 + gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
21772 + gr->gahbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
21773 + gr->gusbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21774 + gr->grxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
21775 + gr->gnptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
21776 + gr->hptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
21777 +#ifdef CONFIG_USB_DWC_OTG_LPM
21778 + gr->glpmcfg_local = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
21779 +#endif
21780 + gr->gi2cctl_local = DWC_READ_REG32(&core_if->core_global_regs->gi2cctl);
21781 + gr->pcgcctl_local = DWC_READ_REG32(core_if->pcgcctl);
21782 + gr->gdfifocfg_local =
21783 + DWC_READ_REG32(&core_if->core_global_regs->gdfifocfg);
21784 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21785 + gr->dtxfsiz_local[i] =
21786 + DWC_READ_REG32(&(core_if->core_global_regs->dtxfsiz[i]));
21787 + }
21788 +
21789 + DWC_DEBUGPL(DBG_ANY, "===========Backing Global registers==========\n");
21790 + DWC_DEBUGPL(DBG_ANY, "Backed up gotgctl = %08x\n", gr->gotgctl_local);
21791 + DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
21792 + DWC_DEBUGPL(DBG_ANY, "Backed up gahbcfg = %08x\n", gr->gahbcfg_local);
21793 + DWC_DEBUGPL(DBG_ANY, "Backed up gusbcfg = %08x\n", gr->gusbcfg_local);
21794 + DWC_DEBUGPL(DBG_ANY, "Backed up grxfsiz = %08x\n", gr->grxfsiz_local);
21795 + DWC_DEBUGPL(DBG_ANY, "Backed up gnptxfsiz = %08x\n",
21796 + gr->gnptxfsiz_local);
21797 + DWC_DEBUGPL(DBG_ANY, "Backed up hptxfsiz = %08x\n",
21798 + gr->hptxfsiz_local);
21799 +#ifdef CONFIG_USB_DWC_OTG_LPM
21800 + DWC_DEBUGPL(DBG_ANY, "Backed up glpmcfg = %08x\n", gr->glpmcfg_local);
21801 +#endif
21802 + DWC_DEBUGPL(DBG_ANY, "Backed up gi2cctl = %08x\n", gr->gi2cctl_local);
21803 + DWC_DEBUGPL(DBG_ANY, "Backed up pcgcctl = %08x\n", gr->pcgcctl_local);
21804 + DWC_DEBUGPL(DBG_ANY,"Backed up gdfifocfg = %08x\n",gr->gdfifocfg_local);
21805 +
21806 + return 0;
21807 +}
21808 +
21809 +/** Saves GINTMSK register before setting the msk bits. */
21810 +int dwc_otg_save_gintmsk_reg(dwc_otg_core_if_t * core_if)
21811 +{
21812 + struct dwc_otg_global_regs_backup *gr;
21813 +
21814 + gr = core_if->gr_backup;
21815 + if (!gr) {
21816 + gr = DWC_ALLOC(sizeof(*gr));
21817 + if (!gr) {
21818 + return -DWC_E_NO_MEMORY;
21819 + }
21820 + core_if->gr_backup = gr;
21821 + }
21822 +
21823 + gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
21824 +
21825 + DWC_DEBUGPL(DBG_ANY,"=============Backing GINTMSK registers============\n");
21826 + DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
21827 +
21828 + return 0;
21829 +}
21830 +
21831 +int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if)
21832 +{
21833 + struct dwc_otg_dev_regs_backup *dr;
21834 + int i;
21835 +
21836 + dr = core_if->dr_backup;
21837 + if (!dr) {
21838 + dr = DWC_ALLOC(sizeof(*dr));
21839 + if (!dr) {
21840 + return -DWC_E_NO_MEMORY;
21841 + }
21842 + core_if->dr_backup = dr;
21843 + }
21844 +
21845 + dr->dcfg = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
21846 + dr->dctl = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
21847 + dr->daintmsk =
21848 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
21849 + dr->diepmsk =
21850 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->diepmsk);
21851 + dr->doepmsk =
21852 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->doepmsk);
21853 +
21854 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21855 + dr->diepctl[i] =
21856 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
21857 + dr->dieptsiz[i] =
21858 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz);
21859 + dr->diepdma[i] =
21860 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma);
21861 + }
21862 +
21863 + DWC_DEBUGPL(DBG_ANY,
21864 + "=============Backing Host registers==============\n");
21865 + DWC_DEBUGPL(DBG_ANY, "Backed up dcfg = %08x\n", dr->dcfg);
21866 + DWC_DEBUGPL(DBG_ANY, "Backed up dctl = %08x\n", dr->dctl);
21867 + DWC_DEBUGPL(DBG_ANY, "Backed up daintmsk = %08x\n",
21868 + dr->daintmsk);
21869 + DWC_DEBUGPL(DBG_ANY, "Backed up diepmsk = %08x\n", dr->diepmsk);
21870 + DWC_DEBUGPL(DBG_ANY, "Backed up doepmsk = %08x\n", dr->doepmsk);
21871 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21872 + DWC_DEBUGPL(DBG_ANY, "Backed up diepctl[%d] = %08x\n", i,
21873 + dr->diepctl[i]);
21874 + DWC_DEBUGPL(DBG_ANY, "Backed up dieptsiz[%d] = %08x\n",
21875 + i, dr->dieptsiz[i]);
21876 + DWC_DEBUGPL(DBG_ANY, "Backed up diepdma[%d] = %08x\n", i,
21877 + dr->diepdma[i]);
21878 + }
21879 +
21880 + return 0;
21881 +}
21882 +
21883 +int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if)
21884 +{
21885 + struct dwc_otg_host_regs_backup *hr;
21886 + int i;
21887 +
21888 + hr = core_if->hr_backup;
21889 + if (!hr) {
21890 + hr = DWC_ALLOC(sizeof(*hr));
21891 + if (!hr) {
21892 + return -DWC_E_NO_MEMORY;
21893 + }
21894 + core_if->hr_backup = hr;
21895 + }
21896 +
21897 + hr->hcfg_local =
21898 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
21899 + hr->haintmsk_local =
21900 + DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
21901 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
21902 + hr->hcintmsk_local[i] =
21903 + DWC_READ_REG32(&core_if->host_if->hc_regs[i]->hcintmsk);
21904 + }
21905 + hr->hprt0_local = DWC_READ_REG32(core_if->host_if->hprt0);
21906 + hr->hfir_local =
21907 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
21908 +
21909 + DWC_DEBUGPL(DBG_ANY,
21910 + "=============Backing Host registers===============\n");
21911 + DWC_DEBUGPL(DBG_ANY, "Backed up hcfg = %08x\n",
21912 + hr->hcfg_local);
21913 + DWC_DEBUGPL(DBG_ANY, "Backed up haintmsk = %08x\n", hr->haintmsk_local);
21914 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
21915 + DWC_DEBUGPL(DBG_ANY, "Backed up hcintmsk[%02d]=%08x\n", i,
21916 + hr->hcintmsk_local[i]);
21917 + }
21918 + DWC_DEBUGPL(DBG_ANY, "Backed up hprt0 = %08x\n",
21919 + hr->hprt0_local);
21920 + DWC_DEBUGPL(DBG_ANY, "Backed up hfir = %08x\n",
21921 + hr->hfir_local);
21922 +
21923 + return 0;
21924 +}
21925 +
21926 +int dwc_otg_restore_global_regs(dwc_otg_core_if_t *core_if)
21927 +{
21928 + struct dwc_otg_global_regs_backup *gr;
21929 + int i;
21930 +
21931 + gr = core_if->gr_backup;
21932 + if (!gr) {
21933 + return -DWC_E_INVALID;
21934 + }
21935 +
21936 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, gr->gotgctl_local);
21937 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gr->gintmsk_local);
21938 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gr->gusbcfg_local);
21939 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gr->gahbcfg_local);
21940 + DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, gr->grxfsiz_local);
21941 + DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz,
21942 + gr->gnptxfsiz_local);
21943 + DWC_WRITE_REG32(&core_if->core_global_regs->hptxfsiz,
21944 + gr->hptxfsiz_local);
21945 + DWC_WRITE_REG32(&core_if->core_global_regs->gdfifocfg,
21946 + gr->gdfifocfg_local);
21947 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21948 + DWC_WRITE_REG32(&core_if->core_global_regs->dtxfsiz[i],
21949 + gr->dtxfsiz_local[i]);
21950 + }
21951 +
21952 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21953 + DWC_WRITE_REG32(core_if->host_if->hprt0, 0x0000100A);
21954 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg,
21955 + (gr->gahbcfg_local));
21956 + return 0;
21957 +}
21958 +
21959 +int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if, int rem_wakeup)
21960 +{
21961 + struct dwc_otg_dev_regs_backup *dr;
21962 + int i;
21963 +
21964 + dr = core_if->dr_backup;
21965 +
21966 + if (!dr) {
21967 + return -DWC_E_INVALID;
21968 + }
21969 +
21970 + if (!rem_wakeup) {
21971 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
21972 + dr->dctl);
21973 + }
21974 +
21975 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, dr->daintmsk);
21976 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, dr->diepmsk);
21977 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, dr->doepmsk);
21978 +
21979 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21980 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz, dr->dieptsiz[i]);
21981 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma, dr->diepdma[i]);
21982 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl, dr->diepctl[i]);
21983 + }
21984 +
21985 + return 0;
21986 +}
21987 +
21988 +int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset)
21989 +{
21990 + struct dwc_otg_host_regs_backup *hr;
21991 + int i;
21992 + hr = core_if->hr_backup;
21993 +
21994 + if (!hr) {
21995 + return -DWC_E_INVALID;
21996 + }
21997 +
21998 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hr->hcfg_local);
21999 + //if (!reset)
22000 + //{
22001 + // DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hr->hfir_local);
22002 + //}
22003 +
22004 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk,
22005 + hr->haintmsk_local);
22006 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
22007 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk,
22008 + hr->hcintmsk_local[i]);
22009 + }
22010 +
22011 + return 0;
22012 +}
22013 +
22014 +int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if)
22015 +{
22016 + struct dwc_otg_global_regs_backup *gr;
22017 +
22018 + gr = core_if->gr_backup;
22019 +
22020 + /* Restore values for LPM and I2C */
22021 +#ifdef CONFIG_USB_DWC_OTG_LPM
22022 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, gr->glpmcfg_local);
22023 +#endif
22024 + DWC_WRITE_REG32(&core_if->core_global_regs->gi2cctl, gr->gi2cctl_local);
22025 +
22026 + return 0;
22027 +}
22028 +
22029 +int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode, int is_host)
22030 +{
22031 + struct dwc_otg_global_regs_backup *gr;
22032 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
22033 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
22034 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
22035 + gintmsk_data_t gintmsk = {.d32 = 0 };
22036 +
22037 + /* Restore LPM and I2C registers */
22038 + restore_lpm_i2c_regs(core_if);
22039 +
22040 + /* Set PCGCCTL to 0 */
22041 + DWC_WRITE_REG32(core_if->pcgcctl, 0x00000000);
22042 +
22043 + gr = core_if->gr_backup;
22044 + /* Load restore values for [31:14] bits */
22045 + DWC_WRITE_REG32(core_if->pcgcctl,
22046 + ((gr->pcgcctl_local & 0xffffc000) | 0x00020000));
22047 +
22048 + /* Umnask global Interrupt in GAHBCFG and restore it */
22049 + gahbcfg.d32 = gr->gahbcfg_local;
22050 + gahbcfg.b.glblintrmsk = 1;
22051 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
22052 +
22053 + /* Clear all pending interupts */
22054 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
22055 +
22056 + /* Unmask restore done interrupt */
22057 + gintmsk.b.restoredone = 1;
22058 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
22059 +
22060 + /* Restore GUSBCFG and HCFG/DCFG */
22061 + gusbcfg.d32 = core_if->gr_backup->gusbcfg_local;
22062 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
22063 +
22064 + if (is_host) {
22065 + hcfg_data_t hcfg = {.d32 = 0 };
22066 + hcfg.d32 = core_if->hr_backup->hcfg_local;
22067 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
22068 + hcfg.d32);
22069 +
22070 + /* Load restore values for [31:14] bits */
22071 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22072 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22073 +
22074 + if (rmode)
22075 + pcgcctl.b.restoremode = 1;
22076 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22077 + dwc_udelay(10);
22078 +
22079 + /* Load restore values for [31:14] bits and set EssRegRestored bit */
22080 + pcgcctl.d32 = gr->pcgcctl_local | 0xffffc000;
22081 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22082 + pcgcctl.b.ess_reg_restored = 1;
22083 + if (rmode)
22084 + pcgcctl.b.restoremode = 1;
22085 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22086 + } else {
22087 + dcfg_data_t dcfg = {.d32 = 0 };
22088 + dcfg.d32 = core_if->dr_backup->dcfg;
22089 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
22090 +
22091 + /* Load restore values for [31:14] bits */
22092 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22093 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22094 + if (!rmode) {
22095 + pcgcctl.d32 |= 0x208;
22096 + }
22097 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22098 + dwc_udelay(10);
22099 +
22100 + /* Load restore values for [31:14] bits */
22101 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22102 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22103 + pcgcctl.b.ess_reg_restored = 1;
22104 + if (!rmode)
22105 + pcgcctl.d32 |= 0x208;
22106 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22107 + }
22108 +
22109 + return 0;
22110 +}
22111 +
22112 +/**
22113 + * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
22114 + * type.
22115 + */
22116 +static void init_fslspclksel(dwc_otg_core_if_t * core_if)
22117 +{
22118 + uint32_t val;
22119 + hcfg_data_t hcfg;
22120 +
22121 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
22122 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22123 + (core_if->core_params->ulpi_fs_ls)) ||
22124 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22125 + /* Full speed PHY */
22126 + val = DWC_HCFG_48_MHZ;
22127 + } else {
22128 + /* High speed PHY running at full speed or high speed */
22129 + val = DWC_HCFG_30_60_MHZ;
22130 + }
22131 +
22132 + DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
22133 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
22134 + hcfg.b.fslspclksel = val;
22135 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
22136 +}
22137 +
22138 +/**
22139 + * Initializes the DevSpd field of the DCFG register depending on the PHY type
22140 + * and the enumeration speed of the device.
22141 + */
22142 +static void init_devspd(dwc_otg_core_if_t * core_if)
22143 +{
22144 + uint32_t val;
22145 + dcfg_data_t dcfg;
22146 +
22147 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
22148 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22149 + (core_if->core_params->ulpi_fs_ls)) ||
22150 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22151 + /* Full speed PHY */
22152 + val = 0x3;
22153 + } else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
22154 + /* High speed PHY running at full speed */
22155 + val = 0x1;
22156 + } else {
22157 + /* High speed PHY running at high speed */
22158 + val = 0x0;
22159 + }
22160 +
22161 + DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
22162 +
22163 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
22164 + dcfg.b.devspd = val;
22165 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
22166 +}
22167 +
22168 +/**
22169 + * This function calculates the number of IN EPS
22170 + * using GHWCFG1 and GHWCFG2 registers values
22171 + *
22172 + * @param core_if Programming view of the DWC_otg controller
22173 + */
22174 +static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if)
22175 +{
22176 + uint32_t num_in_eps = 0;
22177 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
22178 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3;
22179 + uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps;
22180 + int i;
22181 +
22182 + for (i = 0; i < num_eps; ++i) {
22183 + if (!(hwcfg1 & 0x1))
22184 + num_in_eps++;
22185 +
22186 + hwcfg1 >>= 2;
22187 + }
22188 +
22189 + if (core_if->hwcfg4.b.ded_fifo_en) {
22190 + num_in_eps =
22191 + (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
22192 + }
22193 +
22194 + return num_in_eps;
22195 +}
22196 +
22197 +/**
22198 + * This function calculates the number of OUT EPS
22199 + * using GHWCFG1 and GHWCFG2 registers values
22200 + *
22201 + * @param core_if Programming view of the DWC_otg controller
22202 + */
22203 +static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if)
22204 +{
22205 + uint32_t num_out_eps = 0;
22206 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
22207 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2;
22208 + int i;
22209 +
22210 + for (i = 0; i < num_eps; ++i) {
22211 + if (!(hwcfg1 & 0x1))
22212 + num_out_eps++;
22213 +
22214 + hwcfg1 >>= 2;
22215 + }
22216 + return num_out_eps;
22217 +}
22218 +
22219 +/**
22220 + * This function initializes the DWC_otg controller registers and
22221 + * prepares the core for device mode or host mode operation.
22222 + *
22223 + * @param core_if Programming view of the DWC_otg controller
22224 + *
22225 + */
22226 +void dwc_otg_core_init(dwc_otg_core_if_t * core_if)
22227 +{
22228 + int i = 0;
22229 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22230 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
22231 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
22232 + gusbcfg_data_t usbcfg = {.d32 = 0 };
22233 + gi2cctl_data_t i2cctl = {.d32 = 0 };
22234 +
22235 + DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p) regs at %p\n",
22236 + core_if, global_regs);
22237 +
22238 + /* Common Initialization */
22239 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22240 +
22241 + /* Program the ULPI External VBUS bit if needed */
22242 + usbcfg.b.ulpi_ext_vbus_drv =
22243 + (core_if->core_params->phy_ulpi_ext_vbus ==
22244 + DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
22245 +
22246 + /* Set external TS Dline pulsing */
22247 + usbcfg.b.term_sel_dl_pulse =
22248 + (core_if->core_params->ts_dline == 1) ? 1 : 0;
22249 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22250 +
22251 + /* Reset the Controller */
22252 + dwc_otg_core_reset(core_if);
22253 +
22254 + core_if->adp_enable = core_if->core_params->adp_supp_enable;
22255 + core_if->power_down = core_if->core_params->power_down;
22256 + core_if->otg_sts = 0;
22257 +
22258 + /* Initialize parameters from Hardware configuration registers. */
22259 + dev_if->num_in_eps = calc_num_in_eps(core_if);
22260 + dev_if->num_out_eps = calc_num_out_eps(core_if);
22261 +
22262 + DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
22263 + core_if->hwcfg4.b.num_dev_perio_in_ep);
22264 +
22265 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
22266 + dev_if->perio_tx_fifo_size[i] =
22267 + DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
22268 + DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
22269 + i, dev_if->perio_tx_fifo_size[i]);
22270 + }
22271 +
22272 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
22273 + dev_if->tx_fifo_size[i] =
22274 + DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
22275 + DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
22276 + i, dev_if->tx_fifo_size[i]);
22277 + }
22278 +
22279 + core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
22280 + core_if->rx_fifo_size = DWC_READ_REG32(&global_regs->grxfsiz);
22281 + core_if->nperio_tx_fifo_size =
22282 + DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16;
22283 +
22284 + DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
22285 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
22286 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
22287 + core_if->nperio_tx_fifo_size);
22288 +
22289 + /* This programming sequence needs to happen in FS mode before any other
22290 + * programming occurs */
22291 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
22292 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22293 + /* If FS mode with FS PHY */
22294 +
22295 + /* core_init() is now called on every switch so only call the
22296 + * following for the first time through. */
22297 + if (!core_if->phy_init_done) {
22298 + core_if->phy_init_done = 1;
22299 + DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
22300 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22301 + usbcfg.b.physel = 1;
22302 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22303 +
22304 + /* Reset after a PHY select */
22305 + dwc_otg_core_reset(core_if);
22306 + }
22307 +
22308 + /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
22309 + * do this on HNP Dev/Host mode switches (done in dev_init and
22310 + * host_init). */
22311 + if (dwc_otg_is_host_mode(core_if)) {
22312 + init_fslspclksel(core_if);
22313 + } else {
22314 + init_devspd(core_if);
22315 + }
22316 +
22317 + if (core_if->core_params->i2c_enable) {
22318 + DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
22319 + /* Program GUSBCFG.OtgUtmifsSel to I2C */
22320 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22321 + usbcfg.b.otgutmifssel = 1;
22322 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22323 +
22324 + /* Program GI2CCTL.I2CEn */
22325 + i2cctl.d32 = DWC_READ_REG32(&global_regs->gi2cctl);
22326 + i2cctl.b.i2cdevaddr = 1;
22327 + i2cctl.b.i2cen = 0;
22328 + DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
22329 + i2cctl.b.i2cen = 1;
22330 + DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
22331 + }
22332 +
22333 + } /* endif speed == DWC_SPEED_PARAM_FULL */
22334 + else {
22335 + /* High speed PHY. */
22336 + if (!core_if->phy_init_done) {
22337 + core_if->phy_init_done = 1;
22338 + /* HS PHY parameters. These parameters are preserved
22339 + * during soft reset so only program the first time. Do
22340 + * a soft reset immediately after setting phyif. */
22341 +
22342 + if (core_if->core_params->phy_type == 2) {
22343 + /* ULPI interface */
22344 + usbcfg.b.ulpi_utmi_sel = 1;
22345 + usbcfg.b.phyif = 0;
22346 + usbcfg.b.ddrsel =
22347 + core_if->core_params->phy_ulpi_ddr;
22348 + } else if (core_if->core_params->phy_type == 1) {
22349 + /* UTMI+ interface */
22350 + usbcfg.b.ulpi_utmi_sel = 0;
22351 + if (core_if->core_params->phy_utmi_width == 16) {
22352 + usbcfg.b.phyif = 1;
22353 +
22354 + } else {
22355 + usbcfg.b.phyif = 0;
22356 + }
22357 + } else {
22358 + DWC_ERROR("FS PHY TYPE\n");
22359 + }
22360 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22361 + /* Reset after setting the PHY parameters */
22362 + dwc_otg_core_reset(core_if);
22363 + }
22364 + }
22365 +
22366 + if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
22367 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22368 + (core_if->core_params->ulpi_fs_ls)) {
22369 + DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
22370 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22371 + usbcfg.b.ulpi_fsls = 1;
22372 + usbcfg.b.ulpi_clk_sus_m = 1;
22373 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22374 + } else {
22375 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22376 + usbcfg.b.ulpi_fsls = 0;
22377 + usbcfg.b.ulpi_clk_sus_m = 0;
22378 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22379 + }
22380 +
22381 + /* Program the GAHBCFG Register. */
22382 + switch (core_if->hwcfg2.b.architecture) {
22383 +
22384 + case DWC_SLAVE_ONLY_ARCH:
22385 + DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
22386 + ahbcfg.b.nptxfemplvl_txfemplvl =
22387 + DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
22388 + ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
22389 + core_if->dma_enable = 0;
22390 + core_if->dma_desc_enable = 0;
22391 + break;
22392 +
22393 + case DWC_EXT_DMA_ARCH:
22394 + DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
22395 + {
22396 + uint8_t brst_sz = core_if->core_params->dma_burst_size;
22397 + ahbcfg.b.hburstlen = 0;
22398 + while (brst_sz > 1) {
22399 + ahbcfg.b.hburstlen++;
22400 + brst_sz >>= 1;
22401 + }
22402 + }
22403 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
22404 + core_if->dma_desc_enable =
22405 + (core_if->core_params->dma_desc_enable != 0);
22406 + break;
22407 +
22408 + case DWC_INT_DMA_ARCH:
22409 + DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
22410 + /* Old value was DWC_GAHBCFG_INT_DMA_BURST_INCR - done for
22411 + Host mode ISOC in issue fix - vahrama */
22412 + /* Broadcom had altered to (1<<3)|(0<<0) - WRESP=1, max 4 beats */
22413 + ahbcfg.b.hburstlen = (1<<3)|(0<<0);//DWC_GAHBCFG_INT_DMA_BURST_INCR4;
22414 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
22415 + core_if->dma_desc_enable =
22416 + (core_if->core_params->dma_desc_enable != 0);
22417 + break;
22418 +
22419 + }
22420 + if (core_if->dma_enable) {
22421 + if (core_if->dma_desc_enable) {
22422 + DWC_PRINTF("Using Descriptor DMA mode\n");
22423 + } else {
22424 + DWC_PRINTF("Using Buffer DMA mode\n");
22425 +
22426 + }
22427 + } else {
22428 + DWC_PRINTF("Using Slave mode\n");
22429 + core_if->dma_desc_enable = 0;
22430 + }
22431 +
22432 + if (core_if->core_params->ahb_single) {
22433 + ahbcfg.b.ahbsingle = 1;
22434 + }
22435 +
22436 + ahbcfg.b.dmaenable = core_if->dma_enable;
22437 + DWC_WRITE_REG32(&global_regs->gahbcfg, ahbcfg.d32);
22438 +
22439 + core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en;
22440 +
22441 + core_if->pti_enh_enable = core_if->core_params->pti_enable != 0;
22442 + core_if->multiproc_int_enable = core_if->core_params->mpi_enable;
22443 + DWC_PRINTF("Periodic Transfer Interrupt Enhancement - %s\n",
22444 + ((core_if->pti_enh_enable) ? "enabled" : "disabled"));
22445 + DWC_PRINTF("Multiprocessor Interrupt Enhancement - %s\n",
22446 + ((core_if->multiproc_int_enable) ? "enabled" : "disabled"));
22447 +
22448 + /*
22449 + * Program the GUSBCFG register.
22450 + */
22451 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22452 +
22453 + switch (core_if->hwcfg2.b.op_mode) {
22454 + case DWC_MODE_HNP_SRP_CAPABLE:
22455 + usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
22456 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
22457 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22458 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22459 + break;
22460 +
22461 + case DWC_MODE_SRP_ONLY_CAPABLE:
22462 + usbcfg.b.hnpcap = 0;
22463 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22464 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22465 + break;
22466 +
22467 + case DWC_MODE_NO_HNP_SRP_CAPABLE:
22468 + usbcfg.b.hnpcap = 0;
22469 + usbcfg.b.srpcap = 0;
22470 + break;
22471 +
22472 + case DWC_MODE_SRP_CAPABLE_DEVICE:
22473 + usbcfg.b.hnpcap = 0;
22474 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22475 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22476 + break;
22477 +
22478 + case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
22479 + usbcfg.b.hnpcap = 0;
22480 + usbcfg.b.srpcap = 0;
22481 + break;
22482 +
22483 + case DWC_MODE_SRP_CAPABLE_HOST:
22484 + usbcfg.b.hnpcap = 0;
22485 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22486 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22487 + break;
22488 +
22489 + case DWC_MODE_NO_SRP_CAPABLE_HOST:
22490 + usbcfg.b.hnpcap = 0;
22491 + usbcfg.b.srpcap = 0;
22492 + break;
22493 + }
22494 +
22495 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22496 +
22497 +#ifdef CONFIG_USB_DWC_OTG_LPM
22498 + if (core_if->core_params->lpm_enable) {
22499 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
22500 +
22501 + /* To enable LPM support set lpm_cap_en bit */
22502 + lpmcfg.b.lpm_cap_en = 1;
22503 +
22504 + /* Make AppL1Res ACK */
22505 + lpmcfg.b.appl_resp = 1;
22506 +
22507 + /* Retry 3 times */
22508 + lpmcfg.b.retry_count = 3;
22509 +
22510 + DWC_MODIFY_REG32(&core_if->core_global_regs->glpmcfg,
22511 + 0, lpmcfg.d32);
22512 +
22513 + }
22514 +#endif
22515 + if (core_if->core_params->ic_usb_cap) {
22516 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
22517 + gusbcfg.b.ic_usb_cap = 1;
22518 + DWC_MODIFY_REG32(&core_if->core_global_regs->gusbcfg,
22519 + 0, gusbcfg.d32);
22520 + }
22521 + {
22522 + gotgctl_data_t gotgctl = {.d32 = 0 };
22523 + gotgctl.b.otgver = core_if->core_params->otg_ver;
22524 + DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, 0,
22525 + gotgctl.d32);
22526 + /* Set OTG version supported */
22527 + core_if->otg_ver = core_if->core_params->otg_ver;
22528 + DWC_PRINTF("OTG VER PARAM: %d, OTG VER FLAG: %d\n",
22529 + core_if->core_params->otg_ver, core_if->otg_ver);
22530 + }
22531 +
22532 +
22533 + /* Enable common interrupts */
22534 + dwc_otg_enable_common_interrupts(core_if);
22535 +
22536 + /* Do device or host intialization based on mode during PCD
22537 + * and HCD initialization */
22538 + if (dwc_otg_is_host_mode(core_if)) {
22539 + DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
22540 + core_if->op_state = A_HOST;
22541 + } else {
22542 + DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
22543 + core_if->op_state = B_PERIPHERAL;
22544 +#ifdef DWC_DEVICE_ONLY
22545 + dwc_otg_core_dev_init(core_if);
22546 +#endif
22547 + }
22548 +}
22549 +
22550 +/**
22551 + * This function enables the Device mode interrupts.
22552 + *
22553 + * @param core_if Programming view of DWC_otg controller
22554 + */
22555 +void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if)
22556 +{
22557 + gintmsk_data_t intr_mask = {.d32 = 0 };
22558 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22559 +
22560 + DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
22561 +
22562 + /* Disable all interrupts. */
22563 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
22564 +
22565 + /* Clear any pending interrupts */
22566 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
22567 +
22568 + /* Enable the common interrupts */
22569 + dwc_otg_enable_common_interrupts(core_if);
22570 +
22571 + /* Enable interrupts */
22572 + intr_mask.b.usbreset = 1;
22573 + intr_mask.b.enumdone = 1;
22574 + /* Disable Disconnect interrupt in Device mode */
22575 + intr_mask.b.disconnect = 0;
22576 +
22577 + if (!core_if->multiproc_int_enable) {
22578 + intr_mask.b.inepintr = 1;
22579 + intr_mask.b.outepintr = 1;
22580 + }
22581 +
22582 + intr_mask.b.erlysuspend = 1;
22583 +
22584 + if (core_if->en_multiple_tx_fifo == 0) {
22585 + intr_mask.b.epmismatch = 1;
22586 + }
22587 +
22588 + //intr_mask.b.incomplisoout = 1;
22589 + intr_mask.b.incomplisoin = 1;
22590 +
22591 +/* Enable the ignore frame number for ISOC xfers - MAS */
22592 +/* Disable to support high bandwith ISOC transfers - manukz */
22593 +#if 0
22594 +#ifdef DWC_UTE_PER_IO
22595 + if (core_if->dma_enable) {
22596 + if (core_if->dma_desc_enable) {
22597 + dctl_data_t dctl1 = {.d32 = 0 };
22598 + dctl1.b.ifrmnum = 1;
22599 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
22600 + dctl, 0, dctl1.d32);
22601 + DWC_DEBUG("----Enabled Ignore frame number (0x%08x)",
22602 + DWC_READ_REG32(&core_if->dev_if->
22603 + dev_global_regs->dctl));
22604 + }
22605 + }
22606 +#endif
22607 +#endif
22608 +#ifdef DWC_EN_ISOC
22609 + if (core_if->dma_enable) {
22610 + if (core_if->dma_desc_enable == 0) {
22611 + if (core_if->pti_enh_enable) {
22612 + dctl_data_t dctl = {.d32 = 0 };
22613 + dctl.b.ifrmnum = 1;
22614 + DWC_MODIFY_REG32(&core_if->
22615 + dev_if->dev_global_regs->dctl,
22616 + 0, dctl.d32);
22617 + } else {
22618 + intr_mask.b.incomplisoin = 1;
22619 + intr_mask.b.incomplisoout = 1;
22620 + }
22621 + }
22622 + } else {
22623 + intr_mask.b.incomplisoin = 1;
22624 + intr_mask.b.incomplisoout = 1;
22625 + }
22626 +#endif /* DWC_EN_ISOC */
22627 +
22628 + /** @todo NGS: Should this be a module parameter? */
22629 +#ifdef USE_PERIODIC_EP
22630 + intr_mask.b.isooutdrop = 1;
22631 + intr_mask.b.eopframe = 1;
22632 + intr_mask.b.incomplisoin = 1;
22633 + intr_mask.b.incomplisoout = 1;
22634 +#endif
22635 +
22636 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
22637 +
22638 + DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
22639 + DWC_READ_REG32(&global_regs->gintmsk));
22640 +}
22641 +
22642 +/**
22643 + * This function initializes the DWC_otg controller registers for
22644 + * device mode.
22645 + *
22646 + * @param core_if Programming view of DWC_otg controller
22647 + *
22648 + */
22649 +void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if)
22650 +{
22651 + int i;
22652 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22653 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
22654 + dwc_otg_core_params_t *params = core_if->core_params;
22655 + dcfg_data_t dcfg = {.d32 = 0 };
22656 + depctl_data_t diepctl = {.d32 = 0 };
22657 + grstctl_t resetctl = {.d32 = 0 };
22658 + uint32_t rx_fifo_size;
22659 + fifosize_data_t nptxfifosize;
22660 + fifosize_data_t txfifosize;
22661 + dthrctl_data_t dthrctl;
22662 + fifosize_data_t ptxfifosize;
22663 + uint16_t rxfsiz, nptxfsiz;
22664 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
22665 + hwcfg3_data_t hwcfg3 = {.d32 = 0 };
22666 +
22667 + /* Restart the Phy Clock */
22668 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
22669 +
22670 + /* Device configuration register */
22671 + init_devspd(core_if);
22672 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
22673 + dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0;
22674 + dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
22675 + /* Enable Device OUT NAK in case of DDMA mode*/
22676 + if (core_if->core_params->dev_out_nak) {
22677 + dcfg.b.endevoutnak = 1;
22678 + }
22679 +
22680 + if (core_if->core_params->cont_on_bna) {
22681 + dctl_data_t dctl = {.d32 = 0 };
22682 + dctl.b.encontonbna = 1;
22683 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
22684 + }
22685 +
22686 +
22687 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
22688 +
22689 + /* Configure data FIFO sizes */
22690 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
22691 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
22692 + core_if->total_fifo_size);
22693 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
22694 + params->dev_rx_fifo_size);
22695 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
22696 + params->dev_nperio_tx_fifo_size);
22697 +
22698 + /* Rx FIFO */
22699 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
22700 + DWC_READ_REG32(&global_regs->grxfsiz));
22701 +
22702 +#ifdef DWC_UTE_CFI
22703 + core_if->pwron_rxfsiz = DWC_READ_REG32(&global_regs->grxfsiz);
22704 + core_if->init_rxfsiz = params->dev_rx_fifo_size;
22705 +#endif
22706 + rx_fifo_size = params->dev_rx_fifo_size;
22707 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
22708 +
22709 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
22710 + DWC_READ_REG32(&global_regs->grxfsiz));
22711 +
22712 + /** Set Periodic Tx FIFO Mask all bits 0 */
22713 + core_if->p_tx_msk = 0;
22714 +
22715 + /** Set Tx FIFO Mask all bits 0 */
22716 + core_if->tx_msk = 0;
22717 +
22718 + if (core_if->en_multiple_tx_fifo == 0) {
22719 + /* Non-periodic Tx FIFO */
22720 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
22721 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22722 +
22723 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
22724 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
22725 +
22726 + DWC_WRITE_REG32(&global_regs->gnptxfsiz,
22727 + nptxfifosize.d32);
22728 +
22729 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
22730 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22731 +
22732 + /**@todo NGS: Fix Periodic FIFO Sizing! */
22733 + /*
22734 + * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
22735 + * Indexes of the FIFO size module parameters in the
22736 + * dev_perio_tx_fifo_size array and the FIFO size registers in
22737 + * the dptxfsiz array run from 0 to 14.
22738 + */
22739 + /** @todo Finish debug of this */
22740 + ptxfifosize.b.startaddr =
22741 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
22742 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
22743 + ptxfifosize.b.depth =
22744 + params->dev_perio_tx_fifo_size[i];
22745 + DWC_DEBUGPL(DBG_CIL,
22746 + "initial dtxfsiz[%d]=%08x\n", i,
22747 + DWC_READ_REG32(&global_regs->dtxfsiz
22748 + [i]));
22749 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
22750 + ptxfifosize.d32);
22751 + DWC_DEBUGPL(DBG_CIL, "new dtxfsiz[%d]=%08x\n",
22752 + i,
22753 + DWC_READ_REG32(&global_regs->dtxfsiz
22754 + [i]));
22755 + ptxfifosize.b.startaddr += ptxfifosize.b.depth;
22756 + }
22757 + } else {
22758 + /*
22759 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
22760 + * Indexes of the FIFO size module parameters in the
22761 + * dev_tx_fifo_size array and the FIFO size registers in
22762 + * the dtxfsiz array run from 0 to 14.
22763 + */
22764 +
22765 + /* Non-periodic Tx FIFO */
22766 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
22767 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22768 +
22769 +#ifdef DWC_UTE_CFI
22770 + core_if->pwron_gnptxfsiz =
22771 + (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
22772 + core_if->init_gnptxfsiz =
22773 + params->dev_nperio_tx_fifo_size;
22774 +#endif
22775 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
22776 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
22777 +
22778 + DWC_WRITE_REG32(&global_regs->gnptxfsiz,
22779 + nptxfifosize.d32);
22780 +
22781 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
22782 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22783 +
22784 + txfifosize.b.startaddr =
22785 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
22786 +
22787 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
22788 +
22789 + txfifosize.b.depth =
22790 + params->dev_tx_fifo_size[i];
22791 +
22792 + DWC_DEBUGPL(DBG_CIL,
22793 + "initial dtxfsiz[%d]=%08x\n",
22794 + i,
22795 + DWC_READ_REG32(&global_regs->dtxfsiz
22796 + [i]));
22797 +
22798 +#ifdef DWC_UTE_CFI
22799 + core_if->pwron_txfsiz[i] =
22800 + (DWC_READ_REG32
22801 + (&global_regs->dtxfsiz[i]) >> 16);
22802 + core_if->init_txfsiz[i] =
22803 + params->dev_tx_fifo_size[i];
22804 +#endif
22805 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
22806 + txfifosize.d32);
22807 +
22808 + DWC_DEBUGPL(DBG_CIL,
22809 + "new dtxfsiz[%d]=%08x\n",
22810 + i,
22811 + DWC_READ_REG32(&global_regs->dtxfsiz
22812 + [i]));
22813 +
22814 + txfifosize.b.startaddr += txfifosize.b.depth;
22815 + }
22816 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
22817 + /* Calculating DFIFOCFG for Device mode to include RxFIFO and NPTXFIFO */
22818 + gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
22819 + hwcfg3.d32 = DWC_READ_REG32(&global_regs->ghwcfg3);
22820 + gdfifocfg.b.gdfifocfg = (DWC_READ_REG32(&global_regs->ghwcfg3) >> 16);
22821 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
22822 + rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
22823 + nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
22824 + gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz;
22825 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
22826 + }
22827 + }
22828 +
22829 + /* Flush the FIFOs */
22830 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
22831 + dwc_otg_flush_rx_fifo(core_if);
22832 +
22833 + /* Flush the Learning Queue. */
22834 + resetctl.b.intknqflsh = 1;
22835 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
22836 +
22837 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
22838 + core_if->start_predict = 0;
22839 + for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
22840 + core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
22841 + }
22842 + core_if->nextep_seq[0] = 0;
22843 + core_if->first_in_nextep_seq = 0;
22844 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
22845 + diepctl.b.nextep = 0;
22846 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
22847 +
22848 + /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
22849 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
22850 + dcfg.b.epmscnt = 2;
22851 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
22852 +
22853 + DWC_DEBUGPL(DBG_CILV,"%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
22854 + __func__, core_if->first_in_nextep_seq);
22855 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
22856 + DWC_DEBUGPL(DBG_CILV, "%2d ", core_if->nextep_seq[i]);
22857 + }
22858 + DWC_DEBUGPL(DBG_CILV,"\n");
22859 + }
22860 +
22861 + /* Clear all pending Device Interrupts */
22862 + /** @todo - if the condition needed to be checked
22863 + * or in any case all pending interrutps should be cleared?
22864 + */
22865 + if (core_if->multiproc_int_enable) {
22866 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
22867 + DWC_WRITE_REG32(&dev_if->
22868 + dev_global_regs->diepeachintmsk[i], 0);
22869 + }
22870 + }
22871 +
22872 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
22873 + DWC_WRITE_REG32(&dev_if->
22874 + dev_global_regs->doepeachintmsk[i], 0);
22875 + }
22876 +
22877 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF);
22878 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk, 0);
22879 + } else {
22880 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, 0);
22881 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, 0);
22882 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
22883 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk, 0);
22884 + }
22885 +
22886 + for (i = 0; i <= dev_if->num_in_eps; i++) {
22887 + depctl_data_t depctl;
22888 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
22889 + if (depctl.b.epena) {
22890 + depctl.d32 = 0;
22891 + depctl.b.epdis = 1;
22892 + depctl.b.snak = 1;
22893 + } else {
22894 + depctl.d32 = 0;
22895 + }
22896 +
22897 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
22898 +
22899 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
22900 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, 0);
22901 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
22902 + }
22903 +
22904 + for (i = 0; i <= dev_if->num_out_eps; i++) {
22905 + depctl_data_t depctl;
22906 + depctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
22907 + if (depctl.b.epena) {
22908 + dctl_data_t dctl = {.d32 = 0 };
22909 + gintmsk_data_t gintsts = {.d32 = 0 };
22910 + doepint_data_t doepint = {.d32 = 0 };
22911 + dctl.b.sgoutnak = 1;
22912 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
22913 + do {
22914 + dwc_udelay(10);
22915 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
22916 + } while (!gintsts.b.goutnakeff);
22917 + gintsts.d32 = 0;
22918 + gintsts.b.goutnakeff = 1;
22919 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
22920 +
22921 + depctl.d32 = 0;
22922 + depctl.b.epdis = 1;
22923 + depctl.b.snak = 1;
22924 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepctl, depctl.d32);
22925 + do {
22926 + dwc_udelay(10);
22927 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
22928 + out_ep_regs[i]->doepint);
22929 + } while (!doepint.b.epdisabled);
22930 +
22931 + doepint.b.epdisabled = 1;
22932 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepint, doepint.d32);
22933 +
22934 + dctl.d32 = 0;
22935 + dctl.b.cgoutnak = 1;
22936 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
22937 + } else {
22938 + depctl.d32 = 0;
22939 + }
22940 +
22941 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
22942 +
22943 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
22944 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepdma, 0);
22945 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
22946 + }
22947 +
22948 + if (core_if->en_multiple_tx_fifo && core_if->dma_enable) {
22949 + dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1;
22950 + dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1;
22951 + dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1;
22952 +
22953 + dev_if->rx_thr_length = params->rx_thr_length;
22954 + dev_if->tx_thr_length = params->tx_thr_length;
22955 +
22956 + dev_if->setup_desc_index = 0;
22957 +
22958 + dthrctl.d32 = 0;
22959 + dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
22960 + dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
22961 + dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
22962 + dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
22963 + dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
22964 + dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio;
22965 +
22966 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dtknqr3_dthrctl,
22967 + dthrctl.d32);
22968 +
22969 + DWC_DEBUGPL(DBG_CIL,
22970 + "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
22971 + dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en,
22972 + dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len,
22973 + dthrctl.b.rx_thr_len);
22974 +
22975 + }
22976 +
22977 + dwc_otg_enable_device_interrupts(core_if);
22978 +
22979 + {
22980 + diepmsk_data_t msk = {.d32 = 0 };
22981 + msk.b.txfifoundrn = 1;
22982 + if (core_if->multiproc_int_enable) {
22983 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->
22984 + diepeachintmsk[0], msk.d32, msk.d32);
22985 + } else {
22986 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk,
22987 + msk.d32, msk.d32);
22988 + }
22989 + }
22990 +
22991 + if (core_if->multiproc_int_enable) {
22992 + /* Set NAK on Babble */
22993 + dctl_data_t dctl = {.d32 = 0 };
22994 + dctl.b.nakonbble = 1;
22995 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
22996 + }
22997 +
22998 + if (core_if->snpsid >= OTG_CORE_REV_2_94a) {
22999 + dctl_data_t dctl = {.d32 = 0 };
23000 + dctl.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
23001 + dctl.b.sftdiscon = 0;
23002 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl, dctl.d32);
23003 + }
23004 +}
23005 +
23006 +/**
23007 + * This function enables the Host mode interrupts.
23008 + *
23009 + * @param core_if Programming view of DWC_otg controller
23010 + */
23011 +void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if)
23012 +{
23013 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
23014 + gintmsk_data_t intr_mask = {.d32 = 0 };
23015 +
23016 + DWC_DEBUGPL(DBG_CIL, "%s(%p)\n", __func__, core_if);
23017 +
23018 + /* Disable all interrupts. */
23019 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
23020 +
23021 + /* Clear any pending interrupts. */
23022 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
23023 +
23024 + /* Enable the common interrupts */
23025 + dwc_otg_enable_common_interrupts(core_if);
23026 +
23027 + /*
23028 + * Enable host mode interrupts without disturbing common
23029 + * interrupts.
23030 + */
23031 +
23032 + intr_mask.b.disconnect = 1;
23033 + intr_mask.b.portintr = 1;
23034 + intr_mask.b.hcintr = 1;
23035 +
23036 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
23037 +}
23038 +
23039 +/**
23040 + * This function disables the Host Mode interrupts.
23041 + *
23042 + * @param core_if Programming view of DWC_otg controller
23043 + */
23044 +void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if)
23045 +{
23046 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
23047 + gintmsk_data_t intr_mask = {.d32 = 0 };
23048 +
23049 + DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
23050 +
23051 + /*
23052 + * Disable host mode interrupts without disturbing common
23053 + * interrupts.
23054 + */
23055 + intr_mask.b.sofintr = 1;
23056 + intr_mask.b.portintr = 1;
23057 + intr_mask.b.hcintr = 1;
23058 + intr_mask.b.ptxfempty = 1;
23059 + intr_mask.b.nptxfempty = 1;
23060 +
23061 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, 0);
23062 +}
23063 +
23064 +/**
23065 + * This function initializes the DWC_otg controller registers for
23066 + * host mode.
23067 + *
23068 + * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
23069 + * request queues. Host channels are reset to ensure that they are ready for
23070 + * performing transfers.
23071 + *
23072 + * @param core_if Programming view of DWC_otg controller
23073 + *
23074 + */
23075 +void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
23076 +{
23077 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
23078 + dwc_otg_host_if_t *host_if = core_if->host_if;
23079 + dwc_otg_core_params_t *params = core_if->core_params;
23080 + hprt0_data_t hprt0 = {.d32 = 0 };
23081 + fifosize_data_t nptxfifosize;
23082 + fifosize_data_t ptxfifosize;
23083 + uint16_t rxfsiz, nptxfsiz, hptxfsiz;
23084 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
23085 + int i;
23086 + hcchar_data_t hcchar;
23087 + hcfg_data_t hcfg;
23088 + hfir_data_t hfir;
23089 + dwc_otg_hc_regs_t *hc_regs;
23090 + int num_channels;
23091 + gotgctl_data_t gotgctl = {.d32 = 0 };
23092 +
23093 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
23094 +
23095 + /* Restart the Phy Clock */
23096 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
23097 +
23098 + /* Initialize Host Configuration Register */
23099 + init_fslspclksel(core_if);
23100 + if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
23101 + hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
23102 + hcfg.b.fslssupp = 1;
23103 + DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
23104 +
23105 + }
23106 +
23107 + /* This bit allows dynamic reloading of the HFIR register
23108 + * during runtime. This bit needs to be programmed during
23109 + * initial configuration and its value must not be changed
23110 + * during runtime.*/
23111 + if (core_if->core_params->reload_ctl == 1) {
23112 + hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
23113 + hfir.b.hfirrldctrl = 1;
23114 + DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
23115 + }
23116 +
23117 + if (core_if->core_params->dma_desc_enable) {
23118 + uint8_t op_mode = core_if->hwcfg2.b.op_mode;
23119 + if (!
23120 + (core_if->hwcfg4.b.desc_dma
23121 + && (core_if->snpsid >= OTG_CORE_REV_2_90a)
23122 + && ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
23123 + || (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
23124 + || (op_mode ==
23125 + DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG)
23126 + || (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)
23127 + || (op_mode ==
23128 + DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) {
23129 +
23130 + DWC_ERROR("Host can't operate in Descriptor DMA mode.\n"
23131 + "Either core version is below 2.90a or "
23132 + "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n"
23133 + "To run the driver in Buffer DMA host mode set dma_desc_enable "
23134 + "module parameter to 0.\n");
23135 + return;
23136 + }
23137 + hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
23138 + hcfg.b.descdma = 1;
23139 + DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
23140 + }
23141 +
23142 + /* Configure data FIFO sizes */
23143 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
23144 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
23145 + core_if->total_fifo_size);
23146 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
23147 + params->host_rx_fifo_size);
23148 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
23149 + params->host_nperio_tx_fifo_size);
23150 + DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
23151 + params->host_perio_tx_fifo_size);
23152 +
23153 + /* Rx FIFO */
23154 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
23155 + DWC_READ_REG32(&global_regs->grxfsiz));
23156 + DWC_WRITE_REG32(&global_regs->grxfsiz,
23157 + params->host_rx_fifo_size);
23158 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
23159 + DWC_READ_REG32(&global_regs->grxfsiz));
23160 +
23161 + /* Non-periodic Tx FIFO */
23162 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
23163 + DWC_READ_REG32(&global_regs->gnptxfsiz));
23164 + nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
23165 + nptxfifosize.b.startaddr = params->host_rx_fifo_size;
23166 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
23167 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
23168 + DWC_READ_REG32(&global_regs->gnptxfsiz));
23169 +
23170 + /* Periodic Tx FIFO */
23171 + DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
23172 + DWC_READ_REG32(&global_regs->hptxfsiz));
23173 + ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
23174 + ptxfifosize.b.startaddr =
23175 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
23176 + DWC_WRITE_REG32(&global_regs->hptxfsiz, ptxfifosize.d32);
23177 + DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
23178 + DWC_READ_REG32(&global_regs->hptxfsiz));
23179 +
23180 + if (core_if->en_multiple_tx_fifo
23181 + && core_if->snpsid <= OTG_CORE_REV_2_94a) {
23182 + /* Global DFIFOCFG calculation for Host mode - include RxFIFO, NPTXFIFO and HPTXFIFO */
23183 + gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
23184 + rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
23185 + nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
23186 + hptxfsiz = (DWC_READ_REG32(&global_regs->hptxfsiz) >> 16);
23187 + gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz + hptxfsiz;
23188 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
23189 + }
23190 + }
23191 +
23192 + /* TODO - check this */
23193 + /* Clear Host Set HNP Enable in the OTG Control Register */
23194 + gotgctl.b.hstsethnpen = 1;
23195 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
23196 + /* Make sure the FIFOs are flushed. */
23197 + dwc_otg_flush_tx_fifo(core_if, 0x10 /* all TX FIFOs */ );
23198 + dwc_otg_flush_rx_fifo(core_if);
23199 +
23200 + /* Clear Host Set HNP Enable in the OTG Control Register */
23201 + gotgctl.b.hstsethnpen = 1;
23202 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
23203 +
23204 + if (!core_if->core_params->dma_desc_enable) {
23205 + /* Flush out any leftover queued requests. */
23206 + num_channels = core_if->core_params->host_channels;
23207 +
23208 + for (i = 0; i < num_channels; i++) {
23209 + hc_regs = core_if->host_if->hc_regs[i];
23210 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23211 + hcchar.b.chen = 0;
23212 + hcchar.b.chdis = 1;
23213 + hcchar.b.epdir = 0;
23214 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23215 + }
23216 +
23217 + /* Halt all channels to put them into a known state. */
23218 + for (i = 0; i < num_channels; i++) {
23219 + int count = 0;
23220 + hc_regs = core_if->host_if->hc_regs[i];
23221 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23222 + hcchar.b.chen = 1;
23223 + hcchar.b.chdis = 1;
23224 + hcchar.b.epdir = 0;
23225 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23226 + DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d regs %p\n", __func__, i, hc_regs);
23227 + do {
23228 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23229 + if (++count > 1000) {
23230 + DWC_ERROR
23231 + ("%s: Unable to clear halt on channel %d (timeout HCCHAR 0x%X @%p)\n",
23232 + __func__, i, hcchar.d32, &hc_regs->hcchar);
23233 + break;
23234 + }
23235 + dwc_udelay(1);
23236 + } while (hcchar.b.chen);
23237 + }
23238 + }
23239 +
23240 + /* Turn on the vbus power. */
23241 + DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state);
23242 + if (core_if->op_state == A_HOST) {
23243 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
23244 + DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
23245 + if (hprt0.b.prtpwr == 0) {
23246 + hprt0.b.prtpwr = 1;
23247 + DWC_WRITE_REG32(host_if->hprt0, hprt0.d32);
23248 + }
23249 + }
23250 +
23251 + dwc_otg_enable_host_interrupts(core_if);
23252 +}
23253 +
23254 +/**
23255 + * Prepares a host channel for transferring packets to/from a specific
23256 + * endpoint. The HCCHARn register is set up with the characteristics specified
23257 + * in _hc. Host channel interrupts that may need to be serviced while this
23258 + * transfer is in progress are enabled.
23259 + *
23260 + * @param core_if Programming view of DWC_otg controller
23261 + * @param hc Information needed to initialize the host channel
23262 + */
23263 +void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23264 +{
23265 + uint32_t intr_enable;
23266 + hcintmsk_data_t hc_intr_mask;
23267 + gintmsk_data_t gintmsk = {.d32 = 0 };
23268 + hcchar_data_t hcchar;
23269 + hcsplt_data_t hcsplt;
23270 +
23271 + uint8_t hc_num = hc->hc_num;
23272 + dwc_otg_host_if_t *host_if = core_if->host_if;
23273 + dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
23274 +
23275 + /* Clear old interrupt conditions for this host channel. */
23276 + hc_intr_mask.d32 = 0xFFFFFFFF;
23277 + hc_intr_mask.b.reserved14_31 = 0;
23278 + DWC_WRITE_REG32(&hc_regs->hcint, hc_intr_mask.d32);
23279 +
23280 + /* Enable channel interrupts required for this transfer. */
23281 + hc_intr_mask.d32 = 0;
23282 + hc_intr_mask.b.chhltd = 1;
23283 + if (core_if->dma_enable) {
23284 + /* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */
23285 + if (!core_if->dma_desc_enable)
23286 + hc_intr_mask.b.ahberr = 1;
23287 + else {
23288 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23289 + hc_intr_mask.b.xfercompl = 1;
23290 + }
23291 +
23292 + if (hc->error_state && !hc->do_split &&
23293 + hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
23294 + hc_intr_mask.b.ack = 1;
23295 + if (hc->ep_is_in) {
23296 + hc_intr_mask.b.datatglerr = 1;
23297 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
23298 + hc_intr_mask.b.nak = 1;
23299 + }
23300 + }
23301 + }
23302 + } else {
23303 + switch (hc->ep_type) {
23304 + case DWC_OTG_EP_TYPE_CONTROL:
23305 + case DWC_OTG_EP_TYPE_BULK:
23306 + hc_intr_mask.b.xfercompl = 1;
23307 + hc_intr_mask.b.stall = 1;
23308 + hc_intr_mask.b.xacterr = 1;
23309 + hc_intr_mask.b.datatglerr = 1;
23310 + if (hc->ep_is_in) {
23311 + hc_intr_mask.b.bblerr = 1;
23312 + } else {
23313 + hc_intr_mask.b.nak = 1;
23314 + hc_intr_mask.b.nyet = 1;
23315 + if (hc->do_ping) {
23316 + hc_intr_mask.b.ack = 1;
23317 + }
23318 + }
23319 +
23320 + if (hc->do_split) {
23321 + hc_intr_mask.b.nak = 1;
23322 + if (hc->complete_split) {
23323 + hc_intr_mask.b.nyet = 1;
23324 + } else {
23325 + hc_intr_mask.b.ack = 1;
23326 + }
23327 + }
23328 +
23329 + if (hc->error_state) {
23330 + hc_intr_mask.b.ack = 1;
23331 + }
23332 + break;
23333 + case DWC_OTG_EP_TYPE_INTR:
23334 + hc_intr_mask.b.xfercompl = 1;
23335 + hc_intr_mask.b.nak = 1;
23336 + hc_intr_mask.b.stall = 1;
23337 + hc_intr_mask.b.xacterr = 1;
23338 + hc_intr_mask.b.datatglerr = 1;
23339 + hc_intr_mask.b.frmovrun = 1;
23340 +
23341 + if (hc->ep_is_in) {
23342 + hc_intr_mask.b.bblerr = 1;
23343 + }
23344 + if (hc->error_state) {
23345 + hc_intr_mask.b.ack = 1;
23346 + }
23347 + if (hc->do_split) {
23348 + if (hc->complete_split) {
23349 + hc_intr_mask.b.nyet = 1;
23350 + } else {
23351 + hc_intr_mask.b.ack = 1;
23352 + }
23353 + }
23354 + break;
23355 + case DWC_OTG_EP_TYPE_ISOC:
23356 + hc_intr_mask.b.xfercompl = 1;
23357 + hc_intr_mask.b.frmovrun = 1;
23358 + hc_intr_mask.b.ack = 1;
23359 +
23360 + if (hc->ep_is_in) {
23361 + hc_intr_mask.b.xacterr = 1;
23362 + hc_intr_mask.b.bblerr = 1;
23363 + }
23364 + break;
23365 + }
23366 + }
23367 + DWC_WRITE_REG32(&hc_regs->hcintmsk, hc_intr_mask.d32);
23368 +
23369 + /* Enable the top level host channel interrupt. */
23370 + intr_enable = (1 << hc_num);
23371 + DWC_MODIFY_REG32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
23372 +
23373 + /* Make sure host channel interrupts are enabled. */
23374 + gintmsk.b.hcintr = 1;
23375 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
23376 +
23377 + /*
23378 + * Program the HCCHARn register with the endpoint characteristics for
23379 + * the current transfer.
23380 + */
23381 + hcchar.d32 = 0;
23382 + hcchar.b.devaddr = hc->dev_addr;
23383 + hcchar.b.epnum = hc->ep_num;
23384 + hcchar.b.epdir = hc->ep_is_in;
23385 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
23386 + hcchar.b.eptype = hc->ep_type;
23387 + hcchar.b.mps = hc->max_packet;
23388 +
23389 + DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
23390 +
23391 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d, Dev Addr %d, EP #%d\n",
23392 + __func__, hc->hc_num, hcchar.b.devaddr, hcchar.b.epnum);
23393 + DWC_DEBUGPL(DBG_HCDV, " Is In %d, Is Low Speed %d, EP Type %d, "
23394 + "Max Pkt %d, Multi Cnt %d\n",
23395 + hcchar.b.epdir, hcchar.b.lspddev, hcchar.b.eptype,
23396 + hcchar.b.mps, hcchar.b.multicnt);
23397 +
23398 + /*
23399 + * Program the HCSPLIT register for SPLITs
23400 + */
23401 + hcsplt.d32 = 0;
23402 + if (hc->do_split) {
23403 + DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
23404 + hc->hc_num,
23405 + hc->complete_split ? "CSPLIT" : "SSPLIT");
23406 + hcsplt.b.compsplt = hc->complete_split;
23407 + hcsplt.b.xactpos = hc->xact_pos;
23408 + hcsplt.b.hubaddr = hc->hub_addr;
23409 + hcsplt.b.prtaddr = hc->port_addr;
23410 + DWC_DEBUGPL(DBG_HCDV, "\t comp split %d\n", hc->complete_split);
23411 + DWC_DEBUGPL(DBG_HCDV, "\t xact pos %d\n", hc->xact_pos);
23412 + DWC_DEBUGPL(DBG_HCDV, "\t hub addr %d\n", hc->hub_addr);
23413 + DWC_DEBUGPL(DBG_HCDV, "\t port addr %d\n", hc->port_addr);
23414 + DWC_DEBUGPL(DBG_HCDV, "\t is_in %d\n", hc->ep_is_in);
23415 + DWC_DEBUGPL(DBG_HCDV, "\t Max Pkt: %d\n", hcchar.b.mps);
23416 + DWC_DEBUGPL(DBG_HCDV, "\t xferlen: %d\n", hc->xfer_len);
23417 + }
23418 + DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
23419 +
23420 +}
23421 +
23422 +/**
23423 + * Attempts to halt a host channel. This function should only be called in
23424 + * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
23425 + * normal circumstances in DMA mode, the controller halts the channel when the
23426 + * transfer is complete or a condition occurs that requires application
23427 + * intervention.
23428 + *
23429 + * In slave mode, checks for a free request queue entry, then sets the Channel
23430 + * Enable and Channel Disable bits of the Host Channel Characteristics
23431 + * register of the specified channel to intiate the halt. If there is no free
23432 + * request queue entry, sets only the Channel Disable bit of the HCCHARn
23433 + * register to flush requests for this channel. In the latter case, sets a
23434 + * flag to indicate that the host channel needs to be halted when a request
23435 + * queue slot is open.
23436 + *
23437 + * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
23438 + * HCCHARn register. The controller ensures there is space in the request
23439 + * queue before submitting the halt request.
23440 + *
23441 + * Some time may elapse before the core flushes any posted requests for this
23442 + * host channel and halts. The Channel Halted interrupt handler completes the
23443 + * deactivation of the host channel.
23444 + *
23445 + * @param core_if Controller register interface.
23446 + * @param hc Host channel to halt.
23447 + * @param halt_status Reason for halting the channel.
23448 + */
23449 +void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if,
23450 + dwc_hc_t * hc, dwc_otg_halt_status_e halt_status)
23451 +{
23452 + gnptxsts_data_t nptxsts;
23453 + hptxsts_data_t hptxsts;
23454 + hcchar_data_t hcchar;
23455 + dwc_otg_hc_regs_t *hc_regs;
23456 + dwc_otg_core_global_regs_t *global_regs;
23457 + dwc_otg_host_global_regs_t *host_global_regs;
23458 +
23459 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23460 + global_regs = core_if->core_global_regs;
23461 + host_global_regs = core_if->host_if->host_global_regs;
23462 +
23463 + DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS),
23464 + "halt_status = %d\n", halt_status);
23465 +
23466 + if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
23467 + halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
23468 + /*
23469 + * Disable all channel interrupts except Ch Halted. The QTD
23470 + * and QH state associated with this transfer has been cleared
23471 + * (in the case of URB_DEQUEUE), so the channel needs to be
23472 + * shut down carefully to prevent crashes.
23473 + */
23474 + hcintmsk_data_t hcintmsk;
23475 + hcintmsk.d32 = 0;
23476 + hcintmsk.b.chhltd = 1;
23477 + DWC_WRITE_REG32(&hc_regs->hcintmsk, hcintmsk.d32);
23478 +
23479 + /*
23480 + * Make sure no other interrupts besides halt are currently
23481 + * pending. Handling another interrupt could cause a crash due
23482 + * to the QTD and QH state.
23483 + */
23484 + DWC_WRITE_REG32(&hc_regs->hcint, ~hcintmsk.d32);
23485 +
23486 + /*
23487 + * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
23488 + * even if the channel was already halted for some other
23489 + * reason.
23490 + */
23491 + hc->halt_status = halt_status;
23492 +
23493 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23494 + if (hcchar.b.chen == 0) {
23495 + /*
23496 + * The channel is either already halted or it hasn't
23497 + * started yet. In DMA mode, the transfer may halt if
23498 + * it finishes normally or a condition occurs that
23499 + * requires driver intervention. Don't want to halt
23500 + * the channel again. In either Slave or DMA mode,
23501 + * it's possible that the transfer has been assigned
23502 + * to a channel, but not started yet when an URB is
23503 + * dequeued. Don't want to halt a channel that hasn't
23504 + * started yet.
23505 + */
23506 + return;
23507 + }
23508 + }
23509 + if (hc->halt_pending) {
23510 + /*
23511 + * A halt has already been issued for this channel. This might
23512 + * happen when a transfer is aborted by a higher level in
23513 + * the stack.
23514 + */
23515 +#ifdef DEBUG
23516 + DWC_PRINTF
23517 + ("*** %s: Channel %d, _hc->halt_pending already set ***\n",
23518 + __func__, hc->hc_num);
23519 +
23520 +#endif
23521 + return;
23522 + }
23523 +
23524 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23525 +
23526 + /* No need to set the bit in DDMA for disabling the channel */
23527 + //TODO check it everywhere channel is disabled
23528 + if (!core_if->core_params->dma_desc_enable)
23529 + hcchar.b.chen = 1;
23530 + hcchar.b.chdis = 1;
23531 +
23532 + if (!core_if->dma_enable) {
23533 + /* Check for space in the request queue to issue the halt. */
23534 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
23535 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
23536 + nptxsts.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
23537 + if (nptxsts.b.nptxqspcavail == 0) {
23538 + hcchar.b.chen = 0;
23539 + }
23540 + } else {
23541 + hptxsts.d32 =
23542 + DWC_READ_REG32(&host_global_regs->hptxsts);
23543 + if ((hptxsts.b.ptxqspcavail == 0)
23544 + || (core_if->queuing_high_bandwidth)) {
23545 + hcchar.b.chen = 0;
23546 + }
23547 + }
23548 + }
23549 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23550 +
23551 + hc->halt_status = halt_status;
23552 +
23553 + if (hcchar.b.chen) {
23554 + hc->halt_pending = 1;
23555 + hc->halt_on_queue = 0;
23556 + } else {
23557 + hc->halt_on_queue = 1;
23558 + }
23559 +
23560 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23561 + DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32);
23562 + DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", hc->halt_pending);
23563 + DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", hc->halt_on_queue);
23564 + DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", hc->halt_status);
23565 +
23566 + return;
23567 +}
23568 +
23569 +/**
23570 + * Clears the transfer state for a host channel. This function is normally
23571 + * called after a transfer is done and the host channel is being released.
23572 + *
23573 + * @param core_if Programming view of DWC_otg controller.
23574 + * @param hc Identifies the host channel to clean up.
23575 + */
23576 +void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23577 +{
23578 + dwc_otg_hc_regs_t *hc_regs;
23579 +
23580 + hc->xfer_started = 0;
23581 +
23582 + /*
23583 + * Clear channel interrupt enables and any unhandled channel interrupt
23584 + * conditions.
23585 + */
23586 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23587 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0);
23588 + DWC_WRITE_REG32(&hc_regs->hcint, 0xFFFFFFFF);
23589 +#ifdef DEBUG
23590 + DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]);
23591 +#endif
23592 +}
23593 +
23594 +/**
23595 + * Sets the channel property that indicates in which frame a periodic transfer
23596 + * should occur. This is always set to the _next_ frame. This function has no
23597 + * effect on non-periodic transfers.
23598 + *
23599 + * @param core_if Programming view of DWC_otg controller.
23600 + * @param hc Identifies the host channel to set up and its properties.
23601 + * @param hcchar Current value of the HCCHAR register for the specified host
23602 + * channel.
23603 + */
23604 +static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if,
23605 + dwc_hc_t * hc, hcchar_data_t * hcchar)
23606 +{
23607 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23608 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23609 + hfnum_data_t hfnum;
23610 + hfnum.d32 =
23611 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hfnum);
23612 +
23613 + /* 1 if _next_ frame is odd, 0 if it's even */
23614 + hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
23615 +#ifdef DEBUG
23616 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
23617 + && !hc->complete_split) {
23618 + switch (hfnum.b.frnum & 0x7) {
23619 + case 7:
23620 + core_if->hfnum_7_samples++;
23621 + core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
23622 + break;
23623 + case 0:
23624 + core_if->hfnum_0_samples++;
23625 + core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
23626 + break;
23627 + default:
23628 + core_if->hfnum_other_samples++;
23629 + core_if->hfnum_other_frrem_accum +=
23630 + hfnum.b.frrem;
23631 + break;
23632 + }
23633 + }
23634 +#endif
23635 + }
23636 +}
23637 +
23638 +#ifdef DEBUG
23639 +void hc_xfer_timeout(void *ptr)
23640 +{
23641 + hc_xfer_info_t *xfer_info = NULL;
23642 + int hc_num = 0;
23643 +
23644 + if (ptr)
23645 + xfer_info = (hc_xfer_info_t *) ptr;
23646 +
23647 + if (!xfer_info->hc) {
23648 + DWC_ERROR("xfer_info->hc = %p\n", xfer_info->hc);
23649 + return;
23650 + }
23651 +
23652 + hc_num = xfer_info->hc->hc_num;
23653 + DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
23654 + DWC_WARN(" start_hcchar_val 0x%08x\n",
23655 + xfer_info->core_if->start_hcchar_val[hc_num]);
23656 +}
23657 +#endif
23658 +
23659 +void ep_xfer_timeout(void *ptr)
23660 +{
23661 + ep_xfer_info_t *xfer_info = NULL;
23662 + int ep_num = 0;
23663 + dctl_data_t dctl = {.d32 = 0 };
23664 + gintsts_data_t gintsts = {.d32 = 0 };
23665 + gintmsk_data_t gintmsk = {.d32 = 0 };
23666 +
23667 + if (ptr)
23668 + xfer_info = (ep_xfer_info_t *) ptr;
23669 +
23670 + if (!xfer_info->ep) {
23671 + DWC_ERROR("xfer_info->ep = %p\n", xfer_info->ep);
23672 + return;
23673 + }
23674 +
23675 + ep_num = xfer_info->ep->num;
23676 + DWC_WARN("%s: timeout on endpoit %d\n", __func__, ep_num);
23677 + /* Put the sate to 2 as it was time outed */
23678 + xfer_info->state = 2;
23679 +
23680 + dctl.d32 =
23681 + DWC_READ_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl);
23682 + gintsts.d32 =
23683 + DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintsts);
23684 + gintmsk.d32 =
23685 + DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintmsk);
23686 +
23687 + if (!gintmsk.b.goutnakeff) {
23688 + /* Unmask it */
23689 + gintmsk.b.goutnakeff = 1;
23690 + DWC_WRITE_REG32(&xfer_info->core_if->core_global_regs->gintmsk,
23691 + gintmsk.d32);
23692 +
23693 + }
23694 +
23695 + if (!gintsts.b.goutnakeff) {
23696 + dctl.b.sgoutnak = 1;
23697 + }
23698 + DWC_WRITE_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl,
23699 + dctl.d32);
23700 +
23701 +}
23702 +
23703 +void set_pid_isoc(dwc_hc_t * hc)
23704 +{
23705 + /* Set up the initial PID for the transfer. */
23706 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
23707 + if (hc->ep_is_in) {
23708 + if (hc->multi_count == 1) {
23709 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23710 + } else if (hc->multi_count == 2) {
23711 + hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
23712 + } else {
23713 + hc->data_pid_start = DWC_OTG_HC_PID_DATA2;
23714 + }
23715 + } else {
23716 + if (hc->multi_count == 1) {
23717 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23718 + } else {
23719 + hc->data_pid_start = DWC_OTG_HC_PID_MDATA;
23720 + }
23721 + }
23722 + } else {
23723 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23724 + }
23725 +}
23726 +
23727 +/**
23728 + * This function does the setup for a data transfer for a host channel and
23729 + * starts the transfer. May be called in either Slave mode or DMA mode. In
23730 + * Slave mode, the caller must ensure that there is sufficient space in the
23731 + * request queue and Tx Data FIFO.
23732 + *
23733 + * For an OUT transfer in Slave mode, it loads a data packet into the
23734 + * appropriate FIFO. If necessary, additional data packets will be loaded in
23735 + * the Host ISR.
23736 + *
23737 + * For an IN transfer in Slave mode, a data packet is requested. The data
23738 + * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
23739 + * additional data packets are requested in the Host ISR.
23740 + *
23741 + * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
23742 + * register along with a packet count of 1 and the channel is enabled. This
23743 + * causes a single PING transaction to occur. Other fields in HCTSIZ are
23744 + * simply set to 0 since no data transfer occurs in this case.
23745 + *
23746 + * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
23747 + * all the information required to perform the subsequent data transfer. In
23748 + * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
23749 + * controller performs the entire PING protocol, then starts the data
23750 + * transfer.
23751 + *
23752 + * @param core_if Programming view of DWC_otg controller.
23753 + * @param hc Information needed to initialize the host channel. The xfer_len
23754 + * value may be reduced to accommodate the max widths of the XferSize and
23755 + * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
23756 + * to reflect the final xfer_len value.
23757 + */
23758 +void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23759 +{
23760 + hcchar_data_t hcchar;
23761 + hctsiz_data_t hctsiz;
23762 + uint16_t num_packets;
23763 + uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
23764 + uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
23765 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23766 +
23767 + hctsiz.d32 = 0;
23768 +
23769 + if (hc->do_ping) {
23770 + if (!core_if->dma_enable) {
23771 + dwc_otg_hc_do_ping(core_if, hc);
23772 + hc->xfer_started = 1;
23773 + return;
23774 + } else {
23775 + hctsiz.b.dopng = 1;
23776 + }
23777 + }
23778 +
23779 + if (hc->do_split) {
23780 + num_packets = 1;
23781 +
23782 + if (hc->complete_split && !hc->ep_is_in) {
23783 + /* For CSPLIT OUT Transfer, set the size to 0 so the
23784 + * core doesn't expect any data written to the FIFO */
23785 + hc->xfer_len = 0;
23786 + } else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
23787 + hc->xfer_len = hc->max_packet;
23788 + } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
23789 + hc->xfer_len = 188;
23790 + }
23791 +
23792 + hctsiz.b.xfersize = hc->xfer_len;
23793 + } else {
23794 + /*
23795 + * Ensure that the transfer length and packet count will fit
23796 + * in the widths allocated for them in the HCTSIZn register.
23797 + */
23798 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23799 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23800 + /*
23801 + * Make sure the transfer size is no larger than one
23802 + * (micro)frame's worth of data. (A check was done
23803 + * when the periodic transfer was accepted to ensure
23804 + * that a (micro)frame's worth of data can be
23805 + * programmed into a channel.)
23806 + */
23807 + uint32_t max_periodic_len =
23808 + hc->multi_count * hc->max_packet;
23809 + if (hc->xfer_len > max_periodic_len) {
23810 + hc->xfer_len = max_periodic_len;
23811 + } else {
23812 + }
23813 + } else if (hc->xfer_len > max_hc_xfer_size) {
23814 + /* Make sure that xfer_len is a multiple of max packet size. */
23815 + hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
23816 + }
23817 +
23818 + if (hc->xfer_len > 0) {
23819 + num_packets =
23820 + (hc->xfer_len + hc->max_packet -
23821 + 1) / hc->max_packet;
23822 + if (num_packets > max_hc_pkt_count) {
23823 + num_packets = max_hc_pkt_count;
23824 + hc->xfer_len = num_packets * hc->max_packet;
23825 + }
23826 + } else {
23827 + /* Need 1 packet for transfer length of 0. */
23828 + num_packets = 1;
23829 + }
23830 +
23831 + if (hc->ep_is_in) {
23832 + /* Always program an integral # of max packets for IN transfers. */
23833 + hc->xfer_len = num_packets * hc->max_packet;
23834 + }
23835 +
23836 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23837 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23838 + /*
23839 + * Make sure that the multi_count field matches the
23840 + * actual transfer length.
23841 + */
23842 + hc->multi_count = num_packets;
23843 + }
23844 +
23845 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23846 + set_pid_isoc(hc);
23847 +
23848 + hctsiz.b.xfersize = hc->xfer_len;
23849 + }
23850 +
23851 + hc->start_pkt_count = num_packets;
23852 + hctsiz.b.pktcnt = num_packets;
23853 + hctsiz.b.pid = hc->data_pid_start;
23854 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
23855 +
23856 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23857 + DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize);
23858 + DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt);
23859 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
23860 +
23861 + if (core_if->dma_enable) {
23862 + dwc_dma_t dma_addr;
23863 + if (hc->align_buff) {
23864 + dma_addr = hc->align_buff;
23865 + } else {
23866 + dma_addr = ((unsigned long)hc->xfer_buff & 0xffffffff);
23867 + }
23868 + DWC_WRITE_REG32(&hc_regs->hcdma, dma_addr);
23869 + }
23870 +
23871 + /* Start the split */
23872 + if (hc->do_split) {
23873 + hcsplt_data_t hcsplt;
23874 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
23875 + hcsplt.b.spltena = 1;
23876 + DWC_WRITE_REG32(&hc_regs->hcsplt, hcsplt.d32);
23877 + }
23878 +
23879 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23880 + hcchar.b.multicnt = hc->multi_count;
23881 + hc_set_even_odd_frame(core_if, hc, &hcchar);
23882 +#ifdef DEBUG
23883 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
23884 + if (hcchar.b.chdis) {
23885 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
23886 + __func__, hc->hc_num, hcchar.d32);
23887 + }
23888 +#endif
23889 +
23890 + /* Set host channel enable after all other setup is complete. */
23891 + hcchar.b.chen = 1;
23892 + hcchar.b.chdis = 0;
23893 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23894 +
23895 + hc->xfer_started = 1;
23896 + hc->requests++;
23897 +
23898 + if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
23899 + /* Load OUT packet into the appropriate Tx FIFO. */
23900 + dwc_otg_hc_write_packet(core_if, hc);
23901 + }
23902 +#ifdef DEBUG
23903 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
23904 + DWC_DEBUGPL(DBG_HCDV, "transfer %d from core_if %p\n",
23905 + hc->hc_num, core_if);//GRAYG
23906 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
23907 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
23908 +
23909 + /* Start a timer for this transfer. */
23910 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
23911 + }
23912 +#endif
23913 +}
23914 +
23915 +/**
23916 + * This function does the setup for a data transfer for a host channel
23917 + * and starts the transfer in Descriptor DMA mode.
23918 + *
23919 + * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
23920 + * Sets PID and NTD values. For periodic transfers
23921 + * initializes SCHED_INFO field with micro-frame bitmap.
23922 + *
23923 + * Initializes HCDMA register with descriptor list address and CTD value
23924 + * then starts the transfer via enabling the channel.
23925 + *
23926 + * @param core_if Programming view of DWC_otg controller.
23927 + * @param hc Information needed to initialize the host channel.
23928 + */
23929 +void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23930 +{
23931 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23932 + hcchar_data_t hcchar;
23933 + hctsiz_data_t hctsiz;
23934 + hcdma_data_t hcdma;
23935 +
23936 + hctsiz.d32 = 0;
23937 +
23938 + if (hc->do_ping)
23939 + hctsiz.b_ddma.dopng = 1;
23940 +
23941 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23942 + set_pid_isoc(hc);
23943 +
23944 + /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
23945 + hctsiz.b_ddma.pid = hc->data_pid_start;
23946 + hctsiz.b_ddma.ntd = hc->ntd - 1; /* 0 - 1 descriptor, 1 - 2 descriptors, etc. */
23947 + hctsiz.b_ddma.schinfo = hc->schinfo; /* Non-zero only for high-speed interrupt endpoints */
23948 +
23949 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23950 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
23951 + DWC_DEBUGPL(DBG_HCDV, " NTD: %d\n", hctsiz.b_ddma.ntd);
23952 +
23953 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
23954 +
23955 + hcdma.d32 = 0;
23956 + hcdma.b.dma_addr = ((uint32_t) hc->desc_list_addr) >> 11;
23957 +
23958 + /* Always start from first descriptor. */
23959 + hcdma.b.ctd = 0;
23960 + DWC_WRITE_REG32(&hc_regs->hcdma, hcdma.d32);
23961 +
23962 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23963 + hcchar.b.multicnt = hc->multi_count;
23964 +
23965 +#ifdef DEBUG
23966 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
23967 + if (hcchar.b.chdis) {
23968 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
23969 + __func__, hc->hc_num, hcchar.d32);
23970 + }
23971 +#endif
23972 +
23973 + /* Set host channel enable after all other setup is complete. */
23974 + hcchar.b.chen = 1;
23975 + hcchar.b.chdis = 0;
23976 +
23977 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23978 +
23979 + hc->xfer_started = 1;
23980 + hc->requests++;
23981 +
23982 +#ifdef DEBUG
23983 + if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR)
23984 + && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) {
23985 + DWC_DEBUGPL(DBG_HCDV, "DMA transfer %d from core_if %p\n",
23986 + hc->hc_num, core_if);//GRAYG
23987 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
23988 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
23989 + /* Start a timer for this transfer. */
23990 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
23991 + }
23992 +#endif
23993 +
23994 +}
23995 +
23996 +/**
23997 + * This function continues a data transfer that was started by previous call
23998 + * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
23999 + * sufficient space in the request queue and Tx Data FIFO. This function
24000 + * should only be called in Slave mode. In DMA mode, the controller acts
24001 + * autonomously to complete transfers programmed to a host channel.
24002 + *
24003 + * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
24004 + * if there is any data remaining to be queued. For an IN transfer, another
24005 + * data packet is always requested. For the SETUP phase of a control transfer,
24006 + * this function does nothing.
24007 + *
24008 + * @return 1 if a new request is queued, 0 if no more requests are required
24009 + * for this transfer.
24010 + */
24011 +int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24012 +{
24013 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
24014 +
24015 + if (hc->do_split) {
24016 + /* SPLITs always queue just once per channel */
24017 + return 0;
24018 + } else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
24019 + /* SETUPs are queued only once since they can't be NAKed. */
24020 + return 0;
24021 + } else if (hc->ep_is_in) {
24022 + /*
24023 + * Always queue another request for other IN transfers. If
24024 + * back-to-back INs are issued and NAKs are received for both,
24025 + * the driver may still be processing the first NAK when the
24026 + * second NAK is received. When the interrupt handler clears
24027 + * the NAK interrupt for the first NAK, the second NAK will
24028 + * not be seen. So we can't depend on the NAK interrupt
24029 + * handler to requeue a NAKed request. Instead, IN requests
24030 + * are issued each time this function is called. When the
24031 + * transfer completes, the extra requests for the channel will
24032 + * be flushed.
24033 + */
24034 + hcchar_data_t hcchar;
24035 + dwc_otg_hc_regs_t *hc_regs =
24036 + core_if->host_if->hc_regs[hc->hc_num];
24037 +
24038 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24039 + hc_set_even_odd_frame(core_if, hc, &hcchar);
24040 + hcchar.b.chen = 1;
24041 + hcchar.b.chdis = 0;
24042 + DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n",
24043 + hcchar.d32);
24044 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24045 + hc->requests++;
24046 + return 1;
24047 + } else {
24048 + /* OUT transfers. */
24049 + if (hc->xfer_count < hc->xfer_len) {
24050 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
24051 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
24052 + hcchar_data_t hcchar;
24053 + dwc_otg_hc_regs_t *hc_regs;
24054 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
24055 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24056 + hc_set_even_odd_frame(core_if, hc, &hcchar);
24057 + }
24058 +
24059 + /* Load OUT packet into the appropriate Tx FIFO. */
24060 + dwc_otg_hc_write_packet(core_if, hc);
24061 + hc->requests++;
24062 + return 1;
24063 + } else {
24064 + return 0;
24065 + }
24066 + }
24067 +}
24068 +
24069 +/**
24070 + * Starts a PING transfer. This function should only be called in Slave mode.
24071 + * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
24072 + */
24073 +void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24074 +{
24075 + hcchar_data_t hcchar;
24076 + hctsiz_data_t hctsiz;
24077 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
24078 +
24079 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
24080 +
24081 + hctsiz.d32 = 0;
24082 + hctsiz.b.dopng = 1;
24083 + hctsiz.b.pktcnt = 1;
24084 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
24085 +
24086 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24087 + hcchar.b.chen = 1;
24088 + hcchar.b.chdis = 0;
24089 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24090 +}
24091 +
24092 +/*
24093 + * This function writes a packet into the Tx FIFO associated with the Host
24094 + * Channel. For a channel associated with a non-periodic EP, the non-periodic
24095 + * Tx FIFO is written. For a channel associated with a periodic EP, the
24096 + * periodic Tx FIFO is written. This function should only be called in Slave
24097 + * mode.
24098 + *
24099 + * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
24100 + * then number of bytes written to the Tx FIFO.
24101 + */
24102 +void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24103 +{
24104 + uint32_t i;
24105 + uint32_t remaining_count;
24106 + uint32_t byte_count;
24107 + uint32_t dword_count;
24108 +
24109 + uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
24110 + uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
24111 +
24112 + remaining_count = hc->xfer_len - hc->xfer_count;
24113 + if (remaining_count > hc->max_packet) {
24114 + byte_count = hc->max_packet;
24115 + } else {
24116 + byte_count = remaining_count;
24117 + }
24118 +
24119 + dword_count = (byte_count + 3) / 4;
24120 +
24121 + if ((((unsigned long)data_buff) & 0x3) == 0) {
24122 + /* xfer_buff is DWORD aligned. */
24123 + for (i = 0; i < dword_count; i++, data_buff++) {
24124 + DWC_WRITE_REG32(data_fifo, *data_buff);
24125 + }
24126 + } else {
24127 + /* xfer_buff is not DWORD aligned. */
24128 + for (i = 0; i < dword_count; i++, data_buff++) {
24129 + uint32_t data;
24130 + data =
24131 + (data_buff[0] | data_buff[1] << 8 | data_buff[2] <<
24132 + 16 | data_buff[3] << 24);
24133 + DWC_WRITE_REG32(data_fifo, data);
24134 + }
24135 + }
24136 +
24137 + hc->xfer_count += byte_count;
24138 + hc->xfer_buff += byte_count;
24139 +}
24140 +
24141 +/**
24142 + * Gets the current USB frame number. This is the frame number from the last
24143 + * SOF packet.
24144 + */
24145 +uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if)
24146 +{
24147 + dsts_data_t dsts;
24148 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
24149 +
24150 + /* read current frame/microframe number from DSTS register */
24151 + return dsts.b.soffn;
24152 +}
24153 +
24154 +/**
24155 + * Calculates and gets the frame Interval value of HFIR register according PHY
24156 + * type and speed.The application can modify a value of HFIR register only after
24157 + * the Port Enable bit of the Host Port Control and Status register
24158 + * (HPRT.PrtEnaPort) has been set.
24159 +*/
24160 +
24161 +uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if)
24162 +{
24163 + gusbcfg_data_t usbcfg;
24164 + hwcfg2_data_t hwcfg2;
24165 + hprt0_data_t hprt0;
24166 + int clock = 60; // default value
24167 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
24168 + hwcfg2.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
24169 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
24170 + if (!usbcfg.b.physel && usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
24171 + clock = 60;
24172 + if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 3)
24173 + clock = 48;
24174 + if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24175 + !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
24176 + clock = 30;
24177 + if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24178 + !usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
24179 + clock = 60;
24180 + if (usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24181 + !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
24182 + clock = 48;
24183 + if (usbcfg.b.physel && !usbcfg.b.phyif && hwcfg2.b.fs_phy_type == 2)
24184 + clock = 48;
24185 + if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 1)
24186 + clock = 48;
24187 + if (hprt0.b.prtspd == 0)
24188 + /* High speed case */
24189 + return 125 * clock;
24190 + else
24191 + /* FS/LS case */
24192 + return 1000 * clock;
24193 +}
24194 +
24195 +/**
24196 + * This function reads a setup packet from the Rx FIFO into the destination
24197 + * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl)
24198 + * Interrupt routine when a SETUP packet has been received in Slave mode.
24199 + *
24200 + * @param core_if Programming view of DWC_otg controller.
24201 + * @param dest Destination buffer for packet data.
24202 + */
24203 +void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest)
24204 +{
24205 + device_grxsts_data_t status;
24206 + /* Get the 8 bytes of a setup transaction data */
24207 +
24208 + /* Pop 2 DWORDS off the receive data FIFO into memory */
24209 + dest[0] = DWC_READ_REG32(core_if->data_fifo[0]);
24210 + dest[1] = DWC_READ_REG32(core_if->data_fifo[0]);
24211 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
24212 + status.d32 =
24213 + DWC_READ_REG32(&core_if->core_global_regs->grxstsp);
24214 + DWC_DEBUGPL(DBG_ANY,
24215 + "EP:%d BCnt:%d " "pktsts:%x Frame:%d(0x%0x)\n",
24216 + status.b.epnum, status.b.bcnt, status.b.pktsts,
24217 + status.b.fn, status.b.fn);
24218 + }
24219 +}
24220 +
24221 +/**
24222 + * This function enables EP0 OUT to receive SETUP packets and configures EP0
24223 + * IN for transmitting packets. It is normally called when the
24224 + * "Enumeration Done" interrupt occurs.
24225 + *
24226 + * @param core_if Programming view of DWC_otg controller.
24227 + * @param ep The EP0 data.
24228 + */
24229 +void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24230 +{
24231 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24232 + dsts_data_t dsts;
24233 + depctl_data_t diepctl;
24234 + depctl_data_t doepctl;
24235 + dctl_data_t dctl = {.d32 = 0 };
24236 +
24237 + ep->stp_rollover = 0;
24238 + /* Read the Device Status and Endpoint 0 Control registers */
24239 + dsts.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dsts);
24240 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
24241 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
24242 +
24243 + /* Set the MPS of the IN EP based on the enumeration speed */
24244 + switch (dsts.b.enumspd) {
24245 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
24246 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
24247 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
24248 + diepctl.b.mps = DWC_DEP0CTL_MPS_64;
24249 + break;
24250 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
24251 + diepctl.b.mps = DWC_DEP0CTL_MPS_8;
24252 + break;
24253 + }
24254 +
24255 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
24256 +
24257 + /* Enable OUT EP for receive */
24258 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
24259 + doepctl.b.epena = 1;
24260 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
24261 + }
24262 +#ifdef VERBOSE
24263 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
24264 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
24265 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
24266 + DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
24267 +#endif
24268 + dctl.b.cgnpinnak = 1;
24269 +
24270 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
24271 + DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
24272 + DWC_READ_REG32(&dev_if->dev_global_regs->dctl));
24273 +
24274 +}
24275 +
24276 +/**
24277 + * This function activates an EP. The Device EP control register for
24278 + * the EP is configured as defined in the ep structure. Note: This
24279 + * function is not used for EP0.
24280 + *
24281 + * @param core_if Programming view of DWC_otg controller.
24282 + * @param ep The EP to activate.
24283 + */
24284 +void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24285 +{
24286 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24287 + depctl_data_t depctl;
24288 + volatile uint32_t *addr;
24289 + daint_data_t daintmsk = {.d32 = 0 };
24290 + dcfg_data_t dcfg;
24291 + uint8_t i;
24292 +
24293 + DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
24294 + (ep->is_in ? "IN" : "OUT"));
24295 +
24296 +#ifdef DWC_UTE_PER_IO
24297 + ep->xiso_frame_num = 0xFFFFFFFF;
24298 + ep->xiso_active_xfers = 0;
24299 + ep->xiso_queued_xfers = 0;
24300 +#endif
24301 + /* Read DEPCTLn register */
24302 + if (ep->is_in == 1) {
24303 + addr = &dev_if->in_ep_regs[ep->num]->diepctl;
24304 + daintmsk.ep.in = 1 << ep->num;
24305 + } else {
24306 + addr = &dev_if->out_ep_regs[ep->num]->doepctl;
24307 + daintmsk.ep.out = 1 << ep->num;
24308 + }
24309 +
24310 + /* If the EP is already active don't change the EP Control
24311 + * register. */
24312 + depctl.d32 = DWC_READ_REG32(addr);
24313 + if (!depctl.b.usbactep) {
24314 + depctl.b.mps = ep->maxpacket;
24315 + depctl.b.eptype = ep->type;
24316 + depctl.b.txfnum = ep->tx_fifo_num;
24317 +
24318 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24319 + depctl.b.setd0pid = 1; // ???
24320 + } else {
24321 + depctl.b.setd0pid = 1;
24322 + }
24323 + depctl.b.usbactep = 1;
24324 +
24325 + /* Update nextep_seq array and EPMSCNT in DCFG*/
24326 + if (!(depctl.b.eptype & 1) && (ep->is_in == 1)) { // NP IN EP
24327 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
24328 + if (core_if->nextep_seq[i] == core_if->first_in_nextep_seq)
24329 + break;
24330 + }
24331 + core_if->nextep_seq[i] = ep->num;
24332 + core_if->nextep_seq[ep->num] = core_if->first_in_nextep_seq;
24333 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24334 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
24335 + dcfg.b.epmscnt++;
24336 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
24337 +
24338 + DWC_DEBUGPL(DBG_PCDV,
24339 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
24340 + __func__, core_if->first_in_nextep_seq);
24341 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
24342 + DWC_DEBUGPL(DBG_PCDV, "%2d\n",
24343 + core_if->nextep_seq[i]);
24344 + }
24345 +
24346 + }
24347 +
24348 +
24349 + DWC_WRITE_REG32(addr, depctl.d32);
24350 + DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", DWC_READ_REG32(addr));
24351 + }
24352 +
24353 + /* Enable the Interrupt for this EP */
24354 + if (core_if->multiproc_int_enable) {
24355 + if (ep->is_in == 1) {
24356 + diepmsk_data_t diepmsk = {.d32 = 0 };
24357 + diepmsk.b.xfercompl = 1;
24358 + diepmsk.b.timeout = 1;
24359 + diepmsk.b.epdisabled = 1;
24360 + diepmsk.b.ahberr = 1;
24361 + diepmsk.b.intknepmis = 1;
24362 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
24363 + diepmsk.b.intknepmis = 0;
24364 + diepmsk.b.txfifoundrn = 1; //?????
24365 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24366 + diepmsk.b.nak = 1;
24367 + }
24368 +
24369 +
24370 +
24371 +/*
24372 + if (core_if->dma_desc_enable) {
24373 + diepmsk.b.bna = 1;
24374 + }
24375 +*/
24376 +/*
24377 + if (core_if->dma_enable) {
24378 + doepmsk.b.nak = 1;
24379 + }
24380 +*/
24381 + DWC_WRITE_REG32(&dev_if->dev_global_regs->
24382 + diepeachintmsk[ep->num], diepmsk.d32);
24383 +
24384 + } else {
24385 + doepmsk_data_t doepmsk = {.d32 = 0 };
24386 + doepmsk.b.xfercompl = 1;
24387 + doepmsk.b.ahberr = 1;
24388 + doepmsk.b.epdisabled = 1;
24389 + if (ep->type == DWC_OTG_EP_TYPE_ISOC)
24390 + doepmsk.b.outtknepdis = 1;
24391 +
24392 +/*
24393 +
24394 + if (core_if->dma_desc_enable) {
24395 + doepmsk.b.bna = 1;
24396 + }
24397 +*/
24398 +/*
24399 + doepmsk.b.babble = 1;
24400 + doepmsk.b.nyet = 1;
24401 + doepmsk.b.nak = 1;
24402 +*/
24403 + DWC_WRITE_REG32(&dev_if->dev_global_regs->
24404 + doepeachintmsk[ep->num], doepmsk.d32);
24405 + }
24406 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->deachintmsk,
24407 + 0, daintmsk.d32);
24408 + } else {
24409 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24410 + if (ep->is_in) {
24411 + diepmsk_data_t diepmsk = {.d32 = 0 };
24412 + diepmsk.b.nak = 1;
24413 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32);
24414 + } else {
24415 + doepmsk_data_t doepmsk = {.d32 = 0 };
24416 + doepmsk.b.outtknepdis = 1;
24417 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->doepmsk, 0, doepmsk.d32);
24418 + }
24419 + }
24420 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->daintmsk,
24421 + 0, daintmsk.d32);
24422 + }
24423 +
24424 + DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
24425 + DWC_READ_REG32(&dev_if->dev_global_regs->daintmsk));
24426 +
24427 + ep->stall_clear_flag = 0;
24428 +
24429 + return;
24430 +}
24431 +
24432 +/**
24433 + * This function deactivates an EP. This is done by clearing the USB Active
24434 + * EP bit in the Device EP control register. Note: This function is not used
24435 + * for EP0. EP0 cannot be deactivated.
24436 + *
24437 + * @param core_if Programming view of DWC_otg controller.
24438 + * @param ep The EP to deactivate.
24439 + */
24440 +void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24441 +{
24442 + depctl_data_t depctl = {.d32 = 0 };
24443 + volatile uint32_t *addr;
24444 + daint_data_t daintmsk = {.d32 = 0 };
24445 + dcfg_data_t dcfg;
24446 + uint8_t i = 0;
24447 +
24448 +#ifdef DWC_UTE_PER_IO
24449 + ep->xiso_frame_num = 0xFFFFFFFF;
24450 + ep->xiso_active_xfers = 0;
24451 + ep->xiso_queued_xfers = 0;
24452 +#endif
24453 +
24454 + /* Read DEPCTLn register */
24455 + if (ep->is_in == 1) {
24456 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
24457 + daintmsk.ep.in = 1 << ep->num;
24458 + } else {
24459 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
24460 + daintmsk.ep.out = 1 << ep->num;
24461 + }
24462 +
24463 + depctl.d32 = DWC_READ_REG32(addr);
24464 +
24465 + depctl.b.usbactep = 0;
24466 +
24467 + /* Update nextep_seq array and EPMSCNT in DCFG*/
24468 + if (!(depctl.b.eptype & 1) && ep->is_in == 1) { // NP EP IN
24469 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
24470 + if (core_if->nextep_seq[i] == ep->num)
24471 + break;
24472 + }
24473 + core_if->nextep_seq[i] = core_if->nextep_seq[ep->num];
24474 + if (core_if->first_in_nextep_seq == ep->num)
24475 + core_if->first_in_nextep_seq = i;
24476 + core_if->nextep_seq[ep->num] = 0xff;
24477 + depctl.b.nextep = 0;
24478 + dcfg.d32 =
24479 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
24480 + dcfg.b.epmscnt--;
24481 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
24482 + dcfg.d32);
24483 +
24484 + DWC_DEBUGPL(DBG_PCDV,
24485 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
24486 + __func__, core_if->first_in_nextep_seq);
24487 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
24488 + DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
24489 + }
24490 + }
24491 +
24492 + if (ep->is_in == 1)
24493 + depctl.b.txfnum = 0;
24494 +
24495 + if (core_if->dma_desc_enable)
24496 + depctl.b.epdis = 1;
24497 +
24498 + DWC_WRITE_REG32(addr, depctl.d32);
24499 + depctl.d32 = DWC_READ_REG32(addr);
24500 + if (core_if->dma_enable && ep->type == DWC_OTG_EP_TYPE_ISOC
24501 + && depctl.b.epena) {
24502 + depctl_data_t depctl = {.d32 = 0};
24503 + if (ep->is_in) {
24504 + diepint_data_t diepint = {.d32 = 0};
24505 +
24506 + depctl.b.snak = 1;
24507 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24508 + diepctl, depctl.d32);
24509 + do {
24510 + dwc_udelay(10);
24511 + diepint.d32 =
24512 + DWC_READ_REG32(&core_if->
24513 + dev_if->in_ep_regs[ep->num]->
24514 + diepint);
24515 + } while (!diepint.b.inepnakeff);
24516 + diepint.b.inepnakeff = 1;
24517 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24518 + diepint, diepint.d32);
24519 + depctl.d32 = 0;
24520 + depctl.b.epdis = 1;
24521 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24522 + diepctl, depctl.d32);
24523 + do {
24524 + dwc_udelay(10);
24525 + diepint.d32 =
24526 + DWC_READ_REG32(&core_if->
24527 + dev_if->in_ep_regs[ep->num]->
24528 + diepint);
24529 + } while (!diepint.b.epdisabled);
24530 + diepint.b.epdisabled = 1;
24531 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24532 + diepint, diepint.d32);
24533 + } else {
24534 + dctl_data_t dctl = {.d32 = 0};
24535 + gintmsk_data_t gintsts = {.d32 = 0};
24536 + doepint_data_t doepint = {.d32 = 0};
24537 + dctl.b.sgoutnak = 1;
24538 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
24539 + dctl, 0, dctl.d32);
24540 + do {
24541 + dwc_udelay(10);
24542 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
24543 + } while (!gintsts.b.goutnakeff);
24544 + gintsts.d32 = 0;
24545 + gintsts.b.goutnakeff = 1;
24546 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
24547 +
24548 + depctl.d32 = 0;
24549 + depctl.b.epdis = 1;
24550 + depctl.b.snak = 1;
24551 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepctl, depctl.d32);
24552 + do
24553 + {
24554 + dwc_udelay(10);
24555 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
24556 + out_ep_regs[ep->num]->doepint);
24557 + } while (!doepint.b.epdisabled);
24558 +
24559 + doepint.b.epdisabled = 1;
24560 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepint, doepint.d32);
24561 +
24562 + dctl.d32 = 0;
24563 + dctl.b.cgoutnak = 1;
24564 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
24565 + }
24566 + }
24567 +
24568 + /* Disable the Interrupt for this EP */
24569 + if (core_if->multiproc_int_enable) {
24570 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
24571 + daintmsk.d32, 0);
24572 +
24573 + if (ep->is_in == 1) {
24574 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
24575 + diepeachintmsk[ep->num], 0);
24576 + } else {
24577 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
24578 + doepeachintmsk[ep->num], 0);
24579 + }
24580 + } else {
24581 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->daintmsk,
24582 + daintmsk.d32, 0);
24583 + }
24584 +
24585 +}
24586 +
24587 +/**
24588 + * This function initializes dma descriptor chain.
24589 + *
24590 + * @param core_if Programming view of DWC_otg controller.
24591 + * @param ep The EP to start the transfer on.
24592 + */
24593 +static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24594 +{
24595 + dwc_otg_dev_dma_desc_t *dma_desc;
24596 + uint32_t offset;
24597 + uint32_t xfer_est;
24598 + int i;
24599 + unsigned maxxfer_local, total_len;
24600 +
24601 + if (!ep->is_in && ep->type == DWC_OTG_EP_TYPE_INTR &&
24602 + (ep->maxpacket%4)) {
24603 + maxxfer_local = ep->maxpacket;
24604 + total_len = ep->xfer_len;
24605 + } else {
24606 + maxxfer_local = ep->maxxfer;
24607 + total_len = ep->total_len;
24608 + }
24609 +
24610 + ep->desc_cnt = (total_len / maxxfer_local) +
24611 + ((total_len % maxxfer_local) ? 1 : 0);
24612 +
24613 + if (!ep->desc_cnt)
24614 + ep->desc_cnt = 1;
24615 +
24616 + if (ep->desc_cnt > MAX_DMA_DESC_CNT)
24617 + ep->desc_cnt = MAX_DMA_DESC_CNT;
24618 +
24619 + dma_desc = ep->desc_addr;
24620 + if (maxxfer_local == ep->maxpacket) {
24621 + if ((total_len % maxxfer_local) &&
24622 + (total_len/maxxfer_local < MAX_DMA_DESC_CNT)) {
24623 + xfer_est = (ep->desc_cnt - 1) * maxxfer_local +
24624 + (total_len % maxxfer_local);
24625 + } else
24626 + xfer_est = ep->desc_cnt * maxxfer_local;
24627 + } else
24628 + xfer_est = total_len;
24629 + offset = 0;
24630 + for (i = 0; i < ep->desc_cnt; ++i) {
24631 + /** DMA Descriptor Setup */
24632 + if (xfer_est > maxxfer_local) {
24633 + dma_desc->status.b.bs = BS_HOST_BUSY;
24634 + dma_desc->status.b.l = 0;
24635 + dma_desc->status.b.ioc = 0;
24636 + dma_desc->status.b.sp = 0;
24637 + dma_desc->status.b.bytes = maxxfer_local;
24638 + dma_desc->buf = ep->dma_addr + offset;
24639 + dma_desc->status.b.sts = 0;
24640 + dma_desc->status.b.bs = BS_HOST_READY;
24641 +
24642 + xfer_est -= maxxfer_local;
24643 + offset += maxxfer_local;
24644 + } else {
24645 + dma_desc->status.b.bs = BS_HOST_BUSY;
24646 + dma_desc->status.b.l = 1;
24647 + dma_desc->status.b.ioc = 1;
24648 + if (ep->is_in) {
24649 + dma_desc->status.b.sp =
24650 + (xfer_est %
24651 + ep->maxpacket) ? 1 : ((ep->
24652 + sent_zlp) ? 1 : 0);
24653 + dma_desc->status.b.bytes = xfer_est;
24654 + } else {
24655 + if (maxxfer_local == ep->maxpacket)
24656 + dma_desc->status.b.bytes = xfer_est;
24657 + else
24658 + dma_desc->status.b.bytes =
24659 + xfer_est + ((4 - (xfer_est & 0x3)) & 0x3);
24660 + }
24661 +
24662 + dma_desc->buf = ep->dma_addr + offset;
24663 + dma_desc->status.b.sts = 0;
24664 + dma_desc->status.b.bs = BS_HOST_READY;
24665 + }
24666 + dma_desc++;
24667 + }
24668 +}
24669 +/**
24670 + * This function is called when to write ISOC data into appropriate dedicated
24671 + * periodic FIFO.
24672 + */
24673 +static int32_t write_isoc_tx_fifo(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
24674 +{
24675 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24676 + dwc_otg_dev_in_ep_regs_t *ep_regs;
24677 + dtxfsts_data_t txstatus = {.d32 = 0 };
24678 + uint32_t len = 0;
24679 + int epnum = dwc_ep->num;
24680 + int dwords;
24681 +
24682 + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
24683 +
24684 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
24685 +
24686 + len = dwc_ep->xfer_len - dwc_ep->xfer_count;
24687 +
24688 + if (len > dwc_ep->maxpacket) {
24689 + len = dwc_ep->maxpacket;
24690 + }
24691 +
24692 + dwords = (len + 3) / 4;
24693 +
24694 + /* While there is space in the queue and space in the FIFO and
24695 + * More data to tranfer, Write packets to the Tx FIFO */
24696 + txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
24697 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
24698 +
24699 + while (txstatus.b.txfspcavail > dwords &&
24700 + dwc_ep->xfer_count < dwc_ep->xfer_len && dwc_ep->xfer_len != 0) {
24701 + /* Write the FIFO */
24702 + dwc_otg_ep_write_packet(core_if, dwc_ep, 0);
24703 +
24704 + len = dwc_ep->xfer_len - dwc_ep->xfer_count;
24705 + if (len > dwc_ep->maxpacket) {
24706 + len = dwc_ep->maxpacket;
24707 + }
24708 +
24709 + dwords = (len + 3) / 4;
24710 + txstatus.d32 =
24711 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
24712 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
24713 + txstatus.d32);
24714 + }
24715 +
24716 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
24717 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
24718 +
24719 + return 1;
24720 +}
24721 +/**
24722 + * This function does the setup for a data transfer for an EP and
24723 + * starts the transfer. For an IN transfer, the packets will be
24724 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
24725 + * the packets are unloaded from the Rx FIFO in the ISR. the ISR.
24726 + *
24727 + * @param core_if Programming view of DWC_otg controller.
24728 + * @param ep The EP to start the transfer on.
24729 + */
24730 +
24731 +void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24732 +{
24733 + depctl_data_t depctl;
24734 + deptsiz_data_t deptsiz;
24735 + gintmsk_data_t intr_mask = {.d32 = 0 };
24736 +
24737 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
24738 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
24739 + "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n",
24740 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
24741 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
24742 + ep->total_len);
24743 + /* IN endpoint */
24744 + if (ep->is_in == 1) {
24745 + dwc_otg_dev_in_ep_regs_t *in_regs =
24746 + core_if->dev_if->in_ep_regs[ep->num];
24747 +
24748 + gnptxsts_data_t gtxstatus;
24749 +
24750 + gtxstatus.d32 =
24751 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
24752 +
24753 + if (core_if->en_multiple_tx_fifo == 0
24754 + && gtxstatus.b.nptxqspcavail == 0 && !core_if->dma_enable) {
24755 +#ifdef DEBUG
24756 + DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32);
24757 +#endif
24758 + return;
24759 + }
24760 +
24761 + depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
24762 + deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
24763 +
24764 + if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
24765 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
24766 + ep->maxxfer : (ep->total_len - ep->xfer_len);
24767 + else
24768 + ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len - ep->xfer_len)) ?
24769 + MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
24770 +
24771 +
24772 + /* Zero Length Packet? */
24773 + if ((ep->xfer_len - ep->xfer_count) == 0) {
24774 + deptsiz.b.xfersize = 0;
24775 + deptsiz.b.pktcnt = 1;
24776 + } else {
24777 + /* Program the transfer size and packet count
24778 + * as follows: xfersize = N * maxpacket +
24779 + * short_packet pktcnt = N + (short_packet
24780 + * exist ? 1 : 0)
24781 + */
24782 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
24783 + deptsiz.b.pktcnt =
24784 + (ep->xfer_len - ep->xfer_count - 1 +
24785 + ep->maxpacket) / ep->maxpacket;
24786 + if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
24787 + deptsiz.b.pktcnt = MAX_PKT_CNT;
24788 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
24789 + }
24790 + if (ep->type == DWC_OTG_EP_TYPE_ISOC)
24791 + deptsiz.b.mc = deptsiz.b.pktcnt;
24792 + }
24793 +
24794 + /* Write the DMA register */
24795 + if (core_if->dma_enable) {
24796 + if (core_if->dma_desc_enable == 0) {
24797 + if (ep->type != DWC_OTG_EP_TYPE_ISOC)
24798 + deptsiz.b.mc = 1;
24799 + DWC_WRITE_REG32(&in_regs->dieptsiz,
24800 + deptsiz.d32);
24801 + DWC_WRITE_REG32(&(in_regs->diepdma),
24802 + (uint32_t) ep->dma_addr);
24803 + } else {
24804 +#ifdef DWC_UTE_CFI
24805 + /* The descriptor chain should be already initialized by now */
24806 + if (ep->buff_mode != BM_STANDARD) {
24807 + DWC_WRITE_REG32(&in_regs->diepdma,
24808 + ep->descs_dma_addr);
24809 + } else {
24810 +#endif
24811 + init_dma_desc_chain(core_if, ep);
24812 + /** DIEPDMAn Register write */
24813 + DWC_WRITE_REG32(&in_regs->diepdma,
24814 + ep->dma_desc_addr);
24815 +#ifdef DWC_UTE_CFI
24816 + }
24817 +#endif
24818 + }
24819 + } else {
24820 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
24821 + if (ep->type != DWC_OTG_EP_TYPE_ISOC) {
24822 + /**
24823 + * Enable the Non-Periodic Tx FIFO empty interrupt,
24824 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
24825 + * the data will be written into the fifo by the ISR.
24826 + */
24827 + if (core_if->en_multiple_tx_fifo == 0) {
24828 + intr_mask.b.nptxfempty = 1;
24829 + DWC_MODIFY_REG32
24830 + (&core_if->core_global_regs->gintmsk,
24831 + intr_mask.d32, intr_mask.d32);
24832 + } else {
24833 + /* Enable the Tx FIFO Empty Interrupt for this EP */
24834 + if (ep->xfer_len > 0) {
24835 + uint32_t fifoemptymsk = 0;
24836 + fifoemptymsk = 1 << ep->num;
24837 + DWC_MODIFY_REG32
24838 + (&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
24839 + 0, fifoemptymsk);
24840 +
24841 + }
24842 + }
24843 + } else {
24844 + write_isoc_tx_fifo(core_if, ep);
24845 + }
24846 + }
24847 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
24848 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24849 +
24850 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24851 + dsts_data_t dsts = {.d32 = 0};
24852 + if (ep->bInterval == 1) {
24853 + dsts.d32 =
24854 + DWC_READ_REG32(&core_if->dev_if->
24855 + dev_global_regs->dsts);
24856 + ep->frame_num = dsts.b.soffn + ep->bInterval;
24857 + if (ep->frame_num > 0x3FFF) {
24858 + ep->frm_overrun = 1;
24859 + ep->frame_num &= 0x3FFF;
24860 + } else
24861 + ep->frm_overrun = 0;
24862 + if (ep->frame_num & 0x1) {
24863 + depctl.b.setd1pid = 1;
24864 + } else {
24865 + depctl.b.setd0pid = 1;
24866 + }
24867 + }
24868 + }
24869 + /* EP enable, IN data in FIFO */
24870 + depctl.b.cnak = 1;
24871 + depctl.b.epena = 1;
24872 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
24873 +
24874 + } else {
24875 + /* OUT endpoint */
24876 + dwc_otg_dev_out_ep_regs_t *out_regs =
24877 + core_if->dev_if->out_ep_regs[ep->num];
24878 +
24879 + depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
24880 + deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
24881 +
24882 + if (!core_if->dma_desc_enable) {
24883 + if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
24884 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
24885 + ep->maxxfer : (ep->total_len - ep->xfer_len);
24886 + else
24887 + ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len
24888 + - ep->xfer_len)) ? MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
24889 + }
24890 +
24891 + /* Program the transfer size and packet count as follows:
24892 + *
24893 + * pktcnt = N
24894 + * xfersize = N * maxpacket
24895 + */
24896 + if ((ep->xfer_len - ep->xfer_count) == 0) {
24897 + /* Zero Length Packet */
24898 + deptsiz.b.xfersize = ep->maxpacket;
24899 + deptsiz.b.pktcnt = 1;
24900 + } else {
24901 + deptsiz.b.pktcnt =
24902 + (ep->xfer_len - ep->xfer_count +
24903 + (ep->maxpacket - 1)) / ep->maxpacket;
24904 + if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
24905 + deptsiz.b.pktcnt = MAX_PKT_CNT;
24906 + }
24907 + if (!core_if->dma_desc_enable) {
24908 + ep->xfer_len =
24909 + deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count;
24910 + }
24911 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
24912 + }
24913 +
24914 + DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
24915 + ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
24916 +
24917 + if (core_if->dma_enable) {
24918 + if (!core_if->dma_desc_enable) {
24919 + DWC_WRITE_REG32(&out_regs->doeptsiz,
24920 + deptsiz.d32);
24921 +
24922 + DWC_WRITE_REG32(&(out_regs->doepdma),
24923 + (uint32_t) ep->dma_addr);
24924 + } else {
24925 +#ifdef DWC_UTE_CFI
24926 + /* The descriptor chain should be already initialized by now */
24927 + if (ep->buff_mode != BM_STANDARD) {
24928 + DWC_WRITE_REG32(&out_regs->doepdma,
24929 + ep->descs_dma_addr);
24930 + } else {
24931 +#endif
24932 + /** This is used for interrupt out transfers*/
24933 + if (!ep->xfer_len)
24934 + ep->xfer_len = ep->total_len;
24935 + init_dma_desc_chain(core_if, ep);
24936 +
24937 + if (core_if->core_params->dev_out_nak) {
24938 + if (ep->type == DWC_OTG_EP_TYPE_BULK) {
24939 + deptsiz.b.pktcnt = (ep->total_len +
24940 + (ep->maxpacket - 1)) / ep->maxpacket;
24941 + deptsiz.b.xfersize = ep->total_len;
24942 + /* Remember initial value of doeptsiz */
24943 + core_if->start_doeptsiz_val[ep->num] = deptsiz.d32;
24944 + DWC_WRITE_REG32(&out_regs->doeptsiz,
24945 + deptsiz.d32);
24946 + }
24947 + }
24948 + /** DOEPDMAn Register write */
24949 + DWC_WRITE_REG32(&out_regs->doepdma,
24950 + ep->dma_desc_addr);
24951 +#ifdef DWC_UTE_CFI
24952 + }
24953 +#endif
24954 + }
24955 + } else {
24956 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
24957 + }
24958 +
24959 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24960 + dsts_data_t dsts = {.d32 = 0};
24961 + if (ep->bInterval == 1) {
24962 + dsts.d32 =
24963 + DWC_READ_REG32(&core_if->dev_if->
24964 + dev_global_regs->dsts);
24965 + ep->frame_num = dsts.b.soffn + ep->bInterval;
24966 + if (ep->frame_num > 0x3FFF) {
24967 + ep->frm_overrun = 1;
24968 + ep->frame_num &= 0x3FFF;
24969 + } else
24970 + ep->frm_overrun = 0;
24971 +
24972 + if (ep->frame_num & 0x1) {
24973 + depctl.b.setd1pid = 1;
24974 + } else {
24975 + depctl.b.setd0pid = 1;
24976 + }
24977 + }
24978 + }
24979 +
24980 + /* EP enable */
24981 + depctl.b.cnak = 1;
24982 + depctl.b.epena = 1;
24983 +
24984 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
24985 +
24986 + DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
24987 + DWC_READ_REG32(&out_regs->doepctl),
24988 + DWC_READ_REG32(&out_regs->doeptsiz));
24989 + DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
24990 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
24991 + daintmsk),
24992 + DWC_READ_REG32(&core_if->core_global_regs->
24993 + gintmsk));
24994 +
24995 + /* Timer is scheduling only for out bulk transfers for
24996 + * "Device DDMA OUT NAK Enhancement" feature to inform user
24997 + * about received data payload in case of timeout
24998 + */
24999 + if (core_if->core_params->dev_out_nak) {
25000 + if (ep->type == DWC_OTG_EP_TYPE_BULK) {
25001 + core_if->ep_xfer_info[ep->num].core_if = core_if;
25002 + core_if->ep_xfer_info[ep->num].ep = ep;
25003 + core_if->ep_xfer_info[ep->num].state = 1;
25004 +
25005 + /* Start a timer for this transfer. */
25006 + DWC_TIMER_SCHEDULE(core_if->ep_xfer_timer[ep->num], 10000);
25007 + }
25008 + }
25009 + }
25010 +}
25011 +
25012 +/**
25013 + * This function setup a zero length transfer in Buffer DMA and
25014 + * Slave modes for usb requests with zero field set
25015 + *
25016 + * @param core_if Programming view of DWC_otg controller.
25017 + * @param ep The EP to start the transfer on.
25018 + *
25019 + */
25020 +void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25021 +{
25022 +
25023 + depctl_data_t depctl;
25024 + deptsiz_data_t deptsiz;
25025 + gintmsk_data_t intr_mask = {.d32 = 0 };
25026 +
25027 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
25028 + DWC_PRINTF("zero length transfer is called\n");
25029 +
25030 + /* IN endpoint */
25031 + if (ep->is_in == 1) {
25032 + dwc_otg_dev_in_ep_regs_t *in_regs =
25033 + core_if->dev_if->in_ep_regs[ep->num];
25034 +
25035 + depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
25036 + deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
25037 +
25038 + deptsiz.b.xfersize = 0;
25039 + deptsiz.b.pktcnt = 1;
25040 +
25041 + /* Write the DMA register */
25042 + if (core_if->dma_enable) {
25043 + if (core_if->dma_desc_enable == 0) {
25044 + deptsiz.b.mc = 1;
25045 + DWC_WRITE_REG32(&in_regs->dieptsiz,
25046 + deptsiz.d32);
25047 + DWC_WRITE_REG32(&(in_regs->diepdma),
25048 + (uint32_t) ep->dma_addr);
25049 + }
25050 + } else {
25051 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25052 + /**
25053 + * Enable the Non-Periodic Tx FIFO empty interrupt,
25054 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
25055 + * the data will be written into the fifo by the ISR.
25056 + */
25057 + if (core_if->en_multiple_tx_fifo == 0) {
25058 + intr_mask.b.nptxfempty = 1;
25059 + DWC_MODIFY_REG32(&core_if->
25060 + core_global_regs->gintmsk,
25061 + intr_mask.d32, intr_mask.d32);
25062 + } else {
25063 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25064 + if (ep->xfer_len > 0) {
25065 + uint32_t fifoemptymsk = 0;
25066 + fifoemptymsk = 1 << ep->num;
25067 + DWC_MODIFY_REG32(&core_if->
25068 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25069 + 0, fifoemptymsk);
25070 + }
25071 + }
25072 + }
25073 +
25074 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25075 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25076 + /* EP enable, IN data in FIFO */
25077 + depctl.b.cnak = 1;
25078 + depctl.b.epena = 1;
25079 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25080 +
25081 + } else {
25082 + /* OUT endpoint */
25083 + dwc_otg_dev_out_ep_regs_t *out_regs =
25084 + core_if->dev_if->out_ep_regs[ep->num];
25085 +
25086 + depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
25087 + deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
25088 +
25089 + /* Zero Length Packet */
25090 + deptsiz.b.xfersize = ep->maxpacket;
25091 + deptsiz.b.pktcnt = 1;
25092 +
25093 + if (core_if->dma_enable) {
25094 + if (!core_if->dma_desc_enable) {
25095 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25096 + deptsiz.d32);
25097 +
25098 + DWC_WRITE_REG32(&(out_regs->doepdma),
25099 + (uint32_t) ep->dma_addr);
25100 + }
25101 + } else {
25102 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25103 + }
25104 +
25105 + /* EP enable */
25106 + depctl.b.cnak = 1;
25107 + depctl.b.epena = 1;
25108 +
25109 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
25110 +
25111 + }
25112 +}
25113 +
25114 +/**
25115 + * This function does the setup for a data transfer for EP0 and starts
25116 + * the transfer. For an IN transfer, the packets will be loaded into
25117 + * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
25118 + * unloaded from the Rx FIFO in the ISR.
25119 + *
25120 + * @param core_if Programming view of DWC_otg controller.
25121 + * @param ep The EP0 data.
25122 + */
25123 +void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25124 +{
25125 + depctl_data_t depctl;
25126 + deptsiz0_data_t deptsiz;
25127 + gintmsk_data_t intr_mask = {.d32 = 0 };
25128 + dwc_otg_dev_dma_desc_t *dma_desc;
25129 +
25130 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
25131 + "xfer_buff=%p start_xfer_buff=%p \n",
25132 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
25133 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
25134 +
25135 + ep->total_len = ep->xfer_len;
25136 +
25137 + /* IN endpoint */
25138 + if (ep->is_in == 1) {
25139 + dwc_otg_dev_in_ep_regs_t *in_regs =
25140 + core_if->dev_if->in_ep_regs[0];
25141 +
25142 + gnptxsts_data_t gtxstatus;
25143 +
25144 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
25145 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25146 + if (depctl.b.epena)
25147 + return;
25148 + }
25149 +
25150 + gtxstatus.d32 =
25151 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
25152 +
25153 + /* If dedicated FIFO every time flush fifo before enable ep*/
25154 + if (core_if->en_multiple_tx_fifo && core_if->snpsid >= OTG_CORE_REV_3_00a)
25155 + dwc_otg_flush_tx_fifo(core_if, ep->tx_fifo_num);
25156 +
25157 + if (core_if->en_multiple_tx_fifo == 0
25158 + && gtxstatus.b.nptxqspcavail == 0
25159 + && !core_if->dma_enable) {
25160 +#ifdef DEBUG
25161 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25162 + DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
25163 + DWC_READ_REG32(&in_regs->diepctl));
25164 + DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
25165 + deptsiz.d32,
25166 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
25167 + DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n",
25168 + gtxstatus.d32);
25169 +#endif
25170 + return;
25171 + }
25172 +
25173 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25174 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25175 +
25176 + /* Zero Length Packet? */
25177 + if (ep->xfer_len == 0) {
25178 + deptsiz.b.xfersize = 0;
25179 + deptsiz.b.pktcnt = 1;
25180 + } else {
25181 + /* Program the transfer size and packet count
25182 + * as follows: xfersize = N * maxpacket +
25183 + * short_packet pktcnt = N + (short_packet
25184 + * exist ? 1 : 0)
25185 + */
25186 + if (ep->xfer_len > ep->maxpacket) {
25187 + ep->xfer_len = ep->maxpacket;
25188 + deptsiz.b.xfersize = ep->maxpacket;
25189 + } else {
25190 + deptsiz.b.xfersize = ep->xfer_len;
25191 + }
25192 + deptsiz.b.pktcnt = 1;
25193 +
25194 + }
25195 + DWC_DEBUGPL(DBG_PCDV,
25196 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25197 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25198 + deptsiz.d32);
25199 +
25200 + /* Write the DMA register */
25201 + if (core_if->dma_enable) {
25202 + if (core_if->dma_desc_enable == 0) {
25203 + DWC_WRITE_REG32(&in_regs->dieptsiz,
25204 + deptsiz.d32);
25205 +
25206 + DWC_WRITE_REG32(&(in_regs->diepdma),
25207 + (uint32_t) ep->dma_addr);
25208 + } else {
25209 + dma_desc = core_if->dev_if->in_desc_addr;
25210 +
25211 + /** DMA Descriptor Setup */
25212 + dma_desc->status.b.bs = BS_HOST_BUSY;
25213 + dma_desc->status.b.l = 1;
25214 + dma_desc->status.b.ioc = 1;
25215 + dma_desc->status.b.sp =
25216 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
25217 + dma_desc->status.b.bytes = ep->xfer_len;
25218 + dma_desc->buf = ep->dma_addr;
25219 + dma_desc->status.b.sts = 0;
25220 + dma_desc->status.b.bs = BS_HOST_READY;
25221 +
25222 + /** DIEPDMA0 Register write */
25223 + DWC_WRITE_REG32(&in_regs->diepdma,
25224 + core_if->
25225 + dev_if->dma_in_desc_addr);
25226 + }
25227 + } else {
25228 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25229 + }
25230 +
25231 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25232 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25233 + /* EP enable, IN data in FIFO */
25234 + depctl.b.cnak = 1;
25235 + depctl.b.epena = 1;
25236 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25237 +
25238 + /**
25239 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
25240 + * data will be written into the fifo by the ISR.
25241 + */
25242 + if (!core_if->dma_enable) {
25243 + if (core_if->en_multiple_tx_fifo == 0) {
25244 + intr_mask.b.nptxfempty = 1;
25245 + DWC_MODIFY_REG32(&core_if->
25246 + core_global_regs->gintmsk,
25247 + intr_mask.d32, intr_mask.d32);
25248 + } else {
25249 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25250 + if (ep->xfer_len > 0) {
25251 + uint32_t fifoemptymsk = 0;
25252 + fifoemptymsk |= 1 << ep->num;
25253 + DWC_MODIFY_REG32(&core_if->
25254 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25255 + 0, fifoemptymsk);
25256 + }
25257 + }
25258 + }
25259 + } else {
25260 + /* OUT endpoint */
25261 + dwc_otg_dev_out_ep_regs_t *out_regs =
25262 + core_if->dev_if->out_ep_regs[0];
25263 +
25264 + depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
25265 + deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
25266 +
25267 + /* Program the transfer size and packet count as follows:
25268 + * xfersize = N * (maxpacket + 4 - (maxpacket % 4))
25269 + * pktcnt = N */
25270 + /* Zero Length Packet */
25271 + deptsiz.b.xfersize = ep->maxpacket;
25272 + deptsiz.b.pktcnt = 1;
25273 + if (core_if->snpsid >= OTG_CORE_REV_3_00a)
25274 + deptsiz.b.supcnt = 3;
25275 +
25276 + DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n",
25277 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);
25278 +
25279 + if (core_if->dma_enable) {
25280 + if (!core_if->dma_desc_enable) {
25281 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25282 + deptsiz.d32);
25283 +
25284 + DWC_WRITE_REG32(&(out_regs->doepdma),
25285 + (uint32_t) ep->dma_addr);
25286 + } else {
25287 + dma_desc = core_if->dev_if->out_desc_addr;
25288 +
25289 + /** DMA Descriptor Setup */
25290 + dma_desc->status.b.bs = BS_HOST_BUSY;
25291 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
25292 + dma_desc->status.b.mtrf = 0;
25293 + dma_desc->status.b.sr = 0;
25294 + }
25295 + dma_desc->status.b.l = 1;
25296 + dma_desc->status.b.ioc = 1;
25297 + dma_desc->status.b.bytes = ep->maxpacket;
25298 + dma_desc->buf = ep->dma_addr;
25299 + dma_desc->status.b.sts = 0;
25300 + dma_desc->status.b.bs = BS_HOST_READY;
25301 +
25302 + /** DOEPDMA0 Register write */
25303 + DWC_WRITE_REG32(&out_regs->doepdma,
25304 + core_if->dev_if->
25305 + dma_out_desc_addr);
25306 + }
25307 + } else {
25308 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25309 + }
25310 +
25311 + /* EP enable */
25312 + depctl.b.cnak = 1;
25313 + depctl.b.epena = 1;
25314 + DWC_WRITE_REG32(&(out_regs->doepctl), depctl.d32);
25315 + }
25316 +}
25317 +
25318 +/**
25319 + * This function continues control IN transfers started by
25320 + * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
25321 + * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
25322 + * bit for the packet count.
25323 + *
25324 + * @param core_if Programming view of DWC_otg controller.
25325 + * @param ep The EP0 data.
25326 + */
25327 +void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25328 +{
25329 + depctl_data_t depctl;
25330 + deptsiz0_data_t deptsiz;
25331 + gintmsk_data_t intr_mask = {.d32 = 0 };
25332 + dwc_otg_dev_dma_desc_t *dma_desc;
25333 +
25334 + if (ep->is_in == 1) {
25335 + dwc_otg_dev_in_ep_regs_t *in_regs =
25336 + core_if->dev_if->in_ep_regs[0];
25337 + gnptxsts_data_t tx_status = {.d32 = 0 };
25338 +
25339 + tx_status.d32 =
25340 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
25341 + /** @todo Should there be check for room in the Tx
25342 + * Status Queue. If not remove the code above this comment. */
25343 +
25344 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25345 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25346 +
25347 + /* Program the transfer size and packet count
25348 + * as follows: xfersize = N * maxpacket +
25349 + * short_packet pktcnt = N + (short_packet
25350 + * exist ? 1 : 0)
25351 + */
25352 +
25353 + if (core_if->dma_desc_enable == 0) {
25354 + deptsiz.b.xfersize =
25355 + (ep->total_len - ep->xfer_count) >
25356 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
25357 + ep->xfer_count);
25358 + deptsiz.b.pktcnt = 1;
25359 + if (core_if->dma_enable == 0) {
25360 + ep->xfer_len += deptsiz.b.xfersize;
25361 + } else {
25362 + ep->xfer_len = deptsiz.b.xfersize;
25363 + }
25364 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25365 + } else {
25366 + ep->xfer_len =
25367 + (ep->total_len - ep->xfer_count) >
25368 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
25369 + ep->xfer_count);
25370 +
25371 + dma_desc = core_if->dev_if->in_desc_addr;
25372 +
25373 + /** DMA Descriptor Setup */
25374 + dma_desc->status.b.bs = BS_HOST_BUSY;
25375 + dma_desc->status.b.l = 1;
25376 + dma_desc->status.b.ioc = 1;
25377 + dma_desc->status.b.sp =
25378 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
25379 + dma_desc->status.b.bytes = ep->xfer_len;
25380 + dma_desc->buf = ep->dma_addr;
25381 + dma_desc->status.b.sts = 0;
25382 + dma_desc->status.b.bs = BS_HOST_READY;
25383 +
25384 + /** DIEPDMA0 Register write */
25385 + DWC_WRITE_REG32(&in_regs->diepdma,
25386 + core_if->dev_if->dma_in_desc_addr);
25387 + }
25388 +
25389 + DWC_DEBUGPL(DBG_PCDV,
25390 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25391 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25392 + deptsiz.d32);
25393 +
25394 + /* Write the DMA register */
25395 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
25396 + if (core_if->dma_desc_enable == 0)
25397 + DWC_WRITE_REG32(&(in_regs->diepdma),
25398 + (uint32_t) ep->dma_addr);
25399 + }
25400 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25401 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25402 + /* EP enable, IN data in FIFO */
25403 + depctl.b.cnak = 1;
25404 + depctl.b.epena = 1;
25405 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25406 +
25407 + /**
25408 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
25409 + * data will be written into the fifo by the ISR.
25410 + */
25411 + if (!core_if->dma_enable) {
25412 + if (core_if->en_multiple_tx_fifo == 0) {
25413 + /* First clear it from GINTSTS */
25414 + intr_mask.b.nptxfempty = 1;
25415 + DWC_MODIFY_REG32(&core_if->
25416 + core_global_regs->gintmsk,
25417 + intr_mask.d32, intr_mask.d32);
25418 +
25419 + } else {
25420 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25421 + if (ep->xfer_len > 0) {
25422 + uint32_t fifoemptymsk = 0;
25423 + fifoemptymsk |= 1 << ep->num;
25424 + DWC_MODIFY_REG32(&core_if->
25425 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25426 + 0, fifoemptymsk);
25427 + }
25428 + }
25429 + }
25430 + } else {
25431 + dwc_otg_dev_out_ep_regs_t *out_regs =
25432 + core_if->dev_if->out_ep_regs[0];
25433 +
25434 + depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
25435 + deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
25436 +
25437 + /* Program the transfer size and packet count
25438 + * as follows: xfersize = N * maxpacket +
25439 + * short_packet pktcnt = N + (short_packet
25440 + * exist ? 1 : 0)
25441 + */
25442 + deptsiz.b.xfersize = ep->maxpacket;
25443 + deptsiz.b.pktcnt = 1;
25444 +
25445 + if (core_if->dma_desc_enable == 0) {
25446 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25447 + } else {
25448 + dma_desc = core_if->dev_if->out_desc_addr;
25449 +
25450 + /** DMA Descriptor Setup */
25451 + dma_desc->status.b.bs = BS_HOST_BUSY;
25452 + dma_desc->status.b.l = 1;
25453 + dma_desc->status.b.ioc = 1;
25454 + dma_desc->status.b.bytes = ep->maxpacket;
25455 + dma_desc->buf = ep->dma_addr;
25456 + dma_desc->status.b.sts = 0;
25457 + dma_desc->status.b.bs = BS_HOST_READY;
25458 +
25459 + /** DOEPDMA0 Register write */
25460 + DWC_WRITE_REG32(&out_regs->doepdma,
25461 + core_if->dev_if->dma_out_desc_addr);
25462 + }
25463 +
25464 + DWC_DEBUGPL(DBG_PCDV,
25465 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25466 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25467 + deptsiz.d32);
25468 +
25469 + /* Write the DMA register */
25470 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
25471 + if (core_if->dma_desc_enable == 0)
25472 + DWC_WRITE_REG32(&(out_regs->doepdma),
25473 + (uint32_t) ep->dma_addr);
25474 +
25475 + }
25476 +
25477 + /* EP enable, IN data in FIFO */
25478 + depctl.b.cnak = 1;
25479 + depctl.b.epena = 1;
25480 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
25481 +
25482 + }
25483 +}
25484 +
25485 +#ifdef DEBUG
25486 +void dump_msg(const u8 * buf, unsigned int length)
25487 +{
25488 + unsigned int start, num, i;
25489 + char line[52], *p;
25490 +
25491 + if (length >= 512)
25492 + return;
25493 + start = 0;
25494 + while (length > 0) {
25495 + num = length < 16u ? length : 16u;
25496 + p = line;
25497 + for (i = 0; i < num; ++i) {
25498 + if (i == 8)
25499 + *p++ = ' ';
25500 + DWC_SPRINTF(p, " %02x", buf[i]);
25501 + p += 3;
25502 + }
25503 + *p = 0;
25504 + DWC_PRINTF("%6x: %s\n", start, line);
25505 + buf += num;
25506 + start += num;
25507 + length -= num;
25508 + }
25509 +}
25510 +#else
25511 +static inline void dump_msg(const u8 * buf, unsigned int length)
25512 +{
25513 +}
25514 +#endif
25515 +
25516 +/**
25517 + * This function writes a packet into the Tx FIFO associated with the
25518 + * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For
25519 + * periodic EPs the periodic Tx FIFO associated with the EP is written
25520 + * with all packets for the next micro-frame.
25521 + *
25522 + * @param core_if Programming view of DWC_otg controller.
25523 + * @param ep The EP to write packet for.
25524 + * @param dma Indicates if DMA is being used.
25525 + */
25526 +void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep,
25527 + int dma)
25528 +{
25529 + /**
25530 + * The buffer is padded to DWORD on a per packet basis in
25531 + * slave/dma mode if the MPS is not DWORD aligned. The last
25532 + * packet, if short, is also padded to a multiple of DWORD.
25533 + *
25534 + * ep->xfer_buff always starts DWORD aligned in memory and is a
25535 + * multiple of DWORD in length
25536 + *
25537 + * ep->xfer_len can be any number of bytes
25538 + *
25539 + * ep->xfer_count is a multiple of ep->maxpacket until the last
25540 + * packet
25541 + *
25542 + * FIFO access is DWORD */
25543 +
25544 + uint32_t i;
25545 + uint32_t byte_count;
25546 + uint32_t dword_count;
25547 + uint32_t *fifo;
25548 + uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
25549 +
25550 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if,
25551 + ep);
25552 + if (ep->xfer_count >= ep->xfer_len) {
25553 + DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
25554 + return;
25555 + }
25556 +
25557 + /* Find the byte length of the packet either short packet or MPS */
25558 + if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) {
25559 + byte_count = ep->xfer_len - ep->xfer_count;
25560 + } else {
25561 + byte_count = ep->maxpacket;
25562 + }
25563 +
25564 + /* Find the DWORD length, padded by extra bytes as neccessary if MPS
25565 + * is not a multiple of DWORD */
25566 + dword_count = (byte_count + 3) / 4;
25567 +
25568 +#ifdef VERBOSE
25569 + dump_msg(ep->xfer_buff, byte_count);
25570 +#endif
25571 +
25572 + /**@todo NGS Where are the Periodic Tx FIFO addresses
25573 + * intialized? What should this be? */
25574 +
25575 + fifo = core_if->data_fifo[ep->num];
25576 +
25577 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
25578 + fifo, data_buff, *data_buff, byte_count);
25579 +
25580 + if (!dma) {
25581 + for (i = 0; i < dword_count; i++, data_buff++) {
25582 + DWC_WRITE_REG32(fifo, *data_buff);
25583 + }
25584 + }
25585 +
25586 + ep->xfer_count += byte_count;
25587 + ep->xfer_buff += byte_count;
25588 + ep->dma_addr += byte_count;
25589 +}
25590 +
25591 +/**
25592 + * Set the EP STALL.
25593 + *
25594 + * @param core_if Programming view of DWC_otg controller.
25595 + * @param ep The EP to set the stall on.
25596 + */
25597 +void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25598 +{
25599 + depctl_data_t depctl;
25600 + volatile uint32_t *depctl_addr;
25601 +
25602 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
25603 + (ep->is_in ? "IN" : "OUT"));
25604 +
25605 + if (ep->is_in == 1) {
25606 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
25607 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25608 +
25609 + /* set the disable and stall bits */
25610 + if (depctl.b.epena) {
25611 + depctl.b.epdis = 1;
25612 + }
25613 + depctl.b.stall = 1;
25614 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25615 + } else {
25616 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
25617 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25618 +
25619 + /* set the stall bit */
25620 + depctl.b.stall = 1;
25621 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25622 + }
25623 +
25624 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
25625 +
25626 + return;
25627 +}
25628 +
25629 +/**
25630 + * Clear the EP STALL.
25631 + *
25632 + * @param core_if Programming view of DWC_otg controller.
25633 + * @param ep The EP to clear stall from.
25634 + */
25635 +void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25636 +{
25637 + depctl_data_t depctl;
25638 + volatile uint32_t *depctl_addr;
25639 +
25640 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
25641 + (ep->is_in ? "IN" : "OUT"));
25642 +
25643 + if (ep->is_in == 1) {
25644 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
25645 + } else {
25646 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
25647 + }
25648 +
25649 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25650 +
25651 + /* clear the stall bits */
25652 + depctl.b.stall = 0;
25653 +
25654 + /*
25655 + * USB Spec 9.4.5: For endpoints using data toggle, regardless
25656 + * of whether an endpoint has the Halt feature set, a
25657 + * ClearFeature(ENDPOINT_HALT) request always results in the
25658 + * data toggle being reinitialized to DATA0.
25659 + */
25660 + if (ep->type == DWC_OTG_EP_TYPE_INTR ||
25661 + ep->type == DWC_OTG_EP_TYPE_BULK) {
25662 + depctl.b.setd0pid = 1; /* DATA0 */
25663 + }
25664 +
25665 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25666 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
25667 + return;
25668 +}
25669 +
25670 +/**
25671 + * This function reads a packet from the Rx FIFO into the destination
25672 + * buffer. To read SETUP data use dwc_otg_read_setup_packet.
25673 + *
25674 + * @param core_if Programming view of DWC_otg controller.
25675 + * @param dest Destination buffer for the packet.
25676 + * @param bytes Number of bytes to copy to the destination.
25677 + */
25678 +void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
25679 + uint8_t * dest, uint16_t bytes)
25680 +{
25681 + int i;
25682 + int word_count = (bytes + 3) / 4;
25683 +
25684 + volatile uint32_t *fifo = core_if->data_fifo[0];
25685 + uint32_t *data_buff = (uint32_t *) dest;
25686 +
25687 + /**
25688 + * @todo Account for the case where _dest is not dword aligned. This
25689 + * requires reading data from the FIFO into a uint32_t temp buffer,
25690 + * then moving it into the data buffer.
25691 + */
25692 +
25693 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
25694 + core_if, dest, bytes);
25695 +
25696 + for (i = 0; i < word_count; i++, data_buff++) {
25697 + *data_buff = DWC_READ_REG32(fifo);
25698 + }
25699 +
25700 + return;
25701 +}
25702 +
25703 +/**
25704 + * This functions reads the device registers and prints them
25705 + *
25706 + * @param core_if Programming view of DWC_otg controller.
25707 + */
25708 +void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if)
25709 +{
25710 + int i;
25711 + volatile uint32_t *addr;
25712 +
25713 + DWC_PRINTF("Device Global Registers\n");
25714 + addr = &core_if->dev_if->dev_global_regs->dcfg;
25715 + DWC_PRINTF("DCFG @0x%08lX : 0x%08X\n",
25716 + (unsigned long)addr, DWC_READ_REG32(addr));
25717 + addr = &core_if->dev_if->dev_global_regs->dctl;
25718 + DWC_PRINTF("DCTL @0x%08lX : 0x%08X\n",
25719 + (unsigned long)addr, DWC_READ_REG32(addr));
25720 + addr = &core_if->dev_if->dev_global_regs->dsts;
25721 + DWC_PRINTF("DSTS @0x%08lX : 0x%08X\n",
25722 + (unsigned long)addr, DWC_READ_REG32(addr));
25723 + addr = &core_if->dev_if->dev_global_regs->diepmsk;
25724 + DWC_PRINTF("DIEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25725 + DWC_READ_REG32(addr));
25726 + addr = &core_if->dev_if->dev_global_regs->doepmsk;
25727 + DWC_PRINTF("DOEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25728 + DWC_READ_REG32(addr));
25729 + addr = &core_if->dev_if->dev_global_regs->daint;
25730 + DWC_PRINTF("DAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
25731 + DWC_READ_REG32(addr));
25732 + addr = &core_if->dev_if->dev_global_regs->daintmsk;
25733 + DWC_PRINTF("DAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25734 + DWC_READ_REG32(addr));
25735 + addr = &core_if->dev_if->dev_global_regs->dtknqr1;
25736 + DWC_PRINTF("DTKNQR1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25737 + DWC_READ_REG32(addr));
25738 + if (core_if->hwcfg2.b.dev_token_q_depth > 6) {
25739 + addr = &core_if->dev_if->dev_global_regs->dtknqr2;
25740 + DWC_PRINTF("DTKNQR2 @0x%08lX : 0x%08X\n",
25741 + (unsigned long)addr, DWC_READ_REG32(addr));
25742 + }
25743 +
25744 + addr = &core_if->dev_if->dev_global_regs->dvbusdis;
25745 + DWC_PRINTF("DVBUSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
25746 + DWC_READ_REG32(addr));
25747 +
25748 + addr = &core_if->dev_if->dev_global_regs->dvbuspulse;
25749 + DWC_PRINTF("DVBUSPULSE @0x%08lX : 0x%08X\n",
25750 + (unsigned long)addr, DWC_READ_REG32(addr));
25751 +
25752 + addr = &core_if->dev_if->dev_global_regs->dtknqr3_dthrctl;
25753 + DWC_PRINTF("DTKNQR3_DTHRCTL @0x%08lX : 0x%08X\n",
25754 + (unsigned long)addr, DWC_READ_REG32(addr));
25755 +
25756 + if (core_if->hwcfg2.b.dev_token_q_depth > 22) {
25757 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
25758 + DWC_PRINTF("DTKNQR4 @0x%08lX : 0x%08X\n",
25759 + (unsigned long)addr, DWC_READ_REG32(addr));
25760 + }
25761 +
25762 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
25763 + DWC_PRINTF("FIFOEMPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25764 + DWC_READ_REG32(addr));
25765 +
25766 + if (core_if->hwcfg2.b.multi_proc_int) {
25767 +
25768 + addr = &core_if->dev_if->dev_global_regs->deachint;
25769 + DWC_PRINTF("DEACHINT @0x%08lX : 0x%08X\n",
25770 + (unsigned long)addr, DWC_READ_REG32(addr));
25771 + addr = &core_if->dev_if->dev_global_regs->deachintmsk;
25772 + DWC_PRINTF("DEACHINTMSK @0x%08lX : 0x%08X\n",
25773 + (unsigned long)addr, DWC_READ_REG32(addr));
25774 +
25775 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
25776 + addr =
25777 + &core_if->dev_if->
25778 + dev_global_regs->diepeachintmsk[i];
25779 + DWC_PRINTF("DIEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
25780 + i, (unsigned long)addr,
25781 + DWC_READ_REG32(addr));
25782 + }
25783 +
25784 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
25785 + addr =
25786 + &core_if->dev_if->
25787 + dev_global_regs->doepeachintmsk[i];
25788 + DWC_PRINTF("DOEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
25789 + i, (unsigned long)addr,
25790 + DWC_READ_REG32(addr));
25791 + }
25792 + }
25793 +
25794 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
25795 + DWC_PRINTF("Device IN EP %d Registers\n", i);
25796 + addr = &core_if->dev_if->in_ep_regs[i]->diepctl;
25797 + DWC_PRINTF("DIEPCTL @0x%08lX : 0x%08X\n",
25798 + (unsigned long)addr, DWC_READ_REG32(addr));
25799 + addr = &core_if->dev_if->in_ep_regs[i]->diepint;
25800 + DWC_PRINTF("DIEPINT @0x%08lX : 0x%08X\n",
25801 + (unsigned long)addr, DWC_READ_REG32(addr));
25802 + addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz;
25803 + DWC_PRINTF("DIETSIZ @0x%08lX : 0x%08X\n",
25804 + (unsigned long)addr, DWC_READ_REG32(addr));
25805 + addr = &core_if->dev_if->in_ep_regs[i]->diepdma;
25806 + DWC_PRINTF("DIEPDMA @0x%08lX : 0x%08X\n",
25807 + (unsigned long)addr, DWC_READ_REG32(addr));
25808 + addr = &core_if->dev_if->in_ep_regs[i]->dtxfsts;
25809 + DWC_PRINTF("DTXFSTS @0x%08lX : 0x%08X\n",
25810 + (unsigned long)addr, DWC_READ_REG32(addr));
25811 + addr = &core_if->dev_if->in_ep_regs[i]->diepdmab;
25812 + DWC_PRINTF("DIEPDMAB @0x%08lX : 0x%08X\n",
25813 + (unsigned long)addr, 0 /*DWC_READ_REG32(addr) */ );
25814 + }
25815 +
25816 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
25817 + DWC_PRINTF("Device OUT EP %d Registers\n", i);
25818 + addr = &core_if->dev_if->out_ep_regs[i]->doepctl;
25819 + DWC_PRINTF("DOEPCTL @0x%08lX : 0x%08X\n",
25820 + (unsigned long)addr, DWC_READ_REG32(addr));
25821 + addr = &core_if->dev_if->out_ep_regs[i]->doepint;
25822 + DWC_PRINTF("DOEPINT @0x%08lX : 0x%08X\n",
25823 + (unsigned long)addr, DWC_READ_REG32(addr));
25824 + addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz;
25825 + DWC_PRINTF("DOETSIZ @0x%08lX : 0x%08X\n",
25826 + (unsigned long)addr, DWC_READ_REG32(addr));
25827 + addr = &core_if->dev_if->out_ep_regs[i]->doepdma;
25828 + DWC_PRINTF("DOEPDMA @0x%08lX : 0x%08X\n",
25829 + (unsigned long)addr, DWC_READ_REG32(addr));
25830 + if (core_if->dma_enable) { /* Don't access this register in SLAVE mode */
25831 + addr = &core_if->dev_if->out_ep_regs[i]->doepdmab;
25832 + DWC_PRINTF("DOEPDMAB @0x%08lX : 0x%08X\n",
25833 + (unsigned long)addr, DWC_READ_REG32(addr));
25834 + }
25835 +
25836 + }
25837 +}
25838 +
25839 +/**
25840 + * This functions reads the SPRAM and prints its content
25841 + *
25842 + * @param core_if Programming view of DWC_otg controller.
25843 + */
25844 +void dwc_otg_dump_spram(dwc_otg_core_if_t * core_if)
25845 +{
25846 + volatile uint8_t *addr, *start_addr, *end_addr;
25847 +
25848 + DWC_PRINTF("SPRAM Data:\n");
25849 + start_addr = (void *)core_if->core_global_regs;
25850 + DWC_PRINTF("Base Address: 0x%8lX\n", (unsigned long)start_addr);
25851 + start_addr += 0x00028000;
25852 + end_addr = (void *)core_if->core_global_regs;
25853 + end_addr += 0x000280e0;
25854 +
25855 + for (addr = start_addr; addr < end_addr; addr += 16) {
25856 + DWC_PRINTF
25857 + ("0x%8lX:\t%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n",
25858 + (unsigned long)addr, addr[0], addr[1], addr[2], addr[3],
25859 + addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
25860 + addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]
25861 + );
25862 + }
25863 +
25864 + return;
25865 +}
25866 +
25867 +/**
25868 + * This function reads the host registers and prints them
25869 + *
25870 + * @param core_if Programming view of DWC_otg controller.
25871 + */
25872 +void dwc_otg_dump_host_registers(dwc_otg_core_if_t * core_if)
25873 +{
25874 + int i;
25875 + volatile uint32_t *addr;
25876 +
25877 + DWC_PRINTF("Host Global Registers\n");
25878 + addr = &core_if->host_if->host_global_regs->hcfg;
25879 + DWC_PRINTF("HCFG @0x%08lX : 0x%08X\n",
25880 + (unsigned long)addr, DWC_READ_REG32(addr));
25881 + addr = &core_if->host_if->host_global_regs->hfir;
25882 + DWC_PRINTF("HFIR @0x%08lX : 0x%08X\n",
25883 + (unsigned long)addr, DWC_READ_REG32(addr));
25884 + addr = &core_if->host_if->host_global_regs->hfnum;
25885 + DWC_PRINTF("HFNUM @0x%08lX : 0x%08X\n", (unsigned long)addr,
25886 + DWC_READ_REG32(addr));
25887 + addr = &core_if->host_if->host_global_regs->hptxsts;
25888 + DWC_PRINTF("HPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
25889 + DWC_READ_REG32(addr));
25890 + addr = &core_if->host_if->host_global_regs->haint;
25891 + DWC_PRINTF("HAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
25892 + DWC_READ_REG32(addr));
25893 + addr = &core_if->host_if->host_global_regs->haintmsk;
25894 + DWC_PRINTF("HAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25895 + DWC_READ_REG32(addr));
25896 + if (core_if->dma_desc_enable) {
25897 + addr = &core_if->host_if->host_global_regs->hflbaddr;
25898 + DWC_PRINTF("HFLBADDR @0x%08lX : 0x%08X\n",
25899 + (unsigned long)addr, DWC_READ_REG32(addr));
25900 + }
25901 +
25902 + addr = core_if->host_if->hprt0;
25903 + DWC_PRINTF("HPRT0 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25904 + DWC_READ_REG32(addr));
25905 +
25906 + for (i = 0; i < core_if->core_params->host_channels; i++) {
25907 + DWC_PRINTF("Host Channel %d Specific Registers\n", i);
25908 + addr = &core_if->host_if->hc_regs[i]->hcchar;
25909 + DWC_PRINTF("HCCHAR @0x%08lX : 0x%08X\n",
25910 + (unsigned long)addr, DWC_READ_REG32(addr));
25911 + addr = &core_if->host_if->hc_regs[i]->hcsplt;
25912 + DWC_PRINTF("HCSPLT @0x%08lX : 0x%08X\n",
25913 + (unsigned long)addr, DWC_READ_REG32(addr));
25914 + addr = &core_if->host_if->hc_regs[i]->hcint;
25915 + DWC_PRINTF("HCINT @0x%08lX : 0x%08X\n",
25916 + (unsigned long)addr, DWC_READ_REG32(addr));
25917 + addr = &core_if->host_if->hc_regs[i]->hcintmsk;
25918 + DWC_PRINTF("HCINTMSK @0x%08lX : 0x%08X\n",
25919 + (unsigned long)addr, DWC_READ_REG32(addr));
25920 + addr = &core_if->host_if->hc_regs[i]->hctsiz;
25921 + DWC_PRINTF("HCTSIZ @0x%08lX : 0x%08X\n",
25922 + (unsigned long)addr, DWC_READ_REG32(addr));
25923 + addr = &core_if->host_if->hc_regs[i]->hcdma;
25924 + DWC_PRINTF("HCDMA @0x%08lX : 0x%08X\n",
25925 + (unsigned long)addr, DWC_READ_REG32(addr));
25926 + if (core_if->dma_desc_enable) {
25927 + addr = &core_if->host_if->hc_regs[i]->hcdmab;
25928 + DWC_PRINTF("HCDMAB @0x%08lX : 0x%08X\n",
25929 + (unsigned long)addr, DWC_READ_REG32(addr));
25930 + }
25931 +
25932 + }
25933 + return;
25934 +}
25935 +
25936 +/**
25937 + * This function reads the core global registers and prints them
25938 + *
25939 + * @param core_if Programming view of DWC_otg controller.
25940 + */
25941 +void dwc_otg_dump_global_registers(dwc_otg_core_if_t * core_if)
25942 +{
25943 + int i, ep_num;
25944 + volatile uint32_t *addr;
25945 + char *txfsiz;
25946 +
25947 + DWC_PRINTF("Core Global Registers\n");
25948 + addr = &core_if->core_global_regs->gotgctl;
25949 + DWC_PRINTF("GOTGCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25950 + DWC_READ_REG32(addr));
25951 + addr = &core_if->core_global_regs->gotgint;
25952 + DWC_PRINTF("GOTGINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
25953 + DWC_READ_REG32(addr));
25954 + addr = &core_if->core_global_regs->gahbcfg;
25955 + DWC_PRINTF("GAHBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
25956 + DWC_READ_REG32(addr));
25957 + addr = &core_if->core_global_regs->gusbcfg;
25958 + DWC_PRINTF("GUSBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
25959 + DWC_READ_REG32(addr));
25960 + addr = &core_if->core_global_regs->grstctl;
25961 + DWC_PRINTF("GRSTCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25962 + DWC_READ_REG32(addr));
25963 + addr = &core_if->core_global_regs->gintsts;
25964 + DWC_PRINTF("GINTSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
25965 + DWC_READ_REG32(addr));
25966 + addr = &core_if->core_global_regs->gintmsk;
25967 + DWC_PRINTF("GINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25968 + DWC_READ_REG32(addr));
25969 + addr = &core_if->core_global_regs->grxstsr;
25970 + DWC_PRINTF("GRXSTSR @0x%08lX : 0x%08X\n", (unsigned long)addr,
25971 + DWC_READ_REG32(addr));
25972 + addr = &core_if->core_global_regs->grxfsiz;
25973 + DWC_PRINTF("GRXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
25974 + DWC_READ_REG32(addr));
25975 + addr = &core_if->core_global_regs->gnptxfsiz;
25976 + DWC_PRINTF("GNPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
25977 + DWC_READ_REG32(addr));
25978 + addr = &core_if->core_global_regs->gnptxsts;
25979 + DWC_PRINTF("GNPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
25980 + DWC_READ_REG32(addr));
25981 + addr = &core_if->core_global_regs->gi2cctl;
25982 + DWC_PRINTF("GI2CCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25983 + DWC_READ_REG32(addr));
25984 + addr = &core_if->core_global_regs->gpvndctl;
25985 + DWC_PRINTF("GPVNDCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25986 + DWC_READ_REG32(addr));
25987 + addr = &core_if->core_global_regs->ggpio;
25988 + DWC_PRINTF("GGPIO @0x%08lX : 0x%08X\n", (unsigned long)addr,
25989 + DWC_READ_REG32(addr));
25990 + addr = &core_if->core_global_regs->guid;
25991 + DWC_PRINTF("GUID @0x%08lX : 0x%08X\n",
25992 + (unsigned long)addr, DWC_READ_REG32(addr));
25993 + addr = &core_if->core_global_regs->gsnpsid;
25994 + DWC_PRINTF("GSNPSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
25995 + DWC_READ_REG32(addr));
25996 + addr = &core_if->core_global_regs->ghwcfg1;
25997 + DWC_PRINTF("GHWCFG1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25998 + DWC_READ_REG32(addr));
25999 + addr = &core_if->core_global_regs->ghwcfg2;
26000 + DWC_PRINTF("GHWCFG2 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26001 + DWC_READ_REG32(addr));
26002 + addr = &core_if->core_global_regs->ghwcfg3;
26003 + DWC_PRINTF("GHWCFG3 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26004 + DWC_READ_REG32(addr));
26005 + addr = &core_if->core_global_regs->ghwcfg4;
26006 + DWC_PRINTF("GHWCFG4 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26007 + DWC_READ_REG32(addr));
26008 + addr = &core_if->core_global_regs->glpmcfg;
26009 + DWC_PRINTF("GLPMCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
26010 + DWC_READ_REG32(addr));
26011 + addr = &core_if->core_global_regs->gpwrdn;
26012 + DWC_PRINTF("GPWRDN @0x%08lX : 0x%08X\n", (unsigned long)addr,
26013 + DWC_READ_REG32(addr));
26014 + addr = &core_if->core_global_regs->gdfifocfg;
26015 + DWC_PRINTF("GDFIFOCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
26016 + DWC_READ_REG32(addr));
26017 + addr = &core_if->core_global_regs->adpctl;
26018 + DWC_PRINTF("ADPCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26019 + dwc_otg_adp_read_reg(core_if));
26020 + addr = &core_if->core_global_regs->hptxfsiz;
26021 + DWC_PRINTF("HPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
26022 + DWC_READ_REG32(addr));
26023 +
26024 + if (core_if->en_multiple_tx_fifo == 0) {
26025 + ep_num = core_if->hwcfg4.b.num_dev_perio_in_ep;
26026 + txfsiz = "DPTXFSIZ";
26027 + } else {
26028 + ep_num = core_if->hwcfg4.b.num_in_eps;
26029 + txfsiz = "DIENPTXF";
26030 + }
26031 + for (i = 0; i < ep_num; i++) {
26032 + addr = &core_if->core_global_regs->dtxfsiz[i];
26033 + DWC_PRINTF("%s[%d] @0x%08lX : 0x%08X\n", txfsiz, i + 1,
26034 + (unsigned long)addr, DWC_READ_REG32(addr));
26035 + }
26036 + addr = core_if->pcgcctl;
26037 + DWC_PRINTF("PCGCCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26038 + DWC_READ_REG32(addr));
26039 +}
26040 +
26041 +/**
26042 + * Flush a Tx FIFO.
26043 + *
26044 + * @param core_if Programming view of DWC_otg controller.
26045 + * @param num Tx FIFO to flush.
26046 + */
26047 +void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * core_if, const int num)
26048 +{
26049 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26050 + volatile grstctl_t greset = {.d32 = 0 };
26051 + int count = 0;
26052 +
26053 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", num);
26054 +
26055 + greset.b.txfflsh = 1;
26056 + greset.b.txfnum = num;
26057 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26058 +
26059 + do {
26060 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26061 + if (++count > 10000) {
26062 + DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
26063 + __func__, greset.d32,
26064 + DWC_READ_REG32(&global_regs->gnptxsts));
26065 + break;
26066 + }
26067 + dwc_udelay(1);
26068 + } while (greset.b.txfflsh == 1);
26069 +
26070 + /* Wait for 3 PHY Clocks */
26071 + dwc_udelay(1);
26072 +}
26073 +
26074 +/**
26075 + * Flush Rx FIFO.
26076 + *
26077 + * @param core_if Programming view of DWC_otg controller.
26078 + */
26079 +void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * core_if)
26080 +{
26081 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26082 + volatile grstctl_t greset = {.d32 = 0 };
26083 + int count = 0;
26084 +
26085 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__);
26086 + /*
26087 + *
26088 + */
26089 + greset.b.rxfflsh = 1;
26090 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26091 +
26092 + do {
26093 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26094 + if (++count > 10000) {
26095 + DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
26096 + greset.d32);
26097 + break;
26098 + }
26099 + dwc_udelay(1);
26100 + } while (greset.b.rxfflsh == 1);
26101 +
26102 + /* Wait for 3 PHY Clocks */
26103 + dwc_udelay(1);
26104 +}
26105 +
26106 +/**
26107 + * Do core a soft reset of the core. Be careful with this because it
26108 + * resets all the internal state machines of the core.
26109 + */
26110 +void dwc_otg_core_reset(dwc_otg_core_if_t * core_if)
26111 +{
26112 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26113 + volatile grstctl_t greset = {.d32 = 0 };
26114 + int count = 0;
26115 +
26116 + DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
26117 + /* Wait for AHB master IDLE state. */
26118 + do {
26119 + dwc_udelay(10);
26120 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26121 + if (++count > 100000) {
26122 + DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
26123 + greset.d32);
26124 + return;
26125 + }
26126 + }
26127 + while (greset.b.ahbidle == 0);
26128 +
26129 + /* Core Soft Reset */
26130 + count = 0;
26131 + greset.b.csftrst = 1;
26132 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26133 + do {
26134 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26135 + if (++count > 10000) {
26136 + DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n",
26137 + __func__, greset.d32);
26138 + break;
26139 + }
26140 + dwc_udelay(1);
26141 + }
26142 + while (greset.b.csftrst == 1);
26143 +
26144 + /* Wait for 3 PHY Clocks */
26145 + dwc_mdelay(100);
26146 +}
26147 +
26148 +uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if)
26149 +{
26150 + return (dwc_otg_mode(_core_if) != DWC_HOST_MODE);
26151 +}
26152 +
26153 +uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if)
26154 +{
26155 + return (dwc_otg_mode(_core_if) == DWC_HOST_MODE);
26156 +}
26157 +
26158 +/**
26159 + * Register HCD callbacks. The callbacks are used to start and stop
26160 + * the HCD for interrupt processing.
26161 + *
26162 + * @param core_if Programming view of DWC_otg controller.
26163 + * @param cb the HCD callback structure.
26164 + * @param p pointer to be passed to callback function (usb_hcd*).
26165 + */
26166 +void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * core_if,
26167 + dwc_otg_cil_callbacks_t * cb, void *p)
26168 +{
26169 + core_if->hcd_cb = cb;
26170 + cb->p = p;
26171 +}
26172 +
26173 +/**
26174 + * Register PCD callbacks. The callbacks are used to start and stop
26175 + * the PCD for interrupt processing.
26176 + *
26177 + * @param core_if Programming view of DWC_otg controller.
26178 + * @param cb the PCD callback structure.
26179 + * @param p pointer to be passed to callback function (pcd*).
26180 + */
26181 +void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * core_if,
26182 + dwc_otg_cil_callbacks_t * cb, void *p)
26183 +{
26184 + core_if->pcd_cb = cb;
26185 + cb->p = p;
26186 +}
26187 +
26188 +#ifdef DWC_EN_ISOC
26189 +
26190 +/**
26191 + * This function writes isoc data per 1 (micro)frame into tx fifo
26192 + *
26193 + * @param core_if Programming view of DWC_otg controller.
26194 + * @param ep The EP to start the transfer on.
26195 + *
26196 + */
26197 +void write_isoc_frame_data(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
26198 +{
26199 + dwc_otg_dev_in_ep_regs_t *ep_regs;
26200 + dtxfsts_data_t txstatus = {.d32 = 0 };
26201 + uint32_t len = 0;
26202 + uint32_t dwords;
26203 +
26204 + ep->xfer_len = ep->data_per_frame;
26205 + ep->xfer_count = 0;
26206 +
26207 + ep_regs = core_if->dev_if->in_ep_regs[ep->num];
26208 +
26209 + len = ep->xfer_len - ep->xfer_count;
26210 +
26211 + if (len > ep->maxpacket) {
26212 + len = ep->maxpacket;
26213 + }
26214 +
26215 + dwords = (len + 3) / 4;
26216 +
26217 + /* While there is space in the queue and space in the FIFO and
26218 + * More data to tranfer, Write packets to the Tx FIFO */
26219 + txstatus.d32 =
26220 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dtxfsts);
26221 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", ep->num, txstatus.d32);
26222 +
26223 + while (txstatus.b.txfspcavail > dwords &&
26224 + ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) {
26225 + /* Write the FIFO */
26226 + dwc_otg_ep_write_packet(core_if, ep, 0);
26227 +
26228 + len = ep->xfer_len - ep->xfer_count;
26229 + if (len > ep->maxpacket) {
26230 + len = ep->maxpacket;
26231 + }
26232 +
26233 + dwords = (len + 3) / 4;
26234 + txstatus.d32 =
26235 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
26236 + dtxfsts);
26237 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", ep->num,
26238 + txstatus.d32);
26239 + }
26240 +}
26241 +
26242 +/**
26243 + * This function initializes a descriptor chain for Isochronous transfer
26244 + *
26245 + * @param core_if Programming view of DWC_otg controller.
26246 + * @param ep The EP to start the transfer on.
26247 + *
26248 + */
26249 +void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
26250 + dwc_ep_t * ep)
26251 +{
26252 + deptsiz_data_t deptsiz = {.d32 = 0 };
26253 + depctl_data_t depctl = {.d32 = 0 };
26254 + dsts_data_t dsts = {.d32 = 0 };
26255 + volatile uint32_t *addr;
26256 +
26257 + if (ep->is_in) {
26258 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
26259 + } else {
26260 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
26261 + }
26262 +
26263 + ep->xfer_len = ep->data_per_frame;
26264 + ep->xfer_count = 0;
26265 + ep->xfer_buff = ep->cur_pkt_addr;
26266 + ep->dma_addr = ep->cur_pkt_dma_addr;
26267 +
26268 + if (ep->is_in) {
26269 + /* Program the transfer size and packet count
26270 + * as follows: xfersize = N * maxpacket +
26271 + * short_packet pktcnt = N + (short_packet
26272 + * exist ? 1 : 0)
26273 + */
26274 + deptsiz.b.xfersize = ep->xfer_len;
26275 + deptsiz.b.pktcnt =
26276 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
26277 + deptsiz.b.mc = deptsiz.b.pktcnt;
26278 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dieptsiz,
26279 + deptsiz.d32);
26280 +
26281 + /* Write the DMA register */
26282 + if (core_if->dma_enable) {
26283 + DWC_WRITE_REG32(&
26284 + (core_if->dev_if->in_ep_regs[ep->num]->
26285 + diepdma), (uint32_t) ep->dma_addr);
26286 + }
26287 + } else {
26288 + deptsiz.b.pktcnt =
26289 + (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket;
26290 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
26291 +
26292 + DWC_WRITE_REG32(&core_if->dev_if->
26293 + out_ep_regs[ep->num]->doeptsiz, deptsiz.d32);
26294 +
26295 + if (core_if->dma_enable) {
26296 + DWC_WRITE_REG32(&
26297 + (core_if->dev_if->
26298 + out_ep_regs[ep->num]->doepdma),
26299 + (uint32_t) ep->dma_addr);
26300 + }
26301 + }
26302 +
26303 + /** Enable endpoint, clear nak */
26304 +
26305 + depctl.d32 = 0;
26306 + if (ep->bInterval == 1) {
26307 + dsts.d32 =
26308 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
26309 + ep->next_frame = dsts.b.soffn + ep->bInterval;
26310 +
26311 + if (ep->next_frame & 0x1) {
26312 + depctl.b.setd1pid = 1;
26313 + } else {
26314 + depctl.b.setd0pid = 1;
26315 + }
26316 + } else {
26317 + ep->next_frame += ep->bInterval;
26318 +
26319 + if (ep->next_frame & 0x1) {
26320 + depctl.b.setd1pid = 1;
26321 + } else {
26322 + depctl.b.setd0pid = 1;
26323 + }
26324 + }
26325 + depctl.b.epena = 1;
26326 + depctl.b.cnak = 1;
26327 +
26328 + DWC_MODIFY_REG32(addr, 0, depctl.d32);
26329 + depctl.d32 = DWC_READ_REG32(addr);
26330 +
26331 + if (ep->is_in && core_if->dma_enable == 0) {
26332 + write_isoc_frame_data(core_if, ep);
26333 + }
26334 +
26335 +}
26336 +#endif /* DWC_EN_ISOC */
26337 +
26338 +static void dwc_otg_set_uninitialized(int32_t * p, int size)
26339 +{
26340 + int i;
26341 + for (i = 0; i < size; i++) {
26342 + p[i] = -1;
26343 + }
26344 +}
26345 +
26346 +static int dwc_otg_param_initialized(int32_t val)
26347 +{
26348 + return val != -1;
26349 +}
26350 +
26351 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if)
26352 +{
26353 + int i;
26354 + core_if->core_params = DWC_ALLOC(sizeof(*core_if->core_params));
26355 + if (!core_if->core_params) {
26356 + return -DWC_E_NO_MEMORY;
26357 + }
26358 + dwc_otg_set_uninitialized((int32_t *) core_if->core_params,
26359 + sizeof(*core_if->core_params) /
26360 + sizeof(int32_t));
26361 + DWC_PRINTF("Setting default values for core params\n");
26362 + dwc_otg_set_param_otg_cap(core_if, dwc_param_otg_cap_default);
26363 + dwc_otg_set_param_dma_enable(core_if, dwc_param_dma_enable_default);
26364 + dwc_otg_set_param_dma_desc_enable(core_if,
26365 + dwc_param_dma_desc_enable_default);
26366 + dwc_otg_set_param_opt(core_if, dwc_param_opt_default);
26367 + dwc_otg_set_param_dma_burst_size(core_if,
26368 + dwc_param_dma_burst_size_default);
26369 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
26370 + dwc_param_host_support_fs_ls_low_power_default);
26371 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
26372 + dwc_param_enable_dynamic_fifo_default);
26373 + dwc_otg_set_param_data_fifo_size(core_if,
26374 + dwc_param_data_fifo_size_default);
26375 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
26376 + dwc_param_dev_rx_fifo_size_default);
26377 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
26378 + dwc_param_dev_nperio_tx_fifo_size_default);
26379 + dwc_otg_set_param_host_rx_fifo_size(core_if,
26380 + dwc_param_host_rx_fifo_size_default);
26381 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
26382 + dwc_param_host_nperio_tx_fifo_size_default);
26383 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
26384 + dwc_param_host_perio_tx_fifo_size_default);
26385 + dwc_otg_set_param_max_transfer_size(core_if,
26386 + dwc_param_max_transfer_size_default);
26387 + dwc_otg_set_param_max_packet_count(core_if,
26388 + dwc_param_max_packet_count_default);
26389 + dwc_otg_set_param_host_channels(core_if,
26390 + dwc_param_host_channels_default);
26391 + dwc_otg_set_param_dev_endpoints(core_if,
26392 + dwc_param_dev_endpoints_default);
26393 + dwc_otg_set_param_phy_type(core_if, dwc_param_phy_type_default);
26394 + dwc_otg_set_param_speed(core_if, dwc_param_speed_default);
26395 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
26396 + dwc_param_host_ls_low_power_phy_clk_default);
26397 + dwc_otg_set_param_phy_ulpi_ddr(core_if, dwc_param_phy_ulpi_ddr_default);
26398 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
26399 + dwc_param_phy_ulpi_ext_vbus_default);
26400 + dwc_otg_set_param_phy_utmi_width(core_if,
26401 + dwc_param_phy_utmi_width_default);
26402 + dwc_otg_set_param_ts_dline(core_if, dwc_param_ts_dline_default);
26403 + dwc_otg_set_param_i2c_enable(core_if, dwc_param_i2c_enable_default);
26404 + dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_param_ulpi_fs_ls_default);
26405 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
26406 + dwc_param_en_multiple_tx_fifo_default);
26407 + for (i = 0; i < 15; i++) {
26408 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
26409 + dwc_param_dev_perio_tx_fifo_size_default,
26410 + i);
26411 + }
26412 +
26413 + for (i = 0; i < 15; i++) {
26414 + dwc_otg_set_param_dev_tx_fifo_size(core_if,
26415 + dwc_param_dev_tx_fifo_size_default,
26416 + i);
26417 + }
26418 + dwc_otg_set_param_thr_ctl(core_if, dwc_param_thr_ctl_default);
26419 + dwc_otg_set_param_mpi_enable(core_if, dwc_param_mpi_enable_default);
26420 + dwc_otg_set_param_pti_enable(core_if, dwc_param_pti_enable_default);
26421 + dwc_otg_set_param_lpm_enable(core_if, dwc_param_lpm_enable_default);
26422 + dwc_otg_set_param_ic_usb_cap(core_if, dwc_param_ic_usb_cap_default);
26423 + dwc_otg_set_param_tx_thr_length(core_if,
26424 + dwc_param_tx_thr_length_default);
26425 + dwc_otg_set_param_rx_thr_length(core_if,
26426 + dwc_param_rx_thr_length_default);
26427 + dwc_otg_set_param_ahb_thr_ratio(core_if,
26428 + dwc_param_ahb_thr_ratio_default);
26429 + dwc_otg_set_param_power_down(core_if, dwc_param_power_down_default);
26430 + dwc_otg_set_param_reload_ctl(core_if, dwc_param_reload_ctl_default);
26431 + dwc_otg_set_param_dev_out_nak(core_if, dwc_param_dev_out_nak_default);
26432 + dwc_otg_set_param_cont_on_bna(core_if, dwc_param_cont_on_bna_default);
26433 + dwc_otg_set_param_ahb_single(core_if, dwc_param_ahb_single_default);
26434 + dwc_otg_set_param_otg_ver(core_if, dwc_param_otg_ver_default);
26435 + dwc_otg_set_param_adp_enable(core_if, dwc_param_adp_enable_default);
26436 + DWC_PRINTF("Finished setting default values for core params\n");
26437 +
26438 + return 0;
26439 +}
26440 +
26441 +uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if)
26442 +{
26443 + return core_if->dma_enable;
26444 +}
26445 +
26446 +/* Checks if the parameter is outside of its valid range of values */
26447 +#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \
26448 + (((_param_) < (_low_)) || \
26449 + ((_param_) > (_high_)))
26450 +
26451 +/* Parameter access functions */
26452 +int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val)
26453 +{
26454 + int valid;
26455 + int retval = 0;
26456 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
26457 + DWC_WARN("Wrong value for otg_cap parameter\n");
26458 + DWC_WARN("otg_cap parameter must be 0,1 or 2\n");
26459 + retval = -DWC_E_INVALID;
26460 + goto out;
26461 + }
26462 +
26463 + valid = 1;
26464 + switch (val) {
26465 + case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
26466 + if (core_if->hwcfg2.b.op_mode !=
26467 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26468 + valid = 0;
26469 + break;
26470 + case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
26471 + if ((core_if->hwcfg2.b.op_mode !=
26472 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26473 + && (core_if->hwcfg2.b.op_mode !=
26474 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
26475 + && (core_if->hwcfg2.b.op_mode !=
26476 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
26477 + && (core_if->hwcfg2.b.op_mode !=
26478 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) {
26479 + valid = 0;
26480 + }
26481 + break;
26482 + case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
26483 + /* always valid */
26484 + break;
26485 + }
26486 + if (!valid) {
26487 + if (dwc_otg_param_initialized(core_if->core_params->otg_cap)) {
26488 + DWC_ERROR
26489 + ("%d invalid for otg_cap paremter. Check HW configuration.\n",
26490 + val);
26491 + }
26492 + val =
26493 + (((core_if->hwcfg2.b.op_mode ==
26494 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26495 + || (core_if->hwcfg2.b.op_mode ==
26496 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
26497 + || (core_if->hwcfg2.b.op_mode ==
26498 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
26499 + || (core_if->hwcfg2.b.op_mode ==
26500 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ?
26501 + DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE :
26502 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
26503 + retval = -DWC_E_INVALID;
26504 + }
26505 +
26506 + core_if->core_params->otg_cap = val;
26507 +out:
26508 + return retval;
26509 +}
26510 +
26511 +int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if)
26512 +{
26513 + return core_if->core_params->otg_cap;
26514 +}
26515 +
26516 +int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val)
26517 +{
26518 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26519 + DWC_WARN("Wrong value for opt parameter\n");
26520 + return -DWC_E_INVALID;
26521 + }
26522 + core_if->core_params->opt = val;
26523 + return 0;
26524 +}
26525 +
26526 +int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if)
26527 +{
26528 + return core_if->core_params->opt;
26529 +}
26530 +
26531 +int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, int32_t val)
26532 +{
26533 + int retval = 0;
26534 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26535 + DWC_WARN("Wrong value for dma enable\n");
26536 + return -DWC_E_INVALID;
26537 + }
26538 +
26539 + if ((val == 1) && (core_if->hwcfg2.b.architecture == 0)) {
26540 + if (dwc_otg_param_initialized(core_if->core_params->dma_enable)) {
26541 + DWC_ERROR
26542 + ("%d invalid for dma_enable paremter. Check HW configuration.\n",
26543 + val);
26544 + }
26545 + val = 0;
26546 + retval = -DWC_E_INVALID;
26547 + }
26548 +
26549 + core_if->core_params->dma_enable = val;
26550 + if (val == 0) {
26551 + dwc_otg_set_param_dma_desc_enable(core_if, 0);
26552 + }
26553 + return retval;
26554 +}
26555 +
26556 +int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if)
26557 +{
26558 + return core_if->core_params->dma_enable;
26559 +}
26560 +
26561 +int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, int32_t val)
26562 +{
26563 + int retval = 0;
26564 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26565 + DWC_WARN("Wrong value for dma_enable\n");
26566 + DWC_WARN("dma_desc_enable must be 0 or 1\n");
26567 + return -DWC_E_INVALID;
26568 + }
26569 +
26570 + if ((val == 1)
26571 + && ((dwc_otg_get_param_dma_enable(core_if) == 0)
26572 + || (core_if->hwcfg4.b.desc_dma == 0))) {
26573 + if (dwc_otg_param_initialized
26574 + (core_if->core_params->dma_desc_enable)) {
26575 + DWC_ERROR
26576 + ("%d invalid for dma_desc_enable paremter. Check HW configuration.\n",
26577 + val);
26578 + }
26579 + val = 0;
26580 + retval = -DWC_E_INVALID;
26581 + }
26582 + core_if->core_params->dma_desc_enable = val;
26583 + return retval;
26584 +}
26585 +
26586 +int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if)
26587 +{
26588 + return core_if->core_params->dma_desc_enable;
26589 +}
26590 +
26591 +int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * core_if,
26592 + int32_t val)
26593 +{
26594 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26595 + DWC_WARN("Wrong value for host_support_fs_low_power\n");
26596 + DWC_WARN("host_support_fs_low_power must be 0 or 1\n");
26597 + return -DWC_E_INVALID;
26598 + }
26599 + core_if->core_params->host_support_fs_ls_low_power = val;
26600 + return 0;
26601 +}
26602 +
26603 +int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
26604 + core_if)
26605 +{
26606 + return core_if->core_params->host_support_fs_ls_low_power;
26607 +}
26608 +
26609 +int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
26610 + int32_t val)
26611 +{
26612 + int retval = 0;
26613 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26614 + DWC_WARN("Wrong value for enable_dynamic_fifo\n");
26615 + DWC_WARN("enable_dynamic_fifo must be 0 or 1\n");
26616 + return -DWC_E_INVALID;
26617 + }
26618 +
26619 + if ((val == 1) && (core_if->hwcfg2.b.dynamic_fifo == 0)) {
26620 + if (dwc_otg_param_initialized
26621 + (core_if->core_params->enable_dynamic_fifo)) {
26622 + DWC_ERROR
26623 + ("%d invalid for enable_dynamic_fifo paremter. Check HW configuration.\n",
26624 + val);
26625 + }
26626 + val = 0;
26627 + retval = -DWC_E_INVALID;
26628 + }
26629 + core_if->core_params->enable_dynamic_fifo = val;
26630 + return retval;
26631 +}
26632 +
26633 +int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if)
26634 +{
26635 + return core_if->core_params->enable_dynamic_fifo;
26636 +}
26637 +
26638 +int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
26639 +{
26640 + int retval = 0;
26641 + if (DWC_OTG_PARAM_TEST(val, 32, 32768)) {
26642 + DWC_WARN("Wrong value for data_fifo_size\n");
26643 + DWC_WARN("data_fifo_size must be 32-32768\n");
26644 + return -DWC_E_INVALID;
26645 + }
26646 +
26647 + if (val > core_if->hwcfg3.b.dfifo_depth) {
26648 + if (dwc_otg_param_initialized
26649 + (core_if->core_params->data_fifo_size)) {
26650 + DWC_ERROR
26651 + ("%d invalid for data_fifo_size parameter. Check HW configuration.\n",
26652 + val);
26653 + }
26654 + val = core_if->hwcfg3.b.dfifo_depth;
26655 + retval = -DWC_E_INVALID;
26656 + }
26657 +
26658 + core_if->core_params->data_fifo_size = val;
26659 + return retval;
26660 +}
26661 +
26662 +int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if)
26663 +{
26664 + return core_if->core_params->data_fifo_size;
26665 +}
26666 +
26667 +int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
26668 +{
26669 + int retval = 0;
26670 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26671 + DWC_WARN("Wrong value for dev_rx_fifo_size\n");
26672 + DWC_WARN("dev_rx_fifo_size must be 16-32768\n");
26673 + return -DWC_E_INVALID;
26674 + }
26675 +
26676 + if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
26677 + if (dwc_otg_param_initialized(core_if->core_params->dev_rx_fifo_size)) {
26678 + DWC_WARN("%d invalid for dev_rx_fifo_size parameter\n", val);
26679 + }
26680 + val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
26681 + retval = -DWC_E_INVALID;
26682 + }
26683 +
26684 + core_if->core_params->dev_rx_fifo_size = val;
26685 + return retval;
26686 +}
26687 +
26688 +int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if)
26689 +{
26690 + return core_if->core_params->dev_rx_fifo_size;
26691 +}
26692 +
26693 +int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26694 + int32_t val)
26695 +{
26696 + int retval = 0;
26697 +
26698 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26699 + DWC_WARN("Wrong value for dev_nperio_tx_fifo\n");
26700 + DWC_WARN("dev_nperio_tx_fifo must be 16-32768\n");
26701 + return -DWC_E_INVALID;
26702 + }
26703 +
26704 + if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
26705 + if (dwc_otg_param_initialized
26706 + (core_if->core_params->dev_nperio_tx_fifo_size)) {
26707 + DWC_ERROR
26708 + ("%d invalid for dev_nperio_tx_fifo_size. Check HW configuration.\n",
26709 + val);
26710 + }
26711 + val =
26712 + (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
26713 + 16);
26714 + retval = -DWC_E_INVALID;
26715 + }
26716 +
26717 + core_if->core_params->dev_nperio_tx_fifo_size = val;
26718 + return retval;
26719 +}
26720 +
26721 +int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26722 +{
26723 + return core_if->core_params->dev_nperio_tx_fifo_size;
26724 +}
26725 +
26726 +int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
26727 + int32_t val)
26728 +{
26729 + int retval = 0;
26730 +
26731 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26732 + DWC_WARN("Wrong value for host_rx_fifo_size\n");
26733 + DWC_WARN("host_rx_fifo_size must be 16-32768\n");
26734 + return -DWC_E_INVALID;
26735 + }
26736 +
26737 + if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
26738 + if (dwc_otg_param_initialized
26739 + (core_if->core_params->host_rx_fifo_size)) {
26740 + DWC_ERROR
26741 + ("%d invalid for host_rx_fifo_size. Check HW configuration.\n",
26742 + val);
26743 + }
26744 + val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
26745 + retval = -DWC_E_INVALID;
26746 + }
26747 +
26748 + core_if->core_params->host_rx_fifo_size = val;
26749 + return retval;
26750 +
26751 +}
26752 +
26753 +int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if)
26754 +{
26755 + return core_if->core_params->host_rx_fifo_size;
26756 +}
26757 +
26758 +int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26759 + int32_t val)
26760 +{
26761 + int retval = 0;
26762 +
26763 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26764 + DWC_WARN("Wrong value for host_nperio_tx_fifo_size\n");
26765 + DWC_WARN("host_nperio_tx_fifo_size must be 16-32768\n");
26766 + return -DWC_E_INVALID;
26767 + }
26768 +
26769 + if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
26770 + if (dwc_otg_param_initialized
26771 + (core_if->core_params->host_nperio_tx_fifo_size)) {
26772 + DWC_ERROR
26773 + ("%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
26774 + val);
26775 + }
26776 + val =
26777 + (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
26778 + 16);
26779 + retval = -DWC_E_INVALID;
26780 + }
26781 +
26782 + core_if->core_params->host_nperio_tx_fifo_size = val;
26783 + return retval;
26784 +}
26785 +
26786 +int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26787 +{
26788 + return core_if->core_params->host_nperio_tx_fifo_size;
26789 +}
26790 +
26791 +int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26792 + int32_t val)
26793 +{
26794 + int retval = 0;
26795 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26796 + DWC_WARN("Wrong value for host_perio_tx_fifo_size\n");
26797 + DWC_WARN("host_perio_tx_fifo_size must be 16-32768\n");
26798 + return -DWC_E_INVALID;
26799 + }
26800 +
26801 + if (val > ((core_if->hptxfsiz.d32) >> 16)) {
26802 + if (dwc_otg_param_initialized
26803 + (core_if->core_params->host_perio_tx_fifo_size)) {
26804 + DWC_ERROR
26805 + ("%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
26806 + val);
26807 + }
26808 + val = (core_if->hptxfsiz.d32) >> 16;
26809 + retval = -DWC_E_INVALID;
26810 + }
26811 +
26812 + core_if->core_params->host_perio_tx_fifo_size = val;
26813 + return retval;
26814 +}
26815 +
26816 +int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26817 +{
26818 + return core_if->core_params->host_perio_tx_fifo_size;
26819 +}
26820 +
26821 +int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
26822 + int32_t val)
26823 +{
26824 + int retval = 0;
26825 +
26826 + if (DWC_OTG_PARAM_TEST(val, 2047, 524288)) {
26827 + DWC_WARN("Wrong value for max_transfer_size\n");
26828 + DWC_WARN("max_transfer_size must be 2047-524288\n");
26829 + return -DWC_E_INVALID;
26830 + }
26831 +
26832 + if (val >= (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))) {
26833 + if (dwc_otg_param_initialized
26834 + (core_if->core_params->max_transfer_size)) {
26835 + DWC_ERROR
26836 + ("%d invalid for max_transfer_size. Check HW configuration.\n",
26837 + val);
26838 + }
26839 + val =
26840 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 11)) -
26841 + 1);
26842 + retval = -DWC_E_INVALID;
26843 + }
26844 +
26845 + core_if->core_params->max_transfer_size = val;
26846 + return retval;
26847 +}
26848 +
26849 +int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if)
26850 +{
26851 + return core_if->core_params->max_transfer_size;
26852 +}
26853 +
26854 +int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, int32_t val)
26855 +{
26856 + int retval = 0;
26857 +
26858 + if (DWC_OTG_PARAM_TEST(val, 15, 511)) {
26859 + DWC_WARN("Wrong value for max_packet_count\n");
26860 + DWC_WARN("max_packet_count must be 15-511\n");
26861 + return -DWC_E_INVALID;
26862 + }
26863 +
26864 + if (val > (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))) {
26865 + if (dwc_otg_param_initialized
26866 + (core_if->core_params->max_packet_count)) {
26867 + DWC_ERROR
26868 + ("%d invalid for max_packet_count. Check HW configuration.\n",
26869 + val);
26870 + }
26871 + val =
26872 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1);
26873 + retval = -DWC_E_INVALID;
26874 + }
26875 +
26876 + core_if->core_params->max_packet_count = val;
26877 + return retval;
26878 +}
26879 +
26880 +int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if)
26881 +{
26882 + return core_if->core_params->max_packet_count;
26883 +}
26884 +
26885 +int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, int32_t val)
26886 +{
26887 + int retval = 0;
26888 +
26889 + if (DWC_OTG_PARAM_TEST(val, 1, 16)) {
26890 + DWC_WARN("Wrong value for host_channels\n");
26891 + DWC_WARN("host_channels must be 1-16\n");
26892 + return -DWC_E_INVALID;
26893 + }
26894 +
26895 + if (val > (core_if->hwcfg2.b.num_host_chan + 1)) {
26896 + if (dwc_otg_param_initialized
26897 + (core_if->core_params->host_channels)) {
26898 + DWC_ERROR
26899 + ("%d invalid for host_channels. Check HW configurations.\n",
26900 + val);
26901 + }
26902 + val = (core_if->hwcfg2.b.num_host_chan + 1);
26903 + retval = -DWC_E_INVALID;
26904 + }
26905 +
26906 + core_if->core_params->host_channels = val;
26907 + return retval;
26908 +}
26909 +
26910 +int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if)
26911 +{
26912 + return core_if->core_params->host_channels;
26913 +}
26914 +
26915 +int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, int32_t val)
26916 +{
26917 + int retval = 0;
26918 +
26919 + if (DWC_OTG_PARAM_TEST(val, 1, 15)) {
26920 + DWC_WARN("Wrong value for dev_endpoints\n");
26921 + DWC_WARN("dev_endpoints must be 1-15\n");
26922 + return -DWC_E_INVALID;
26923 + }
26924 +
26925 + if (val > (core_if->hwcfg2.b.num_dev_ep)) {
26926 + if (dwc_otg_param_initialized
26927 + (core_if->core_params->dev_endpoints)) {
26928 + DWC_ERROR
26929 + ("%d invalid for dev_endpoints. Check HW configurations.\n",
26930 + val);
26931 + }
26932 + val = core_if->hwcfg2.b.num_dev_ep;
26933 + retval = -DWC_E_INVALID;
26934 + }
26935 +
26936 + core_if->core_params->dev_endpoints = val;
26937 + return retval;
26938 +}
26939 +
26940 +int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if)
26941 +{
26942 + return core_if->core_params->dev_endpoints;
26943 +}
26944 +
26945 +int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val)
26946 +{
26947 + int retval = 0;
26948 + int valid = 0;
26949 +
26950 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
26951 + DWC_WARN("Wrong value for phy_type\n");
26952 + DWC_WARN("phy_type must be 0,1 or 2\n");
26953 + return -DWC_E_INVALID;
26954 + }
26955 +#ifndef NO_FS_PHY_HW_CHECKS
26956 + if ((val == DWC_PHY_TYPE_PARAM_UTMI) &&
26957 + ((core_if->hwcfg2.b.hs_phy_type == 1) ||
26958 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
26959 + valid = 1;
26960 + } else if ((val == DWC_PHY_TYPE_PARAM_ULPI) &&
26961 + ((core_if->hwcfg2.b.hs_phy_type == 2) ||
26962 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
26963 + valid = 1;
26964 + } else if ((val == DWC_PHY_TYPE_PARAM_FS) &&
26965 + (core_if->hwcfg2.b.fs_phy_type == 1)) {
26966 + valid = 1;
26967 + }
26968 + if (!valid) {
26969 + if (dwc_otg_param_initialized(core_if->core_params->phy_type)) {
26970 + DWC_ERROR
26971 + ("%d invalid for phy_type. Check HW configurations.\n",
26972 + val);
26973 + }
26974 + if (core_if->hwcfg2.b.hs_phy_type) {
26975 + if ((core_if->hwcfg2.b.hs_phy_type == 3) ||
26976 + (core_if->hwcfg2.b.hs_phy_type == 1)) {
26977 + val = DWC_PHY_TYPE_PARAM_UTMI;
26978 + } else {
26979 + val = DWC_PHY_TYPE_PARAM_ULPI;
26980 + }
26981 + }
26982 + retval = -DWC_E_INVALID;
26983 + }
26984 +#endif
26985 + core_if->core_params->phy_type = val;
26986 + return retval;
26987 +}
26988 +
26989 +int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if)
26990 +{
26991 + return core_if->core_params->phy_type;
26992 +}
26993 +
26994 +int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val)
26995 +{
26996 + int retval = 0;
26997 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26998 + DWC_WARN("Wrong value for speed parameter\n");
26999 + DWC_WARN("max_speed parameter must be 0 or 1\n");
27000 + return -DWC_E_INVALID;
27001 + }
27002 + if ((val == 0)
27003 + && dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS) {
27004 + if (dwc_otg_param_initialized(core_if->core_params->speed)) {
27005 + DWC_ERROR
27006 + ("%d invalid for speed paremter. Check HW configuration.\n",
27007 + val);
27008 + }
27009 + val =
27010 + (dwc_otg_get_param_phy_type(core_if) ==
27011 + DWC_PHY_TYPE_PARAM_FS ? 1 : 0);
27012 + retval = -DWC_E_INVALID;
27013 + }
27014 + core_if->core_params->speed = val;
27015 + return retval;
27016 +}
27017 +
27018 +int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if)
27019 +{
27020 + return core_if->core_params->speed;
27021 +}
27022 +
27023 +int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if,
27024 + int32_t val)
27025 +{
27026 + int retval = 0;
27027 +
27028 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27029 + DWC_WARN
27030 + ("Wrong value for host_ls_low_power_phy_clk parameter\n");
27031 + DWC_WARN("host_ls_low_power_phy_clk must be 0 or 1\n");
27032 + return -DWC_E_INVALID;
27033 + }
27034 +
27035 + if ((val == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)
27036 + && (dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS)) {
27037 + if (dwc_otg_param_initialized
27038 + (core_if->core_params->host_ls_low_power_phy_clk)) {
27039 + DWC_ERROR
27040 + ("%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
27041 + val);
27042 + }
27043 + val =
27044 + (dwc_otg_get_param_phy_type(core_if) ==
27045 + DWC_PHY_TYPE_PARAM_FS) ?
27046 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ :
27047 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
27048 + retval = -DWC_E_INVALID;
27049 + }
27050 +
27051 + core_if->core_params->host_ls_low_power_phy_clk = val;
27052 + return retval;
27053 +}
27054 +
27055 +int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if)
27056 +{
27057 + return core_if->core_params->host_ls_low_power_phy_clk;
27058 +}
27059 +
27060 +int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, int32_t val)
27061 +{
27062 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27063 + DWC_WARN("Wrong value for phy_ulpi_ddr\n");
27064 + DWC_WARN("phy_upli_ddr must be 0 or 1\n");
27065 + return -DWC_E_INVALID;
27066 + }
27067 +
27068 + core_if->core_params->phy_ulpi_ddr = val;
27069 + return 0;
27070 +}
27071 +
27072 +int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if)
27073 +{
27074 + return core_if->core_params->phy_ulpi_ddr;
27075 +}
27076 +
27077 +int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
27078 + int32_t val)
27079 +{
27080 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27081 + DWC_WARN("Wrong valaue for phy_ulpi_ext_vbus\n");
27082 + DWC_WARN("phy_ulpi_ext_vbus must be 0 or 1\n");
27083 + return -DWC_E_INVALID;
27084 + }
27085 +
27086 + core_if->core_params->phy_ulpi_ext_vbus = val;
27087 + return 0;
27088 +}
27089 +
27090 +int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if)
27091 +{
27092 + return core_if->core_params->phy_ulpi_ext_vbus;
27093 +}
27094 +
27095 +int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, int32_t val)
27096 +{
27097 + if (DWC_OTG_PARAM_TEST(val, 8, 8) && DWC_OTG_PARAM_TEST(val, 16, 16)) {
27098 + DWC_WARN("Wrong valaue for phy_utmi_width\n");
27099 + DWC_WARN("phy_utmi_width must be 8 or 16\n");
27100 + return -DWC_E_INVALID;
27101 + }
27102 +
27103 + core_if->core_params->phy_utmi_width = val;
27104 + return 0;
27105 +}
27106 +
27107 +int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if)
27108 +{
27109 + return core_if->core_params->phy_utmi_width;
27110 +}
27111 +
27112 +int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, int32_t val)
27113 +{
27114 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27115 + DWC_WARN("Wrong valaue for ulpi_fs_ls\n");
27116 + DWC_WARN("ulpi_fs_ls must be 0 or 1\n");
27117 + return -DWC_E_INVALID;
27118 + }
27119 +
27120 + core_if->core_params->ulpi_fs_ls = val;
27121 + return 0;
27122 +}
27123 +
27124 +int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if)
27125 +{
27126 + return core_if->core_params->ulpi_fs_ls;
27127 +}
27128 +
27129 +int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val)
27130 +{
27131 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27132 + DWC_WARN("Wrong valaue for ts_dline\n");
27133 + DWC_WARN("ts_dline must be 0 or 1\n");
27134 + return -DWC_E_INVALID;
27135 + }
27136 +
27137 + core_if->core_params->ts_dline = val;
27138 + return 0;
27139 +}
27140 +
27141 +int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if)
27142 +{
27143 + return core_if->core_params->ts_dline;
27144 +}
27145 +
27146 +int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, int32_t val)
27147 +{
27148 + int retval = 0;
27149 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27150 + DWC_WARN("Wrong valaue for i2c_enable\n");
27151 + DWC_WARN("i2c_enable must be 0 or 1\n");
27152 + return -DWC_E_INVALID;
27153 + }
27154 +#ifndef NO_FS_PHY_HW_CHECK
27155 + if (val == 1 && core_if->hwcfg3.b.i2c == 0) {
27156 + if (dwc_otg_param_initialized(core_if->core_params->i2c_enable)) {
27157 + DWC_ERROR
27158 + ("%d invalid for i2c_enable. Check HW configuration.\n",
27159 + val);
27160 + }
27161 + val = 0;
27162 + retval = -DWC_E_INVALID;
27163 + }
27164 +#endif
27165 +
27166 + core_if->core_params->i2c_enable = val;
27167 + return retval;
27168 +}
27169 +
27170 +int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if)
27171 +{
27172 + return core_if->core_params->i2c_enable;
27173 +}
27174 +
27175 +int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
27176 + int32_t val, int fifo_num)
27177 +{
27178 + int retval = 0;
27179 +
27180 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
27181 + DWC_WARN("Wrong value for dev_perio_tx_fifo_size\n");
27182 + DWC_WARN("dev_perio_tx_fifo_size must be 4-768\n");
27183 + return -DWC_E_INVALID;
27184 + }
27185 +
27186 + if (val >
27187 + (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
27188 + if (dwc_otg_param_initialized
27189 + (core_if->core_params->dev_perio_tx_fifo_size[fifo_num])) {
27190 + DWC_ERROR
27191 + ("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n",
27192 + val, fifo_num);
27193 + }
27194 + val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
27195 + retval = -DWC_E_INVALID;
27196 + }
27197 +
27198 + core_if->core_params->dev_perio_tx_fifo_size[fifo_num] = val;
27199 + return retval;
27200 +}
27201 +
27202 +int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
27203 + int fifo_num)
27204 +{
27205 + return core_if->core_params->dev_perio_tx_fifo_size[fifo_num];
27206 +}
27207 +
27208 +int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
27209 + int32_t val)
27210 +{
27211 + int retval = 0;
27212 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27213 + DWC_WARN("Wrong valaue for en_multiple_tx_fifo,\n");
27214 + DWC_WARN("en_multiple_tx_fifo must be 0 or 1\n");
27215 + return -DWC_E_INVALID;
27216 + }
27217 +
27218 + if (val == 1 && core_if->hwcfg4.b.ded_fifo_en == 0) {
27219 + if (dwc_otg_param_initialized
27220 + (core_if->core_params->en_multiple_tx_fifo)) {
27221 + DWC_ERROR
27222 + ("%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
27223 + val);
27224 + }
27225 + val = 0;
27226 + retval = -DWC_E_INVALID;
27227 + }
27228 +
27229 + core_if->core_params->en_multiple_tx_fifo = val;
27230 + return retval;
27231 +}
27232 +
27233 +int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if)
27234 +{
27235 + return core_if->core_params->en_multiple_tx_fifo;
27236 +}
27237 +
27238 +int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val,
27239 + int fifo_num)
27240 +{
27241 + int retval = 0;
27242 +
27243 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
27244 + DWC_WARN("Wrong value for dev_tx_fifo_size\n");
27245 + DWC_WARN("dev_tx_fifo_size must be 4-768\n");
27246 + return -DWC_E_INVALID;
27247 + }
27248 +
27249 + if (val >
27250 + (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
27251 + if (dwc_otg_param_initialized
27252 + (core_if->core_params->dev_tx_fifo_size[fifo_num])) {
27253 + DWC_ERROR
27254 + ("`%d' invalid for parameter `dev_tx_fifo_size_%d'. Check HW configuration.\n",
27255 + val, fifo_num);
27256 + }
27257 + val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
27258 + retval = -DWC_E_INVALID;
27259 + }
27260 +
27261 + core_if->core_params->dev_tx_fifo_size[fifo_num] = val;
27262 + return retval;
27263 +}
27264 +
27265 +int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
27266 + int fifo_num)
27267 +{
27268 + return core_if->core_params->dev_tx_fifo_size[fifo_num];
27269 +}
27270 +
27271 +int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val)
27272 +{
27273 + int retval = 0;
27274 +
27275 + if (DWC_OTG_PARAM_TEST(val, 0, 7)) {
27276 + DWC_WARN("Wrong value for thr_ctl\n");
27277 + DWC_WARN("thr_ctl must be 0-7\n");
27278 + return -DWC_E_INVALID;
27279 + }
27280 +
27281 + if ((val != 0) &&
27282 + (!dwc_otg_get_param_dma_enable(core_if) ||
27283 + !core_if->hwcfg4.b.ded_fifo_en)) {
27284 + if (dwc_otg_param_initialized(core_if->core_params->thr_ctl)) {
27285 + DWC_ERROR
27286 + ("%d invalid for parameter thr_ctl. Check HW configuration.\n",
27287 + val);
27288 + }
27289 + val = 0;
27290 + retval = -DWC_E_INVALID;
27291 + }
27292 +
27293 + core_if->core_params->thr_ctl = val;
27294 + return retval;
27295 +}
27296 +
27297 +int32_t dwc_otg_get_param_thr_ctl(dwc_otg_core_if_t * core_if)
27298 +{
27299 + return core_if->core_params->thr_ctl;
27300 +}
27301 +
27302 +int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, int32_t val)
27303 +{
27304 + int retval = 0;
27305 +
27306 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27307 + DWC_WARN("Wrong value for lpm_enable\n");
27308 + DWC_WARN("lpm_enable must be 0 or 1\n");
27309 + return -DWC_E_INVALID;
27310 + }
27311 +
27312 + if (val && !core_if->hwcfg3.b.otg_lpm_en) {
27313 + if (dwc_otg_param_initialized(core_if->core_params->lpm_enable)) {
27314 + DWC_ERROR
27315 + ("%d invalid for parameter lpm_enable. Check HW configuration.\n",
27316 + val);
27317 + }
27318 + val = 0;
27319 + retval = -DWC_E_INVALID;
27320 + }
27321 +
27322 + core_if->core_params->lpm_enable = val;
27323 + return retval;
27324 +}
27325 +
27326 +int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if)
27327 +{
27328 + return core_if->core_params->lpm_enable;
27329 +}
27330 +
27331 +int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
27332 +{
27333 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
27334 + DWC_WARN("Wrong valaue for tx_thr_length\n");
27335 + DWC_WARN("tx_thr_length must be 8 - 128\n");
27336 + return -DWC_E_INVALID;
27337 + }
27338 +
27339 + core_if->core_params->tx_thr_length = val;
27340 + return 0;
27341 +}
27342 +
27343 +int32_t dwc_otg_get_param_tx_thr_length(dwc_otg_core_if_t * core_if)
27344 +{
27345 + return core_if->core_params->tx_thr_length;
27346 +}
27347 +
27348 +int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
27349 +{
27350 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
27351 + DWC_WARN("Wrong valaue for rx_thr_length\n");
27352 + DWC_WARN("rx_thr_length must be 8 - 128\n");
27353 + return -DWC_E_INVALID;
27354 + }
27355 +
27356 + core_if->core_params->rx_thr_length = val;
27357 + return 0;
27358 +}
27359 +
27360 +int32_t dwc_otg_get_param_rx_thr_length(dwc_otg_core_if_t * core_if)
27361 +{
27362 + return core_if->core_params->rx_thr_length;
27363 +}
27364 +
27365 +int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, int32_t val)
27366 +{
27367 + if (DWC_OTG_PARAM_TEST(val, 1, 1) &&
27368 + DWC_OTG_PARAM_TEST(val, 4, 4) &&
27369 + DWC_OTG_PARAM_TEST(val, 8, 8) &&
27370 + DWC_OTG_PARAM_TEST(val, 16, 16) &&
27371 + DWC_OTG_PARAM_TEST(val, 32, 32) &&
27372 + DWC_OTG_PARAM_TEST(val, 64, 64) &&
27373 + DWC_OTG_PARAM_TEST(val, 128, 128) &&
27374 + DWC_OTG_PARAM_TEST(val, 256, 256)) {
27375 + DWC_WARN("`%d' invalid for parameter `dma_burst_size'\n", val);
27376 + return -DWC_E_INVALID;
27377 + }
27378 + core_if->core_params->dma_burst_size = val;
27379 + return 0;
27380 +}
27381 +
27382 +int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if)
27383 +{
27384 + return core_if->core_params->dma_burst_size;
27385 +}
27386 +
27387 +int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, int32_t val)
27388 +{
27389 + int retval = 0;
27390 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27391 + DWC_WARN("`%d' invalid for parameter `pti_enable'\n", val);
27392 + return -DWC_E_INVALID;
27393 + }
27394 + if (val && (core_if->snpsid < OTG_CORE_REV_2_72a)) {
27395 + if (dwc_otg_param_initialized(core_if->core_params->pti_enable)) {
27396 + DWC_ERROR
27397 + ("%d invalid for parameter pti_enable. Check HW configuration.\n",
27398 + val);
27399 + }
27400 + retval = -DWC_E_INVALID;
27401 + val = 0;
27402 + }
27403 + core_if->core_params->pti_enable = val;
27404 + return retval;
27405 +}
27406 +
27407 +int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if)
27408 +{
27409 + return core_if->core_params->pti_enable;
27410 +}
27411 +
27412 +int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, int32_t val)
27413 +{
27414 + int retval = 0;
27415 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27416 + DWC_WARN("`%d' invalid for parameter `mpi_enable'\n", val);
27417 + return -DWC_E_INVALID;
27418 + }
27419 + if (val && (core_if->hwcfg2.b.multi_proc_int == 0)) {
27420 + if (dwc_otg_param_initialized(core_if->core_params->mpi_enable)) {
27421 + DWC_ERROR
27422 + ("%d invalid for parameter mpi_enable. Check HW configuration.\n",
27423 + val);
27424 + }
27425 + retval = -DWC_E_INVALID;
27426 + val = 0;
27427 + }
27428 + core_if->core_params->mpi_enable = val;
27429 + return retval;
27430 +}
27431 +
27432 +int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if)
27433 +{
27434 + return core_if->core_params->mpi_enable;
27435 +}
27436 +
27437 +int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if, int32_t val)
27438 +{
27439 + int retval = 0;
27440 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27441 + DWC_WARN("`%d' invalid for parameter `adp_enable'\n", val);
27442 + return -DWC_E_INVALID;
27443 + }
27444 + if (val && (core_if->hwcfg3.b.adp_supp == 0)) {
27445 + if (dwc_otg_param_initialized
27446 + (core_if->core_params->adp_supp_enable)) {
27447 + DWC_ERROR
27448 + ("%d invalid for parameter adp_enable. Check HW configuration.\n",
27449 + val);
27450 + }
27451 + retval = -DWC_E_INVALID;
27452 + val = 0;
27453 + }
27454 + core_if->core_params->adp_supp_enable = val;
27455 + /*Set OTG version 2.0 in case of enabling ADP*/
27456 + if (val)
27457 + dwc_otg_set_param_otg_ver(core_if, 1);
27458 +
27459 + return retval;
27460 +}
27461 +
27462 +int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if)
27463 +{
27464 + return core_if->core_params->adp_supp_enable;
27465 +}
27466 +
27467 +int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if, int32_t val)
27468 +{
27469 + int retval = 0;
27470 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27471 + DWC_WARN("`%d' invalid for parameter `ic_usb_cap'\n", val);
27472 + DWC_WARN("ic_usb_cap must be 0 or 1\n");
27473 + return -DWC_E_INVALID;
27474 + }
27475 +
27476 + if (val && (core_if->hwcfg2.b.otg_enable_ic_usb == 0)) {
27477 + if (dwc_otg_param_initialized(core_if->core_params->ic_usb_cap)) {
27478 + DWC_ERROR
27479 + ("%d invalid for parameter ic_usb_cap. Check HW configuration.\n",
27480 + val);
27481 + }
27482 + retval = -DWC_E_INVALID;
27483 + val = 0;
27484 + }
27485 + core_if->core_params->ic_usb_cap = val;
27486 + return retval;
27487 +}
27488 +
27489 +int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if)
27490 +{
27491 + return core_if->core_params->ic_usb_cap;
27492 +}
27493 +
27494 +int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val)
27495 +{
27496 + int retval = 0;
27497 + int valid = 1;
27498 +
27499 + if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
27500 + DWC_WARN("`%d' invalid for parameter `ahb_thr_ratio'\n", val);
27501 + DWC_WARN("ahb_thr_ratio must be 0 - 3\n");
27502 + return -DWC_E_INVALID;
27503 + }
27504 +
27505 + if (val
27506 + && (core_if->snpsid < OTG_CORE_REV_2_81a
27507 + || !dwc_otg_get_param_thr_ctl(core_if))) {
27508 + valid = 0;
27509 + } else if (val
27510 + && ((dwc_otg_get_param_tx_thr_length(core_if) / (1 << val)) <
27511 + 4)) {
27512 + valid = 0;
27513 + }
27514 + if (valid == 0) {
27515 + if (dwc_otg_param_initialized
27516 + (core_if->core_params->ahb_thr_ratio)) {
27517 + DWC_ERROR
27518 + ("%d invalid for parameter ahb_thr_ratio. Check HW configuration.\n",
27519 + val);
27520 + }
27521 + retval = -DWC_E_INVALID;
27522 + val = 0;
27523 + }
27524 +
27525 + core_if->core_params->ahb_thr_ratio = val;
27526 + return retval;
27527 +}
27528 +
27529 +int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if)
27530 +{
27531 + return core_if->core_params->ahb_thr_ratio;
27532 +}
27533 +
27534 +int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if, int32_t val)
27535 +{
27536 + int retval = 0;
27537 + int valid = 1;
27538 + hwcfg4_data_t hwcfg4 = {.d32 = 0 };
27539 + hwcfg4.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
27540 +
27541 + if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
27542 + DWC_WARN("`%d' invalid for parameter `power_down'\n", val);
27543 + DWC_WARN("power_down must be 0 - 2\n");
27544 + return -DWC_E_INVALID;
27545 + }
27546 +
27547 + if ((val == 2) && (core_if->snpsid < OTG_CORE_REV_2_91a)) {
27548 + valid = 0;
27549 + }
27550 + if ((val == 3)
27551 + && ((core_if->snpsid < OTG_CORE_REV_3_00a)
27552 + || (hwcfg4.b.xhiber == 0))) {
27553 + valid = 0;
27554 + }
27555 + if (valid == 0) {
27556 + if (dwc_otg_param_initialized(core_if->core_params->power_down)) {
27557 + DWC_ERROR
27558 + ("%d invalid for parameter power_down. Check HW configuration.\n",
27559 + val);
27560 + }
27561 + retval = -DWC_E_INVALID;
27562 + val = 0;
27563 + }
27564 + core_if->core_params->power_down = val;
27565 + return retval;
27566 +}
27567 +
27568 +int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if)
27569 +{
27570 + return core_if->core_params->power_down;
27571 +}
27572 +
27573 +int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if, int32_t val)
27574 +{
27575 + int retval = 0;
27576 + int valid = 1;
27577 +
27578 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27579 + DWC_WARN("`%d' invalid for parameter `reload_ctl'\n", val);
27580 + DWC_WARN("reload_ctl must be 0 or 1\n");
27581 + return -DWC_E_INVALID;
27582 + }
27583 +
27584 + if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_92a)) {
27585 + valid = 0;
27586 + }
27587 + if (valid == 0) {
27588 + if (dwc_otg_param_initialized(core_if->core_params->reload_ctl)) {
27589 + DWC_ERROR("%d invalid for parameter reload_ctl."
27590 + "Check HW configuration.\n", val);
27591 + }
27592 + retval = -DWC_E_INVALID;
27593 + val = 0;
27594 + }
27595 + core_if->core_params->reload_ctl = val;
27596 + return retval;
27597 +}
27598 +
27599 +int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if)
27600 +{
27601 + return core_if->core_params->reload_ctl;
27602 +}
27603 +
27604 +int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if, int32_t val)
27605 +{
27606 + int retval = 0;
27607 + int valid = 1;
27608 +
27609 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27610 + DWC_WARN("`%d' invalid for parameter `dev_out_nak'\n", val);
27611 + DWC_WARN("dev_out_nak must be 0 or 1\n");
27612 + return -DWC_E_INVALID;
27613 + }
27614 +
27615 + if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_93a) ||
27616 + !(core_if->core_params->dma_desc_enable))) {
27617 + valid = 0;
27618 + }
27619 + if (valid == 0) {
27620 + if (dwc_otg_param_initialized(core_if->core_params->dev_out_nak)) {
27621 + DWC_ERROR("%d invalid for parameter dev_out_nak."
27622 + "Check HW configuration.\n", val);
27623 + }
27624 + retval = -DWC_E_INVALID;
27625 + val = 0;
27626 + }
27627 + core_if->core_params->dev_out_nak = val;
27628 + return retval;
27629 +}
27630 +
27631 +int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if)
27632 +{
27633 + return core_if->core_params->dev_out_nak;
27634 +}
27635 +
27636 +int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if, int32_t val)
27637 +{
27638 + int retval = 0;
27639 + int valid = 1;
27640 +
27641 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27642 + DWC_WARN("`%d' invalid for parameter `cont_on_bna'\n", val);
27643 + DWC_WARN("cont_on_bna must be 0 or 1\n");
27644 + return -DWC_E_INVALID;
27645 + }
27646 +
27647 + if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_94a) ||
27648 + !(core_if->core_params->dma_desc_enable))) {
27649 + valid = 0;
27650 + }
27651 + if (valid == 0) {
27652 + if (dwc_otg_param_initialized(core_if->core_params->cont_on_bna)) {
27653 + DWC_ERROR("%d invalid for parameter cont_on_bna."
27654 + "Check HW configuration.\n", val);
27655 + }
27656 + retval = -DWC_E_INVALID;
27657 + val = 0;
27658 + }
27659 + core_if->core_params->cont_on_bna = val;
27660 + return retval;
27661 +}
27662 +
27663 +int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if)
27664 +{
27665 + return core_if->core_params->cont_on_bna;
27666 +}
27667 +
27668 +int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if, int32_t val)
27669 +{
27670 + int retval = 0;
27671 + int valid = 1;
27672 +
27673 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27674 + DWC_WARN("`%d' invalid for parameter `ahb_single'\n", val);
27675 + DWC_WARN("ahb_single must be 0 or 1\n");
27676 + return -DWC_E_INVALID;
27677 + }
27678 +
27679 + if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
27680 + valid = 0;
27681 + }
27682 + if (valid == 0) {
27683 + if (dwc_otg_param_initialized(core_if->core_params->ahb_single)) {
27684 + DWC_ERROR("%d invalid for parameter ahb_single."
27685 + "Check HW configuration.\n", val);
27686 + }
27687 + retval = -DWC_E_INVALID;
27688 + val = 0;
27689 + }
27690 + core_if->core_params->ahb_single = val;
27691 + return retval;
27692 +}
27693 +
27694 +int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if)
27695 +{
27696 + return core_if->core_params->ahb_single;
27697 +}
27698 +
27699 +int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val)
27700 +{
27701 + int retval = 0;
27702 +
27703 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27704 + DWC_WARN("`%d' invalid for parameter `otg_ver'\n", val);
27705 + DWC_WARN
27706 + ("otg_ver must be 0(for OTG 1.3 support) or 1(for OTG 2.0 support)\n");
27707 + return -DWC_E_INVALID;
27708 + }
27709 +
27710 + core_if->core_params->otg_ver = val;
27711 + return retval;
27712 +}
27713 +
27714 +int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if)
27715 +{
27716 + return core_if->core_params->otg_ver;
27717 +}
27718 +
27719 +uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if)
27720 +{
27721 + gotgctl_data_t otgctl;
27722 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27723 + return otgctl.b.hstnegscs;
27724 +}
27725 +
27726 +uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if)
27727 +{
27728 + gotgctl_data_t otgctl;
27729 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27730 + return otgctl.b.sesreqscs;
27731 +}
27732 +
27733 +void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val)
27734 +{
27735 + if(core_if->otg_ver == 0) {
27736 + gotgctl_data_t otgctl;
27737 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27738 + otgctl.b.hnpreq = val;
27739 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, otgctl.d32);
27740 + } else {
27741 + core_if->otg_sts = val;
27742 + }
27743 +}
27744 +
27745 +uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if)
27746 +{
27747 + return core_if->snpsid;
27748 +}
27749 +
27750 +uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if)
27751 +{
27752 + gintsts_data_t gintsts;
27753 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
27754 + return gintsts.b.curmode;
27755 +}
27756 +
27757 +uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if)
27758 +{
27759 + gusbcfg_data_t usbcfg;
27760 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27761 + return usbcfg.b.hnpcap;
27762 +}
27763 +
27764 +void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
27765 +{
27766 + gusbcfg_data_t usbcfg;
27767 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27768 + usbcfg.b.hnpcap = val;
27769 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
27770 +}
27771 +
27772 +uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if)
27773 +{
27774 + gusbcfg_data_t usbcfg;
27775 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27776 + return usbcfg.b.srpcap;
27777 +}
27778 +
27779 +void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
27780 +{
27781 + gusbcfg_data_t usbcfg;
27782 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27783 + usbcfg.b.srpcap = val;
27784 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
27785 +}
27786 +
27787 +uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if)
27788 +{
27789 + dcfg_data_t dcfg;
27790 + /* originally: dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg); */
27791 +
27792 + dcfg.d32 = -1; //GRAYG
27793 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)\n", __func__, core_if);
27794 + if (NULL == core_if)
27795 + DWC_ERROR("reg request with NULL core_if\n");
27796 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)\n", __func__,
27797 + core_if, core_if->dev_if);
27798 + if (NULL == core_if->dev_if)
27799 + DWC_ERROR("reg request with NULL dev_if\n");
27800 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)->"
27801 + "dev_global_regs(%p)\n", __func__,
27802 + core_if, core_if->dev_if,
27803 + core_if->dev_if->dev_global_regs);
27804 + if (NULL == core_if->dev_if->dev_global_regs)
27805 + DWC_ERROR("reg request with NULL dev_global_regs\n");
27806 + else {
27807 + DWC_DEBUGPL(DBG_CILV, "%s - &core_if(%p)->dev_if(%p)->"
27808 + "dev_global_regs(%p)->dcfg = %p\n", __func__,
27809 + core_if, core_if->dev_if,
27810 + core_if->dev_if->dev_global_regs,
27811 + &core_if->dev_if->dev_global_regs->dcfg);
27812 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
27813 + }
27814 + return dcfg.b.devspd;
27815 +}
27816 +
27817 +void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val)
27818 +{
27819 + dcfg_data_t dcfg;
27820 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
27821 + dcfg.b.devspd = val;
27822 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
27823 +}
27824 +
27825 +uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if)
27826 +{
27827 + hprt0_data_t hprt0;
27828 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27829 + return hprt0.b.prtconnsts;
27830 +}
27831 +
27832 +uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if)
27833 +{
27834 + dsts_data_t dsts;
27835 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
27836 + return dsts.b.enumspd;
27837 +}
27838 +
27839 +uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if)
27840 +{
27841 + hprt0_data_t hprt0;
27842 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27843 + return hprt0.b.prtpwr;
27844 +
27845 +}
27846 +
27847 +uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if)
27848 +{
27849 + return core_if->hibernation_suspend;
27850 +}
27851 +
27852 +void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val)
27853 +{
27854 + hprt0_data_t hprt0;
27855 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27856 + hprt0.b.prtpwr = val;
27857 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27858 +}
27859 +
27860 +uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if)
27861 +{
27862 + hprt0_data_t hprt0;
27863 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27864 + return hprt0.b.prtsusp;
27865 +
27866 +}
27867 +
27868 +void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val)
27869 +{
27870 + hprt0_data_t hprt0;
27871 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27872 + hprt0.b.prtsusp = val;
27873 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27874 +}
27875 +
27876 +uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if)
27877 +{
27878 + hfir_data_t hfir;
27879 + hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
27880 + return hfir.b.frint;
27881 +
27882 +}
27883 +
27884 +void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val)
27885 +{
27886 + hfir_data_t hfir;
27887 + uint32_t fram_int;
27888 + fram_int = calc_frame_interval(core_if);
27889 + hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
27890 + if (!core_if->core_params->reload_ctl) {
27891 + DWC_WARN("\nCannot reload HFIR register.HFIR.HFIRRldCtrl bit is"
27892 + "not set to 1.\nShould load driver with reload_ctl=1"
27893 + " module parameter\n");
27894 + return;
27895 + }
27896 + switch (fram_int) {
27897 + case 3750:
27898 + if ((val < 3350) || (val > 4150)) {
27899 + DWC_WARN("HFIR interval for HS core and 30 MHz"
27900 + "clock freq should be from 3350 to 4150\n");
27901 + return;
27902 + }
27903 + break;
27904 + case 30000:
27905 + if ((val < 26820) || (val > 33180)) {
27906 + DWC_WARN("HFIR interval for FS/LS core and 30 MHz"
27907 + "clock freq should be from 26820 to 33180\n");
27908 + return;
27909 + }
27910 + break;
27911 + case 6000:
27912 + if ((val < 5360) || (val > 6640)) {
27913 + DWC_WARN("HFIR interval for HS core and 48 MHz"
27914 + "clock freq should be from 5360 to 6640\n");
27915 + return;
27916 + }
27917 + break;
27918 + case 48000:
27919 + if ((val < 42912) || (val > 53088)) {
27920 + DWC_WARN("HFIR interval for FS/LS core and 48 MHz"
27921 + "clock freq should be from 42912 to 53088\n");
27922 + return;
27923 + }
27924 + break;
27925 + case 7500:
27926 + if ((val < 6700) || (val > 8300)) {
27927 + DWC_WARN("HFIR interval for HS core and 60 MHz"
27928 + "clock freq should be from 6700 to 8300\n");
27929 + return;
27930 + }
27931 + break;
27932 + case 60000:
27933 + if ((val < 53640) || (val > 65536)) {
27934 + DWC_WARN("HFIR interval for FS/LS core and 60 MHz"
27935 + "clock freq should be from 53640 to 65536\n");
27936 + return;
27937 + }
27938 + break;
27939 + default:
27940 + DWC_WARN("Unknown frame interval\n");
27941 + return;
27942 + break;
27943 +
27944 + }
27945 + hfir.b.frint = val;
27946 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hfir.d32);
27947 +}
27948 +
27949 +uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if)
27950 +{
27951 + hcfg_data_t hcfg;
27952 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
27953 + return hcfg.b.modechtimen;
27954 +
27955 +}
27956 +
27957 +void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val)
27958 +{
27959 + hcfg_data_t hcfg;
27960 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
27961 + hcfg.b.modechtimen = val;
27962 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
27963 +}
27964 +
27965 +void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val)
27966 +{
27967 + hprt0_data_t hprt0;
27968 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27969 + hprt0.b.prtres = val;
27970 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27971 +}
27972 +
27973 +uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if)
27974 +{
27975 + dctl_data_t dctl;
27976 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
27977 + return dctl.b.rmtwkupsig;
27978 +}
27979 +
27980 +uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if)
27981 +{
27982 + glpmcfg_data_t lpmcfg;
27983 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27984 +
27985 + DWC_ASSERT(!
27986 + ((core_if->lx_state == DWC_OTG_L1) ^ lpmcfg.b.prt_sleep_sts),
27987 + "lx_state = %d, lmpcfg.prt_sleep_sts = %d\n",
27988 + core_if->lx_state, lpmcfg.b.prt_sleep_sts);
27989 +
27990 + return lpmcfg.b.prt_sleep_sts;
27991 +}
27992 +
27993 +uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if)
27994 +{
27995 + glpmcfg_data_t lpmcfg;
27996 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27997 + return lpmcfg.b.rem_wkup_en;
27998 +}
27999 +
28000 +uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if)
28001 +{
28002 + glpmcfg_data_t lpmcfg;
28003 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28004 + return lpmcfg.b.appl_resp;
28005 +}
28006 +
28007 +void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val)
28008 +{
28009 + glpmcfg_data_t lpmcfg;
28010 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28011 + lpmcfg.b.appl_resp = val;
28012 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
28013 +}
28014 +
28015 +uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if)
28016 +{
28017 + glpmcfg_data_t lpmcfg;
28018 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28019 + return lpmcfg.b.hsic_connect;
28020 +}
28021 +
28022 +void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val)
28023 +{
28024 + glpmcfg_data_t lpmcfg;
28025 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28026 + lpmcfg.b.hsic_connect = val;
28027 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
28028 +}
28029 +
28030 +uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if)
28031 +{
28032 + glpmcfg_data_t lpmcfg;
28033 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28034 + return lpmcfg.b.inv_sel_hsic;
28035 +
28036 +}
28037 +
28038 +void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val)
28039 +{
28040 + glpmcfg_data_t lpmcfg;
28041 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28042 + lpmcfg.b.inv_sel_hsic = val;
28043 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
28044 +}
28045 +
28046 +uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if)
28047 +{
28048 + return DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
28049 +}
28050 +
28051 +void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val)
28052 +{
28053 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, val);
28054 +}
28055 +
28056 +uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if)
28057 +{
28058 + return DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
28059 +}
28060 +
28061 +void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val)
28062 +{
28063 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, val);
28064 +}
28065 +
28066 +uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if)
28067 +{
28068 + return DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
28069 +}
28070 +
28071 +void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
28072 +{
28073 + DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, val);
28074 +}
28075 +
28076 +uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if)
28077 +{
28078 + return DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
28079 +}
28080 +
28081 +void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
28082 +{
28083 + DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz, val);
28084 +}
28085 +
28086 +uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if)
28087 +{
28088 + return DWC_READ_REG32(&core_if->core_global_regs->gpvndctl);
28089 +}
28090 +
28091 +void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val)
28092 +{
28093 + DWC_WRITE_REG32(&core_if->core_global_regs->gpvndctl, val);
28094 +}
28095 +
28096 +uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if)
28097 +{
28098 + return DWC_READ_REG32(&core_if->core_global_regs->ggpio);
28099 +}
28100 +
28101 +void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val)
28102 +{
28103 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, val);
28104 +}
28105 +
28106 +uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if)
28107 +{
28108 + return DWC_READ_REG32(core_if->host_if->hprt0);
28109 +
28110 +}
28111 +
28112 +void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val)
28113 +{
28114 + DWC_WRITE_REG32(core_if->host_if->hprt0, val);
28115 +}
28116 +
28117 +uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if)
28118 +{
28119 + return DWC_READ_REG32(&core_if->core_global_regs->guid);
28120 +}
28121 +
28122 +void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val)
28123 +{
28124 + DWC_WRITE_REG32(&core_if->core_global_regs->guid, val);
28125 +}
28126 +
28127 +uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if)
28128 +{
28129 + return DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
28130 +}
28131 +
28132 +uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if)
28133 +{
28134 + return ((core_if->otg_ver == 1) ? (uint16_t)0x0200 : (uint16_t)0x0103);
28135 +}
28136 +
28137 +/**
28138 + * Start the SRP timer to detect when the SRP does not complete within
28139 + * 6 seconds.
28140 + *
28141 + * @param core_if the pointer to core_if strucure.
28142 + */
28143 +void dwc_otg_pcd_start_srp_timer(dwc_otg_core_if_t * core_if)
28144 +{
28145 + core_if->srp_timer_started = 1;
28146 + DWC_TIMER_SCHEDULE(core_if->srp_timer, 6000 /* 6 secs */ );
28147 +}
28148 +
28149 +void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if)
28150 +{
28151 + uint32_t *addr = (uint32_t *) & (core_if->core_global_regs->gotgctl);
28152 + gotgctl_data_t mem;
28153 + gotgctl_data_t val;
28154 +
28155 + val.d32 = DWC_READ_REG32(addr);
28156 + if (val.b.sesreq) {
28157 + DWC_ERROR("Session Request Already active!\n");
28158 + return;
28159 + }
28160 +
28161 + DWC_INFO("Session Request Initated\n"); //NOTICE
28162 + mem.d32 = DWC_READ_REG32(addr);
28163 + mem.b.sesreq = 1;
28164 + DWC_WRITE_REG32(addr, mem.d32);
28165 +
28166 + /* Start the SRP timer */
28167 + dwc_otg_pcd_start_srp_timer(core_if);
28168 + return;
28169 +}
28170 --- /dev/null
28171 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.h
28172 @@ -0,0 +1,1464 @@
28173 +/* ==========================================================================
28174 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.h $
28175 + * $Revision: #123 $
28176 + * $Date: 2012/08/10 $
28177 + * $Change: 2047372 $
28178 + *
28179 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
28180 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
28181 + * otherwise expressly agreed to in writing between Synopsys and you.
28182 + *
28183 + * The Software IS NOT an item of Licensed Software or Licensed Product under
28184 + * any End User Software License Agreement or Agreement for Licensed Product
28185 + * with Synopsys or any supplement thereto. You are permitted to use and
28186 + * redistribute this Software in source and binary forms, with or without
28187 + * modification, provided that redistributions of source code must retain this
28188 + * notice. You may not view, use, disclose, copy or distribute this file or
28189 + * any information contained herein except pursuant to this license grant from
28190 + * Synopsys. If you do not agree with this notice, including the disclaimer
28191 + * below, then you are not authorized to use the Software.
28192 + *
28193 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
28194 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28195 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28196 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
28197 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28198 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28199 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28200 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28201 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28202 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28203 + * DAMAGE.
28204 + * ========================================================================== */
28205 +
28206 +#if !defined(__DWC_CIL_H__)
28207 +#define __DWC_CIL_H__
28208 +
28209 +#include "dwc_list.h"
28210 +#include "dwc_otg_dbg.h"
28211 +#include "dwc_otg_regs.h"
28212 +
28213 +#include "dwc_otg_core_if.h"
28214 +#include "dwc_otg_adp.h"
28215 +
28216 +/**
28217 + * @file
28218 + * This file contains the interface to the Core Interface Layer.
28219 + */
28220 +
28221 +#ifdef DWC_UTE_CFI
28222 +
28223 +#define MAX_DMA_DESCS_PER_EP 256
28224 +
28225 +/**
28226 + * Enumeration for the data buffer mode
28227 + */
28228 +typedef enum _data_buffer_mode {
28229 + BM_STANDARD = 0, /* data buffer is in normal mode */
28230 + BM_SG = 1, /* data buffer uses the scatter/gather mode */
28231 + BM_CONCAT = 2, /* data buffer uses the concatenation mode */
28232 + BM_CIRCULAR = 3, /* data buffer uses the circular DMA mode */
28233 + BM_ALIGN = 4 /* data buffer is in buffer alignment mode */
28234 +} data_buffer_mode_e;
28235 +#endif //DWC_UTE_CFI
28236 +
28237 +/** Macros defined for DWC OTG HW Release version */
28238 +
28239 +#define OTG_CORE_REV_2_60a 0x4F54260A
28240 +#define OTG_CORE_REV_2_71a 0x4F54271A
28241 +#define OTG_CORE_REV_2_72a 0x4F54272A
28242 +#define OTG_CORE_REV_2_80a 0x4F54280A
28243 +#define OTG_CORE_REV_2_81a 0x4F54281A
28244 +#define OTG_CORE_REV_2_90a 0x4F54290A
28245 +#define OTG_CORE_REV_2_91a 0x4F54291A
28246 +#define OTG_CORE_REV_2_92a 0x4F54292A
28247 +#define OTG_CORE_REV_2_93a 0x4F54293A
28248 +#define OTG_CORE_REV_2_94a 0x4F54294A
28249 +#define OTG_CORE_REV_3_00a 0x4F54300A
28250 +
28251 +/**
28252 + * Information for each ISOC packet.
28253 + */
28254 +typedef struct iso_pkt_info {
28255 + uint32_t offset;
28256 + uint32_t length;
28257 + int32_t status;
28258 +} iso_pkt_info_t;
28259 +
28260 +/**
28261 + * The <code>dwc_ep</code> structure represents the state of a single
28262 + * endpoint when acting in device mode. It contains the data items
28263 + * needed for an endpoint to be activated and transfer packets.
28264 + */
28265 +typedef struct dwc_ep {
28266 + /** EP number used for register address lookup */
28267 + uint8_t num;
28268 + /** EP direction 0 = OUT */
28269 + unsigned is_in:1;
28270 + /** EP active. */
28271 + unsigned active:1;
28272 +
28273 + /**
28274 + * Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic
28275 + * Tx FIFO. If dedicated Tx FIFOs are enabled Tx FIFO # FOR IN EPs*/
28276 + unsigned tx_fifo_num:4;
28277 + /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */
28278 + unsigned type:2;
28279 +#define DWC_OTG_EP_TYPE_CONTROL 0
28280 +#define DWC_OTG_EP_TYPE_ISOC 1
28281 +#define DWC_OTG_EP_TYPE_BULK 2
28282 +#define DWC_OTG_EP_TYPE_INTR 3
28283 +
28284 + /** DATA start PID for INTR and BULK EP */
28285 + unsigned data_pid_start:1;
28286 + /** Frame (even/odd) for ISOC EP */
28287 + unsigned even_odd_frame:1;
28288 + /** Max Packet bytes */
28289 + unsigned maxpacket:11;
28290 +
28291 + /** Max Transfer size */
28292 + uint32_t maxxfer;
28293 +
28294 + /** @name Transfer state */
28295 + /** @{ */
28296 +
28297 + /**
28298 + * Pointer to the beginning of the transfer buffer -- do not modify
28299 + * during transfer.
28300 + */
28301 +
28302 + dwc_dma_t dma_addr;
28303 +
28304 + dwc_dma_t dma_desc_addr;
28305 + dwc_otg_dev_dma_desc_t *desc_addr;
28306 +
28307 + uint8_t *start_xfer_buff;
28308 + /** pointer to the transfer buffer */
28309 + uint8_t *xfer_buff;
28310 + /** Number of bytes to transfer */
28311 + unsigned xfer_len:19;
28312 + /** Number of bytes transferred. */
28313 + unsigned xfer_count:19;
28314 + /** Sent ZLP */
28315 + unsigned sent_zlp:1;
28316 + /** Total len for control transfer */
28317 + unsigned total_len:19;
28318 +
28319 + /** stall clear flag */
28320 + unsigned stall_clear_flag:1;
28321 +
28322 + /** SETUP pkt cnt rollover flag for EP0 out*/
28323 + unsigned stp_rollover;
28324 +
28325 +#ifdef DWC_UTE_CFI
28326 + /* The buffer mode */
28327 + data_buffer_mode_e buff_mode;
28328 +
28329 + /* The chain of DMA descriptors.
28330 + * MAX_DMA_DESCS_PER_EP will be allocated for each active EP.
28331 + */
28332 + dwc_otg_dma_desc_t *descs;
28333 +
28334 + /* The DMA address of the descriptors chain start */
28335 + dma_addr_t descs_dma_addr;
28336 + /** This variable stores the length of the last enqueued request */
28337 + uint32_t cfi_req_len;
28338 +#endif //DWC_UTE_CFI
28339 +
28340 +/** Max DMA Descriptor count for any EP */
28341 +#define MAX_DMA_DESC_CNT 256
28342 + /** Allocated DMA Desc count */
28343 + uint32_t desc_cnt;
28344 +
28345 + /** bInterval */
28346 + uint32_t bInterval;
28347 + /** Next frame num to setup next ISOC transfer */
28348 + uint32_t frame_num;
28349 + /** Indicates SOF number overrun in DSTS */
28350 + uint8_t frm_overrun;
28351 +
28352 +#ifdef DWC_UTE_PER_IO
28353 + /** Next frame num for which will be setup DMA Desc */
28354 + uint32_t xiso_frame_num;
28355 + /** bInterval */
28356 + uint32_t xiso_bInterval;
28357 + /** Count of currently active transfers - shall be either 0 or 1 */
28358 + int xiso_active_xfers;
28359 + int xiso_queued_xfers;
28360 +#endif
28361 +#ifdef DWC_EN_ISOC
28362 + /**
28363 + * Variables specific for ISOC EPs
28364 + *
28365 + */
28366 + /** DMA addresses of ISOC buffers */
28367 + dwc_dma_t dma_addr0;
28368 + dwc_dma_t dma_addr1;
28369 +
28370 + dwc_dma_t iso_dma_desc_addr;
28371 + dwc_otg_dev_dma_desc_t *iso_desc_addr;
28372 +
28373 + /** pointer to the transfer buffers */
28374 + uint8_t *xfer_buff0;
28375 + uint8_t *xfer_buff1;
28376 +
28377 + /** number of ISOC Buffer is processing */
28378 + uint32_t proc_buf_num;
28379 + /** Interval of ISOC Buffer processing */
28380 + uint32_t buf_proc_intrvl;
28381 + /** Data size for regular frame */
28382 + uint32_t data_per_frame;
28383 +
28384 + /* todo - pattern data support is to be implemented in the future */
28385 + /** Data size for pattern frame */
28386 + uint32_t data_pattern_frame;
28387 + /** Frame number of pattern data */
28388 + uint32_t sync_frame;
28389 +
28390 + /** bInterval */
28391 + uint32_t bInterval;
28392 + /** ISO Packet number per frame */
28393 + uint32_t pkt_per_frm;
28394 + /** Next frame num for which will be setup DMA Desc */
28395 + uint32_t next_frame;
28396 + /** Number of packets per buffer processing */
28397 + uint32_t pkt_cnt;
28398 + /** Info for all isoc packets */
28399 + iso_pkt_info_t *pkt_info;
28400 + /** current pkt number */
28401 + uint32_t cur_pkt;
28402 + /** current pkt number */
28403 + uint8_t *cur_pkt_addr;
28404 + /** current pkt number */
28405 + uint32_t cur_pkt_dma_addr;
28406 +#endif /* DWC_EN_ISOC */
28407 +
28408 +/** @} */
28409 +} dwc_ep_t;
28410 +
28411 +/*
28412 + * Reasons for halting a host channel.
28413 + */
28414 +typedef enum dwc_otg_halt_status {
28415 + DWC_OTG_HC_XFER_NO_HALT_STATUS,
28416 + DWC_OTG_HC_XFER_COMPLETE,
28417 + DWC_OTG_HC_XFER_URB_COMPLETE,
28418 + DWC_OTG_HC_XFER_ACK,
28419 + DWC_OTG_HC_XFER_NAK,
28420 + DWC_OTG_HC_XFER_NYET,
28421 + DWC_OTG_HC_XFER_STALL,
28422 + DWC_OTG_HC_XFER_XACT_ERR,
28423 + DWC_OTG_HC_XFER_FRAME_OVERRUN,
28424 + DWC_OTG_HC_XFER_BABBLE_ERR,
28425 + DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
28426 + DWC_OTG_HC_XFER_AHB_ERR,
28427 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
28428 + DWC_OTG_HC_XFER_URB_DEQUEUE
28429 +} dwc_otg_halt_status_e;
28430 +
28431 +/**
28432 + * Host channel descriptor. This structure represents the state of a single
28433 + * host channel when acting in host mode. It contains the data items needed to
28434 + * transfer packets to an endpoint via a host channel.
28435 + */
28436 +typedef struct dwc_hc {
28437 + /** Host channel number used for register address lookup */
28438 + uint8_t hc_num;
28439 +
28440 + /** Device to access */
28441 + unsigned dev_addr:7;
28442 +
28443 + /** EP to access */
28444 + unsigned ep_num:4;
28445 +
28446 + /** EP direction. 0: OUT, 1: IN */
28447 + unsigned ep_is_in:1;
28448 +
28449 + /**
28450 + * EP speed.
28451 + * One of the following values:
28452 + * - DWC_OTG_EP_SPEED_LOW
28453 + * - DWC_OTG_EP_SPEED_FULL
28454 + * - DWC_OTG_EP_SPEED_HIGH
28455 + */
28456 + unsigned speed:2;
28457 +#define DWC_OTG_EP_SPEED_LOW 0
28458 +#define DWC_OTG_EP_SPEED_FULL 1
28459 +#define DWC_OTG_EP_SPEED_HIGH 2
28460 +
28461 + /**
28462 + * Endpoint type.
28463 + * One of the following values:
28464 + * - DWC_OTG_EP_TYPE_CONTROL: 0
28465 + * - DWC_OTG_EP_TYPE_ISOC: 1
28466 + * - DWC_OTG_EP_TYPE_BULK: 2
28467 + * - DWC_OTG_EP_TYPE_INTR: 3
28468 + */
28469 + unsigned ep_type:2;
28470 +
28471 + /** Max packet size in bytes */
28472 + unsigned max_packet:11;
28473 +
28474 + /**
28475 + * PID for initial transaction.
28476 + * 0: DATA0,<br>
28477 + * 1: DATA2,<br>
28478 + * 2: DATA1,<br>
28479 + * 3: MDATA (non-Control EP),
28480 + * SETUP (Control EP)
28481 + */
28482 + unsigned data_pid_start:2;
28483 +#define DWC_OTG_HC_PID_DATA0 0
28484 +#define DWC_OTG_HC_PID_DATA2 1
28485 +#define DWC_OTG_HC_PID_DATA1 2
28486 +#define DWC_OTG_HC_PID_MDATA 3
28487 +#define DWC_OTG_HC_PID_SETUP 3
28488 +
28489 + /** Number of periodic transactions per (micro)frame */
28490 + unsigned multi_count:2;
28491 +
28492 + /** @name Transfer State */
28493 + /** @{ */
28494 +
28495 + /** Pointer to the current transfer buffer position. */
28496 + uint8_t *xfer_buff;
28497 + /**
28498 + * In Buffer DMA mode this buffer will be used
28499 + * if xfer_buff is not DWORD aligned.
28500 + */
28501 + dwc_dma_t align_buff;
28502 + /** Total number of bytes to transfer. */
28503 + uint32_t xfer_len;
28504 + /** Number of bytes transferred so far. */
28505 + uint32_t xfer_count;
28506 + /** Packet count at start of transfer.*/
28507 + uint16_t start_pkt_count;
28508 +
28509 + /**
28510 + * Flag to indicate whether the transfer has been started. Set to 1 if
28511 + * it has been started, 0 otherwise.
28512 + */
28513 + uint8_t xfer_started;
28514 +
28515 + /**
28516 + * Set to 1 to indicate that a PING request should be issued on this
28517 + * channel. If 0, process normally.
28518 + */
28519 + uint8_t do_ping;
28520 +
28521 + /**
28522 + * Set to 1 to indicate that the error count for this transaction is
28523 + * non-zero. Set to 0 if the error count is 0.
28524 + */
28525 + uint8_t error_state;
28526 +
28527 + /**
28528 + * Set to 1 to indicate that this channel should be halted the next
28529 + * time a request is queued for the channel. This is necessary in
28530 + * slave mode if no request queue space is available when an attempt
28531 + * is made to halt the channel.
28532 + */
28533 + uint8_t halt_on_queue;
28534 +
28535 + /**
28536 + * Set to 1 if the host channel has been halted, but the core is not
28537 + * finished flushing queued requests. Otherwise 0.
28538 + */
28539 + uint8_t halt_pending;
28540 +
28541 + /**
28542 + * Reason for halting the host channel.
28543 + */
28544 + dwc_otg_halt_status_e halt_status;
28545 +
28546 + /*
28547 + * Split settings for the host channel
28548 + */
28549 + uint8_t do_split; /**< Enable split for the channel */
28550 + uint8_t complete_split; /**< Enable complete split */
28551 + uint8_t hub_addr; /**< Address of high speed hub */
28552 +
28553 + uint8_t port_addr; /**< Port of the low/full speed device */
28554 + /** Split transaction position
28555 + * One of the following values:
28556 + * - DWC_HCSPLIT_XACTPOS_MID
28557 + * - DWC_HCSPLIT_XACTPOS_BEGIN
28558 + * - DWC_HCSPLIT_XACTPOS_END
28559 + * - DWC_HCSPLIT_XACTPOS_ALL */
28560 + uint8_t xact_pos;
28561 +
28562 + /** Set when the host channel does a short read. */
28563 + uint8_t short_read;
28564 +
28565 + /**
28566 + * Number of requests issued for this channel since it was assigned to
28567 + * the current transfer (not counting PINGs).
28568 + */
28569 + uint8_t requests;
28570 +
28571 + /**
28572 + * Queue Head for the transfer being processed by this channel.
28573 + */
28574 + struct dwc_otg_qh *qh;
28575 +
28576 + /** @} */
28577 +
28578 + /** Entry in list of host channels. */
28579 + DWC_CIRCLEQ_ENTRY(dwc_hc) hc_list_entry;
28580 +
28581 + /** @name Descriptor DMA support */
28582 + /** @{ */
28583 +
28584 + /** Number of Transfer Descriptors */
28585 + uint16_t ntd;
28586 +
28587 + /** Descriptor List DMA address */
28588 + dwc_dma_t desc_list_addr;
28589 +
28590 + /** Scheduling micro-frame bitmap. */
28591 + uint8_t schinfo;
28592 +
28593 + /** @} */
28594 +} dwc_hc_t;
28595 +
28596 +/**
28597 + * The following parameters may be specified when starting the module. These
28598 + * parameters define how the DWC_otg controller should be configured.
28599 + */
28600 +typedef struct dwc_otg_core_params {
28601 + int32_t opt;
28602 +
28603 + /**
28604 + * Specifies the OTG capabilities. The driver will automatically
28605 + * detect the value for this parameter if none is specified.
28606 + * 0 - HNP and SRP capable (default)
28607 + * 1 - SRP Only capable
28608 + * 2 - No HNP/SRP capable
28609 + */
28610 + int32_t otg_cap;
28611 +
28612 + /**
28613 + * Specifies whether to use slave or DMA mode for accessing the data
28614 + * FIFOs. The driver will automatically detect the value for this
28615 + * parameter if none is specified.
28616 + * 0 - Slave
28617 + * 1 - DMA (default, if available)
28618 + */
28619 + int32_t dma_enable;
28620 +
28621 + /**
28622 + * When DMA mode is enabled specifies whether to use address DMA or DMA
28623 + * Descriptor mode for accessing the data FIFOs in device mode. The driver
28624 + * will automatically detect the value for this if none is specified.
28625 + * 0 - address DMA
28626 + * 1 - DMA Descriptor(default, if available)
28627 + */
28628 + int32_t dma_desc_enable;
28629 + /** The DMA Burst size (applicable only for External DMA
28630 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
28631 + */
28632 + int32_t dma_burst_size; /* Translate this to GAHBCFG values */
28633 +
28634 + /**
28635 + * Specifies the maximum speed of operation in host and device mode.
28636 + * The actual speed depends on the speed of the attached device and
28637 + * the value of phy_type. The actual speed depends on the speed of the
28638 + * attached device.
28639 + * 0 - High Speed (default)
28640 + * 1 - Full Speed
28641 + */
28642 + int32_t speed;
28643 + /** Specifies whether low power mode is supported when attached
28644 + * to a Full Speed or Low Speed device in host mode.
28645 + * 0 - Don't support low power mode (default)
28646 + * 1 - Support low power mode
28647 + */
28648 + int32_t host_support_fs_ls_low_power;
28649 +
28650 + /** Specifies the PHY clock rate in low power mode when connected to a
28651 + * Low Speed device in host mode. This parameter is applicable only if
28652 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
28653 + * then defaults to 6 MHZ otherwise 48 MHZ.
28654 + *
28655 + * 0 - 48 MHz
28656 + * 1 - 6 MHz
28657 + */
28658 + int32_t host_ls_low_power_phy_clk;
28659 +
28660 + /**
28661 + * 0 - Use cC FIFO size parameters
28662 + * 1 - Allow dynamic FIFO sizing (default)
28663 + */
28664 + int32_t enable_dynamic_fifo;
28665 +
28666 + /** Total number of 4-byte words in the data FIFO memory. This
28667 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
28668 + * Tx FIFOs.
28669 + * 32 to 32768 (default 8192)
28670 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
28671 + */
28672 + int32_t data_fifo_size;
28673 +
28674 + /** Number of 4-byte words in the Rx FIFO in device mode when dynamic
28675 + * FIFO sizing is enabled.
28676 + * 16 to 32768 (default 1064)
28677 + */
28678 + int32_t dev_rx_fifo_size;
28679 +
28680 + /** Number of 4-byte words in the non-periodic Tx FIFO in device mode
28681 + * when dynamic FIFO sizing is enabled.
28682 + * 16 to 32768 (default 1024)
28683 + */
28684 + int32_t dev_nperio_tx_fifo_size;
28685 +
28686 + /** Number of 4-byte words in each of the periodic Tx FIFOs in device
28687 + * mode when dynamic FIFO sizing is enabled.
28688 + * 4 to 768 (default 256)
28689 + */
28690 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
28691 +
28692 + /** Number of 4-byte words in the Rx FIFO in host mode when dynamic
28693 + * FIFO sizing is enabled.
28694 + * 16 to 32768 (default 1024)
28695 + */
28696 + int32_t host_rx_fifo_size;
28697 +
28698 + /** Number of 4-byte words in the non-periodic Tx FIFO in host mode
28699 + * when Dynamic FIFO sizing is enabled in the core.
28700 + * 16 to 32768 (default 1024)
28701 + */
28702 + int32_t host_nperio_tx_fifo_size;
28703 +
28704 + /** Number of 4-byte words in the host periodic Tx FIFO when dynamic
28705 + * FIFO sizing is enabled.
28706 + * 16 to 32768 (default 1024)
28707 + */
28708 + int32_t host_perio_tx_fifo_size;
28709 +
28710 + /** The maximum transfer size supported in bytes.
28711 + * 2047 to 65,535 (default 65,535)
28712 + */
28713 + int32_t max_transfer_size;
28714 +
28715 + /** The maximum number of packets in a transfer.
28716 + * 15 to 511 (default 511)
28717 + */
28718 + int32_t max_packet_count;
28719 +
28720 + /** The number of host channel registers to use.
28721 + * 1 to 16 (default 12)
28722 + * Note: The FPGA configuration supports a maximum of 12 host channels.
28723 + */
28724 + int32_t host_channels;
28725 +
28726 + /** The number of endpoints in addition to EP0 available for device
28727 + * mode operations.
28728 + * 1 to 15 (default 6 IN and OUT)
28729 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
28730 + * endpoints in addition to EP0.
28731 + */
28732 + int32_t dev_endpoints;
28733 +
28734 + /**
28735 + * Specifies the type of PHY interface to use. By default, the driver
28736 + * will automatically detect the phy_type.
28737 + *
28738 + * 0 - Full Speed PHY
28739 + * 1 - UTMI+ (default)
28740 + * 2 - ULPI
28741 + */
28742 + int32_t phy_type;
28743 +
28744 + /**
28745 + * Specifies the UTMI+ Data Width. This parameter is
28746 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
28747 + * PHY_TYPE, this parameter indicates the data width between
28748 + * the MAC and the ULPI Wrapper.) Also, this parameter is
28749 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
28750 + * to "8 and 16 bits", meaning that the core has been
28751 + * configured to work at either data path width.
28752 + *
28753 + * 8 or 16 bits (default 16)
28754 + */
28755 + int32_t phy_utmi_width;
28756 +
28757 + /**
28758 + * Specifies whether the ULPI operates at double or single
28759 + * data rate. This parameter is only applicable if PHY_TYPE is
28760 + * ULPI.
28761 + *
28762 + * 0 - single data rate ULPI interface with 8 bit wide data
28763 + * bus (default)
28764 + * 1 - double data rate ULPI interface with 4 bit wide data
28765 + * bus
28766 + */
28767 + int32_t phy_ulpi_ddr;
28768 +
28769 + /**
28770 + * Specifies whether to use the internal or external supply to
28771 + * drive the vbus with a ULPI phy.
28772 + */
28773 + int32_t phy_ulpi_ext_vbus;
28774 +
28775 + /**
28776 + * Specifies whether to use the I2Cinterface for full speed PHY. This
28777 + * parameter is only applicable if PHY_TYPE is FS.
28778 + * 0 - No (default)
28779 + * 1 - Yes
28780 + */
28781 + int32_t i2c_enable;
28782 +
28783 + int32_t ulpi_fs_ls;
28784 +
28785 + int32_t ts_dline;
28786 +
28787 + /**
28788 + * Specifies whether dedicated transmit FIFOs are
28789 + * enabled for non periodic IN endpoints in device mode
28790 + * 0 - No
28791 + * 1 - Yes
28792 + */
28793 + int32_t en_multiple_tx_fifo;
28794 +
28795 + /** Number of 4-byte words in each of the Tx FIFOs in device
28796 + * mode when dynamic FIFO sizing is enabled.
28797 + * 4 to 768 (default 256)
28798 + */
28799 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
28800 +
28801 + /** Thresholding enable flag-
28802 + * bit 0 - enable non-ISO Tx thresholding
28803 + * bit 1 - enable ISO Tx thresholding
28804 + * bit 2 - enable Rx thresholding
28805 + */
28806 + uint32_t thr_ctl;
28807 +
28808 + /** Thresholding length for Tx
28809 + * FIFOs in 32 bit DWORDs
28810 + */
28811 + uint32_t tx_thr_length;
28812 +
28813 + /** Thresholding length for Rx
28814 + * FIFOs in 32 bit DWORDs
28815 + */
28816 + uint32_t rx_thr_length;
28817 +
28818 + /**
28819 + * Specifies whether LPM (Link Power Management) support is enabled
28820 + */
28821 + int32_t lpm_enable;
28822 +
28823 + /** Per Transfer Interrupt
28824 + * mode enable flag
28825 + * 1 - Enabled
28826 + * 0 - Disabled
28827 + */
28828 + int32_t pti_enable;
28829 +
28830 + /** Multi Processor Interrupt
28831 + * mode enable flag
28832 + * 1 - Enabled
28833 + * 0 - Disabled
28834 + */
28835 + int32_t mpi_enable;
28836 +
28837 + /** IS_USB Capability
28838 + * 1 - Enabled
28839 + * 0 - Disabled
28840 + */
28841 + int32_t ic_usb_cap;
28842 +
28843 + /** AHB Threshold Ratio
28844 + * 2'b00 AHB Threshold = MAC Threshold
28845 + * 2'b01 AHB Threshold = 1/2 MAC Threshold
28846 + * 2'b10 AHB Threshold = 1/4 MAC Threshold
28847 + * 2'b11 AHB Threshold = 1/8 MAC Threshold
28848 + */
28849 + int32_t ahb_thr_ratio;
28850 +
28851 + /** ADP Support
28852 + * 1 - Enabled
28853 + * 0 - Disabled
28854 + */
28855 + int32_t adp_supp_enable;
28856 +
28857 + /** HFIR Reload Control
28858 + * 0 - The HFIR cannot be reloaded dynamically.
28859 + * 1 - Allow dynamic reloading of the HFIR register during runtime.
28860 + */
28861 + int32_t reload_ctl;
28862 +
28863 + /** DCFG: Enable device Out NAK
28864 + * 0 - The core does not set NAK after Bulk Out transfer complete.
28865 + * 1 - The core sets NAK after Bulk OUT transfer complete.
28866 + */
28867 + int32_t dev_out_nak;
28868 +
28869 + /** DCFG: Enable Continue on BNA
28870 + * After receiving BNA interrupt the core disables the endpoint,when the
28871 + * endpoint is re-enabled by the application the core starts processing
28872 + * 0 - from the DOEPDMA descriptor
28873 + * 1 - from the descriptor which received the BNA.
28874 + */
28875 + int32_t cont_on_bna;
28876 +
28877 + /** GAHBCFG: AHB Single Support
28878 + * This bit when programmed supports SINGLE transfers for remainder
28879 + * data in a transfer for DMA mode of operation.
28880 + * 0 - in this case the remainder data will be sent using INCR burst size.
28881 + * 1 - in this case the remainder data will be sent using SINGLE burst size.
28882 + */
28883 + int32_t ahb_single;
28884 +
28885 + /** Core Power down mode
28886 + * 0 - No Power Down is enabled
28887 + * 1 - Reserved
28888 + * 2 - Complete Power Down (Hibernation)
28889 + */
28890 + int32_t power_down;
28891 +
28892 + /** OTG revision supported
28893 + * 0 - OTG 1.3 revision
28894 + * 1 - OTG 2.0 revision
28895 + */
28896 + int32_t otg_ver;
28897 +
28898 +} dwc_otg_core_params_t;
28899 +
28900 +#ifdef DEBUG
28901 +struct dwc_otg_core_if;
28902 +typedef struct hc_xfer_info {
28903 + struct dwc_otg_core_if *core_if;
28904 + dwc_hc_t *hc;
28905 +} hc_xfer_info_t;
28906 +#endif
28907 +
28908 +typedef struct ep_xfer_info {
28909 + struct dwc_otg_core_if *core_if;
28910 + dwc_ep_t *ep;
28911 + uint8_t state;
28912 +} ep_xfer_info_t;
28913 +/*
28914 + * Device States
28915 + */
28916 +typedef enum dwc_otg_lx_state {
28917 + /** On state */
28918 + DWC_OTG_L0,
28919 + /** LPM sleep state*/
28920 + DWC_OTG_L1,
28921 + /** USB suspend state*/
28922 + DWC_OTG_L2,
28923 + /** Off state*/
28924 + DWC_OTG_L3
28925 +} dwc_otg_lx_state_e;
28926 +
28927 +struct dwc_otg_global_regs_backup {
28928 + uint32_t gotgctl_local;
28929 + uint32_t gintmsk_local;
28930 + uint32_t gahbcfg_local;
28931 + uint32_t gusbcfg_local;
28932 + uint32_t grxfsiz_local;
28933 + uint32_t gnptxfsiz_local;
28934 +#ifdef CONFIG_USB_DWC_OTG_LPM
28935 + uint32_t glpmcfg_local;
28936 +#endif
28937 + uint32_t gi2cctl_local;
28938 + uint32_t hptxfsiz_local;
28939 + uint32_t pcgcctl_local;
28940 + uint32_t gdfifocfg_local;
28941 + uint32_t dtxfsiz_local[MAX_EPS_CHANNELS];
28942 + uint32_t gpwrdn_local;
28943 + uint32_t xhib_pcgcctl;
28944 + uint32_t xhib_gpwrdn;
28945 +};
28946 +
28947 +struct dwc_otg_host_regs_backup {
28948 + uint32_t hcfg_local;
28949 + uint32_t haintmsk_local;
28950 + uint32_t hcintmsk_local[MAX_EPS_CHANNELS];
28951 + uint32_t hprt0_local;
28952 + uint32_t hfir_local;
28953 +};
28954 +
28955 +struct dwc_otg_dev_regs_backup {
28956 + uint32_t dcfg;
28957 + uint32_t dctl;
28958 + uint32_t daintmsk;
28959 + uint32_t diepmsk;
28960 + uint32_t doepmsk;
28961 + uint32_t diepctl[MAX_EPS_CHANNELS];
28962 + uint32_t dieptsiz[MAX_EPS_CHANNELS];
28963 + uint32_t diepdma[MAX_EPS_CHANNELS];
28964 +};
28965 +/**
28966 + * The <code>dwc_otg_core_if</code> structure contains information needed to manage
28967 + * the DWC_otg controller acting in either host or device mode. It
28968 + * represents the programming view of the controller as a whole.
28969 + */
28970 +struct dwc_otg_core_if {
28971 + /** Parameters that define how the core should be configured.*/
28972 + dwc_otg_core_params_t *core_params;
28973 +
28974 + /** Core Global registers starting at offset 000h. */
28975 + dwc_otg_core_global_regs_t *core_global_regs;
28976 +
28977 + /** Device-specific information */
28978 + dwc_otg_dev_if_t *dev_if;
28979 + /** Host-specific information */
28980 + dwc_otg_host_if_t *host_if;
28981 +
28982 + /** Value from SNPSID register */
28983 + uint32_t snpsid;
28984 +
28985 + /*
28986 + * Set to 1 if the core PHY interface bits in USBCFG have been
28987 + * initialized.
28988 + */
28989 + uint8_t phy_init_done;
28990 +
28991 + /*
28992 + * SRP Success flag, set by srp success interrupt in FS I2C mode
28993 + */
28994 + uint8_t srp_success;
28995 + uint8_t srp_timer_started;
28996 + /** Timer for SRP. If it expires before SRP is successful
28997 + * clear the SRP. */
28998 + dwc_timer_t *srp_timer;
28999 +
29000 +#ifdef DWC_DEV_SRPCAP
29001 + /* This timer is needed to power on the hibernated host core if SRP is not
29002 + * initiated on connected SRP capable device for limited period of time
29003 + */
29004 + uint8_t pwron_timer_started;
29005 + dwc_timer_t *pwron_timer;
29006 +#endif
29007 + /* Common configuration information */
29008 + /** Power and Clock Gating Control Register */
29009 + volatile uint32_t *pcgcctl;
29010 +#define DWC_OTG_PCGCCTL_OFFSET 0xE00
29011 +
29012 + /** Push/pop addresses for endpoints or host channels.*/
29013 + uint32_t *data_fifo[MAX_EPS_CHANNELS];
29014 +#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
29015 +#define DWC_OTG_DATA_FIFO_SIZE 0x1000
29016 +
29017 + /** Total RAM for FIFOs (Bytes) */
29018 + uint16_t total_fifo_size;
29019 + /** Size of Rx FIFO (Bytes) */
29020 + uint16_t rx_fifo_size;
29021 + /** Size of Non-periodic Tx FIFO (Bytes) */
29022 + uint16_t nperio_tx_fifo_size;
29023 +
29024 + /** 1 if DMA is enabled, 0 otherwise. */
29025 + uint8_t dma_enable;
29026 +
29027 + /** 1 if DMA descriptor is enabled, 0 otherwise. */
29028 + uint8_t dma_desc_enable;
29029 +
29030 + /** 1 if PTI Enhancement mode is enabled, 0 otherwise. */
29031 + uint8_t pti_enh_enable;
29032 +
29033 + /** 1 if MPI Enhancement mode is enabled, 0 otherwise. */
29034 + uint8_t multiproc_int_enable;
29035 +
29036 + /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */
29037 + uint8_t en_multiple_tx_fifo;
29038 +
29039 + /** Set to 1 if multiple packets of a high-bandwidth transfer is in
29040 + * process of being queued */
29041 + uint8_t queuing_high_bandwidth;
29042 +
29043 + /** Hardware Configuration -- stored here for convenience.*/
29044 + hwcfg1_data_t hwcfg1;
29045 + hwcfg2_data_t hwcfg2;
29046 + hwcfg3_data_t hwcfg3;
29047 + hwcfg4_data_t hwcfg4;
29048 + fifosize_data_t hptxfsiz;
29049 +
29050 + /** Host and Device Configuration -- stored here for convenience.*/
29051 + hcfg_data_t hcfg;
29052 + dcfg_data_t dcfg;
29053 +
29054 + /** The operational State, during transations
29055 + * (a_host>>a_peripherial and b_device=>b_host) this may not
29056 + * match the core but allows the software to determine
29057 + * transitions.
29058 + */
29059 + uint8_t op_state;
29060 +
29061 + /**
29062 + * Set to 1 if the HCD needs to be restarted on a session request
29063 + * interrupt. This is required if no connector ID status change has
29064 + * occurred since the HCD was last disconnected.
29065 + */
29066 + uint8_t restart_hcd_on_session_req;
29067 +
29068 + /** HCD callbacks */
29069 + /** A-Device is a_host */
29070 +#define A_HOST (1)
29071 + /** A-Device is a_suspend */
29072 +#define A_SUSPEND (2)
29073 + /** A-Device is a_peripherial */
29074 +#define A_PERIPHERAL (3)
29075 + /** B-Device is operating as a Peripheral. */
29076 +#define B_PERIPHERAL (4)
29077 + /** B-Device is operating as a Host. */
29078 +#define B_HOST (5)
29079 +
29080 + /** HCD callbacks */
29081 + struct dwc_otg_cil_callbacks *hcd_cb;
29082 + /** PCD callbacks */
29083 + struct dwc_otg_cil_callbacks *pcd_cb;
29084 +
29085 + /** Device mode Periodic Tx FIFO Mask */
29086 + uint32_t p_tx_msk;
29087 + /** Device mode Periodic Tx FIFO Mask */
29088 + uint32_t tx_msk;
29089 +
29090 + /** Workqueue object used for handling several interrupts */
29091 + dwc_workq_t *wq_otg;
29092 +
29093 + /** Timer object used for handling "Wakeup Detected" Interrupt */
29094 + dwc_timer_t *wkp_timer;
29095 + /** This arrays used for debug purposes for DEV OUT NAK enhancement */
29096 + uint32_t start_doeptsiz_val[MAX_EPS_CHANNELS];
29097 + ep_xfer_info_t ep_xfer_info[MAX_EPS_CHANNELS];
29098 + dwc_timer_t *ep_xfer_timer[MAX_EPS_CHANNELS];
29099 +#ifdef DEBUG
29100 + uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
29101 +
29102 + hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS];
29103 + dwc_timer_t *hc_xfer_timer[MAX_EPS_CHANNELS];
29104 +
29105 + uint32_t hfnum_7_samples;
29106 + uint64_t hfnum_7_frrem_accum;
29107 + uint32_t hfnum_0_samples;
29108 + uint64_t hfnum_0_frrem_accum;
29109 + uint32_t hfnum_other_samples;
29110 + uint64_t hfnum_other_frrem_accum;
29111 +#endif
29112 +
29113 +#ifdef DWC_UTE_CFI
29114 + uint16_t pwron_rxfsiz;
29115 + uint16_t pwron_gnptxfsiz;
29116 + uint16_t pwron_txfsiz[15];
29117 +
29118 + uint16_t init_rxfsiz;
29119 + uint16_t init_gnptxfsiz;
29120 + uint16_t init_txfsiz[15];
29121 +#endif
29122 +
29123 + /** Lx state of device */
29124 + dwc_otg_lx_state_e lx_state;
29125 +
29126 + /** Saved Core Global registers */
29127 + struct dwc_otg_global_regs_backup *gr_backup;
29128 + /** Saved Host registers */
29129 + struct dwc_otg_host_regs_backup *hr_backup;
29130 + /** Saved Device registers */
29131 + struct dwc_otg_dev_regs_backup *dr_backup;
29132 +
29133 + /** Power Down Enable */
29134 + uint32_t power_down;
29135 +
29136 + /** ADP support Enable */
29137 + uint32_t adp_enable;
29138 +
29139 + /** ADP structure object */
29140 + dwc_otg_adp_t adp;
29141 +
29142 + /** hibernation/suspend flag */
29143 + int hibernation_suspend;
29144 +
29145 + /** Device mode extended hibernation flag */
29146 + int xhib;
29147 +
29148 + /** OTG revision supported */
29149 + uint32_t otg_ver;
29150 +
29151 + /** OTG status flag used for HNP polling */
29152 + uint8_t otg_sts;
29153 +
29154 + /** Pointer to either hcd->lock or pcd->lock */
29155 + dwc_spinlock_t *lock;
29156 +
29157 + /** Start predict NextEP based on Learning Queue if equal 1,
29158 + * also used as counter of disabled NP IN EP's */
29159 + uint8_t start_predict;
29160 +
29161 + /** NextEp sequence, including EP0: nextep_seq[] = EP if non-periodic and
29162 + * active, 0xff otherwise */
29163 + uint8_t nextep_seq[MAX_EPS_CHANNELS];
29164 +
29165 + /** Index of fisrt EP in nextep_seq array which should be re-enabled **/
29166 + uint8_t first_in_nextep_seq;
29167 +
29168 + /** Frame number while entering to ISR - needed for ISOCs **/
29169 + uint32_t frame_num;
29170 +
29171 +};
29172 +
29173 +#ifdef DEBUG
29174 +/*
29175 + * This function is called when transfer is timed out.
29176 + */
29177 +extern void hc_xfer_timeout(void *ptr);
29178 +#endif
29179 +
29180 +/*
29181 + * This function is called when transfer is timed out on endpoint.
29182 + */
29183 +extern void ep_xfer_timeout(void *ptr);
29184 +
29185 +/*
29186 + * The following functions are functions for works
29187 + * using during handling some interrupts
29188 + */
29189 +extern void w_conn_id_status_change(void *p);
29190 +
29191 +extern void w_wakeup_detected(void *p);
29192 +
29193 +/** Saves global register values into system memory. */
29194 +extern int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if);
29195 +/** Saves device register values into system memory. */
29196 +extern int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if);
29197 +/** Saves host register values into system memory. */
29198 +extern int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if);
29199 +/** Restore global register values. */
29200 +extern int dwc_otg_restore_global_regs(dwc_otg_core_if_t * core_if);
29201 +/** Restore host register values. */
29202 +extern int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset);
29203 +/** Restore device register values. */
29204 +extern int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if,
29205 + int rem_wakeup);
29206 +extern int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if);
29207 +extern int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode,
29208 + int is_host);
29209 +
29210 +extern int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
29211 + int restore_mode, int reset);
29212 +extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
29213 + int rem_wakeup, int reset);
29214 +
29215 +/*
29216 + * The following functions support initialization of the CIL driver component
29217 + * and the DWC_otg controller.
29218 + */
29219 +extern void dwc_otg_core_host_init(dwc_otg_core_if_t * _core_if);
29220 +extern void dwc_otg_core_dev_init(dwc_otg_core_if_t * _core_if);
29221 +
29222 +/** @name Device CIL Functions
29223 + * The following functions support managing the DWC_otg controller in device
29224 + * mode.
29225 + */
29226 +/**@{*/
29227 +extern void dwc_otg_wakeup(dwc_otg_core_if_t * _core_if);
29228 +extern void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if,
29229 + uint32_t * _dest);
29230 +extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if);
29231 +extern void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29232 +extern void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29233 +extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29234 +extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if,
29235 + dwc_ep_t * _ep);
29236 +extern void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * _core_if,
29237 + dwc_ep_t * _ep);
29238 +extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * _core_if,
29239 + dwc_ep_t * _ep);
29240 +extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * _core_if,
29241 + dwc_ep_t * _ep);
29242 +extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t * _core_if,
29243 + dwc_ep_t * _ep, int _dma);
29244 +extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29245 +extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * _core_if,
29246 + dwc_ep_t * _ep);
29247 +extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * _core_if);
29248 +
29249 +#ifdef DWC_EN_ISOC
29250 +extern void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
29251 + dwc_ep_t * ep);
29252 +extern void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
29253 + dwc_ep_t * ep);
29254 +#endif /* DWC_EN_ISOC */
29255 +/**@}*/
29256 +
29257 +/** @name Host CIL Functions
29258 + * The following functions support managing the DWC_otg controller in host
29259 + * mode.
29260 + */
29261 +/**@{*/
29262 +extern void dwc_otg_hc_init(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29263 +extern void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if,
29264 + dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status);
29265 +extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29266 +extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if,
29267 + dwc_hc_t * _hc);
29268 +extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if,
29269 + dwc_hc_t * _hc);
29270 +extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29271 +extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if,
29272 + dwc_hc_t * _hc);
29273 +extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * _core_if);
29274 +extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * _core_if);
29275 +
29276 +extern void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if,
29277 + dwc_hc_t * hc);
29278 +
29279 +extern uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if);
29280 +
29281 +/* Macro used to clear one channel interrupt */
29282 +#define clear_hc_int(_hc_regs_, _intr_) \
29283 +do { \
29284 + hcint_data_t hcint_clear = {.d32 = 0}; \
29285 + hcint_clear.b._intr_ = 1; \
29286 + DWC_WRITE_REG32(&(_hc_regs_)->hcint, hcint_clear.d32); \
29287 +} while (0)
29288 +
29289 +/*
29290 + * Macro used to disable one channel interrupt. Channel interrupts are
29291 + * disabled when the channel is halted or released by the interrupt handler.
29292 + * There is no need to handle further interrupts of that type until the
29293 + * channel is re-assigned. In fact, subsequent handling may cause crashes
29294 + * because the channel structures are cleaned up when the channel is released.
29295 + */
29296 +#define disable_hc_int(_hc_regs_, _intr_) \
29297 +do { \
29298 + hcintmsk_data_t hcintmsk = {.d32 = 0}; \
29299 + hcintmsk.b._intr_ = 1; \
29300 + DWC_MODIFY_REG32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \
29301 +} while (0)
29302 +
29303 +/**
29304 + * This function Reads HPRT0 in preparation to modify. It keeps the
29305 + * WC bits 0 so that if they are read as 1, they won't clear when you
29306 + * write it back
29307 + */
29308 +static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t * _core_if)
29309 +{
29310 + hprt0_data_t hprt0;
29311 + hprt0.d32 = DWC_READ_REG32(_core_if->host_if->hprt0);
29312 + hprt0.b.prtena = 0;
29313 + hprt0.b.prtconndet = 0;
29314 + hprt0.b.prtenchng = 0;
29315 + hprt0.b.prtovrcurrchng = 0;
29316 + return hprt0.d32;
29317 +}
29318 +
29319 +/**@}*/
29320 +
29321 +/** @name Common CIL Functions
29322 + * The following functions support managing the DWC_otg controller in either
29323 + * device or host mode.
29324 + */
29325 +/**@{*/
29326 +
29327 +extern void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
29328 + uint8_t * dest, uint16_t bytes);
29329 +
29330 +extern void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * _core_if, const int _num);
29331 +extern void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * _core_if);
29332 +extern void dwc_otg_core_reset(dwc_otg_core_if_t * _core_if);
29333 +
29334 +/**
29335 + * This function returns the Core Interrupt register.
29336 + */
29337 +static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t * core_if)
29338 +{
29339 + return (DWC_READ_REG32(&core_if->core_global_regs->gintsts) &
29340 + DWC_READ_REG32(&core_if->core_global_regs->gintmsk));
29341 +}
29342 +
29343 +/**
29344 + * This function returns the OTG Interrupt register.
29345 + */
29346 +static inline uint32_t dwc_otg_read_otg_intr(dwc_otg_core_if_t * core_if)
29347 +{
29348 + return (DWC_READ_REG32(&core_if->core_global_regs->gotgint));
29349 +}
29350 +
29351 +/**
29352 + * This function reads the Device All Endpoints Interrupt register and
29353 + * returns the IN endpoint interrupt bits.
29354 + */
29355 +static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *
29356 + core_if)
29357 +{
29358 +
29359 + uint32_t v;
29360 +
29361 + if (core_if->multiproc_int_enable) {
29362 + v = DWC_READ_REG32(&core_if->dev_if->
29363 + dev_global_regs->deachint) &
29364 + DWC_READ_REG32(&core_if->
29365 + dev_if->dev_global_regs->deachintmsk);
29366 + } else {
29367 + v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
29368 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
29369 + }
29370 + return (v & 0xffff);
29371 +}
29372 +
29373 +/**
29374 + * This function reads the Device All Endpoints Interrupt register and
29375 + * returns the OUT endpoint interrupt bits.
29376 + */
29377 +static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *
29378 + core_if)
29379 +{
29380 + uint32_t v;
29381 +
29382 + if (core_if->multiproc_int_enable) {
29383 + v = DWC_READ_REG32(&core_if->dev_if->
29384 + dev_global_regs->deachint) &
29385 + DWC_READ_REG32(&core_if->
29386 + dev_if->dev_global_regs->deachintmsk);
29387 + } else {
29388 + v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
29389 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
29390 + }
29391 +
29392 + return ((v & 0xffff0000) >> 16);
29393 +}
29394 +
29395 +/**
29396 + * This function returns the Device IN EP Interrupt register
29397 + */
29398 +static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t * core_if,
29399 + dwc_ep_t * ep)
29400 +{
29401 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
29402 + uint32_t v, msk, emp;
29403 +
29404 + if (core_if->multiproc_int_enable) {
29405 + msk =
29406 + DWC_READ_REG32(&dev_if->
29407 + dev_global_regs->diepeachintmsk[ep->num]);
29408 + emp =
29409 + DWC_READ_REG32(&dev_if->
29410 + dev_global_regs->dtknqr4_fifoemptymsk);
29411 + msk |= ((emp >> ep->num) & 0x1) << 7;
29412 + v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
29413 + } else {
29414 + msk = DWC_READ_REG32(&dev_if->dev_global_regs->diepmsk);
29415 + emp =
29416 + DWC_READ_REG32(&dev_if->
29417 + dev_global_regs->dtknqr4_fifoemptymsk);
29418 + msk |= ((emp >> ep->num) & 0x1) << 7;
29419 + v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
29420 + }
29421 +
29422 + return v;
29423 +}
29424 +
29425 +/**
29426 + * This function returns the Device OUT EP Interrupt register
29427 + */
29428 +static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *
29429 + _core_if, dwc_ep_t * _ep)
29430 +{
29431 + dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
29432 + uint32_t v;
29433 + doepmsk_data_t msk = {.d32 = 0 };
29434 +
29435 + if (_core_if->multiproc_int_enable) {
29436 + msk.d32 =
29437 + DWC_READ_REG32(&dev_if->
29438 + dev_global_regs->doepeachintmsk[_ep->num]);
29439 + if (_core_if->pti_enh_enable) {
29440 + msk.b.pktdrpsts = 1;
29441 + }
29442 + v = DWC_READ_REG32(&dev_if->
29443 + out_ep_regs[_ep->num]->doepint) & msk.d32;
29444 + } else {
29445 + msk.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->doepmsk);
29446 + if (_core_if->pti_enh_enable) {
29447 + msk.b.pktdrpsts = 1;
29448 + }
29449 + v = DWC_READ_REG32(&dev_if->
29450 + out_ep_regs[_ep->num]->doepint) & msk.d32;
29451 + }
29452 + return v;
29453 +}
29454 +
29455 +/**
29456 + * This function returns the Host All Channel Interrupt register
29457 + */
29458 +static inline uint32_t dwc_otg_read_host_all_channels_intr(dwc_otg_core_if_t *
29459 + _core_if)
29460 +{
29461 + return (DWC_READ_REG32(&_core_if->host_if->host_global_regs->haint));
29462 +}
29463 +
29464 +static inline uint32_t dwc_otg_read_host_channel_intr(dwc_otg_core_if_t *
29465 + _core_if, dwc_hc_t * _hc)
29466 +{
29467 + return (DWC_READ_REG32
29468 + (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint));
29469 +}
29470 +
29471 +/**
29472 + * This function returns the mode of the operation, host or device.
29473 + *
29474 + * @return 0 - Device Mode, 1 - Host Mode
29475 + */
29476 +static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t * _core_if)
29477 +{
29478 + return (DWC_READ_REG32(&_core_if->core_global_regs->gintsts) & 0x1);
29479 +}
29480 +
29481 +/**@}*/
29482 +
29483 +/**
29484 + * DWC_otg CIL callback structure. This structure allows the HCD and
29485 + * PCD to register functions used for starting and stopping the PCD
29486 + * and HCD for role change on for a DRD.
29487 + */
29488 +typedef struct dwc_otg_cil_callbacks {
29489 + /** Start function for role change */
29490 + int (*start) (void *_p);
29491 + /** Stop Function for role change */
29492 + int (*stop) (void *_p);
29493 + /** Disconnect Function for role change */
29494 + int (*disconnect) (void *_p);
29495 + /** Resume/Remote wakeup Function */
29496 + int (*resume_wakeup) (void *_p);
29497 + /** Suspend function */
29498 + int (*suspend) (void *_p);
29499 + /** Session Start (SRP) */
29500 + int (*session_start) (void *_p);
29501 +#ifdef CONFIG_USB_DWC_OTG_LPM
29502 + /** Sleep (switch to L0 state) */
29503 + int (*sleep) (void *_p);
29504 +#endif
29505 + /** Pointer passed to start() and stop() */
29506 + void *p;
29507 +} dwc_otg_cil_callbacks_t;
29508 +
29509 +extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if,
29510 + dwc_otg_cil_callbacks_t * _cb,
29511 + void *_p);
29512 +extern void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * _core_if,
29513 + dwc_otg_cil_callbacks_t * _cb,
29514 + void *_p);
29515 +
29516 +void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if);
29517 +
29518 +//////////////////////////////////////////////////////////////////////
29519 +/** Start the HCD. Helper function for using the HCD callbacks.
29520 + *
29521 + * @param core_if Programming view of DWC_otg controller.
29522 + */
29523 +static inline void cil_hcd_start(dwc_otg_core_if_t * core_if)
29524 +{
29525 + if (core_if->hcd_cb && core_if->hcd_cb->start) {
29526 + core_if->hcd_cb->start(core_if->hcd_cb->p);
29527 + }
29528 +}
29529 +
29530 +/** Stop the HCD. Helper function for using the HCD callbacks.
29531 + *
29532 + * @param core_if Programming view of DWC_otg controller.
29533 + */
29534 +static inline void cil_hcd_stop(dwc_otg_core_if_t * core_if)
29535 +{
29536 + if (core_if->hcd_cb && core_if->hcd_cb->stop) {
29537 + core_if->hcd_cb->stop(core_if->hcd_cb->p);
29538 + }
29539 +}
29540 +
29541 +/** Disconnect the HCD. Helper function for using the HCD callbacks.
29542 + *
29543 + * @param core_if Programming view of DWC_otg controller.
29544 + */
29545 +static inline void cil_hcd_disconnect(dwc_otg_core_if_t * core_if)
29546 +{
29547 + if (core_if->hcd_cb && core_if->hcd_cb->disconnect) {
29548 + core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
29549 + }
29550 +}
29551 +
29552 +/** Inform the HCD the a New Session has begun. Helper function for
29553 + * using the HCD callbacks.
29554 + *
29555 + * @param core_if Programming view of DWC_otg controller.
29556 + */
29557 +static inline void cil_hcd_session_start(dwc_otg_core_if_t * core_if)
29558 +{
29559 + if (core_if->hcd_cb && core_if->hcd_cb->session_start) {
29560 + core_if->hcd_cb->session_start(core_if->hcd_cb->p);
29561 + }
29562 +}
29563 +
29564 +#ifdef CONFIG_USB_DWC_OTG_LPM
29565 +/**
29566 + * Inform the HCD about LPM sleep.
29567 + * Helper function for using the HCD callbacks.
29568 + *
29569 + * @param core_if Programming view of DWC_otg controller.
29570 + */
29571 +static inline void cil_hcd_sleep(dwc_otg_core_if_t * core_if)
29572 +{
29573 + if (core_if->hcd_cb && core_if->hcd_cb->sleep) {
29574 + core_if->hcd_cb->sleep(core_if->hcd_cb->p);
29575 + }
29576 +}
29577 +#endif
29578 +
29579 +/** Resume the HCD. Helper function for using the HCD callbacks.
29580 + *
29581 + * @param core_if Programming view of DWC_otg controller.
29582 + */
29583 +static inline void cil_hcd_resume(dwc_otg_core_if_t * core_if)
29584 +{
29585 + if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) {
29586 + core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p);
29587 + }
29588 +}
29589 +
29590 +/** Start the PCD. Helper function for using the PCD callbacks.
29591 + *
29592 + * @param core_if Programming view of DWC_otg controller.
29593 + */
29594 +static inline void cil_pcd_start(dwc_otg_core_if_t * core_if)
29595 +{
29596 + if (core_if->pcd_cb && core_if->pcd_cb->start) {
29597 + core_if->pcd_cb->start(core_if->pcd_cb->p);
29598 + }
29599 +}
29600 +
29601 +/** Stop the PCD. Helper function for using the PCD callbacks.
29602 + *
29603 + * @param core_if Programming view of DWC_otg controller.
29604 + */
29605 +static inline void cil_pcd_stop(dwc_otg_core_if_t * core_if)
29606 +{
29607 + if (core_if->pcd_cb && core_if->pcd_cb->stop) {
29608 + core_if->pcd_cb->stop(core_if->pcd_cb->p);
29609 + }
29610 +}
29611 +
29612 +/** Suspend the PCD. Helper function for using the PCD callbacks.
29613 + *
29614 + * @param core_if Programming view of DWC_otg controller.
29615 + */
29616 +static inline void cil_pcd_suspend(dwc_otg_core_if_t * core_if)
29617 +{
29618 + if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
29619 + core_if->pcd_cb->suspend(core_if->pcd_cb->p);
29620 + }
29621 +}
29622 +
29623 +/** Resume the PCD. Helper function for using the PCD callbacks.
29624 + *
29625 + * @param core_if Programming view of DWC_otg controller.
29626 + */
29627 +static inline void cil_pcd_resume(dwc_otg_core_if_t * core_if)
29628 +{
29629 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
29630 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
29631 + }
29632 +}
29633 +
29634 +//////////////////////////////////////////////////////////////////////
29635 +
29636 +#endif
29637 --- /dev/null
29638 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
29639 @@ -0,0 +1,1563 @@
29640 +/* ==========================================================================
29641 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
29642 + * $Revision: #32 $
29643 + * $Date: 2012/08/10 $
29644 + * $Change: 2047372 $
29645 + *
29646 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
29647 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
29648 + * otherwise expressly agreed to in writing between Synopsys and you.
29649 + *
29650 + * The Software IS NOT an item of Licensed Software or Licensed Product under
29651 + * any End User Software License Agreement or Agreement for Licensed Product
29652 + * with Synopsys or any supplement thereto. You are permitted to use and
29653 + * redistribute this Software in source and binary forms, with or without
29654 + * modification, provided that redistributions of source code must retain this
29655 + * notice. You may not view, use, disclose, copy or distribute this file or
29656 + * any information contained herein except pursuant to this license grant from
29657 + * Synopsys. If you do not agree with this notice, including the disclaimer
29658 + * below, then you are not authorized to use the Software.
29659 + *
29660 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
29661 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29662 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29663 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
29664 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29665 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29666 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29667 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29668 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29669 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29670 + * DAMAGE.
29671 + * ========================================================================== */
29672 +
29673 +/** @file
29674 + *
29675 + * The Core Interface Layer provides basic services for accessing and
29676 + * managing the DWC_otg hardware. These services are used by both the
29677 + * Host Controller Driver and the Peripheral Controller Driver.
29678 + *
29679 + * This file contains the Common Interrupt handlers.
29680 + */
29681 +#include "dwc_os.h"
29682 +#include "dwc_otg_regs.h"
29683 +#include "dwc_otg_cil.h"
29684 +#include "dwc_otg_driver.h"
29685 +#include "dwc_otg_pcd.h"
29686 +#include "dwc_otg_hcd.h"
29687 +
29688 +#ifdef DEBUG
29689 +inline const char *op_state_str(dwc_otg_core_if_t * core_if)
29690 +{
29691 + return (core_if->op_state == A_HOST ? "a_host" :
29692 + (core_if->op_state == A_SUSPEND ? "a_suspend" :
29693 + (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
29694 + (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
29695 + (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
29696 +}
29697 +#endif
29698 +
29699 +/** This function will log a debug message
29700 + *
29701 + * @param core_if Programming view of DWC_otg controller.
29702 + */
29703 +int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if)
29704 +{
29705 + gintsts_data_t gintsts;
29706 + DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
29707 + dwc_otg_mode(core_if) ? "Host" : "Device");
29708 +
29709 + /* Clear interrupt */
29710 + gintsts.d32 = 0;
29711 + gintsts.b.modemismatch = 1;
29712 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
29713 + return 1;
29714 +}
29715 +
29716 +/**
29717 + * This function handles the OTG Interrupts. It reads the OTG
29718 + * Interrupt Register (GOTGINT) to determine what interrupt has
29719 + * occurred.
29720 + *
29721 + * @param core_if Programming view of DWC_otg controller.
29722 + */
29723 +int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if)
29724 +{
29725 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
29726 + gotgint_data_t gotgint;
29727 + gotgctl_data_t gotgctl;
29728 + gintmsk_data_t gintmsk;
29729 + gpwrdn_data_t gpwrdn;
29730 +
29731 + gotgint.d32 = DWC_READ_REG32(&global_regs->gotgint);
29732 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29733 + DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
29734 + op_state_str(core_if));
29735 +
29736 + if (gotgint.b.sesenddet) {
29737 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29738 + "Session End Detected++ (%s)\n",
29739 + op_state_str(core_if));
29740 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29741 +
29742 + if (core_if->op_state == B_HOST) {
29743 + cil_pcd_start(core_if);
29744 + core_if->op_state = B_PERIPHERAL;
29745 + } else {
29746 + /* If not B_HOST and Device HNP still set. HNP
29747 + * Did not succeed!*/
29748 + if (gotgctl.b.devhnpen) {
29749 + DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
29750 + __DWC_ERROR("Device Not Connected/Responding!\n");
29751 + }
29752 +
29753 + /* If Session End Detected the B-Cable has
29754 + * been disconnected. */
29755 + /* Reset PCD and Gadget driver to a
29756 + * clean state. */
29757 + core_if->lx_state = DWC_OTG_L0;
29758 + DWC_SPINUNLOCK(core_if->lock);
29759 + cil_pcd_stop(core_if);
29760 + DWC_SPINLOCK(core_if->lock);
29761 +
29762 + if (core_if->adp_enable) {
29763 + if (core_if->power_down == 2) {
29764 + gpwrdn.d32 = 0;
29765 + gpwrdn.b.pwrdnswtch = 1;
29766 + DWC_MODIFY_REG32(&core_if->
29767 + core_global_regs->
29768 + gpwrdn, gpwrdn.d32, 0);
29769 + }
29770 +
29771 + gpwrdn.d32 = 0;
29772 + gpwrdn.b.pmuintsel = 1;
29773 + gpwrdn.b.pmuactv = 1;
29774 + DWC_MODIFY_REG32(&core_if->core_global_regs->
29775 + gpwrdn, 0, gpwrdn.d32);
29776 +
29777 + dwc_otg_adp_sense_start(core_if);
29778 + }
29779 + }
29780 +
29781 + gotgctl.d32 = 0;
29782 + gotgctl.b.devhnpen = 1;
29783 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
29784 + }
29785 + if (gotgint.b.sesreqsucstschng) {
29786 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29787 + "Session Reqeust Success Status Change++\n");
29788 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29789 + if (gotgctl.b.sesreqscs) {
29790 +
29791 + if ((core_if->core_params->phy_type ==
29792 + DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) {
29793 + core_if->srp_success = 1;
29794 + } else {
29795 + DWC_SPINUNLOCK(core_if->lock);
29796 + cil_pcd_resume(core_if);
29797 + DWC_SPINLOCK(core_if->lock);
29798 + /* Clear Session Request */
29799 + gotgctl.d32 = 0;
29800 + gotgctl.b.sesreq = 1;
29801 + DWC_MODIFY_REG32(&global_regs->gotgctl,
29802 + gotgctl.d32, 0);
29803 + }
29804 + }
29805 + }
29806 + if (gotgint.b.hstnegsucstschng) {
29807 + /* Print statements during the HNP interrupt handling
29808 + * can cause it to fail.*/
29809 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29810 + /* WA for 3.00a- HW is not setting cur_mode, even sometimes
29811 + * this does not help*/
29812 + if (core_if->snpsid >= OTG_CORE_REV_3_00a)
29813 + dwc_udelay(100);
29814 + if (gotgctl.b.hstnegscs) {
29815 + if (dwc_otg_is_host_mode(core_if)) {
29816 + core_if->op_state = B_HOST;
29817 + /*
29818 + * Need to disable SOF interrupt immediately.
29819 + * When switching from device to host, the PCD
29820 + * interrupt handler won't handle the
29821 + * interrupt if host mode is already set. The
29822 + * HCD interrupt handler won't get called if
29823 + * the HCD state is HALT. This means that the
29824 + * interrupt does not get handled and Linux
29825 + * complains loudly.
29826 + */
29827 + gintmsk.d32 = 0;
29828 + gintmsk.b.sofintr = 1;
29829 + DWC_MODIFY_REG32(&global_regs->gintmsk,
29830 + gintmsk.d32, 0);
29831 + /* Call callback function with spin lock released */
29832 + DWC_SPINUNLOCK(core_if->lock);
29833 + cil_pcd_stop(core_if);
29834 + /*
29835 + * Initialize the Core for Host mode.
29836 + */
29837 + cil_hcd_start(core_if);
29838 + DWC_SPINLOCK(core_if->lock);
29839 + core_if->op_state = B_HOST;
29840 + }
29841 + } else {
29842 + gotgctl.d32 = 0;
29843 + gotgctl.b.hnpreq = 1;
29844 + gotgctl.b.devhnpen = 1;
29845 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
29846 + DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
29847 + __DWC_ERROR("Device Not Connected/Responding\n");
29848 + }
29849 + }
29850 + if (gotgint.b.hstnegdet) {
29851 + /* The disconnect interrupt is set at the same time as
29852 + * Host Negotiation Detected. During the mode
29853 + * switch all interrupts are cleared so the disconnect
29854 + * interrupt handler will not get executed.
29855 + */
29856 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29857 + "Host Negotiation Detected++ (%s)\n",
29858 + (dwc_otg_is_host_mode(core_if) ? "Host" :
29859 + "Device"));
29860 + if (dwc_otg_is_device_mode(core_if)) {
29861 + DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
29862 + core_if->op_state);
29863 + DWC_SPINUNLOCK(core_if->lock);
29864 + cil_hcd_disconnect(core_if);
29865 + cil_pcd_start(core_if);
29866 + DWC_SPINLOCK(core_if->lock);
29867 + core_if->op_state = A_PERIPHERAL;
29868 + } else {
29869 + /*
29870 + * Need to disable SOF interrupt immediately. When
29871 + * switching from device to host, the PCD interrupt
29872 + * handler won't handle the interrupt if host mode is
29873 + * already set. The HCD interrupt handler won't get
29874 + * called if the HCD state is HALT. This means that
29875 + * the interrupt does not get handled and Linux
29876 + * complains loudly.
29877 + */
29878 + gintmsk.d32 = 0;
29879 + gintmsk.b.sofintr = 1;
29880 + DWC_MODIFY_REG32(&global_regs->gintmsk, gintmsk.d32, 0);
29881 + DWC_SPINUNLOCK(core_if->lock);
29882 + cil_pcd_stop(core_if);
29883 + cil_hcd_start(core_if);
29884 + DWC_SPINLOCK(core_if->lock);
29885 + core_if->op_state = A_HOST;
29886 + }
29887 + }
29888 + if (gotgint.b.adevtoutchng) {
29889 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29890 + "A-Device Timeout Change++\n");
29891 + }
29892 + if (gotgint.b.debdone) {
29893 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
29894 + }
29895 +
29896 + /* Clear GOTGINT */
29897 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, gotgint.d32);
29898 +
29899 + return 1;
29900 +}
29901 +
29902 +void w_conn_id_status_change(void *p)
29903 +{
29904 + dwc_otg_core_if_t *core_if = p;
29905 + uint32_t count = 0;
29906 + gotgctl_data_t gotgctl = {.d32 = 0 };
29907 +
29908 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
29909 + DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
29910 + DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
29911 +
29912 + /* B-Device connector (Device Mode) */
29913 + if (gotgctl.b.conidsts) {
29914 + /* Wait for switch to device mode. */
29915 + while (!dwc_otg_is_device_mode(core_if)) {
29916 + DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
29917 + (dwc_otg_is_host_mode(core_if) ? "Host" :
29918 + "Peripheral"));
29919 + dwc_mdelay(100);
29920 + if (++count > 10000)
29921 + break;
29922 + }
29923 + DWC_ASSERT(++count < 10000,
29924 + "Connection id status change timed out");
29925 + core_if->op_state = B_PERIPHERAL;
29926 + dwc_otg_core_init(core_if);
29927 + dwc_otg_enable_global_interrupts(core_if);
29928 + cil_pcd_start(core_if);
29929 + } else {
29930 + /* A-Device connector (Host Mode) */
29931 + while (!dwc_otg_is_host_mode(core_if)) {
29932 + DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
29933 + (dwc_otg_is_host_mode(core_if) ? "Host" :
29934 + "Peripheral"));
29935 + dwc_mdelay(100);
29936 + if (++count > 10000)
29937 + break;
29938 + }
29939 + DWC_ASSERT(++count < 10000,
29940 + "Connection id status change timed out");
29941 + core_if->op_state = A_HOST;
29942 + /*
29943 + * Initialize the Core for Host mode.
29944 + */
29945 + dwc_otg_core_init(core_if);
29946 + dwc_otg_enable_global_interrupts(core_if);
29947 + cil_hcd_start(core_if);
29948 + }
29949 +}
29950 +
29951 +/**
29952 + * This function handles the Connector ID Status Change Interrupt. It
29953 + * reads the OTG Interrupt Register (GOTCTL) to determine whether this
29954 + * is a Device to Host Mode transition or a Host Mode to Device
29955 + * Transition.
29956 + *
29957 + * This only occurs when the cable is connected/removed from the PHY
29958 + * connector.
29959 + *
29960 + * @param core_if Programming view of DWC_otg controller.
29961 + */
29962 +int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
29963 +{
29964 +
29965 + /*
29966 + * Need to disable SOF interrupt immediately. If switching from device
29967 + * to host, the PCD interrupt handler won't handle the interrupt if
29968 + * host mode is already set. The HCD interrupt handler won't get
29969 + * called if the HCD state is HALT. This means that the interrupt does
29970 + * not get handled and Linux complains loudly.
29971 + */
29972 + gintmsk_data_t gintmsk = {.d32 = 0 };
29973 + gintsts_data_t gintsts = {.d32 = 0 };
29974 +
29975 + gintmsk.b.sofintr = 1;
29976 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
29977 +
29978 + DWC_DEBUGPL(DBG_CIL,
29979 + " ++Connector ID Status Change Interrupt++ (%s)\n",
29980 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
29981 +
29982 + DWC_SPINUNLOCK(core_if->lock);
29983 +
29984 + /*
29985 + * Need to schedule a work, as there are possible DELAY function calls
29986 + * Release lock before scheduling workq as it holds spinlock during scheduling
29987 + */
29988 +
29989 + DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
29990 + core_if, "connection id status change");
29991 + DWC_SPINLOCK(core_if->lock);
29992 +
29993 + /* Set flag and clear interrupt */
29994 + gintsts.b.conidstschng = 1;
29995 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
29996 +
29997 + return 1;
29998 +}
29999 +
30000 +/**
30001 + * This interrupt indicates that a device is initiating the Session
30002 + * Request Protocol to request the host to turn on bus power so a new
30003 + * session can begin. The handler responds by turning on bus power. If
30004 + * the DWC_otg controller is in low power mode, the handler brings the
30005 + * controller out of low power mode before turning on bus power.
30006 + *
30007 + * @param core_if Programming view of DWC_otg controller.
30008 + */
30009 +int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
30010 +{
30011 + gintsts_data_t gintsts;
30012 +
30013 +#ifndef DWC_HOST_ONLY
30014 + DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
30015 +
30016 + if (dwc_otg_is_device_mode(core_if)) {
30017 + DWC_PRINTF("SRP: Device mode\n");
30018 + } else {
30019 + hprt0_data_t hprt0;
30020 + DWC_PRINTF("SRP: Host mode\n");
30021 +
30022 + /* Turn on the port power bit. */
30023 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
30024 + hprt0.b.prtpwr = 1;
30025 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
30026 +
30027 + /* Start the Connection timer. So a message can be displayed
30028 + * if connect does not occur within 10 seconds. */
30029 + cil_hcd_session_start(core_if);
30030 + }
30031 +#endif
30032 +
30033 + /* Clear interrupt */
30034 + gintsts.d32 = 0;
30035 + gintsts.b.sessreqintr = 1;
30036 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30037 +
30038 + return 1;
30039 +}
30040 +
30041 +void w_wakeup_detected(void *p)
30042 +{
30043 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
30044 + /*
30045 + * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
30046 + * so that OPT tests pass with all PHYs).
30047 + */
30048 + hprt0_data_t hprt0 = {.d32 = 0 };
30049 +#if 0
30050 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30051 + /* Restart the Phy Clock */
30052 + pcgcctl.b.stoppclk = 1;
30053 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
30054 + dwc_udelay(10);
30055 +#endif //0
30056 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
30057 + DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
30058 +// dwc_mdelay(70);
30059 + hprt0.b.prtres = 0; /* Resume */
30060 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
30061 + DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
30062 + DWC_READ_REG32(core_if->host_if->hprt0));
30063 +
30064 + cil_hcd_resume(core_if);
30065 +
30066 + /** Change to L0 state*/
30067 + core_if->lx_state = DWC_OTG_L0;
30068 +}
30069 +
30070 +/**
30071 + * This interrupt indicates that the DWC_otg controller has detected a
30072 + * resume or remote wakeup sequence. If the DWC_otg controller is in
30073 + * low power mode, the handler must brings the controller out of low
30074 + * power mode. The controller automatically begins resume
30075 + * signaling. The handler schedules a time to stop resume signaling.
30076 + */
30077 +int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
30078 +{
30079 + gintsts_data_t gintsts;
30080 +
30081 + DWC_DEBUGPL(DBG_ANY,
30082 + "++Resume and Remote Wakeup Detected Interrupt++\n");
30083 +
30084 + DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
30085 +
30086 + if (dwc_otg_is_device_mode(core_if)) {
30087 + dctl_data_t dctl = {.d32 = 0 };
30088 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
30089 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
30090 + dsts));
30091 + if (core_if->lx_state == DWC_OTG_L2) {
30092 +#ifdef PARTIAL_POWER_DOWN
30093 + if (core_if->hwcfg4.b.power_optimiz) {
30094 + pcgcctl_data_t power = {.d32 = 0 };
30095 +
30096 + power.d32 = DWC_READ_REG32(core_if->pcgcctl);
30097 + DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
30098 + power.d32);
30099 +
30100 + power.b.stoppclk = 0;
30101 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30102 +
30103 + power.b.pwrclmp = 0;
30104 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30105 +
30106 + power.b.rstpdwnmodule = 0;
30107 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30108 + }
30109 +#endif
30110 + /* Clear the Remote Wakeup Signaling */
30111 + dctl.b.rmtwkupsig = 1;
30112 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
30113 + dctl, dctl.d32, 0);
30114 +
30115 + DWC_SPINUNLOCK(core_if->lock);
30116 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
30117 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
30118 + }
30119 + DWC_SPINLOCK(core_if->lock);
30120 + } else {
30121 + glpmcfg_data_t lpmcfg;
30122 + lpmcfg.d32 =
30123 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
30124 + lpmcfg.b.hird_thres &= (~(1 << 4));
30125 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
30126 + lpmcfg.d32);
30127 + }
30128 + /** Change to L0 state*/
30129 + core_if->lx_state = DWC_OTG_L0;
30130 + } else {
30131 + if (core_if->lx_state != DWC_OTG_L1) {
30132 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30133 +
30134 + /* Restart the Phy Clock */
30135 + pcgcctl.b.stoppclk = 1;
30136 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
30137 + DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
30138 + } else {
30139 + /** Change to L0 state*/
30140 + core_if->lx_state = DWC_OTG_L0;
30141 + }
30142 + }
30143 +
30144 + /* Clear interrupt */
30145 + gintsts.d32 = 0;
30146 + gintsts.b.wkupintr = 1;
30147 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30148 +
30149 + return 1;
30150 +}
30151 +
30152 +/**
30153 + * This interrupt indicates that the Wakeup Logic has detected a
30154 + * Device disconnect.
30155 + */
30156 +static int32_t dwc_otg_handle_pwrdn_disconnect_intr(dwc_otg_core_if_t *core_if)
30157 +{
30158 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
30159 + gpwrdn_data_t gpwrdn_temp = { .d32 = 0 };
30160 + gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30161 +
30162 + DWC_PRINTF("%s called\n", __FUNCTION__);
30163 +
30164 + if (!core_if->hibernation_suspend) {
30165 + DWC_PRINTF("Already exited from Hibernation\n");
30166 + return 1;
30167 + }
30168 +
30169 + /* Switch on the voltage to the core */
30170 + gpwrdn.b.pwrdnswtch = 1;
30171 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30172 + dwc_udelay(10);
30173 +
30174 + /* Reset the core */
30175 + gpwrdn.d32 = 0;
30176 + gpwrdn.b.pwrdnrstn = 1;
30177 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30178 + dwc_udelay(10);
30179 +
30180 + /* Disable power clamps*/
30181 + gpwrdn.d32 = 0;
30182 + gpwrdn.b.pwrdnclmp = 1;
30183 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30184 +
30185 + /* Remove reset the core signal */
30186 + gpwrdn.d32 = 0;
30187 + gpwrdn.b.pwrdnrstn = 1;
30188 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30189 + dwc_udelay(10);
30190 +
30191 + /* Disable PMU interrupt */
30192 + gpwrdn.d32 = 0;
30193 + gpwrdn.b.pmuintsel = 1;
30194 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30195 +
30196 + core_if->hibernation_suspend = 0;
30197 +
30198 + /* Disable PMU */
30199 + gpwrdn.d32 = 0;
30200 + gpwrdn.b.pmuactv = 1;
30201 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30202 + dwc_udelay(10);
30203 +
30204 + if (gpwrdn_temp.b.idsts) {
30205 + core_if->op_state = B_PERIPHERAL;
30206 + dwc_otg_core_init(core_if);
30207 + dwc_otg_enable_global_interrupts(core_if);
30208 + cil_pcd_start(core_if);
30209 + } else {
30210 + core_if->op_state = A_HOST;
30211 + dwc_otg_core_init(core_if);
30212 + dwc_otg_enable_global_interrupts(core_if);
30213 + cil_hcd_start(core_if);
30214 + }
30215 +
30216 + return 1;
30217 +}
30218 +
30219 +/**
30220 + * This interrupt indicates that the Wakeup Logic has detected a
30221 + * remote wakeup sequence.
30222 + */
30223 +static int32_t dwc_otg_handle_pwrdn_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
30224 +{
30225 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30226 + DWC_DEBUGPL(DBG_ANY,
30227 + "++Powerdown Remote Wakeup Detected Interrupt++\n");
30228 +
30229 + if (!core_if->hibernation_suspend) {
30230 + DWC_PRINTF("Already exited from Hibernation\n");
30231 + return 1;
30232 + }
30233 +
30234 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30235 + if (gpwrdn.b.idsts) { // Device Mode
30236 + if ((core_if->power_down == 2)
30237 + && (core_if->hibernation_suspend == 1)) {
30238 + dwc_otg_device_hibernation_restore(core_if, 0, 0);
30239 + }
30240 + } else {
30241 + if ((core_if->power_down == 2)
30242 + && (core_if->hibernation_suspend == 1)) {
30243 + dwc_otg_host_hibernation_restore(core_if, 1, 0);
30244 + }
30245 + }
30246 + return 1;
30247 +}
30248 +
30249 +static int32_t dwc_otg_handle_pwrdn_idsts_change(dwc_otg_device_t *otg_dev)
30250 +{
30251 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30252 + gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
30253 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30254 +
30255 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30256 + gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30257 + if (core_if->power_down == 2) {
30258 + if (!core_if->hibernation_suspend) {
30259 + DWC_PRINTF("Already exited from Hibernation\n");
30260 + return 1;
30261 + }
30262 + DWC_DEBUGPL(DBG_ANY, "Exit from hibernation on ID sts change\n");
30263 + /* Switch on the voltage to the core */
30264 + gpwrdn.b.pwrdnswtch = 1;
30265 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30266 + dwc_udelay(10);
30267 +
30268 + /* Reset the core */
30269 + gpwrdn.d32 = 0;
30270 + gpwrdn.b.pwrdnrstn = 1;
30271 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30272 + dwc_udelay(10);
30273 +
30274 + /* Disable power clamps */
30275 + gpwrdn.d32 = 0;
30276 + gpwrdn.b.pwrdnclmp = 1;
30277 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30278 +
30279 + /* Remove reset the core signal */
30280 + gpwrdn.d32 = 0;
30281 + gpwrdn.b.pwrdnrstn = 1;
30282 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30283 + dwc_udelay(10);
30284 +
30285 + /* Disable PMU interrupt */
30286 + gpwrdn.d32 = 0;
30287 + gpwrdn.b.pmuintsel = 1;
30288 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30289 +
30290 + /*Indicates that we are exiting from hibernation */
30291 + core_if->hibernation_suspend = 0;
30292 +
30293 + /* Disable PMU */
30294 + gpwrdn.d32 = 0;
30295 + gpwrdn.b.pmuactv = 1;
30296 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30297 + dwc_udelay(10);
30298 +
30299 + gpwrdn.d32 = core_if->gr_backup->gpwrdn_local;
30300 + if (gpwrdn.b.dis_vbus == 1) {
30301 + gpwrdn.d32 = 0;
30302 + gpwrdn.b.dis_vbus = 1;
30303 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30304 + }
30305 +
30306 + if (gpwrdn_temp.b.idsts) {
30307 + core_if->op_state = B_PERIPHERAL;
30308 + dwc_otg_core_init(core_if);
30309 + dwc_otg_enable_global_interrupts(core_if);
30310 + cil_pcd_start(core_if);
30311 + } else {
30312 + core_if->op_state = A_HOST;
30313 + dwc_otg_core_init(core_if);
30314 + dwc_otg_enable_global_interrupts(core_if);
30315 + cil_hcd_start(core_if);
30316 + }
30317 + }
30318 +
30319 + if (core_if->adp_enable) {
30320 + uint8_t is_host = 0;
30321 + DWC_SPINUNLOCK(core_if->lock);
30322 + /* Change the core_if's lock to hcd/pcd lock depend on mode? */
30323 +#ifndef DWC_HOST_ONLY
30324 + if (gpwrdn_temp.b.idsts)
30325 + core_if->lock = otg_dev->pcd->lock;
30326 +#endif
30327 +#ifndef DWC_DEVICE_ONLY
30328 + if (!gpwrdn_temp.b.idsts) {
30329 + core_if->lock = otg_dev->hcd->lock;
30330 + is_host = 1;
30331 + }
30332 +#endif
30333 + DWC_PRINTF("RESTART ADP\n");
30334 + if (core_if->adp.probe_enabled)
30335 + dwc_otg_adp_probe_stop(core_if);
30336 + if (core_if->adp.sense_enabled)
30337 + dwc_otg_adp_sense_stop(core_if);
30338 + if (core_if->adp.sense_timer_started)
30339 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
30340 + if (core_if->adp.vbuson_timer_started)
30341 + DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
30342 + core_if->adp.probe_timer_values[0] = -1;
30343 + core_if->adp.probe_timer_values[1] = -1;
30344 + core_if->adp.sense_timer_started = 0;
30345 + core_if->adp.vbuson_timer_started = 0;
30346 + core_if->adp.probe_counter = 0;
30347 + core_if->adp.gpwrdn = 0;
30348 +
30349 + /* Disable PMU and restart ADP */
30350 + gpwrdn_temp.d32 = 0;
30351 + gpwrdn_temp.b.pmuactv = 1;
30352 + gpwrdn_temp.b.pmuintsel = 1;
30353 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30354 + DWC_PRINTF("Check point 1\n");
30355 + dwc_mdelay(110);
30356 + dwc_otg_adp_start(core_if, is_host);
30357 + DWC_SPINLOCK(core_if->lock);
30358 + }
30359 +
30360 +
30361 + return 1;
30362 +}
30363 +
30364 +static int32_t dwc_otg_handle_pwrdn_session_change(dwc_otg_core_if_t * core_if)
30365 +{
30366 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30367 + int32_t otg_cap_param = core_if->core_params->otg_cap;
30368 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30369 +
30370 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30371 + if (core_if->power_down == 2) {
30372 + if (!core_if->hibernation_suspend) {
30373 + DWC_PRINTF("Already exited from Hibernation\n");
30374 + return 1;
30375 + }
30376 +
30377 + if ((otg_cap_param != DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
30378 + otg_cap_param != DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) &&
30379 + gpwrdn.b.bsessvld == 0) {
30380 + /* Save gpwrdn register for further usage if stschng interrupt */
30381 + core_if->gr_backup->gpwrdn_local =
30382 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30383 + /*Exit from ISR and wait for stschng interrupt with bsessvld = 1 */
30384 + return 1;
30385 + }
30386 +
30387 + /* Switch on the voltage to the core */
30388 + gpwrdn.d32 = 0;
30389 + gpwrdn.b.pwrdnswtch = 1;
30390 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30391 + dwc_udelay(10);
30392 +
30393 + /* Reset the core */
30394 + gpwrdn.d32 = 0;
30395 + gpwrdn.b.pwrdnrstn = 1;
30396 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30397 + dwc_udelay(10);
30398 +
30399 + /* Disable power clamps */
30400 + gpwrdn.d32 = 0;
30401 + gpwrdn.b.pwrdnclmp = 1;
30402 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30403 +
30404 + /* Remove reset the core signal */
30405 + gpwrdn.d32 = 0;
30406 + gpwrdn.b.pwrdnrstn = 1;
30407 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30408 + dwc_udelay(10);
30409 +
30410 + /* Disable PMU interrupt */
30411 + gpwrdn.d32 = 0;
30412 + gpwrdn.b.pmuintsel = 1;
30413 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30414 + dwc_udelay(10);
30415 +
30416 + /*Indicates that we are exiting from hibernation */
30417 + core_if->hibernation_suspend = 0;
30418 +
30419 + /* Disable PMU */
30420 + gpwrdn.d32 = 0;
30421 + gpwrdn.b.pmuactv = 1;
30422 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30423 + dwc_udelay(10);
30424 +
30425 + core_if->op_state = B_PERIPHERAL;
30426 + dwc_otg_core_init(core_if);
30427 + dwc_otg_enable_global_interrupts(core_if);
30428 + cil_pcd_start(core_if);
30429 +
30430 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
30431 + otg_cap_param == DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) {
30432 + /*
30433 + * Initiate SRP after initial ADP probe.
30434 + */
30435 + dwc_otg_initiate_srp(core_if);
30436 + }
30437 + }
30438 +
30439 + return 1;
30440 +}
30441 +/**
30442 + * This interrupt indicates that the Wakeup Logic has detected a
30443 + * status change either on IDDIG or BSessVld.
30444 + */
30445 +static uint32_t dwc_otg_handle_pwrdn_stschng_intr(dwc_otg_device_t *otg_dev)
30446 +{
30447 + int retval;
30448 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30449 + gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
30450 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30451 +
30452 + DWC_PRINTF("%s called\n", __FUNCTION__);
30453 +
30454 + if (core_if->power_down == 2) {
30455 + if (core_if->hibernation_suspend <= 0) {
30456 + DWC_PRINTF("Already exited from Hibernation\n");
30457 + return 1;
30458 + } else
30459 + gpwrdn_temp.d32 = core_if->gr_backup->gpwrdn_local;
30460 +
30461 + } else {
30462 + gpwrdn_temp.d32 = core_if->adp.gpwrdn;
30463 + }
30464 +
30465 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30466 +
30467 + if (gpwrdn.b.idsts ^ gpwrdn_temp.b.idsts) {
30468 + retval = dwc_otg_handle_pwrdn_idsts_change(otg_dev);
30469 + } else if (gpwrdn.b.bsessvld ^ gpwrdn_temp.b.bsessvld) {
30470 + retval = dwc_otg_handle_pwrdn_session_change(core_if);
30471 + }
30472 +
30473 + return retval;
30474 +}
30475 +
30476 +/**
30477 + * This interrupt indicates that the Wakeup Logic has detected a
30478 + * SRP.
30479 + */
30480 +static int32_t dwc_otg_handle_pwrdn_srp_intr(dwc_otg_core_if_t * core_if)
30481 +{
30482 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30483 +
30484 + DWC_PRINTF("%s called\n", __FUNCTION__);
30485 +
30486 + if (!core_if->hibernation_suspend) {
30487 + DWC_PRINTF("Already exited from Hibernation\n");
30488 + return 1;
30489 + }
30490 +#ifdef DWC_DEV_SRPCAP
30491 + if (core_if->pwron_timer_started) {
30492 + core_if->pwron_timer_started = 0;
30493 + DWC_TIMER_CANCEL(core_if->pwron_timer);
30494 + }
30495 +#endif
30496 +
30497 + /* Switch on the voltage to the core */
30498 + gpwrdn.b.pwrdnswtch = 1;
30499 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30500 + dwc_udelay(10);
30501 +
30502 + /* Reset the core */
30503 + gpwrdn.d32 = 0;
30504 + gpwrdn.b.pwrdnrstn = 1;
30505 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30506 + dwc_udelay(10);
30507 +
30508 + /* Disable power clamps */
30509 + gpwrdn.d32 = 0;
30510 + gpwrdn.b.pwrdnclmp = 1;
30511 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30512 +
30513 + /* Remove reset the core signal */
30514 + gpwrdn.d32 = 0;
30515 + gpwrdn.b.pwrdnrstn = 1;
30516 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30517 + dwc_udelay(10);
30518 +
30519 + /* Disable PMU interrupt */
30520 + gpwrdn.d32 = 0;
30521 + gpwrdn.b.pmuintsel = 1;
30522 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30523 +
30524 + /* Indicates that we are exiting from hibernation */
30525 + core_if->hibernation_suspend = 0;
30526 +
30527 + /* Disable PMU */
30528 + gpwrdn.d32 = 0;
30529 + gpwrdn.b.pmuactv = 1;
30530 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30531 + dwc_udelay(10);
30532 +
30533 + /* Programm Disable VBUS to 0 */
30534 + gpwrdn.d32 = 0;
30535 + gpwrdn.b.dis_vbus = 1;
30536 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30537 +
30538 + /*Initialize the core as Host */
30539 + core_if->op_state = A_HOST;
30540 + dwc_otg_core_init(core_if);
30541 + dwc_otg_enable_global_interrupts(core_if);
30542 + cil_hcd_start(core_if);
30543 +
30544 + return 1;
30545 +}
30546 +
30547 +/** This interrupt indicates that restore command after Hibernation
30548 + * was completed by the core. */
30549 +int32_t dwc_otg_handle_restore_done_intr(dwc_otg_core_if_t * core_if)
30550 +{
30551 + pcgcctl_data_t pcgcctl;
30552 + DWC_DEBUGPL(DBG_ANY, "++Restore Done Interrupt++\n");
30553 +
30554 + //TODO De-assert restore signal. 8.a
30555 + pcgcctl.d32 = DWC_READ_REG32(core_if->pcgcctl);
30556 + if (pcgcctl.b.restoremode == 1) {
30557 + gintmsk_data_t gintmsk = {.d32 = 0 };
30558 + /*
30559 + * If restore mode is Remote Wakeup,
30560 + * unmask Remote Wakeup interrupt.
30561 + */
30562 + gintmsk.b.wkupintr = 1;
30563 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
30564 + 0, gintmsk.d32);
30565 + }
30566 +
30567 + return 1;
30568 +}
30569 +
30570 +/**
30571 + * This interrupt indicates that a device has been disconnected from
30572 + * the root port.
30573 + */
30574 +int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if)
30575 +{
30576 + gintsts_data_t gintsts;
30577 +
30578 + DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
30579 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
30580 + op_state_str(core_if));
30581 +
30582 +/** @todo Consolidate this if statement. */
30583 +#ifndef DWC_HOST_ONLY
30584 + if (core_if->op_state == B_HOST) {
30585 + /* If in device mode Disconnect and stop the HCD, then
30586 + * start the PCD. */
30587 + DWC_SPINUNLOCK(core_if->lock);
30588 + cil_hcd_disconnect(core_if);
30589 + cil_pcd_start(core_if);
30590 + DWC_SPINLOCK(core_if->lock);
30591 + core_if->op_state = B_PERIPHERAL;
30592 + } else if (dwc_otg_is_device_mode(core_if)) {
30593 + gotgctl_data_t gotgctl = {.d32 = 0 };
30594 + gotgctl.d32 =
30595 + DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
30596 + if (gotgctl.b.hstsethnpen == 1) {
30597 + /* Do nothing, if HNP in process the OTG
30598 + * interrupt "Host Negotiation Detected"
30599 + * interrupt will do the mode switch.
30600 + */
30601 + } else if (gotgctl.b.devhnpen == 0) {
30602 + /* If in device mode Disconnect and stop the HCD, then
30603 + * start the PCD. */
30604 + DWC_SPINUNLOCK(core_if->lock);
30605 + cil_hcd_disconnect(core_if);
30606 + cil_pcd_start(core_if);
30607 + DWC_SPINLOCK(core_if->lock);
30608 + core_if->op_state = B_PERIPHERAL;
30609 + } else {
30610 + DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
30611 + }
30612 + } else {
30613 + if (core_if->op_state == A_HOST) {
30614 + /* A-Cable still connected but device disconnected. */
30615 + cil_hcd_disconnect(core_if);
30616 + if (core_if->adp_enable) {
30617 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
30618 + cil_hcd_stop(core_if);
30619 + /* Enable Power Down Logic */
30620 + gpwrdn.b.pmuintsel = 1;
30621 + gpwrdn.b.pmuactv = 1;
30622 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30623 + gpwrdn, 0, gpwrdn.d32);
30624 + dwc_otg_adp_probe_start(core_if);
30625 +
30626 + /* Power off the core */
30627 + if (core_if->power_down == 2) {
30628 + gpwrdn.d32 = 0;
30629 + gpwrdn.b.pwrdnswtch = 1;
30630 + DWC_MODIFY_REG32
30631 + (&core_if->core_global_regs->gpwrdn,
30632 + gpwrdn.d32, 0);
30633 + }
30634 + }
30635 + }
30636 + }
30637 +#endif
30638 + /* Change to L3(OFF) state */
30639 + core_if->lx_state = DWC_OTG_L3;
30640 +
30641 + gintsts.d32 = 0;
30642 + gintsts.b.disconnect = 1;
30643 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30644 + return 1;
30645 +}
30646 +
30647 +/**
30648 + * This interrupt indicates that SUSPEND state has been detected on
30649 + * the USB.
30650 + *
30651 + * For HNP the USB Suspend interrupt signals the change from
30652 + * "a_peripheral" to "a_host".
30653 + *
30654 + * When power management is enabled the core will be put in low power
30655 + * mode.
30656 + */
30657 +int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if)
30658 +{
30659 + dsts_data_t dsts;
30660 + gintsts_data_t gintsts;
30661 + dcfg_data_t dcfg;
30662 +
30663 + DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
30664 +
30665 + if (dwc_otg_is_device_mode(core_if)) {
30666 + /* Check the Device status register to determine if the Suspend
30667 + * state is active. */
30668 + dsts.d32 =
30669 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
30670 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
30671 + DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
30672 + "HWCFG4.power Optimize=%d\n",
30673 + dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
30674 +
30675 +#ifdef PARTIAL_POWER_DOWN
30676 +/** @todo Add a module parameter for power management. */
30677 +
30678 + if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
30679 + pcgcctl_data_t power = {.d32 = 0 };
30680 + DWC_DEBUGPL(DBG_CIL, "suspend\n");
30681 +
30682 + power.b.pwrclmp = 1;
30683 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30684 +
30685 + power.b.rstpdwnmodule = 1;
30686 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
30687 +
30688 + power.b.stoppclk = 1;
30689 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
30690 +
30691 + } else {
30692 + DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
30693 + }
30694 +#endif
30695 + /* PCD callback for suspend. Release the lock inside of callback function */
30696 + cil_pcd_suspend(core_if);
30697 + if (core_if->power_down == 2)
30698 + {
30699 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
30700 + DWC_DEBUGPL(DBG_ANY,"lx_state = %08x\n",core_if->lx_state);
30701 + DWC_DEBUGPL(DBG_ANY," device address = %08d\n",dcfg.b.devaddr);
30702 +
30703 + if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
30704 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30705 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30706 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
30707 +
30708 + /* Change to L2(suspend) state */
30709 + core_if->lx_state = DWC_OTG_L2;
30710 +
30711 + /* Clear interrupt in gintsts */
30712 + gintsts.d32 = 0;
30713 + gintsts.b.usbsuspend = 1;
30714 + DWC_WRITE_REG32(&core_if->core_global_regs->
30715 + gintsts, gintsts.d32);
30716 + DWC_PRINTF("Start of hibernation completed\n");
30717 + dwc_otg_save_global_regs(core_if);
30718 + dwc_otg_save_dev_regs(core_if);
30719 +
30720 + gusbcfg.d32 =
30721 + DWC_READ_REG32(&core_if->core_global_regs->
30722 + gusbcfg);
30723 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
30724 + /* ULPI interface */
30725 + /* Suspend the Phy Clock */
30726 + pcgcctl.d32 = 0;
30727 + pcgcctl.b.stoppclk = 1;
30728 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
30729 + pcgcctl.d32);
30730 + dwc_udelay(10);
30731 + gpwrdn.b.pmuactv = 1;
30732 + DWC_MODIFY_REG32(&core_if->
30733 + core_global_regs->
30734 + gpwrdn, 0, gpwrdn.d32);
30735 + } else {
30736 + /* UTMI+ Interface */
30737 + gpwrdn.b.pmuactv = 1;
30738 + DWC_MODIFY_REG32(&core_if->
30739 + core_global_regs->
30740 + gpwrdn, 0, gpwrdn.d32);
30741 + dwc_udelay(10);
30742 + pcgcctl.b.stoppclk = 1;
30743 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
30744 + pcgcctl.d32);
30745 + dwc_udelay(10);
30746 + }
30747 +
30748 + /* Set flag to indicate that we are in hibernation */
30749 + core_if->hibernation_suspend = 1;
30750 + /* Enable interrupts from wake up logic */
30751 + gpwrdn.d32 = 0;
30752 + gpwrdn.b.pmuintsel = 1;
30753 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30754 + gpwrdn, 0, gpwrdn.d32);
30755 + dwc_udelay(10);
30756 +
30757 + /* Unmask device mode interrupts in GPWRDN */
30758 + gpwrdn.d32 = 0;
30759 + gpwrdn.b.rst_det_msk = 1;
30760 + gpwrdn.b.lnstchng_msk = 1;
30761 + gpwrdn.b.sts_chngint_msk = 1;
30762 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30763 + gpwrdn, 0, gpwrdn.d32);
30764 + dwc_udelay(10);
30765 +
30766 + /* Enable Power Down Clamp */
30767 + gpwrdn.d32 = 0;
30768 + gpwrdn.b.pwrdnclmp = 1;
30769 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30770 + gpwrdn, 0, gpwrdn.d32);
30771 + dwc_udelay(10);
30772 +
30773 + /* Switch off VDD */
30774 + gpwrdn.d32 = 0;
30775 + gpwrdn.b.pwrdnswtch = 1;
30776 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30777 + gpwrdn, 0, gpwrdn.d32);
30778 +
30779 + /* Save gpwrdn register for further usage if stschng interrupt */
30780 + core_if->gr_backup->gpwrdn_local =
30781 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30782 + DWC_PRINTF("Hibernation completed\n");
30783 +
30784 + return 1;
30785 + }
30786 + } else if (core_if->power_down == 3) {
30787 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30788 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
30789 + DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",core_if->lx_state);
30790 + DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",dcfg.b.devaddr);
30791 +
30792 + if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
30793 + DWC_DEBUGPL(DBG_ANY, "Start entering to extended hibernation\n");
30794 + core_if->xhib = 1;
30795 +
30796 + /* Clear interrupt in gintsts */
30797 + gintsts.d32 = 0;
30798 + gintsts.b.usbsuspend = 1;
30799 + DWC_WRITE_REG32(&core_if->core_global_regs->
30800 + gintsts, gintsts.d32);
30801 +
30802 + dwc_otg_save_global_regs(core_if);
30803 + dwc_otg_save_dev_regs(core_if);
30804 +
30805 + /* Wait for 10 PHY clocks */
30806 + dwc_udelay(10);
30807 +
30808 + /* Program GPIO register while entering to xHib */
30809 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x1);
30810 +
30811 + pcgcctl.b.enbl_extnd_hiber = 1;
30812 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30813 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30814 +
30815 + pcgcctl.d32 = 0;
30816 + pcgcctl.b.extnd_hiber_pwrclmp = 1;
30817 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30818 +
30819 + pcgcctl.d32 = 0;
30820 + pcgcctl.b.extnd_hiber_switch = 1;
30821 + core_if->gr_backup->xhib_gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30822 + core_if->gr_backup->xhib_pcgcctl = DWC_READ_REG32(core_if->pcgcctl) | pcgcctl.d32;
30823 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30824 +
30825 + DWC_DEBUGPL(DBG_ANY, "Finished entering to extended hibernation\n");
30826 +
30827 + return 1;
30828 + }
30829 + }
30830 + } else {
30831 + if (core_if->op_state == A_PERIPHERAL) {
30832 + DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
30833 + /* Clear the a_peripheral flag, back to a_host. */
30834 + DWC_SPINUNLOCK(core_if->lock);
30835 + cil_pcd_stop(core_if);
30836 + cil_hcd_start(core_if);
30837 + DWC_SPINLOCK(core_if->lock);
30838 + core_if->op_state = A_HOST;
30839 + }
30840 + }
30841 +
30842 + /* Change to L2(suspend) state */
30843 + core_if->lx_state = DWC_OTG_L2;
30844 +
30845 + /* Clear interrupt */
30846 + gintsts.d32 = 0;
30847 + gintsts.b.usbsuspend = 1;
30848 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30849 +
30850 + return 1;
30851 +}
30852 +
30853 +static int32_t dwc_otg_handle_xhib_exit_intr(dwc_otg_core_if_t * core_if)
30854 +{
30855 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30856 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30857 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
30858 +
30859 + dwc_udelay(10);
30860 +
30861 + /* Program GPIO register while entering to xHib */
30862 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x0);
30863 +
30864 + pcgcctl.d32 = core_if->gr_backup->xhib_pcgcctl;
30865 + pcgcctl.b.extnd_hiber_pwrclmp = 0;
30866 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30867 + dwc_udelay(10);
30868 +
30869 + gpwrdn.d32 = core_if->gr_backup->xhib_gpwrdn;
30870 + gpwrdn.b.restore = 1;
30871 + DWC_WRITE_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32);
30872 + dwc_udelay(10);
30873 +
30874 + restore_lpm_i2c_regs(core_if);
30875 +
30876 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
30877 + pcgcctl.b.max_xcvrselect = 1;
30878 + pcgcctl.b.ess_reg_restored = 0;
30879 + pcgcctl.b.extnd_hiber_switch = 0;
30880 + pcgcctl.b.extnd_hiber_pwrclmp = 0;
30881 + pcgcctl.b.enbl_extnd_hiber = 1;
30882 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30883 +
30884 + gahbcfg.d32 = core_if->gr_backup->gahbcfg_local;
30885 + gahbcfg.b.glblintrmsk = 1;
30886 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
30887 +
30888 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
30889 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0x1 << 16);
30890 +
30891 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
30892 + core_if->gr_backup->gusbcfg_local);
30893 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
30894 + core_if->dr_backup->dcfg);
30895 +
30896 + pcgcctl.d32 = 0;
30897 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
30898 + pcgcctl.b.max_xcvrselect = 1;
30899 + pcgcctl.d32 |= 0x608;
30900 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30901 + dwc_udelay(10);
30902 +
30903 + pcgcctl.d32 = 0;
30904 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
30905 + pcgcctl.b.max_xcvrselect = 1;
30906 + pcgcctl.b.ess_reg_restored = 1;
30907 + pcgcctl.b.enbl_extnd_hiber = 1;
30908 + pcgcctl.b.rstpdwnmodule = 1;
30909 + pcgcctl.b.restoremode = 1;
30910 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30911 +
30912 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30913 +
30914 + return 1;
30915 +}
30916 +
30917 +#ifdef CONFIG_USB_DWC_OTG_LPM
30918 +/**
30919 + * This function hadles LPM transaction received interrupt.
30920 + */
30921 +static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
30922 +{
30923 + glpmcfg_data_t lpmcfg;
30924 + gintsts_data_t gintsts;
30925 +
30926 + if (!core_if->core_params->lpm_enable) {
30927 + DWC_PRINTF("Unexpected LPM interrupt\n");
30928 + }
30929 +
30930 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
30931 + DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
30932 +
30933 + if (dwc_otg_is_host_mode(core_if)) {
30934 + cil_hcd_sleep(core_if);
30935 + } else {
30936 + lpmcfg.b.hird_thres |= (1 << 4);
30937 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
30938 + lpmcfg.d32);
30939 + }
30940 +
30941 + /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
30942 + dwc_udelay(10);
30943 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
30944 + if (lpmcfg.b.prt_sleep_sts) {
30945 + /* Save the current state */
30946 + core_if->lx_state = DWC_OTG_L1;
30947 + }
30948 +
30949 + /* Clear interrupt */
30950 + gintsts.d32 = 0;
30951 + gintsts.b.lpmtranrcvd = 1;
30952 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30953 + return 1;
30954 +}
30955 +#endif /* CONFIG_USB_DWC_OTG_LPM */
30956 +
30957 +/**
30958 + * This function returns the Core Interrupt register.
30959 + */
30960 +static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
30961 +{
30962 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
30963 + gintsts_data_t gintsts;
30964 + gintmsk_data_t gintmsk;
30965 + gintmsk_data_t gintmsk_common = {.d32 = 0 };
30966 + gintmsk_common.b.wkupintr = 1;
30967 + gintmsk_common.b.sessreqintr = 1;
30968 + gintmsk_common.b.conidstschng = 1;
30969 + gintmsk_common.b.otgintr = 1;
30970 + gintmsk_common.b.modemismatch = 1;
30971 + gintmsk_common.b.disconnect = 1;
30972 + gintmsk_common.b.usbsuspend = 1;
30973 +#ifdef CONFIG_USB_DWC_OTG_LPM
30974 + gintmsk_common.b.lpmtranrcvd = 1;
30975 +#endif
30976 + gintmsk_common.b.restoredone = 1;
30977 + /** @todo: The port interrupt occurs while in device
30978 + * mode. Added code to CIL to clear the interrupt for now!
30979 + */
30980 + gintmsk_common.b.portintr = 1;
30981 +
30982 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
30983 + gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
30984 + gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
30985 +
30986 +#ifdef DEBUG
30987 + /* if any common interrupts set */
30988 + if (gintsts.d32 & gintmsk_common.d32) {
30989 + DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
30990 + gintsts.d32, gintmsk.d32);
30991 + }
30992 +#endif
30993 + if (gahbcfg.b.glblintrmsk)
30994 + return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
30995 + else
30996 + return 0;
30997 +
30998 +}
30999 +
31000 +/* MACRO for clearing interupt bits in GPWRDN register */
31001 +#define CLEAR_GPWRDN_INTR(__core_if,__intr) \
31002 +do { \
31003 + gpwrdn_data_t gpwrdn = {.d32=0}; \
31004 + gpwrdn.b.__intr = 1; \
31005 + DWC_MODIFY_REG32(&__core_if->core_global_regs->gpwrdn, \
31006 + 0, gpwrdn.d32); \
31007 +} while (0)
31008 +
31009 +/**
31010 + * Common interrupt handler.
31011 + *
31012 + * The common interrupts are those that occur in both Host and Device mode.
31013 + * This handler handles the following interrupts:
31014 + * - Mode Mismatch Interrupt
31015 + * - Disconnect Interrupt
31016 + * - OTG Interrupt
31017 + * - Connector ID Status Change Interrupt
31018 + * - Session Request Interrupt.
31019 + * - Resume / Remote Wakeup Detected Interrupt.
31020 + * - LPM Transaction Received Interrupt
31021 + * - ADP Transaction Received Interrupt
31022 + *
31023 + */
31024 +int32_t dwc_otg_handle_common_intr(void *dev)
31025 +{
31026 + int retval = 0;
31027 + gintsts_data_t gintsts;
31028 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
31029 + dwc_otg_device_t *otg_dev = dev;
31030 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
31031 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
31032 + if (dwc_otg_is_device_mode(core_if))
31033 + core_if->frame_num = dwc_otg_get_frame_number(core_if);
31034 +
31035 + if (core_if->lock)
31036 + DWC_SPINLOCK(core_if->lock);
31037 +
31038 + if (core_if->power_down == 3 && core_if->xhib == 1) {
31039 + DWC_DEBUGPL(DBG_ANY, "Exiting from xHIB state\n");
31040 + retval |= dwc_otg_handle_xhib_exit_intr(core_if);
31041 + core_if->xhib = 2;
31042 + if (core_if->lock)
31043 + DWC_SPINUNLOCK(core_if->lock);
31044 +
31045 + return retval;
31046 + }
31047 +
31048 + if (core_if->hibernation_suspend <= 0) {
31049 + gintsts.d32 = dwc_otg_read_common_intr(core_if);
31050 +
31051 + if (gintsts.b.modemismatch) {
31052 + retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
31053 + }
31054 + if (gintsts.b.otgintr) {
31055 + retval |= dwc_otg_handle_otg_intr(core_if);
31056 + }
31057 + if (gintsts.b.conidstschng) {
31058 + retval |=
31059 + dwc_otg_handle_conn_id_status_change_intr(core_if);
31060 + }
31061 + if (gintsts.b.disconnect) {
31062 + retval |= dwc_otg_handle_disconnect_intr(core_if);
31063 + }
31064 + if (gintsts.b.sessreqintr) {
31065 + retval |= dwc_otg_handle_session_req_intr(core_if);
31066 + }
31067 + if (gintsts.b.wkupintr) {
31068 + retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
31069 + }
31070 + if (gintsts.b.usbsuspend) {
31071 + retval |= dwc_otg_handle_usb_suspend_intr(core_if);
31072 + }
31073 +#ifdef CONFIG_USB_DWC_OTG_LPM
31074 + if (gintsts.b.lpmtranrcvd) {
31075 + retval |= dwc_otg_handle_lpm_intr(core_if);
31076 + }
31077 +#endif
31078 + if (gintsts.b.restoredone) {
31079 + gintsts.d32 = 0;
31080 + if (core_if->power_down == 2)
31081 + core_if->hibernation_suspend = -1;
31082 + else if (core_if->power_down == 3 && core_if->xhib == 2) {
31083 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
31084 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
31085 + dctl_data_t dctl = {.d32 = 0 };
31086 +
31087 + DWC_WRITE_REG32(&core_if->core_global_regs->
31088 + gintsts, 0xFFFFFFFF);
31089 +
31090 + DWC_DEBUGPL(DBG_ANY,
31091 + "RESTORE DONE generated\n");
31092 +
31093 + gpwrdn.b.restore = 1;
31094 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
31095 + dwc_udelay(10);
31096 +
31097 + pcgcctl.b.rstpdwnmodule = 1;
31098 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
31099 +
31100 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, core_if->gr_backup->gusbcfg_local);
31101 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, core_if->dr_backup->dcfg);
31102 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, core_if->dr_backup->dctl);
31103 + dwc_udelay(50);
31104 +
31105 + dctl.b.pwronprgdone = 1;
31106 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
31107 + dwc_udelay(10);
31108 +
31109 + dwc_otg_restore_global_regs(core_if);
31110 + dwc_otg_restore_dev_regs(core_if, 0);
31111 +
31112 + dctl.d32 = 0;
31113 + dctl.b.pwronprgdone = 1;
31114 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
31115 + dwc_udelay(10);
31116 +
31117 + pcgcctl.d32 = 0;
31118 + pcgcctl.b.enbl_extnd_hiber = 1;
31119 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
31120 +
31121 + /* The core will be in ON STATE */
31122 + core_if->lx_state = DWC_OTG_L0;
31123 + core_if->xhib = 0;
31124 +
31125 + DWC_SPINUNLOCK(core_if->lock);
31126 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
31127 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
31128 + }
31129 + DWC_SPINLOCK(core_if->lock);
31130 +
31131 + }
31132 +
31133 + gintsts.b.restoredone = 1;
31134 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
31135 + DWC_PRINTF(" --Restore done interrupt received-- \n");
31136 + retval |= 1;
31137 + }
31138 + if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
31139 + /* The port interrupt occurs while in device mode with HPRT0
31140 + * Port Enable/Disable.
31141 + */
31142 + gintsts.d32 = 0;
31143 + gintsts.b.portintr = 1;
31144 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
31145 + retval |= 1;
31146 +
31147 + }
31148 + } else {
31149 + DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
31150 +
31151 + if (gpwrdn.b.disconn_det && gpwrdn.b.disconn_det_msk) {
31152 + CLEAR_GPWRDN_INTR(core_if, disconn_det);
31153 + if (gpwrdn.b.linestate == 0) {
31154 + dwc_otg_handle_pwrdn_disconnect_intr(core_if);
31155 + } else {
31156 + DWC_PRINTF("Disconnect detected while linestate is not 0\n");
31157 + }
31158 +
31159 + retval |= 1;
31160 + }
31161 + if (gpwrdn.b.lnstschng && gpwrdn.b.lnstchng_msk) {
31162 + CLEAR_GPWRDN_INTR(core_if, lnstschng);
31163 + /* remote wakeup from hibernation */
31164 + if (gpwrdn.b.linestate == 2 || gpwrdn.b.linestate == 1) {
31165 + dwc_otg_handle_pwrdn_wakeup_detected_intr(core_if);
31166 + } else {
31167 + DWC_PRINTF("gpwrdn.linestate = %d\n", gpwrdn.b.linestate);
31168 + }
31169 + retval |= 1;
31170 + }
31171 + if (gpwrdn.b.rst_det && gpwrdn.b.rst_det_msk) {
31172 + CLEAR_GPWRDN_INTR(core_if, rst_det);
31173 + if (gpwrdn.b.linestate == 0) {
31174 + DWC_PRINTF("Reset detected\n");
31175 + retval |= dwc_otg_device_hibernation_restore(core_if, 0, 1);
31176 + }
31177 + }
31178 + if (gpwrdn.b.srp_det && gpwrdn.b.srp_det_msk) {
31179 + CLEAR_GPWRDN_INTR(core_if, srp_det);
31180 + dwc_otg_handle_pwrdn_srp_intr(core_if);
31181 + retval |= 1;
31182 + }
31183 + }
31184 + /* Handle ADP interrupt here */
31185 + if (gpwrdn.b.adp_int) {
31186 + DWC_PRINTF("ADP interrupt\n");
31187 + CLEAR_GPWRDN_INTR(core_if, adp_int);
31188 + dwc_otg_adp_handle_intr(core_if);
31189 + retval |= 1;
31190 + }
31191 + if (gpwrdn.b.sts_chngint && gpwrdn.b.sts_chngint_msk) {
31192 + DWC_PRINTF("STS CHNG interrupt asserted\n");
31193 + CLEAR_GPWRDN_INTR(core_if, sts_chngint);
31194 + dwc_otg_handle_pwrdn_stschng_intr(otg_dev);
31195 +
31196 + retval |= 1;
31197 + }
31198 + if (core_if->lock)
31199 + DWC_SPINUNLOCK(core_if->lock);
31200 +
31201 + return retval;
31202 +}
31203 --- /dev/null
31204 +++ b/drivers/usb/host/dwc_otg/dwc_otg_core_if.h
31205 @@ -0,0 +1,705 @@
31206 +/* ==========================================================================
31207 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $
31208 + * $Revision: #13 $
31209 + * $Date: 2012/08/10 $
31210 + * $Change: 2047372 $
31211 + *
31212 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
31213 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
31214 + * otherwise expressly agreed to in writing between Synopsys and you.
31215 + *
31216 + * The Software IS NOT an item of Licensed Software or Licensed Product under
31217 + * any End User Software License Agreement or Agreement for Licensed Product
31218 + * with Synopsys or any supplement thereto. You are permitted to use and
31219 + * redistribute this Software in source and binary forms, with or without
31220 + * modification, provided that redistributions of source code must retain this
31221 + * notice. You may not view, use, disclose, copy or distribute this file or
31222 + * any information contained herein except pursuant to this license grant from
31223 + * Synopsys. If you do not agree with this notice, including the disclaimer
31224 + * below, then you are not authorized to use the Software.
31225 + *
31226 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
31227 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31228 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31229 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
31230 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31231 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31232 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31233 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31234 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31235 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31236 + * DAMAGE.
31237 + * ========================================================================== */
31238 +#if !defined(__DWC_CORE_IF_H__)
31239 +#define __DWC_CORE_IF_H__
31240 +
31241 +#include "dwc_os.h"
31242 +
31243 +/** @file
31244 + * This file defines DWC_OTG Core API
31245 + */
31246 +
31247 +struct dwc_otg_core_if;
31248 +typedef struct dwc_otg_core_if dwc_otg_core_if_t;
31249 +
31250 +/** Maximum number of Periodic FIFOs */
31251 +#define MAX_PERIO_FIFOS 15
31252 +/** Maximum number of Periodic FIFOs */
31253 +#define MAX_TX_FIFOS 15
31254 +
31255 +/** Maximum number of Endpoints/HostChannels */
31256 +#define MAX_EPS_CHANNELS 16
31257 +
31258 +extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr);
31259 +extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if);
31260 +extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if);
31261 +
31262 +extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if);
31263 +extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if);
31264 +
31265 +extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if);
31266 +extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if);
31267 +
31268 +extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if);
31269 +
31270 +/** This function should be called on every hardware interrupt. */
31271 +extern int32_t dwc_otg_handle_common_intr(void *otg_dev);
31272 +
31273 +/** @name OTG Core Parameters */
31274 +/** @{ */
31275 +
31276 +/**
31277 + * Specifies the OTG capabilities. The driver will automatically
31278 + * detect the value for this parameter if none is specified.
31279 + * 0 - HNP and SRP capable (default)
31280 + * 1 - SRP Only capable
31281 + * 2 - No HNP/SRP capable
31282 + */
31283 +extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val);
31284 +extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if);
31285 +#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
31286 +#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
31287 +#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
31288 +#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
31289 +
31290 +extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val);
31291 +extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if);
31292 +#define dwc_param_opt_default 1
31293 +
31294 +/**
31295 + * Specifies whether to use slave or DMA mode for accessing the data
31296 + * FIFOs. The driver will automatically detect the value for this
31297 + * parameter if none is specified.
31298 + * 0 - Slave
31299 + * 1 - DMA (default, if available)
31300 + */
31301 +extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if,
31302 + int32_t val);
31303 +extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if);
31304 +#define dwc_param_dma_enable_default 1
31305 +
31306 +/**
31307 + * When DMA mode is enabled specifies whether to use
31308 + * address DMA or DMA Descritor mode for accessing the data
31309 + * FIFOs in device mode. The driver will automatically detect
31310 + * the value for this parameter if none is specified.
31311 + * 0 - address DMA
31312 + * 1 - DMA Descriptor(default, if available)
31313 + */
31314 +extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if,
31315 + int32_t val);
31316 +extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if);
31317 +//#define dwc_param_dma_desc_enable_default 1
31318 +#define dwc_param_dma_desc_enable_default 0 // Broadcom BCM2708
31319 +
31320 +/** The DMA Burst size (applicable only for External DMA
31321 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
31322 + */
31323 +extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if,
31324 + int32_t val);
31325 +extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if);
31326 +#define dwc_param_dma_burst_size_default 32
31327 +
31328 +/**
31329 + * Specifies the maximum speed of operation in host and device mode.
31330 + * The actual speed depends on the speed of the attached device and
31331 + * the value of phy_type. The actual speed depends on the speed of the
31332 + * attached device.
31333 + * 0 - High Speed (default)
31334 + * 1 - Full Speed
31335 + */
31336 +extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val);
31337 +extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if);
31338 +#define dwc_param_speed_default 0
31339 +#define DWC_SPEED_PARAM_HIGH 0
31340 +#define DWC_SPEED_PARAM_FULL 1
31341 +
31342 +/** Specifies whether low power mode is supported when attached
31343 + * to a Full Speed or Low Speed device in host mode.
31344 + * 0 - Don't support low power mode (default)
31345 + * 1 - Support low power mode
31346 + */
31347 +extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
31348 + core_if, int32_t val);
31349 +extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t
31350 + * core_if);
31351 +#define dwc_param_host_support_fs_ls_low_power_default 0
31352 +
31353 +/** Specifies the PHY clock rate in low power mode when connected to a
31354 + * Low Speed device in host mode. This parameter is applicable only if
31355 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
31356 + * then defaults to 6 MHZ otherwise 48 MHZ.
31357 + *
31358 + * 0 - 48 MHz
31359 + * 1 - 6 MHz
31360 + */
31361 +extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
31362 + core_if, int32_t val);
31363 +extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
31364 + core_if);
31365 +#define dwc_param_host_ls_low_power_phy_clk_default 0
31366 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
31367 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
31368 +
31369 +/**
31370 + * 0 - Use cC FIFO size parameters
31371 + * 1 - Allow dynamic FIFO sizing (default)
31372 + */
31373 +extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
31374 + int32_t val);
31375 +extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t *
31376 + core_if);
31377 +#define dwc_param_enable_dynamic_fifo_default 1
31378 +
31379 +/** Total number of 4-byte words in the data FIFO memory. This
31380 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
31381 + * Tx FIFOs.
31382 + * 32 to 32768 (default 8192)
31383 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
31384 + */
31385 +extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if,
31386 + int32_t val);
31387 +extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if);
31388 +//#define dwc_param_data_fifo_size_default 8192
31389 +#define dwc_param_data_fifo_size_default 0xFF0 // Broadcom BCM2708
31390 +
31391 +/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
31392 + * FIFO sizing is enabled.
31393 + * 16 to 32768 (default 1064)
31394 + */
31395 +extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if,
31396 + int32_t val);
31397 +extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if);
31398 +#define dwc_param_dev_rx_fifo_size_default 1064
31399 +
31400 +/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
31401 + * when dynamic FIFO sizing is enabled.
31402 + * 16 to 32768 (default 1024)
31403 + */
31404 +extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
31405 + core_if, int32_t val);
31406 +extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
31407 + core_if);
31408 +#define dwc_param_dev_nperio_tx_fifo_size_default 1024
31409 +
31410 +/** Number of 4-byte words in each of the periodic Tx FIFOs in device
31411 + * mode when dynamic FIFO sizing is enabled.
31412 + * 4 to 768 (default 256)
31413 + */
31414 +extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
31415 + int32_t val, int fifo_num);
31416 +extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t *
31417 + core_if, int fifo_num);
31418 +#define dwc_param_dev_perio_tx_fifo_size_default 256
31419 +
31420 +/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
31421 + * FIFO sizing is enabled.
31422 + * 16 to 32768 (default 1024)
31423 + */
31424 +extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
31425 + int32_t val);
31426 +extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if);
31427 +//#define dwc_param_host_rx_fifo_size_default 1024
31428 +#define dwc_param_host_rx_fifo_size_default 774 // Broadcom BCM2708
31429 +
31430 +/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
31431 + * when Dynamic FIFO sizing is enabled in the core.
31432 + * 16 to 32768 (default 1024)
31433 + */
31434 +extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
31435 + core_if, int32_t val);
31436 +extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
31437 + core_if);
31438 +//#define dwc_param_host_nperio_tx_fifo_size_default 1024
31439 +#define dwc_param_host_nperio_tx_fifo_size_default 0x100 // Broadcom BCM2708
31440 +
31441 +/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
31442 + * FIFO sizing is enabled.
31443 + * 16 to 32768 (default 1024)
31444 + */
31445 +extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
31446 + core_if, int32_t val);
31447 +extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
31448 + core_if);
31449 +//#define dwc_param_host_perio_tx_fifo_size_default 1024
31450 +#define dwc_param_host_perio_tx_fifo_size_default 0x200 // Broadcom BCM2708
31451 +
31452 +/** The maximum transfer size supported in bytes.
31453 + * 2047 to 65,535 (default 65,535)
31454 + */
31455 +extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
31456 + int32_t val);
31457 +extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if);
31458 +#define dwc_param_max_transfer_size_default 65535
31459 +
31460 +/** The maximum number of packets in a transfer.
31461 + * 15 to 511 (default 511)
31462 + */
31463 +extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if,
31464 + int32_t val);
31465 +extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if);
31466 +#define dwc_param_max_packet_count_default 511
31467 +
31468 +/** The number of host channel registers to use.
31469 + * 1 to 16 (default 12)
31470 + * Note: The FPGA configuration supports a maximum of 12 host channels.
31471 + */
31472 +extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if,
31473 + int32_t val);
31474 +extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if);
31475 +//#define dwc_param_host_channels_default 12
31476 +#define dwc_param_host_channels_default 8 // Broadcom BCM2708
31477 +
31478 +/** The number of endpoints in addition to EP0 available for device
31479 + * mode operations.
31480 + * 1 to 15 (default 6 IN and OUT)
31481 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
31482 + * endpoints in addition to EP0.
31483 + */
31484 +extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if,
31485 + int32_t val);
31486 +extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if);
31487 +#define dwc_param_dev_endpoints_default 6
31488 +
31489 +/**
31490 + * Specifies the type of PHY interface to use. By default, the driver
31491 + * will automatically detect the phy_type.
31492 + *
31493 + * 0 - Full Speed PHY
31494 + * 1 - UTMI+ (default)
31495 + * 2 - ULPI
31496 + */
31497 +extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val);
31498 +extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if);
31499 +#define DWC_PHY_TYPE_PARAM_FS 0
31500 +#define DWC_PHY_TYPE_PARAM_UTMI 1
31501 +#define DWC_PHY_TYPE_PARAM_ULPI 2
31502 +#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
31503 +
31504 +/**
31505 + * Specifies the UTMI+ Data Width. This parameter is
31506 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
31507 + * PHY_TYPE, this parameter indicates the data width between
31508 + * the MAC and the ULPI Wrapper.) Also, this parameter is
31509 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
31510 + * to "8 and 16 bits", meaning that the core has been
31511 + * configured to work at either data path width.
31512 + *
31513 + * 8 or 16 bits (default 16)
31514 + */
31515 +extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if,
31516 + int32_t val);
31517 +extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if);
31518 +//#define dwc_param_phy_utmi_width_default 16
31519 +#define dwc_param_phy_utmi_width_default 8 // Broadcom BCM2708
31520 +
31521 +/**
31522 + * Specifies whether the ULPI operates at double or single
31523 + * data rate. This parameter is only applicable if PHY_TYPE is
31524 + * ULPI.
31525 + *
31526 + * 0 - single data rate ULPI interface with 8 bit wide data
31527 + * bus (default)
31528 + * 1 - double data rate ULPI interface with 4 bit wide data
31529 + * bus
31530 + */
31531 +extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if,
31532 + int32_t val);
31533 +extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if);
31534 +#define dwc_param_phy_ulpi_ddr_default 0
31535 +
31536 +/**
31537 + * Specifies whether to use the internal or external supply to
31538 + * drive the vbus with a ULPI phy.
31539 + */
31540 +extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
31541 + int32_t val);
31542 +extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if);
31543 +#define DWC_PHY_ULPI_INTERNAL_VBUS 0
31544 +#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
31545 +#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
31546 +
31547 +/**
31548 + * Specifies whether to use the I2Cinterface for full speed PHY. This
31549 + * parameter is only applicable if PHY_TYPE is FS.
31550 + * 0 - No (default)
31551 + * 1 - Yes
31552 + */
31553 +extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if,
31554 + int32_t val);
31555 +extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if);
31556 +#define dwc_param_i2c_enable_default 0
31557 +
31558 +extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if,
31559 + int32_t val);
31560 +extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if);
31561 +#define dwc_param_ulpi_fs_ls_default 0
31562 +
31563 +extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val);
31564 +extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if);
31565 +#define dwc_param_ts_dline_default 0
31566 +
31567 +/**
31568 + * Specifies whether dedicated transmit FIFOs are
31569 + * enabled for non periodic IN endpoints in device mode
31570 + * 0 - No
31571 + * 1 - Yes
31572 + */
31573 +extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
31574 + int32_t val);
31575 +extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t *
31576 + core_if);
31577 +#define dwc_param_en_multiple_tx_fifo_default 1
31578 +
31579 +/** Number of 4-byte words in each of the Tx FIFOs in device
31580 + * mode when dynamic FIFO sizing is enabled.
31581 + * 4 to 768 (default 256)
31582 + */
31583 +extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
31584 + int fifo_num, int32_t val);
31585 +extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
31586 + int fifo_num);
31587 +#define dwc_param_dev_tx_fifo_size_default 768
31588 +
31589 +/** Thresholding enable flag-
31590 + * bit 0 - enable non-ISO Tx thresholding
31591 + * bit 1 - enable ISO Tx thresholding
31592 + * bit 2 - enable Rx thresholding
31593 + */
31594 +extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val);
31595 +extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num);
31596 +#define dwc_param_thr_ctl_default 0
31597 +
31598 +/** Thresholding length for Tx
31599 + * FIFOs in 32 bit DWORDs
31600 + */
31601 +extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if,
31602 + int32_t val);
31603 +extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if);
31604 +#define dwc_param_tx_thr_length_default 64
31605 +
31606 +/** Thresholding length for Rx
31607 + * FIFOs in 32 bit DWORDs
31608 + */
31609 +extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if,
31610 + int32_t val);
31611 +extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if);
31612 +#define dwc_param_rx_thr_length_default 64
31613 +
31614 +/**
31615 + * Specifies whether LPM (Link Power Management) support is enabled
31616 + */
31617 +extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if,
31618 + int32_t val);
31619 +extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if);
31620 +#define dwc_param_lpm_enable_default 1
31621 +
31622 +/**
31623 + * Specifies whether PTI enhancement is enabled
31624 + */
31625 +extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if,
31626 + int32_t val);
31627 +extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if);
31628 +#define dwc_param_pti_enable_default 0
31629 +
31630 +/**
31631 + * Specifies whether MPI enhancement is enabled
31632 + */
31633 +extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if,
31634 + int32_t val);
31635 +extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if);
31636 +#define dwc_param_mpi_enable_default 0
31637 +
31638 +/**
31639 + * Specifies whether ADP capability is enabled
31640 + */
31641 +extern int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if,
31642 + int32_t val);
31643 +extern int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if);
31644 +#define dwc_param_adp_enable_default 0
31645 +
31646 +/**
31647 + * Specifies whether IC_USB capability is enabled
31648 + */
31649 +
31650 +extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
31651 + int32_t val);
31652 +extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if);
31653 +#define dwc_param_ic_usb_cap_default 0
31654 +
31655 +extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if,
31656 + int32_t val);
31657 +extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if);
31658 +#define dwc_param_ahb_thr_ratio_default 0
31659 +
31660 +extern int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if,
31661 + int32_t val);
31662 +extern int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if);
31663 +#define dwc_param_power_down_default 0
31664 +
31665 +extern int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if,
31666 + int32_t val);
31667 +extern int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if);
31668 +#define dwc_param_reload_ctl_default 0
31669 +
31670 +extern int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if,
31671 + int32_t val);
31672 +extern int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if);
31673 +#define dwc_param_dev_out_nak_default 0
31674 +
31675 +extern int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if,
31676 + int32_t val);
31677 +extern int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if);
31678 +#define dwc_param_cont_on_bna_default 0
31679 +
31680 +extern int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if,
31681 + int32_t val);
31682 +extern int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if);
31683 +#define dwc_param_ahb_single_default 0
31684 +
31685 +extern int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val);
31686 +extern int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if);
31687 +#define dwc_param_otg_ver_default 0
31688 +
31689 +/** @} */
31690 +
31691 +/** @name Access to registers and bit-fields */
31692 +
31693 +/**
31694 + * Dump core registers and SPRAM
31695 + */
31696 +extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if);
31697 +extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if);
31698 +extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if);
31699 +extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if);
31700 +
31701 +/**
31702 + * Get host negotiation status.
31703 + */
31704 +extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if);
31705 +
31706 +/**
31707 + * Get srp status
31708 + */
31709 +extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if);
31710 +
31711 +/**
31712 + * Set hnpreq bit in the GOTGCTL register.
31713 + */
31714 +extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val);
31715 +
31716 +/**
31717 + * Get Content of SNPSID register.
31718 + */
31719 +extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if);
31720 +
31721 +/**
31722 + * Get current mode.
31723 + * Returns 0 if in device mode, and 1 if in host mode.
31724 + */
31725 +extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if);
31726 +
31727 +/**
31728 + * Get value of hnpcapable field in the GUSBCFG register
31729 + */
31730 +extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if);
31731 +/**
31732 + * Set value of hnpcapable field in the GUSBCFG register
31733 + */
31734 +extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
31735 +
31736 +/**
31737 + * Get value of srpcapable field in the GUSBCFG register
31738 + */
31739 +extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if);
31740 +/**
31741 + * Set value of srpcapable field in the GUSBCFG register
31742 + */
31743 +extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
31744 +
31745 +/**
31746 + * Get value of devspeed field in the DCFG register
31747 + */
31748 +extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if);
31749 +/**
31750 + * Set value of devspeed field in the DCFG register
31751 + */
31752 +extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val);
31753 +
31754 +/**
31755 + * Get the value of busconnected field from the HPRT0 register
31756 + */
31757 +extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if);
31758 +
31759 +/**
31760 + * Gets the device enumeration Speed.
31761 + */
31762 +extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if);
31763 +
31764 +/**
31765 + * Get value of prtpwr field from the HPRT0 register
31766 + */
31767 +extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if);
31768 +
31769 +/**
31770 + * Get value of flag indicating core state - hibernated or not
31771 + */
31772 +extern uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if);
31773 +
31774 +/**
31775 + * Set value of prtpwr field from the HPRT0 register
31776 + */
31777 +extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val);
31778 +
31779 +/**
31780 + * Get value of prtsusp field from the HPRT0 regsiter
31781 + */
31782 +extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if);
31783 +/**
31784 + * Set value of prtpwr field from the HPRT0 register
31785 + */
31786 +extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val);
31787 +
31788 +/**
31789 + * Get value of ModeChTimEn field from the HCFG regsiter
31790 + */
31791 +extern uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if);
31792 +/**
31793 + * Set value of ModeChTimEn field from the HCFG regsiter
31794 + */
31795 +extern void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val);
31796 +
31797 +/**
31798 + * Get value of Fram Interval field from the HFIR regsiter
31799 + */
31800 +extern uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if);
31801 +/**
31802 + * Set value of Frame Interval field from the HFIR regsiter
31803 + */
31804 +extern void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val);
31805 +
31806 +/**
31807 + * Set value of prtres field from the HPRT0 register
31808 + *FIXME Remove?
31809 + */
31810 +extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val);
31811 +
31812 +/**
31813 + * Get value of rmtwkupsig bit in DCTL register
31814 + */
31815 +extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if);
31816 +
31817 +/**
31818 + * Get value of prt_sleep_sts field from the GLPMCFG register
31819 + */
31820 +extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if);
31821 +
31822 +/**
31823 + * Get value of rem_wkup_en field from the GLPMCFG register
31824 + */
31825 +extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if);
31826 +
31827 +/**
31828 + * Get value of appl_resp field from the GLPMCFG register
31829 + */
31830 +extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if);
31831 +/**
31832 + * Set value of appl_resp field from the GLPMCFG register
31833 + */
31834 +extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val);
31835 +
31836 +/**
31837 + * Get value of hsic_connect field from the GLPMCFG register
31838 + */
31839 +extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if);
31840 +/**
31841 + * Set value of hsic_connect field from the GLPMCFG register
31842 + */
31843 +extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val);
31844 +
31845 +/**
31846 + * Get value of inv_sel_hsic field from the GLPMCFG register.
31847 + */
31848 +extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if);
31849 +/**
31850 + * Set value of inv_sel_hsic field from the GLPMFG register.
31851 + */
31852 +extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val);
31853 +
31854 +/*
31855 + * Some functions for accessing registers
31856 + */
31857 +
31858 +/**
31859 + * GOTGCTL register
31860 + */
31861 +extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if);
31862 +extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val);
31863 +
31864 +/**
31865 + * GUSBCFG register
31866 + */
31867 +extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if);
31868 +extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val);
31869 +
31870 +/**
31871 + * GRXFSIZ register
31872 + */
31873 +extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if);
31874 +extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
31875 +
31876 +/**
31877 + * GNPTXFSIZ register
31878 + */
31879 +extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if);
31880 +extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
31881 +
31882 +extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if);
31883 +extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val);
31884 +
31885 +/**
31886 + * GGPIO register
31887 + */
31888 +extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if);
31889 +extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val);
31890 +
31891 +/**
31892 + * GUID register
31893 + */
31894 +extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if);
31895 +extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val);
31896 +
31897 +/**
31898 + * HPRT0 register
31899 + */
31900 +extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if);
31901 +extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val);
31902 +
31903 +/**
31904 + * GHPTXFSIZE
31905 + */
31906 +extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if);
31907 +
31908 +/** @} */
31909 +
31910 +#endif /* __DWC_CORE_IF_H__ */
31911 --- /dev/null
31912 +++ b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h
31913 @@ -0,0 +1,116 @@
31914 +/* ==========================================================================
31915 + *
31916 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
31917 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
31918 + * otherwise expressly agreed to in writing between Synopsys and you.
31919 + *
31920 + * The Software IS NOT an item of Licensed Software or Licensed Product under
31921 + * any End User Software License Agreement or Agreement for Licensed Product
31922 + * with Synopsys or any supplement thereto. You are permitted to use and
31923 + * redistribute this Software in source and binary forms, with or without
31924 + * modification, provided that redistributions of source code must retain this
31925 + * notice. You may not view, use, disclose, copy or distribute this file or
31926 + * any information contained herein except pursuant to this license grant from
31927 + * Synopsys. If you do not agree with this notice, including the disclaimer
31928 + * below, then you are not authorized to use the Software.
31929 + *
31930 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
31931 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31932 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31933 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
31934 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31935 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31936 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31937 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31938 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31939 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31940 + * DAMAGE.
31941 + * ========================================================================== */
31942 +
31943 +#ifndef __DWC_OTG_DBG_H__
31944 +#define __DWC_OTG_DBG_H__
31945 +
31946 +/** @file
31947 + * This file defines debug levels.
31948 + * Debugging support vanishes in non-debug builds.
31949 + */
31950 +
31951 +/**
31952 + * The Debug Level bit-mask variable.
31953 + */
31954 +extern uint32_t g_dbg_lvl;
31955 +/**
31956 + * Set the Debug Level variable.
31957 + */
31958 +static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new)
31959 +{
31960 + uint32_t old = g_dbg_lvl;
31961 + g_dbg_lvl = new;
31962 + return old;
31963 +}
31964 +
31965 +/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
31966 +#define DBG_CIL (0x2)
31967 +/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
31968 + * messages */
31969 +#define DBG_CILV (0x20)
31970 +/** When debug level has the DBG_PCD bit set, display PCD (Device) debug
31971 + * messages */
31972 +#define DBG_PCD (0x4)
31973 +/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
31974 + * messages */
31975 +#define DBG_PCDV (0x40)
31976 +/** When debug level has the DBG_HCD bit set, display Host debug messages */
31977 +#define DBG_HCD (0x8)
31978 +/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
31979 + * messages */
31980 +#define DBG_HCDV (0x80)
31981 +/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
31982 + * mode. */
31983 +#define DBG_HCD_URB (0x800)
31984 +/** When debug level has the DBG_HCDI bit set, display host interrupt
31985 + * messages. */
31986 +#define DBG_HCDI (0x1000)
31987 +
31988 +/** When debug level has any bit set, display debug messages */
31989 +#define DBG_ANY (0xFF)
31990 +
31991 +/** All debug messages off */
31992 +#define DBG_OFF 0
31993 +
31994 +/** Prefix string for DWC_DEBUG print macros. */
31995 +#define USB_DWC "DWC_otg: "
31996 +
31997 +/**
31998 + * Print a debug message when the Global debug level variable contains
31999 + * the bit defined in <code>lvl</code>.
32000 + *
32001 + * @param[in] lvl - Debug level, use one of the DBG_ constants above.
32002 + * @param[in] x - like printf
32003 + *
32004 + * Example:<p>
32005 + * <code>
32006 + * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
32007 + * </code>
32008 + * <br>
32009 + * results in:<br>
32010 + * <code>
32011 + * usb-DWC_otg: dwc_otg_cil_init(ca867000)
32012 + * </code>
32013 + */
32014 +#ifdef DEBUG
32015 +
32016 +# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0)
32017 +# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x )
32018 +
32019 +# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
32020 +
32021 +#else
32022 +
32023 +# define DWC_DEBUGPL(lvl, x...) do{}while(0)
32024 +# define DWC_DEBUGP(x...)
32025 +
32026 +# define CHK_DEBUG_LEVEL(level) (0)
32027 +
32028 +#endif /*DEBUG*/
32029 +#endif
32030 --- /dev/null
32031 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
32032 @@ -0,0 +1,1700 @@
32033 +/* ==========================================================================
32034 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $
32035 + * $Revision: #92 $
32036 + * $Date: 2012/08/10 $
32037 + * $Change: 2047372 $
32038 + *
32039 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
32040 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
32041 + * otherwise expressly agreed to in writing between Synopsys and you.
32042 + *
32043 + * The Software IS NOT an item of Licensed Software or Licensed Product under
32044 + * any End User Software License Agreement or Agreement for Licensed Product
32045 + * with Synopsys or any supplement thereto. You are permitted to use and
32046 + * redistribute this Software in source and binary forms, with or without
32047 + * modification, provided that redistributions of source code must retain this
32048 + * notice. You may not view, use, disclose, copy or distribute this file or
32049 + * any information contained herein except pursuant to this license grant from
32050 + * Synopsys. If you do not agree with this notice, including the disclaimer
32051 + * below, then you are not authorized to use the Software.
32052 + *
32053 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
32054 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32055 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32056 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
32057 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32058 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32059 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32060 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32061 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32062 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32063 + * DAMAGE.
32064 + * ========================================================================== */
32065 +
32066 +/** @file
32067 + * The dwc_otg_driver module provides the initialization and cleanup entry
32068 + * points for the DWC_otg driver. This module will be dynamically installed
32069 + * after Linux is booted using the insmod command. When the module is
32070 + * installed, the dwc_otg_driver_init function is called. When the module is
32071 + * removed (using rmmod), the dwc_otg_driver_cleanup function is called.
32072 + *
32073 + * This module also defines a data structure for the dwc_otg_driver, which is
32074 + * used in conjunction with the standard ARM lm_device structure. These
32075 + * structures allow the OTG driver to comply with the standard Linux driver
32076 + * model in which devices and drivers are registered with a bus driver. This
32077 + * has the benefit that Linux can expose attributes of the driver and device
32078 + * in its special sysfs file system. Users can then read or write files in
32079 + * this file system to perform diagnostics on the driver components or the
32080 + * device.
32081 + */
32082 +
32083 +#include "dwc_otg_os_dep.h"
32084 +#include "dwc_os.h"
32085 +#include "dwc_otg_dbg.h"
32086 +#include "dwc_otg_driver.h"
32087 +#include "dwc_otg_attr.h"
32088 +#include "dwc_otg_core_if.h"
32089 +#include "dwc_otg_pcd_if.h"
32090 +#include "dwc_otg_hcd_if.h"
32091 +
32092 +#define DWC_DRIVER_VERSION "3.00a 10-AUG-2012"
32093 +#define DWC_DRIVER_DESC "HS OTG USB Controller driver"
32094 +
32095 +bool microframe_schedule=true;
32096 +
32097 +static const char dwc_driver_name[] = "dwc_otg";
32098 +
32099 +extern int pcd_init(
32100 +#ifdef LM_INTERFACE
32101 + struct lm_device *_dev
32102 +#elif defined(PCI_INTERFACE)
32103 + struct pci_dev *_dev
32104 +#elif defined(PLATFORM_INTERFACE)
32105 + struct platform_device *dev
32106 +#endif
32107 + );
32108 +extern int hcd_init(
32109 +#ifdef LM_INTERFACE
32110 + struct lm_device *_dev
32111 +#elif defined(PCI_INTERFACE)
32112 + struct pci_dev *_dev
32113 +#elif defined(PLATFORM_INTERFACE)
32114 + struct platform_device *dev
32115 +#endif
32116 + );
32117 +
32118 +extern int pcd_remove(
32119 +#ifdef LM_INTERFACE
32120 + struct lm_device *_dev
32121 +#elif defined(PCI_INTERFACE)
32122 + struct pci_dev *_dev
32123 +#elif defined(PLATFORM_INTERFACE)
32124 + struct platform_device *_dev
32125 +#endif
32126 + );
32127 +
32128 +extern void hcd_remove(
32129 +#ifdef LM_INTERFACE
32130 + struct lm_device *_dev
32131 +#elif defined(PCI_INTERFACE)
32132 + struct pci_dev *_dev
32133 +#elif defined(PLATFORM_INTERFACE)
32134 + struct platform_device *_dev
32135 +#endif
32136 + );
32137 +
32138 +extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
32139 +
32140 +/*-------------------------------------------------------------------------*/
32141 +/* Encapsulate the module parameter settings */
32142 +
32143 +struct dwc_otg_driver_module_params {
32144 + int32_t opt;
32145 + int32_t otg_cap;
32146 + int32_t dma_enable;
32147 + int32_t dma_desc_enable;
32148 + int32_t dma_burst_size;
32149 + int32_t speed;
32150 + int32_t host_support_fs_ls_low_power;
32151 + int32_t host_ls_low_power_phy_clk;
32152 + int32_t enable_dynamic_fifo;
32153 + int32_t data_fifo_size;
32154 + int32_t dev_rx_fifo_size;
32155 + int32_t dev_nperio_tx_fifo_size;
32156 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
32157 + int32_t host_rx_fifo_size;
32158 + int32_t host_nperio_tx_fifo_size;
32159 + int32_t host_perio_tx_fifo_size;
32160 + int32_t max_transfer_size;
32161 + int32_t max_packet_count;
32162 + int32_t host_channels;
32163 + int32_t dev_endpoints;
32164 + int32_t phy_type;
32165 + int32_t phy_utmi_width;
32166 + int32_t phy_ulpi_ddr;
32167 + int32_t phy_ulpi_ext_vbus;
32168 + int32_t i2c_enable;
32169 + int32_t ulpi_fs_ls;
32170 + int32_t ts_dline;
32171 + int32_t en_multiple_tx_fifo;
32172 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
32173 + uint32_t thr_ctl;
32174 + uint32_t tx_thr_length;
32175 + uint32_t rx_thr_length;
32176 + int32_t pti_enable;
32177 + int32_t mpi_enable;
32178 + int32_t lpm_enable;
32179 + int32_t ic_usb_cap;
32180 + int32_t ahb_thr_ratio;
32181 + int32_t power_down;
32182 + int32_t reload_ctl;
32183 + int32_t dev_out_nak;
32184 + int32_t cont_on_bna;
32185 + int32_t ahb_single;
32186 + int32_t otg_ver;
32187 + int32_t adp_enable;
32188 +};
32189 +
32190 +static struct dwc_otg_driver_module_params dwc_otg_module_params = {
32191 + .opt = -1,
32192 + .otg_cap = -1,
32193 + .dma_enable = -1,
32194 + .dma_desc_enable = -1,
32195 + .dma_burst_size = -1,
32196 + .speed = -1,
32197 + .host_support_fs_ls_low_power = -1,
32198 + .host_ls_low_power_phy_clk = -1,
32199 + .enable_dynamic_fifo = -1,
32200 + .data_fifo_size = -1,
32201 + .dev_rx_fifo_size = -1,
32202 + .dev_nperio_tx_fifo_size = -1,
32203 + .dev_perio_tx_fifo_size = {
32204 + /* dev_perio_tx_fifo_size_1 */
32205 + -1,
32206 + -1,
32207 + -1,
32208 + -1,
32209 + -1,
32210 + -1,
32211 + -1,
32212 + -1,
32213 + -1,
32214 + -1,
32215 + -1,
32216 + -1,
32217 + -1,
32218 + -1,
32219 + -1
32220 + /* 15 */
32221 + },
32222 + .host_rx_fifo_size = -1,
32223 + .host_nperio_tx_fifo_size = -1,
32224 + .host_perio_tx_fifo_size = -1,
32225 + .max_transfer_size = -1,
32226 + .max_packet_count = -1,
32227 + .host_channels = -1,
32228 + .dev_endpoints = -1,
32229 + .phy_type = -1,
32230 + .phy_utmi_width = -1,
32231 + .phy_ulpi_ddr = -1,
32232 + .phy_ulpi_ext_vbus = -1,
32233 + .i2c_enable = -1,
32234 + .ulpi_fs_ls = -1,
32235 + .ts_dline = -1,
32236 + .en_multiple_tx_fifo = -1,
32237 + .dev_tx_fifo_size = {
32238 + /* dev_tx_fifo_size */
32239 + -1,
32240 + -1,
32241 + -1,
32242 + -1,
32243 + -1,
32244 + -1,
32245 + -1,
32246 + -1,
32247 + -1,
32248 + -1,
32249 + -1,
32250 + -1,
32251 + -1,
32252 + -1,
32253 + -1
32254 + /* 15 */
32255 + },
32256 + .thr_ctl = -1,
32257 + .tx_thr_length = -1,
32258 + .rx_thr_length = -1,
32259 + .pti_enable = -1,
32260 + .mpi_enable = -1,
32261 + .lpm_enable = -1,
32262 + .ic_usb_cap = -1,
32263 + .ahb_thr_ratio = -1,
32264 + .power_down = -1,
32265 + .reload_ctl = -1,
32266 + .dev_out_nak = -1,
32267 + .cont_on_bna = -1,
32268 + .ahb_single = -1,
32269 + .otg_ver = -1,
32270 + .adp_enable = -1,
32271 +};
32272 +
32273 +/**
32274 + * This function shows the Driver Version.
32275 + */
32276 +static ssize_t version_show(struct device_driver *dev, char *buf)
32277 +{
32278 + return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n",
32279 + DWC_DRIVER_VERSION);
32280 +}
32281 +
32282 +static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
32283 +
32284 +/**
32285 + * Global Debug Level Mask.
32286 + */
32287 +uint32_t g_dbg_lvl = 0; /* OFF */
32288 +
32289 +/**
32290 + * This function shows the driver Debug Level.
32291 + */
32292 +static ssize_t dbg_level_show(struct device_driver *drv, char *buf)
32293 +{
32294 + return sprintf(buf, "0x%0x\n", g_dbg_lvl);
32295 +}
32296 +
32297 +/**
32298 + * This function stores the driver Debug Level.
32299 + */
32300 +static ssize_t dbg_level_store(struct device_driver *drv, const char *buf,
32301 + size_t count)
32302 +{
32303 + g_dbg_lvl = simple_strtoul(buf, NULL, 16);
32304 + return count;
32305 +}
32306 +
32307 +static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show,
32308 + dbg_level_store);
32309 +
32310 +/**
32311 + * This function is called during module intialization
32312 + * to pass module parameters to the DWC_OTG CORE.
32313 + */
32314 +static int set_parameters(dwc_otg_core_if_t * core_if)
32315 +{
32316 + int retval = 0;
32317 + int i;
32318 +
32319 + if (dwc_otg_module_params.otg_cap != -1) {
32320 + retval +=
32321 + dwc_otg_set_param_otg_cap(core_if,
32322 + dwc_otg_module_params.otg_cap);
32323 + }
32324 + if (dwc_otg_module_params.dma_enable != -1) {
32325 + retval +=
32326 + dwc_otg_set_param_dma_enable(core_if,
32327 + dwc_otg_module_params.
32328 + dma_enable);
32329 + }
32330 + if (dwc_otg_module_params.dma_desc_enable != -1) {
32331 + retval +=
32332 + dwc_otg_set_param_dma_desc_enable(core_if,
32333 + dwc_otg_module_params.
32334 + dma_desc_enable);
32335 + }
32336 + if (dwc_otg_module_params.opt != -1) {
32337 + retval +=
32338 + dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt);
32339 + }
32340 + if (dwc_otg_module_params.dma_burst_size != -1) {
32341 + retval +=
32342 + dwc_otg_set_param_dma_burst_size(core_if,
32343 + dwc_otg_module_params.
32344 + dma_burst_size);
32345 + }
32346 + if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) {
32347 + retval +=
32348 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
32349 + dwc_otg_module_params.
32350 + host_support_fs_ls_low_power);
32351 + }
32352 + if (dwc_otg_module_params.enable_dynamic_fifo != -1) {
32353 + retval +=
32354 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
32355 + dwc_otg_module_params.
32356 + enable_dynamic_fifo);
32357 + }
32358 + if (dwc_otg_module_params.data_fifo_size != -1) {
32359 + retval +=
32360 + dwc_otg_set_param_data_fifo_size(core_if,
32361 + dwc_otg_module_params.
32362 + data_fifo_size);
32363 + }
32364 + if (dwc_otg_module_params.dev_rx_fifo_size != -1) {
32365 + retval +=
32366 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
32367 + dwc_otg_module_params.
32368 + dev_rx_fifo_size);
32369 + }
32370 + if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) {
32371 + retval +=
32372 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
32373 + dwc_otg_module_params.
32374 + dev_nperio_tx_fifo_size);
32375 + }
32376 + if (dwc_otg_module_params.host_rx_fifo_size != -1) {
32377 + retval +=
32378 + dwc_otg_set_param_host_rx_fifo_size(core_if,
32379 + dwc_otg_module_params.host_rx_fifo_size);
32380 + }
32381 + if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) {
32382 + retval +=
32383 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
32384 + dwc_otg_module_params.
32385 + host_nperio_tx_fifo_size);
32386 + }
32387 + if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) {
32388 + retval +=
32389 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
32390 + dwc_otg_module_params.
32391 + host_perio_tx_fifo_size);
32392 + }
32393 + if (dwc_otg_module_params.max_transfer_size != -1) {
32394 + retval +=
32395 + dwc_otg_set_param_max_transfer_size(core_if,
32396 + dwc_otg_module_params.
32397 + max_transfer_size);
32398 + }
32399 + if (dwc_otg_module_params.max_packet_count != -1) {
32400 + retval +=
32401 + dwc_otg_set_param_max_packet_count(core_if,
32402 + dwc_otg_module_params.
32403 + max_packet_count);
32404 + }
32405 + if (dwc_otg_module_params.host_channels != -1) {
32406 + retval +=
32407 + dwc_otg_set_param_host_channels(core_if,
32408 + dwc_otg_module_params.
32409 + host_channels);
32410 + }
32411 + if (dwc_otg_module_params.dev_endpoints != -1) {
32412 + retval +=
32413 + dwc_otg_set_param_dev_endpoints(core_if,
32414 + dwc_otg_module_params.
32415 + dev_endpoints);
32416 + }
32417 + if (dwc_otg_module_params.phy_type != -1) {
32418 + retval +=
32419 + dwc_otg_set_param_phy_type(core_if,
32420 + dwc_otg_module_params.phy_type);
32421 + }
32422 + if (dwc_otg_module_params.speed != -1) {
32423 + retval +=
32424 + dwc_otg_set_param_speed(core_if,
32425 + dwc_otg_module_params.speed);
32426 + }
32427 + if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) {
32428 + retval +=
32429 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
32430 + dwc_otg_module_params.
32431 + host_ls_low_power_phy_clk);
32432 + }
32433 + if (dwc_otg_module_params.phy_ulpi_ddr != -1) {
32434 + retval +=
32435 + dwc_otg_set_param_phy_ulpi_ddr(core_if,
32436 + dwc_otg_module_params.
32437 + phy_ulpi_ddr);
32438 + }
32439 + if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) {
32440 + retval +=
32441 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
32442 + dwc_otg_module_params.
32443 + phy_ulpi_ext_vbus);
32444 + }
32445 + if (dwc_otg_module_params.phy_utmi_width != -1) {
32446 + retval +=
32447 + dwc_otg_set_param_phy_utmi_width(core_if,
32448 + dwc_otg_module_params.
32449 + phy_utmi_width);
32450 + }
32451 + if (dwc_otg_module_params.ulpi_fs_ls != -1) {
32452 + retval +=
32453 + dwc_otg_set_param_ulpi_fs_ls(core_if,
32454 + dwc_otg_module_params.ulpi_fs_ls);
32455 + }
32456 + if (dwc_otg_module_params.ts_dline != -1) {
32457 + retval +=
32458 + dwc_otg_set_param_ts_dline(core_if,
32459 + dwc_otg_module_params.ts_dline);
32460 + }
32461 + if (dwc_otg_module_params.i2c_enable != -1) {
32462 + retval +=
32463 + dwc_otg_set_param_i2c_enable(core_if,
32464 + dwc_otg_module_params.
32465 + i2c_enable);
32466 + }
32467 + if (dwc_otg_module_params.en_multiple_tx_fifo != -1) {
32468 + retval +=
32469 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
32470 + dwc_otg_module_params.
32471 + en_multiple_tx_fifo);
32472 + }
32473 + for (i = 0; i < 15; i++) {
32474 + if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) {
32475 + retval +=
32476 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
32477 + dwc_otg_module_params.
32478 + dev_perio_tx_fifo_size
32479 + [i], i);
32480 + }
32481 + }
32482 +
32483 + for (i = 0; i < 15; i++) {
32484 + if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) {
32485 + retval += dwc_otg_set_param_dev_tx_fifo_size(core_if,
32486 + dwc_otg_module_params.
32487 + dev_tx_fifo_size
32488 + [i], i);
32489 + }
32490 + }
32491 + if (dwc_otg_module_params.thr_ctl != -1) {
32492 + retval +=
32493 + dwc_otg_set_param_thr_ctl(core_if,
32494 + dwc_otg_module_params.thr_ctl);
32495 + }
32496 + if (dwc_otg_module_params.mpi_enable != -1) {
32497 + retval +=
32498 + dwc_otg_set_param_mpi_enable(core_if,
32499 + dwc_otg_module_params.
32500 + mpi_enable);
32501 + }
32502 + if (dwc_otg_module_params.pti_enable != -1) {
32503 + retval +=
32504 + dwc_otg_set_param_pti_enable(core_if,
32505 + dwc_otg_module_params.
32506 + pti_enable);
32507 + }
32508 + if (dwc_otg_module_params.lpm_enable != -1) {
32509 + retval +=
32510 + dwc_otg_set_param_lpm_enable(core_if,
32511 + dwc_otg_module_params.
32512 + lpm_enable);
32513 + }
32514 + if (dwc_otg_module_params.ic_usb_cap != -1) {
32515 + retval +=
32516 + dwc_otg_set_param_ic_usb_cap(core_if,
32517 + dwc_otg_module_params.
32518 + ic_usb_cap);
32519 + }
32520 + if (dwc_otg_module_params.tx_thr_length != -1) {
32521 + retval +=
32522 + dwc_otg_set_param_tx_thr_length(core_if,
32523 + dwc_otg_module_params.tx_thr_length);
32524 + }
32525 + if (dwc_otg_module_params.rx_thr_length != -1) {
32526 + retval +=
32527 + dwc_otg_set_param_rx_thr_length(core_if,
32528 + dwc_otg_module_params.
32529 + rx_thr_length);
32530 + }
32531 + if (dwc_otg_module_params.ahb_thr_ratio != -1) {
32532 + retval +=
32533 + dwc_otg_set_param_ahb_thr_ratio(core_if,
32534 + dwc_otg_module_params.ahb_thr_ratio);
32535 + }
32536 + if (dwc_otg_module_params.power_down != -1) {
32537 + retval +=
32538 + dwc_otg_set_param_power_down(core_if,
32539 + dwc_otg_module_params.power_down);
32540 + }
32541 + if (dwc_otg_module_params.reload_ctl != -1) {
32542 + retval +=
32543 + dwc_otg_set_param_reload_ctl(core_if,
32544 + dwc_otg_module_params.reload_ctl);
32545 + }
32546 +
32547 + if (dwc_otg_module_params.dev_out_nak != -1) {
32548 + retval +=
32549 + dwc_otg_set_param_dev_out_nak(core_if,
32550 + dwc_otg_module_params.dev_out_nak);
32551 + }
32552 +
32553 + if (dwc_otg_module_params.cont_on_bna != -1) {
32554 + retval +=
32555 + dwc_otg_set_param_cont_on_bna(core_if,
32556 + dwc_otg_module_params.cont_on_bna);
32557 + }
32558 +
32559 + if (dwc_otg_module_params.ahb_single != -1) {
32560 + retval +=
32561 + dwc_otg_set_param_ahb_single(core_if,
32562 + dwc_otg_module_params.ahb_single);
32563 + }
32564 +
32565 + if (dwc_otg_module_params.otg_ver != -1) {
32566 + retval +=
32567 + dwc_otg_set_param_otg_ver(core_if,
32568 + dwc_otg_module_params.otg_ver);
32569 + }
32570 + if (dwc_otg_module_params.adp_enable != -1) {
32571 + retval +=
32572 + dwc_otg_set_param_adp_enable(core_if,
32573 + dwc_otg_module_params.
32574 + adp_enable);
32575 + }
32576 + return retval;
32577 +}
32578 +
32579 +/**
32580 + * This function is the top level interrupt handler for the Common
32581 + * (Device and host modes) interrupts.
32582 + */
32583 +static irqreturn_t dwc_otg_common_irq(int irq, void *dev)
32584 +{
32585 + int32_t retval = IRQ_NONE;
32586 +
32587 + retval = dwc_otg_handle_common_intr(dev);
32588 + if (retval != 0) {
32589 + S3C2410X_CLEAR_EINTPEND();
32590 + }
32591 + return IRQ_RETVAL(retval);
32592 +}
32593 +
32594 +/**
32595 + * This function is called when a lm_device is unregistered with the
32596 + * dwc_otg_driver. This happens, for example, when the rmmod command is
32597 + * executed. The device may or may not be electrically present. If it is
32598 + * present, the driver stops device processing. Any resources used on behalf
32599 + * of this device are freed.
32600 + *
32601 + * @param _dev
32602 + */
32603 +#ifdef LM_INTERFACE
32604 +#define REM_RETVAL(n)
32605 +static void dwc_otg_driver_remove( struct lm_device *_dev )
32606 +{ dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
32607 +#elif defined(PCI_INTERFACE)
32608 +#define REM_RETVAL(n)
32609 +static void dwc_otg_driver_remove( struct pci_dev *_dev )
32610 +{ dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
32611 +#elif defined(PLATFORM_INTERFACE)
32612 +#define REM_RETVAL(n) n
32613 +static int dwc_otg_driver_remove( struct platform_device *_dev )
32614 +{ dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
32615 +#endif
32616 +
32617 + DWC_DEBUGPL(DBG_ANY, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
32618 +
32619 + if (!otg_dev) {
32620 + /* Memory allocation for the dwc_otg_device failed. */
32621 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
32622 + return REM_RETVAL(-ENOMEM);
32623 + }
32624 +#ifndef DWC_DEVICE_ONLY
32625 + if (otg_dev->hcd) {
32626 + hcd_remove(_dev);
32627 + } else {
32628 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
32629 + return REM_RETVAL(-EINVAL);
32630 + }
32631 +#endif
32632 +
32633 +#ifndef DWC_HOST_ONLY
32634 + if (otg_dev->pcd) {
32635 + pcd_remove(_dev);
32636 + } else {
32637 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->pcd NULL!\n", __func__);
32638 + return REM_RETVAL(-EINVAL);
32639 + }
32640 +#endif
32641 + /*
32642 + * Free the IRQ
32643 + */
32644 + if (otg_dev->common_irq_installed) {
32645 +#ifdef PLATFORM_INTERFACE
32646 + free_irq(platform_get_irq(_dev, 0), otg_dev);
32647 +#else
32648 + free_irq(_dev->irq, otg_dev);
32649 +#endif
32650 + } else {
32651 + DWC_DEBUGPL(DBG_ANY, "%s: There is no installed irq!\n", __func__);
32652 + return REM_RETVAL(-ENXIO);
32653 + }
32654 +
32655 + if (otg_dev->core_if) {
32656 + dwc_otg_cil_remove(otg_dev->core_if);
32657 + } else {
32658 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->core_if NULL!\n", __func__);
32659 + return REM_RETVAL(-ENXIO);
32660 + }
32661 +
32662 + /*
32663 + * Remove the device attributes
32664 + */
32665 + dwc_otg_attr_remove(_dev);
32666 +
32667 + /*
32668 + * Return the memory.
32669 + */
32670 + if (otg_dev->os_dep.base) {
32671 + iounmap(otg_dev->os_dep.base);
32672 + }
32673 + DWC_FREE(otg_dev);
32674 +
32675 + /*
32676 + * Clear the drvdata pointer.
32677 + */
32678 +#ifdef LM_INTERFACE
32679 + lm_set_drvdata(_dev, 0);
32680 +#elif defined(PCI_INTERFACE)
32681 + release_mem_region(otg_dev->os_dep.rsrc_start,
32682 + otg_dev->os_dep.rsrc_len);
32683 + pci_set_drvdata(_dev, 0);
32684 +#elif defined(PLATFORM_INTERFACE)
32685 + platform_set_drvdata(_dev, 0);
32686 +#endif
32687 + return REM_RETVAL(0);
32688 +}
32689 +
32690 +/**
32691 + * This function is called when an lm_device is bound to a
32692 + * dwc_otg_driver. It creates the driver components required to
32693 + * control the device (CIL, HCD, and PCD) and it initializes the
32694 + * device. The driver components are stored in a dwc_otg_device
32695 + * structure. A reference to the dwc_otg_device is saved in the
32696 + * lm_device. This allows the driver to access the dwc_otg_device
32697 + * structure on subsequent calls to driver methods for this device.
32698 + *
32699 + * @param _dev Bus device
32700 + */
32701 +static int dwc_otg_driver_probe(
32702 +#ifdef LM_INTERFACE
32703 + struct lm_device *_dev
32704 +#elif defined(PCI_INTERFACE)
32705 + struct pci_dev *_dev,
32706 + const struct pci_device_id *id
32707 +#elif defined(PLATFORM_INTERFACE)
32708 + struct platform_device *_dev
32709 +#endif
32710 + )
32711 +{
32712 + int retval = 0;
32713 + dwc_otg_device_t *dwc_otg_device;
32714 + int devirq;
32715 +
32716 + dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev);
32717 +#ifdef LM_INTERFACE
32718 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource.start);
32719 +#elif defined(PCI_INTERFACE)
32720 + if (!id) {
32721 + DWC_ERROR("Invalid pci_device_id %p", id);
32722 + return -EINVAL;
32723 + }
32724 +
32725 + if (!_dev || (pci_enable_device(_dev) < 0)) {
32726 + DWC_ERROR("Invalid pci_device %p", _dev);
32727 + return -ENODEV;
32728 + }
32729 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(_dev,0));
32730 + /* other stuff needed as well? */
32731 +
32732 +#elif defined(PLATFORM_INTERFACE)
32733 + dev_dbg(&_dev->dev, "start=0x%08x (len 0x%x)\n",
32734 + (unsigned)_dev->resource->start,
32735 + (unsigned)(_dev->resource->end - _dev->resource->start));
32736 +#endif
32737 +
32738 + dwc_otg_device = DWC_ALLOC(sizeof(dwc_otg_device_t));
32739 +
32740 + if (!dwc_otg_device) {
32741 + dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n");
32742 + return -ENOMEM;
32743 + }
32744 +
32745 + memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
32746 + dwc_otg_device->os_dep.reg_offset = 0xFFFFFFFF;
32747 +
32748 + /*
32749 + * Map the DWC_otg Core memory into virtual address space.
32750 + */
32751 +#ifdef LM_INTERFACE
32752 + dwc_otg_device->os_dep.base = ioremap(_dev->resource.start, SZ_256K);
32753 +
32754 + if (!dwc_otg_device->os_dep.base) {
32755 + dev_err(&_dev->dev, "ioremap() failed\n");
32756 + DWC_FREE(dwc_otg_device);
32757 + return -ENOMEM;
32758 + }
32759 + dev_dbg(&_dev->dev, "base=0x%08x\n",
32760 + (unsigned)dwc_otg_device->os_dep.base);
32761 +#elif defined(PCI_INTERFACE)
32762 + _dev->current_state = PCI_D0;
32763 + _dev->dev.power.power_state = PMSG_ON;
32764 +
32765 + if (!_dev->irq) {
32766 + DWC_ERROR("Found HC with no IRQ. Check BIOS/PCI %s setup!",
32767 + pci_name(_dev));
32768 + iounmap(dwc_otg_device->os_dep.base);
32769 + DWC_FREE(dwc_otg_device);
32770 + return -ENODEV;
32771 + }
32772 +
32773 + dwc_otg_device->os_dep.rsrc_start = pci_resource_start(_dev, 0);
32774 + dwc_otg_device->os_dep.rsrc_len = pci_resource_len(_dev, 0);
32775 + DWC_DEBUGPL(DBG_ANY, "PCI resource: start=%08x, len=%08x\n",
32776 + (unsigned)dwc_otg_device->os_dep.rsrc_start,
32777 + (unsigned)dwc_otg_device->os_dep.rsrc_len);
32778 + if (!request_mem_region
32779 + (dwc_otg_device->os_dep.rsrc_start, dwc_otg_device->os_dep.rsrc_len,
32780 + "dwc_otg")) {
32781 + dev_dbg(&_dev->dev, "error requesting memory\n");
32782 + iounmap(dwc_otg_device->os_dep.base);
32783 + DWC_FREE(dwc_otg_device);
32784 + return -EFAULT;
32785 + }
32786 +
32787 + dwc_otg_device->os_dep.base =
32788 + ioremap_nocache(dwc_otg_device->os_dep.rsrc_start,
32789 + dwc_otg_device->os_dep.rsrc_len);
32790 + if (dwc_otg_device->os_dep.base == NULL) {
32791 + dev_dbg(&_dev->dev, "error mapping memory\n");
32792 + release_mem_region(dwc_otg_device->os_dep.rsrc_start,
32793 + dwc_otg_device->os_dep.rsrc_len);
32794 + iounmap(dwc_otg_device->os_dep.base);
32795 + DWC_FREE(dwc_otg_device);
32796 + return -EFAULT;
32797 + }
32798 + dev_dbg(&_dev->dev, "base=0x%p (before adjust) \n",
32799 + dwc_otg_device->os_dep.base);
32800 + dwc_otg_device->os_dep.base = (char *)dwc_otg_device->os_dep.base;
32801 + dev_dbg(&_dev->dev, "base=0x%p (after adjust) \n",
32802 + dwc_otg_device->os_dep.base);
32803 + dev_dbg(&_dev->dev, "%s: mapped PA 0x%x to VA 0x%p\n", __func__,
32804 + (unsigned)dwc_otg_device->os_dep.rsrc_start,
32805 + dwc_otg_device->os_dep.base);
32806 +
32807 + pci_set_master(_dev);
32808 + pci_set_drvdata(_dev, dwc_otg_device);
32809 +#elif defined(PLATFORM_INTERFACE)
32810 + DWC_DEBUGPL(DBG_ANY,"Platform resource: start=%08x, len=%08x\n",
32811 + _dev->resource->start,
32812 + _dev->resource->end - _dev->resource->start + 1);
32813 +#if 1
32814 + if (!request_mem_region(_dev->resource->start,
32815 + _dev->resource->end - _dev->resource->start + 1,
32816 + "dwc_otg")) {
32817 + dev_dbg(&_dev->dev, "error reserving mapped memory\n");
32818 + retval = -EFAULT;
32819 + goto fail;
32820 + }
32821 +
32822 + dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource->start,
32823 + _dev->resource->end -
32824 + _dev->resource->start+1);
32825 +#else
32826 + {
32827 + struct map_desc desc = {
32828 + .virtual = IO_ADDRESS((unsigned)_dev->resource->start),
32829 + .pfn = __phys_to_pfn((unsigned)_dev->resource->start),
32830 + .length = SZ_128K,
32831 + .type = MT_DEVICE
32832 + };
32833 + iotable_init(&desc, 1);
32834 + dwc_otg_device->os_dep.base = (void *)desc.virtual;
32835 + }
32836 +#endif
32837 + if (!dwc_otg_device->os_dep.base) {
32838 + dev_err(&_dev->dev, "ioremap() failed\n");
32839 + retval = -ENOMEM;
32840 + goto fail;
32841 + }
32842 + dev_dbg(&_dev->dev, "base=0x%08x\n",
32843 + (unsigned)dwc_otg_device->os_dep.base);
32844 +#endif
32845 +
32846 + /*
32847 + * Initialize driver data to point to the global DWC_otg
32848 + * Device structure.
32849 + */
32850 +#ifdef LM_INTERFACE
32851 + lm_set_drvdata(_dev, dwc_otg_device);
32852 +#elif defined(PLATFORM_INTERFACE)
32853 + platform_set_drvdata(_dev, dwc_otg_device);
32854 +#endif
32855 + dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device);
32856 +
32857 + dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->os_dep.base);
32858 + DWC_DEBUGPL(DBG_HCDV, "probe of device %p given core_if %p\n",
32859 + dwc_otg_device, dwc_otg_device->core_if);//GRAYG
32860 +
32861 + if (!dwc_otg_device->core_if) {
32862 + dev_err(&_dev->dev, "CIL initialization failed!\n");
32863 + retval = -ENOMEM;
32864 + goto fail;
32865 + }
32866 +
32867 + dev_dbg(&_dev->dev, "Calling get_gsnpsid\n");
32868 + /*
32869 + * Attempt to ensure this device is really a DWC_otg Controller.
32870 + * Read and verify the SNPSID register contents. The value should be
32871 + * 0x45F42XXX or 0x45F42XXX, which corresponds to either "OT2" or "OTG3",
32872 + * as in "OTG version 2.XX" or "OTG version 3.XX".
32873 + */
32874 +
32875 + if (((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F542000) &&
32876 + ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F543000)) {
32877 + dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n",
32878 + dwc_otg_get_gsnpsid(dwc_otg_device->core_if));
32879 + retval = -EINVAL;
32880 + goto fail;
32881 + }
32882 +
32883 + /*
32884 + * Validate parameter values.
32885 + */
32886 + dev_dbg(&_dev->dev, "Calling set_parameters\n");
32887 + if (set_parameters(dwc_otg_device->core_if)) {
32888 + retval = -EINVAL;
32889 + goto fail;
32890 + }
32891 +
32892 + /*
32893 + * Create Device Attributes in sysfs
32894 + */
32895 + dev_dbg(&_dev->dev, "Calling attr_create\n");
32896 + dwc_otg_attr_create(_dev);
32897 +
32898 + /*
32899 + * Disable the global interrupt until all the interrupt
32900 + * handlers are installed.
32901 + */
32902 + dev_dbg(&_dev->dev, "Calling disable_global_interrupts\n");
32903 + dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
32904 +
32905 + /*
32906 + * Install the interrupt handler for the common interrupts before
32907 + * enabling common interrupts in core_init below.
32908 + */
32909 +
32910 +#if defined(PLATFORM_INTERFACE)
32911 + devirq = platform_get_irq(_dev, 0);
32912 +#else
32913 + devirq = _dev->irq;
32914 +#endif
32915 + DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n",
32916 + devirq);
32917 + dev_dbg(&_dev->dev, "Calling request_irq(%d)\n", devirq);
32918 + retval = request_irq(devirq, dwc_otg_common_irq,
32919 + IRQF_SHARED,
32920 + "dwc_otg", dwc_otg_device);
32921 + if (retval) {
32922 + DWC_ERROR("request of irq%d failed\n", devirq);
32923 + retval = -EBUSY;
32924 + goto fail;
32925 + } else {
32926 + dwc_otg_device->common_irq_installed = 1;
32927 + }
32928 +
32929 +#ifndef IRQF_TRIGGER_LOW
32930 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
32931 + dev_dbg(&_dev->dev, "Calling set_irq_type\n");
32932 + set_irq_type(devirq,
32933 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
32934 + IRQT_LOW
32935 +#else
32936 + IRQ_TYPE_LEVEL_LOW
32937 +#endif
32938 + );
32939 +#endif
32940 +#endif /*IRQF_TRIGGER_LOW*/
32941 +
32942 + /*
32943 + * Initialize the DWC_otg core.
32944 + */
32945 + dev_dbg(&_dev->dev, "Calling dwc_otg_core_init\n");
32946 + dwc_otg_core_init(dwc_otg_device->core_if);
32947 +
32948 +#ifndef DWC_HOST_ONLY
32949 + /*
32950 + * Initialize the PCD
32951 + */
32952 + dev_dbg(&_dev->dev, "Calling pcd_init\n");
32953 + retval = pcd_init(_dev);
32954 + if (retval != 0) {
32955 + DWC_ERROR("pcd_init failed\n");
32956 + dwc_otg_device->pcd = NULL;
32957 + goto fail;
32958 + }
32959 +#endif
32960 +#ifndef DWC_DEVICE_ONLY
32961 + /*
32962 + * Initialize the HCD
32963 + */
32964 + dev_dbg(&_dev->dev, "Calling hcd_init\n");
32965 + retval = hcd_init(_dev);
32966 + if (retval != 0) {
32967 + DWC_ERROR("hcd_init failed\n");
32968 + dwc_otg_device->hcd = NULL;
32969 + goto fail;
32970 + }
32971 +#endif
32972 + /* Recover from drvdata having been overwritten by hcd_init() */
32973 +#ifdef LM_INTERFACE
32974 + lm_set_drvdata(_dev, dwc_otg_device);
32975 +#elif defined(PLATFORM_INTERFACE)
32976 + platform_set_drvdata(_dev, dwc_otg_device);
32977 +#elif defined(PCI_INTERFACE)
32978 + pci_set_drvdata(_dev, dwc_otg_device);
32979 + dwc_otg_device->os_dep.pcidev = _dev;
32980 +#endif
32981 +
32982 + /*
32983 + * Enable the global interrupt after all the interrupt
32984 + * handlers are installed if there is no ADP support else
32985 + * perform initial actions required for Internal ADP logic.
32986 + */
32987 + if (!dwc_otg_get_param_adp_enable(dwc_otg_device->core_if)) {
32988 + dev_dbg(&_dev->dev, "Calling enable_global_interrupts\n");
32989 + dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);
32990 + dev_dbg(&_dev->dev, "Done\n");
32991 + } else
32992 + dwc_otg_adp_start(dwc_otg_device->core_if,
32993 + dwc_otg_is_host_mode(dwc_otg_device->core_if));
32994 +
32995 + return 0;
32996 +
32997 +fail:
32998 + dwc_otg_driver_remove(_dev);
32999 + return retval;
33000 +}
33001 +
33002 +/**
33003 + * This structure defines the methods to be called by a bus driver
33004 + * during the lifecycle of a device on that bus. Both drivers and
33005 + * devices are registered with a bus driver. The bus driver matches
33006 + * devices to drivers based on information in the device and driver
33007 + * structures.
33008 + *
33009 + * The probe function is called when the bus driver matches a device
33010 + * to this driver. The remove function is called when a device is
33011 + * unregistered with the bus driver.
33012 + */
33013 +#ifdef LM_INTERFACE
33014 +static struct lm_driver dwc_otg_driver = {
33015 + .drv = {.name = (char *)dwc_driver_name,},
33016 + .probe = dwc_otg_driver_probe,
33017 + .remove = dwc_otg_driver_remove,
33018 + // 'suspend' and 'resume' absent
33019 +};
33020 +#elif defined(PCI_INTERFACE)
33021 +static const struct pci_device_id pci_ids[] = { {
33022 + PCI_DEVICE(0x16c3, 0xabcd),
33023 + .driver_data =
33024 + (unsigned long)0xdeadbeef,
33025 + }, { /* end: all zeroes */ }
33026 +};
33027 +
33028 +MODULE_DEVICE_TABLE(pci, pci_ids);
33029 +
33030 +/* pci driver glue; this is a "new style" PCI driver module */
33031 +static struct pci_driver dwc_otg_driver = {
33032 + .name = "dwc_otg",
33033 + .id_table = pci_ids,
33034 +
33035 + .probe = dwc_otg_driver_probe,
33036 + .remove = dwc_otg_driver_remove,
33037 +
33038 + .driver = {
33039 + .name = (char *)dwc_driver_name,
33040 + },
33041 +};
33042 +#elif defined(PLATFORM_INTERFACE)
33043 +static struct platform_device_id platform_ids[] = {
33044 + {
33045 + .name = "bcm2708_usb",
33046 + .driver_data = (kernel_ulong_t) 0xdeadbeef,
33047 + },
33048 + { /* end: all zeroes */ }
33049 +};
33050 +MODULE_DEVICE_TABLE(platform, platform_ids);
33051 +
33052 +static struct platform_driver dwc_otg_driver = {
33053 + .driver = {
33054 + .name = (char *)dwc_driver_name,
33055 + },
33056 + .id_table = platform_ids,
33057 +
33058 + .probe = dwc_otg_driver_probe,
33059 + .remove = dwc_otg_driver_remove,
33060 + // no 'shutdown', 'suspend', 'resume', 'suspend_late' or 'resume_early'
33061 +};
33062 +#endif
33063 +
33064 +/**
33065 + * This function is called when the dwc_otg_driver is installed with the
33066 + * insmod command. It registers the dwc_otg_driver structure with the
33067 + * appropriate bus driver. This will cause the dwc_otg_driver_probe function
33068 + * to be called. In addition, the bus driver will automatically expose
33069 + * attributes defined for the device and driver in the special sysfs file
33070 + * system.
33071 + *
33072 + * @return
33073 + */
33074 +static int __init dwc_otg_driver_init(void)
33075 +{
33076 + int retval = 0;
33077 + int error;
33078 + struct device_driver *drv;
33079 + printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name,
33080 + DWC_DRIVER_VERSION,
33081 +#ifdef LM_INTERFACE
33082 + "logicmodule");
33083 + retval = lm_driver_register(&dwc_otg_driver);
33084 + drv = &dwc_otg_driver.drv;
33085 +#elif defined(PCI_INTERFACE)
33086 + "pci");
33087 + retval = pci_register_driver(&dwc_otg_driver);
33088 + drv = &dwc_otg_driver.driver;
33089 +#elif defined(PLATFORM_INTERFACE)
33090 + "platform");
33091 + retval = platform_driver_register(&dwc_otg_driver);
33092 + drv = &dwc_otg_driver.driver;
33093 +#endif
33094 + if (retval < 0) {
33095 + printk(KERN_ERR "%s retval=%d\n", __func__, retval);
33096 + return retval;
33097 + }
33098 +
33099 + error = driver_create_file(drv, &driver_attr_version);
33100 +#ifdef DEBUG
33101 + error = driver_create_file(drv, &driver_attr_debuglevel);
33102 +#endif
33103 + return retval;
33104 +}
33105 +
33106 +module_init(dwc_otg_driver_init);
33107 +
33108 +/**
33109 + * This function is called when the driver is removed from the kernel
33110 + * with the rmmod command. The driver unregisters itself with its bus
33111 + * driver.
33112 + *
33113 + */
33114 +static void __exit dwc_otg_driver_cleanup(void)
33115 +{
33116 + printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n");
33117 +
33118 +#ifdef LM_INTERFACE
33119 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
33120 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_version);
33121 + lm_driver_unregister(&dwc_otg_driver);
33122 +#elif defined(PCI_INTERFACE)
33123 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
33124 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
33125 + pci_unregister_driver(&dwc_otg_driver);
33126 +#elif defined(PLATFORM_INTERFACE)
33127 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
33128 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
33129 + platform_driver_unregister(&dwc_otg_driver);
33130 +#endif
33131 +
33132 + printk(KERN_INFO "%s module removed\n", dwc_driver_name);
33133 +}
33134 +
33135 +module_exit(dwc_otg_driver_cleanup);
33136 +
33137 +MODULE_DESCRIPTION(DWC_DRIVER_DESC);
33138 +MODULE_AUTHOR("Synopsys Inc.");
33139 +MODULE_LICENSE("GPL");
33140 +
33141 +module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444);
33142 +MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None");
33143 +module_param_named(opt, dwc_otg_module_params.opt, int, 0444);
33144 +MODULE_PARM_DESC(opt, "OPT Mode");
33145 +module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444);
33146 +MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled");
33147 +
33148 +module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int,
33149 + 0444);
33150 +MODULE_PARM_DESC(dma_desc_enable,
33151 + "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled");
33152 +
33153 +module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int,
33154 + 0444);
33155 +MODULE_PARM_DESC(dma_burst_size,
33156 + "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256");
33157 +module_param_named(speed, dwc_otg_module_params.speed, int, 0444);
33158 +MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed");
33159 +module_param_named(host_support_fs_ls_low_power,
33160 + dwc_otg_module_params.host_support_fs_ls_low_power, int,
33161 + 0444);
33162 +MODULE_PARM_DESC(host_support_fs_ls_low_power,
33163 + "Support Low Power w/FS or LS 0=Support 1=Don't Support");
33164 +module_param_named(host_ls_low_power_phy_clk,
33165 + dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444);
33166 +MODULE_PARM_DESC(host_ls_low_power_phy_clk,
33167 + "Low Speed Low Power Clock 0=48Mhz 1=6Mhz");
33168 +module_param_named(enable_dynamic_fifo,
33169 + dwc_otg_module_params.enable_dynamic_fifo, int, 0444);
33170 +MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing");
33171 +module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int,
33172 + 0444);
33173 +MODULE_PARM_DESC(data_fifo_size,
33174 + "Total number of words in the data FIFO memory 32-32768");
33175 +module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size,
33176 + int, 0444);
33177 +MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
33178 +module_param_named(dev_nperio_tx_fifo_size,
33179 + dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444);
33180 +MODULE_PARM_DESC(dev_nperio_tx_fifo_size,
33181 + "Number of words in the non-periodic Tx FIFO 16-32768");
33182 +module_param_named(dev_perio_tx_fifo_size_1,
33183 + dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444);
33184 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_1,
33185 + "Number of words in the periodic Tx FIFO 4-768");
33186 +module_param_named(dev_perio_tx_fifo_size_2,
33187 + dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444);
33188 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_2,
33189 + "Number of words in the periodic Tx FIFO 4-768");
33190 +module_param_named(dev_perio_tx_fifo_size_3,
33191 + dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444);
33192 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_3,
33193 + "Number of words in the periodic Tx FIFO 4-768");
33194 +module_param_named(dev_perio_tx_fifo_size_4,
33195 + dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444);
33196 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_4,
33197 + "Number of words in the periodic Tx FIFO 4-768");
33198 +module_param_named(dev_perio_tx_fifo_size_5,
33199 + dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444);
33200 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_5,
33201 + "Number of words in the periodic Tx FIFO 4-768");
33202 +module_param_named(dev_perio_tx_fifo_size_6,
33203 + dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444);
33204 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_6,
33205 + "Number of words in the periodic Tx FIFO 4-768");
33206 +module_param_named(dev_perio_tx_fifo_size_7,
33207 + dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444);
33208 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_7,
33209 + "Number of words in the periodic Tx FIFO 4-768");
33210 +module_param_named(dev_perio_tx_fifo_size_8,
33211 + dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444);
33212 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_8,
33213 + "Number of words in the periodic Tx FIFO 4-768");
33214 +module_param_named(dev_perio_tx_fifo_size_9,
33215 + dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444);
33216 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_9,
33217 + "Number of words in the periodic Tx FIFO 4-768");
33218 +module_param_named(dev_perio_tx_fifo_size_10,
33219 + dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444);
33220 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_10,
33221 + "Number of words in the periodic Tx FIFO 4-768");
33222 +module_param_named(dev_perio_tx_fifo_size_11,
33223 + dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444);
33224 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_11,
33225 + "Number of words in the periodic Tx FIFO 4-768");
33226 +module_param_named(dev_perio_tx_fifo_size_12,
33227 + dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444);
33228 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_12,
33229 + "Number of words in the periodic Tx FIFO 4-768");
33230 +module_param_named(dev_perio_tx_fifo_size_13,
33231 + dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444);
33232 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_13,
33233 + "Number of words in the periodic Tx FIFO 4-768");
33234 +module_param_named(dev_perio_tx_fifo_size_14,
33235 + dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444);
33236 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_14,
33237 + "Number of words in the periodic Tx FIFO 4-768");
33238 +module_param_named(dev_perio_tx_fifo_size_15,
33239 + dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444);
33240 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_15,
33241 + "Number of words in the periodic Tx FIFO 4-768");
33242 +module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size,
33243 + int, 0444);
33244 +MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
33245 +module_param_named(host_nperio_tx_fifo_size,
33246 + dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444);
33247 +MODULE_PARM_DESC(host_nperio_tx_fifo_size,
33248 + "Number of words in the non-periodic Tx FIFO 16-32768");
33249 +module_param_named(host_perio_tx_fifo_size,
33250 + dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444);
33251 +MODULE_PARM_DESC(host_perio_tx_fifo_size,
33252 + "Number of words in the host periodic Tx FIFO 16-32768");
33253 +module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size,
33254 + int, 0444);
33255 +/** @todo Set the max to 512K, modify checks */
33256 +MODULE_PARM_DESC(max_transfer_size,
33257 + "The maximum transfer size supported in bytes 2047-65535");
33258 +module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count,
33259 + int, 0444);
33260 +MODULE_PARM_DESC(max_packet_count,
33261 + "The maximum number of packets in a transfer 15-511");
33262 +module_param_named(host_channels, dwc_otg_module_params.host_channels, int,
33263 + 0444);
33264 +MODULE_PARM_DESC(host_channels,
33265 + "The number of host channel registers to use 1-16");
33266 +module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int,
33267 + 0444);
33268 +MODULE_PARM_DESC(dev_endpoints,
33269 + "The number of endpoints in addition to EP0 available for device mode 1-15");
33270 +module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444);
33271 +MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI");
33272 +module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int,
33273 + 0444);
33274 +MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits");
33275 +module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444);
33276 +MODULE_PARM_DESC(phy_ulpi_ddr,
33277 + "ULPI at double or single data rate 0=Single 1=Double");
33278 +module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus,
33279 + int, 0444);
33280 +MODULE_PARM_DESC(phy_ulpi_ext_vbus,
33281 + "ULPI PHY using internal or external vbus 0=Internal");
33282 +module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444);
33283 +MODULE_PARM_DESC(i2c_enable, "FS PHY Interface");
33284 +module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444);
33285 +MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only");
33286 +module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444);
33287 +MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs");
33288 +module_param_named(debug, g_dbg_lvl, int, 0444);
33289 +MODULE_PARM_DESC(debug, "");
33290 +
33291 +module_param_named(en_multiple_tx_fifo,
33292 + dwc_otg_module_params.en_multiple_tx_fifo, int, 0444);
33293 +MODULE_PARM_DESC(en_multiple_tx_fifo,
33294 + "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled");
33295 +module_param_named(dev_tx_fifo_size_1,
33296 + dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444);
33297 +MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768");
33298 +module_param_named(dev_tx_fifo_size_2,
33299 + dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444);
33300 +MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768");
33301 +module_param_named(dev_tx_fifo_size_3,
33302 + dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444);
33303 +MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768");
33304 +module_param_named(dev_tx_fifo_size_4,
33305 + dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444);
33306 +MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768");
33307 +module_param_named(dev_tx_fifo_size_5,
33308 + dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444);
33309 +MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768");
33310 +module_param_named(dev_tx_fifo_size_6,
33311 + dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444);
33312 +MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768");
33313 +module_param_named(dev_tx_fifo_size_7,
33314 + dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444);
33315 +MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768");
33316 +module_param_named(dev_tx_fifo_size_8,
33317 + dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444);
33318 +MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768");
33319 +module_param_named(dev_tx_fifo_size_9,
33320 + dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444);
33321 +MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768");
33322 +module_param_named(dev_tx_fifo_size_10,
33323 + dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444);
33324 +MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768");
33325 +module_param_named(dev_tx_fifo_size_11,
33326 + dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444);
33327 +MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768");
33328 +module_param_named(dev_tx_fifo_size_12,
33329 + dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444);
33330 +MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768");
33331 +module_param_named(dev_tx_fifo_size_13,
33332 + dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444);
33333 +MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768");
33334 +module_param_named(dev_tx_fifo_size_14,
33335 + dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444);
33336 +MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768");
33337 +module_param_named(dev_tx_fifo_size_15,
33338 + dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444);
33339 +MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768");
33340 +
33341 +module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444);
33342 +MODULE_PARM_DESC(thr_ctl,
33343 + "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled");
33344 +module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int,
33345 + 0444);
33346 +MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs");
33347 +module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int,
33348 + 0444);
33349 +MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs");
33350 +
33351 +module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444);
33352 +module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444);
33353 +module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444);
33354 +MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled");
33355 +module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444);
33356 +MODULE_PARM_DESC(ic_usb_cap,
33357 + "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled");
33358 +module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int,
33359 + 0444);
33360 +MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio");
33361 +module_param_named(power_down, dwc_otg_module_params.power_down, int, 0444);
33362 +MODULE_PARM_DESC(power_down, "Power Down Mode");
33363 +module_param_named(reload_ctl, dwc_otg_module_params.reload_ctl, int, 0444);
33364 +MODULE_PARM_DESC(reload_ctl, "HFIR Reload Control");
33365 +module_param_named(dev_out_nak, dwc_otg_module_params.dev_out_nak, int, 0444);
33366 +MODULE_PARM_DESC(dev_out_nak, "Enable Device OUT NAK");
33367 +module_param_named(cont_on_bna, dwc_otg_module_params.cont_on_bna, int, 0444);
33368 +MODULE_PARM_DESC(cont_on_bna, "Enable Enable Continue on BNA");
33369 +module_param_named(ahb_single, dwc_otg_module_params.ahb_single, int, 0444);
33370 +MODULE_PARM_DESC(ahb_single, "Enable AHB Single Support");
33371 +module_param_named(adp_enable, dwc_otg_module_params.adp_enable, int, 0444);
33372 +MODULE_PARM_DESC(adp_enable, "ADP Enable 0=ADP Disabled 1=ADP Enabled");
33373 +module_param_named(otg_ver, dwc_otg_module_params.otg_ver, int, 0444);
33374 +MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0");
33375 +module_param(microframe_schedule, bool, 0444);
33376 +MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");
33377 +
33378 +/** @page "Module Parameters"
33379 + *
33380 + * The following parameters may be specified when starting the module.
33381 + * These parameters define how the DWC_otg controller should be
33382 + * configured. Parameter values are passed to the CIL initialization
33383 + * function dwc_otg_cil_init
33384 + *
33385 + * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code>
33386 + *
33387 +
33388 + <table>
33389 + <tr><td>Parameter Name</td><td>Meaning</td></tr>
33390 +
33391 + <tr>
33392 + <td>otg_cap</td>
33393 + <td>Specifies the OTG capabilities. The driver will automatically detect the
33394 + value for this parameter if none is specified.
33395 + - 0: HNP and SRP capable (default, if available)
33396 + - 1: SRP Only capable
33397 + - 2: No HNP/SRP capable
33398 + </td></tr>
33399 +
33400 + <tr>
33401 + <td>dma_enable</td>
33402 + <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs.
33403 + The driver will automatically detect the value for this parameter if none is
33404 + specified.
33405 + - 0: Slave
33406 + - 1: DMA (default, if available)
33407 + </td></tr>
33408 +
33409 + <tr>
33410 + <td>dma_burst_size</td>
33411 + <td>The DMA Burst size (applicable only for External DMA Mode).
33412 + - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32)
33413 + </td></tr>
33414 +
33415 + <tr>
33416 + <td>speed</td>
33417 + <td>Specifies the maximum speed of operation in host and device mode. The
33418 + actual speed depends on the speed of the attached device and the value of
33419 + phy_type.
33420 + - 0: High Speed (default)
33421 + - 1: Full Speed
33422 + </td></tr>
33423 +
33424 + <tr>
33425 + <td>host_support_fs_ls_low_power</td>
33426 + <td>Specifies whether low power mode is supported when attached to a Full
33427 + Speed or Low Speed device in host mode.
33428 + - 0: Don't support low power mode (default)
33429 + - 1: Support low power mode
33430 + </td></tr>
33431 +
33432 + <tr>
33433 + <td>host_ls_low_power_phy_clk</td>
33434 + <td>Specifies the PHY clock rate in low power mode when connected to a Low
33435 + Speed device in host mode. This parameter is applicable only if
33436 + HOST_SUPPORT_FS_LS_LOW_POWER is enabled.
33437 + - 0: 48 MHz (default)
33438 + - 1: 6 MHz
33439 + </td></tr>
33440 +
33441 + <tr>
33442 + <td>enable_dynamic_fifo</td>
33443 + <td> Specifies whether FIFOs may be resized by the driver software.
33444 + - 0: Use cC FIFO size parameters
33445 + - 1: Allow dynamic FIFO sizing (default)
33446 + </td></tr>
33447 +
33448 + <tr>
33449 + <td>data_fifo_size</td>
33450 + <td>Total number of 4-byte words in the data FIFO memory. This memory
33451 + includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs.
33452 + - Values: 32 to 32768 (default 8192)
33453 +
33454 + Note: The total FIFO memory depth in the FPGA configuration is 8192.
33455 + </td></tr>
33456 +
33457 + <tr>
33458 + <td>dev_rx_fifo_size</td>
33459 + <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic
33460 + FIFO sizing is enabled.
33461 + - Values: 16 to 32768 (default 1064)
33462 + </td></tr>
33463 +
33464 + <tr>
33465 + <td>dev_nperio_tx_fifo_size</td>
33466 + <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when
33467 + dynamic FIFO sizing is enabled.
33468 + - Values: 16 to 32768 (default 1024)
33469 + </td></tr>
33470 +
33471 + <tr>
33472 + <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td>
33473 + <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode
33474 + when dynamic FIFO sizing is enabled.
33475 + - Values: 4 to 768 (default 256)
33476 + </td></tr>
33477 +
33478 + <tr>
33479 + <td>host_rx_fifo_size</td>
33480 + <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO
33481 + sizing is enabled.
33482 + - Values: 16 to 32768 (default 1024)
33483 + </td></tr>
33484 +
33485 + <tr>
33486 + <td>host_nperio_tx_fifo_size</td>
33487 + <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when
33488 + dynamic FIFO sizing is enabled in the core.
33489 + - Values: 16 to 32768 (default 1024)
33490 + </td></tr>
33491 +
33492 + <tr>
33493 + <td>host_perio_tx_fifo_size</td>
33494 + <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO
33495 + sizing is enabled.
33496 + - Values: 16 to 32768 (default 1024)
33497 + </td></tr>
33498 +
33499 + <tr>
33500 + <td>max_transfer_size</td>
33501 + <td>The maximum transfer size supported in bytes.
33502 + - Values: 2047 to 65,535 (default 65,535)
33503 + </td></tr>
33504 +
33505 + <tr>
33506 + <td>max_packet_count</td>
33507 + <td>The maximum number of packets in a transfer.
33508 + - Values: 15 to 511 (default 511)
33509 + </td></tr>
33510 +
33511 + <tr>
33512 + <td>host_channels</td>
33513 + <td>The number of host channel registers to use.
33514 + - Values: 1 to 16 (default 12)
33515 +
33516 + Note: The FPGA configuration supports a maximum of 12 host channels.
33517 + </td></tr>
33518 +
33519 + <tr>
33520 + <td>dev_endpoints</td>
33521 + <td>The number of endpoints in addition to EP0 available for device mode
33522 + operations.
33523 + - Values: 1 to 15 (default 6 IN and OUT)
33524 +
33525 + Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in
33526 + addition to EP0.
33527 + </td></tr>
33528 +
33529 + <tr>
33530 + <td>phy_type</td>
33531 + <td>Specifies the type of PHY interface to use. By default, the driver will
33532 + automatically detect the phy_type.
33533 + - 0: Full Speed
33534 + - 1: UTMI+ (default, if available)
33535 + - 2: ULPI
33536 + </td></tr>
33537 +
33538 + <tr>
33539 + <td>phy_utmi_width</td>
33540 + <td>Specifies the UTMI+ Data Width. This parameter is applicable for a
33541 + phy_type of UTMI+. Also, this parameter is applicable only if the
33542 + OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the
33543 + core has been configured to work at either data path width.
33544 + - Values: 8 or 16 bits (default 16)
33545 + </td></tr>
33546 +
33547 + <tr>
33548 + <td>phy_ulpi_ddr</td>
33549 + <td>Specifies whether the ULPI operates at double or single data rate. This
33550 + parameter is only applicable if phy_type is ULPI.
33551 + - 0: single data rate ULPI interface with 8 bit wide data bus (default)
33552 + - 1: double data rate ULPI interface with 4 bit wide data bus
33553 + </td></tr>
33554 +
33555 + <tr>
33556 + <td>i2c_enable</td>
33557 + <td>Specifies whether to use the I2C interface for full speed PHY. This
33558 + parameter is only applicable if PHY_TYPE is FS.
33559 + - 0: Disabled (default)
33560 + - 1: Enabled
33561 + </td></tr>
33562 +
33563 + <tr>
33564 + <td>ulpi_fs_ls</td>
33565 + <td>Specifies whether to use ULPI FS/LS mode only.
33566 + - 0: Disabled (default)
33567 + - 1: Enabled
33568 + </td></tr>
33569 +
33570 + <tr>
33571 + <td>ts_dline</td>
33572 + <td>Specifies whether term select D-Line pulsing for all PHYs is enabled.
33573 + - 0: Disabled (default)
33574 + - 1: Enabled
33575 + </td></tr>
33576 +
33577 + <tr>
33578 + <td>en_multiple_tx_fifo</td>
33579 + <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs.
33580 + The driver will automatically detect the value for this parameter if none is
33581 + specified.
33582 + - 0: Disabled
33583 + - 1: Enabled (default, if available)
33584 + </td></tr>
33585 +
33586 + <tr>
33587 + <td>dev_tx_fifo_size_n (n = 1 to 15)</td>
33588 + <td>Number of 4-byte words in each of the Tx FIFOs in device mode
33589 + when dynamic FIFO sizing is enabled.
33590 + - Values: 4 to 768 (default 256)
33591 + </td></tr>
33592 +
33593 + <tr>
33594 + <td>tx_thr_length</td>
33595 + <td>Transmit Threshold length in 32 bit double words
33596 + - Values: 8 to 128 (default 64)
33597 + </td></tr>
33598 +
33599 + <tr>
33600 + <td>rx_thr_length</td>
33601 + <td>Receive Threshold length in 32 bit double words
33602 + - Values: 8 to 128 (default 64)
33603 + </td></tr>
33604 +
33605 +<tr>
33606 + <td>thr_ctl</td>
33607 + <td>Specifies whether to enable Thresholding for Device mode. Bits 0, 1, 2 of
33608 + this parmater specifies if thresholding is enabled for non-Iso Tx, Iso Tx and
33609 + Rx transfers accordingly.
33610 + The driver will automatically detect the value for this parameter if none is
33611 + specified.
33612 + - Values: 0 to 7 (default 0)
33613 + Bit values indicate:
33614 + - 0: Thresholding disabled
33615 + - 1: Thresholding enabled
33616 + </td></tr>
33617 +
33618 +<tr>
33619 + <td>dma_desc_enable</td>
33620 + <td>Specifies whether to enable Descriptor DMA mode.
33621 + The driver will automatically detect the value for this parameter if none is
33622 + specified.
33623 + - 0: Descriptor DMA disabled
33624 + - 1: Descriptor DMA (default, if available)
33625 + </td></tr>
33626 +
33627 +<tr>
33628 + <td>mpi_enable</td>
33629 + <td>Specifies whether to enable MPI enhancement mode.
33630 + The driver will automatically detect the value for this parameter if none is
33631 + specified.
33632 + - 0: MPI disabled (default)
33633 + - 1: MPI enable
33634 + </td></tr>
33635 +
33636 +<tr>
33637 + <td>pti_enable</td>
33638 + <td>Specifies whether to enable PTI enhancement support.
33639 + The driver will automatically detect the value for this parameter if none is
33640 + specified.
33641 + - 0: PTI disabled (default)
33642 + - 1: PTI enable
33643 + </td></tr>
33644 +
33645 +<tr>
33646 + <td>lpm_enable</td>
33647 + <td>Specifies whether to enable LPM support.
33648 + The driver will automatically detect the value for this parameter if none is
33649 + specified.
33650 + - 0: LPM disabled
33651 + - 1: LPM enable (default, if available)
33652 + </td></tr>
33653 +
33654 +<tr>
33655 + <td>ic_usb_cap</td>
33656 + <td>Specifies whether to enable IC_USB capability.
33657 + The driver will automatically detect the value for this parameter if none is
33658 + specified.
33659 + - 0: IC_USB disabled (default, if available)
33660 + - 1: IC_USB enable
33661 + </td></tr>
33662 +
33663 +<tr>
33664 + <td>ahb_thr_ratio</td>
33665 + <td>Specifies AHB Threshold ratio.
33666 + - Values: 0 to 3 (default 0)
33667 + </td></tr>
33668 +
33669 +<tr>
33670 + <td>power_down</td>
33671 + <td>Specifies Power Down(Hibernation) Mode.
33672 + The driver will automatically detect the value for this parameter if none is
33673 + specified.
33674 + - 0: Power Down disabled (default)
33675 + - 2: Power Down enabled
33676 + </td></tr>
33677 +
33678 + <tr>
33679 + <td>reload_ctl</td>
33680 + <td>Specifies whether dynamic reloading of the HFIR register is allowed during
33681 + run time. The driver will automatically detect the value for this parameter if
33682 + none is specified. In case the HFIR value is reloaded when HFIR.RldCtrl == 1'b0
33683 + the core might misbehave.
33684 + - 0: Reload Control disabled (default)
33685 + - 1: Reload Control enabled
33686 + </td></tr>
33687 +
33688 + <tr>
33689 + <td>dev_out_nak</td>
33690 + <td>Specifies whether Device OUT NAK enhancement enabled or no.
33691 + The driver will automatically detect the value for this parameter if
33692 + none is specified. This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
33693 + - 0: The core does not set NAK after Bulk OUT transfer complete (default)
33694 + - 1: The core sets NAK after Bulk OUT transfer complete
33695 + </td></tr>
33696 +
33697 + <tr>
33698 + <td>cont_on_bna</td>
33699 + <td>Specifies whether Enable Continue on BNA enabled or no.
33700 + After receiving BNA interrupt the core disables the endpoint,when the
33701 + endpoint is re-enabled by the application the
33702 + - 0: Core starts processing from the DOEPDMA descriptor (default)
33703 + - 1: Core starts processing from the descriptor which received the BNA.
33704 + This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
33705 + </td></tr>
33706 +
33707 + <tr>
33708 + <td>ahb_single</td>
33709 + <td>This bit when programmed supports SINGLE transfers for remainder data
33710 + in a transfer for DMA mode of operation.
33711 + - 0: The remainder data will be sent using INCR burst size (default)
33712 + - 1: The remainder data will be sent using SINGLE burst size.
33713 + </td></tr>
33714 +
33715 +<tr>
33716 + <td>adp_enable</td>
33717 + <td>Specifies whether ADP feature is enabled.
33718 + The driver will automatically detect the value for this parameter if none is
33719 + specified.
33720 + - 0: ADP feature disabled (default)
33721 + - 1: ADP feature enabled
33722 + </td></tr>
33723 +
33724 + <tr>
33725 + <td>otg_ver</td>
33726 + <td>Specifies whether OTG is performing as USB OTG Revision 2.0 or Revision 1.3
33727 + USB OTG device.
33728 + - 0: OTG 2.0 support disabled (default)
33729 + - 1: OTG 2.0 support enabled
33730 + </td></tr>
33731 +
33732 +*/
33733 --- /dev/null
33734 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.h
33735 @@ -0,0 +1,86 @@
33736 +/* ==========================================================================
33737 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $
33738 + * $Revision: #19 $
33739 + * $Date: 2010/11/15 $
33740 + * $Change: 1627671 $
33741 + *
33742 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
33743 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
33744 + * otherwise expressly agreed to in writing between Synopsys and you.
33745 + *
33746 + * The Software IS NOT an item of Licensed Software or Licensed Product under
33747 + * any End User Software License Agreement or Agreement for Licensed Product
33748 + * with Synopsys or any supplement thereto. You are permitted to use and
33749 + * redistribute this Software in source and binary forms, with or without
33750 + * modification, provided that redistributions of source code must retain this
33751 + * notice. You may not view, use, disclose, copy or distribute this file or
33752 + * any information contained herein except pursuant to this license grant from
33753 + * Synopsys. If you do not agree with this notice, including the disclaimer
33754 + * below, then you are not authorized to use the Software.
33755 + *
33756 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
33757 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33758 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33759 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
33760 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33761 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33762 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33763 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33764 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33765 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33766 + * DAMAGE.
33767 + * ========================================================================== */
33768 +
33769 +#ifndef __DWC_OTG_DRIVER_H__
33770 +#define __DWC_OTG_DRIVER_H__
33771 +
33772 +/** @file
33773 + * This file contains the interface to the Linux driver.
33774 + */
33775 +#include "dwc_otg_os_dep.h"
33776 +#include "dwc_otg_core_if.h"
33777 +
33778 +/* Type declarations */
33779 +struct dwc_otg_pcd;
33780 +struct dwc_otg_hcd;
33781 +
33782 +/**
33783 + * This structure is a wrapper that encapsulates the driver components used to
33784 + * manage a single DWC_otg controller.
33785 + */
33786 +typedef struct dwc_otg_device {
33787 + /** Structure containing OS-dependent stuff. KEEP THIS STRUCT AT THE
33788 + * VERY BEGINNING OF THE DEVICE STRUCT. OSes such as FreeBSD and NetBSD
33789 + * require this. */
33790 + struct os_dependent os_dep;
33791 +
33792 + /** Pointer to the core interface structure. */
33793 + dwc_otg_core_if_t *core_if;
33794 +
33795 + /** Pointer to the PCD structure. */
33796 + struct dwc_otg_pcd *pcd;
33797 +
33798 + /** Pointer to the HCD structure. */
33799 + struct dwc_otg_hcd *hcd;
33800 +
33801 + /** Flag to indicate whether the common IRQ handler is installed. */
33802 + uint8_t common_irq_installed;
33803 +
33804 +} dwc_otg_device_t;
33805 +
33806 +/*We must clear S3C24XX_EINTPEND external interrupt register
33807 + * because after clearing in this register trigerred IRQ from
33808 + * H/W core in kernel interrupt can be occured again before OTG
33809 + * handlers clear all IRQ sources of Core registers because of
33810 + * timing latencies and Low Level IRQ Type.
33811 + */
33812 +#ifdef CONFIG_MACH_IPMATE
33813 +#define S3C2410X_CLEAR_EINTPEND() \
33814 +do { \
33815 + __raw_writel(1UL << 11,S3C24XX_EINTPEND); \
33816 +} while (0)
33817 +#else
33818 +#define S3C2410X_CLEAR_EINTPEND() do { } while (0)
33819 +#endif
33820 +
33821 +#endif
33822 --- /dev/null
33823 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
33824 @@ -0,0 +1,3473 @@
33825 +
33826 +/* ==========================================================================
33827 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
33828 + * $Revision: #104 $
33829 + * $Date: 2011/10/24 $
33830 + * $Change: 1871159 $
33831 + *
33832 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
33833 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
33834 + * otherwise expressly agreed to in writing between Synopsys and you.
33835 + *
33836 + * The Software IS NOT an item of Licensed Software or Licensed Product under
33837 + * any End User Software License Agreement or Agreement for Licensed Product
33838 + * with Synopsys or any supplement thereto. You are permitted to use and
33839 + * redistribute this Software in source and binary forms, with or without
33840 + * modification, provided that redistributions of source code must retain this
33841 + * notice. You may not view, use, disclose, copy or distribute this file or
33842 + * any information contained herein except pursuant to this license grant from
33843 + * Synopsys. If you do not agree with this notice, including the disclaimer
33844 + * below, then you are not authorized to use the Software.
33845 + *
33846 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
33847 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33848 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33849 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
33850 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33851 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33852 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33853 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33854 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33855 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33856 + * DAMAGE.
33857 + * ========================================================================== */
33858 +#ifndef DWC_DEVICE_ONLY
33859 +
33860 +/** @file
33861 + * This file implements HCD Core. All code in this file is portable and doesn't
33862 + * use any OS specific functions.
33863 + * Interface provided by HCD Core is defined in <code><hcd_if.h></code>
33864 + * header file.
33865 + */
33866 +
33867 +#include "dwc_otg_hcd.h"
33868 +#include "dwc_otg_regs.h"
33869 +
33870 +extern bool microframe_schedule;
33871 +
33872 +//#define DEBUG_HOST_CHANNELS
33873 +#ifdef DEBUG_HOST_CHANNELS
33874 +static int last_sel_trans_num_per_scheduled = 0;
33875 +static int last_sel_trans_num_nonper_scheduled = 0;
33876 +static int last_sel_trans_num_avail_hc_at_start = 0;
33877 +static int last_sel_trans_num_avail_hc_at_end = 0;
33878 +#endif /* DEBUG_HOST_CHANNELS */
33879 +
33880 +dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
33881 +{
33882 + return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
33883 +}
33884 +
33885 +/**
33886 + * Connection timeout function. An OTG host is required to display a
33887 + * message if the device does not connect within 10 seconds.
33888 + */
33889 +void dwc_otg_hcd_connect_timeout(void *ptr)
33890 +{
33891 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
33892 + DWC_PRINTF("Connect Timeout\n");
33893 + __DWC_ERROR("Device Not Connected/Responding\n");
33894 +}
33895 +
33896 +#if defined(DEBUG)
33897 +static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
33898 +{
33899 + if (qh->channel != NULL) {
33900 + dwc_hc_t *hc = qh->channel;
33901 + dwc_list_link_t *item;
33902 + dwc_otg_qh_t *qh_item;
33903 + int num_channels = hcd->core_if->core_params->host_channels;
33904 + int i;
33905 +
33906 + dwc_otg_hc_regs_t *hc_regs;
33907 + hcchar_data_t hcchar;
33908 + hcsplt_data_t hcsplt;
33909 + hctsiz_data_t hctsiz;
33910 + uint32_t hcdma;
33911 +
33912 + hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
33913 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
33914 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
33915 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
33916 + hcdma = DWC_READ_REG32(&hc_regs->hcdma);
33917 +
33918 + DWC_PRINTF(" Assigned to channel %p:\n", hc);
33919 + DWC_PRINTF(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
33920 + hcsplt.d32);
33921 + DWC_PRINTF(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
33922 + hcdma);
33923 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
33924 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
33925 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
33926 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
33927 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
33928 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
33929 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
33930 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
33931 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
33932 + DWC_PRINTF(" qh: %p\n", hc->qh);
33933 + DWC_PRINTF(" NP inactive sched:\n");
33934 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
33935 + qh_item =
33936 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
33937 + DWC_PRINTF(" %p\n", qh_item);
33938 + }
33939 + DWC_PRINTF(" NP active sched:\n");
33940 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
33941 + qh_item =
33942 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
33943 + DWC_PRINTF(" %p\n", qh_item);
33944 + }
33945 + DWC_PRINTF(" Channels: \n");
33946 + for (i = 0; i < num_channels; i++) {
33947 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
33948 + DWC_PRINTF(" %2d: %p\n", i, hc);
33949 + }
33950 + }
33951 +}
33952 +#else
33953 +#define dump_channel_info(hcd, qh)
33954 +#endif /* DEBUG */
33955 +
33956 +/**
33957 + * Work queue function for starting the HCD when A-Cable is connected.
33958 + * The hcd_start() must be called in a process context.
33959 + */
33960 +static void hcd_start_func(void *_vp)
33961 +{
33962 + dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
33963 +
33964 + DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
33965 + if (hcd) {
33966 + hcd->fops->start(hcd);
33967 + }
33968 +}
33969 +
33970 +static void del_xfer_timers(dwc_otg_hcd_t * hcd)
33971 +{
33972 +#ifdef DEBUG
33973 + int i;
33974 + int num_channels = hcd->core_if->core_params->host_channels;
33975 + for (i = 0; i < num_channels; i++) {
33976 + DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
33977 + }
33978 +#endif
33979 +}
33980 +
33981 +static void del_timers(dwc_otg_hcd_t * hcd)
33982 +{
33983 + del_xfer_timers(hcd);
33984 + DWC_TIMER_CANCEL(hcd->conn_timer);
33985 +}
33986 +
33987 +/**
33988 + * Processes all the URBs in a single list of QHs. Completes them with
33989 + * -ETIMEDOUT and frees the QTD.
33990 + */
33991 +static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
33992 +{
33993 + dwc_list_link_t *qh_item;
33994 + dwc_otg_qh_t *qh;
33995 + dwc_otg_qtd_t *qtd, *qtd_tmp;
33996 +
33997 + DWC_LIST_FOREACH(qh_item, qh_list) {
33998 + qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
33999 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
34000 + &qh->qtd_list, qtd_list_entry) {
34001 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
34002 + if (qtd->urb != NULL) {
34003 + hcd->fops->complete(hcd, qtd->urb->priv,
34004 + qtd->urb, -DWC_E_TIMEOUT);
34005 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
34006 + }
34007 +
34008 + }
34009 + }
34010 +}
34011 +
34012 +/**
34013 + * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
34014 + * and periodic schedules. The QTD associated with each URB is removed from
34015 + * the schedule and freed. This function may be called when a disconnect is
34016 + * detected or when the HCD is being stopped.
34017 + */
34018 +static void kill_all_urbs(dwc_otg_hcd_t * hcd)
34019 +{
34020 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
34021 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
34022 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
34023 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
34024 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
34025 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
34026 +}
34027 +
34028 +/**
34029 + * Start the connection timer. An OTG host is required to display a
34030 + * message if the device does not connect within 10 seconds. The
34031 + * timer is deleted if a port connect interrupt occurs before the
34032 + * timer expires.
34033 + */
34034 +static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
34035 +{
34036 + DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
34037 +}
34038 +
34039 +/**
34040 + * HCD Callback function for disconnect of the HCD.
34041 + *
34042 + * @param p void pointer to the <code>struct usb_hcd</code>
34043 + */
34044 +static int32_t dwc_otg_hcd_session_start_cb(void *p)
34045 +{
34046 + dwc_otg_hcd_t *dwc_otg_hcd;
34047 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
34048 + dwc_otg_hcd = p;
34049 + dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
34050 + return 1;
34051 +}
34052 +
34053 +/**
34054 + * HCD Callback function for starting the HCD when A-Cable is
34055 + * connected.
34056 + *
34057 + * @param p void pointer to the <code>struct usb_hcd</code>
34058 + */
34059 +static int32_t dwc_otg_hcd_start_cb(void *p)
34060 +{
34061 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34062 + dwc_otg_core_if_t *core_if;
34063 + hprt0_data_t hprt0;
34064 +
34065 + core_if = dwc_otg_hcd->core_if;
34066 +
34067 + if (core_if->op_state == B_HOST) {
34068 + /*
34069 + * Reset the port. During a HNP mode switch the reset
34070 + * needs to occur within 1ms and have a duration of at
34071 + * least 50ms.
34072 + */
34073 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
34074 + hprt0.b.prtrst = 1;
34075 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34076 + }
34077 + DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
34078 + hcd_start_func, dwc_otg_hcd, 50,
34079 + "start hcd");
34080 +
34081 + return 1;
34082 +}
34083 +
34084 +/**
34085 + * HCD Callback function for disconnect of the HCD.
34086 + *
34087 + * @param p void pointer to the <code>struct usb_hcd</code>
34088 + */
34089 +static int32_t dwc_otg_hcd_disconnect_cb(void *p)
34090 +{
34091 + gintsts_data_t intr;
34092 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34093 +
34094 + /*
34095 + * Set status flags for the hub driver.
34096 + */
34097 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
34098 + dwc_otg_hcd->flags.b.port_connect_status = 0;
34099 +
34100 + /*
34101 + * Shutdown any transfers in process by clearing the Tx FIFO Empty
34102 + * interrupt mask and status bits and disabling subsequent host
34103 + * channel interrupts.
34104 + */
34105 + intr.d32 = 0;
34106 + intr.b.nptxfempty = 1;
34107 + intr.b.ptxfempty = 1;
34108 + intr.b.hcintr = 1;
34109 + DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
34110 + intr.d32, 0);
34111 + DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
34112 + intr.d32, 0);
34113 +
34114 + del_timers(dwc_otg_hcd);
34115 +
34116 + /*
34117 + * Turn off the vbus power only if the core has transitioned to device
34118 + * mode. If still in host mode, need to keep power on to detect a
34119 + * reconnection.
34120 + */
34121 + if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
34122 + if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
34123 + hprt0_data_t hprt0 = {.d32 = 0 };
34124 + DWC_PRINTF("Disconnect: PortPower off\n");
34125 + hprt0.b.prtpwr = 0;
34126 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0,
34127 + hprt0.d32);
34128 + }
34129 +
34130 + dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
34131 + }
34132 +
34133 + /* Respond with an error status to all URBs in the schedule. */
34134 + kill_all_urbs(dwc_otg_hcd);
34135 +
34136 + if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
34137 + /* Clean up any host channels that were in use. */
34138 + int num_channels;
34139 + int i;
34140 + dwc_hc_t *channel;
34141 + dwc_otg_hc_regs_t *hc_regs;
34142 + hcchar_data_t hcchar;
34143 +
34144 + num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
34145 +
34146 + if (!dwc_otg_hcd->core_if->dma_enable) {
34147 + /* Flush out any channel requests in slave mode. */
34148 + for (i = 0; i < num_channels; i++) {
34149 + channel = dwc_otg_hcd->hc_ptr_array[i];
34150 + if (DWC_CIRCLEQ_EMPTY_ENTRY
34151 + (channel, hc_list_entry)) {
34152 + hc_regs =
34153 + dwc_otg_hcd->core_if->
34154 + host_if->hc_regs[i];
34155 + hcchar.d32 =
34156 + DWC_READ_REG32(&hc_regs->hcchar);
34157 + if (hcchar.b.chen) {
34158 + hcchar.b.chen = 0;
34159 + hcchar.b.chdis = 1;
34160 + hcchar.b.epdir = 0;
34161 + DWC_WRITE_REG32
34162 + (&hc_regs->hcchar,
34163 + hcchar.d32);
34164 + }
34165 + }
34166 + }
34167 + }
34168 +
34169 + for (i = 0; i < num_channels; i++) {
34170 + channel = dwc_otg_hcd->hc_ptr_array[i];
34171 + if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
34172 + hc_regs =
34173 + dwc_otg_hcd->core_if->host_if->hc_regs[i];
34174 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
34175 + if (hcchar.b.chen) {
34176 + /* Halt the channel. */
34177 + hcchar.b.chdis = 1;
34178 + DWC_WRITE_REG32(&hc_regs->hcchar,
34179 + hcchar.d32);
34180 + }
34181 +
34182 + dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
34183 + channel);
34184 + DWC_CIRCLEQ_INSERT_TAIL
34185 + (&dwc_otg_hcd->free_hc_list, channel,
34186 + hc_list_entry);
34187 + /*
34188 + * Added for Descriptor DMA to prevent channel double cleanup
34189 + * in release_channel_ddma(). Which called from ep_disable
34190 + * when device disconnect.
34191 + */
34192 + channel->qh = NULL;
34193 + }
34194 + }
34195 + }
34196 +
34197 + if (dwc_otg_hcd->fops->disconnect) {
34198 + dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
34199 + }
34200 +
34201 + return 1;
34202 +}
34203 +
34204 +/**
34205 + * HCD Callback function for stopping the HCD.
34206 + *
34207 + * @param p void pointer to the <code>struct usb_hcd</code>
34208 + */
34209 +static int32_t dwc_otg_hcd_stop_cb(void *p)
34210 +{
34211 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34212 +
34213 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
34214 + dwc_otg_hcd_stop(dwc_otg_hcd);
34215 + return 1;
34216 +}
34217 +
34218 +#ifdef CONFIG_USB_DWC_OTG_LPM
34219 +/**
34220 + * HCD Callback function for sleep of HCD.
34221 + *
34222 + * @param p void pointer to the <code>struct usb_hcd</code>
34223 + */
34224 +static int dwc_otg_hcd_sleep_cb(void *p)
34225 +{
34226 + dwc_otg_hcd_t *hcd = p;
34227 +
34228 + dwc_otg_hcd_free_hc_from_lpm(hcd);
34229 +
34230 + return 0;
34231 +}
34232 +#endif
34233 +
34234 +/**
34235 + * HCD Callback function for Remote Wakeup.
34236 + *
34237 + * @param p void pointer to the <code>struct usb_hcd</code>
34238 + */
34239 +static int dwc_otg_hcd_rem_wakeup_cb(void *p)
34240 +{
34241 + dwc_otg_hcd_t *hcd = p;
34242 +
34243 + if (hcd->core_if->lx_state == DWC_OTG_L2) {
34244 + hcd->flags.b.port_suspend_change = 1;
34245 + }
34246 +#ifdef CONFIG_USB_DWC_OTG_LPM
34247 + else {
34248 + hcd->flags.b.port_l1_change = 1;
34249 + }
34250 +#endif
34251 + return 0;
34252 +}
34253 +
34254 +/**
34255 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
34256 + * stopped.
34257 + */
34258 +void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
34259 +{
34260 + hprt0_data_t hprt0 = {.d32 = 0 };
34261 +
34262 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
34263 +
34264 + /*
34265 + * The root hub should be disconnected before this function is called.
34266 + * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
34267 + * and the QH lists (via ..._hcd_endpoint_disable).
34268 + */
34269 +
34270 + /* Turn off all host-specific interrupts. */
34271 + dwc_otg_disable_host_interrupts(hcd->core_if);
34272 +
34273 + /* Turn off the vbus power */
34274 + DWC_PRINTF("PortPower off\n");
34275 + hprt0.b.prtpwr = 0;
34276 + DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
34277 + dwc_mdelay(1);
34278 +}
34279 +
34280 +int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
34281 + dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
34282 + int atomic_alloc)
34283 +{
34284 + dwc_irqflags_t flags;
34285 + int retval = 0;
34286 + dwc_otg_qtd_t *qtd;
34287 + gintmsk_data_t intr_mask = {.d32 = 0 };
34288 +
34289 +#ifdef DEBUG /* integrity checks (Broadcom) */
34290 + if (NULL == hcd->core_if) {
34291 + DWC_ERROR("**** DWC OTG HCD URB Enqueue - HCD has NULL core_if\n");
34292 + /* No longer connected. */
34293 + return -DWC_E_INVALID;
34294 + }
34295 +#endif
34296 + if (!hcd->flags.b.port_connect_status) {
34297 + /* No longer connected. */
34298 + DWC_ERROR("Not connected\n");
34299 + return -DWC_E_NO_DEVICE;
34300 + }
34301 +
34302 + qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
34303 + if (qtd == NULL) {
34304 + DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
34305 + return -DWC_E_NO_MEMORY;
34306 + }
34307 +#ifdef DEBUG /* integrity checks (Broadcom) */
34308 + if (qtd->urb == NULL) {
34309 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD with no URBs\n");
34310 + return -DWC_E_NO_MEMORY;
34311 + }
34312 + if (qtd->urb->priv == NULL) {
34313 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD URB with no URB handle\n");
34314 + return -DWC_E_NO_MEMORY;
34315 + }
34316 +#endif
34317 + retval =
34318 + dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
34319 + // creates a new queue in ep_handle if it doesn't exist already
34320 + if (retval < 0) {
34321 + DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
34322 + "Error status %d\n", retval);
34323 + dwc_otg_hcd_qtd_free(qtd);
34324 + } else {
34325 + qtd->qh = *ep_handle;
34326 + }
34327 + intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
34328 + if (!intr_mask.b.sofintr && retval == 0) {
34329 + dwc_otg_transaction_type_e tr_type;
34330 + if ((qtd->qh->ep_type == UE_BULK)
34331 + && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
34332 + /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
34333 + return 0;
34334 + }
34335 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34336 + tr_type = dwc_otg_hcd_select_transactions(hcd);
34337 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
34338 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
34339 + }
34340 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34341 + }
34342 +
34343 + return retval;
34344 +}
34345 +
34346 +int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
34347 + dwc_otg_hcd_urb_t * dwc_otg_urb)
34348 +{
34349 + dwc_otg_qh_t *qh;
34350 + dwc_otg_qtd_t *urb_qtd;
34351 +
34352 +#ifdef DEBUG /* integrity checks (Broadcom) */
34353 +
34354 + if (hcd == NULL) {
34355 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL HCD\n");
34356 + return -DWC_E_INVALID;
34357 + }
34358 + if (dwc_otg_urb == NULL) {
34359 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL URB\n");
34360 + return -DWC_E_INVALID;
34361 + }
34362 + if (dwc_otg_urb->qtd == NULL) {
34363 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with NULL QTD\n");
34364 + return -DWC_E_INVALID;
34365 + }
34366 + urb_qtd = dwc_otg_urb->qtd;
34367 + if (urb_qtd->qh == NULL) {
34368 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
34369 + return -DWC_E_INVALID;
34370 + }
34371 +#else
34372 + urb_qtd = dwc_otg_urb->qtd;
34373 +#endif
34374 + qh = urb_qtd->qh;
34375 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
34376 + if (urb_qtd->in_process) {
34377 + dump_channel_info(hcd, qh);
34378 + }
34379 + }
34380 +#ifdef DEBUG /* integrity checks (Broadcom) */
34381 + if (hcd->core_if == NULL) {
34382 + DWC_ERROR("**** DWC OTG HCD URB Dequeue HCD has NULL core_if\n");
34383 + return -DWC_E_INVALID;
34384 + }
34385 +#endif
34386 + if (urb_qtd->in_process && qh->channel) {
34387 + /* The QTD is in process (it has been assigned to a channel). */
34388 + if (hcd->flags.b.port_connect_status) {
34389 + /*
34390 + * If still connected (i.e. in host mode), halt the
34391 + * channel so it can be used for other transfers. If
34392 + * no longer connected, the host registers can't be
34393 + * written to halt the channel since the core is in
34394 + * device mode.
34395 + */
34396 + dwc_otg_hc_halt(hcd->core_if, qh->channel,
34397 + DWC_OTG_HC_XFER_URB_DEQUEUE);
34398 + }
34399 + }
34400 +
34401 + /*
34402 + * Free the QTD and clean up the associated QH. Leave the QH in the
34403 + * schedule if it has any remaining QTDs.
34404 + */
34405 +
34406 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue - "
34407 + "delete %sQueue handler\n",
34408 + hcd->core_if->dma_desc_enable?"DMA ":"");
34409 + if (!hcd->core_if->dma_desc_enable) {
34410 + uint8_t b = urb_qtd->in_process;
34411 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
34412 + if (b) {
34413 + dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
34414 + qh->channel = NULL;
34415 + } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
34416 + dwc_otg_hcd_qh_remove(hcd, qh);
34417 + }
34418 + } else {
34419 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
34420 + }
34421 + return 0;
34422 +}
34423 +
34424 +int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
34425 + int retry)
34426 +{
34427 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
34428 + int retval = 0;
34429 + dwc_irqflags_t flags;
34430 +
34431 + if (retry < 0) {
34432 + retval = -DWC_E_INVALID;
34433 + goto done;
34434 + }
34435 +
34436 + if (!qh) {
34437 + retval = -DWC_E_INVALID;
34438 + goto done;
34439 + }
34440 +
34441 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34442 +
34443 + while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
34444 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34445 + retry--;
34446 + dwc_msleep(5);
34447 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34448 + }
34449 +
34450 + dwc_otg_hcd_qh_remove(hcd, qh);
34451 +
34452 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34453 + /*
34454 + * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
34455 + * and qh_free to prevent stack dump on DWC_DMA_FREE() with
34456 + * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
34457 + * and dwc_otg_hcd_frame_list_alloc().
34458 + */
34459 + dwc_otg_hcd_qh_free(hcd, qh);
34460 +
34461 +done:
34462 + return retval;
34463 +}
34464 +
34465 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
34466 +int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle)
34467 +{
34468 + int retval = 0;
34469 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
34470 + if (!qh)
34471 + return -DWC_E_INVALID;
34472 +
34473 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
34474 + return retval;
34475 +}
34476 +#endif
34477 +
34478 +/**
34479 + * HCD Callback structure for handling mode switching.
34480 + */
34481 +static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
34482 + .start = dwc_otg_hcd_start_cb,
34483 + .stop = dwc_otg_hcd_stop_cb,
34484 + .disconnect = dwc_otg_hcd_disconnect_cb,
34485 + .session_start = dwc_otg_hcd_session_start_cb,
34486 + .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
34487 +#ifdef CONFIG_USB_DWC_OTG_LPM
34488 + .sleep = dwc_otg_hcd_sleep_cb,
34489 +#endif
34490 + .p = 0,
34491 +};
34492 +
34493 +/**
34494 + * Reset tasklet function
34495 + */
34496 +static void reset_tasklet_func(void *data)
34497 +{
34498 + dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
34499 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
34500 + hprt0_data_t hprt0;
34501 +
34502 + DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
34503 +
34504 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
34505 + hprt0.b.prtrst = 1;
34506 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34507 + dwc_mdelay(60);
34508 +
34509 + hprt0.b.prtrst = 0;
34510 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34511 + dwc_otg_hcd->flags.b.port_reset_change = 1;
34512 +}
34513 +
34514 +static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
34515 +{
34516 + dwc_list_link_t *item;
34517 + dwc_otg_qh_t *qh;
34518 + dwc_irqflags_t flags;
34519 +
34520 + if (!qh_list->next) {
34521 + /* The list hasn't been initialized yet. */
34522 + return;
34523 + }
34524 + /*
34525 + * Hold spinlock here. Not needed in that case if bellow
34526 + * function is being called from ISR
34527 + */
34528 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34529 + /* Ensure there are no QTDs or URBs left. */
34530 + kill_urbs_in_qh_list(hcd, qh_list);
34531 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34532 +
34533 + DWC_LIST_FOREACH(item, qh_list) {
34534 + qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
34535 + dwc_otg_hcd_qh_remove_and_free(hcd, qh);
34536 + }
34537 +}
34538 +
34539 +/**
34540 + * Exit from Hibernation if Host did not detect SRP from connected SRP capable
34541 + * Device during SRP time by host power up.
34542 + */
34543 +void dwc_otg_hcd_power_up(void *ptr)
34544 +{
34545 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
34546 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
34547 +
34548 + DWC_PRINTF("%s called\n", __FUNCTION__);
34549 +
34550 + if (!core_if->hibernation_suspend) {
34551 + DWC_PRINTF("Already exited from Hibernation\n");
34552 + return;
34553 + }
34554 +
34555 + /* Switch on the voltage to the core */
34556 + gpwrdn.b.pwrdnswtch = 1;
34557 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34558 + dwc_udelay(10);
34559 +
34560 + /* Reset the core */
34561 + gpwrdn.d32 = 0;
34562 + gpwrdn.b.pwrdnrstn = 1;
34563 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34564 + dwc_udelay(10);
34565 +
34566 + /* Disable power clamps */
34567 + gpwrdn.d32 = 0;
34568 + gpwrdn.b.pwrdnclmp = 1;
34569 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34570 +
34571 + /* Remove reset the core signal */
34572 + gpwrdn.d32 = 0;
34573 + gpwrdn.b.pwrdnrstn = 1;
34574 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
34575 + dwc_udelay(10);
34576 +
34577 + /* Disable PMU interrupt */
34578 + gpwrdn.d32 = 0;
34579 + gpwrdn.b.pmuintsel = 1;
34580 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34581 +
34582 + core_if->hibernation_suspend = 0;
34583 +
34584 + /* Disable PMU */
34585 + gpwrdn.d32 = 0;
34586 + gpwrdn.b.pmuactv = 1;
34587 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34588 + dwc_udelay(10);
34589 +
34590 + /* Enable VBUS */
34591 + gpwrdn.d32 = 0;
34592 + gpwrdn.b.dis_vbus = 1;
34593 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34594 +
34595 + core_if->op_state = A_HOST;
34596 + dwc_otg_core_init(core_if);
34597 + dwc_otg_enable_global_interrupts(core_if);
34598 + cil_hcd_start(core_if);
34599 +}
34600 +
34601 +/**
34602 + * Frees secondary storage associated with the dwc_otg_hcd structure contained
34603 + * in the struct usb_hcd field.
34604 + */
34605 +static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
34606 +{
34607 + int i;
34608 +
34609 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
34610 +
34611 + del_timers(dwc_otg_hcd);
34612 +
34613 + /* Free memory for QH/QTD lists */
34614 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
34615 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
34616 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
34617 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
34618 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
34619 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
34620 +
34621 + /* Free memory for the host channels. */
34622 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
34623 + dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
34624 +
34625 +#ifdef DEBUG
34626 + if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
34627 + DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
34628 + }
34629 +#endif
34630 + if (hc != NULL) {
34631 + DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
34632 + i, hc);
34633 + DWC_FREE(hc);
34634 + }
34635 + }
34636 +
34637 + if (dwc_otg_hcd->core_if->dma_enable) {
34638 + if (dwc_otg_hcd->status_buf_dma) {
34639 + DWC_DMA_FREE(DWC_OTG_HCD_STATUS_BUF_SIZE,
34640 + dwc_otg_hcd->status_buf,
34641 + dwc_otg_hcd->status_buf_dma);
34642 + }
34643 + } else if (dwc_otg_hcd->status_buf != NULL) {
34644 + DWC_FREE(dwc_otg_hcd->status_buf);
34645 + }
34646 + DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
34647 + /* Set core_if's lock pointer to NULL */
34648 + dwc_otg_hcd->core_if->lock = NULL;
34649 +
34650 + DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
34651 + DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
34652 +
34653 +#ifdef DWC_DEV_SRPCAP
34654 + if (dwc_otg_hcd->core_if->power_down == 2 &&
34655 + dwc_otg_hcd->core_if->pwron_timer) {
34656 + DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer);
34657 + }
34658 +#endif
34659 + DWC_FREE(dwc_otg_hcd);
34660 +}
34661 +
34662 +int init_hcd_usecs(dwc_otg_hcd_t *_hcd);
34663 +
34664 +int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
34665 +{
34666 + int retval = 0;
34667 + int num_channels;
34668 + int i;
34669 + dwc_hc_t *channel;
34670 +
34671 + hcd->lock = DWC_SPINLOCK_ALLOC();
34672 + DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n",
34673 + hcd, core_if);
34674 + if (!hcd->lock) {
34675 + DWC_ERROR("Could not allocate lock for pcd");
34676 + DWC_FREE(hcd);
34677 + retval = -DWC_E_NO_MEMORY;
34678 + goto out;
34679 + }
34680 + hcd->core_if = core_if;
34681 +
34682 + /* Register the HCD CIL Callbacks */
34683 + dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
34684 + &hcd_cil_callbacks, hcd);
34685 +
34686 + /* Initialize the non-periodic schedule. */
34687 + DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
34688 + DWC_LIST_INIT(&hcd->non_periodic_sched_active);
34689 +
34690 + /* Initialize the periodic schedule. */
34691 + DWC_LIST_INIT(&hcd->periodic_sched_inactive);
34692 + DWC_LIST_INIT(&hcd->periodic_sched_ready);
34693 + DWC_LIST_INIT(&hcd->periodic_sched_assigned);
34694 + DWC_LIST_INIT(&hcd->periodic_sched_queued);
34695 +
34696 + /*
34697 + * Create a host channel descriptor for each host channel implemented
34698 + * in the controller. Initialize the channel descriptor array.
34699 + */
34700 + DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
34701 + num_channels = hcd->core_if->core_params->host_channels;
34702 + DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
34703 + for (i = 0; i < num_channels; i++) {
34704 + channel = DWC_ALLOC(sizeof(dwc_hc_t));
34705 + if (channel == NULL) {
34706 + retval = -DWC_E_NO_MEMORY;
34707 + DWC_ERROR("%s: host channel allocation failed\n",
34708 + __func__);
34709 + dwc_otg_hcd_free(hcd);
34710 + goto out;
34711 + }
34712 + channel->hc_num = i;
34713 + hcd->hc_ptr_array[i] = channel;
34714 +#ifdef DEBUG
34715 + hcd->core_if->hc_xfer_timer[i] =
34716 + DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
34717 + &hcd->core_if->hc_xfer_info[i]);
34718 +#endif
34719 + DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
34720 + channel);
34721 + }
34722 +
34723 + /* Initialize the Connection timeout timer. */
34724 + hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
34725 + dwc_otg_hcd_connect_timeout, 0);
34726 +
34727 + printk(KERN_DEBUG "dwc_otg: Microframe scheduler %s\n", microframe_schedule ? "enabled":"disabled");
34728 + if (microframe_schedule)
34729 + init_hcd_usecs(hcd);
34730 +
34731 + /* Initialize reset tasklet. */
34732 + hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
34733 +#ifdef DWC_DEV_SRPCAP
34734 + if (hcd->core_if->power_down == 2) {
34735 + /* Initialize Power on timer for Host power up in case hibernation */
34736 + hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER",
34737 + dwc_otg_hcd_power_up, core_if);
34738 + }
34739 +#endif
34740 +
34741 + /*
34742 + * Allocate space for storing data on status transactions. Normally no
34743 + * data is sent, but this space acts as a bit bucket. This must be
34744 + * done after usb_add_hcd since that function allocates the DMA buffer
34745 + * pool.
34746 + */
34747 + if (hcd->core_if->dma_enable) {
34748 + hcd->status_buf =
34749 + DWC_DMA_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE,
34750 + &hcd->status_buf_dma);
34751 + } else {
34752 + hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE);
34753 + }
34754 + if (!hcd->status_buf) {
34755 + retval = -DWC_E_NO_MEMORY;
34756 + DWC_ERROR("%s: status_buf allocation failed\n", __func__);
34757 + dwc_otg_hcd_free(hcd);
34758 + goto out;
34759 + }
34760 +
34761 + hcd->otg_port = 1;
34762 + hcd->frame_list = NULL;
34763 + hcd->frame_list_dma = 0;
34764 + hcd->periodic_qh_count = 0;
34765 +out:
34766 + return retval;
34767 +}
34768 +
34769 +void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
34770 +{
34771 + /* Turn off all host-specific interrupts. */
34772 + dwc_otg_disable_host_interrupts(hcd->core_if);
34773 +
34774 + dwc_otg_hcd_free(hcd);
34775 +}
34776 +
34777 +/**
34778 + * Initializes dynamic portions of the DWC_otg HCD state.
34779 + */
34780 +static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
34781 +{
34782 + int num_channels;
34783 + int i;
34784 + dwc_hc_t *channel;
34785 + dwc_hc_t *channel_tmp;
34786 +
34787 + hcd->flags.d32 = 0;
34788 +
34789 + hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
34790 + if (!microframe_schedule) {
34791 + hcd->non_periodic_channels = 0;
34792 + hcd->periodic_channels = 0;
34793 + } else {
34794 + hcd->available_host_channels = hcd->core_if->core_params->host_channels;
34795 + }
34796 + /*
34797 + * Put all channels in the free channel list and clean up channel
34798 + * states.
34799 + */
34800 + DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
34801 + &hcd->free_hc_list, hc_list_entry) {
34802 + DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
34803 + }
34804 +
34805 + num_channels = hcd->core_if->core_params->host_channels;
34806 + for (i = 0; i < num_channels; i++) {
34807 + channel = hcd->hc_ptr_array[i];
34808 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
34809 + hc_list_entry);
34810 + dwc_otg_hc_cleanup(hcd->core_if, channel);
34811 + }
34812 +
34813 + /* Initialize the DWC core for host mode operation. */
34814 + dwc_otg_core_host_init(hcd->core_if);
34815 +
34816 + /* Set core_if's lock pointer to the hcd->lock */
34817 + hcd->core_if->lock = hcd->lock;
34818 +}
34819 +
34820 +/**
34821 + * Assigns transactions from a QTD to a free host channel and initializes the
34822 + * host channel to perform the transactions. The host channel is removed from
34823 + * the free list.
34824 + *
34825 + * @param hcd The HCD state structure.
34826 + * @param qh Transactions from the first QTD for this QH are selected and
34827 + * assigned to a free host channel.
34828 + */
34829 +static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
34830 +{
34831 + dwc_hc_t *hc;
34832 + dwc_otg_qtd_t *qtd;
34833 + dwc_otg_hcd_urb_t *urb;
34834 + void* ptr = NULL;
34835 +
34836 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
34837 +
34838 + urb = qtd->urb;
34839 +
34840 + DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p) - urb %x, actual_length %d\n", __func__, hcd, qh, (unsigned int)urb, urb->actual_length);
34841 +
34842 + if (((urb->actual_length < 0) || (urb->actual_length > urb->length)) && !dwc_otg_hcd_is_pipe_in(&urb->pipe_info))
34843 + urb->actual_length = urb->length;
34844 +
34845 +
34846 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
34847 +
34848 + /* Remove the host channel from the free list. */
34849 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
34850 +
34851 + qh->channel = hc;
34852 +
34853 + qtd->in_process = 1;
34854 +
34855 + /*
34856 + * Use usb_pipedevice to determine device address. This address is
34857 + * 0 before the SET_ADDRESS command and the correct address afterward.
34858 + */
34859 + hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
34860 + hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
34861 + hc->speed = qh->dev_speed;
34862 + hc->max_packet = dwc_max_packet(qh->maxp);
34863 +
34864 + hc->xfer_started = 0;
34865 + hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
34866 + hc->error_state = (qtd->error_count > 0);
34867 + hc->halt_on_queue = 0;
34868 + hc->halt_pending = 0;
34869 + hc->requests = 0;
34870 +
34871 + /*
34872 + * The following values may be modified in the transfer type section
34873 + * below. The xfer_len value may be reduced when the transfer is
34874 + * started to accommodate the max widths of the XferSize and PktCnt
34875 + * fields in the HCTSIZn register.
34876 + */
34877 +
34878 + hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
34879 + if (hc->ep_is_in) {
34880 + hc->do_ping = 0;
34881 + } else {
34882 + hc->do_ping = qh->ping_state;
34883 + }
34884 +
34885 + hc->data_pid_start = qh->data_toggle;
34886 + hc->multi_count = 1;
34887 +
34888 + if (hcd->core_if->dma_enable) {
34889 + hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
34890 +
34891 + /* For non-dword aligned case */
34892 + if (((unsigned long)hc->xfer_buff & 0x3)
34893 + && !hcd->core_if->dma_desc_enable) {
34894 + ptr = (uint8_t *) urb->buf + urb->actual_length;
34895 + }
34896 + } else {
34897 + hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
34898 + }
34899 + hc->xfer_len = urb->length - urb->actual_length;
34900 + hc->xfer_count = 0;
34901 +
34902 + /*
34903 + * Set the split attributes
34904 + */
34905 + hc->do_split = 0;
34906 + if (qh->do_split) {
34907 + uint32_t hub_addr, port_addr;
34908 + hc->do_split = 1;
34909 + hc->xact_pos = qtd->isoc_split_pos;
34910 + hc->complete_split = qtd->complete_split;
34911 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
34912 + hc->hub_addr = (uint8_t) hub_addr;
34913 + hc->port_addr = (uint8_t) port_addr;
34914 + }
34915 +
34916 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
34917 + case UE_CONTROL:
34918 + hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
34919 + switch (qtd->control_phase) {
34920 + case DWC_OTG_CONTROL_SETUP:
34921 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n");
34922 + hc->do_ping = 0;
34923 + hc->ep_is_in = 0;
34924 + hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
34925 + if (hcd->core_if->dma_enable) {
34926 + hc->xfer_buff = (uint8_t *) urb->setup_dma;
34927 + } else {
34928 + hc->xfer_buff = (uint8_t *) urb->setup_packet;
34929 + }
34930 + hc->xfer_len = 8;
34931 + ptr = NULL;
34932 + break;
34933 + case DWC_OTG_CONTROL_DATA:
34934 + DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
34935 + hc->data_pid_start = qtd->data_toggle;
34936 + break;
34937 + case DWC_OTG_CONTROL_STATUS:
34938 + /*
34939 + * Direction is opposite of data direction or IN if no
34940 + * data.
34941 + */
34942 + DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n");
34943 + if (urb->length == 0) {
34944 + hc->ep_is_in = 1;
34945 + } else {
34946 + hc->ep_is_in =
34947 + dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
34948 + }
34949 + if (hc->ep_is_in) {
34950 + hc->do_ping = 0;
34951 + }
34952 +
34953 + hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
34954 +
34955 + hc->xfer_len = 0;
34956 + if (hcd->core_if->dma_enable) {
34957 + hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
34958 + } else {
34959 + hc->xfer_buff = (uint8_t *) hcd->status_buf;
34960 + }
34961 + ptr = NULL;
34962 + break;
34963 + }
34964 + break;
34965 + case UE_BULK:
34966 + hc->ep_type = DWC_OTG_EP_TYPE_BULK;
34967 + break;
34968 + case UE_INTERRUPT:
34969 + hc->ep_type = DWC_OTG_EP_TYPE_INTR;
34970 + break;
34971 + case UE_ISOCHRONOUS:
34972 + {
34973 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
34974 +
34975 + hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
34976 +
34977 + if (hcd->core_if->dma_desc_enable)
34978 + break;
34979 +
34980 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
34981 +
34982 + frame_desc->status = 0;
34983 +
34984 + if (hcd->core_if->dma_enable) {
34985 + hc->xfer_buff = (uint8_t *) urb->dma;
34986 + } else {
34987 + hc->xfer_buff = (uint8_t *) urb->buf;
34988 + }
34989 + hc->xfer_buff +=
34990 + frame_desc->offset + qtd->isoc_split_offset;
34991 + hc->xfer_len =
34992 + frame_desc->length - qtd->isoc_split_offset;
34993 +
34994 + /* For non-dword aligned buffers */
34995 + if (((unsigned long)hc->xfer_buff & 0x3)
34996 + && hcd->core_if->dma_enable) {
34997 + ptr =
34998 + (uint8_t *) urb->buf + frame_desc->offset +
34999 + qtd->isoc_split_offset;
35000 + } else
35001 + ptr = NULL;
35002 +
35003 + if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
35004 + if (hc->xfer_len <= 188) {
35005 + hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
35006 + } else {
35007 + hc->xact_pos =
35008 + DWC_HCSPLIT_XACTPOS_BEGIN;
35009 + }
35010 + }
35011 + }
35012 + break;
35013 + }
35014 + /* non DWORD-aligned buffer case */
35015 + if (ptr) {
35016 + uint32_t buf_size;
35017 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
35018 + buf_size = hcd->core_if->core_params->max_transfer_size;
35019 + } else {
35020 + buf_size = 4096;
35021 + }
35022 + if (!qh->dw_align_buf) {
35023 + qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(buf_size,
35024 + &qh->dw_align_buf_dma);
35025 + if (!qh->dw_align_buf) {
35026 + DWC_ERROR
35027 + ("%s: Failed to allocate memory to handle "
35028 + "non-dword aligned buffer case\n",
35029 + __func__);
35030 + return;
35031 + }
35032 + }
35033 + if (!hc->ep_is_in) {
35034 + dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
35035 + }
35036 + hc->align_buff = qh->dw_align_buf_dma;
35037 + } else {
35038 + hc->align_buff = 0;
35039 + }
35040 +
35041 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
35042 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
35043 + /*
35044 + * This value may be modified when the transfer is started to
35045 + * reflect the actual transfer length.
35046 + */
35047 + hc->multi_count = dwc_hb_mult(qh->maxp);
35048 + }
35049 +
35050 + if (hcd->core_if->dma_desc_enable)
35051 + hc->desc_list_addr = qh->desc_list_dma;
35052 +
35053 + dwc_otg_hc_init(hcd->core_if, hc);
35054 + hc->qh = qh;
35055 +}
35056 +
35057 +/**
35058 + * This function selects transactions from the HCD transfer schedule and
35059 + * assigns them to available host channels. It is called from HCD interrupt
35060 + * handler functions.
35061 + *
35062 + * @param hcd The HCD state structure.
35063 + *
35064 + * @return The types of new transactions that were assigned to host channels.
35065 + */
35066 +dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
35067 +{
35068 + dwc_list_link_t *qh_ptr;
35069 + dwc_otg_qh_t *qh;
35070 + int num_channels;
35071 + dwc_irqflags_t flags;
35072 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
35073 + dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
35074 +
35075 +#ifdef DEBUG_SOF
35076 + DWC_DEBUGPL(DBG_HCD, " Select Transactions\n");
35077 +#endif
35078 +
35079 +#ifdef DEBUG_HOST_CHANNELS
35080 + last_sel_trans_num_per_scheduled = 0;
35081 + last_sel_trans_num_nonper_scheduled = 0;
35082 + last_sel_trans_num_avail_hc_at_start = hcd->available_host_channels;
35083 +#endif /* DEBUG_HOST_CHANNELS */
35084 +
35085 + /* Process entries in the periodic ready list. */
35086 + qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
35087 +
35088 + while (qh_ptr != &hcd->periodic_sched_ready &&
35089 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
35090 + if (microframe_schedule) {
35091 + // Make sure we leave one channel for non periodic transactions.
35092 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35093 + if (hcd->available_host_channels <= 1) {
35094 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35095 + break;
35096 + }
35097 + hcd->available_host_channels--;
35098 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35099 +#ifdef DEBUG_HOST_CHANNELS
35100 + last_sel_trans_num_per_scheduled++;
35101 +#endif /* DEBUG_HOST_CHANNELS */
35102 + }
35103 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35104 + assign_and_init_hc(hcd, qh);
35105 +
35106 + /*
35107 + * Move the QH from the periodic ready schedule to the
35108 + * periodic assigned schedule.
35109 + */
35110 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
35111 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35112 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
35113 + &qh->qh_list_entry);
35114 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35115 +
35116 + ret_val = DWC_OTG_TRANSACTION_PERIODIC;
35117 + }
35118 +
35119 + /*
35120 + * Process entries in the inactive portion of the non-periodic
35121 + * schedule. Some free host channels may not be used if they are
35122 + * reserved for periodic transfers.
35123 + */
35124 + qh_ptr = hcd->non_periodic_sched_inactive.next;
35125 + num_channels = hcd->core_if->core_params->host_channels;
35126 + while (qh_ptr != &hcd->non_periodic_sched_inactive &&
35127 + (microframe_schedule || hcd->non_periodic_channels <
35128 + num_channels - hcd->periodic_channels) &&
35129 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
35130 +
35131 + if (microframe_schedule) {
35132 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35133 + if (hcd->available_host_channels < 1) {
35134 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35135 + break;
35136 + }
35137 + hcd->available_host_channels--;
35138 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35139 +#ifdef DEBUG_HOST_CHANNELS
35140 + last_sel_trans_num_nonper_scheduled++;
35141 +#endif /* DEBUG_HOST_CHANNELS */
35142 + }
35143 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35144 +
35145 + assign_and_init_hc(hcd, qh);
35146 +
35147 + /*
35148 + * Move the QH from the non-periodic inactive schedule to the
35149 + * non-periodic active schedule.
35150 + */
35151 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
35152 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35153 + DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
35154 + &qh->qh_list_entry);
35155 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35156 +
35157 + if (ret_val == DWC_OTG_TRANSACTION_NONE) {
35158 + ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
35159 + } else {
35160 + ret_val = DWC_OTG_TRANSACTION_ALL;
35161 + }
35162 +
35163 + if (!microframe_schedule)
35164 + hcd->non_periodic_channels++;
35165 + }
35166 +
35167 +#ifdef DEBUG_HOST_CHANNELS
35168 + last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels;
35169 +#endif /* DEBUG_HOST_CHANNELS */
35170 +
35171 + DWC_SPINLOCK_FREE(channel_lock);
35172 + return ret_val;
35173 +}
35174 +
35175 +/**
35176 + * Attempts to queue a single transaction request for a host channel
35177 + * associated with either a periodic or non-periodic transfer. This function
35178 + * assumes that there is space available in the appropriate request queue. For
35179 + * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
35180 + * is available in the appropriate Tx FIFO.
35181 + *
35182 + * @param hcd The HCD state structure.
35183 + * @param hc Host channel descriptor associated with either a periodic or
35184 + * non-periodic transfer.
35185 + * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx
35186 + * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
35187 + * transfers.
35188 + *
35189 + * @return 1 if a request is queued and more requests may be needed to
35190 + * complete the transfer, 0 if no more requests are required for this
35191 + * transfer, -1 if there is insufficient space in the Tx FIFO.
35192 + */
35193 +static int queue_transaction(dwc_otg_hcd_t * hcd,
35194 + dwc_hc_t * hc, uint16_t fifo_dwords_avail)
35195 +{
35196 + int retval;
35197 +
35198 + if (hcd->core_if->dma_enable) {
35199 + if (hcd->core_if->dma_desc_enable) {
35200 + if (!hc->xfer_started
35201 + || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
35202 + dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
35203 + hc->qh->ping_state = 0;
35204 + }
35205 + } else if (!hc->xfer_started) {
35206 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35207 + hc->qh->ping_state = 0;
35208 + }
35209 + retval = 0;
35210 + } else if (hc->halt_pending) {
35211 + /* Don't queue a request if the channel has been halted. */
35212 + retval = 0;
35213 + } else if (hc->halt_on_queue) {
35214 + dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
35215 + retval = 0;
35216 + } else if (hc->do_ping) {
35217 + if (!hc->xfer_started) {
35218 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35219 + }
35220 + retval = 0;
35221 + } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
35222 + if ((fifo_dwords_avail * 4) >= hc->max_packet) {
35223 + if (!hc->xfer_started) {
35224 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35225 + retval = 1;
35226 + } else {
35227 + retval =
35228 + dwc_otg_hc_continue_transfer(hcd->core_if,
35229 + hc);
35230 + }
35231 + } else {
35232 + retval = -1;
35233 + }
35234 + } else {
35235 + if (!hc->xfer_started) {
35236 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35237 + retval = 1;
35238 + } else {
35239 + retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
35240 + }
35241 + }
35242 +
35243 + return retval;
35244 +}
35245 +
35246 +/**
35247 + * Processes periodic channels for the next frame and queues transactions for
35248 + * these channels to the DWC_otg controller. After queueing transactions, the
35249 + * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
35250 + * to queue as Periodic Tx FIFO or request queue space becomes available.
35251 + * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
35252 + */
35253 +static void process_periodic_channels(dwc_otg_hcd_t * hcd)
35254 +{
35255 + hptxsts_data_t tx_status;
35256 + dwc_list_link_t *qh_ptr;
35257 + dwc_otg_qh_t *qh;
35258 + int status;
35259 + int no_queue_space = 0;
35260 + int no_fifo_space = 0;
35261 +
35262 + dwc_otg_host_global_regs_t *host_regs;
35263 + host_regs = hcd->core_if->host_if->host_global_regs;
35264 +
35265 + DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
35266 +#ifdef DEBUG
35267 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35268 + DWC_DEBUGPL(DBG_HCDV,
35269 + " P Tx Req Queue Space Avail (before queue): %d\n",
35270 + tx_status.b.ptxqspcavail);
35271 + DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n",
35272 + tx_status.b.ptxfspcavail);
35273 +#endif
35274 +
35275 + qh_ptr = hcd->periodic_sched_assigned.next;
35276 + while (qh_ptr != &hcd->periodic_sched_assigned) {
35277 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35278 + if (tx_status.b.ptxqspcavail == 0) {
35279 + no_queue_space = 1;
35280 + break;
35281 + }
35282 +
35283 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35284 +
35285 + /*
35286 + * Set a flag if we're queuing high-bandwidth in slave mode.
35287 + * The flag prevents any halts to get into the request queue in
35288 + * the middle of multiple high-bandwidth packets getting queued.
35289 + */
35290 + if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
35291 + hcd->core_if->queuing_high_bandwidth = 1;
35292 + }
35293 + status =
35294 + queue_transaction(hcd, qh->channel,
35295 + tx_status.b.ptxfspcavail);
35296 + if (status < 0) {
35297 + no_fifo_space = 1;
35298 + break;
35299 + }
35300 +
35301 + /*
35302 + * In Slave mode, stay on the current transfer until there is
35303 + * nothing more to do or the high-bandwidth request count is
35304 + * reached. In DMA mode, only need to queue one request. The
35305 + * controller automatically handles multiple packets for
35306 + * high-bandwidth transfers.
35307 + */
35308 + if (hcd->core_if->dma_enable || status == 0 ||
35309 + qh->channel->requests == qh->channel->multi_count) {
35310 + qh_ptr = qh_ptr->next;
35311 + /*
35312 + * Move the QH from the periodic assigned schedule to
35313 + * the periodic queued schedule.
35314 + */
35315 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
35316 + &qh->qh_list_entry);
35317 +
35318 + /* done queuing high bandwidth */
35319 + hcd->core_if->queuing_high_bandwidth = 0;
35320 + }
35321 + }
35322 +
35323 + if (!hcd->core_if->dma_enable) {
35324 + dwc_otg_core_global_regs_t *global_regs;
35325 + gintmsk_data_t intr_mask = {.d32 = 0 };
35326 +
35327 + global_regs = hcd->core_if->core_global_regs;
35328 + intr_mask.b.ptxfempty = 1;
35329 +#ifdef DEBUG
35330 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35331 + DWC_DEBUGPL(DBG_HCDV,
35332 + " P Tx Req Queue Space Avail (after queue): %d\n",
35333 + tx_status.b.ptxqspcavail);
35334 + DWC_DEBUGPL(DBG_HCDV,
35335 + " P Tx FIFO Space Avail (after queue): %d\n",
35336 + tx_status.b.ptxfspcavail);
35337 +#endif
35338 + if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
35339 + no_queue_space || no_fifo_space) {
35340 + /*
35341 + * May need to queue more transactions as the request
35342 + * queue or Tx FIFO empties. Enable the periodic Tx
35343 + * FIFO empty interrupt. (Always use the half-empty
35344 + * level to ensure that new requests are loaded as
35345 + * soon as possible.)
35346 + */
35347 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
35348 + intr_mask.d32);
35349 + } else {
35350 + /*
35351 + * Disable the Tx FIFO empty interrupt since there are
35352 + * no more transactions that need to be queued right
35353 + * now. This function is called from interrupt
35354 + * handlers to queue more transactions as transfer
35355 + * states change.
35356 + */
35357 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
35358 + 0);
35359 + }
35360 + }
35361 +}
35362 +
35363 +/**
35364 + * Processes active non-periodic channels and queues transactions for these
35365 + * channels to the DWC_otg controller. After queueing transactions, the NP Tx
35366 + * FIFO Empty interrupt is enabled if there are more transactions to queue as
35367 + * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
35368 + * FIFO Empty interrupt is disabled.
35369 + */
35370 +static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
35371 +{
35372 + gnptxsts_data_t tx_status;
35373 + dwc_list_link_t *orig_qh_ptr;
35374 + dwc_otg_qh_t *qh;
35375 + int status;
35376 + int no_queue_space = 0;
35377 + int no_fifo_space = 0;
35378 + int more_to_do = 0;
35379 +
35380 + dwc_otg_core_global_regs_t *global_regs =
35381 + hcd->core_if->core_global_regs;
35382 +
35383 + DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
35384 +#ifdef DEBUG
35385 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35386 + DWC_DEBUGPL(DBG_HCDV,
35387 + " NP Tx Req Queue Space Avail (before queue): %d\n",
35388 + tx_status.b.nptxqspcavail);
35389 + DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n",
35390 + tx_status.b.nptxfspcavail);
35391 +#endif
35392 + /*
35393 + * Keep track of the starting point. Skip over the start-of-list
35394 + * entry.
35395 + */
35396 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
35397 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
35398 + }
35399 + orig_qh_ptr = hcd->non_periodic_qh_ptr;
35400 +
35401 + /*
35402 + * Process once through the active list or until no more space is
35403 + * available in the request queue or the Tx FIFO.
35404 + */
35405 + do {
35406 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35407 + if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
35408 + no_queue_space = 1;
35409 + break;
35410 + }
35411 +
35412 + qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
35413 + qh_list_entry);
35414 + status =
35415 + queue_transaction(hcd, qh->channel,
35416 + tx_status.b.nptxfspcavail);
35417 +
35418 + if (status > 0) {
35419 + more_to_do = 1;
35420 + } else if (status < 0) {
35421 + no_fifo_space = 1;
35422 + break;
35423 + }
35424 +
35425 + /* Advance to next QH, skipping start-of-list entry. */
35426 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
35427 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
35428 + hcd->non_periodic_qh_ptr =
35429 + hcd->non_periodic_qh_ptr->next;
35430 + }
35431 +
35432 + } while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
35433 +
35434 + if (!hcd->core_if->dma_enable) {
35435 + gintmsk_data_t intr_mask = {.d32 = 0 };
35436 + intr_mask.b.nptxfempty = 1;
35437 +
35438 +#ifdef DEBUG
35439 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35440 + DWC_DEBUGPL(DBG_HCDV,
35441 + " NP Tx Req Queue Space Avail (after queue): %d\n",
35442 + tx_status.b.nptxqspcavail);
35443 + DWC_DEBUGPL(DBG_HCDV,
35444 + " NP Tx FIFO Space Avail (after queue): %d\n",
35445 + tx_status.b.nptxfspcavail);
35446 +#endif
35447 + if (more_to_do || no_queue_space || no_fifo_space) {
35448 + /*
35449 + * May need to queue more transactions as the request
35450 + * queue or Tx FIFO empties. Enable the non-periodic
35451 + * Tx FIFO empty interrupt. (Always use the half-empty
35452 + * level to ensure that new requests are loaded as
35453 + * soon as possible.)
35454 + */
35455 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
35456 + intr_mask.d32);
35457 + } else {
35458 + /*
35459 + * Disable the Tx FIFO empty interrupt since there are
35460 + * no more transactions that need to be queued right
35461 + * now. This function is called from interrupt
35462 + * handlers to queue more transactions as transfer
35463 + * states change.
35464 + */
35465 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
35466 + 0);
35467 + }
35468 + }
35469 +}
35470 +
35471 +/**
35472 + * This function processes the currently active host channels and queues
35473 + * transactions for these channels to the DWC_otg controller. It is called
35474 + * from HCD interrupt handler functions.
35475 + *
35476 + * @param hcd The HCD state structure.
35477 + * @param tr_type The type(s) of transactions to queue (non-periodic,
35478 + * periodic, or both).
35479 + */
35480 +void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
35481 + dwc_otg_transaction_type_e tr_type)
35482 +{
35483 +#ifdef DEBUG_SOF
35484 + DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
35485 +#endif
35486 + /* Process host channels associated with periodic transfers. */
35487 + if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
35488 + tr_type == DWC_OTG_TRANSACTION_ALL) &&
35489 + !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
35490 +
35491 + process_periodic_channels(hcd);
35492 + }
35493 +
35494 + /* Process host channels associated with non-periodic transfers. */
35495 + if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
35496 + tr_type == DWC_OTG_TRANSACTION_ALL) {
35497 + if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
35498 + process_non_periodic_channels(hcd);
35499 + } else {
35500 + /*
35501 + * Ensure NP Tx FIFO empty interrupt is disabled when
35502 + * there are no non-periodic transfers to process.
35503 + */
35504 + gintmsk_data_t gintmsk = {.d32 = 0 };
35505 + gintmsk.b.nptxfempty = 1;
35506 + DWC_MODIFY_REG32(&hcd->core_if->
35507 + core_global_regs->gintmsk, gintmsk.d32,
35508 + 0);
35509 + }
35510 + }
35511 +}
35512 +
35513 +#ifdef DWC_HS_ELECT_TST
35514 +/*
35515 + * Quick and dirty hack to implement the HS Electrical Test
35516 + * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
35517 + *
35518 + * This code was copied from our userspace app "hset". It sends a
35519 + * Get Device Descriptor control sequence in two parts, first the
35520 + * Setup packet by itself, followed some time later by the In and
35521 + * Ack packets. Rather than trying to figure out how to add this
35522 + * functionality to the normal driver code, we just hijack the
35523 + * hardware, using these two function to drive the hardware
35524 + * directly.
35525 + */
35526 +
35527 +static dwc_otg_core_global_regs_t *global_regs;
35528 +static dwc_otg_host_global_regs_t *hc_global_regs;
35529 +static dwc_otg_hc_regs_t *hc_regs;
35530 +static uint32_t *data_fifo;
35531 +
35532 +static void do_setup(void)
35533 +{
35534 + gintsts_data_t gintsts;
35535 + hctsiz_data_t hctsiz;
35536 + hcchar_data_t hcchar;
35537 + haint_data_t haint;
35538 + hcint_data_t hcint;
35539 +
35540 + /* Enable HAINTs */
35541 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
35542 +
35543 + /* Enable HCINTs */
35544 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
35545 +
35546 + /* Read GINTSTS */
35547 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35548 +
35549 + /* Read HAINT */
35550 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35551 +
35552 + /* Read HCINT */
35553 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35554 +
35555 + /* Read HCCHAR */
35556 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35557 +
35558 + /* Clear HCINT */
35559 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35560 +
35561 + /* Clear HAINT */
35562 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35563 +
35564 + /* Clear GINTSTS */
35565 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35566 +
35567 + /* Read GINTSTS */
35568 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35569 +
35570 + /*
35571 + * Send Setup packet (Get Device Descriptor)
35572 + */
35573 +
35574 + /* Make sure channel is disabled */
35575 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35576 + if (hcchar.b.chen) {
35577 + hcchar.b.chdis = 1;
35578 +// hcchar.b.chen = 1;
35579 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35580 + //sleep(1);
35581 + dwc_mdelay(1000);
35582 +
35583 + /* Read GINTSTS */
35584 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35585 +
35586 + /* Read HAINT */
35587 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35588 +
35589 + /* Read HCINT */
35590 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35591 +
35592 + /* Read HCCHAR */
35593 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35594 +
35595 + /* Clear HCINT */
35596 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35597 +
35598 + /* Clear HAINT */
35599 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35600 +
35601 + /* Clear GINTSTS */
35602 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35603 +
35604 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35605 + }
35606 +
35607 + /* Set HCTSIZ */
35608 + hctsiz.d32 = 0;
35609 + hctsiz.b.xfersize = 8;
35610 + hctsiz.b.pktcnt = 1;
35611 + hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
35612 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35613 +
35614 + /* Set HCCHAR */
35615 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35616 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35617 + hcchar.b.epdir = 0;
35618 + hcchar.b.epnum = 0;
35619 + hcchar.b.mps = 8;
35620 + hcchar.b.chen = 1;
35621 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35622 +
35623 + /* Fill FIFO with Setup data for Get Device Descriptor */
35624 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
35625 + DWC_WRITE_REG32(data_fifo++, 0x01000680);
35626 + DWC_WRITE_REG32(data_fifo++, 0x00080000);
35627 +
35628 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35629 +
35630 + /* Wait for host channel interrupt */
35631 + do {
35632 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35633 + } while (gintsts.b.hcintr == 0);
35634 +
35635 + /* Disable HCINTs */
35636 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
35637 +
35638 + /* Disable HAINTs */
35639 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
35640 +
35641 + /* Read HAINT */
35642 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35643 +
35644 + /* Read HCINT */
35645 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35646 +
35647 + /* Read HCCHAR */
35648 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35649 +
35650 + /* Clear HCINT */
35651 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35652 +
35653 + /* Clear HAINT */
35654 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35655 +
35656 + /* Clear GINTSTS */
35657 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35658 +
35659 + /* Read GINTSTS */
35660 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35661 +}
35662 +
35663 +static void do_in_ack(void)
35664 +{
35665 + gintsts_data_t gintsts;
35666 + hctsiz_data_t hctsiz;
35667 + hcchar_data_t hcchar;
35668 + haint_data_t haint;
35669 + hcint_data_t hcint;
35670 + host_grxsts_data_t grxsts;
35671 +
35672 + /* Enable HAINTs */
35673 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
35674 +
35675 + /* Enable HCINTs */
35676 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
35677 +
35678 + /* Read GINTSTS */
35679 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35680 +
35681 + /* Read HAINT */
35682 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35683 +
35684 + /* Read HCINT */
35685 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35686 +
35687 + /* Read HCCHAR */
35688 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35689 +
35690 + /* Clear HCINT */
35691 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35692 +
35693 + /* Clear HAINT */
35694 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35695 +
35696 + /* Clear GINTSTS */
35697 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35698 +
35699 + /* Read GINTSTS */
35700 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35701 +
35702 + /*
35703 + * Receive Control In packet
35704 + */
35705 +
35706 + /* Make sure channel is disabled */
35707 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35708 + if (hcchar.b.chen) {
35709 + hcchar.b.chdis = 1;
35710 + hcchar.b.chen = 1;
35711 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35712 + //sleep(1);
35713 + dwc_mdelay(1000);
35714 +
35715 + /* Read GINTSTS */
35716 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35717 +
35718 + /* Read HAINT */
35719 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35720 +
35721 + /* Read HCINT */
35722 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35723 +
35724 + /* Read HCCHAR */
35725 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35726 +
35727 + /* Clear HCINT */
35728 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35729 +
35730 + /* Clear HAINT */
35731 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35732 +
35733 + /* Clear GINTSTS */
35734 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35735 +
35736 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35737 + }
35738 +
35739 + /* Set HCTSIZ */
35740 + hctsiz.d32 = 0;
35741 + hctsiz.b.xfersize = 8;
35742 + hctsiz.b.pktcnt = 1;
35743 + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
35744 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35745 +
35746 + /* Set HCCHAR */
35747 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35748 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35749 + hcchar.b.epdir = 1;
35750 + hcchar.b.epnum = 0;
35751 + hcchar.b.mps = 8;
35752 + hcchar.b.chen = 1;
35753 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35754 +
35755 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35756 +
35757 + /* Wait for receive status queue interrupt */
35758 + do {
35759 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35760 + } while (gintsts.b.rxstsqlvl == 0);
35761 +
35762 + /* Read RXSTS */
35763 + grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
35764 +
35765 + /* Clear RXSTSQLVL in GINTSTS */
35766 + gintsts.d32 = 0;
35767 + gintsts.b.rxstsqlvl = 1;
35768 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35769 +
35770 + switch (grxsts.b.pktsts) {
35771 + case DWC_GRXSTS_PKTSTS_IN:
35772 + /* Read the data into the host buffer */
35773 + if (grxsts.b.bcnt > 0) {
35774 + int i;
35775 + int word_count = (grxsts.b.bcnt + 3) / 4;
35776 +
35777 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
35778 +
35779 + for (i = 0; i < word_count; i++) {
35780 + (void)DWC_READ_REG32(data_fifo++);
35781 + }
35782 + }
35783 + break;
35784 +
35785 + default:
35786 + break;
35787 + }
35788 +
35789 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35790 +
35791 + /* Wait for receive status queue interrupt */
35792 + do {
35793 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35794 + } while (gintsts.b.rxstsqlvl == 0);
35795 +
35796 + /* Read RXSTS */
35797 + grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
35798 +
35799 + /* Clear RXSTSQLVL in GINTSTS */
35800 + gintsts.d32 = 0;
35801 + gintsts.b.rxstsqlvl = 1;
35802 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35803 +
35804 + switch (grxsts.b.pktsts) {
35805 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
35806 + break;
35807 +
35808 + default:
35809 + break;
35810 + }
35811 +
35812 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35813 +
35814 + /* Wait for host channel interrupt */
35815 + do {
35816 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35817 + } while (gintsts.b.hcintr == 0);
35818 +
35819 + /* Read HAINT */
35820 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35821 +
35822 + /* Read HCINT */
35823 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35824 +
35825 + /* Read HCCHAR */
35826 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35827 +
35828 + /* Clear HCINT */
35829 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35830 +
35831 + /* Clear HAINT */
35832 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35833 +
35834 + /* Clear GINTSTS */
35835 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35836 +
35837 + /* Read GINTSTS */
35838 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35839 +
35840 +// usleep(100000);
35841 +// mdelay(100);
35842 + dwc_mdelay(1);
35843 +
35844 + /*
35845 + * Send handshake packet
35846 + */
35847 +
35848 + /* Read HAINT */
35849 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35850 +
35851 + /* Read HCINT */
35852 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35853 +
35854 + /* Read HCCHAR */
35855 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35856 +
35857 + /* Clear HCINT */
35858 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35859 +
35860 + /* Clear HAINT */
35861 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35862 +
35863 + /* Clear GINTSTS */
35864 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35865 +
35866 + /* Read GINTSTS */
35867 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35868 +
35869 + /* Make sure channel is disabled */
35870 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35871 + if (hcchar.b.chen) {
35872 + hcchar.b.chdis = 1;
35873 + hcchar.b.chen = 1;
35874 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35875 + //sleep(1);
35876 + dwc_mdelay(1000);
35877 +
35878 + /* Read GINTSTS */
35879 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35880 +
35881 + /* Read HAINT */
35882 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35883 +
35884 + /* Read HCINT */
35885 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35886 +
35887 + /* Read HCCHAR */
35888 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35889 +
35890 + /* Clear HCINT */
35891 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35892 +
35893 + /* Clear HAINT */
35894 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35895 +
35896 + /* Clear GINTSTS */
35897 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35898 +
35899 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35900 + }
35901 +
35902 + /* Set HCTSIZ */
35903 + hctsiz.d32 = 0;
35904 + hctsiz.b.xfersize = 0;
35905 + hctsiz.b.pktcnt = 1;
35906 + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
35907 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35908 +
35909 + /* Set HCCHAR */
35910 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35911 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35912 + hcchar.b.epdir = 0;
35913 + hcchar.b.epnum = 0;
35914 + hcchar.b.mps = 8;
35915 + hcchar.b.chen = 1;
35916 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35917 +
35918 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35919 +
35920 + /* Wait for host channel interrupt */
35921 + do {
35922 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35923 + } while (gintsts.b.hcintr == 0);
35924 +
35925 + /* Disable HCINTs */
35926 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
35927 +
35928 + /* Disable HAINTs */
35929 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
35930 +
35931 + /* Read HAINT */
35932 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35933 +
35934 + /* Read HCINT */
35935 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35936 +
35937 + /* Read HCCHAR */
35938 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35939 +
35940 + /* Clear HCINT */
35941 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35942 +
35943 + /* Clear HAINT */
35944 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35945 +
35946 + /* Clear GINTSTS */
35947 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35948 +
35949 + /* Read GINTSTS */
35950 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35951 +}
35952 +#endif
35953 +
35954 +/** Handles hub class-specific requests. */
35955 +int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
35956 + uint16_t typeReq,
35957 + uint16_t wValue,
35958 + uint16_t wIndex, uint8_t * buf, uint16_t wLength)
35959 +{
35960 + int retval = 0;
35961 +
35962 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
35963 + usb_hub_descriptor_t *hub_desc;
35964 + hprt0_data_t hprt0 = {.d32 = 0 };
35965 +
35966 + uint32_t port_status;
35967 +
35968 + switch (typeReq) {
35969 + case UCR_CLEAR_HUB_FEATURE:
35970 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35971 + "ClearHubFeature 0x%x\n", wValue);
35972 + switch (wValue) {
35973 + case UHF_C_HUB_LOCAL_POWER:
35974 + case UHF_C_HUB_OVER_CURRENT:
35975 + /* Nothing required here */
35976 + break;
35977 + default:
35978 + retval = -DWC_E_INVALID;
35979 + DWC_ERROR("DWC OTG HCD - "
35980 + "ClearHubFeature request %xh unknown\n",
35981 + wValue);
35982 + }
35983 + break;
35984 + case UCR_CLEAR_PORT_FEATURE:
35985 +#ifdef CONFIG_USB_DWC_OTG_LPM
35986 + if (wValue != UHF_PORT_L1)
35987 +#endif
35988 + if (!wIndex || wIndex > 1)
35989 + goto error;
35990 +
35991 + switch (wValue) {
35992 + case UHF_PORT_ENABLE:
35993 + DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
35994 + "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
35995 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
35996 + hprt0.b.prtena = 1;
35997 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
35998 + break;
35999 + case UHF_PORT_SUSPEND:
36000 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36001 + "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
36002 +
36003 + if (core_if->power_down == 2) {
36004 + dwc_otg_host_hibernation_restore(core_if, 0, 0);
36005 + } else {
36006 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
36007 + dwc_mdelay(5);
36008 +
36009 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36010 + hprt0.b.prtres = 1;
36011 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36012 + hprt0.b.prtsusp = 0;
36013 + /* Clear Resume bit */
36014 + dwc_mdelay(100);
36015 + hprt0.b.prtres = 0;
36016 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36017 + }
36018 + break;
36019 +#ifdef CONFIG_USB_DWC_OTG_LPM
36020 + case UHF_PORT_L1:
36021 + {
36022 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36023 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
36024 +
36025 + lpmcfg.d32 =
36026 + DWC_READ_REG32(&core_if->
36027 + core_global_regs->glpmcfg);
36028 + lpmcfg.b.en_utmi_sleep = 0;
36029 + lpmcfg.b.hird_thres &= (~(1 << 4));
36030 + lpmcfg.b.prt_sleep_sts = 1;
36031 + DWC_WRITE_REG32(&core_if->
36032 + core_global_regs->glpmcfg,
36033 + lpmcfg.d32);
36034 +
36035 + /* Clear Enbl_L1Gating bit. */
36036 + pcgcctl.b.enbl_sleep_gating = 1;
36037 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
36038 + 0);
36039 +
36040 + dwc_mdelay(5);
36041 +
36042 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36043 + hprt0.b.prtres = 1;
36044 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36045 + hprt0.d32);
36046 + /* This bit will be cleared in wakeup interrupt handle */
36047 + break;
36048 + }
36049 +#endif
36050 + case UHF_PORT_POWER:
36051 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36052 + "ClearPortFeature USB_PORT_FEAT_POWER\n");
36053 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36054 + hprt0.b.prtpwr = 0;
36055 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36056 + break;
36057 + case UHF_PORT_INDICATOR:
36058 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36059 + "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
36060 + /* Port inidicator not supported */
36061 + break;
36062 + case UHF_C_PORT_CONNECTION:
36063 + /* Clears drivers internal connect status change
36064 + * flag */
36065 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36066 + "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
36067 + dwc_otg_hcd->flags.b.port_connect_status_change = 0;
36068 + break;
36069 + case UHF_C_PORT_RESET:
36070 + /* Clears the driver's internal Port Reset Change
36071 + * flag */
36072 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36073 + "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
36074 + dwc_otg_hcd->flags.b.port_reset_change = 0;
36075 + break;
36076 + case UHF_C_PORT_ENABLE:
36077 + /* Clears the driver's internal Port
36078 + * Enable/Disable Change flag */
36079 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36080 + "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
36081 + dwc_otg_hcd->flags.b.port_enable_change = 0;
36082 + break;
36083 + case UHF_C_PORT_SUSPEND:
36084 + /* Clears the driver's internal Port Suspend
36085 + * Change flag, which is set when resume signaling on
36086 + * the host port is complete */
36087 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36088 + "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
36089 + dwc_otg_hcd->flags.b.port_suspend_change = 0;
36090 + break;
36091 +#ifdef CONFIG_USB_DWC_OTG_LPM
36092 + case UHF_C_PORT_L1:
36093 + dwc_otg_hcd->flags.b.port_l1_change = 0;
36094 + break;
36095 +#endif
36096 + case UHF_C_PORT_OVER_CURRENT:
36097 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36098 + "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
36099 + dwc_otg_hcd->flags.b.port_over_current_change = 0;
36100 + break;
36101 + default:
36102 + retval = -DWC_E_INVALID;
36103 + DWC_ERROR("DWC OTG HCD - "
36104 + "ClearPortFeature request %xh "
36105 + "unknown or unsupported\n", wValue);
36106 + }
36107 + break;
36108 + case UCR_GET_HUB_DESCRIPTOR:
36109 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36110 + "GetHubDescriptor\n");
36111 + hub_desc = (usb_hub_descriptor_t *) buf;
36112 + hub_desc->bDescLength = 9;
36113 + hub_desc->bDescriptorType = 0x29;
36114 + hub_desc->bNbrPorts = 1;
36115 + USETW(hub_desc->wHubCharacteristics, 0x08);
36116 + hub_desc->bPwrOn2PwrGood = 1;
36117 + hub_desc->bHubContrCurrent = 0;
36118 + hub_desc->DeviceRemovable[0] = 0;
36119 + hub_desc->DeviceRemovable[1] = 0xff;
36120 + break;
36121 + case UCR_GET_HUB_STATUS:
36122 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36123 + "GetHubStatus\n");
36124 + DWC_MEMSET(buf, 0, 4);
36125 + break;
36126 + case UCR_GET_PORT_STATUS:
36127 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36128 + "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n",
36129 + wIndex, dwc_otg_hcd->flags.d32);
36130 + if (!wIndex || wIndex > 1)
36131 + goto error;
36132 +
36133 + port_status = 0;
36134 +
36135 + if (dwc_otg_hcd->flags.b.port_connect_status_change)
36136 + port_status |= (1 << UHF_C_PORT_CONNECTION);
36137 +
36138 + if (dwc_otg_hcd->flags.b.port_enable_change)
36139 + port_status |= (1 << UHF_C_PORT_ENABLE);
36140 +
36141 + if (dwc_otg_hcd->flags.b.port_suspend_change)
36142 + port_status |= (1 << UHF_C_PORT_SUSPEND);
36143 +
36144 + if (dwc_otg_hcd->flags.b.port_l1_change)
36145 + port_status |= (1 << UHF_C_PORT_L1);
36146 +
36147 + if (dwc_otg_hcd->flags.b.port_reset_change) {
36148 + port_status |= (1 << UHF_C_PORT_RESET);
36149 + }
36150 +
36151 + if (dwc_otg_hcd->flags.b.port_over_current_change) {
36152 + DWC_WARN("Overcurrent change detected\n");
36153 + port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
36154 + }
36155 +
36156 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
36157 + /*
36158 + * The port is disconnected, which means the core is
36159 + * either in device mode or it soon will be. Just
36160 + * return 0's for the remainder of the port status
36161 + * since the port register can't be read if the core
36162 + * is in device mode.
36163 + */
36164 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
36165 + break;
36166 + }
36167 +
36168 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
36169 + DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32);
36170 +
36171 + if (hprt0.b.prtconnsts)
36172 + port_status |= (1 << UHF_PORT_CONNECTION);
36173 +
36174 + if (hprt0.b.prtena)
36175 + port_status |= (1 << UHF_PORT_ENABLE);
36176 +
36177 + if (hprt0.b.prtsusp)
36178 + port_status |= (1 << UHF_PORT_SUSPEND);
36179 +
36180 + if (hprt0.b.prtovrcurract)
36181 + port_status |= (1 << UHF_PORT_OVER_CURRENT);
36182 +
36183 + if (hprt0.b.prtrst)
36184 + port_status |= (1 << UHF_PORT_RESET);
36185 +
36186 + if (hprt0.b.prtpwr)
36187 + port_status |= (1 << UHF_PORT_POWER);
36188 +
36189 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
36190 + port_status |= (1 << UHF_PORT_HIGH_SPEED);
36191 + else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
36192 + port_status |= (1 << UHF_PORT_LOW_SPEED);
36193 +
36194 + if (hprt0.b.prttstctl)
36195 + port_status |= (1 << UHF_PORT_TEST);
36196 + if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
36197 + port_status |= (1 << UHF_PORT_L1);
36198 + }
36199 + /*
36200 + For Synopsys HW emulation of Power down wkup_control asserts the
36201 + hreset_n and prst_n on suspned. This causes the HPRT0 to be zero.
36202 + We intentionally tell the software that port is in L2Suspend state.
36203 + Only for STE.
36204 + */
36205 + if ((core_if->power_down == 2)
36206 + && (core_if->hibernation_suspend == 1)) {
36207 + port_status |= (1 << UHF_PORT_SUSPEND);
36208 + }
36209 + /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
36210 +
36211 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
36212 +
36213 + break;
36214 + case UCR_SET_HUB_FEATURE:
36215 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36216 + "SetHubFeature\n");
36217 + /* No HUB features supported */
36218 + break;
36219 + case UCR_SET_PORT_FEATURE:
36220 + if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
36221 + goto error;
36222 +
36223 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
36224 + /*
36225 + * The port is disconnected, which means the core is
36226 + * either in device mode or it soon will be. Just
36227 + * return without doing anything since the port
36228 + * register can't be written if the core is in device
36229 + * mode.
36230 + */
36231 + break;
36232 + }
36233 +
36234 + switch (wValue) {
36235 + case UHF_PORT_SUSPEND:
36236 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36237 + "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
36238 + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) {
36239 + goto error;
36240 + }
36241 + if (core_if->power_down == 2) {
36242 + int timeout = 300;
36243 + dwc_irqflags_t flags;
36244 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36245 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
36246 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
36247 +#ifdef DWC_DEV_SRPCAP
36248 + int32_t otg_cap_param = core_if->core_params->otg_cap;
36249 +#endif
36250 + DWC_PRINTF("Preparing for complete power-off\n");
36251 +
36252 + /* Save registers before hibernation */
36253 + dwc_otg_save_global_regs(core_if);
36254 + dwc_otg_save_host_regs(core_if);
36255 +
36256 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36257 + hprt0.b.prtsusp = 1;
36258 + hprt0.b.prtena = 0;
36259 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36260 + /* Spin hprt0.b.prtsusp to became 1 */
36261 + do {
36262 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36263 + if (hprt0.b.prtsusp) {
36264 + break;
36265 + }
36266 + dwc_mdelay(1);
36267 + } while (--timeout);
36268 + if (!timeout) {
36269 + DWC_WARN("Suspend wasn't genereted\n");
36270 + }
36271 + dwc_udelay(10);
36272 +
36273 + /*
36274 + * We need to disable interrupts to prevent servicing of any IRQ
36275 + * during going to hibernation
36276 + */
36277 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
36278 + core_if->lx_state = DWC_OTG_L2;
36279 +#ifdef DWC_DEV_SRPCAP
36280 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36281 + hprt0.b.prtpwr = 0;
36282 + hprt0.b.prtena = 0;
36283 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36284 + hprt0.d32);
36285 +#endif
36286 + gusbcfg.d32 =
36287 + DWC_READ_REG32(&core_if->core_global_regs->
36288 + gusbcfg);
36289 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
36290 + /* ULPI interface */
36291 + /* Suspend the Phy Clock */
36292 + pcgcctl.d32 = 0;
36293 + pcgcctl.b.stoppclk = 1;
36294 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
36295 + pcgcctl.d32);
36296 + dwc_udelay(10);
36297 + gpwrdn.b.pmuactv = 1;
36298 + DWC_MODIFY_REG32(&core_if->
36299 + core_global_regs->
36300 + gpwrdn, 0, gpwrdn.d32);
36301 + } else {
36302 + /* UTMI+ Interface */
36303 + gpwrdn.b.pmuactv = 1;
36304 + DWC_MODIFY_REG32(&core_if->
36305 + core_global_regs->
36306 + gpwrdn, 0, gpwrdn.d32);
36307 + dwc_udelay(10);
36308 + pcgcctl.b.stoppclk = 1;
36309 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
36310 + dwc_udelay(10);
36311 + }
36312 +#ifdef DWC_DEV_SRPCAP
36313 + gpwrdn.d32 = 0;
36314 + gpwrdn.b.dis_vbus = 1;
36315 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36316 + gpwrdn, 0, gpwrdn.d32);
36317 +#endif
36318 + gpwrdn.d32 = 0;
36319 + gpwrdn.b.pmuintsel = 1;
36320 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36321 + gpwrdn, 0, gpwrdn.d32);
36322 + dwc_udelay(10);
36323 +
36324 + gpwrdn.d32 = 0;
36325 +#ifdef DWC_DEV_SRPCAP
36326 + gpwrdn.b.srp_det_msk = 1;
36327 +#endif
36328 + gpwrdn.b.disconn_det_msk = 1;
36329 + gpwrdn.b.lnstchng_msk = 1;
36330 + gpwrdn.b.sts_chngint_msk = 1;
36331 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36332 + gpwrdn, 0, gpwrdn.d32);
36333 + dwc_udelay(10);
36334 +
36335 + /* Enable Power Down Clamp and all interrupts in GPWRDN */
36336 + gpwrdn.d32 = 0;
36337 + gpwrdn.b.pwrdnclmp = 1;
36338 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36339 + gpwrdn, 0, gpwrdn.d32);
36340 + dwc_udelay(10);
36341 +
36342 + /* Switch off VDD */
36343 + gpwrdn.d32 = 0;
36344 + gpwrdn.b.pwrdnswtch = 1;
36345 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36346 + gpwrdn, 0, gpwrdn.d32);
36347 +
36348 +#ifdef DWC_DEV_SRPCAP
36349 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
36350 + {
36351 + core_if->pwron_timer_started = 1;
36352 + DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ );
36353 + }
36354 +#endif
36355 + /* Save gpwrdn register for further usage if stschng interrupt */
36356 + core_if->gr_backup->gpwrdn_local =
36357 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
36358 +
36359 + /* Set flag to indicate that we are in hibernation */
36360 + core_if->hibernation_suspend = 1;
36361 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags);
36362 +
36363 + DWC_PRINTF("Host hibernation completed\n");
36364 + // Exit from case statement
36365 + break;
36366 +
36367 + }
36368 + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
36369 + dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
36370 + gotgctl_data_t gotgctl = {.d32 = 0 };
36371 + gotgctl.b.hstsethnpen = 1;
36372 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36373 + gotgctl, 0, gotgctl.d32);
36374 + core_if->op_state = A_SUSPEND;
36375 + }
36376 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36377 + hprt0.b.prtsusp = 1;
36378 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36379 + {
36380 + dwc_irqflags_t flags;
36381 + /* Update lx_state */
36382 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
36383 + core_if->lx_state = DWC_OTG_L2;
36384 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
36385 + }
36386 + /* Suspend the Phy Clock */
36387 + {
36388 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36389 + pcgcctl.b.stoppclk = 1;
36390 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
36391 + pcgcctl.d32);
36392 + dwc_udelay(10);
36393 + }
36394 +
36395 + /* For HNP the bus must be suspended for at least 200ms. */
36396 + if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
36397 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36398 + pcgcctl.b.stoppclk = 1;
36399 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
36400 + dwc_mdelay(200);
36401 + }
36402 +
36403 + /** @todo - check how sw can wait for 1 sec to check asesvld??? */
36404 +#if 0 //vahrama !!!!!!!!!!!!!!!!!!
36405 + if (core_if->adp_enable) {
36406 + gotgctl_data_t gotgctl = {.d32 = 0 };
36407 + gpwrdn_data_t gpwrdn;
36408 +
36409 + while (gotgctl.b.asesvld == 1) {
36410 + gotgctl.d32 =
36411 + DWC_READ_REG32(&core_if->
36412 + core_global_regs->
36413 + gotgctl);
36414 + dwc_mdelay(100);
36415 + }
36416 +
36417 + /* Enable Power Down Logic */
36418 + gpwrdn.d32 = 0;
36419 + gpwrdn.b.pmuactv = 1;
36420 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36421 + gpwrdn, 0, gpwrdn.d32);
36422 +
36423 + /* Unmask SRP detected interrupt from Power Down Logic */
36424 + gpwrdn.d32 = 0;
36425 + gpwrdn.b.srp_det_msk = 1;
36426 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36427 + gpwrdn, 0, gpwrdn.d32);
36428 +
36429 + dwc_otg_adp_probe_start(core_if);
36430 + }
36431 +#endif
36432 + break;
36433 + case UHF_PORT_POWER:
36434 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36435 + "SetPortFeature - USB_PORT_FEAT_POWER\n");
36436 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36437 + hprt0.b.prtpwr = 1;
36438 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36439 + break;
36440 + case UHF_PORT_RESET:
36441 + if ((core_if->power_down == 2)
36442 + && (core_if->hibernation_suspend == 1)) {
36443 + /* If we are going to exit from Hibernated
36444 + * state via USB RESET.
36445 + */
36446 + dwc_otg_host_hibernation_restore(core_if, 0, 1);
36447 + } else {
36448 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36449 +
36450 + DWC_DEBUGPL(DBG_HCD,
36451 + "DWC OTG HCD HUB CONTROL - "
36452 + "SetPortFeature - USB_PORT_FEAT_RESET\n");
36453 + {
36454 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36455 + pcgcctl.b.enbl_sleep_gating = 1;
36456 + pcgcctl.b.stoppclk = 1;
36457 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
36458 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
36459 + }
36460 +#ifdef CONFIG_USB_DWC_OTG_LPM
36461 + {
36462 + glpmcfg_data_t lpmcfg;
36463 + lpmcfg.d32 =
36464 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36465 + if (lpmcfg.b.prt_sleep_sts) {
36466 + lpmcfg.b.en_utmi_sleep = 0;
36467 + lpmcfg.b.hird_thres &= (~(1 << 4));
36468 + DWC_WRITE_REG32
36469 + (&core_if->core_global_regs->glpmcfg,
36470 + lpmcfg.d32);
36471 + dwc_mdelay(1);
36472 + }
36473 + }
36474 +#endif
36475 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36476 + /* Clear suspend bit if resetting from suspended state. */
36477 + hprt0.b.prtsusp = 0;
36478 + /* When B-Host the Port reset bit is set in
36479 + * the Start HCD Callback function, so that
36480 + * the reset is started within 1ms of the HNP
36481 + * success interrupt. */
36482 + if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
36483 + hprt0.b.prtpwr = 1;
36484 + hprt0.b.prtrst = 1;
36485 + DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32);
36486 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36487 + hprt0.d32);
36488 + }
36489 + /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
36490 + dwc_mdelay(60);
36491 + hprt0.b.prtrst = 0;
36492 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36493 + core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */
36494 + }
36495 + break;
36496 +#ifdef DWC_HS_ELECT_TST
36497 + case UHF_PORT_TEST:
36498 + {
36499 + uint32_t t;
36500 + gintmsk_data_t gintmsk;
36501 +
36502 + t = (wIndex >> 8); /* MSB wIndex USB */
36503 + DWC_DEBUGPL(DBG_HCD,
36504 + "DWC OTG HCD HUB CONTROL - "
36505 + "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
36506 + t);
36507 + DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
36508 + if (t < 6) {
36509 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36510 + hprt0.b.prttstctl = t;
36511 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36512 + hprt0.d32);
36513 + } else {
36514 + /* Setup global vars with reg addresses (quick and
36515 + * dirty hack, should be cleaned up)
36516 + */
36517 + global_regs = core_if->core_global_regs;
36518 + hc_global_regs =
36519 + core_if->host_if->host_global_regs;
36520 + hc_regs =
36521 + (dwc_otg_hc_regs_t *) ((char *)
36522 + global_regs +
36523 + 0x500);
36524 + data_fifo =
36525 + (uint32_t *) ((char *)global_regs +
36526 + 0x1000);
36527 +
36528 + if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */
36529 + /* Save current interrupt mask */
36530 + gintmsk.d32 =
36531 + DWC_READ_REG32
36532 + (&global_regs->gintmsk);
36533 +
36534 + /* Disable all interrupts while we muck with
36535 + * the hardware directly
36536 + */
36537 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36538 +
36539 + /* 15 second delay per the test spec */
36540 + dwc_mdelay(15000);
36541 +
36542 + /* Drive suspend on the root port */
36543 + hprt0.d32 =
36544 + dwc_otg_read_hprt0(core_if);
36545 + hprt0.b.prtsusp = 1;
36546 + hprt0.b.prtres = 0;
36547 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36548 +
36549 + /* 15 second delay per the test spec */
36550 + dwc_mdelay(15000);
36551 +
36552 + /* Drive resume on the root port */
36553 + hprt0.d32 =
36554 + dwc_otg_read_hprt0(core_if);
36555 + hprt0.b.prtsusp = 0;
36556 + hprt0.b.prtres = 1;
36557 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36558 + dwc_mdelay(100);
36559 +
36560 + /* Clear the resume bit */
36561 + hprt0.b.prtres = 0;
36562 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36563 +
36564 + /* Restore interrupts */
36565 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36566 + } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
36567 + /* Save current interrupt mask */
36568 + gintmsk.d32 =
36569 + DWC_READ_REG32
36570 + (&global_regs->gintmsk);
36571 +
36572 + /* Disable all interrupts while we muck with
36573 + * the hardware directly
36574 + */
36575 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36576 +
36577 + /* 15 second delay per the test spec */
36578 + dwc_mdelay(15000);
36579 +
36580 + /* Send the Setup packet */
36581 + do_setup();
36582 +
36583 + /* 15 second delay so nothing else happens for awhile */
36584 + dwc_mdelay(15000);
36585 +
36586 + /* Restore interrupts */
36587 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36588 + } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
36589 + /* Save current interrupt mask */
36590 + gintmsk.d32 =
36591 + DWC_READ_REG32
36592 + (&global_regs->gintmsk);
36593 +
36594 + /* Disable all interrupts while we muck with
36595 + * the hardware directly
36596 + */
36597 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36598 +
36599 + /* Send the Setup packet */
36600 + do_setup();
36601 +
36602 + /* 15 second delay so nothing else happens for awhile */
36603 + dwc_mdelay(15000);
36604 +
36605 + /* Send the In and Ack packets */
36606 + do_in_ack();
36607 +
36608 + /* 15 second delay so nothing else happens for awhile */
36609 + dwc_mdelay(15000);
36610 +
36611 + /* Restore interrupts */
36612 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36613 + }
36614 + }
36615 + break;
36616 + }
36617 +#endif /* DWC_HS_ELECT_TST */
36618 +
36619 + case UHF_PORT_INDICATOR:
36620 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36621 + "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
36622 + /* Not supported */
36623 + break;
36624 + default:
36625 + retval = -DWC_E_INVALID;
36626 + DWC_ERROR("DWC OTG HCD - "
36627 + "SetPortFeature request %xh "
36628 + "unknown or unsupported\n", wValue);
36629 + break;
36630 + }
36631 + break;
36632 +#ifdef CONFIG_USB_DWC_OTG_LPM
36633 + case UCR_SET_AND_TEST_PORT_FEATURE:
36634 + if (wValue != UHF_PORT_L1) {
36635 + goto error;
36636 + }
36637 + {
36638 + int portnum, hird, devaddr, remwake;
36639 + glpmcfg_data_t lpmcfg;
36640 + uint32_t time_usecs;
36641 + gintsts_data_t gintsts;
36642 + gintmsk_data_t gintmsk;
36643 +
36644 + if (!dwc_otg_get_param_lpm_enable(core_if)) {
36645 + goto error;
36646 + }
36647 + if (wValue != UHF_PORT_L1 || wLength != 1) {
36648 + goto error;
36649 + }
36650 + /* Check if the port currently is in SLEEP state */
36651 + lpmcfg.d32 =
36652 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36653 + if (lpmcfg.b.prt_sleep_sts) {
36654 + DWC_INFO("Port is already in sleep mode\n");
36655 + buf[0] = 0; /* Return success */
36656 + break;
36657 + }
36658 +
36659 + portnum = wIndex & 0xf;
36660 + hird = (wIndex >> 4) & 0xf;
36661 + devaddr = (wIndex >> 8) & 0x7f;
36662 + remwake = (wIndex >> 15);
36663 +
36664 + if (portnum != 1) {
36665 + retval = -DWC_E_INVALID;
36666 + DWC_WARN
36667 + ("Wrong port number(%d) in SetandTestPortFeature request\n",
36668 + portnum);
36669 + break;
36670 + }
36671 +
36672 + DWC_PRINTF
36673 + ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
36674 + portnum, hird, devaddr, remwake);
36675 + /* Disable LPM interrupt */
36676 + gintmsk.d32 = 0;
36677 + gintmsk.b.lpmtranrcvd = 1;
36678 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
36679 + gintmsk.d32, 0);
36680 +
36681 + if (dwc_otg_hcd_send_lpm
36682 + (dwc_otg_hcd, devaddr, hird, remwake)) {
36683 + retval = -DWC_E_INVALID;
36684 + break;
36685 + }
36686 +
36687 + time_usecs = 10 * (lpmcfg.b.retry_count + 1);
36688 + /* We will consider timeout if time_usecs microseconds pass,
36689 + * and we don't receive LPM transaction status.
36690 + * After receiving non-error responce(ACK/NYET/STALL) from device,
36691 + * core will set lpmtranrcvd bit.
36692 + */
36693 + do {
36694 + gintsts.d32 =
36695 + DWC_READ_REG32(&core_if->core_global_regs->gintsts);
36696 + if (gintsts.b.lpmtranrcvd) {
36697 + break;
36698 + }
36699 + dwc_udelay(1);
36700 + } while (--time_usecs);
36701 + /* lpm_int bit will be cleared in LPM interrupt handler */
36702 +
36703 + /* Now fill status
36704 + * 0x00 - Success
36705 + * 0x10 - NYET
36706 + * 0x11 - Timeout
36707 + */
36708 + if (!gintsts.b.lpmtranrcvd) {
36709 + buf[0] = 0x3; /* Completion code is Timeout */
36710 + dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
36711 + } else {
36712 + lpmcfg.d32 =
36713 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36714 + if (lpmcfg.b.lpm_resp == 0x3) {
36715 + /* ACK responce from the device */
36716 + buf[0] = 0x00; /* Success */
36717 + } else if (lpmcfg.b.lpm_resp == 0x2) {
36718 + /* NYET responce from the device */
36719 + buf[0] = 0x2;
36720 + } else {
36721 + /* Otherwise responce with Timeout */
36722 + buf[0] = 0x3;
36723 + }
36724 + }
36725 + DWC_PRINTF("Device responce to LPM trans is %x\n",
36726 + lpmcfg.b.lpm_resp);
36727 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0,
36728 + gintmsk.d32);
36729 +
36730 + break;
36731 + }
36732 +#endif /* CONFIG_USB_DWC_OTG_LPM */
36733 + default:
36734 +error:
36735 + retval = -DWC_E_INVALID;
36736 + DWC_WARN("DWC OTG HCD - "
36737 + "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
36738 + typeReq, wIndex, wValue);
36739 + break;
36740 + }
36741 +
36742 + return retval;
36743 +}
36744 +
36745 +#ifdef CONFIG_USB_DWC_OTG_LPM
36746 +/** Returns index of host channel to perform LPM transaction. */
36747 +int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
36748 +{
36749 + dwc_otg_core_if_t *core_if = hcd->core_if;
36750 + dwc_hc_t *hc;
36751 + hcchar_data_t hcchar;
36752 + gintmsk_data_t gintmsk = {.d32 = 0 };
36753 +
36754 + if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
36755 + DWC_PRINTF("No free channel to select for LPM transaction\n");
36756 + return -1;
36757 + }
36758 +
36759 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
36760 +
36761 + /* Mask host channel interrupts. */
36762 + gintmsk.b.hcintr = 1;
36763 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
36764 +
36765 + /* Fill fields that core needs for LPM transaction */
36766 + hcchar.b.devaddr = devaddr;
36767 + hcchar.b.epnum = 0;
36768 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
36769 + hcchar.b.mps = 64;
36770 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
36771 + hcchar.b.epdir = 0; /* OUT */
36772 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
36773 + hcchar.d32);
36774 +
36775 + /* Remove the host channel from the free list. */
36776 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
36777 +
36778 + DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
36779 +
36780 + return hc->hc_num;
36781 +}
36782 +
36783 +/** Release hc after performing LPM transaction */
36784 +void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
36785 +{
36786 + dwc_hc_t *hc;
36787 + glpmcfg_data_t lpmcfg;
36788 + uint8_t hc_num;
36789 +
36790 + lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
36791 + hc_num = lpmcfg.b.lpm_chan_index;
36792 +
36793 + hc = hcd->hc_ptr_array[hc_num];
36794 +
36795 + DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
36796 + /* Return host channel to free list */
36797 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
36798 +}
36799 +
36800 +int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
36801 + uint8_t bRemoteWake)
36802 +{
36803 + glpmcfg_data_t lpmcfg;
36804 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36805 + int channel;
36806 +
36807 + channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
36808 + if (channel < 0) {
36809 + return channel;
36810 + }
36811 +
36812 + pcgcctl.b.enbl_sleep_gating = 1;
36813 + DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
36814 +
36815 + /* Read LPM config register */
36816 + lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
36817 +
36818 + /* Program LPM transaction fields */
36819 + lpmcfg.b.rem_wkup_en = bRemoteWake;
36820 + lpmcfg.b.hird = hird;
36821 + lpmcfg.b.hird_thres = 0x1c;
36822 + lpmcfg.b.lpm_chan_index = channel;
36823 + lpmcfg.b.en_utmi_sleep = 1;
36824 + /* Program LPM config register */
36825 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
36826 +
36827 + /* Send LPM transaction */
36828 + lpmcfg.b.send_lpm = 1;
36829 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
36830 +
36831 + return 0;
36832 +}
36833 +
36834 +#endif /* CONFIG_USB_DWC_OTG_LPM */
36835 +
36836 +int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
36837 +{
36838 + int retval;
36839 +
36840 + if (port != 1) {
36841 + return -DWC_E_INVALID;
36842 + }
36843 +
36844 + retval = (hcd->flags.b.port_connect_status_change ||
36845 + hcd->flags.b.port_reset_change ||
36846 + hcd->flags.b.port_enable_change ||
36847 + hcd->flags.b.port_suspend_change ||
36848 + hcd->flags.b.port_over_current_change);
36849 +#ifdef DEBUG
36850 + if (retval) {
36851 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
36852 + " Root port status changed\n");
36853 + DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n",
36854 + hcd->flags.b.port_connect_status_change);
36855 + DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n",
36856 + hcd->flags.b.port_reset_change);
36857 + DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n",
36858 + hcd->flags.b.port_enable_change);
36859 + DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n",
36860 + hcd->flags.b.port_suspend_change);
36861 + DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n",
36862 + hcd->flags.b.port_over_current_change);
36863 + }
36864 +#endif
36865 + return retval;
36866 +}
36867 +
36868 +int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
36869 +{
36870 + hfnum_data_t hfnum;
36871 + hfnum.d32 =
36872 + DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
36873 + hfnum);
36874 +
36875 +#ifdef DEBUG_SOF
36876 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
36877 + hfnum.b.frnum);
36878 +#endif
36879 + return hfnum.b.frnum;
36880 +}
36881 +
36882 +int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
36883 + struct dwc_otg_hcd_function_ops *fops)
36884 +{
36885 + int retval = 0;
36886 +
36887 + hcd->fops = fops;
36888 + if (!dwc_otg_is_device_mode(hcd->core_if) &&
36889 + (!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) {
36890 + dwc_otg_hcd_reinit(hcd);
36891 + } else {
36892 + retval = -DWC_E_NO_DEVICE;
36893 + }
36894 +
36895 + return retval;
36896 +}
36897 +
36898 +void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
36899 +{
36900 + return hcd->priv;
36901 +}
36902 +
36903 +void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
36904 +{
36905 + hcd->priv = priv_data;
36906 +}
36907 +
36908 +uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
36909 +{
36910 + return hcd->otg_port;
36911 +}
36912 +
36913 +uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
36914 +{
36915 + uint32_t is_b_host;
36916 + if (hcd->core_if->op_state == B_HOST) {
36917 + is_b_host = 1;
36918 + } else {
36919 + is_b_host = 0;
36920 + }
36921 +
36922 + return is_b_host;
36923 +}
36924 +
36925 +dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
36926 + int iso_desc_count, int atomic_alloc)
36927 +{
36928 + dwc_otg_hcd_urb_t *dwc_otg_urb;
36929 + uint32_t size;
36930 +
36931 + size =
36932 + sizeof(*dwc_otg_urb) +
36933 + iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
36934 + if (atomic_alloc)
36935 + dwc_otg_urb = DWC_ALLOC_ATOMIC(size);
36936 + else
36937 + dwc_otg_urb = DWC_ALLOC(size);
36938 +
36939 + if (NULL != dwc_otg_urb)
36940 + dwc_otg_urb->packet_count = iso_desc_count;
36941 + else {
36942 + dwc_otg_urb->packet_count = 0;
36943 + if (size != 0) {
36944 + DWC_ERROR("**** DWC OTG HCD URB alloc - "
36945 + "%salloc of %db failed\n",
36946 + atomic_alloc?"atomic ":"", size);
36947 + }
36948 + }
36949 +
36950 + return dwc_otg_urb;
36951 +}
36952 +
36953 +void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
36954 + uint8_t dev_addr, uint8_t ep_num,
36955 + uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
36956 +{
36957 + dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
36958 + ep_type, ep_dir, mps);
36959 +#if 0
36960 + DWC_PRINTF
36961 + ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
36962 + dev_addr, ep_num, ep_dir, ep_type, mps);
36963 +#endif
36964 +}
36965 +
36966 +void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
36967 + void *urb_handle, void *buf, dwc_dma_t dma,
36968 + uint32_t buflen, void *setup_packet,
36969 + dwc_dma_t setup_dma, uint32_t flags,
36970 + uint16_t interval)
36971 +{
36972 + dwc_otg_urb->priv = urb_handle;
36973 + dwc_otg_urb->buf = buf;
36974 + dwc_otg_urb->dma = dma;
36975 + dwc_otg_urb->length = buflen;
36976 + dwc_otg_urb->setup_packet = setup_packet;
36977 + dwc_otg_urb->setup_dma = setup_dma;
36978 + dwc_otg_urb->flags = flags;
36979 + dwc_otg_urb->interval = interval;
36980 + dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
36981 +}
36982 +
36983 +uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
36984 +{
36985 + return dwc_otg_urb->status;
36986 +}
36987 +
36988 +uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
36989 +{
36990 + return dwc_otg_urb->actual_length;
36991 +}
36992 +
36993 +uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
36994 +{
36995 + return dwc_otg_urb->error_count;
36996 +}
36997 +
36998 +void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
36999 + int desc_num, uint32_t offset,
37000 + uint32_t length)
37001 +{
37002 + dwc_otg_urb->iso_descs[desc_num].offset = offset;
37003 + dwc_otg_urb->iso_descs[desc_num].length = length;
37004 +}
37005 +
37006 +uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
37007 + int desc_num)
37008 +{
37009 + return dwc_otg_urb->iso_descs[desc_num].status;
37010 +}
37011 +
37012 +uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
37013 + dwc_otg_urb, int desc_num)
37014 +{
37015 + return dwc_otg_urb->iso_descs[desc_num].actual_length;
37016 +}
37017 +
37018 +int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
37019 +{
37020 + int allocated = 0;
37021 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
37022 +
37023 + if (qh) {
37024 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
37025 + allocated = 1;
37026 + }
37027 + }
37028 + return allocated;
37029 +}
37030 +
37031 +int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
37032 +{
37033 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
37034 + int freed = 0;
37035 + DWC_ASSERT(qh, "qh is not allocated\n");
37036 +
37037 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
37038 + freed = 1;
37039 + }
37040 +
37041 + return freed;
37042 +}
37043 +
37044 +uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
37045 +{
37046 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
37047 + DWC_ASSERT(qh, "qh is not allocated\n");
37048 + return qh->usecs;
37049 +}
37050 +
37051 +void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
37052 +{
37053 +#ifdef DEBUG
37054 + int num_channels;
37055 + int i;
37056 + gnptxsts_data_t np_tx_status;
37057 + hptxsts_data_t p_tx_status;
37058 +
37059 + num_channels = hcd->core_if->core_params->host_channels;
37060 + DWC_PRINTF("\n");
37061 + DWC_PRINTF
37062 + ("************************************************************\n");
37063 + DWC_PRINTF("HCD State:\n");
37064 + DWC_PRINTF(" Num channels: %d\n", num_channels);
37065 + for (i = 0; i < num_channels; i++) {
37066 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
37067 + DWC_PRINTF(" Channel %d:\n", i);
37068 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
37069 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
37070 + DWC_PRINTF(" speed: %d\n", hc->speed);
37071 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
37072 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
37073 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
37074 + DWC_PRINTF(" multi_count: %d\n", hc->multi_count);
37075 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
37076 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
37077 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
37078 + DWC_PRINTF(" xfer_count: %d\n", hc->xfer_count);
37079 + DWC_PRINTF(" halt_on_queue: %d\n", hc->halt_on_queue);
37080 + DWC_PRINTF(" halt_pending: %d\n", hc->halt_pending);
37081 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
37082 + DWC_PRINTF(" do_split: %d\n", hc->do_split);
37083 + DWC_PRINTF(" complete_split: %d\n", hc->complete_split);
37084 + DWC_PRINTF(" hub_addr: %d\n", hc->hub_addr);
37085 + DWC_PRINTF(" port_addr: %d\n", hc->port_addr);
37086 + DWC_PRINTF(" xact_pos: %d\n", hc->xact_pos);
37087 + DWC_PRINTF(" requests: %d\n", hc->requests);
37088 + DWC_PRINTF(" qh: %p\n", hc->qh);
37089 + if (hc->xfer_started) {
37090 + hfnum_data_t hfnum;
37091 + hcchar_data_t hcchar;
37092 + hctsiz_data_t hctsiz;
37093 + hcint_data_t hcint;
37094 + hcintmsk_data_t hcintmsk;
37095 + hfnum.d32 =
37096 + DWC_READ_REG32(&hcd->core_if->
37097 + host_if->host_global_regs->hfnum);
37098 + hcchar.d32 =
37099 + DWC_READ_REG32(&hcd->core_if->host_if->
37100 + hc_regs[i]->hcchar);
37101 + hctsiz.d32 =
37102 + DWC_READ_REG32(&hcd->core_if->host_if->
37103 + hc_regs[i]->hctsiz);
37104 + hcint.d32 =
37105 + DWC_READ_REG32(&hcd->core_if->host_if->
37106 + hc_regs[i]->hcint);
37107 + hcintmsk.d32 =
37108 + DWC_READ_REG32(&hcd->core_if->host_if->
37109 + hc_regs[i]->hcintmsk);
37110 + DWC_PRINTF(" hfnum: 0x%08x\n", hfnum.d32);
37111 + DWC_PRINTF(" hcchar: 0x%08x\n", hcchar.d32);
37112 + DWC_PRINTF(" hctsiz: 0x%08x\n", hctsiz.d32);
37113 + DWC_PRINTF(" hcint: 0x%08x\n", hcint.d32);
37114 + DWC_PRINTF(" hcintmsk: 0x%08x\n", hcintmsk.d32);
37115 + }
37116 + if (hc->xfer_started && hc->qh) {
37117 + dwc_otg_qtd_t *qtd;
37118 + dwc_otg_hcd_urb_t *urb;
37119 +
37120 + DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
37121 + if (!qtd->in_process)
37122 + break;
37123 +
37124 + urb = qtd->urb;
37125 + DWC_PRINTF(" URB Info:\n");
37126 + DWC_PRINTF(" qtd: %p, urb: %p\n", qtd, urb);
37127 + if (urb) {
37128 + DWC_PRINTF(" Dev: %d, EP: %d %s\n",
37129 + dwc_otg_hcd_get_dev_addr(&urb->
37130 + pipe_info),
37131 + dwc_otg_hcd_get_ep_num(&urb->
37132 + pipe_info),
37133 + dwc_otg_hcd_is_pipe_in(&urb->
37134 + pipe_info) ?
37135 + "IN" : "OUT");
37136 + DWC_PRINTF(" Max packet size: %d\n",
37137 + dwc_otg_hcd_get_mps(&urb->
37138 + pipe_info));
37139 + DWC_PRINTF(" transfer_buffer: %p\n",
37140 + urb->buf);
37141 + DWC_PRINTF(" transfer_dma: %p\n",
37142 + (void *)urb->dma);
37143 + DWC_PRINTF(" transfer_buffer_length: %d\n",
37144 + urb->length);
37145 + DWC_PRINTF(" actual_length: %d\n",
37146 + urb->actual_length);
37147 + }
37148 + }
37149 + }
37150 + }
37151 + DWC_PRINTF(" non_periodic_channels: %d\n", hcd->non_periodic_channels);
37152 + DWC_PRINTF(" periodic_channels: %d\n", hcd->periodic_channels);
37153 + DWC_PRINTF(" periodic_usecs: %d\n", hcd->periodic_usecs);
37154 + np_tx_status.d32 =
37155 + DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts);
37156 + DWC_PRINTF(" NP Tx Req Queue Space Avail: %d\n",
37157 + np_tx_status.b.nptxqspcavail);
37158 + DWC_PRINTF(" NP Tx FIFO Space Avail: %d\n",
37159 + np_tx_status.b.nptxfspcavail);
37160 + p_tx_status.d32 =
37161 + DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts);
37162 + DWC_PRINTF(" P Tx Req Queue Space Avail: %d\n",
37163 + p_tx_status.b.ptxqspcavail);
37164 + DWC_PRINTF(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
37165 + dwc_otg_hcd_dump_frrem(hcd);
37166 + dwc_otg_dump_global_registers(hcd->core_if);
37167 + dwc_otg_dump_host_registers(hcd->core_if);
37168 + DWC_PRINTF
37169 + ("************************************************************\n");
37170 + DWC_PRINTF("\n");
37171 +#endif
37172 +}
37173 +
37174 +#ifdef DEBUG
37175 +void dwc_print_setup_data(uint8_t * setup)
37176 +{
37177 + int i;
37178 + if (CHK_DEBUG_LEVEL(DBG_HCD)) {
37179 + DWC_PRINTF("Setup Data = MSB ");
37180 + for (i = 7; i >= 0; i--)
37181 + DWC_PRINTF("%02x ", setup[i]);
37182 + DWC_PRINTF("\n");
37183 + DWC_PRINTF(" bmRequestType Tranfer = %s\n",
37184 + (setup[0] & 0x80) ? "Device-to-Host" :
37185 + "Host-to-Device");
37186 + DWC_PRINTF(" bmRequestType Type = ");
37187 + switch ((setup[0] & 0x60) >> 5) {
37188 + case 0:
37189 + DWC_PRINTF("Standard\n");
37190 + break;
37191 + case 1:
37192 + DWC_PRINTF("Class\n");
37193 + break;
37194 + case 2:
37195 + DWC_PRINTF("Vendor\n");
37196 + break;
37197 + case 3:
37198 + DWC_PRINTF("Reserved\n");
37199 + break;
37200 + }
37201 + DWC_PRINTF(" bmRequestType Recipient = ");
37202 + switch (setup[0] & 0x1f) {
37203 + case 0:
37204 + DWC_PRINTF("Device\n");
37205 + break;
37206 + case 1:
37207 + DWC_PRINTF("Interface\n");
37208 + break;
37209 + case 2:
37210 + DWC_PRINTF("Endpoint\n");
37211 + break;
37212 + case 3:
37213 + DWC_PRINTF("Other\n");
37214 + break;
37215 + default:
37216 + DWC_PRINTF("Reserved\n");
37217 + break;
37218 + }
37219 + DWC_PRINTF(" bRequest = 0x%0x\n", setup[1]);
37220 + DWC_PRINTF(" wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
37221 + DWC_PRINTF(" wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
37222 + DWC_PRINTF(" wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
37223 + }
37224 +}
37225 +#endif
37226 +
37227 +void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
37228 +{
37229 +#if 0
37230 + DWC_PRINTF("Frame remaining at SOF:\n");
37231 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37232 + hcd->frrem_samples, hcd->frrem_accum,
37233 + (hcd->frrem_samples > 0) ?
37234 + hcd->frrem_accum / hcd->frrem_samples : 0);
37235 +
37236 + DWC_PRINTF("\n");
37237 + DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
37238 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37239 + hcd->core_if->hfnum_7_samples,
37240 + hcd->core_if->hfnum_7_frrem_accum,
37241 + (hcd->core_if->hfnum_7_samples >
37242 + 0) ? hcd->core_if->hfnum_7_frrem_accum /
37243 + hcd->core_if->hfnum_7_samples : 0);
37244 + DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
37245 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37246 + hcd->core_if->hfnum_0_samples,
37247 + hcd->core_if->hfnum_0_frrem_accum,
37248 + (hcd->core_if->hfnum_0_samples >
37249 + 0) ? hcd->core_if->hfnum_0_frrem_accum /
37250 + hcd->core_if->hfnum_0_samples : 0);
37251 + DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
37252 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37253 + hcd->core_if->hfnum_other_samples,
37254 + hcd->core_if->hfnum_other_frrem_accum,
37255 + (hcd->core_if->hfnum_other_samples >
37256 + 0) ? hcd->core_if->hfnum_other_frrem_accum /
37257 + hcd->core_if->hfnum_other_samples : 0);
37258 +
37259 + DWC_PRINTF("\n");
37260 + DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
37261 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37262 + hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
37263 + (hcd->hfnum_7_samples_a > 0) ?
37264 + hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
37265 + DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
37266 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37267 + hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
37268 + (hcd->hfnum_0_samples_a > 0) ?
37269 + hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
37270 + DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
37271 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37272 + hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
37273 + (hcd->hfnum_other_samples_a > 0) ?
37274 + hcd->hfnum_other_frrem_accum_a /
37275 + hcd->hfnum_other_samples_a : 0);
37276 +
37277 + DWC_PRINTF("\n");
37278 + DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
37279 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37280 + hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
37281 + (hcd->hfnum_7_samples_b > 0) ?
37282 + hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
37283 + DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
37284 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37285 + hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
37286 + (hcd->hfnum_0_samples_b > 0) ?
37287 + hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
37288 + DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
37289 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37290 + hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
37291 + (hcd->hfnum_other_samples_b > 0) ?
37292 + hcd->hfnum_other_frrem_accum_b /
37293 + hcd->hfnum_other_samples_b : 0);
37294 +#endif
37295 +}
37296 +
37297 +#endif /* DWC_DEVICE_ONLY */
37298 --- /dev/null
37299 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
37300 @@ -0,0 +1,824 @@
37301 +/* ==========================================================================
37302 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $
37303 + * $Revision: #58 $
37304 + * $Date: 2011/09/15 $
37305 + * $Change: 1846647 $
37306 + *
37307 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
37308 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
37309 + * otherwise expressly agreed to in writing between Synopsys and you.
37310 + *
37311 + * The Software IS NOT an item of Licensed Software or Licensed Product under
37312 + * any End User Software License Agreement or Agreement for Licensed Product
37313 + * with Synopsys or any supplement thereto. You are permitted to use and
37314 + * redistribute this Software in source and binary forms, with or without
37315 + * modification, provided that redistributions of source code must retain this
37316 + * notice. You may not view, use, disclose, copy or distribute this file or
37317 + * any information contained herein except pursuant to this license grant from
37318 + * Synopsys. If you do not agree with this notice, including the disclaimer
37319 + * below, then you are not authorized to use the Software.
37320 + *
37321 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
37322 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37323 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37324 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
37325 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37326 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37327 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37328 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37329 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37330 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
37331 + * DAMAGE.
37332 + * ========================================================================== */
37333 +#ifndef DWC_DEVICE_ONLY
37334 +#ifndef __DWC_HCD_H__
37335 +#define __DWC_HCD_H__
37336 +
37337 +#include "dwc_otg_os_dep.h"
37338 +#include "usb.h"
37339 +#include "dwc_otg_hcd_if.h"
37340 +#include "dwc_otg_core_if.h"
37341 +#include "dwc_list.h"
37342 +#include "dwc_otg_cil.h"
37343 +
37344 +/**
37345 + * @file
37346 + *
37347 + * This file contains the structures, constants, and interfaces for
37348 + * the Host Contoller Driver (HCD).
37349 + *
37350 + * The Host Controller Driver (HCD) is responsible for translating requests
37351 + * from the USB Driver into the appropriate actions on the DWC_otg controller.
37352 + * It isolates the USBD from the specifics of the controller by providing an
37353 + * API to the USBD.
37354 + */
37355 +
37356 +struct dwc_otg_hcd_pipe_info {
37357 + uint8_t dev_addr;
37358 + uint8_t ep_num;
37359 + uint8_t pipe_type;
37360 + uint8_t pipe_dir;
37361 + uint16_t mps;
37362 +};
37363 +
37364 +struct dwc_otg_hcd_iso_packet_desc {
37365 + uint32_t offset;
37366 + uint32_t length;
37367 + uint32_t actual_length;
37368 + uint32_t status;
37369 +};
37370 +
37371 +struct dwc_otg_qtd;
37372 +
37373 +struct dwc_otg_hcd_urb {
37374 + void *priv;
37375 + struct dwc_otg_qtd *qtd;
37376 + void *buf;
37377 + dwc_dma_t dma;
37378 + void *setup_packet;
37379 + dwc_dma_t setup_dma;
37380 + uint32_t length;
37381 + uint32_t actual_length;
37382 + uint32_t status;
37383 + uint32_t error_count;
37384 + uint32_t packet_count;
37385 + uint32_t flags;
37386 + uint16_t interval;
37387 + struct dwc_otg_hcd_pipe_info pipe_info;
37388 + struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
37389 +};
37390 +
37391 +static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
37392 +{
37393 + return pipe->ep_num;
37394 +}
37395 +
37396 +static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info
37397 + *pipe)
37398 +{
37399 + return pipe->pipe_type;
37400 +}
37401 +
37402 +static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe)
37403 +{
37404 + return pipe->mps;
37405 +}
37406 +
37407 +static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info
37408 + *pipe)
37409 +{
37410 + return pipe->dev_addr;
37411 +}
37412 +
37413 +static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info
37414 + *pipe)
37415 +{
37416 + return (pipe->pipe_type == UE_ISOCHRONOUS);
37417 +}
37418 +
37419 +static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info
37420 + *pipe)
37421 +{
37422 + return (pipe->pipe_type == UE_INTERRUPT);
37423 +}
37424 +
37425 +static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info
37426 + *pipe)
37427 +{
37428 + return (pipe->pipe_type == UE_BULK);
37429 +}
37430 +
37431 +static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info
37432 + *pipe)
37433 +{
37434 + return (pipe->pipe_type == UE_CONTROL);
37435 +}
37436 +
37437 +static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe)
37438 +{
37439 + return (pipe->pipe_dir == UE_DIR_IN);
37440 +}
37441 +
37442 +static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info
37443 + *pipe)
37444 +{
37445 + return (!dwc_otg_hcd_is_pipe_in(pipe));
37446 +}
37447 +
37448 +static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe,
37449 + uint8_t devaddr, uint8_t ep_num,
37450 + uint8_t pipe_type, uint8_t pipe_dir,
37451 + uint16_t mps)
37452 +{
37453 + pipe->dev_addr = devaddr;
37454 + pipe->ep_num = ep_num;
37455 + pipe->pipe_type = pipe_type;
37456 + pipe->pipe_dir = pipe_dir;
37457 + pipe->mps = mps;
37458 +}
37459 +
37460 +/**
37461 + * Phases for control transfers.
37462 + */
37463 +typedef enum dwc_otg_control_phase {
37464 + DWC_OTG_CONTROL_SETUP,
37465 + DWC_OTG_CONTROL_DATA,
37466 + DWC_OTG_CONTROL_STATUS
37467 +} dwc_otg_control_phase_e;
37468 +
37469 +/** Transaction types. */
37470 +typedef enum dwc_otg_transaction_type {
37471 + DWC_OTG_TRANSACTION_NONE,
37472 + DWC_OTG_TRANSACTION_PERIODIC,
37473 + DWC_OTG_TRANSACTION_NON_PERIODIC,
37474 + DWC_OTG_TRANSACTION_ALL
37475 +} dwc_otg_transaction_type_e;
37476 +
37477 +struct dwc_otg_qh;
37478 +
37479 +/**
37480 + * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
37481 + * interrupt, or isochronous transfer. A single QTD is created for each URB
37482 + * (of one of these types) submitted to the HCD. The transfer associated with
37483 + * a QTD may require one or multiple transactions.
37484 + *
37485 + * A QTD is linked to a Queue Head, which is entered in either the
37486 + * non-periodic or periodic schedule for execution. When a QTD is chosen for
37487 + * execution, some or all of its transactions may be executed. After
37488 + * execution, the state of the QTD is updated. The QTD may be retired if all
37489 + * its transactions are complete or if an error occurred. Otherwise, it
37490 + * remains in the schedule so more transactions can be executed later.
37491 + */
37492 +typedef struct dwc_otg_qtd {
37493 + /**
37494 + * Determines the PID of the next data packet for the data phase of
37495 + * control transfers. Ignored for other transfer types.<br>
37496 + * One of the following values:
37497 + * - DWC_OTG_HC_PID_DATA0
37498 + * - DWC_OTG_HC_PID_DATA1
37499 + */
37500 + uint8_t data_toggle;
37501 +
37502 + /** Current phase for control transfers (Setup, Data, or Status). */
37503 + dwc_otg_control_phase_e control_phase;
37504 +
37505 + /** Keep track of the current split type
37506 + * for FS/LS endpoints on a HS Hub */
37507 + uint8_t complete_split;
37508 +
37509 + /** How many bytes transferred during SSPLIT OUT */
37510 + uint32_t ssplit_out_xfer_count;
37511 +
37512 + /**
37513 + * Holds the number of bus errors that have occurred for a transaction
37514 + * within this transfer.
37515 + */
37516 + uint8_t error_count;
37517 +
37518 + /**
37519 + * Index of the next frame descriptor for an isochronous transfer. A
37520 + * frame descriptor describes the buffer position and length of the
37521 + * data to be transferred in the next scheduled (micro)frame of an
37522 + * isochronous transfer. It also holds status for that transaction.
37523 + * The frame index starts at 0.
37524 + */
37525 + uint16_t isoc_frame_index;
37526 +
37527 + /** Position of the ISOC split on full/low speed */
37528 + uint8_t isoc_split_pos;
37529 +
37530 + /** Position of the ISOC split in the buffer for the current frame */
37531 + uint16_t isoc_split_offset;
37532 +
37533 + /** URB for this transfer */
37534 + struct dwc_otg_hcd_urb *urb;
37535 +
37536 + struct dwc_otg_qh *qh;
37537 +
37538 + /** This list of QTDs */
37539 + DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry;
37540 +
37541 + /** Indicates if this QTD is currently processed by HW. */
37542 + uint8_t in_process;
37543 +
37544 + /** Number of DMA descriptors for this QTD */
37545 + uint8_t n_desc;
37546 +
37547 + /**
37548 + * Last activated frame(packet) index.
37549 + * Used in Descriptor DMA mode only.
37550 + */
37551 + uint16_t isoc_frame_index_last;
37552 +
37553 +} dwc_otg_qtd_t;
37554 +
37555 +DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd);
37556 +
37557 +/**
37558 + * A Queue Head (QH) holds the static characteristics of an endpoint and
37559 + * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
37560 + * be entered in either the non-periodic or periodic schedule.
37561 + */
37562 +typedef struct dwc_otg_qh {
37563 + /**
37564 + * Endpoint type.
37565 + * One of the following values:
37566 + * - UE_CONTROL
37567 + * - UE_BULK
37568 + * - UE_INTERRUPT
37569 + * - UE_ISOCHRONOUS
37570 + */
37571 + uint8_t ep_type;
37572 + uint8_t ep_is_in;
37573 +
37574 + /** wMaxPacketSize Field of Endpoint Descriptor. */
37575 + uint16_t maxp;
37576 +
37577 + /**
37578 + * Device speed.
37579 + * One of the following values:
37580 + * - DWC_OTG_EP_SPEED_LOW
37581 + * - DWC_OTG_EP_SPEED_FULL
37582 + * - DWC_OTG_EP_SPEED_HIGH
37583 + */
37584 + uint8_t dev_speed;
37585 +
37586 + /**
37587 + * Determines the PID of the next data packet for non-control
37588 + * transfers. Ignored for control transfers.<br>
37589 + * One of the following values:
37590 + * - DWC_OTG_HC_PID_DATA0
37591 + * - DWC_OTG_HC_PID_DATA1
37592 + */
37593 + uint8_t data_toggle;
37594 +
37595 + /** Ping state if 1. */
37596 + uint8_t ping_state;
37597 +
37598 + /**
37599 + * List of QTDs for this QH.
37600 + */
37601 + struct dwc_otg_qtd_list qtd_list;
37602 +
37603 + /** Host channel currently processing transfers for this QH. */
37604 + struct dwc_hc *channel;
37605 +
37606 + /** Full/low speed endpoint on high-speed hub requires split. */
37607 + uint8_t do_split;
37608 +
37609 + /** @name Periodic schedule information */
37610 + /** @{ */
37611 +
37612 + /** Bandwidth in microseconds per (micro)frame. */
37613 + uint16_t usecs;
37614 +
37615 + /** Interval between transfers in (micro)frames. */
37616 + uint16_t interval;
37617 +
37618 + /**
37619 + * (micro)frame to initialize a periodic transfer. The transfer
37620 + * executes in the following (micro)frame.
37621 + */
37622 + uint16_t sched_frame;
37623 +
37624 + /** (micro)frame at which last start split was initialized. */
37625 + uint16_t start_split_frame;
37626 +
37627 + /** @} */
37628 +
37629 + /**
37630 + * Used instead of original buffer if
37631 + * it(physical address) is not dword-aligned.
37632 + */
37633 + uint8_t *dw_align_buf;
37634 + dwc_dma_t dw_align_buf_dma;
37635 +
37636 + /** Entry for QH in either the periodic or non-periodic schedule. */
37637 + dwc_list_link_t qh_list_entry;
37638 +
37639 + /** @name Descriptor DMA support */
37640 + /** @{ */
37641 +
37642 + /** Descriptor List. */
37643 + dwc_otg_host_dma_desc_t *desc_list;
37644 +
37645 + /** Descriptor List physical address. */
37646 + dwc_dma_t desc_list_dma;
37647 +
37648 + /**
37649 + * Xfer Bytes array.
37650 + * Each element corresponds to a descriptor and indicates
37651 + * original XferSize size value for the descriptor.
37652 + */
37653 + uint32_t *n_bytes;
37654 +
37655 + /** Actual number of transfer descriptors in a list. */
37656 + uint16_t ntd;
37657 +
37658 + /** First activated isochronous transfer descriptor index. */
37659 + uint8_t td_first;
37660 + /** Last activated isochronous transfer descriptor index. */
37661 + uint8_t td_last;
37662 +
37663 + /** @} */
37664 +
37665 +
37666 + uint16_t speed;
37667 + uint16_t frame_usecs[8];
37668 +} dwc_otg_qh_t;
37669 +
37670 +DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
37671 +
37672 +/**
37673 + * This structure holds the state of the HCD, including the non-periodic and
37674 + * periodic schedules.
37675 + */
37676 +struct dwc_otg_hcd {
37677 + /** The DWC otg device pointer */
37678 + struct dwc_otg_device *otg_dev;
37679 + /** DWC OTG Core Interface Layer */
37680 + dwc_otg_core_if_t *core_if;
37681 +
37682 + /** Function HCD driver callbacks */
37683 + struct dwc_otg_hcd_function_ops *fops;
37684 +
37685 + /** Internal DWC HCD Flags */
37686 + volatile union dwc_otg_hcd_internal_flags {
37687 + uint32_t d32;
37688 + struct {
37689 + unsigned port_connect_status_change:1;
37690 + unsigned port_connect_status:1;
37691 + unsigned port_reset_change:1;
37692 + unsigned port_enable_change:1;
37693 + unsigned port_suspend_change:1;
37694 + unsigned port_over_current_change:1;
37695 + unsigned port_l1_change:1;
37696 + unsigned reserved:26;
37697 + } b;
37698 + } flags;
37699 +
37700 + /**
37701 + * Inactive items in the non-periodic schedule. This is a list of
37702 + * Queue Heads. Transfers associated with these Queue Heads are not
37703 + * currently assigned to a host channel.
37704 + */
37705 + dwc_list_link_t non_periodic_sched_inactive;
37706 +
37707 + /**
37708 + * Active items in the non-periodic schedule. This is a list of
37709 + * Queue Heads. Transfers associated with these Queue Heads are
37710 + * currently assigned to a host channel.
37711 + */
37712 + dwc_list_link_t non_periodic_sched_active;
37713 +
37714 + /**
37715 + * Pointer to the next Queue Head to process in the active
37716 + * non-periodic schedule.
37717 + */
37718 + dwc_list_link_t *non_periodic_qh_ptr;
37719 +
37720 + /**
37721 + * Inactive items in the periodic schedule. This is a list of QHs for
37722 + * periodic transfers that are _not_ scheduled for the next frame.
37723 + * Each QH in the list has an interval counter that determines when it
37724 + * needs to be scheduled for execution. This scheduling mechanism
37725 + * allows only a simple calculation for periodic bandwidth used (i.e.
37726 + * must assume that all periodic transfers may need to execute in the
37727 + * same frame). However, it greatly simplifies scheduling and should
37728 + * be sufficient for the vast majority of OTG hosts, which need to
37729 + * connect to a small number of peripherals at one time.
37730 + *
37731 + * Items move from this list to periodic_sched_ready when the QH
37732 + * interval counter is 0 at SOF.
37733 + */
37734 + dwc_list_link_t periodic_sched_inactive;
37735 +
37736 + /**
37737 + * List of periodic QHs that are ready for execution in the next
37738 + * frame, but have not yet been assigned to host channels.
37739 + *
37740 + * Items move from this list to periodic_sched_assigned as host
37741 + * channels become available during the current frame.
37742 + */
37743 + dwc_list_link_t periodic_sched_ready;
37744 +
37745 + /**
37746 + * List of periodic QHs to be executed in the next frame that are
37747 + * assigned to host channels.
37748 + *
37749 + * Items move from this list to periodic_sched_queued as the
37750 + * transactions for the QH are queued to the DWC_otg controller.
37751 + */
37752 + dwc_list_link_t periodic_sched_assigned;
37753 +
37754 + /**
37755 + * List of periodic QHs that have been queued for execution.
37756 + *
37757 + * Items move from this list to either periodic_sched_inactive or
37758 + * periodic_sched_ready when the channel associated with the transfer
37759 + * is released. If the interval for the QH is 1, the item moves to
37760 + * periodic_sched_ready because it must be rescheduled for the next
37761 + * frame. Otherwise, the item moves to periodic_sched_inactive.
37762 + */
37763 + dwc_list_link_t periodic_sched_queued;
37764 +
37765 + /**
37766 + * Total bandwidth claimed so far for periodic transfers. This value
37767 + * is in microseconds per (micro)frame. The assumption is that all
37768 + * periodic transfers may occur in the same (micro)frame.
37769 + */
37770 + uint16_t periodic_usecs;
37771 +
37772 + /**
37773 + * Total bandwidth claimed so far for all periodic transfers
37774 + * in a frame.
37775 + * This will include a mixture of HS and FS transfers.
37776 + * Units are microseconds per (micro)frame.
37777 + * We have a budget per frame and have to schedule
37778 + * transactions accordingly.
37779 + * Watch out for the fact that things are actually scheduled for the
37780 + * "next frame".
37781 + */
37782 + uint16_t frame_usecs[8];
37783 +
37784 +
37785 + /**
37786 + * Frame number read from the core at SOF. The value ranges from 0 to
37787 + * DWC_HFNUM_MAX_FRNUM.
37788 + */
37789 + uint16_t frame_number;
37790 +
37791 + /**
37792 + * Count of periodic QHs, if using several eps. For SOF enable/disable.
37793 + */
37794 + uint16_t periodic_qh_count;
37795 +
37796 + /**
37797 + * Free host channels in the controller. This is a list of
37798 + * dwc_hc_t items.
37799 + */
37800 + struct hc_list free_hc_list;
37801 + /**
37802 + * Number of host channels assigned to periodic transfers. Currently
37803 + * assuming that there is a dedicated host channel for each periodic
37804 + * transaction and at least one host channel available for
37805 + * non-periodic transactions.
37806 + */
37807 + int periodic_channels; /* microframe_schedule==0 */
37808 +
37809 + /**
37810 + * Number of host channels assigned to non-periodic transfers.
37811 + */
37812 + int non_periodic_channels; /* microframe_schedule==0 */
37813 +
37814 + /**
37815 + * Number of host channels assigned to non-periodic transfers.
37816 + */
37817 + int available_host_channels;
37818 +
37819 + /**
37820 + * Array of pointers to the host channel descriptors. Allows accessing
37821 + * a host channel descriptor given the host channel number. This is
37822 + * useful in interrupt handlers.
37823 + */
37824 + struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
37825 +
37826 + /**
37827 + * Buffer to use for any data received during the status phase of a
37828 + * control transfer. Normally no data is transferred during the status
37829 + * phase. This buffer is used as a bit bucket.
37830 + */
37831 + uint8_t *status_buf;
37832 +
37833 + /**
37834 + * DMA address for status_buf.
37835 + */
37836 + dma_addr_t status_buf_dma;
37837 +#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
37838 +
37839 + /**
37840 + * Connection timer. An OTG host must display a message if the device
37841 + * does not connect. Started when the VBus power is turned on via
37842 + * sysfs attribute "buspower".
37843 + */
37844 + dwc_timer_t *conn_timer;
37845 +
37846 + /* Tasket to do a reset */
37847 + dwc_tasklet_t *reset_tasklet;
37848 +
37849 + /* */
37850 + dwc_spinlock_t *lock;
37851 +
37852 + /**
37853 + * Private data that could be used by OS wrapper.
37854 + */
37855 + void *priv;
37856 +
37857 + uint8_t otg_port;
37858 +
37859 + /** Frame List */
37860 + uint32_t *frame_list;
37861 +
37862 + /** Frame List DMA address */
37863 + dma_addr_t frame_list_dma;
37864 +
37865 +#ifdef DEBUG
37866 + uint32_t frrem_samples;
37867 + uint64_t frrem_accum;
37868 +
37869 + uint32_t hfnum_7_samples_a;
37870 + uint64_t hfnum_7_frrem_accum_a;
37871 + uint32_t hfnum_0_samples_a;
37872 + uint64_t hfnum_0_frrem_accum_a;
37873 + uint32_t hfnum_other_samples_a;
37874 + uint64_t hfnum_other_frrem_accum_a;
37875 +
37876 + uint32_t hfnum_7_samples_b;
37877 + uint64_t hfnum_7_frrem_accum_b;
37878 + uint32_t hfnum_0_samples_b;
37879 + uint64_t hfnum_0_frrem_accum_b;
37880 + uint32_t hfnum_other_samples_b;
37881 + uint64_t hfnum_other_frrem_accum_b;
37882 +#endif
37883 +};
37884 +
37885 +/** @name Transaction Execution Functions */
37886 +/** @{ */
37887 +extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
37888 + * hcd);
37889 +extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
37890 + dwc_otg_transaction_type_e tr_type);
37891 +
37892 +/** @} */
37893 +
37894 +/** @name Interrupt Handler Functions */
37895 +/** @{ */
37896 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37897 +extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37898 +extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t *
37899 + dwc_otg_hcd);
37900 +extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t *
37901 + dwc_otg_hcd);
37902 +extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t *
37903 + dwc_otg_hcd);
37904 +extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *
37905 + dwc_otg_hcd);
37906 +extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37907 +extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t *
37908 + dwc_otg_hcd);
37909 +extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37910 +extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37911 +extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd,
37912 + uint32_t num);
37913 +extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37914 +extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t *
37915 + dwc_otg_hcd);
37916 +/** @} */
37917 +
37918 +/** @name Schedule Queue Functions */
37919 +/** @{ */
37920 +
37921 +/* Implemented in dwc_otg_hcd_queue.c */
37922 +extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
37923 + dwc_otg_hcd_urb_t * urb, int atomic_alloc);
37924 +extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
37925 +extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
37926 +extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
37927 +extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
37928 + int sched_csplit);
37929 +
37930 +/** Remove and free a QH */
37931 +static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd,
37932 + dwc_otg_qh_t * qh)
37933 +{
37934 + dwc_irqflags_t flags;
37935 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
37936 + dwc_otg_hcd_qh_remove(hcd, qh);
37937 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
37938 + dwc_otg_hcd_qh_free(hcd, qh);
37939 +}
37940 +
37941 +/** Allocates memory for a QH structure.
37942 + * @return Returns the memory allocate or NULL on error. */
37943 +static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(int atomic_alloc)
37944 +{
37945 + if (atomic_alloc)
37946 + return (dwc_otg_qh_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qh_t));
37947 + else
37948 + return (dwc_otg_qh_t *) DWC_ALLOC(sizeof(dwc_otg_qh_t));
37949 +}
37950 +
37951 +extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb,
37952 + int atomic_alloc);
37953 +extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb);
37954 +extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd,
37955 + dwc_otg_qh_t ** qh, int atomic_alloc);
37956 +
37957 +/** Allocates memory for a QTD structure.
37958 + * @return Returns the memory allocate or NULL on error. */
37959 +static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(int atomic_alloc)
37960 +{
37961 + if (atomic_alloc)
37962 + return (dwc_otg_qtd_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qtd_t));
37963 + else
37964 + return (dwc_otg_qtd_t *) DWC_ALLOC(sizeof(dwc_otg_qtd_t));
37965 +}
37966 +
37967 +/** Frees the memory for a QTD structure. QTD should already be removed from
37968 + * list.
37969 + * @param qtd QTD to free.*/
37970 +static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd)
37971 +{
37972 + DWC_FREE(qtd);
37973 +}
37974 +
37975 +/** Removes a QTD from list.
37976 + * @param hcd HCD instance.
37977 + * @param qtd QTD to remove from list.
37978 + * @param qh QTD belongs to.
37979 + */
37980 +static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd,
37981 + dwc_otg_qtd_t * qtd,
37982 + dwc_otg_qh_t * qh)
37983 +{
37984 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
37985 +}
37986 +
37987 +/** Remove and free a QTD
37988 + * Need to disable IRQ and hold hcd lock while calling this function out of
37989 + * interrupt servicing chain */
37990 +static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd,
37991 + dwc_otg_qtd_t * qtd,
37992 + dwc_otg_qh_t * qh)
37993 +{
37994 + dwc_otg_hcd_qtd_remove(hcd, qtd, qh);
37995 + dwc_otg_hcd_qtd_free(qtd);
37996 +}
37997 +
37998 +/** @} */
37999 +
38000 +/** @name Descriptor DMA Supporting Functions */
38001 +/** @{ */
38002 +
38003 +extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38004 +extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
38005 + dwc_hc_t * hc,
38006 + dwc_otg_hc_regs_t * hc_regs,
38007 + dwc_otg_halt_status_e halt_status);
38008 +
38009 +extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38010 +extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38011 +
38012 +/** @} */
38013 +
38014 +/** @name Internal Functions */
38015 +/** @{ */
38016 +dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb);
38017 +/** @} */
38018 +
38019 +#ifdef CONFIG_USB_DWC_OTG_LPM
38020 +extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd,
38021 + uint8_t devaddr);
38022 +extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd);
38023 +#endif
38024 +
38025 +/** Gets the QH that contains the list_head */
38026 +#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
38027 +
38028 +/** Gets the QTD that contains the list_head */
38029 +#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
38030 +
38031 +/** Check if QH is non-periodic */
38032 +#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \
38033 + (_qh_ptr_->ep_type == UE_CONTROL))
38034 +
38035 +/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
38036 +#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
38037 +
38038 +/** Packet size for any kind of endpoint descriptor */
38039 +#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
38040 +
38041 +/**
38042 + * Returns true if _frame1 is less than or equal to _frame2. The comparison is
38043 + * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
38044 + * frame number when the max frame number is reached.
38045 + */
38046 +static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
38047 +{
38048 + return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
38049 + (DWC_HFNUM_MAX_FRNUM >> 1);
38050 +}
38051 +
38052 +/**
38053 + * Returns true if _frame1 is greater than _frame2. The comparison is done
38054 + * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
38055 + * number when the max frame number is reached.
38056 + */
38057 +static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
38058 +{
38059 + return (frame1 != frame2) &&
38060 + (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
38061 + (DWC_HFNUM_MAX_FRNUM >> 1));
38062 +}
38063 +
38064 +/**
38065 + * Increments _frame by the amount specified by _inc. The addition is done
38066 + * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
38067 + */
38068 +static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
38069 +{
38070 + return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
38071 +}
38072 +
38073 +static inline uint16_t dwc_full_frame_num(uint16_t frame)
38074 +{
38075 + return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
38076 +}
38077 +
38078 +static inline uint16_t dwc_micro_frame_num(uint16_t frame)
38079 +{
38080 + return frame & 0x7;
38081 +}
38082 +
38083 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
38084 + dwc_otg_hc_regs_t * hc_regs,
38085 + dwc_otg_qtd_t * qtd);
38086 +
38087 +#ifdef DEBUG
38088 +/**
38089 + * Macro to sample the remaining PHY clocks left in the current frame. This
38090 + * may be used during debugging to determine the average time it takes to
38091 + * execute sections of code. There are two possible sample points, "a" and
38092 + * "b", so the _letter argument must be one of these values.
38093 + *
38094 + * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
38095 + * example, "cat /sys/devices/lm0/hcd_frrem".
38096 + */
38097 +#define dwc_sample_frrem(_hcd, _qh, _letter) \
38098 +{ \
38099 + hfnum_data_t hfnum; \
38100 + dwc_otg_qtd_t *qtd; \
38101 + qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
38102 + if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
38103 + hfnum.d32 = DWC_READ_REG32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
38104 + switch (hfnum.b.frnum & 0x7) { \
38105 + case 7: \
38106 + _hcd->hfnum_7_samples_##_letter++; \
38107 + _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
38108 + break; \
38109 + case 0: \
38110 + _hcd->hfnum_0_samples_##_letter++; \
38111 + _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
38112 + break; \
38113 + default: \
38114 + _hcd->hfnum_other_samples_##_letter++; \
38115 + _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
38116 + break; \
38117 + } \
38118 + } \
38119 +}
38120 +#else
38121 +#define dwc_sample_frrem(_hcd, _qh, _letter)
38122 +#endif
38123 +#endif
38124 +#endif /* DWC_DEVICE_ONLY */
38125 --- /dev/null
38126 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
38127 @@ -0,0 +1,1133 @@
38128 +/*==========================================================================
38129 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
38130 + * $Revision: #10 $
38131 + * $Date: 2011/10/20 $
38132 + * $Change: 1869464 $
38133 + *
38134 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
38135 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
38136 + * otherwise expressly agreed to in writing between Synopsys and you.
38137 + *
38138 + * The Software IS NOT an item of Licensed Software or Licensed Product under
38139 + * any End User Software License Agreement or Agreement for Licensed Product
38140 + * with Synopsys or any supplement thereto. You are permitted to use and
38141 + * redistribute this Software in source and binary forms, with or without
38142 + * modification, provided that redistributions of source code must retain this
38143 + * notice. You may not view, use, disclose, copy or distribute this file or
38144 + * any information contained herein except pursuant to this license grant from
38145 + * Synopsys. If you do not agree with this notice, including the disclaimer
38146 + * below, then you are not authorized to use the Software.
38147 + *
38148 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
38149 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38150 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38151 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
38152 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38153 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
38154 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38155 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38156 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38157 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38158 + * DAMAGE.
38159 + * ========================================================================== */
38160 +#ifndef DWC_DEVICE_ONLY
38161 +
38162 +/** @file
38163 + * This file contains Descriptor DMA support implementation for host mode.
38164 + */
38165 +
38166 +#include "dwc_otg_hcd.h"
38167 +#include "dwc_otg_regs.h"
38168 +
38169 +extern bool microframe_schedule;
38170 +
38171 +static inline uint8_t frame_list_idx(uint16_t frame)
38172 +{
38173 + return (frame & (MAX_FRLIST_EN_NUM - 1));
38174 +}
38175 +
38176 +static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
38177 +{
38178 + return (idx + inc) &
38179 + (((speed ==
38180 + DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
38181 + MAX_DMA_DESC_NUM_GENERIC) - 1);
38182 +}
38183 +
38184 +static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
38185 +{
38186 + return (idx - inc) &
38187 + (((speed ==
38188 + DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
38189 + MAX_DMA_DESC_NUM_GENERIC) - 1);
38190 +}
38191 +
38192 +static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
38193 +{
38194 + return (((qh->ep_type == UE_ISOCHRONOUS)
38195 + && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH))
38196 + ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC);
38197 +}
38198 +static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
38199 +{
38200 + return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)
38201 + ? ((qh->interval + 8 - 1) / 8)
38202 + : qh->interval);
38203 +}
38204 +
38205 +static int desc_list_alloc(dwc_otg_qh_t * qh)
38206 +{
38207 + int retval = 0;
38208 +
38209 + qh->desc_list = (dwc_otg_host_dma_desc_t *)
38210 + DWC_DMA_ALLOC(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
38211 + &qh->desc_list_dma);
38212 +
38213 + if (!qh->desc_list) {
38214 + retval = -DWC_E_NO_MEMORY;
38215 + DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
38216 +
38217 + }
38218 +
38219 + dwc_memset(qh->desc_list, 0x00,
38220 + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
38221 +
38222 + qh->n_bytes =
38223 + (uint32_t *) DWC_ALLOC(sizeof(uint32_t) * max_desc_num(qh));
38224 +
38225 + if (!qh->n_bytes) {
38226 + retval = -DWC_E_NO_MEMORY;
38227 + DWC_ERROR
38228 + ("%s: Failed to allocate array for descriptors' size actual values\n",
38229 + __func__);
38230 +
38231 + }
38232 + return retval;
38233 +
38234 +}
38235 +
38236 +static void desc_list_free(dwc_otg_qh_t * qh)
38237 +{
38238 + if (qh->desc_list) {
38239 + DWC_DMA_FREE(max_desc_num(qh), qh->desc_list,
38240 + qh->desc_list_dma);
38241 + qh->desc_list = NULL;
38242 + }
38243 +
38244 + if (qh->n_bytes) {
38245 + DWC_FREE(qh->n_bytes);
38246 + qh->n_bytes = NULL;
38247 + }
38248 +}
38249 +
38250 +static int frame_list_alloc(dwc_otg_hcd_t * hcd)
38251 +{
38252 + int retval = 0;
38253 + if (hcd->frame_list)
38254 + return 0;
38255 +
38256 + hcd->frame_list = DWC_DMA_ALLOC(4 * MAX_FRLIST_EN_NUM,
38257 + &hcd->frame_list_dma);
38258 + if (!hcd->frame_list) {
38259 + retval = -DWC_E_NO_MEMORY;
38260 + DWC_ERROR("%s: Frame List allocation failed\n", __func__);
38261 + }
38262 +
38263 + dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
38264 +
38265 + return retval;
38266 +}
38267 +
38268 +static void frame_list_free(dwc_otg_hcd_t * hcd)
38269 +{
38270 + if (!hcd->frame_list)
38271 + return;
38272 +
38273 + DWC_DMA_FREE(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
38274 + hcd->frame_list = NULL;
38275 +}
38276 +
38277 +static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
38278 +{
38279 +
38280 + hcfg_data_t hcfg;
38281 +
38282 + hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
38283 +
38284 + if (hcfg.b.perschedena) {
38285 + /* already enabled */
38286 + return;
38287 + }
38288 +
38289 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hflbaddr,
38290 + hcd->frame_list_dma);
38291 +
38292 + switch (fr_list_en) {
38293 + case 64:
38294 + hcfg.b.frlisten = 3;
38295 + break;
38296 + case 32:
38297 + hcfg.b.frlisten = 2;
38298 + break;
38299 + case 16:
38300 + hcfg.b.frlisten = 1;
38301 + break;
38302 + case 8:
38303 + hcfg.b.frlisten = 0;
38304 + break;
38305 + default:
38306 + break;
38307 + }
38308 +
38309 + hcfg.b.perschedena = 1;
38310 +
38311 + DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
38312 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
38313 +
38314 +}
38315 +
38316 +static void per_sched_disable(dwc_otg_hcd_t * hcd)
38317 +{
38318 + hcfg_data_t hcfg;
38319 +
38320 + hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
38321 +
38322 + if (!hcfg.b.perschedena) {
38323 + /* already disabled */
38324 + return;
38325 + }
38326 + hcfg.b.perschedena = 0;
38327 +
38328 + DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
38329 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
38330 +}
38331 +
38332 +/*
38333 + * Activates/Deactivates FrameList entries for the channel
38334 + * based on endpoint servicing period.
38335 + */
38336 +void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
38337 +{
38338 + uint16_t i, j, inc;
38339 + dwc_hc_t *hc = NULL;
38340 +
38341 + if (!qh->channel) {
38342 + DWC_ERROR("qh->channel = %p", qh->channel);
38343 + return;
38344 + }
38345 +
38346 + if (!hcd) {
38347 + DWC_ERROR("------hcd = %p", hcd);
38348 + return;
38349 + }
38350 +
38351 + if (!hcd->frame_list) {
38352 + DWC_ERROR("-------hcd->frame_list = %p", hcd->frame_list);
38353 + return;
38354 + }
38355 +
38356 + hc = qh->channel;
38357 + inc = frame_incr_val(qh);
38358 + if (qh->ep_type == UE_ISOCHRONOUS)
38359 + i = frame_list_idx(qh->sched_frame);
38360 + else
38361 + i = 0;
38362 +
38363 + j = i;
38364 + do {
38365 + if (enable)
38366 + hcd->frame_list[j] |= (1 << hc->hc_num);
38367 + else
38368 + hcd->frame_list[j] &= ~(1 << hc->hc_num);
38369 + j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
38370 + }
38371 + while (j != i);
38372 + if (!enable)
38373 + return;
38374 + hc->schinfo = 0;
38375 + if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
38376 + j = 1;
38377 + /* TODO - check this */
38378 + inc = (8 + qh->interval - 1) / qh->interval;
38379 + for (i = 0; i < inc; i++) {
38380 + hc->schinfo |= j;
38381 + j = j << qh->interval;
38382 + }
38383 + } else {
38384 + hc->schinfo = 0xff;
38385 + }
38386 +}
38387 +
38388 +#if 1
38389 +void dump_frame_list(dwc_otg_hcd_t * hcd)
38390 +{
38391 + int i = 0;
38392 + DWC_PRINTF("--FRAME LIST (hex) --\n");
38393 + for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
38394 + DWC_PRINTF("%x\t", hcd->frame_list[i]);
38395 + if (!(i % 8) && i)
38396 + DWC_PRINTF("\n");
38397 + }
38398 + DWC_PRINTF("\n----\n");
38399 +
38400 +}
38401 +#endif
38402 +
38403 +static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38404 +{
38405 + dwc_irqflags_t flags;
38406 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
38407 +
38408 + dwc_hc_t *hc = qh->channel;
38409 + if (dwc_qh_is_non_per(qh)) {
38410 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
38411 + if (!microframe_schedule)
38412 + hcd->non_periodic_channels--;
38413 + else
38414 + hcd->available_host_channels++;
38415 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
38416 + } else
38417 + update_frame_list(hcd, qh, 0);
38418 +
38419 + /*
38420 + * The condition is added to prevent double cleanup try in case of device
38421 + * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
38422 + */
38423 + if (hc->qh) {
38424 + dwc_otg_hc_cleanup(hcd->core_if, hc);
38425 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
38426 + hc->qh = NULL;
38427 + }
38428 +
38429 + qh->channel = NULL;
38430 + qh->ntd = 0;
38431 +
38432 + if (qh->desc_list) {
38433 + dwc_memset(qh->desc_list, 0x00,
38434 + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
38435 + }
38436 + DWC_SPINLOCK_FREE(channel_lock);
38437 +}
38438 +
38439 +/**
38440 + * Initializes a QH structure's Descriptor DMA related members.
38441 + * Allocates memory for descriptor list.
38442 + * On first periodic QH, allocates memory for FrameList
38443 + * and enables periodic scheduling.
38444 + *
38445 + * @param hcd The HCD state structure for the DWC OTG controller.
38446 + * @param qh The QH to init.
38447 + *
38448 + * @return 0 if successful, negative error code otherwise.
38449 + */
38450 +int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38451 +{
38452 + int retval = 0;
38453 +
38454 + if (qh->do_split) {
38455 + DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
38456 + return -1;
38457 + }
38458 +
38459 + retval = desc_list_alloc(qh);
38460 +
38461 + if ((retval == 0)
38462 + && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
38463 + if (!hcd->frame_list) {
38464 + retval = frame_list_alloc(hcd);
38465 + /* Enable periodic schedule on first periodic QH */
38466 + if (retval == 0)
38467 + per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
38468 + }
38469 + }
38470 +
38471 + qh->ntd = 0;
38472 +
38473 + return retval;
38474 +}
38475 +
38476 +/**
38477 + * Frees descriptor list memory associated with the QH.
38478 + * If QH is periodic and the last, frees FrameList memory
38479 + * and disables periodic scheduling.
38480 + *
38481 + * @param hcd The HCD state structure for the DWC OTG controller.
38482 + * @param qh The QH to init.
38483 + */
38484 +void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38485 +{
38486 + desc_list_free(qh);
38487 +
38488 + /*
38489 + * Channel still assigned due to some reasons.
38490 + * Seen on Isoc URB dequeue. Channel halted but no subsequent
38491 + * ChHalted interrupt to release the channel. Afterwards
38492 + * when it comes here from endpoint disable routine
38493 + * channel remains assigned.
38494 + */
38495 + if (qh->channel)
38496 + release_channel_ddma(hcd, qh);
38497 +
38498 + if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
38499 + && (microframe_schedule || !hcd->periodic_channels) && hcd->frame_list) {
38500 +
38501 + per_sched_disable(hcd);
38502 + frame_list_free(hcd);
38503 + }
38504 +}
38505 +
38506 +static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
38507 +{
38508 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
38509 + /*
38510 + * Descriptor set(8 descriptors) index
38511 + * which is 8-aligned.
38512 + */
38513 + return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
38514 + } else {
38515 + return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
38516 + }
38517 +}
38518 +
38519 +/*
38520 + * Determine starting frame for Isochronous transfer.
38521 + * Few frames skipped to prevent race condition with HC.
38522 + */
38523 +static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
38524 + uint8_t * skip_frames)
38525 +{
38526 + uint16_t frame = 0;
38527 + hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
38528 +
38529 + /* sched_frame is always frame number(not uFrame) both in FS and HS !! */
38530 +
38531 + /*
38532 + * skip_frames is used to limit activated descriptors number
38533 + * to avoid the situation when HC services the last activated
38534 + * descriptor firstly.
38535 + * Example for FS:
38536 + * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
38537 + * corresponding to curr_frame+1, the descriptor corresponding to frame 2
38538 + * will be fetched. If the number of descriptors is max=64 (or greather) the
38539 + * list will be fully programmed with Active descriptors and it is possible
38540 + * case(rare) that the latest descriptor(considering rollback) corresponding
38541 + * to frame 2 will be serviced first. HS case is more probable because, in fact,
38542 + * up to 11 uframes(16 in the code) may be skipped.
38543 + */
38544 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
38545 + /*
38546 + * Consider uframe counter also, to start xfer asap.
38547 + * If half of the frame elapsed skip 2 frames otherwise
38548 + * just 1 frame.
38549 + * Starting descriptor index must be 8-aligned, so
38550 + * if the current frame is near to complete the next one
38551 + * is skipped as well.
38552 + */
38553 +
38554 + if (dwc_micro_frame_num(hcd->frame_number) >= 5) {
38555 + *skip_frames = 2 * 8;
38556 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
38557 + } else {
38558 + *skip_frames = 1 * 8;
38559 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
38560 + }
38561 +
38562 + frame = dwc_full_frame_num(frame);
38563 + } else {
38564 + /*
38565 + * Two frames are skipped for FS - the current and the next.
38566 + * But for descriptor programming, 1 frame(descriptor) is enough,
38567 + * see example above.
38568 + */
38569 + *skip_frames = 1;
38570 + frame = dwc_frame_num_inc(hcd->frame_number, 2);
38571 + }
38572 +
38573 + return frame;
38574 +}
38575 +
38576 +/*
38577 + * Calculate initial descriptor index for isochronous transfer
38578 + * based on scheduled frame.
38579 + */
38580 +static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38581 +{
38582 + uint16_t frame = 0, fr_idx, fr_idx_tmp;
38583 + uint8_t skip_frames = 0;
38584 + /*
38585 + * With current ISOC processing algorithm the channel is being
38586 + * released when no more QTDs in the list(qh->ntd == 0).
38587 + * Thus this function is called only when qh->ntd == 0 and qh->channel == 0.
38588 + *
38589 + * So qh->channel != NULL branch is not used and just not removed from the
38590 + * source file. It is required for another possible approach which is,
38591 + * do not disable and release the channel when ISOC session completed,
38592 + * just move QH to inactive schedule until new QTD arrives.
38593 + * On new QTD, the QH moved back to 'ready' schedule,
38594 + * starting frame and therefore starting desc_index are recalculated.
38595 + * In this case channel is released only on ep_disable.
38596 + */
38597 +
38598 + /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
38599 + if (qh->channel) {
38600 + frame = calc_starting_frame(hcd, qh, &skip_frames);
38601 + /*
38602 + * Calculate initial descriptor index based on FrameList current bitmap
38603 + * and servicing period.
38604 + */
38605 + fr_idx_tmp = frame_list_idx(frame);
38606 + fr_idx =
38607 + (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) -
38608 + fr_idx_tmp)
38609 + % frame_incr_val(qh);
38610 + fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
38611 + } else {
38612 + qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);
38613 + fr_idx = frame_list_idx(qh->sched_frame);
38614 + }
38615 +
38616 + qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx);
38617 +
38618 + return skip_frames;
38619 +}
38620 +
38621 +#define ISOC_URB_GIVEBACK_ASAP
38622 +
38623 +#define MAX_ISOC_XFER_SIZE_FS 1023
38624 +#define MAX_ISOC_XFER_SIZE_HS 3072
38625 +#define DESCNUM_THRESHOLD 4
38626 +
38627 +static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
38628 + uint8_t skip_frames)
38629 +{
38630 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
38631 + dwc_otg_qtd_t *qtd;
38632 + dwc_otg_host_dma_desc_t *dma_desc;
38633 + uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
38634 +
38635 + idx = qh->td_last;
38636 + inc = qh->interval;
38637 + n_desc = 0;
38638 +
38639 + ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
38640 + if (skip_frames && !qh->channel)
38641 + ntd_max = ntd_max - skip_frames / qh->interval;
38642 +
38643 + max_xfer_size =
38644 + (qh->dev_speed ==
38645 + DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS :
38646 + MAX_ISOC_XFER_SIZE_FS;
38647 +
38648 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
38649 + while ((qh->ntd < ntd_max)
38650 + && (qtd->isoc_frame_index_last <
38651 + qtd->urb->packet_count)) {
38652 +
38653 + dma_desc = &qh->desc_list[idx];
38654 + dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
38655 +
38656 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
38657 +
38658 + if (frame_desc->length > max_xfer_size)
38659 + qh->n_bytes[idx] = max_xfer_size;
38660 + else
38661 + qh->n_bytes[idx] = frame_desc->length;
38662 + dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
38663 + dma_desc->status.b_isoc.a = 1;
38664 + dma_desc->status.b_isoc.sts = 0;
38665 +
38666 + dma_desc->buf = qtd->urb->dma + frame_desc->offset;
38667 +
38668 + qh->ntd++;
38669 +
38670 + qtd->isoc_frame_index_last++;
38671 +
38672 +#ifdef ISOC_URB_GIVEBACK_ASAP
38673 + /*
38674 + * Set IOC for each descriptor corresponding to the
38675 + * last frame of the URB.
38676 + */
38677 + if (qtd->isoc_frame_index_last ==
38678 + qtd->urb->packet_count)
38679 + dma_desc->status.b_isoc.ioc = 1;
38680 +
38681 +#endif
38682 + idx = desclist_idx_inc(idx, inc, qh->dev_speed);
38683 + n_desc++;
38684 +
38685 + }
38686 + qtd->in_process = 1;
38687 + }
38688 +
38689 + qh->td_last = idx;
38690 +
38691 +#ifdef ISOC_URB_GIVEBACK_ASAP
38692 + /* Set IOC for the last descriptor if descriptor list is full */
38693 + if (qh->ntd == ntd_max) {
38694 + idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
38695 + qh->desc_list[idx].status.b_isoc.ioc = 1;
38696 + }
38697 +#else
38698 + /*
38699 + * Set IOC bit only for one descriptor.
38700 + * Always try to be ahead of HW processing,
38701 + * i.e. on IOC generation driver activates next descriptors but
38702 + * core continues to process descriptors followed the one with IOC set.
38703 + */
38704 +
38705 + if (n_desc > DESCNUM_THRESHOLD) {
38706 + /*
38707 + * Move IOC "up". Required even if there is only one QTD
38708 + * in the list, cause QTDs migth continue to be queued,
38709 + * but during the activation it was only one queued.
38710 + * Actually more than one QTD might be in the list if this function called
38711 + * from XferCompletion - QTDs was queued during HW processing of the previous
38712 + * descriptor chunk.
38713 + */
38714 + idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
38715 + } else {
38716 + /*
38717 + * Set the IOC for the latest descriptor
38718 + * if either number of descriptor is not greather than threshold
38719 + * or no more new descriptors activated.
38720 + */
38721 + idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
38722 + }
38723 +
38724 + qh->desc_list[idx].status.b_isoc.ioc = 1;
38725 +#endif
38726 +}
38727 +
38728 +static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38729 +{
38730 +
38731 + dwc_hc_t *hc;
38732 + dwc_otg_host_dma_desc_t *dma_desc;
38733 + dwc_otg_qtd_t *qtd;
38734 + int num_packets, len, n_desc = 0;
38735 +
38736 + hc = qh->channel;
38737 +
38738 + /*
38739 + * Start with hc->xfer_buff initialized in
38740 + * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
38741 + * this pointer re-assigned to the buffer of the currently processed QTD.
38742 + * For non-SG request there is always one QTD active.
38743 + */
38744 +
38745 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
38746 +
38747 + if (n_desc) {
38748 + /* SG request - more than 1 QTDs */
38749 + hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
38750 + hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
38751 + }
38752 +
38753 + qtd->n_desc = 0;
38754 +
38755 + do {
38756 + dma_desc = &qh->desc_list[n_desc];
38757 + len = hc->xfer_len;
38758 +
38759 + if (len > MAX_DMA_DESC_SIZE)
38760 + len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
38761 +
38762 + if (hc->ep_is_in) {
38763 + if (len > 0) {
38764 + num_packets = (len + hc->max_packet - 1) / hc->max_packet;
38765 + } else {
38766 + /* Need 1 packet for transfer length of 0. */
38767 + num_packets = 1;
38768 + }
38769 + /* Always program an integral # of max packets for IN transfers. */
38770 + len = num_packets * hc->max_packet;
38771 + }
38772 +
38773 + dma_desc->status.b.n_bytes = len;
38774 +
38775 + qh->n_bytes[n_desc] = len;
38776 +
38777 + if ((qh->ep_type == UE_CONTROL)
38778 + && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
38779 + dma_desc->status.b.sup = 1; /* Setup Packet */
38780 +
38781 + dma_desc->status.b.a = 1; /* Active descriptor */
38782 + dma_desc->status.b.sts = 0;
38783 +
38784 + dma_desc->buf =
38785 + ((unsigned long)hc->xfer_buff & 0xffffffff);
38786 +
38787 + /*
38788 + * Last descriptor(or single) of IN transfer
38789 + * with actual size less than MaxPacket.
38790 + */
38791 + if (len > hc->xfer_len) {
38792 + hc->xfer_len = 0;
38793 + } else {
38794 + hc->xfer_buff += len;
38795 + hc->xfer_len -= len;
38796 + }
38797 +
38798 + qtd->n_desc++;
38799 + n_desc++;
38800 + }
38801 + while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
38802 +
38803 +
38804 + qtd->in_process = 1;
38805 +
38806 + if (qh->ep_type == UE_CONTROL)
38807 + break;
38808 +
38809 + if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
38810 + break;
38811 + }
38812 +
38813 + if (n_desc) {
38814 + /* Request Transfer Complete interrupt for the last descriptor */
38815 + qh->desc_list[n_desc - 1].status.b.ioc = 1;
38816 + /* End of List indicator */
38817 + qh->desc_list[n_desc - 1].status.b.eol = 1;
38818 +
38819 + hc->ntd = n_desc;
38820 + }
38821 +}
38822 +
38823 +/**
38824 + * For Control and Bulk endpoints initializes descriptor list
38825 + * and starts the transfer.
38826 + *
38827 + * For Interrupt and Isochronous endpoints initializes descriptor list
38828 + * then updates FrameList, marking appropriate entries as active.
38829 + * In case of Isochronous, the starting descriptor index is calculated based
38830 + * on the scheduled frame, but only on the first transfer descriptor within a session.
38831 + * Then starts the transfer via enabling the channel.
38832 + * For Isochronous endpoint the channel is not halted on XferComplete
38833 + * interrupt so remains assigned to the endpoint(QH) until session is done.
38834 + *
38835 + * @param hcd The HCD state structure for the DWC OTG controller.
38836 + * @param qh The QH to init.
38837 + *
38838 + * @return 0 if successful, negative error code otherwise.
38839 + */
38840 +void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38841 +{
38842 + /* Channel is already assigned */
38843 + dwc_hc_t *hc = qh->channel;
38844 + uint8_t skip_frames = 0;
38845 +
38846 + switch (hc->ep_type) {
38847 + case DWC_OTG_EP_TYPE_CONTROL:
38848 + case DWC_OTG_EP_TYPE_BULK:
38849 + init_non_isoc_dma_desc(hcd, qh);
38850 +
38851 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
38852 + break;
38853 + case DWC_OTG_EP_TYPE_INTR:
38854 + init_non_isoc_dma_desc(hcd, qh);
38855 +
38856 + update_frame_list(hcd, qh, 1);
38857 +
38858 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
38859 + break;
38860 + case DWC_OTG_EP_TYPE_ISOC:
38861 +
38862 + if (!qh->ntd)
38863 + skip_frames = recalc_initial_desc_idx(hcd, qh);
38864 +
38865 + init_isoc_dma_desc(hcd, qh, skip_frames);
38866 +
38867 + if (!hc->xfer_started) {
38868 +
38869 + update_frame_list(hcd, qh, 1);
38870 +
38871 + /*
38872 + * Always set to max, instead of actual size.
38873 + * Otherwise ntd will be changed with
38874 + * channel being enabled. Not recommended.
38875 + *
38876 + */
38877 + hc->ntd = max_desc_num(qh);
38878 + /* Enable channel only once for ISOC */
38879 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
38880 + }
38881 +
38882 + break;
38883 + default:
38884 +
38885 + break;
38886 + }
38887 +}
38888 +
38889 +static void complete_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
38890 + dwc_hc_t * hc,
38891 + dwc_otg_hc_regs_t * hc_regs,
38892 + dwc_otg_halt_status_e halt_status)
38893 +{
38894 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
38895 + dwc_otg_qtd_t *qtd, *qtd_tmp;
38896 + dwc_otg_qh_t *qh;
38897 + dwc_otg_host_dma_desc_t *dma_desc;
38898 + uint16_t idx, remain;
38899 + uint8_t urb_compl;
38900 +
38901 + qh = hc->qh;
38902 + idx = qh->td_first;
38903 +
38904 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
38905 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
38906 + qtd->in_process = 0;
38907 + return;
38908 + } else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) ||
38909 + (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
38910 + /*
38911 + * Channel is halted in these error cases.
38912 + * Considered as serious issues.
38913 + * Complete all URBs marking all frames as failed,
38914 + * irrespective whether some of the descriptors(frames) succeeded or no.
38915 + * Pass error code to completion routine as well, to
38916 + * update urb->status, some of class drivers might use it to stop
38917 + * queing transfer requests.
38918 + */
38919 + int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR)
38920 + ? (-DWC_E_IO)
38921 + : (-DWC_E_OVERFLOW);
38922 +
38923 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
38924 + for (idx = 0; idx < qtd->urb->packet_count; idx++) {
38925 + frame_desc = &qtd->urb->iso_descs[idx];
38926 + frame_desc->status = err;
38927 + }
38928 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
38929 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
38930 + }
38931 + return;
38932 + }
38933 +
38934 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
38935 +
38936 + if (!qtd->in_process)
38937 + break;
38938 +
38939 + urb_compl = 0;
38940 +
38941 + do {
38942 +
38943 + dma_desc = &qh->desc_list[idx];
38944 +
38945 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
38946 + remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
38947 +
38948 + if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
38949 + /*
38950 + * XactError or, unable to complete all the transactions
38951 + * in the scheduled micro-frame/frame,
38952 + * both indicated by DMA_DESC_STS_PKTERR.
38953 + */
38954 + qtd->urb->error_count++;
38955 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
38956 + frame_desc->status = -DWC_E_PROTOCOL;
38957 + } else {
38958 + /* Success */
38959 +
38960 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
38961 + frame_desc->status = 0;
38962 + }
38963 +
38964 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
38965 + /*
38966 + * urb->status is not used for isoc transfers here.
38967 + * The individual frame_desc status are used instead.
38968 + */
38969 +
38970 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
38971 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
38972 +
38973 + /*
38974 + * This check is necessary because urb_dequeue can be called
38975 + * from urb complete callback(sound driver example).
38976 + * All pending URBs are dequeued there, so no need for
38977 + * further processing.
38978 + */
38979 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
38980 + return;
38981 + }
38982 +
38983 + urb_compl = 1;
38984 +
38985 + }
38986 +
38987 + qh->ntd--;
38988 +
38989 + /* Stop if IOC requested descriptor reached */
38990 + if (dma_desc->status.b_isoc.ioc) {
38991 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
38992 + goto stop_scan;
38993 + }
38994 +
38995 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
38996 +
38997 + if (urb_compl)
38998 + break;
38999 + }
39000 + while (idx != qh->td_first);
39001 + }
39002 +stop_scan:
39003 + qh->td_first = idx;
39004 +}
39005 +
39006 +uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
39007 + dwc_hc_t * hc,
39008 + dwc_otg_qtd_t * qtd,
39009 + dwc_otg_host_dma_desc_t * dma_desc,
39010 + dwc_otg_halt_status_e halt_status,
39011 + uint32_t n_bytes, uint8_t * xfer_done)
39012 +{
39013 +
39014 + uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
39015 + dwc_otg_hcd_urb_t *urb = qtd->urb;
39016 +
39017 + if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
39018 + urb->status = -DWC_E_IO;
39019 + return 1;
39020 + }
39021 + if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
39022 + switch (halt_status) {
39023 + case DWC_OTG_HC_XFER_STALL:
39024 + urb->status = -DWC_E_PIPE;
39025 + break;
39026 + case DWC_OTG_HC_XFER_BABBLE_ERR:
39027 + urb->status = -DWC_E_OVERFLOW;
39028 + break;
39029 + case DWC_OTG_HC_XFER_XACT_ERR:
39030 + urb->status = -DWC_E_PROTOCOL;
39031 + break;
39032 + default:
39033 + DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
39034 + halt_status);
39035 + break;
39036 + }
39037 + return 1;
39038 + }
39039 +
39040 + if (dma_desc->status.b.a == 1) {
39041 + DWC_DEBUGPL(DBG_HCDV,
39042 + "Active descriptor encountered on channel %d\n",
39043 + hc->hc_num);
39044 + return 0;
39045 + }
39046 +
39047 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
39048 + if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
39049 + urb->actual_length += n_bytes - remain;
39050 + if (remain || urb->actual_length == urb->length) {
39051 + /*
39052 + * For Control Data stage do not set urb->status=0 to prevent
39053 + * URB callback. Set it when Status phase done. See below.
39054 + */
39055 + *xfer_done = 1;
39056 + }
39057 +
39058 + } else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
39059 + urb->status = 0;
39060 + *xfer_done = 1;
39061 + }
39062 + /* No handling for SETUP stage */
39063 + } else {
39064 + /* BULK and INTR */
39065 + urb->actual_length += n_bytes - remain;
39066 + if (remain || urb->actual_length == urb->length) {
39067 + urb->status = 0;
39068 + *xfer_done = 1;
39069 + }
39070 + }
39071 +
39072 + return 0;
39073 +}
39074 +
39075 +static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
39076 + dwc_hc_t * hc,
39077 + dwc_otg_hc_regs_t * hc_regs,
39078 + dwc_otg_halt_status_e halt_status)
39079 +{
39080 + dwc_otg_hcd_urb_t *urb = NULL;
39081 + dwc_otg_qtd_t *qtd, *qtd_tmp;
39082 + dwc_otg_qh_t *qh;
39083 + dwc_otg_host_dma_desc_t *dma_desc;
39084 + uint32_t n_bytes, n_desc, i;
39085 + uint8_t failed = 0, xfer_done;
39086 +
39087 + n_desc = 0;
39088 +
39089 + qh = hc->qh;
39090 +
39091 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
39092 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
39093 + qtd->in_process = 0;
39094 + }
39095 + return;
39096 + }
39097 +
39098 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
39099 +
39100 + urb = qtd->urb;
39101 +
39102 + n_bytes = 0;
39103 + xfer_done = 0;
39104 +
39105 + for (i = 0; i < qtd->n_desc; i++) {
39106 + dma_desc = &qh->desc_list[n_desc];
39107 +
39108 + n_bytes = qh->n_bytes[n_desc];
39109 +
39110 + failed =
39111 + update_non_isoc_urb_state_ddma(hcd, hc, qtd,
39112 + dma_desc,
39113 + halt_status, n_bytes,
39114 + &xfer_done);
39115 +
39116 + if (failed
39117 + || (xfer_done
39118 + && (urb->status != -DWC_E_IN_PROGRESS))) {
39119 +
39120 + hcd->fops->complete(hcd, urb->priv, urb,
39121 + urb->status);
39122 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
39123 +
39124 + if (failed)
39125 + goto stop_scan;
39126 + } else if (qh->ep_type == UE_CONTROL) {
39127 + if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
39128 + if (urb->length > 0) {
39129 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
39130 + } else {
39131 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
39132 + }
39133 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n");
39134 + } else if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
39135 + if (xfer_done) {
39136 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
39137 + DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n");
39138 + } else if (i + 1 == qtd->n_desc) {
39139 + /*
39140 + * Last descriptor for Control data stage which is
39141 + * not completed yet.
39142 + */
39143 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
39144 + }
39145 + }
39146 + }
39147 +
39148 + n_desc++;
39149 + }
39150 +
39151 + }
39152 +
39153 +stop_scan:
39154 +
39155 + if (qh->ep_type != UE_CONTROL) {
39156 + /*
39157 + * Resetting the data toggle for bulk
39158 + * and interrupt endpoints in case of stall. See handle_hc_stall_intr()
39159 + */
39160 + if (halt_status == DWC_OTG_HC_XFER_STALL)
39161 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
39162 + else
39163 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
39164 + }
39165 +
39166 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
39167 + hcint_data_t hcint;
39168 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
39169 + if (hcint.b.nyet) {
39170 + /*
39171 + * Got a NYET on the last transaction of the transfer. It
39172 + * means that the endpoint should be in the PING state at the
39173 + * beginning of the next transfer.
39174 + */
39175 + qh->ping_state = 1;
39176 + clear_hc_int(hc_regs, nyet);
39177 + }
39178 +
39179 + }
39180 +
39181 +}
39182 +
39183 +/**
39184 + * This function is called from interrupt handlers.
39185 + * Scans the descriptor list, updates URB's status and
39186 + * calls completion routine for the URB if it's done.
39187 + * Releases the channel to be used by other transfers.
39188 + * In case of Isochronous endpoint the channel is not halted until
39189 + * the end of the session, i.e. QTD list is empty.
39190 + * If periodic channel released the FrameList is updated accordingly.
39191 + *
39192 + * Calls transaction selection routines to activate pending transfers.
39193 + *
39194 + * @param hcd The HCD state structure for the DWC OTG controller.
39195 + * @param hc Host channel, the transfer is completed on.
39196 + * @param hc_regs Host channel registers.
39197 + * @param halt_status Reason the channel is being halted,
39198 + * or just XferComplete for isochronous transfer
39199 + */
39200 +void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
39201 + dwc_hc_t * hc,
39202 + dwc_otg_hc_regs_t * hc_regs,
39203 + dwc_otg_halt_status_e halt_status)
39204 +{
39205 + uint8_t continue_isoc_xfer = 0;
39206 + dwc_otg_transaction_type_e tr_type;
39207 + dwc_otg_qh_t *qh = hc->qh;
39208 +
39209 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
39210 +
39211 + complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
39212 +
39213 + /* Release the channel if halted or session completed */
39214 + if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
39215 + DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
39216 +
39217 + /* Halt the channel if session completed */
39218 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
39219 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
39220 + }
39221 +
39222 + release_channel_ddma(hcd, qh);
39223 + dwc_otg_hcd_qh_remove(hcd, qh);
39224 + } else {
39225 + /* Keep in assigned schedule to continue transfer */
39226 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
39227 + &qh->qh_list_entry);
39228 + continue_isoc_xfer = 1;
39229 +
39230 + }
39231 + /** @todo Consider the case when period exceeds FrameList size.
39232 + * Frame Rollover interrupt should be used.
39233 + */
39234 + } else {
39235 + /* Scan descriptor list to complete the URB(s), then release the channel */
39236 + complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
39237 +
39238 + release_channel_ddma(hcd, qh);
39239 + dwc_otg_hcd_qh_remove(hcd, qh);
39240 +
39241 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
39242 + /* Add back to inactive non-periodic schedule on normal completion */
39243 + dwc_otg_hcd_qh_add(hcd, qh);
39244 + }
39245 +
39246 + }
39247 + tr_type = dwc_otg_hcd_select_transactions(hcd);
39248 + if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
39249 + if (continue_isoc_xfer) {
39250 + if (tr_type == DWC_OTG_TRANSACTION_NONE) {
39251 + tr_type = DWC_OTG_TRANSACTION_PERIODIC;
39252 + } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
39253 + tr_type = DWC_OTG_TRANSACTION_ALL;
39254 + }
39255 + }
39256 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
39257 + }
39258 +}
39259 +
39260 +#endif /* DWC_DEVICE_ONLY */
39261 --- /dev/null
39262 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
39263 @@ -0,0 +1,412 @@
39264 +/* ==========================================================================
39265 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $
39266 + * $Revision: #12 $
39267 + * $Date: 2011/10/26 $
39268 + * $Change: 1873028 $
39269 + *
39270 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
39271 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
39272 + * otherwise expressly agreed to in writing between Synopsys and you.
39273 + *
39274 + * The Software IS NOT an item of Licensed Software or Licensed Product under
39275 + * any End User Software License Agreement or Agreement for Licensed Product
39276 + * with Synopsys or any supplement thereto. You are permitted to use and
39277 + * redistribute this Software in source and binary forms, with or without
39278 + * modification, provided that redistributions of source code must retain this
39279 + * notice. You may not view, use, disclose, copy or distribute this file or
39280 + * any information contained herein except pursuant to this license grant from
39281 + * Synopsys. If you do not agree with this notice, including the disclaimer
39282 + * below, then you are not authorized to use the Software.
39283 + *
39284 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
39285 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39286 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39287 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
39288 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39289 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39290 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39291 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39292 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39293 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39294 + * DAMAGE.
39295 + * ========================================================================== */
39296 +#ifndef DWC_DEVICE_ONLY
39297 +#ifndef __DWC_HCD_IF_H__
39298 +#define __DWC_HCD_IF_H__
39299 +
39300 +#include "dwc_otg_core_if.h"
39301 +
39302 +/** @file
39303 + * This file defines DWC_OTG HCD Core API.
39304 + */
39305 +
39306 +struct dwc_otg_hcd;
39307 +typedef struct dwc_otg_hcd dwc_otg_hcd_t;
39308 +
39309 +struct dwc_otg_hcd_urb;
39310 +typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t;
39311 +
39312 +/** @name HCD Function Driver Callbacks */
39313 +/** @{ */
39314 +
39315 +/** This function is called whenever core switches to host mode. */
39316 +typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd);
39317 +
39318 +/** This function is called when device has been disconnected */
39319 +typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd);
39320 +
39321 +/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */
39322 +typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
39323 + void *urb_handle,
39324 + uint32_t * hub_addr,
39325 + uint32_t * port_addr);
39326 +/** Via this function HCD core gets device speed */
39327 +typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
39328 + void *urb_handle);
39329 +
39330 +/** This function is called when urb is completed */
39331 +typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd,
39332 + void *urb_handle,
39333 + dwc_otg_hcd_urb_t * dwc_otg_urb,
39334 + int32_t status);
39335 +
39336 +/** Via this function HCD core gets b_hnp_enable parameter */
39337 +typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd);
39338 +
39339 +struct dwc_otg_hcd_function_ops {
39340 + dwc_otg_hcd_start_cb_t start;
39341 + dwc_otg_hcd_disconnect_cb_t disconnect;
39342 + dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
39343 + dwc_otg_hcd_speed_from_urb_cb_t speed;
39344 + dwc_otg_hcd_complete_urb_cb_t complete;
39345 + dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
39346 +};
39347 +/** @} */
39348 +
39349 +/** @name HCD Core API */
39350 +/** @{ */
39351 +/** This function allocates dwc_otg_hcd structure and returns pointer on it. */
39352 +extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void);
39353 +
39354 +/** This function should be called to initiate HCD Core.
39355 + *
39356 + * @param hcd The HCD
39357 + * @param core_if The DWC_OTG Core
39358 + *
39359 + * Returns -DWC_E_NO_MEMORY if no enough memory.
39360 + * Returns 0 on success
39361 + */
39362 +extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if);
39363 +
39364 +/** Frees HCD
39365 + *
39366 + * @param hcd The HCD
39367 + */
39368 +extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
39369 +
39370 +/** This function should be called on every hardware interrupt.
39371 + *
39372 + * @param dwc_otg_hcd The HCD
39373 + *
39374 + * Returns non zero if interrupt is handled
39375 + * Return 0 if interrupt is not handled
39376 + */
39377 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
39378 +
39379 +/**
39380 + * Returns private data set by
39381 + * dwc_otg_hcd_set_priv_data function.
39382 + *
39383 + * @param hcd The HCD
39384 + */
39385 +extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd);
39386 +
39387 +/**
39388 + * Set private data.
39389 + *
39390 + * @param hcd The HCD
39391 + * @param priv_data pointer to be stored in private data
39392 + */
39393 +extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data);
39394 +
39395 +/**
39396 + * This function initializes the HCD Core.
39397 + *
39398 + * @param hcd The HCD
39399 + * @param fops The Function Driver Operations data structure containing pointers to all callbacks.
39400 + *
39401 + * Returns -DWC_E_NO_DEVICE if Core is currently is in device mode.
39402 + * Returns 0 on success
39403 + */
39404 +extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
39405 + struct dwc_otg_hcd_function_ops *fops);
39406 +
39407 +/**
39408 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
39409 + * stopped.
39410 + *
39411 + * @param hcd The HCD
39412 + */
39413 +extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd);
39414 +
39415 +/**
39416 + * Handles hub class-specific requests.
39417 + *
39418 + * @param dwc_otg_hcd The HCD
39419 + * @param typeReq Request Type
39420 + * @param wValue wValue from control request
39421 + * @param wIndex wIndex from control request
39422 + * @param buf data buffer
39423 + * @param wLength data buffer length
39424 + *
39425 + * Returns -DWC_E_INVALID if invalid argument is passed
39426 + * Returns 0 on success
39427 + */
39428 +extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
39429 + uint16_t typeReq, uint16_t wValue,
39430 + uint16_t wIndex, uint8_t * buf,
39431 + uint16_t wLength);
39432 +
39433 +/**
39434 + * Returns otg port number.
39435 + *
39436 + * @param hcd The HCD
39437 + */
39438 +extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd);
39439 +
39440 +/**
39441 + * Returns OTG version - either 1.3 or 2.0.
39442 + *
39443 + * @param core_if The core_if structure pointer
39444 + */
39445 +extern uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if);
39446 +
39447 +/**
39448 + * Returns 1 if currently core is acting as B host, and 0 otherwise.
39449 + *
39450 + * @param hcd The HCD
39451 + */
39452 +extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd);
39453 +
39454 +/**
39455 + * Returns current frame number.
39456 + *
39457 + * @param hcd The HCD
39458 + */
39459 +extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd);
39460 +
39461 +/**
39462 + * Dumps hcd state.
39463 + *
39464 + * @param hcd The HCD
39465 + */
39466 +extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd);
39467 +
39468 +/**
39469 + * Dump the average frame remaining at SOF. This can be used to
39470 + * determine average interrupt latency. Frame remaining is also shown for
39471 + * start transfer and two additional sample points.
39472 + * Currently this function is not implemented.
39473 + *
39474 + * @param hcd The HCD
39475 + */
39476 +extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd);
39477 +
39478 +/**
39479 + * Sends LPM transaction to the local device.
39480 + *
39481 + * @param hcd The HCD
39482 + * @param devaddr Device Address
39483 + * @param hird Host initiated resume duration
39484 + * @param bRemoteWake Value of bRemoteWake field in LPM transaction
39485 + *
39486 + * Returns negative value if sending LPM transaction was not succeeded.
39487 + * Returns 0 on success.
39488 + */
39489 +extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr,
39490 + uint8_t hird, uint8_t bRemoteWake);
39491 +
39492 +/* URB interface */
39493 +
39494 +/**
39495 + * Allocates memory for dwc_otg_hcd_urb structure.
39496 + * Allocated memory should be freed by call of DWC_FREE.
39497 + *
39498 + * @param hcd The HCD
39499 + * @param iso_desc_count Count of ISOC descriptors
39500 + * @param atomic_alloc Specefies whether to perform atomic allocation.
39501 + */
39502 +extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
39503 + int iso_desc_count,
39504 + int atomic_alloc);
39505 +
39506 +/**
39507 + * Set pipe information in URB.
39508 + *
39509 + * @param hcd_urb DWC_OTG URB
39510 + * @param devaddr Device Address
39511 + * @param ep_num Endpoint Number
39512 + * @param ep_type Endpoint Type
39513 + * @param ep_dir Endpoint Direction
39514 + * @param mps Max Packet Size
39515 + */
39516 +extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb,
39517 + uint8_t devaddr, uint8_t ep_num,
39518 + uint8_t ep_type, uint8_t ep_dir,
39519 + uint16_t mps);
39520 +
39521 +/* Transfer flags */
39522 +#define URB_GIVEBACK_ASAP 0x1
39523 +#define URB_SEND_ZERO_PACKET 0x2
39524 +
39525 +/**
39526 + * Sets dwc_otg_hcd_urb parameters.
39527 + *
39528 + * @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
39529 + * @param urb_handle Unique handle for request, this will be passed back
39530 + * to function driver in completion callback.
39531 + * @param buf The buffer for the data
39532 + * @param dma The DMA buffer for the data
39533 + * @param buflen Transfer length
39534 + * @param sp Buffer for setup data
39535 + * @param sp_dma DMA address of setup data buffer
39536 + * @param flags Transfer flags
39537 + * @param interval Polling interval for interrupt or isochronous transfers.
39538 + */
39539 +extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb,
39540 + void *urb_handle, void *buf,
39541 + dwc_dma_t dma, uint32_t buflen, void *sp,
39542 + dwc_dma_t sp_dma, uint32_t flags,
39543 + uint16_t interval);
39544 +
39545 +/** Gets status from dwc_otg_hcd_urb
39546 + *
39547 + * @param dwc_otg_urb DWC_OTG URB
39548 + */
39549 +extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb);
39550 +
39551 +/** Gets actual length from dwc_otg_hcd_urb
39552 + *
39553 + * @param dwc_otg_urb DWC_OTG URB
39554 + */
39555 +extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t *
39556 + dwc_otg_urb);
39557 +
39558 +/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs
39559 + *
39560 + * @param dwc_otg_urb DWC_OTG URB
39561 + */
39562 +extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t *
39563 + dwc_otg_urb);
39564 +
39565 +/** Set ISOC descriptor offset and length
39566 + *
39567 + * @param dwc_otg_urb DWC_OTG URB
39568 + * @param desc_num ISOC descriptor number
39569 + * @param offset Offset from beginig of buffer.
39570 + * @param length Transaction length
39571 + */
39572 +extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
39573 + int desc_num, uint32_t offset,
39574 + uint32_t length);
39575 +
39576 +/** Get status of ISOC descriptor, specified by desc_num
39577 + *
39578 + * @param dwc_otg_urb DWC_OTG URB
39579 + * @param desc_num ISOC descriptor number
39580 + */
39581 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t *
39582 + dwc_otg_urb, int desc_num);
39583 +
39584 +/** Get actual length of ISOC descriptor, specified by desc_num
39585 + *
39586 + * @param dwc_otg_urb DWC_OTG URB
39587 + * @param desc_num ISOC descriptor number
39588 + */
39589 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
39590 + dwc_otg_urb,
39591 + int desc_num);
39592 +
39593 +/** Queue URB. After transfer is completes, the complete callback will be called with the URB status
39594 + *
39595 + * @param dwc_otg_hcd The HCD
39596 + * @param dwc_otg_urb DWC_OTG URB
39597 + * @param ep_handle Out parameter for returning endpoint handle
39598 + * @param atomic_alloc Flag to do atomic allocation if needed
39599 + *
39600 + * Returns -DWC_E_NO_DEVICE if no device is connected.
39601 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
39602 + * Returns 0 on success.
39603 + */
39604 +extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd,
39605 + dwc_otg_hcd_urb_t * dwc_otg_urb,
39606 + void **ep_handle, int atomic_alloc);
39607 +
39608 +/** De-queue the specified URB
39609 + *
39610 + * @param dwc_otg_hcd The HCD
39611 + * @param dwc_otg_urb DWC_OTG URB
39612 + */
39613 +extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd,
39614 + dwc_otg_hcd_urb_t * dwc_otg_urb);
39615 +
39616 +/** Frees resources in the DWC_otg controller related to a given endpoint.
39617 + * Any URBs for the endpoint must already be dequeued.
39618 + *
39619 + * @param hcd The HCD
39620 + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
39621 + * @param retry Number of retries if there are queued transfers.
39622 + *
39623 + * Returns -DWC_E_INVALID if invalid arguments are passed.
39624 + * Returns 0 on success
39625 + */
39626 +extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
39627 + int retry);
39628 +
39629 +/* Resets the data toggle in qh structure. This function can be called from
39630 + * usb_clear_halt routine.
39631 + *
39632 + * @param hcd The HCD
39633 + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
39634 + *
39635 + * Returns -DWC_E_INVALID if invalid arguments are passed.
39636 + * Returns 0 on success
39637 + */
39638 +extern int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle);
39639 +
39640 +/** Returns 1 if status of specified port is changed and 0 otherwise.
39641 + *
39642 + * @param hcd The HCD
39643 + * @param port Port number
39644 + */
39645 +extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port);
39646 +
39647 +/** Call this function to check if bandwidth was allocated for specified endpoint.
39648 + * Only for ISOC and INTERRUPT endpoints.
39649 + *
39650 + * @param hcd The HCD
39651 + * @param ep_handle Endpoint handle
39652 + */
39653 +extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd,
39654 + void *ep_handle);
39655 +
39656 +/** Call this function to check if bandwidth was freed for specified endpoint.
39657 + *
39658 + * @param hcd The HCD
39659 + * @param ep_handle Endpoint handle
39660 + */
39661 +extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle);
39662 +
39663 +/** Returns bandwidth allocated for specified endpoint in microseconds.
39664 + * Only for ISOC and INTERRUPT endpoints.
39665 + *
39666 + * @param hcd The HCD
39667 + * @param ep_handle Endpoint handle
39668 + */
39669 +extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd,
39670 + void *ep_handle);
39671 +
39672 +/** @} */
39673 +
39674 +#endif /* __DWC_HCD_IF_H__ */
39675 +#endif /* DWC_DEVICE_ONLY */
39676 --- /dev/null
39677 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
39678 @@ -0,0 +1,2106 @@
39679 +/* ==========================================================================
39680 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $
39681 + * $Revision: #89 $
39682 + * $Date: 2011/10/20 $
39683 + * $Change: 1869487 $
39684 + *
39685 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
39686 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
39687 + * otherwise expressly agreed to in writing between Synopsys and you.
39688 + *
39689 + * The Software IS NOT an item of Licensed Software or Licensed Product under
39690 + * any End User Software License Agreement or Agreement for Licensed Product
39691 + * with Synopsys or any supplement thereto. You are permitted to use and
39692 + * redistribute this Software in source and binary forms, with or without
39693 + * modification, provided that redistributions of source code must retain this
39694 + * notice. You may not view, use, disclose, copy or distribute this file or
39695 + * any information contained herein except pursuant to this license grant from
39696 + * Synopsys. If you do not agree with this notice, including the disclaimer
39697 + * below, then you are not authorized to use the Software.
39698 + *
39699 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
39700 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39701 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39702 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
39703 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39704 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39705 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39706 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39707 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39708 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39709 + * DAMAGE.
39710 + * ========================================================================== */
39711 +#ifndef DWC_DEVICE_ONLY
39712 +
39713 +#include "dwc_otg_hcd.h"
39714 +#include "dwc_otg_regs.h"
39715 +
39716 +extern bool microframe_schedule;
39717 +
39718 +/** @file
39719 + * This file contains the implementation of the HCD Interrupt handlers.
39720 + */
39721 +
39722 +/** This function handles interrupts for the HCD. */
39723 +int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39724 +{
39725 + int retval = 0;
39726 +
39727 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
39728 + gintsts_data_t gintsts;
39729 +#ifdef DEBUG
39730 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
39731 +
39732 + //GRAYG: debugging
39733 + if (NULL == global_regs) {
39734 + DWC_DEBUGPL(DBG_HCD, "**** NULL regs: dwc_otg_hcd=%p "
39735 + "core_if=%p\n",
39736 + dwc_otg_hcd, global_regs);
39737 + return retval;
39738 + }
39739 +#endif
39740 +
39741 + /* Exit from ISR if core is hibernated */
39742 + if (core_if->hibernation_suspend == 1) {
39743 + return retval;
39744 + }
39745 + DWC_SPINLOCK(dwc_otg_hcd->lock);
39746 + /* Check if HOST Mode */
39747 + if (dwc_otg_is_host_mode(core_if)) {
39748 + gintsts.d32 = dwc_otg_read_core_intr(core_if);
39749 + if (!gintsts.d32) {
39750 + DWC_SPINUNLOCK(dwc_otg_hcd->lock);
39751 + return 0;
39752 + }
39753 +#ifdef DEBUG
39754 + /* Don't print debug message in the interrupt handler on SOF */
39755 +#ifndef DEBUG_SOF
39756 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39757 +#endif
39758 + DWC_DEBUGPL(DBG_HCDI, "\n");
39759 +#endif
39760 +
39761 +#ifdef DEBUG
39762 +#ifndef DEBUG_SOF
39763 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39764 +#endif
39765 + DWC_DEBUGPL(DBG_HCDI,
39766 + "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n",
39767 + gintsts.d32, core_if);
39768 +#endif
39769 +
39770 + if (gintsts.b.sofintr) {
39771 + retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
39772 + }
39773 + if (gintsts.b.rxstsqlvl) {
39774 + retval |=
39775 + dwc_otg_hcd_handle_rx_status_q_level_intr
39776 + (dwc_otg_hcd);
39777 + }
39778 + if (gintsts.b.nptxfempty) {
39779 + retval |=
39780 + dwc_otg_hcd_handle_np_tx_fifo_empty_intr
39781 + (dwc_otg_hcd);
39782 + }
39783 + if (gintsts.b.i2cintr) {
39784 + /** @todo Implement i2cintr handler. */
39785 + }
39786 + if (gintsts.b.portintr) {
39787 + retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
39788 + }
39789 + if (gintsts.b.hcintr) {
39790 + retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
39791 + }
39792 + if (gintsts.b.ptxfempty) {
39793 + retval |=
39794 + dwc_otg_hcd_handle_perio_tx_fifo_empty_intr
39795 + (dwc_otg_hcd);
39796 + }
39797 +#ifdef DEBUG
39798 +#ifndef DEBUG_SOF
39799 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39800 +#endif
39801 + {
39802 + DWC_DEBUGPL(DBG_HCDI,
39803 + "DWC OTG HCD Finished Servicing Interrupts\n");
39804 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
39805 + DWC_READ_REG32(&global_regs->gintsts));
39806 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
39807 + DWC_READ_REG32(&global_regs->gintmsk));
39808 + }
39809 +#endif
39810 +
39811 +#ifdef DEBUG
39812 +#ifndef DEBUG_SOF
39813 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39814 +#endif
39815 + DWC_DEBUGPL(DBG_HCDI, "\n");
39816 +#endif
39817 +
39818 + }
39819 + DWC_SPINUNLOCK(dwc_otg_hcd->lock);
39820 + return retval;
39821 +}
39822 +
39823 +#ifdef DWC_TRACK_MISSED_SOFS
39824 +#warning Compiling code to track missed SOFs
39825 +#define FRAME_NUM_ARRAY_SIZE 1000
39826 +/**
39827 + * This function is for debug only.
39828 + */
39829 +static inline void track_missed_sofs(uint16_t curr_frame_number)
39830 +{
39831 + static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
39832 + static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
39833 + static int frame_num_idx = 0;
39834 + static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
39835 + static int dumped_frame_num_array = 0;
39836 +
39837 + if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
39838 + if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
39839 + curr_frame_number) {
39840 + frame_num_array[frame_num_idx] = curr_frame_number;
39841 + last_frame_num_array[frame_num_idx++] = last_frame_num;
39842 + }
39843 + } else if (!dumped_frame_num_array) {
39844 + int i;
39845 + DWC_PRINTF("Frame Last Frame\n");
39846 + DWC_PRINTF("----- ----------\n");
39847 + for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
39848 + DWC_PRINTF("0x%04x 0x%04x\n",
39849 + frame_num_array[i], last_frame_num_array[i]);
39850 + }
39851 + dumped_frame_num_array = 1;
39852 + }
39853 + last_frame_num = curr_frame_number;
39854 +}
39855 +#endif
39856 +
39857 +/**
39858 + * Handles the start-of-frame interrupt in host mode. Non-periodic
39859 + * transactions may be queued to the DWC_otg controller for the current
39860 + * (micro)frame. Periodic transactions may be queued to the controller for the
39861 + * next (micro)frame.
39862 + */
39863 +int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd)
39864 +{
39865 + hfnum_data_t hfnum;
39866 + dwc_list_link_t *qh_entry;
39867 + dwc_otg_qh_t *qh;
39868 + dwc_otg_transaction_type_e tr_type;
39869 + gintsts_data_t gintsts = {.d32 = 0 };
39870 +
39871 + hfnum.d32 =
39872 + DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
39873 +
39874 +#ifdef DEBUG_SOF
39875 + DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
39876 +#endif
39877 + hcd->frame_number = hfnum.b.frnum;
39878 +
39879 +#ifdef DEBUG
39880 + hcd->frrem_accum += hfnum.b.frrem;
39881 + hcd->frrem_samples++;
39882 +#endif
39883 +
39884 +#ifdef DWC_TRACK_MISSED_SOFS
39885 + track_missed_sofs(hcd->frame_number);
39886 +#endif
39887 + /* Determine whether any periodic QHs should be executed. */
39888 + qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive);
39889 + while (qh_entry != &hcd->periodic_sched_inactive) {
39890 + qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry);
39891 + qh_entry = qh_entry->next;
39892 + if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
39893 + /*
39894 + * Move QH to the ready list to be executed next
39895 + * (micro)frame.
39896 + */
39897 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
39898 + &qh->qh_list_entry);
39899 + }
39900 + }
39901 + tr_type = dwc_otg_hcd_select_transactions(hcd);
39902 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
39903 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
39904 + }
39905 +
39906 + /* Clear interrupt */
39907 + gintsts.b.sofintr = 1;
39908 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
39909 +
39910 + return 1;
39911 +}
39912 +
39913 +/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at
39914 + * least one packet in the Rx FIFO. The packets are moved from the FIFO to
39915 + * memory if the DWC_otg controller is operating in Slave mode. */
39916 +int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39917 +{
39918 + host_grxsts_data_t grxsts;
39919 + dwc_hc_t *hc = NULL;
39920 +
39921 + DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
39922 +
39923 + grxsts.d32 =
39924 + DWC_READ_REG32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp);
39925 +
39926 + hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
39927 + if (!hc) {
39928 + DWC_ERROR("Unable to get corresponding channel\n");
39929 + return 0;
39930 + }
39931 +
39932 + /* Packet Status */
39933 + DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum);
39934 + DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt);
39935 + DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid,
39936 + hc->data_pid_start);
39937 + DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts);
39938 +
39939 + switch (grxsts.b.pktsts) {
39940 + case DWC_GRXSTS_PKTSTS_IN:
39941 + /* Read the data into the host buffer. */
39942 + if (grxsts.b.bcnt > 0) {
39943 + dwc_otg_read_packet(dwc_otg_hcd->core_if,
39944 + hc->xfer_buff, grxsts.b.bcnt);
39945 +
39946 + /* Update the HC fields for the next packet received. */
39947 + hc->xfer_count += grxsts.b.bcnt;
39948 + hc->xfer_buff += grxsts.b.bcnt;
39949 + }
39950 +
39951 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
39952 + case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
39953 + case DWC_GRXSTS_PKTSTS_CH_HALTED:
39954 + /* Handled in interrupt, just ignore data */
39955 + break;
39956 + default:
39957 + DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n",
39958 + grxsts.b.pktsts);
39959 + break;
39960 + }
39961 +
39962 + return 1;
39963 +}
39964 +
39965 +/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
39966 + * data packets may be written to the FIFO for OUT transfers. More requests
39967 + * may be written to the non-periodic request queue for IN transfers. This
39968 + * interrupt is enabled only in Slave mode. */
39969 +int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39970 +{
39971 + DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
39972 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
39973 + DWC_OTG_TRANSACTION_NON_PERIODIC);
39974 + return 1;
39975 +}
39976 +
39977 +/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data
39978 + * packets may be written to the FIFO for OUT transfers. More requests may be
39979 + * written to the periodic request queue for IN transfers. This interrupt is
39980 + * enabled only in Slave mode. */
39981 +int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39982 +{
39983 + DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
39984 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
39985 + DWC_OTG_TRANSACTION_PERIODIC);
39986 + return 1;
39987 +}
39988 +
39989 +/** There are multiple conditions that can cause a port interrupt. This function
39990 + * determines which interrupt conditions have occurred and handles them
39991 + * appropriately. */
39992 +int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39993 +{
39994 + int retval = 0;
39995 + hprt0_data_t hprt0;
39996 + hprt0_data_t hprt0_modify;
39997 +
39998 + hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
39999 + hprt0_modify.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
40000 +
40001 + /* Clear appropriate bits in HPRT0 to clear the interrupt bit in
40002 + * GINTSTS */
40003 +
40004 + hprt0_modify.b.prtena = 0;
40005 + hprt0_modify.b.prtconndet = 0;
40006 + hprt0_modify.b.prtenchng = 0;
40007 + hprt0_modify.b.prtovrcurrchng = 0;
40008 +
40009 + /* Port Connect Detected
40010 + * Set flag and clear if detected */
40011 + if (dwc_otg_hcd->core_if->hibernation_suspend == 1) {
40012 + // Dont modify port status if we are in hibernation state
40013 + hprt0_modify.b.prtconndet = 1;
40014 + hprt0_modify.b.prtenchng = 1;
40015 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
40016 + hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
40017 + return retval;
40018 + }
40019 +
40020 + if (hprt0.b.prtconndet) {
40021 + /** @todo - check if steps performed in 'else' block should be perfromed regardles adp */
40022 + if (dwc_otg_hcd->core_if->adp_enable &&
40023 + dwc_otg_hcd->core_if->adp.vbuson_timer_started == 1) {
40024 + DWC_PRINTF("PORT CONNECT DETECTED ----------------\n");
40025 + DWC_TIMER_CANCEL(dwc_otg_hcd->core_if->adp.vbuson_timer);
40026 + dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
40027 + /* TODO - check if this is required, as
40028 + * host initialization was already performed
40029 + * after initial ADP probing
40030 + */
40031 + /*dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
40032 + dwc_otg_core_init(dwc_otg_hcd->core_if);
40033 + dwc_otg_enable_global_interrupts(dwc_otg_hcd->core_if);
40034 + cil_hcd_start(dwc_otg_hcd->core_if);*/
40035 + } else {
40036 +
40037 + DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
40038 + "Port Connect Detected--\n", hprt0.d32);
40039 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
40040 + dwc_otg_hcd->flags.b.port_connect_status = 1;
40041 + hprt0_modify.b.prtconndet = 1;
40042 +
40043 + /* B-Device has connected, Delete the connection timer. */
40044 + DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer);
40045 + }
40046 + /* The Hub driver asserts a reset when it sees port connect
40047 + * status change flag */
40048 + retval |= 1;
40049 + }
40050 +
40051 + /* Port Enable Changed
40052 + * Clear if detected - Set internal flag if disabled */
40053 + if (hprt0.b.prtenchng) {
40054 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
40055 + "Port Enable Changed--\n", hprt0.d32);
40056 + hprt0_modify.b.prtenchng = 1;
40057 + if (hprt0.b.prtena == 1) {
40058 + hfir_data_t hfir;
40059 + int do_reset = 0;
40060 + dwc_otg_core_params_t *params =
40061 + dwc_otg_hcd->core_if->core_params;
40062 + dwc_otg_core_global_regs_t *global_regs =
40063 + dwc_otg_hcd->core_if->core_global_regs;
40064 + dwc_otg_host_if_t *host_if =
40065 + dwc_otg_hcd->core_if->host_if;
40066 +
40067 + /* Every time when port enables calculate
40068 + * HFIR.FrInterval
40069 + */
40070 + hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
40071 + hfir.b.frint = calc_frame_interval(dwc_otg_hcd->core_if);
40072 + DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
40073 +
40074 + /* Check if we need to adjust the PHY clock speed for
40075 + * low power and adjust it */
40076 + if (params->host_support_fs_ls_low_power) {
40077 + gusbcfg_data_t usbcfg;
40078 +
40079 + usbcfg.d32 =
40080 + DWC_READ_REG32(&global_regs->gusbcfg);
40081 +
40082 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED
40083 + || hprt0.b.prtspd ==
40084 + DWC_HPRT0_PRTSPD_FULL_SPEED) {
40085 + /*
40086 + * Low power
40087 + */
40088 + hcfg_data_t hcfg;
40089 + if (usbcfg.b.phylpwrclksel == 0) {
40090 + /* Set PHY low power clock select for FS/LS devices */
40091 + usbcfg.b.phylpwrclksel = 1;
40092 + DWC_WRITE_REG32
40093 + (&global_regs->gusbcfg,
40094 + usbcfg.d32);
40095 + do_reset = 1;
40096 + }
40097 +
40098 + hcfg.d32 =
40099 + DWC_READ_REG32
40100 + (&host_if->host_global_regs->hcfg);
40101 +
40102 + if (hprt0.b.prtspd ==
40103 + DWC_HPRT0_PRTSPD_LOW_SPEED
40104 + && params->host_ls_low_power_phy_clk
40105 + ==
40106 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)
40107 + {
40108 + /* 6 MHZ */
40109 + DWC_DEBUGPL(DBG_CIL,
40110 + "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
40111 + if (hcfg.b.fslspclksel !=
40112 + DWC_HCFG_6_MHZ) {
40113 + hcfg.b.fslspclksel =
40114 + DWC_HCFG_6_MHZ;
40115 + DWC_WRITE_REG32
40116 + (&host_if->host_global_regs->hcfg,
40117 + hcfg.d32);
40118 + do_reset = 1;
40119 + }
40120 + } else {
40121 + /* 48 MHZ */
40122 + DWC_DEBUGPL(DBG_CIL,
40123 + "FS_PHY programming HCFG to 48 MHz ()\n");
40124 + if (hcfg.b.fslspclksel !=
40125 + DWC_HCFG_48_MHZ) {
40126 + hcfg.b.fslspclksel =
40127 + DWC_HCFG_48_MHZ;
40128 + DWC_WRITE_REG32
40129 + (&host_if->host_global_regs->hcfg,
40130 + hcfg.d32);
40131 + do_reset = 1;
40132 + }
40133 + }
40134 + } else {
40135 + /*
40136 + * Not low power
40137 + */
40138 + if (usbcfg.b.phylpwrclksel == 1) {
40139 + usbcfg.b.phylpwrclksel = 0;
40140 + DWC_WRITE_REG32
40141 + (&global_regs->gusbcfg,
40142 + usbcfg.d32);
40143 + do_reset = 1;
40144 + }
40145 + }
40146 +
40147 + if (do_reset) {
40148 + DWC_TASK_SCHEDULE(dwc_otg_hcd->reset_tasklet);
40149 + }
40150 + }
40151 +
40152 + if (!do_reset) {
40153 + /* Port has been enabled set the reset change flag */
40154 + dwc_otg_hcd->flags.b.port_reset_change = 1;
40155 + }
40156 + } else {
40157 + dwc_otg_hcd->flags.b.port_enable_change = 1;
40158 + }
40159 + retval |= 1;
40160 + }
40161 +
40162 + /** Overcurrent Change Interrupt */
40163 + if (hprt0.b.prtovrcurrchng) {
40164 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
40165 + "Port Overcurrent Changed--\n", hprt0.d32);
40166 + dwc_otg_hcd->flags.b.port_over_current_change = 1;
40167 + hprt0_modify.b.prtovrcurrchng = 1;
40168 + retval |= 1;
40169 + }
40170 +
40171 + /* Clear Port Interrupts */
40172 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
40173 +
40174 + return retval;
40175 +}
40176 +
40177 +/** This interrupt indicates that one or more host channels has a pending
40178 + * interrupt. There are multiple conditions that can cause each host channel
40179 + * interrupt. This function determines which conditions have occurred for each
40180 + * host channel interrupt and handles them appropriately. */
40181 +int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40182 +{
40183 + int i;
40184 + int retval = 0;
40185 + haint_data_t haint;
40186 +
40187 + /* Clear appropriate bits in HCINTn to clear the interrupt bit in
40188 + * GINTSTS */
40189 +
40190 + haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
40191 +
40192 + for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
40193 + if (haint.b2.chint & (1 << i)) {
40194 + retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
40195 + }
40196 + }
40197 +
40198 + return retval;
40199 +}
40200 +
40201 +/**
40202 + * Gets the actual length of a transfer after the transfer halts. _halt_status
40203 + * holds the reason for the halt.
40204 + *
40205 + * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE,
40206 + * *short_read is set to 1 upon return if less than the requested
40207 + * number of bytes were transferred. Otherwise, *short_read is set to 0 upon
40208 + * return. short_read may also be NULL on entry, in which case it remains
40209 + * unchanged.
40210 + */
40211 +static uint32_t get_actual_xfer_length(dwc_hc_t * hc,
40212 + dwc_otg_hc_regs_t * hc_regs,
40213 + dwc_otg_qtd_t * qtd,
40214 + dwc_otg_halt_status_e halt_status,
40215 + int *short_read)
40216 +{
40217 + hctsiz_data_t hctsiz;
40218 + uint32_t length;
40219 +
40220 + if (short_read != NULL) {
40221 + *short_read = 0;
40222 + }
40223 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40224 +
40225 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
40226 + if (hc->ep_is_in) {
40227 + length = hc->xfer_len - hctsiz.b.xfersize;
40228 + if (short_read != NULL) {
40229 + *short_read = (hctsiz.b.xfersize != 0);
40230 + }
40231 + } else if (hc->qh->do_split) {
40232 + length = qtd->ssplit_out_xfer_count;
40233 + } else {
40234 + length = hc->xfer_len;
40235 + }
40236 + } else {
40237 + /*
40238 + * Must use the hctsiz.pktcnt field to determine how much data
40239 + * has been transferred. This field reflects the number of
40240 + * packets that have been transferred via the USB. This is
40241 + * always an integral number of packets if the transfer was
40242 + * halted before its normal completion. (Can't use the
40243 + * hctsiz.xfersize field because that reflects the number of
40244 + * bytes transferred via the AHB, not the USB).
40245 + */
40246 + length =
40247 + (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet;
40248 + }
40249 +
40250 + return length;
40251 +}
40252 +
40253 +/**
40254 + * Updates the state of the URB after a Transfer Complete interrupt on the
40255 + * host channel. Updates the actual_length field of the URB based on the
40256 + * number of bytes transferred via the host channel. Sets the URB status
40257 + * if the data transfer is finished.
40258 + *
40259 + * @return 1 if the data transfer specified by the URB is completely finished,
40260 + * 0 otherwise.
40261 + */
40262 +static int update_urb_state_xfer_comp(dwc_hc_t * hc,
40263 + dwc_otg_hc_regs_t * hc_regs,
40264 + dwc_otg_hcd_urb_t * urb,
40265 + dwc_otg_qtd_t * qtd)
40266 +{
40267 + int xfer_done = 0;
40268 + int short_read = 0;
40269 +
40270 + int xfer_length;
40271 +
40272 + xfer_length = get_actual_xfer_length(hc, hc_regs, qtd,
40273 + DWC_OTG_HC_XFER_COMPLETE,
40274 + &short_read);
40275 +
40276 +
40277 + /* non DWORD-aligned buffer case handling. */
40278 + if (hc->align_buff && xfer_length && hc->ep_is_in) {
40279 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
40280 + xfer_length);
40281 + }
40282 +
40283 + urb->actual_length += xfer_length;
40284 +
40285 + if (xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) &&
40286 + (urb->flags & URB_SEND_ZERO_PACKET)
40287 + && (urb->actual_length == urb->length)
40288 + && !(urb->length % hc->max_packet)) {
40289 + xfer_done = 0;
40290 + } else if (short_read || urb->actual_length >= urb->length) {
40291 + xfer_done = 1;
40292 + urb->status = 0;
40293 + }
40294 +
40295 +#ifdef DEBUG
40296 + {
40297 + hctsiz_data_t hctsiz;
40298 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40299 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
40300 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
40301 + hc->hc_num);
40302 + DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", hc->xfer_len);
40303 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n",
40304 + hctsiz.b.xfersize);
40305 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
40306 + urb->length);
40307 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
40308 + urb->actual_length);
40309 + DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n",
40310 + short_read, xfer_done);
40311 + }
40312 +#endif
40313 +
40314 + return xfer_done;
40315 +}
40316 +
40317 +/*
40318 + * Save the starting data toggle for the next transfer. The data toggle is
40319 + * saved in the QH for non-control transfers and it's saved in the QTD for
40320 + * control transfers.
40321 + */
40322 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
40323 + dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd)
40324 +{
40325 + hctsiz_data_t hctsiz;
40326 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40327 +
40328 + if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
40329 + dwc_otg_qh_t *qh = hc->qh;
40330 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
40331 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
40332 + } else {
40333 + qh->data_toggle = DWC_OTG_HC_PID_DATA1;
40334 + }
40335 + } else {
40336 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
40337 + qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
40338 + } else {
40339 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
40340 + }
40341 + }
40342 +}
40343 +
40344 +/**
40345 + * Updates the state of an Isochronous URB when the transfer is stopped for
40346 + * any reason. The fields of the current entry in the frame descriptor array
40347 + * are set based on the transfer state and the input _halt_status. Completes
40348 + * the Isochronous URB if all the URB frames have been completed.
40349 + *
40350 + * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be
40351 + * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
40352 + */
40353 +static dwc_otg_halt_status_e
40354 +update_isoc_urb_state(dwc_otg_hcd_t * hcd,
40355 + dwc_hc_t * hc,
40356 + dwc_otg_hc_regs_t * hc_regs,
40357 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
40358 +{
40359 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40360 + dwc_otg_halt_status_e ret_val = halt_status;
40361 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
40362 +
40363 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
40364 + switch (halt_status) {
40365 + case DWC_OTG_HC_XFER_COMPLETE:
40366 + frame_desc->status = 0;
40367 + frame_desc->actual_length =
40368 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
40369 +
40370 + /* non DWORD-aligned buffer case handling. */
40371 + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
40372 + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
40373 + hc->qh->dw_align_buf, frame_desc->actual_length);
40374 + }
40375 +
40376 + break;
40377 + case DWC_OTG_HC_XFER_FRAME_OVERRUN:
40378 + urb->error_count++;
40379 + if (hc->ep_is_in) {
40380 + frame_desc->status = -DWC_E_NO_STREAM_RES;
40381 + } else {
40382 + frame_desc->status = -DWC_E_COMMUNICATION;
40383 + }
40384 + frame_desc->actual_length = 0;
40385 + break;
40386 + case DWC_OTG_HC_XFER_BABBLE_ERR:
40387 + urb->error_count++;
40388 + frame_desc->status = -DWC_E_OVERFLOW;
40389 + /* Don't need to update actual_length in this case. */
40390 + break;
40391 + case DWC_OTG_HC_XFER_XACT_ERR:
40392 + urb->error_count++;
40393 + frame_desc->status = -DWC_E_PROTOCOL;
40394 + frame_desc->actual_length =
40395 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
40396 +
40397 + /* non DWORD-aligned buffer case handling. */
40398 + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
40399 + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
40400 + hc->qh->dw_align_buf, frame_desc->actual_length);
40401 + }
40402 + /* Skip whole frame */
40403 + if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) &&
40404 + hc->ep_is_in && hcd->core_if->dma_enable) {
40405 + qtd->complete_split = 0;
40406 + qtd->isoc_split_offset = 0;
40407 + }
40408 +
40409 + break;
40410 + default:
40411 + DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status);
40412 + break;
40413 + }
40414 + if (++qtd->isoc_frame_index == urb->packet_count) {
40415 + /*
40416 + * urb->status is not used for isoc transfers.
40417 + * The individual frame_desc statuses are used instead.
40418 + */
40419 + hcd->fops->complete(hcd, urb->priv, urb, 0);
40420 + ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
40421 + } else {
40422 + ret_val = DWC_OTG_HC_XFER_COMPLETE;
40423 + }
40424 + return ret_val;
40425 +}
40426 +
40427 +/**
40428 + * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
40429 + * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
40430 + * still linked to the QH, the QH is added to the end of the inactive
40431 + * non-periodic schedule. For periodic QHs, removes the QH from the periodic
40432 + * schedule if no more QTDs are linked to the QH.
40433 + */
40434 +static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd)
40435 +{
40436 + int continue_split = 0;
40437 + dwc_otg_qtd_t *qtd;
40438 +
40439 + DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd);
40440 +
40441 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
40442 +
40443 + if (qtd->complete_split) {
40444 + continue_split = 1;
40445 + } else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
40446 + qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) {
40447 + continue_split = 1;
40448 + }
40449 +
40450 + if (free_qtd) {
40451 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
40452 + continue_split = 0;
40453 + }
40454 +
40455 + qh->channel = NULL;
40456 + dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
40457 +}
40458 +
40459 +/**
40460 + * Releases a host channel for use by other transfers. Attempts to select and
40461 + * queue more transactions since at least one host channel is available.
40462 + *
40463 + * @param hcd The HCD state structure.
40464 + * @param hc The host channel to release.
40465 + * @param qtd The QTD associated with the host channel. This QTD may be freed
40466 + * if the transfer is complete or an error has occurred.
40467 + * @param halt_status Reason the channel is being released. This status
40468 + * determines the actions taken by this function.
40469 + */
40470 +static void release_channel(dwc_otg_hcd_t * hcd,
40471 + dwc_hc_t * hc,
40472 + dwc_otg_qtd_t * qtd,
40473 + dwc_otg_halt_status_e halt_status)
40474 +{
40475 + dwc_otg_transaction_type_e tr_type;
40476 + int free_qtd;
40477 + dwc_irqflags_t flags;
40478 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
40479 +
40480 + DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n",
40481 + __func__, hc->hc_num, halt_status, hc->xfer_len);
40482 +
40483 + switch (halt_status) {
40484 + case DWC_OTG_HC_XFER_URB_COMPLETE:
40485 + free_qtd = 1;
40486 + break;
40487 + case DWC_OTG_HC_XFER_AHB_ERR:
40488 + case DWC_OTG_HC_XFER_STALL:
40489 + case DWC_OTG_HC_XFER_BABBLE_ERR:
40490 + free_qtd = 1;
40491 + break;
40492 + case DWC_OTG_HC_XFER_XACT_ERR:
40493 + if (qtd->error_count >= 3) {
40494 + DWC_DEBUGPL(DBG_HCDV,
40495 + " Complete URB with transaction error\n");
40496 + free_qtd = 1;
40497 + qtd->urb->status = -DWC_E_PROTOCOL;
40498 + hcd->fops->complete(hcd, qtd->urb->priv,
40499 + qtd->urb, -DWC_E_PROTOCOL);
40500 + } else {
40501 + free_qtd = 0;
40502 + }
40503 + break;
40504 + case DWC_OTG_HC_XFER_URB_DEQUEUE:
40505 + /*
40506 + * The QTD has already been removed and the QH has been
40507 + * deactivated. Don't want to do anything except release the
40508 + * host channel and try to queue more transfers.
40509 + */
40510 + goto cleanup;
40511 + case DWC_OTG_HC_XFER_NO_HALT_STATUS:
40512 + free_qtd = 0;
40513 + break;
40514 + case DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE:
40515 + DWC_DEBUGPL(DBG_HCDV,
40516 + " Complete URB with I/O error\n");
40517 + free_qtd = 1;
40518 + qtd->urb->status = -DWC_E_IO;
40519 + hcd->fops->complete(hcd, qtd->urb->priv,
40520 + qtd->urb, -DWC_E_IO);
40521 + break;
40522 + default:
40523 + free_qtd = 0;
40524 + break;
40525 + }
40526 +
40527 + deactivate_qh(hcd, hc->qh, free_qtd);
40528 +
40529 +cleanup:
40530 + /*
40531 + * Release the host channel for use by other transfers. The cleanup
40532 + * function clears the channel interrupt enables and conditions, so
40533 + * there's no need to clear the Channel Halted interrupt separately.
40534 + */
40535 + dwc_otg_hc_cleanup(hcd->core_if, hc);
40536 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
40537 +
40538 + if (!microframe_schedule) {
40539 + switch (hc->ep_type) {
40540 + case DWC_OTG_EP_TYPE_CONTROL:
40541 + case DWC_OTG_EP_TYPE_BULK:
40542 + hcd->non_periodic_channels--;
40543 + break;
40544 +
40545 + default:
40546 + /*
40547 + * Don't release reservations for periodic channels here.
40548 + * That's done when a periodic transfer is descheduled (i.e.
40549 + * when the QH is removed from the periodic schedule).
40550 + */
40551 + break;
40552 + }
40553 + } else {
40554 +
40555 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
40556 + hcd->available_host_channels++;
40557 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
40558 + }
40559 +
40560 + /* Try to queue more transfers now that there's a free channel. */
40561 + tr_type = dwc_otg_hcd_select_transactions(hcd);
40562 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
40563 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
40564 + }
40565 + DWC_SPINLOCK_FREE(channel_lock);
40566 +}
40567 +
40568 +/**
40569 + * Halts a host channel. If the channel cannot be halted immediately because
40570 + * the request queue is full, this function ensures that the FIFO empty
40571 + * interrupt for the appropriate queue is enabled so that the halt request can
40572 + * be queued when there is space in the request queue.
40573 + *
40574 + * This function may also be called in DMA mode. In that case, the channel is
40575 + * simply released since the core always halts the channel automatically in
40576 + * DMA mode.
40577 + */
40578 +static void halt_channel(dwc_otg_hcd_t * hcd,
40579 + dwc_hc_t * hc,
40580 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
40581 +{
40582 + if (hcd->core_if->dma_enable) {
40583 + release_channel(hcd, hc, qtd, halt_status);
40584 + return;
40585 + }
40586 +
40587 + /* Slave mode processing... */
40588 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
40589 +
40590 + if (hc->halt_on_queue) {
40591 + gintmsk_data_t gintmsk = {.d32 = 0 };
40592 + dwc_otg_core_global_regs_t *global_regs;
40593 + global_regs = hcd->core_if->core_global_regs;
40594 +
40595 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
40596 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
40597 + /*
40598 + * Make sure the Non-periodic Tx FIFO empty interrupt
40599 + * is enabled so that the non-periodic schedule will
40600 + * be processed.
40601 + */
40602 + gintmsk.b.nptxfempty = 1;
40603 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
40604 + } else {
40605 + /*
40606 + * Move the QH from the periodic queued schedule to
40607 + * the periodic assigned schedule. This allows the
40608 + * halt to be queued when the periodic schedule is
40609 + * processed.
40610 + */
40611 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
40612 + &hc->qh->qh_list_entry);
40613 +
40614 + /*
40615 + * Make sure the Periodic Tx FIFO Empty interrupt is
40616 + * enabled so that the periodic schedule will be
40617 + * processed.
40618 + */
40619 + gintmsk.b.ptxfempty = 1;
40620 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
40621 + }
40622 + }
40623 +}
40624 +
40625 +/**
40626 + * Performs common cleanup for non-periodic transfers after a Transfer
40627 + * Complete interrupt. This function should be called after any endpoint type
40628 + * specific handling is finished to release the host channel.
40629 + */
40630 +static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd,
40631 + dwc_hc_t * hc,
40632 + dwc_otg_hc_regs_t * hc_regs,
40633 + dwc_otg_qtd_t * qtd,
40634 + dwc_otg_halt_status_e halt_status)
40635 +{
40636 + hcint_data_t hcint;
40637 +
40638 + qtd->error_count = 0;
40639 +
40640 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
40641 + if (hcint.b.nyet) {
40642 + /*
40643 + * Got a NYET on the last transaction of the transfer. This
40644 + * means that the endpoint should be in the PING state at the
40645 + * beginning of the next transfer.
40646 + */
40647 + hc->qh->ping_state = 1;
40648 + clear_hc_int(hc_regs, nyet);
40649 + }
40650 +
40651 + /*
40652 + * Always halt and release the host channel to make it available for
40653 + * more transfers. There may still be more phases for a control
40654 + * transfer or more data packets for a bulk transfer at this point,
40655 + * but the host channel is still halted. A channel will be reassigned
40656 + * to the transfer when the non-periodic schedule is processed after
40657 + * the channel is released. This allows transactions to be queued
40658 + * properly via dwc_otg_hcd_queue_transactions, which also enables the
40659 + * Tx FIFO Empty interrupt if necessary.
40660 + */
40661 + if (hc->ep_is_in) {
40662 + /*
40663 + * IN transfers in Slave mode require an explicit disable to
40664 + * halt the channel. (In DMA mode, this call simply releases
40665 + * the channel.)
40666 + */
40667 + halt_channel(hcd, hc, qtd, halt_status);
40668 + } else {
40669 + /*
40670 + * The channel is automatically disabled by the core for OUT
40671 + * transfers in Slave mode.
40672 + */
40673 + release_channel(hcd, hc, qtd, halt_status);
40674 + }
40675 +}
40676 +
40677 +/**
40678 + * Performs common cleanup for periodic transfers after a Transfer Complete
40679 + * interrupt. This function should be called after any endpoint type specific
40680 + * handling is finished to release the host channel.
40681 + */
40682 +static void complete_periodic_xfer(dwc_otg_hcd_t * hcd,
40683 + dwc_hc_t * hc,
40684 + dwc_otg_hc_regs_t * hc_regs,
40685 + dwc_otg_qtd_t * qtd,
40686 + dwc_otg_halt_status_e halt_status)
40687 +{
40688 + hctsiz_data_t hctsiz;
40689 + qtd->error_count = 0;
40690 +
40691 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40692 + if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) {
40693 + /* Core halts channel in these cases. */
40694 + release_channel(hcd, hc, qtd, halt_status);
40695 + } else {
40696 + /* Flush any outstanding requests from the Tx queue. */
40697 + halt_channel(hcd, hc, qtd, halt_status);
40698 + }
40699 +}
40700 +
40701 +static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd,
40702 + dwc_hc_t * hc,
40703 + dwc_otg_hc_regs_t * hc_regs,
40704 + dwc_otg_qtd_t * qtd)
40705 +{
40706 + uint32_t len;
40707 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
40708 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
40709 +
40710 + len = get_actual_xfer_length(hc, hc_regs, qtd,
40711 + DWC_OTG_HC_XFER_COMPLETE, NULL);
40712 +
40713 + if (!len) {
40714 + qtd->complete_split = 0;
40715 + qtd->isoc_split_offset = 0;
40716 + return 0;
40717 + }
40718 + frame_desc->actual_length += len;
40719 +
40720 + if (hc->align_buff && len)
40721 + dwc_memcpy(qtd->urb->buf + frame_desc->offset +
40722 + qtd->isoc_split_offset, hc->qh->dw_align_buf, len);
40723 + qtd->isoc_split_offset += len;
40724 +
40725 + if (frame_desc->length == frame_desc->actual_length) {
40726 + frame_desc->status = 0;
40727 + qtd->isoc_frame_index++;
40728 + qtd->complete_split = 0;
40729 + qtd->isoc_split_offset = 0;
40730 + }
40731 +
40732 + if (qtd->isoc_frame_index == qtd->urb->packet_count) {
40733 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
40734 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
40735 + } else {
40736 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
40737 + }
40738 +
40739 + return 1; /* Indicates that channel released */
40740 +}
40741 +
40742 +/**
40743 + * Handles a host channel Transfer Complete interrupt. This handler may be
40744 + * called in either DMA mode or Slave mode.
40745 + */
40746 +static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd,
40747 + dwc_hc_t * hc,
40748 + dwc_otg_hc_regs_t * hc_regs,
40749 + dwc_otg_qtd_t * qtd)
40750 +{
40751 + int urb_xfer_done;
40752 + dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;
40753 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40754 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
40755 +
40756 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
40757 + "Transfer Complete--\n", hc->hc_num);
40758 +
40759 + if (hcd->core_if->dma_desc_enable) {
40760 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status);
40761 + if (pipe_type == UE_ISOCHRONOUS) {
40762 + /* Do not disable the interrupt, just clear it */
40763 + clear_hc_int(hc_regs, xfercomp);
40764 + return 1;
40765 + }
40766 + goto handle_xfercomp_done;
40767 + }
40768 +
40769 + /*
40770 + * Handle xfer complete on CSPLIT.
40771 + */
40772 +
40773 + if (hc->qh->do_split) {
40774 + if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in
40775 + && hcd->core_if->dma_enable) {
40776 + if (qtd->complete_split
40777 + && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs,
40778 + qtd))
40779 + goto handle_xfercomp_done;
40780 + } else {
40781 + qtd->complete_split = 0;
40782 + }
40783 + }
40784 +
40785 + /* Update the QTD and URB states. */
40786 + switch (pipe_type) {
40787 + case UE_CONTROL:
40788 + switch (qtd->control_phase) {
40789 + case DWC_OTG_CONTROL_SETUP:
40790 + if (urb->length > 0) {
40791 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
40792 + } else {
40793 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
40794 + }
40795 + DWC_DEBUGPL(DBG_HCDV,
40796 + " Control setup transaction done\n");
40797 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40798 + break;
40799 + case DWC_OTG_CONTROL_DATA:{
40800 + urb_xfer_done =
40801 + update_urb_state_xfer_comp(hc, hc_regs, urb,
40802 + qtd);
40803 + if (urb_xfer_done) {
40804 + qtd->control_phase =
40805 + DWC_OTG_CONTROL_STATUS;
40806 + DWC_DEBUGPL(DBG_HCDV,
40807 + " Control data transfer done\n");
40808 + } else {
40809 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40810 + }
40811 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40812 + break;
40813 + }
40814 + case DWC_OTG_CONTROL_STATUS:
40815 + DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n");
40816 + if (urb->status == -DWC_E_IN_PROGRESS) {
40817 + urb->status = 0;
40818 + }
40819 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40820 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40821 + break;
40822 + }
40823 +
40824 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40825 + break;
40826 + case UE_BULK:
40827 + DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n");
40828 + urb_xfer_done =
40829 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
40830 + if (urb_xfer_done) {
40831 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40832 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40833 + } else {
40834 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40835 + }
40836 +
40837 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40838 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40839 + break;
40840 + case UE_INTERRUPT:
40841 + DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n");
40842 + urb_xfer_done =
40843 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
40844 +
40845 + /*
40846 + * Interrupt URB is done on the first transfer complete
40847 + * interrupt.
40848 + */
40849 + if (urb_xfer_done) {
40850 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40851 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40852 + } else {
40853 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40854 + }
40855 +
40856 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40857 + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40858 + break;
40859 + case UE_ISOCHRONOUS:
40860 + DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n");
40861 + if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {
40862 + halt_status =
40863 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
40864 + DWC_OTG_HC_XFER_COMPLETE);
40865 + }
40866 + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40867 + break;
40868 + }
40869 +
40870 +handle_xfercomp_done:
40871 + disable_hc_int(hc_regs, xfercompl);
40872 +
40873 + return 1;
40874 +}
40875 +
40876 +/**
40877 + * Handles a host channel STALL interrupt. This handler may be called in
40878 + * either DMA mode or Slave mode.
40879 + */
40880 +static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd,
40881 + dwc_hc_t * hc,
40882 + dwc_otg_hc_regs_t * hc_regs,
40883 + dwc_otg_qtd_t * qtd)
40884 +{
40885 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40886 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
40887 +
40888 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
40889 + "STALL Received--\n", hc->hc_num);
40890 +
40891 + if (hcd->core_if->dma_desc_enable) {
40892 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL);
40893 + goto handle_stall_done;
40894 + }
40895 +
40896 + if (pipe_type == UE_CONTROL) {
40897 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
40898 + }
40899 +
40900 + if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) {
40901 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
40902 + /*
40903 + * USB protocol requires resetting the data toggle for bulk
40904 + * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
40905 + * setup command is issued to the endpoint. Anticipate the
40906 + * CLEAR_FEATURE command since a STALL has occurred and reset
40907 + * the data toggle now.
40908 + */
40909 + hc->qh->data_toggle = 0;
40910 + }
40911 +
40912 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL);
40913 +
40914 +handle_stall_done:
40915 + disable_hc_int(hc_regs, stall);
40916 +
40917 + return 1;
40918 +}
40919 +
40920 +/*
40921 + * Updates the state of the URB when a transfer has been stopped due to an
40922 + * abnormal condition before the transfer completes. Modifies the
40923 + * actual_length field of the URB to reflect the number of bytes that have
40924 + * actually been transferred via the host channel.
40925 + */
40926 +static void update_urb_state_xfer_intr(dwc_hc_t * hc,
40927 + dwc_otg_hc_regs_t * hc_regs,
40928 + dwc_otg_hcd_urb_t * urb,
40929 + dwc_otg_qtd_t * qtd,
40930 + dwc_otg_halt_status_e halt_status)
40931 +{
40932 + uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
40933 + halt_status, NULL);
40934 + /* non DWORD-aligned buffer case handling. */
40935 + if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
40936 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
40937 + bytes_transferred);
40938 + }
40939 +
40940 + urb->actual_length += bytes_transferred;
40941 +
40942 +#ifdef DEBUG
40943 + {
40944 + hctsiz_data_t hctsiz;
40945 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40946 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
40947 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
40948 + hc->hc_num);
40949 + DWC_DEBUGPL(DBG_HCDV, " hc->start_pkt_count %d\n",
40950 + hc->start_pkt_count);
40951 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
40952 + DWC_DEBUGPL(DBG_HCDV, " hc->max_packet %d\n", hc->max_packet);
40953 + DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n",
40954 + bytes_transferred);
40955 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
40956 + urb->actual_length);
40957 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
40958 + urb->length);
40959 + }
40960 +#endif
40961 +}
40962 +
40963 +/**
40964 + * Handles a host channel NAK interrupt. This handler may be called in either
40965 + * DMA mode or Slave mode.
40966 + */
40967 +static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
40968 + dwc_hc_t * hc,
40969 + dwc_otg_hc_regs_t * hc_regs,
40970 + dwc_otg_qtd_t * qtd)
40971 +{
40972 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
40973 + "NAK Received--\n", hc->hc_num);
40974 +
40975 + /*
40976 + * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
40977 + * interrupt. Re-start the SSPLIT transfer.
40978 + */
40979 + if (hc->do_split) {
40980 + if (hc->complete_split) {
40981 + qtd->error_count = 0;
40982 + }
40983 + qtd->complete_split = 0;
40984 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
40985 + goto handle_nak_done;
40986 + }
40987 +
40988 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
40989 + case UE_CONTROL:
40990 + case UE_BULK:
40991 + if (hcd->core_if->dma_enable && hc->ep_is_in) {
40992 + /*
40993 + * NAK interrupts are enabled on bulk/control IN
40994 + * transfers in DMA mode for the sole purpose of
40995 + * resetting the error count after a transaction error
40996 + * occurs. The core will continue transferring data.
40997 + */
40998 + qtd->error_count = 0;
40999 + goto handle_nak_done;
41000 + }
41001 +
41002 + /*
41003 + * NAK interrupts normally occur during OUT transfers in DMA
41004 + * or Slave mode. For IN transfers, more requests will be
41005 + * queued as request queue space is available.
41006 + */
41007 + qtd->error_count = 0;
41008 +
41009 + if (!hc->qh->ping_state) {
41010 + update_urb_state_xfer_intr(hc, hc_regs,
41011 + qtd->urb, qtd,
41012 + DWC_OTG_HC_XFER_NAK);
41013 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41014 +
41015 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH)
41016 + hc->qh->ping_state = 1;
41017 + }
41018 +
41019 + /*
41020 + * Halt the channel so the transfer can be re-started from
41021 + * the appropriate point or the PING protocol will
41022 + * start/continue.
41023 + */
41024 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
41025 + break;
41026 + case UE_INTERRUPT:
41027 + qtd->error_count = 0;
41028 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
41029 + break;
41030 + case UE_ISOCHRONOUS:
41031 + /* Should never get called for isochronous transfers. */
41032 + DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n");
41033 + break;
41034 + }
41035 +
41036 +handle_nak_done:
41037 + disable_hc_int(hc_regs, nak);
41038 +
41039 + return 1;
41040 +}
41041 +
41042 +/**
41043 + * Handles a host channel ACK interrupt. This interrupt is enabled when
41044 + * performing the PING protocol in Slave mode, when errors occur during
41045 + * either Slave mode or DMA mode, and during Start Split transactions.
41046 + */
41047 +static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd,
41048 + dwc_hc_t * hc,
41049 + dwc_otg_hc_regs_t * hc_regs,
41050 + dwc_otg_qtd_t * qtd)
41051 +{
41052 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41053 + "ACK Received--\n", hc->hc_num);
41054 +
41055 + if (hc->do_split) {
41056 + /*
41057 + * Handle ACK on SSPLIT.
41058 + * ACK should not occur in CSPLIT.
41059 + */
41060 + if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) {
41061 + qtd->ssplit_out_xfer_count = hc->xfer_len;
41062 + }
41063 + if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) {
41064 + /* Don't need complete for isochronous out transfers. */
41065 + qtd->complete_split = 1;
41066 + }
41067 +
41068 + /* ISOC OUT */
41069 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
41070 + switch (hc->xact_pos) {
41071 + case DWC_HCSPLIT_XACTPOS_ALL:
41072 + break;
41073 + case DWC_HCSPLIT_XACTPOS_END:
41074 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
41075 + qtd->isoc_split_offset = 0;
41076 + break;
41077 + case DWC_HCSPLIT_XACTPOS_BEGIN:
41078 + case DWC_HCSPLIT_XACTPOS_MID:
41079 + /*
41080 + * For BEGIN or MID, calculate the length for
41081 + * the next microframe to determine the correct
41082 + * SSPLIT token, either MID or END.
41083 + */
41084 + {
41085 + struct dwc_otg_hcd_iso_packet_desc
41086 + *frame_desc;
41087 +
41088 + frame_desc =
41089 + &qtd->urb->
41090 + iso_descs[qtd->isoc_frame_index];
41091 + qtd->isoc_split_offset += 188;
41092 +
41093 + if ((frame_desc->length -
41094 + qtd->isoc_split_offset) <= 188) {
41095 + qtd->isoc_split_pos =
41096 + DWC_HCSPLIT_XACTPOS_END;
41097 + } else {
41098 + qtd->isoc_split_pos =
41099 + DWC_HCSPLIT_XACTPOS_MID;
41100 + }
41101 +
41102 + }
41103 + break;
41104 + }
41105 + } else {
41106 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
41107 + }
41108 + } else {
41109 + qtd->error_count = 0;
41110 +
41111 + if (hc->qh->ping_state) {
41112 + hc->qh->ping_state = 0;
41113 + /*
41114 + * Halt the channel so the transfer can be re-started
41115 + * from the appropriate point. This only happens in
41116 + * Slave mode. In DMA mode, the ping_state is cleared
41117 + * when the transfer is started because the core
41118 + * automatically executes the PING, then the transfer.
41119 + */
41120 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
41121 + }
41122 + }
41123 +
41124 + /*
41125 + * If the ACK occurred when _not_ in the PING state, let the channel
41126 + * continue transferring data after clearing the error count.
41127 + */
41128 +
41129 + disable_hc_int(hc_regs, ack);
41130 +
41131 + return 1;
41132 +}
41133 +
41134 +/**
41135 + * Handles a host channel NYET interrupt. This interrupt should only occur on
41136 + * Bulk and Control OUT endpoints and for complete split transactions. If a
41137 + * NYET occurs at the same time as a Transfer Complete interrupt, it is
41138 + * handled in the xfercomp interrupt handler, not here. This handler may be
41139 + * called in either DMA mode or Slave mode.
41140 + */
41141 +static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
41142 + dwc_hc_t * hc,
41143 + dwc_otg_hc_regs_t * hc_regs,
41144 + dwc_otg_qtd_t * qtd)
41145 +{
41146 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41147 + "NYET Received--\n", hc->hc_num);
41148 +
41149 + /*
41150 + * NYET on CSPLIT
41151 + * re-do the CSPLIT immediately on non-periodic
41152 + */
41153 + if (hc->do_split && hc->complete_split) {
41154 + if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
41155 + && hcd->core_if->dma_enable) {
41156 + qtd->complete_split = 0;
41157 + qtd->isoc_split_offset = 0;
41158 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
41159 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
41160 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
41161 + }
41162 + else
41163 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
41164 + goto handle_nyet_done;
41165 + }
41166 +
41167 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
41168 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
41169 + int frnum = dwc_otg_hcd_get_frame_number(hcd);
41170 +
41171 + if (dwc_full_frame_num(frnum) !=
41172 + dwc_full_frame_num(hc->qh->sched_frame)) {
41173 + /*
41174 + * No longer in the same full speed frame.
41175 + * Treat this as a transaction error.
41176 + */
41177 +#if 0
41178 + /** @todo Fix system performance so this can
41179 + * be treated as an error. Right now complete
41180 + * splits cannot be scheduled precisely enough
41181 + * due to other system activity, so this error
41182 + * occurs regularly in Slave mode.
41183 + */
41184 + qtd->error_count++;
41185 +#endif
41186 + qtd->complete_split = 0;
41187 + halt_channel(hcd, hc, qtd,
41188 + DWC_OTG_HC_XFER_XACT_ERR);
41189 + /** @todo add support for isoc release */
41190 + goto handle_nyet_done;
41191 + }
41192 + }
41193 +
41194 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
41195 + goto handle_nyet_done;
41196 + }
41197 +
41198 + hc->qh->ping_state = 1;
41199 + qtd->error_count = 0;
41200 +
41201 + update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd,
41202 + DWC_OTG_HC_XFER_NYET);
41203 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41204 +
41205 + /*
41206 + * Halt the channel and re-start the transfer so the PING
41207 + * protocol will start.
41208 + */
41209 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
41210 +
41211 +handle_nyet_done:
41212 + disable_hc_int(hc_regs, nyet);
41213 + return 1;
41214 +}
41215 +
41216 +/**
41217 + * Handles a host channel babble interrupt. This handler may be called in
41218 + * either DMA mode or Slave mode.
41219 + */
41220 +static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd,
41221 + dwc_hc_t * hc,
41222 + dwc_otg_hc_regs_t * hc_regs,
41223 + dwc_otg_qtd_t * qtd)
41224 +{
41225 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41226 + "Babble Error--\n", hc->hc_num);
41227 +
41228 + if (hcd->core_if->dma_desc_enable) {
41229 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41230 + DWC_OTG_HC_XFER_BABBLE_ERR);
41231 + goto handle_babble_done;
41232 + }
41233 +
41234 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
41235 + hcd->fops->complete(hcd, qtd->urb->priv,
41236 + qtd->urb, -DWC_E_OVERFLOW);
41237 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
41238 + } else {
41239 + dwc_otg_halt_status_e halt_status;
41240 + halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41241 + DWC_OTG_HC_XFER_BABBLE_ERR);
41242 + halt_channel(hcd, hc, qtd, halt_status);
41243 + }
41244 +
41245 +handle_babble_done:
41246 + disable_hc_int(hc_regs, bblerr);
41247 + return 1;
41248 +}
41249 +
41250 +/**
41251 + * Handles a host channel AHB error interrupt. This handler is only called in
41252 + * DMA mode.
41253 + */
41254 +static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd,
41255 + dwc_hc_t * hc,
41256 + dwc_otg_hc_regs_t * hc_regs,
41257 + dwc_otg_qtd_t * qtd)
41258 +{
41259 + hcchar_data_t hcchar;
41260 + hcsplt_data_t hcsplt;
41261 + hctsiz_data_t hctsiz;
41262 + uint32_t hcdma;
41263 + char *pipetype, *speed;
41264 +
41265 + dwc_otg_hcd_urb_t *urb = qtd->urb;
41266 +
41267 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41268 + "AHB Error--\n", hc->hc_num);
41269 +
41270 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41271 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
41272 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41273 + hcdma = DWC_READ_REG32(&hc_regs->hcdma);
41274 +
41275 + DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num);
41276 + DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
41277 + DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
41278 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
41279 + DWC_ERROR(" Device address: %d\n",
41280 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
41281 + DWC_ERROR(" Endpoint: %d, %s\n",
41282 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
41283 + (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"));
41284 +
41285 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
41286 + case UE_CONTROL:
41287 + pipetype = "CONTROL";
41288 + break;
41289 + case UE_BULK:
41290 + pipetype = "BULK";
41291 + break;
41292 + case UE_INTERRUPT:
41293 + pipetype = "INTERRUPT";
41294 + break;
41295 + case UE_ISOCHRONOUS:
41296 + pipetype = "ISOCHRONOUS";
41297 + break;
41298 + default:
41299 + pipetype = "UNKNOWN";
41300 + break;
41301 + }
41302 +
41303 + DWC_ERROR(" Endpoint type: %s\n", pipetype);
41304 +
41305 + switch (hc->speed) {
41306 + case DWC_OTG_EP_SPEED_HIGH:
41307 + speed = "HIGH";
41308 + break;
41309 + case DWC_OTG_EP_SPEED_FULL:
41310 + speed = "FULL";
41311 + break;
41312 + case DWC_OTG_EP_SPEED_LOW:
41313 + speed = "LOW";
41314 + break;
41315 + default:
41316 + speed = "UNKNOWN";
41317 + break;
41318 + };
41319 +
41320 + DWC_ERROR(" Speed: %s\n", speed);
41321 +
41322 + DWC_ERROR(" Max packet size: %d\n",
41323 + dwc_otg_hcd_get_mps(&urb->pipe_info));
41324 + DWC_ERROR(" Data buffer length: %d\n", urb->length);
41325 + DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n",
41326 + urb->buf, (void *)urb->dma);
41327 + DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n",
41328 + urb->setup_packet, (void *)urb->setup_dma);
41329 + DWC_ERROR(" Interval: %d\n", urb->interval);
41330 +
41331 + /* Core haltes the channel for Descriptor DMA mode */
41332 + if (hcd->core_if->dma_desc_enable) {
41333 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41334 + DWC_OTG_HC_XFER_AHB_ERR);
41335 + goto handle_ahberr_done;
41336 + }
41337 +
41338 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO);
41339 +
41340 + /*
41341 + * Force a channel halt. Don't call halt_channel because that won't
41342 + * write to the HCCHARn register in DMA mode to force the halt.
41343 + */
41344 + dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
41345 +handle_ahberr_done:
41346 + disable_hc_int(hc_regs, ahberr);
41347 + return 1;
41348 +}
41349 +
41350 +/**
41351 + * Handles a host channel transaction error interrupt. This handler may be
41352 + * called in either DMA mode or Slave mode.
41353 + */
41354 +static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd,
41355 + dwc_hc_t * hc,
41356 + dwc_otg_hc_regs_t * hc_regs,
41357 + dwc_otg_qtd_t * qtd)
41358 +{
41359 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41360 + "Transaction Error--\n", hc->hc_num);
41361 +
41362 + if (hcd->core_if->dma_desc_enable) {
41363 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41364 + DWC_OTG_HC_XFER_XACT_ERR);
41365 + goto handle_xacterr_done;
41366 + }
41367 +
41368 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41369 + case UE_CONTROL:
41370 + case UE_BULK:
41371 + qtd->error_count++;
41372 + if (!hc->qh->ping_state) {
41373 +
41374 + update_urb_state_xfer_intr(hc, hc_regs,
41375 + qtd->urb, qtd,
41376 + DWC_OTG_HC_XFER_XACT_ERR);
41377 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41378 + if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) {
41379 + hc->qh->ping_state = 1;
41380 + }
41381 + }
41382 +
41383 + /*
41384 + * Halt the channel so the transfer can be re-started from
41385 + * the appropriate point or the PING protocol will start.
41386 + */
41387 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41388 + break;
41389 + case UE_INTERRUPT:
41390 + qtd->error_count++;
41391 + if (hc->do_split && hc->complete_split) {
41392 + qtd->complete_split = 0;
41393 + }
41394 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41395 + break;
41396 + case UE_ISOCHRONOUS:
41397 + {
41398 + dwc_otg_halt_status_e halt_status;
41399 + halt_status =
41400 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41401 + DWC_OTG_HC_XFER_XACT_ERR);
41402 +
41403 + halt_channel(hcd, hc, qtd, halt_status);
41404 + }
41405 + break;
41406 + }
41407 +handle_xacterr_done:
41408 + disable_hc_int(hc_regs, xacterr);
41409 +
41410 + return 1;
41411 +}
41412 +
41413 +/**
41414 + * Handles a host channel frame overrun interrupt. This handler may be called
41415 + * in either DMA mode or Slave mode.
41416 + */
41417 +static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd,
41418 + dwc_hc_t * hc,
41419 + dwc_otg_hc_regs_t * hc_regs,
41420 + dwc_otg_qtd_t * qtd)
41421 +{
41422 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41423 + "Frame Overrun--\n", hc->hc_num);
41424 +
41425 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41426 + case UE_CONTROL:
41427 + case UE_BULK:
41428 + break;
41429 + case UE_INTERRUPT:
41430 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
41431 + break;
41432 + case UE_ISOCHRONOUS:
41433 + {
41434 + dwc_otg_halt_status_e halt_status;
41435 + halt_status =
41436 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41437 + DWC_OTG_HC_XFER_FRAME_OVERRUN);
41438 +
41439 + halt_channel(hcd, hc, qtd, halt_status);
41440 + }
41441 + break;
41442 + }
41443 +
41444 + disable_hc_int(hc_regs, frmovrun);
41445 +
41446 + return 1;
41447 +}
41448 +
41449 +/**
41450 + * Handles a host channel data toggle error interrupt. This handler may be
41451 + * called in either DMA mode or Slave mode.
41452 + */
41453 +static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd,
41454 + dwc_hc_t * hc,
41455 + dwc_otg_hc_regs_t * hc_regs,
41456 + dwc_otg_qtd_t * qtd)
41457 +{
41458 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41459 + "Data Toggle Error--\n", hc->hc_num);
41460 +
41461 + if (hc->ep_is_in) {
41462 + qtd->error_count = 0;
41463 + } else {
41464 + DWC_ERROR("Data Toggle Error on OUT transfer,"
41465 + "channel %d\n", hc->hc_num);
41466 + }
41467 +
41468 + disable_hc_int(hc_regs, datatglerr);
41469 +
41470 + return 1;
41471 +}
41472 +
41473 +#ifdef DEBUG
41474 +/**
41475 + * This function is for debug only. It checks that a valid halt status is set
41476 + * and that HCCHARn.chdis is clear. If there's a problem, corrective action is
41477 + * taken and a warning is issued.
41478 + * @return 1 if halt status is ok, 0 otherwise.
41479 + */
41480 +static inline int halt_status_ok(dwc_otg_hcd_t * hcd,
41481 + dwc_hc_t * hc,
41482 + dwc_otg_hc_regs_t * hc_regs,
41483 + dwc_otg_qtd_t * qtd)
41484 +{
41485 + hcchar_data_t hcchar;
41486 + hctsiz_data_t hctsiz;
41487 + hcint_data_t hcint;
41488 + hcintmsk_data_t hcintmsk;
41489 + hcsplt_data_t hcsplt;
41490 +
41491 + if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
41492 + /*
41493 + * This code is here only as a check. This condition should
41494 + * never happen. Ignore the halt if it does occur.
41495 + */
41496 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41497 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41498 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41499 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41500 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
41501 + DWC_WARN
41502 + ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
41503 + "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
41504 + "hcint 0x%08x, hcintmsk 0x%08x, "
41505 + "hcsplt 0x%08x, qtd->complete_split %d\n", __func__,
41506 + hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32,
41507 + hcintmsk.d32, hcsplt.d32, qtd->complete_split);
41508 +
41509 + DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
41510 + __func__, hc->hc_num);
41511 + DWC_WARN("\n");
41512 + clear_hc_int(hc_regs, chhltd);
41513 + return 0;
41514 + }
41515 +
41516 + /*
41517 + * This code is here only as a check. hcchar.chdis should
41518 + * never be set when the halt interrupt occurs. Halt the
41519 + * channel again if it does occur.
41520 + */
41521 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41522 + if (hcchar.b.chdis) {
41523 + DWC_WARN("%s: hcchar.chdis set unexpectedly, "
41524 + "hcchar 0x%08x, trying to halt again\n",
41525 + __func__, hcchar.d32);
41526 + clear_hc_int(hc_regs, chhltd);
41527 + hc->halt_pending = 0;
41528 + halt_channel(hcd, hc, qtd, hc->halt_status);
41529 + return 0;
41530 + }
41531 +
41532 + return 1;
41533 +}
41534 +#endif
41535 +
41536 +/**
41537 + * Handles a host Channel Halted interrupt in DMA mode. This handler
41538 + * determines the reason the channel halted and proceeds accordingly.
41539 + */
41540 +static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
41541 + dwc_hc_t * hc,
41542 + dwc_otg_hc_regs_t * hc_regs,
41543 + dwc_otg_qtd_t * qtd)
41544 +{
41545 + hcint_data_t hcint;
41546 + hcintmsk_data_t hcintmsk;
41547 + int out_nak_enh = 0;
41548 +
41549 + /* For core with OUT NAK enhancement, the flow for high-
41550 + * speed CONTROL/BULK OUT is handled a little differently.
41551 + */
41552 + if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) {
41553 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in &&
41554 + (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
41555 + hc->ep_type == DWC_OTG_EP_TYPE_BULK)) {
41556 + out_nak_enh = 1;
41557 + }
41558 + }
41559 +
41560 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
41561 + (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR
41562 + && !hcd->core_if->dma_desc_enable)) {
41563 + /*
41564 + * Just release the channel. A dequeue can happen on a
41565 + * transfer timeout. In the case of an AHB Error, the channel
41566 + * was forced to halt because there's no way to gracefully
41567 + * recover.
41568 + */
41569 + if (hcd->core_if->dma_desc_enable)
41570 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41571 + hc->halt_status);
41572 + else
41573 + release_channel(hcd, hc, qtd, hc->halt_status);
41574 + return;
41575 + }
41576 +
41577 + /* Read the HCINTn register to determine the cause for the halt. */
41578 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41579 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41580 +
41581 + if (hcint.b.xfercomp) {
41582 + /** @todo This is here because of a possible hardware bug. Spec
41583 + * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
41584 + * interrupt w/ACK bit set should occur, but I only see the
41585 + * XFERCOMP bit, even with it masked out. This is a workaround
41586 + * for that behavior. Should fix this when hardware is fixed.
41587 + */
41588 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
41589 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
41590 + }
41591 + handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
41592 + } else if (hcint.b.stall) {
41593 + handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
41594 + } else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) {
41595 + if (out_nak_enh) {
41596 + if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) {
41597 + DWC_DEBUGPL(DBG_HCD, "XactErr with NYET/NAK/ACK\n");
41598 + qtd->error_count = 0;
41599 + } else {
41600 + DWC_DEBUGPL(DBG_HCD, "XactErr without NYET/NAK/ACK\n");
41601 + }
41602 + }
41603 +
41604 + /*
41605 + * Must handle xacterr before nak or ack. Could get a xacterr
41606 + * at the same time as either of these on a BULK/CONTROL OUT
41607 + * that started with a PING. The xacterr takes precedence.
41608 + */
41609 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
41610 + } else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) {
41611 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
41612 + } else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) {
41613 + handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
41614 + } else if (hcint.b.bblerr) {
41615 + handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
41616 + } else if (hcint.b.frmovrun) {
41617 + handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
41618 + } else if (!out_nak_enh) {
41619 + if (hcint.b.nyet) {
41620 + /*
41621 + * Must handle nyet before nak or ack. Could get a nyet at the
41622 + * same time as either of those on a BULK/CONTROL OUT that
41623 + * started with a PING. The nyet takes precedence.
41624 + */
41625 + handle_hc_nyet_intr(hcd, hc, hc_regs, qtd);
41626 + } else if (hcint.b.nak && !hcintmsk.b.nak) {
41627 + /*
41628 + * If nak is not masked, it's because a non-split IN transfer
41629 + * is in an error state. In that case, the nak is handled by
41630 + * the nak interrupt handler, not here. Handle nak here for
41631 + * BULK/CONTROL OUT transfers, which halt on a NAK to allow
41632 + * rewinding the buffer pointer.
41633 + */
41634 + handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
41635 + } else if (hcint.b.ack && !hcintmsk.b.ack) {
41636 + /*
41637 + * If ack is not masked, it's because a non-split IN transfer
41638 + * is in an error state. In that case, the ack is handled by
41639 + * the ack interrupt handler, not here. Handle ack here for
41640 + * split transfers. Start splits halt on ACK.
41641 + */
41642 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
41643 + } else {
41644 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
41645 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
41646 + /*
41647 + * A periodic transfer halted with no other channel
41648 + * interrupts set. Assume it was halted by the core
41649 + * because it could not be completed in its scheduled
41650 + * (micro)frame.
41651 + */
41652 +#ifdef DEBUG
41653 + DWC_PRINTF
41654 + ("%s: Halt channel %d (assume incomplete periodic transfer)\n",
41655 + __func__, hc->hc_num);
41656 +#endif
41657 + halt_channel(hcd, hc, qtd,
41658 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
41659 + } else {
41660 + DWC_ERROR
41661 + ("%s: Channel %d, DMA Mode -- ChHltd set, but reason "
41662 + "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
41663 + __func__, hc->hc_num, hcint.d32,
41664 + DWC_READ_REG32(&hcd->
41665 + core_if->core_global_regs->
41666 + gintsts));
41667 + }
41668 +
41669 + }
41670 + } else {
41671 + DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n",
41672 + hcint.d32);
41673 + }
41674 +}
41675 +
41676 +/**
41677 + * Handles a host channel Channel Halted interrupt.
41678 + *
41679 + * In slave mode, this handler is called only when the driver specifically
41680 + * requests a halt. This occurs during handling other host channel interrupts
41681 + * (e.g. nak, xacterr, stall, nyet, etc.).
41682 + *
41683 + * In DMA mode, this is the interrupt that occurs when the core has finished
41684 + * processing a transfer on a channel. Other host channel interrupts (except
41685 + * ahberr) are disabled in DMA mode.
41686 + */
41687 +static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
41688 + dwc_hc_t * hc,
41689 + dwc_otg_hc_regs_t * hc_regs,
41690 + dwc_otg_qtd_t * qtd)
41691 +{
41692 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41693 + "Channel Halted--\n", hc->hc_num);
41694 +
41695 + if (hcd->core_if->dma_enable) {
41696 + handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd);
41697 + } else {
41698 +#ifdef DEBUG
41699 + if (!halt_status_ok(hcd, hc, hc_regs, qtd)) {
41700 + return 1;
41701 + }
41702 +#endif
41703 + release_channel(hcd, hc, qtd, hc->halt_status);
41704 + }
41705 +
41706 + return 1;
41707 +}
41708 +
41709 +/** Handles interrupt for a specific Host Channel */
41710 +int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
41711 +{
41712 + int retval = 0;
41713 + hcint_data_t hcint;
41714 + hcintmsk_data_t hcintmsk;
41715 + dwc_hc_t *hc;
41716 + dwc_otg_hc_regs_t *hc_regs;
41717 + dwc_otg_qtd_t *qtd;
41718 +
41719 + DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num);
41720 +
41721 + hc = dwc_otg_hcd->hc_ptr_array[num];
41722 + hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
41723 + qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
41724 +
41725 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41726 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41727 + DWC_DEBUGPL(DBG_HCDV,
41728 + " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
41729 + hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
41730 + hcint.d32 = hcint.d32 & hcintmsk.d32;
41731 +
41732 + if (!dwc_otg_hcd->core_if->dma_enable) {
41733 + if (hcint.b.chhltd && hcint.d32 != 0x2) {
41734 + hcint.b.chhltd = 0;
41735 + }
41736 + }
41737 +
41738 + if (hcint.b.xfercomp) {
41739 + retval |=
41740 + handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41741 + /*
41742 + * If NYET occurred at same time as Xfer Complete, the NYET is
41743 + * handled by the Xfer Complete interrupt handler. Don't want
41744 + * to call the NYET interrupt handler in this case.
41745 + */
41746 + hcint.b.nyet = 0;
41747 + }
41748 + if (hcint.b.chhltd) {
41749 + retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41750 + }
41751 + if (hcint.b.ahberr) {
41752 + retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41753 + }
41754 + if (hcint.b.stall) {
41755 + retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41756 + }
41757 + if (hcint.b.nak) {
41758 + retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41759 + }
41760 + if (hcint.b.ack) {
41761 + retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41762 + }
41763 + if (hcint.b.nyet) {
41764 + retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41765 + }
41766 + if (hcint.b.xacterr) {
41767 + retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41768 + }
41769 + if (hcint.b.bblerr) {
41770 + retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41771 + }
41772 + if (hcint.b.frmovrun) {
41773 + retval |=
41774 + handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41775 + }
41776 + if (hcint.b.datatglerr) {
41777 + retval |=
41778 + handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41779 + }
41780 +
41781 + return retval;
41782 +}
41783 +
41784 +#endif /* DWC_DEVICE_ONLY */
41785 --- /dev/null
41786 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
41787 @@ -0,0 +1,893 @@
41788 +/* ==========================================================================
41789 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
41790 + * $Revision: #20 $
41791 + * $Date: 2011/10/26 $
41792 + * $Change: 1872981 $
41793 + *
41794 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
41795 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
41796 + * otherwise expressly agreed to in writing between Synopsys and you.
41797 + *
41798 + * The Software IS NOT an item of Licensed Software or Licensed Product under
41799 + * any End User Software License Agreement or Agreement for Licensed Product
41800 + * with Synopsys or any supplement thereto. You are permitted to use and
41801 + * redistribute this Software in source and binary forms, with or without
41802 + * modification, provided that redistributions of source code must retain this
41803 + * notice. You may not view, use, disclose, copy or distribute this file or
41804 + * any information contained herein except pursuant to this license grant from
41805 + * Synopsys. If you do not agree with this notice, including the disclaimer
41806 + * below, then you are not authorized to use the Software.
41807 + *
41808 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
41809 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41810 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41811 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
41812 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41813 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41814 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
41815 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41816 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41817 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
41818 + * DAMAGE.
41819 + * ========================================================================== */
41820 +#ifndef DWC_DEVICE_ONLY
41821 +
41822 +/**
41823 + * @file
41824 + *
41825 + * This file contains the implementation of the HCD. In Linux, the HCD
41826 + * implements the hc_driver API.
41827 + */
41828 +#include <linux/kernel.h>
41829 +#include <linux/module.h>
41830 +#include <linux/moduleparam.h>
41831 +#include <linux/init.h>
41832 +#include <linux/device.h>
41833 +#include <linux/errno.h>
41834 +#include <linux/list.h>
41835 +#include <linux/interrupt.h>
41836 +#include <linux/string.h>
41837 +#include <linux/dma-mapping.h>
41838 +#include <linux/version.h>
41839 +#include <asm/io.h>
41840 +#include <linux/usb.h>
41841 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
41842 +#include <../drivers/usb/core/hcd.h>
41843 +#else
41844 +#include <linux/usb/hcd.h>
41845 +#endif
41846 +
41847 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
41848 +#define USB_URB_EP_LINKING 1
41849 +#else
41850 +#define USB_URB_EP_LINKING 0
41851 +#endif
41852 +
41853 +#include "dwc_otg_hcd_if.h"
41854 +#include "dwc_otg_dbg.h"
41855 +#include "dwc_otg_driver.h"
41856 +#include "dwc_otg_hcd.h"
41857 +/**
41858 + * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
41859 + * qualified with its direction (possible 32 endpoints per device).
41860 + */
41861 +#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
41862 + ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
41863 +
41864 +static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
41865 +
41866 +/** @name Linux HC Driver API Functions */
41867 +/** @{ */
41868 +/* manage i/o requests, device state */
41869 +static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
41870 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
41871 + struct usb_host_endpoint *ep,
41872 +#endif
41873 + struct urb *urb, gfp_t mem_flags);
41874 +
41875 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
41876 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
41877 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
41878 +#endif
41879 +#else /* kernels at or post 2.6.30 */
41880 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd,
41881 + struct urb *urb, int status);
41882 +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) */
41883 +
41884 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
41885 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
41886 +static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
41887 +#endif
41888 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
41889 +extern int hcd_start(struct usb_hcd *hcd);
41890 +extern void hcd_stop(struct usb_hcd *hcd);
41891 +static int get_frame_number(struct usb_hcd *hcd);
41892 +extern int hub_status_data(struct usb_hcd *hcd, char *buf);
41893 +extern int hub_control(struct usb_hcd *hcd,
41894 + u16 typeReq,
41895 + u16 wValue, u16 wIndex, char *buf, u16 wLength);
41896 +
41897 +struct wrapper_priv_data {
41898 + dwc_otg_hcd_t *dwc_otg_hcd;
41899 +};
41900 +
41901 +/** @} */
41902 +
41903 +static struct hc_driver dwc_otg_hc_driver = {
41904 +
41905 + .description = dwc_otg_hcd_name,
41906 + .product_desc = "DWC OTG Controller",
41907 + .hcd_priv_size = sizeof(struct wrapper_priv_data),
41908 +
41909 + .irq = dwc_otg_hcd_irq,
41910 +
41911 + .flags = HCD_MEMORY | HCD_USB2,
41912 +
41913 + //.reset =
41914 + .start = hcd_start,
41915 + //.suspend =
41916 + //.resume =
41917 + .stop = hcd_stop,
41918 +
41919 + .urb_enqueue = dwc_otg_urb_enqueue,
41920 + .urb_dequeue = dwc_otg_urb_dequeue,
41921 + .endpoint_disable = endpoint_disable,
41922 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
41923 + .endpoint_reset = endpoint_reset,
41924 +#endif
41925 + .get_frame_number = get_frame_number,
41926 +
41927 + .hub_status_data = hub_status_data,
41928 + .hub_control = hub_control,
41929 + //.bus_suspend =
41930 + //.bus_resume =
41931 +};
41932 +
41933 +/** Gets the dwc_otg_hcd from a struct usb_hcd */
41934 +static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
41935 +{
41936 + struct wrapper_priv_data *p;
41937 + p = (struct wrapper_priv_data *)(hcd->hcd_priv);
41938 + return p->dwc_otg_hcd;
41939 +}
41940 +
41941 +/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
41942 +static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
41943 +{
41944 + return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
41945 +}
41946 +
41947 +/** Gets the usb_host_endpoint associated with an URB. */
41948 +inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
41949 +{
41950 + struct usb_device *dev = urb->dev;
41951 + int ep_num = usb_pipeendpoint(urb->pipe);
41952 +
41953 + if (usb_pipein(urb->pipe))
41954 + return dev->ep_in[ep_num];
41955 + else
41956 + return dev->ep_out[ep_num];
41957 +}
41958 +
41959 +static int _disconnect(dwc_otg_hcd_t * hcd)
41960 +{
41961 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
41962 +
41963 + usb_hcd->self.is_b_host = 0;
41964 + return 0;
41965 +}
41966 +
41967 +static int _start(dwc_otg_hcd_t * hcd)
41968 +{
41969 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
41970 +
41971 + usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
41972 + hcd_start(usb_hcd);
41973 +
41974 + return 0;
41975 +}
41976 +
41977 +static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
41978 + uint32_t * port_addr)
41979 +{
41980 + struct urb *urb = (struct urb *)urb_handle;
41981 + struct usb_bus *bus;
41982 +#if 1 //GRAYG - temporary
41983 + if (NULL == urb_handle)
41984 + DWC_ERROR("**** %s - NULL URB handle\n", __func__);//GRAYG
41985 + if (NULL == urb->dev)
41986 + DWC_ERROR("**** %s - URB has no device\n", __func__);//GRAYG
41987 + if (NULL == port_addr)
41988 + DWC_ERROR("**** %s - NULL port_address\n", __func__);//GRAYG
41989 +#endif
41990 + if (urb->dev->tt) {
41991 + if (NULL == urb->dev->tt->hub) {
41992 + DWC_ERROR("**** %s - (URB's transactor has no TT - giving no hub)\n",
41993 + __func__); //GRAYG
41994 + //*hub_addr = (u8)usb_pipedevice(urb->pipe); //GRAYG
41995 + *hub_addr = 0; //GRAYG
41996 + // we probably shouldn't have a transaction translator if
41997 + // there's no associated hub?
41998 + } else {
41999 + bus = hcd_to_bus(dwc_otg_hcd_to_hcd(hcd));
42000 + if (urb->dev->tt->hub == bus->root_hub)
42001 + *hub_addr = 0;
42002 + else
42003 + *hub_addr = urb->dev->tt->hub->devnum;
42004 + }
42005 + *port_addr = urb->dev->tt->multi ? urb->dev->ttport : 1;
42006 + } else {
42007 + *hub_addr = 0;
42008 + *port_addr = urb->dev->ttport;
42009 + }
42010 + return 0;
42011 +}
42012 +
42013 +static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
42014 +{
42015 + struct urb *urb = (struct urb *)urb_handle;
42016 + return urb->dev->speed;
42017 +}
42018 +
42019 +static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
42020 +{
42021 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
42022 + return usb_hcd->self.b_hnp_enable;
42023 +}
42024 +
42025 +static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
42026 + struct urb *urb)
42027 +{
42028 + hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
42029 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42030 + hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
42031 + } else {
42032 + hcd_to_bus(hcd)->bandwidth_int_reqs++;
42033 + }
42034 +}
42035 +
42036 +static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
42037 + struct urb *urb)
42038 +{
42039 + hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
42040 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42041 + hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
42042 + } else {
42043 + hcd_to_bus(hcd)->bandwidth_int_reqs--;
42044 + }
42045 +}
42046 +
42047 +/**
42048 + * Sets the final status of an URB and returns it to the device driver. Any
42049 + * required cleanup of the URB is performed.
42050 + */
42051 +static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
42052 + dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
42053 +{
42054 + struct urb *urb = (struct urb *)urb_handle;
42055 +
42056 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42057 + DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
42058 + __func__, urb, usb_pipedevice(urb->pipe),
42059 + usb_pipeendpoint(urb->pipe),
42060 + usb_pipein(urb->pipe) ? "IN" : "OUT", status);
42061 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42062 + int i;
42063 + for (i = 0; i < urb->number_of_packets; i++) {
42064 + DWC_PRINTF(" ISO Desc %d status: %d\n",
42065 + i, urb->iso_frame_desc[i].status);
42066 + }
42067 + }
42068 + }
42069 +
42070 + urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
42071 + /* Convert status value. */
42072 + switch (status) {
42073 + case -DWC_E_PROTOCOL:
42074 + status = -EPROTO;
42075 + break;
42076 + case -DWC_E_IN_PROGRESS:
42077 + status = -EINPROGRESS;
42078 + break;
42079 + case -DWC_E_PIPE:
42080 + status = -EPIPE;
42081 + break;
42082 + case -DWC_E_IO:
42083 + status = -EIO;
42084 + break;
42085 + case -DWC_E_TIMEOUT:
42086 + status = -ETIMEDOUT;
42087 + break;
42088 + case -DWC_E_OVERFLOW:
42089 + status = -EOVERFLOW;
42090 + break;
42091 + default:
42092 + if (status) {
42093 + DWC_PRINTF("Uknown urb status %d\n", status);
42094 +
42095 + }
42096 + }
42097 +
42098 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42099 + int i;
42100 +
42101 + urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
42102 + for (i = 0; i < urb->number_of_packets; ++i) {
42103 + urb->iso_frame_desc[i].actual_length =
42104 + dwc_otg_hcd_urb_get_iso_desc_actual_length
42105 + (dwc_otg_urb, i);
42106 + urb->iso_frame_desc[i].status =
42107 + dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
42108 + }
42109 + }
42110 +
42111 + urb->status = status;
42112 + urb->hcpriv = NULL;
42113 + if (!status) {
42114 + if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
42115 + (urb->actual_length < urb->transfer_buffer_length)) {
42116 + urb->status = -EREMOTEIO;
42117 + }
42118 + }
42119 +
42120 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
42121 + (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
42122 + struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
42123 + if (ep) {
42124 + free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
42125 + dwc_otg_hcd_get_ep_bandwidth(hcd,
42126 + ep->hcpriv),
42127 + urb);
42128 + }
42129 + }
42130 +
42131 + DWC_FREE(dwc_otg_urb);
42132 +
42133 +#if USB_URB_EP_LINKING
42134 + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
42135 +#endif
42136 + DWC_SPINUNLOCK(hcd->lock);
42137 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42138 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
42139 +#else
42140 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
42141 +#endif
42142 + DWC_SPINLOCK(hcd->lock);
42143 +
42144 + return 0;
42145 +}
42146 +
42147 +static struct dwc_otg_hcd_function_ops hcd_fops = {
42148 + .start = _start,
42149 + .disconnect = _disconnect,
42150 + .hub_info = _hub_info,
42151 + .speed = _speed,
42152 + .complete = _complete,
42153 + .get_b_hnp_enable = _get_b_hnp_enable,
42154 +};
42155 +
42156 +/**
42157 + * Initializes the HCD. This function allocates memory for and initializes the
42158 + * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
42159 + * USB bus with the core and calls the hc_driver->start() function. It returns
42160 + * a negative error on failure.
42161 + */
42162 +int hcd_init(dwc_bus_dev_t *_dev)
42163 +{
42164 + struct usb_hcd *hcd = NULL;
42165 + dwc_otg_hcd_t *dwc_otg_hcd = NULL;
42166 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
42167 + int retval = 0;
42168 + u64 dmamask;
42169 +
42170 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev);
42171 +
42172 + /* Set device flags indicating whether the HCD supports DMA. */
42173 + if (dwc_otg_is_dma_enable(otg_dev->core_if))
42174 + dmamask = DMA_BIT_MASK(32);
42175 + else
42176 + dmamask = 0;
42177 +
42178 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
42179 + dma_set_mask(&_dev->dev, dmamask);
42180 + dma_set_coherent_mask(&_dev->dev, dmamask);
42181 +#elif defined(PCI_INTERFACE)
42182 + pci_set_dma_mask(_dev, dmamask);
42183 + pci_set_consistent_dma_mask(_dev, dmamask);
42184 +#endif
42185 +
42186 + /*
42187 + * Allocate memory for the base HCD plus the DWC OTG HCD.
42188 + * Initialize the base HCD.
42189 + */
42190 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
42191 + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
42192 +#else
42193 + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
42194 + hcd->has_tt = 1;
42195 +// hcd->uses_new_polling = 1;
42196 +// hcd->poll_rh = 0;
42197 +#endif
42198 + if (!hcd) {
42199 + retval = -ENOMEM;
42200 + goto error1;
42201 + }
42202 +
42203 + hcd->regs = otg_dev->os_dep.base;
42204 +
42205 + /* Initialize the DWC OTG HCD. */
42206 + dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
42207 + if (!dwc_otg_hcd) {
42208 + goto error2;
42209 + }
42210 + ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
42211 + dwc_otg_hcd;
42212 + otg_dev->hcd = dwc_otg_hcd;
42213 +
42214 + if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
42215 + goto error2;
42216 + }
42217 +
42218 + otg_dev->hcd->otg_dev = otg_dev;
42219 + hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
42220 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
42221 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) //version field absent later
42222 + hcd->self.otg_version = dwc_otg_get_otg_version(otg_dev->core_if);
42223 +#endif
42224 + /* Don't support SG list at this point */
42225 + hcd->self.sg_tablesize = 0;
42226 +#endif
42227 + /*
42228 + * Finish generic HCD initialization and start the HCD. This function
42229 + * allocates the DMA buffer pool, registers the USB bus, requests the
42230 + * IRQ line, and calls hcd_start method.
42231 + */
42232 +#ifdef PLATFORM_INTERFACE
42233 + retval = usb_add_hcd(hcd, platform_get_irq(_dev, 0), IRQF_SHARED | IRQF_DISABLED);
42234 +#else
42235 + retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED);
42236 +#endif
42237 + if (retval < 0) {
42238 + goto error2;
42239 + }
42240 +
42241 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
42242 + return 0;
42243 +
42244 +error2:
42245 + usb_put_hcd(hcd);
42246 +error1:
42247 + return retval;
42248 +}
42249 +
42250 +/**
42251 + * Removes the HCD.
42252 + * Frees memory and resources associated with the HCD and deregisters the bus.
42253 + */
42254 +void hcd_remove(dwc_bus_dev_t *_dev)
42255 +{
42256 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
42257 + dwc_otg_hcd_t *dwc_otg_hcd;
42258 + struct usb_hcd *hcd;
42259 +
42260 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE otg_dev=%p\n", otg_dev);
42261 +
42262 + if (!otg_dev) {
42263 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
42264 + return;
42265 + }
42266 +
42267 + dwc_otg_hcd = otg_dev->hcd;
42268 +
42269 + if (!dwc_otg_hcd) {
42270 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
42271 + return;
42272 + }
42273 +
42274 + hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
42275 +
42276 + if (!hcd) {
42277 + DWC_DEBUGPL(DBG_ANY,
42278 + "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
42279 + __func__);
42280 + return;
42281 + }
42282 + usb_remove_hcd(hcd);
42283 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
42284 + dwc_otg_hcd_remove(dwc_otg_hcd);
42285 + usb_put_hcd(hcd);
42286 +}
42287 +
42288 +/* =========================================================================
42289 + * Linux HC Driver Functions
42290 + * ========================================================================= */
42291 +
42292 +/** Initializes the DWC_otg controller and its root hub and prepares it for host
42293 + * mode operation. Activates the root port. Returns 0 on success and a negative
42294 + * error code on failure. */
42295 +int hcd_start(struct usb_hcd *hcd)
42296 +{
42297 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42298 + struct usb_bus *bus;
42299 +
42300 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
42301 + bus = hcd_to_bus(hcd);
42302 +
42303 + hcd->state = HC_STATE_RUNNING;
42304 + if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
42305 + return 0;
42306 + }
42307 +
42308 + /* Initialize and connect root hub if one is not already attached */
42309 + if (bus->root_hub) {
42310 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
42311 + /* Inform the HUB driver to resume. */
42312 + usb_hcd_resume_root_hub(hcd);
42313 + }
42314 +
42315 + return 0;
42316 +}
42317 +
42318 +/**
42319 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
42320 + * stopped.
42321 + */
42322 +void hcd_stop(struct usb_hcd *hcd)
42323 +{
42324 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42325 +
42326 + dwc_otg_hcd_stop(dwc_otg_hcd);
42327 +}
42328 +
42329 +/** Returns the current frame number. */
42330 +static int get_frame_number(struct usb_hcd *hcd)
42331 +{
42332 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42333 +
42334 + return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
42335 +}
42336 +
42337 +#ifdef DEBUG
42338 +static void dump_urb_info(struct urb *urb, char *fn_name)
42339 +{
42340 + DWC_PRINTF("%s, urb %p\n", fn_name, urb);
42341 + DWC_PRINTF(" Device address: %d\n", usb_pipedevice(urb->pipe));
42342 + DWC_PRINTF(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
42343 + (usb_pipein(urb->pipe) ? "IN" : "OUT"));
42344 + DWC_PRINTF(" Endpoint type: %s\n", ( {
42345 + char *pipetype;
42346 + switch (usb_pipetype(urb->pipe)) {
42347 +case PIPE_CONTROL:
42348 +pipetype = "CONTROL"; break; case PIPE_BULK:
42349 +pipetype = "BULK"; break; case PIPE_INTERRUPT:
42350 +pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
42351 +pipetype = "ISOCHRONOUS"; break; default:
42352 + pipetype = "UNKNOWN"; break;};
42353 + pipetype;}
42354 + )) ;
42355 + DWC_PRINTF(" Speed: %s\n", ( {
42356 + char *speed; switch (urb->dev->speed) {
42357 +case USB_SPEED_HIGH:
42358 +speed = "HIGH"; break; case USB_SPEED_FULL:
42359 +speed = "FULL"; break; case USB_SPEED_LOW:
42360 +speed = "LOW"; break; default:
42361 + speed = "UNKNOWN"; break;};
42362 + speed;}
42363 + )) ;
42364 + DWC_PRINTF(" Max packet size: %d\n",
42365 + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
42366 + DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length);
42367 + DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n",
42368 + urb->transfer_buffer, (void *)urb->transfer_dma);
42369 + DWC_PRINTF(" Setup buffer: %p, Setup DMA: %p\n",
42370 + urb->setup_packet, (void *)urb->setup_dma);
42371 + DWC_PRINTF(" Interval: %d\n", urb->interval);
42372 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42373 + int i;
42374 + for (i = 0; i < urb->number_of_packets; i++) {
42375 + DWC_PRINTF(" ISO Desc %d:\n", i);
42376 + DWC_PRINTF(" offset: %d, length %d\n",
42377 + urb->iso_frame_desc[i].offset,
42378 + urb->iso_frame_desc[i].length);
42379 + }
42380 + }
42381 +}
42382 +#endif
42383 +
42384 +/** Starts processing a USB transfer request specified by a USB Request Block
42385 + * (URB). mem_flags indicates the type of memory allocation to use while
42386 + * processing this URB. */
42387 +static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
42388 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42389 + struct usb_host_endpoint *ep,
42390 +#endif
42391 + struct urb *urb, gfp_t mem_flags)
42392 +{
42393 + int retval = 0;
42394 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
42395 + struct usb_host_endpoint *ep = urb->ep;
42396 +#endif
42397 +#if USB_URB_EP_LINKING
42398 + dwc_irqflags_t irqflags;
42399 +#endif
42400 + void **ref_ep_hcpriv = &ep->hcpriv;
42401 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42402 + dwc_otg_hcd_urb_t *dwc_otg_urb;
42403 + int i;
42404 + int alloc_bandwidth = 0;
42405 + uint8_t ep_type = 0;
42406 + uint32_t flags = 0;
42407 + void *buf;
42408 +
42409 +#ifdef DEBUG
42410 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42411 + dump_urb_info(urb, "dwc_otg_urb_enqueue");
42412 + }
42413 +#endif
42414 +
42415 + if (!urb->transfer_buffer && urb->transfer_buffer_length)
42416 + return -EINVAL;
42417 +
42418 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
42419 + || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
42420 + if (!dwc_otg_hcd_is_bandwidth_allocated
42421 + (dwc_otg_hcd, ref_ep_hcpriv)) {
42422 + alloc_bandwidth = 1;
42423 + }
42424 + }
42425 +
42426 + switch (usb_pipetype(urb->pipe)) {
42427 + case PIPE_CONTROL:
42428 + ep_type = USB_ENDPOINT_XFER_CONTROL;
42429 + break;
42430 + case PIPE_ISOCHRONOUS:
42431 + ep_type = USB_ENDPOINT_XFER_ISOC;
42432 + break;
42433 + case PIPE_BULK:
42434 + ep_type = USB_ENDPOINT_XFER_BULK;
42435 + break;
42436 + case PIPE_INTERRUPT:
42437 + ep_type = USB_ENDPOINT_XFER_INT;
42438 + break;
42439 + default:
42440 + DWC_WARN("Wrong EP type - %d\n", usb_pipetype(urb->pipe));
42441 + }
42442 +
42443 + /* # of packets is often 0 - do we really need to call this then? */
42444 + dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
42445 + urb->number_of_packets,
42446 + mem_flags == GFP_ATOMIC ? 1 : 0);
42447 +
42448 + if(dwc_otg_urb == NULL)
42449 + return -ENOMEM;
42450 +
42451 + urb->hcpriv = dwc_otg_urb;
42452 + if (!dwc_otg_urb && urb->number_of_packets)
42453 + return -ENOMEM;
42454 +
42455 + dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
42456 + usb_pipeendpoint(urb->pipe), ep_type,
42457 + usb_pipein(urb->pipe),
42458 + usb_maxpacket(urb->dev, urb->pipe,
42459 + !(usb_pipein(urb->pipe))));
42460 +
42461 + buf = urb->transfer_buffer;
42462 + if (hcd->self.uses_dma) {
42463 + /*
42464 + * Calculate virtual address from physical address,
42465 + * because some class driver may not fill transfer_buffer.
42466 + * In Buffer DMA mode virual address is used,
42467 + * when handling non DWORD aligned buffers.
42468 + */
42469 + //buf = phys_to_virt(urb->transfer_dma);
42470 + // DMA addresses are bus addresses not physical addresses!
42471 + buf = dma_to_virt(&urb->dev->dev, urb->transfer_dma);
42472 + }
42473 +
42474 + if (!(urb->transfer_flags & URB_NO_INTERRUPT))
42475 + flags |= URB_GIVEBACK_ASAP;
42476 + if (urb->transfer_flags & URB_ZERO_PACKET)
42477 + flags |= URB_SEND_ZERO_PACKET;
42478 +
42479 + dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
42480 + urb->transfer_dma,
42481 + urb->transfer_buffer_length,
42482 + urb->setup_packet,
42483 + urb->setup_dma, flags, urb->interval);
42484 +
42485 + for (i = 0; i < urb->number_of_packets; ++i) {
42486 + dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
42487 + urb->
42488 + iso_frame_desc[i].offset,
42489 + urb->
42490 + iso_frame_desc[i].length);
42491 + }
42492 +
42493 +#if USB_URB_EP_LINKING
42494 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
42495 + retval = usb_hcd_link_urb_to_ep(hcd, urb);
42496 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
42497 + if (0 == retval)
42498 +#endif
42499 + {
42500 + retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
42501 + /*(dwc_otg_qh_t **)*/
42502 + ref_ep_hcpriv,
42503 + mem_flags == GFP_ATOMIC ? 1 : 0);
42504 + if (0 == retval) {
42505 + if (alloc_bandwidth) {
42506 + allocate_bus_bandwidth(hcd,
42507 + dwc_otg_hcd_get_ep_bandwidth(
42508 + dwc_otg_hcd, *ref_ep_hcpriv),
42509 + urb);
42510 + }
42511 + } else {
42512 +#if USB_URB_EP_LINKING
42513 + dwc_irqflags_t irqflags;
42514 + DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
42515 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
42516 + usb_hcd_unlink_urb_from_ep(hcd, urb);
42517 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
42518 +#endif
42519 + if (retval == -DWC_E_NO_DEVICE) {
42520 + retval = -ENODEV;
42521 + }
42522 + }
42523 + }
42524 + return retval;
42525 +}
42526 +
42527 +/** Aborts/cancels a USB transfer request. Always returns 0 to indicate
42528 + * success. */
42529 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42530 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
42531 +#else
42532 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
42533 +#endif
42534 +{
42535 + dwc_irqflags_t flags;
42536 + dwc_otg_hcd_t *dwc_otg_hcd;
42537 + int rc;
42538 +
42539 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
42540 +
42541 + dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42542 +
42543 +#ifdef DEBUG
42544 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42545 + dump_urb_info(urb, "dwc_otg_urb_dequeue");
42546 + }
42547 +#endif
42548 +
42549 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
42550 + rc = usb_hcd_check_unlink_urb(hcd, urb, status);
42551 + if (0 == rc) {
42552 + if(urb->hcpriv != NULL) {
42553 + dwc_otg_hcd_urb_dequeue(dwc_otg_hcd,
42554 + (dwc_otg_hcd_urb_t *)urb->hcpriv);
42555 +
42556 + DWC_FREE(urb->hcpriv);
42557 + urb->hcpriv = NULL;
42558 + }
42559 + }
42560 +
42561 + if (0 == rc) {
42562 + /* Higher layer software sets URB status. */
42563 +#if USB_URB_EP_LINKING
42564 + usb_hcd_unlink_urb_from_ep(hcd, urb);
42565 +#endif
42566 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42567 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42568 + usb_hcd_giveback_urb(hcd, urb);
42569 +#else
42570 + usb_hcd_giveback_urb(hcd, urb, status);
42571 +#endif
42572 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42573 + DWC_PRINTF("Called usb_hcd_giveback_urb() \n");
42574 + DWC_PRINTF(" 1urb->status = %d\n", urb->status);
42575 + }
42576 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue OK\n");
42577 + } else {
42578 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42579 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue failed - rc %d\n",
42580 + rc);
42581 + }
42582 +
42583 + return rc;
42584 +}
42585 +
42586 +/* Frees resources in the DWC_otg controller related to a given endpoint. Also
42587 + * clears state in the HCD related to the endpoint. Any URBs for the endpoint
42588 + * must already be dequeued. */
42589 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
42590 +{
42591 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42592 +
42593 + DWC_DEBUGPL(DBG_HCD,
42594 + "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
42595 + "endpoint=%d\n", ep->desc.bEndpointAddress,
42596 + dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
42597 + dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
42598 + ep->hcpriv = NULL;
42599 +}
42600 +
42601 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
42602 +/* Resets endpoint specific parameter values, in current version used to reset
42603 + * the data toggle(as a WA). This function can be called from usb_clear_halt routine */
42604 +static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
42605 +{
42606 + dwc_irqflags_t flags;
42607 + struct usb_device *udev = NULL;
42608 + int epnum = usb_endpoint_num(&ep->desc);
42609 + int is_out = usb_endpoint_dir_out(&ep->desc);
42610 + int is_control = usb_endpoint_xfer_control(&ep->desc);
42611 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42612 + struct device *dev = DWC_OTG_OS_GETDEV(dwc_otg_hcd->otg_dev->os_dep);
42613 +
42614 + if (dev)
42615 + udev = to_usb_device(dev);
42616 + else
42617 + return;
42618 +
42619 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum);
42620 +
42621 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
42622 + usb_settoggle(udev, epnum, is_out, 0);
42623 + if (is_control)
42624 + usb_settoggle(udev, epnum, !is_out, 0);
42625 +
42626 + if (ep->hcpriv) {
42627 + dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
42628 + }
42629 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42630 +}
42631 +#endif
42632 +
42633 +/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
42634 + * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
42635 + * interrupt.
42636 + *
42637 + * This function is called by the USB core when an interrupt occurs */
42638 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
42639 +{
42640 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42641 + int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
42642 + if (retval != 0) {
42643 + S3C2410X_CLEAR_EINTPEND();
42644 + }
42645 + return IRQ_RETVAL(retval);
42646 +}
42647 +
42648 +/** Creates Status Change bitmap for the root hub and root port. The bitmap is
42649 + * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
42650 + * is the status change indicator for the single root port. Returns 1 if either
42651 + * change indicator is 1, otherwise returns 0. */
42652 +int hub_status_data(struct usb_hcd *hcd, char *buf)
42653 +{
42654 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42655 +
42656 + buf[0] = 0;
42657 + buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
42658 +
42659 + return (buf[0] != 0);
42660 +}
42661 +
42662 +/** Handles hub class-specific requests. */
42663 +int hub_control(struct usb_hcd *hcd,
42664 + u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
42665 +{
42666 + int retval;
42667 +
42668 + retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
42669 + typeReq, wValue, wIndex, buf, wLength);
42670 +
42671 + switch (retval) {
42672 + case -DWC_E_INVALID:
42673 + retval = -EINVAL;
42674 + break;
42675 + }
42676 +
42677 + return retval;
42678 +}
42679 +
42680 +#endif /* DWC_DEVICE_ONLY */
42681 --- /dev/null
42682 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
42683 @@ -0,0 +1,922 @@
42684 +/* ==========================================================================
42685 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
42686 + * $Revision: #44 $
42687 + * $Date: 2011/10/26 $
42688 + * $Change: 1873028 $
42689 + *
42690 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
42691 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
42692 + * otherwise expressly agreed to in writing between Synopsys and you.
42693 + *
42694 + * The Software IS NOT an item of Licensed Software or Licensed Product under
42695 + * any End User Software License Agreement or Agreement for Licensed Product
42696 + * with Synopsys or any supplement thereto. You are permitted to use and
42697 + * redistribute this Software in source and binary forms, with or without
42698 + * modification, provided that redistributions of source code must retain this
42699 + * notice. You may not view, use, disclose, copy or distribute this file or
42700 + * any information contained herein except pursuant to this license grant from
42701 + * Synopsys. If you do not agree with this notice, including the disclaimer
42702 + * below, then you are not authorized to use the Software.
42703 + *
42704 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
42705 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42706 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42707 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
42708 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42709 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
42710 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
42711 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42712 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42713 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
42714 + * DAMAGE.
42715 + * ========================================================================== */
42716 +#ifndef DWC_DEVICE_ONLY
42717 +
42718 +/**
42719 + * @file
42720 + *
42721 + * This file contains the functions to manage Queue Heads and Queue
42722 + * Transfer Descriptors.
42723 + */
42724 +
42725 +#include "dwc_otg_hcd.h"
42726 +#include "dwc_otg_regs.h"
42727 +
42728 +extern bool microframe_schedule;
42729 +
42730 +/**
42731 + * Free each QTD in the QH's QTD-list then free the QH. QH should already be
42732 + * removed from a list. QTD list should already be empty if called from URB
42733 + * Dequeue.
42734 + *
42735 + * @param hcd HCD instance.
42736 + * @param qh The QH to free.
42737 + */
42738 +void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
42739 +{
42740 + dwc_otg_qtd_t *qtd, *qtd_tmp;
42741 +
42742 + /* Free each QTD in the QTD list */
42743 + DWC_SPINLOCK(hcd->lock);
42744 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
42745 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
42746 + dwc_otg_hcd_qtd_free(qtd);
42747 + }
42748 +
42749 + if (hcd->core_if->dma_desc_enable) {
42750 + dwc_otg_hcd_qh_free_ddma(hcd, qh);
42751 + } else if (qh->dw_align_buf) {
42752 + uint32_t buf_size;
42753 + if (qh->ep_type == UE_ISOCHRONOUS) {
42754 + buf_size = 4096;
42755 + } else {
42756 + buf_size = hcd->core_if->core_params->max_transfer_size;
42757 + }
42758 + DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
42759 + }
42760 +
42761 + DWC_FREE(qh);
42762 + DWC_SPINUNLOCK(hcd->lock);
42763 + return;
42764 +}
42765 +
42766 +#define BitStuffTime(bytecount) ((8 * 7* bytecount) / 6)
42767 +#define HS_HOST_DELAY 5 /* nanoseconds */
42768 +#define FS_LS_HOST_DELAY 1000 /* nanoseconds */
42769 +#define HUB_LS_SETUP 333 /* nanoseconds */
42770 +#define NS_TO_US(ns) ((ns + 500) / 1000)
42771 + /* convert & round nanoseconds to microseconds */
42772 +
42773 +static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
42774 +{
42775 + unsigned long retval;
42776 +
42777 + switch (speed) {
42778 + case USB_SPEED_HIGH:
42779 + if (is_isoc) {
42780 + retval =
42781 + ((38 * 8 * 2083) +
42782 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
42783 + HS_HOST_DELAY;
42784 + } else {
42785 + retval =
42786 + ((55 * 8 * 2083) +
42787 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
42788 + HS_HOST_DELAY;
42789 + }
42790 + break;
42791 + case USB_SPEED_FULL:
42792 + if (is_isoc) {
42793 + retval =
42794 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
42795 + if (is_in) {
42796 + retval = 7268 + FS_LS_HOST_DELAY + retval;
42797 + } else {
42798 + retval = 6265 + FS_LS_HOST_DELAY + retval;
42799 + }
42800 + } else {
42801 + retval =
42802 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
42803 + retval = 9107 + FS_LS_HOST_DELAY + retval;
42804 + }
42805 + break;
42806 + case USB_SPEED_LOW:
42807 + if (is_in) {
42808 + retval =
42809 + (67667 * (31 + 10 * BitStuffTime(bytecount))) /
42810 + 1000;
42811 + retval =
42812 + 64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
42813 + retval;
42814 + } else {
42815 + retval =
42816 + (66700 * (31 + 10 * BitStuffTime(bytecount))) /
42817 + 1000;
42818 + retval =
42819 + 64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
42820 + retval;
42821 + }
42822 + break;
42823 + default:
42824 + DWC_WARN("Unknown device speed\n");
42825 + retval = -1;
42826 + }
42827 +
42828 + return NS_TO_US(retval);
42829 +}
42830 +
42831 +/**
42832 + * Initializes a QH structure.
42833 + *
42834 + * @param hcd The HCD state structure for the DWC OTG controller.
42835 + * @param qh The QH to init.
42836 + * @param urb Holds the information about the device/endpoint that we need
42837 + * to initialize the QH.
42838 + */
42839 +#define SCHEDULE_SLOP 10
42840 +void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
42841 +{
42842 + char *speed, *type;
42843 + int dev_speed;
42844 + uint32_t hub_addr, hub_port;
42845 +
42846 + dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
42847 +
42848 + /* Initialize QH */
42849 + qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
42850 + qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
42851 +
42852 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
42853 + qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
42854 + DWC_CIRCLEQ_INIT(&qh->qtd_list);
42855 + DWC_LIST_INIT(&qh->qh_list_entry);
42856 + qh->channel = NULL;
42857 +
42858 + /* FS/LS Enpoint on HS Hub
42859 + * NOT virtual root hub */
42860 + dev_speed = hcd->fops->speed(hcd, urb->priv);
42861 +
42862 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
42863 + qh->do_split = 0;
42864 + if (microframe_schedule)
42865 + qh->speed = dev_speed;
42866 +
42867 +
42868 + if (((dev_speed == USB_SPEED_LOW) ||
42869 + (dev_speed == USB_SPEED_FULL)) &&
42870 + (hub_addr != 0 && hub_addr != 1)) {
42871 + DWC_DEBUGPL(DBG_HCD,
42872 + "QH init: EP %d: TT found at hub addr %d, for port %d\n",
42873 + dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
42874 + hub_port);
42875 + qh->do_split = 1;
42876 + }
42877 +
42878 + if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
42879 + /* Compute scheduling parameters once and save them. */
42880 + hprt0_data_t hprt;
42881 +
42882 + /** @todo Account for split transfers in the bus time. */
42883 + int bytecount =
42884 + dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
42885 +
42886 + qh->usecs =
42887 + calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
42888 + qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
42889 + bytecount);
42890 + /* Start in a slightly future (micro)frame. */
42891 + qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
42892 + SCHEDULE_SLOP);
42893 + qh->interval = urb->interval;
42894 +
42895 +#if 0
42896 + /* Increase interrupt polling rate for debugging. */
42897 + if (qh->ep_type == UE_INTERRUPT) {
42898 + qh->interval = 8;
42899 + }
42900 +#endif
42901 + hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
42902 + if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
42903 + ((dev_speed == USB_SPEED_LOW) ||
42904 + (dev_speed == USB_SPEED_FULL))) {
42905 + qh->interval *= 8;
42906 + qh->sched_frame |= 0x7;
42907 + qh->start_split_frame = qh->sched_frame;
42908 + }
42909 +
42910 + }
42911 +
42912 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
42913 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", qh);
42914 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n",
42915 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
42916 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n",
42917 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
42918 + dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
42919 + switch (dev_speed) {
42920 + case USB_SPEED_LOW:
42921 + qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
42922 + speed = "low";
42923 + break;
42924 + case USB_SPEED_FULL:
42925 + qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
42926 + speed = "full";
42927 + break;
42928 + case USB_SPEED_HIGH:
42929 + qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
42930 + speed = "high";
42931 + break;
42932 + default:
42933 + speed = "?";
42934 + break;
42935 + }
42936 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", speed);
42937 +
42938 + switch (qh->ep_type) {
42939 + case UE_ISOCHRONOUS:
42940 + type = "isochronous";
42941 + break;
42942 + case UE_INTERRUPT:
42943 + type = "interrupt";
42944 + break;
42945 + case UE_CONTROL:
42946 + type = "control";
42947 + break;
42948 + case UE_BULK:
42949 + type = "bulk";
42950 + break;
42951 + default:
42952 + type = "?";
42953 + break;
42954 + }
42955 +
42956 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", type);
42957 +
42958 +#ifdef DEBUG
42959 + if (qh->ep_type == UE_INTERRUPT) {
42960 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
42961 + qh->usecs);
42962 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
42963 + qh->interval);
42964 + }
42965 +#endif
42966 +
42967 +}
42968 +
42969 +/**
42970 + * This function allocates and initializes a QH.
42971 + *
42972 + * @param hcd The HCD state structure for the DWC OTG controller.
42973 + * @param urb Holds the information about the device/endpoint that we need
42974 + * to initialize the QH.
42975 + * @param atomic_alloc Flag to do atomic allocation if needed
42976 + *
42977 + * @return Returns pointer to the newly allocated QH, or NULL on error. */
42978 +dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
42979 + dwc_otg_hcd_urb_t * urb, int atomic_alloc)
42980 +{
42981 + dwc_otg_qh_t *qh;
42982 +
42983 + /* Allocate memory */
42984 + /** @todo add memflags argument */
42985 + qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
42986 + if (qh == NULL) {
42987 + DWC_ERROR("qh allocation failed");
42988 + return NULL;
42989 + }
42990 +
42991 + qh_init(hcd, qh, urb);
42992 +
42993 + if (hcd->core_if->dma_desc_enable
42994 + && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
42995 + dwc_otg_hcd_qh_free(hcd, qh);
42996 + return NULL;
42997 + }
42998 +
42999 + return qh;
43000 +}
43001 +
43002 +/* microframe_schedule=0 start */
43003 +
43004 +/**
43005 + * Checks that a channel is available for a periodic transfer.
43006 + *
43007 + * @return 0 if successful, negative error code otherise.
43008 + */
43009 +static int periodic_channel_available(dwc_otg_hcd_t * hcd)
43010 +{
43011 + /*
43012 + * Currently assuming that there is a dedicated host channnel for each
43013 + * periodic transaction plus at least one host channel for
43014 + * non-periodic transactions.
43015 + */
43016 + int status;
43017 + int num_channels;
43018 +
43019 + num_channels = hcd->core_if->core_params->host_channels;
43020 + if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
43021 + && (hcd->periodic_channels < num_channels - 1)) {
43022 + status = 0;
43023 + } else {
43024 + DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
43025 + __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels); //NOTICE
43026 + status = -DWC_E_NO_SPACE;
43027 + }
43028 +
43029 + return status;
43030 +}
43031 +
43032 +/**
43033 + * Checks that there is sufficient bandwidth for the specified QH in the
43034 + * periodic schedule. For simplicity, this calculation assumes that all the
43035 + * transfers in the periodic schedule may occur in the same (micro)frame.
43036 + *
43037 + * @param hcd The HCD state structure for the DWC OTG controller.
43038 + * @param qh QH containing periodic bandwidth required.
43039 + *
43040 + * @return 0 if successful, negative error code otherwise.
43041 + */
43042 +static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43043 +{
43044 + int status;
43045 + int16_t max_claimed_usecs;
43046 +
43047 + status = 0;
43048 +
43049 + if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
43050 + /*
43051 + * High speed mode.
43052 + * Max periodic usecs is 80% x 125 usec = 100 usec.
43053 + */
43054 +
43055 + max_claimed_usecs = 100 - qh->usecs;
43056 + } else {
43057 + /*
43058 + * Full speed mode.
43059 + * Max periodic usecs is 90% x 1000 usec = 900 usec.
43060 + */
43061 + max_claimed_usecs = 900 - qh->usecs;
43062 + }
43063 +
43064 + if (hcd->periodic_usecs > max_claimed_usecs) {
43065 + DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs); //NOTICE
43066 + status = -DWC_E_NO_SPACE;
43067 + }
43068 +
43069 + return status;
43070 +}
43071 +
43072 +/* microframe_schedule=0 end */
43073 +
43074 +/**
43075 + * Microframe scheduler
43076 + * track the total use in hcd->frame_usecs
43077 + * keep each qh use in qh->frame_usecs
43078 + * when surrendering the qh then donate the time back
43079 + */
43080 +const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 };
43081 +
43082 +/*
43083 + * called from dwc_otg_hcd.c:dwc_otg_hcd_init
43084 + */
43085 +int init_hcd_usecs(dwc_otg_hcd_t *_hcd)
43086 +{
43087 + int i;
43088 + for (i=0; i<8; i++) {
43089 + _hcd->frame_usecs[i] = max_uframe_usecs[i];
43090 + }
43091 + return 0;
43092 +}
43093 +
43094 +static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43095 +{
43096 + int i;
43097 + unsigned short utime;
43098 + int t_left;
43099 + int ret;
43100 + int done;
43101 +
43102 + ret = -1;
43103 + utime = _qh->usecs;
43104 + t_left = utime;
43105 + i = 0;
43106 + done = 0;
43107 + while (done == 0) {
43108 + /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */
43109 + if (utime <= _hcd->frame_usecs[i]) {
43110 + _hcd->frame_usecs[i] -= utime;
43111 + _qh->frame_usecs[i] += utime;
43112 + t_left -= utime;
43113 + ret = i;
43114 + done = 1;
43115 + return ret;
43116 + } else {
43117 + i++;
43118 + if (i == 8) {
43119 + done = 1;
43120 + ret = -1;
43121 + }
43122 + }
43123 + }
43124 + return ret;
43125 + }
43126 +
43127 +/*
43128 + * use this for FS apps that can span multiple uframes
43129 + */
43130 +static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43131 +{
43132 + int i;
43133 + int j;
43134 + unsigned short utime;
43135 + int t_left;
43136 + int ret;
43137 + int done;
43138 + unsigned short xtime;
43139 +
43140 + ret = -1;
43141 + utime = _qh->usecs;
43142 + t_left = utime;
43143 + i = 0;
43144 + done = 0;
43145 +loop:
43146 + while (done == 0) {
43147 + if(_hcd->frame_usecs[i] <= 0) {
43148 + i++;
43149 + if (i == 8) {
43150 + done = 1;
43151 + ret = -1;
43152 + }
43153 + goto loop;
43154 + }
43155 +
43156 + /*
43157 + * we need n consecutive slots
43158 + * so use j as a start slot j plus j+1 must be enough time (for now)
43159 + */
43160 + xtime= _hcd->frame_usecs[i];
43161 + for (j = i+1 ; j < 8 ; j++ ) {
43162 + /*
43163 + * if we add this frame remaining time to xtime we may
43164 + * be OK, if not we need to test j for a complete frame
43165 + */
43166 + if ((xtime+_hcd->frame_usecs[j]) < utime) {
43167 + if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) {
43168 + j = 8;
43169 + ret = -1;
43170 + continue;
43171 + }
43172 + }
43173 + if (xtime >= utime) {
43174 + ret = i;
43175 + j = 8; /* stop loop with a good value ret */
43176 + continue;
43177 + }
43178 + /* add the frame time to x time */
43179 + xtime += _hcd->frame_usecs[j];
43180 + /* we must have a fully available next frame or break */
43181 + if ((xtime < utime)
43182 + && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) {
43183 + ret = -1;
43184 + j = 8; /* stop loop with a bad value ret */
43185 + continue;
43186 + }
43187 + }
43188 + if (ret >= 0) {
43189 + t_left = utime;
43190 + for (j = i; (t_left>0) && (j < 8); j++ ) {
43191 + t_left -= _hcd->frame_usecs[j];
43192 + if ( t_left <= 0 ) {
43193 + _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left;
43194 + _hcd->frame_usecs[j]= -t_left;
43195 + ret = i;
43196 + done = 1;
43197 + } else {
43198 + _qh->frame_usecs[j] += _hcd->frame_usecs[j];
43199 + _hcd->frame_usecs[j] = 0;
43200 + }
43201 + }
43202 + } else {
43203 + i++;
43204 + if (i == 8) {
43205 + done = 1;
43206 + ret = -1;
43207 + }
43208 + }
43209 + }
43210 + return ret;
43211 +}
43212 +
43213 +static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43214 +{
43215 + int ret;
43216 + ret = -1;
43217 +
43218 + if (_qh->speed == USB_SPEED_HIGH) {
43219 + /* if this is a hs transaction we need a full frame */
43220 + ret = find_single_uframe(_hcd, _qh);
43221 + } else {
43222 + /* if this is a fs transaction we may need a sequence of frames */
43223 + ret = find_multi_uframe(_hcd, _qh);
43224 + }
43225 + return ret;
43226 +}
43227 +
43228 +/**
43229 + * Checks that the max transfer size allowed in a host channel is large enough
43230 + * to handle the maximum data transfer in a single (micro)frame for a periodic
43231 + * transfer.
43232 + *
43233 + * @param hcd The HCD state structure for the DWC OTG controller.
43234 + * @param qh QH for a periodic endpoint.
43235 + *
43236 + * @return 0 if successful, negative error code otherwise.
43237 + */
43238 +static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43239 +{
43240 + int status;
43241 + uint32_t max_xfer_size;
43242 + uint32_t max_channel_xfer_size;
43243 +
43244 + status = 0;
43245 +
43246 + max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
43247 + max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
43248 +
43249 + if (max_xfer_size > max_channel_xfer_size) {
43250 + DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
43251 + __func__, max_xfer_size, max_channel_xfer_size); //NOTICE
43252 + status = -DWC_E_NO_SPACE;
43253 + }
43254 +
43255 + return status;
43256 +}
43257 +
43258 +/**
43259 + * Schedules an interrupt or isochronous transfer in the periodic schedule.
43260 + *
43261 + * @param hcd The HCD state structure for the DWC OTG controller.
43262 + * @param qh QH for the periodic transfer. The QH should already contain the
43263 + * scheduling information.
43264 + *
43265 + * @return 0 if successful, negative error code otherwise.
43266 + */
43267 +static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43268 +{
43269 + int status = 0;
43270 +
43271 + if (microframe_schedule) {
43272 + int frame;
43273 + status = find_uframe(hcd, qh);
43274 + frame = -1;
43275 + if (status == 0) {
43276 + frame = 7;
43277 + } else {
43278 + if (status > 0 )
43279 + frame = status-1;
43280 + }
43281 +
43282 + /* Set the new frame up */
43283 + if (frame > -1) {
43284 + qh->sched_frame &= ~0x7;
43285 + qh->sched_frame |= (frame & 7);
43286 + }
43287 +
43288 + if (status != -1)
43289 + status = 0;
43290 + } else {
43291 + status = periodic_channel_available(hcd);
43292 + if (status) {
43293 + DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE
43294 + return status;
43295 + }
43296 +
43297 + status = check_periodic_bandwidth(hcd, qh);
43298 + }
43299 + if (status) {
43300 + DWC_INFO("%s: Insufficient periodic bandwidth for "
43301 + "periodic transfer.\n", __func__);
43302 + return status;
43303 + }
43304 + status = check_max_xfer_size(hcd, qh);
43305 + if (status) {
43306 + DWC_INFO("%s: Channel max transfer size too small "
43307 + "for periodic transfer.\n", __func__);
43308 + return status;
43309 + }
43310 +
43311 + if (hcd->core_if->dma_desc_enable) {
43312 + /* Don't rely on SOF and start in ready schedule */
43313 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
43314 + }
43315 + else {
43316 + /* Always start in the inactive schedule. */
43317 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
43318 + }
43319 +
43320 + if (!microframe_schedule) {
43321 + /* Reserve the periodic channel. */
43322 + hcd->periodic_channels++;
43323 + }
43324 +
43325 + /* Update claimed usecs per (micro)frame. */
43326 + hcd->periodic_usecs += qh->usecs;
43327 +
43328 + return status;
43329 +}
43330 +
43331 +/**
43332 + * This function adds a QH to either the non periodic or periodic schedule if
43333 + * it is not already in the schedule. If the QH is already in the schedule, no
43334 + * action is taken.
43335 + *
43336 + * @return 0 if successful, negative error code otherwise.
43337 + */
43338 +int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43339 +{
43340 + int status = 0;
43341 + gintmsk_data_t intr_mask = {.d32 = 0 };
43342 +
43343 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
43344 + /* QH already in a schedule. */
43345 + return status;
43346 + }
43347 +
43348 + /* Add the new QH to the appropriate schedule */
43349 + if (dwc_qh_is_non_per(qh)) {
43350 + /* Always start in the inactive schedule. */
43351 + DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
43352 + &qh->qh_list_entry);
43353 + } else {
43354 + status = schedule_periodic(hcd, qh);
43355 + if ( !hcd->periodic_qh_count ) {
43356 + intr_mask.b.sofintr = 1;
43357 + DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
43358 + intr_mask.d32, intr_mask.d32);
43359 + }
43360 + hcd->periodic_qh_count++;
43361 + }
43362 +
43363 + return status;
43364 +}
43365 +
43366 +/**
43367 + * Removes an interrupt or isochronous transfer from the periodic schedule.
43368 + *
43369 + * @param hcd The HCD state structure for the DWC OTG controller.
43370 + * @param qh QH for the periodic transfer.
43371 + */
43372 +static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43373 +{
43374 + int i;
43375 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
43376 +
43377 + /* Update claimed usecs per (micro)frame. */
43378 + hcd->periodic_usecs -= qh->usecs;
43379 +
43380 + if (!microframe_schedule) {
43381 + /* Release the periodic channel reservation. */
43382 + hcd->periodic_channels--;
43383 + } else {
43384 + for (i = 0; i < 8; i++) {
43385 + hcd->frame_usecs[i] += qh->frame_usecs[i];
43386 + qh->frame_usecs[i] = 0;
43387 + }
43388 + }
43389 +}
43390 +
43391 +/**
43392 + * Removes a QH from either the non-periodic or periodic schedule. Memory is
43393 + * not freed.
43394 + *
43395 + * @param hcd The HCD state structure.
43396 + * @param qh QH to remove from schedule. */
43397 +void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43398 +{
43399 + gintmsk_data_t intr_mask = {.d32 = 0 };
43400 +
43401 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
43402 + /* QH is not in a schedule. */
43403 + return;
43404 + }
43405 +
43406 + if (dwc_qh_is_non_per(qh)) {
43407 + if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
43408 + hcd->non_periodic_qh_ptr =
43409 + hcd->non_periodic_qh_ptr->next;
43410 + }
43411 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
43412 + } else {
43413 + deschedule_periodic(hcd, qh);
43414 + hcd->periodic_qh_count--;
43415 + if( !hcd->periodic_qh_count ) {
43416 + intr_mask.b.sofintr = 1;
43417 + DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
43418 + intr_mask.d32, 0);
43419 + }
43420 + }
43421 +}
43422 +
43423 +/**
43424 + * Deactivates a QH. For non-periodic QHs, removes the QH from the active
43425 + * non-periodic schedule. The QH is added to the inactive non-periodic
43426 + * schedule if any QTDs are still attached to the QH.
43427 + *
43428 + * For periodic QHs, the QH is removed from the periodic queued schedule. If
43429 + * there are any QTDs still attached to the QH, the QH is added to either the
43430 + * periodic inactive schedule or the periodic ready schedule and its next
43431 + * scheduled frame is calculated. The QH is placed in the ready schedule if
43432 + * the scheduled frame has been reached already. Otherwise it's placed in the
43433 + * inactive schedule. If there are no QTDs attached to the QH, the QH is
43434 + * completely removed from the periodic schedule.
43435 + */
43436 +void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
43437 + int sched_next_periodic_split)
43438 +{
43439 + if (dwc_qh_is_non_per(qh)) {
43440 + dwc_otg_hcd_qh_remove(hcd, qh);
43441 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
43442 + /* Add back to inactive non-periodic schedule. */
43443 + dwc_otg_hcd_qh_add(hcd, qh);
43444 + }
43445 + } else {
43446 + uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
43447 +
43448 + if (qh->do_split) {
43449 + /* Schedule the next continuing periodic split transfer */
43450 + if (sched_next_periodic_split) {
43451 +
43452 + qh->sched_frame = frame_number;
43453 + if (dwc_frame_num_le(frame_number,
43454 + dwc_frame_num_inc
43455 + (qh->start_split_frame,
43456 + 1))) {
43457 + /*
43458 + * Allow one frame to elapse after start
43459 + * split microframe before scheduling
43460 + * complete split, but DONT if we are
43461 + * doing the next start split in the
43462 + * same frame for an ISOC out.
43463 + */
43464 + if ((qh->ep_type != UE_ISOCHRONOUS) ||
43465 + (qh->ep_is_in != 0)) {
43466 + qh->sched_frame =
43467 + dwc_frame_num_inc(qh->sched_frame, 1);
43468 + }
43469 + }
43470 + } else {
43471 + qh->sched_frame =
43472 + dwc_frame_num_inc(qh->start_split_frame,
43473 + qh->interval);
43474 + if (dwc_frame_num_le
43475 + (qh->sched_frame, frame_number)) {
43476 + qh->sched_frame = frame_number;
43477 + }
43478 + qh->sched_frame |= 0x7;
43479 + qh->start_split_frame = qh->sched_frame;
43480 + }
43481 + } else {
43482 + qh->sched_frame =
43483 + dwc_frame_num_inc(qh->sched_frame, qh->interval);
43484 + if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
43485 + qh->sched_frame = frame_number;
43486 + }
43487 + }
43488 +
43489 + if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
43490 + dwc_otg_hcd_qh_remove(hcd, qh);
43491 + } else {
43492 + /*
43493 + * Remove from periodic_sched_queued and move to
43494 + * appropriate queue.
43495 + */
43496 + if ((microframe_schedule && dwc_frame_num_le(qh->sched_frame, frame_number)) ||
43497 + (!microframe_schedule && qh->sched_frame == frame_number)) {
43498 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
43499 + &qh->qh_list_entry);
43500 + } else {
43501 + DWC_LIST_MOVE_HEAD
43502 + (&hcd->periodic_sched_inactive,
43503 + &qh->qh_list_entry);
43504 + }
43505 + }
43506 + }
43507 +}
43508 +
43509 +/**
43510 + * This function allocates and initializes a QTD.
43511 + *
43512 + * @param urb The URB to create a QTD from. Each URB-QTD pair will end up
43513 + * pointing to each other so each pair should have a unique correlation.
43514 + * @param atomic_alloc Flag to do atomic alloc if needed
43515 + *
43516 + * @return Returns pointer to the newly allocated QTD, or NULL on error. */
43517 +dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
43518 +{
43519 + dwc_otg_qtd_t *qtd;
43520 +
43521 + qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
43522 + if (qtd == NULL) {
43523 + return NULL;
43524 + }
43525 +
43526 + dwc_otg_hcd_qtd_init(qtd, urb);
43527 + return qtd;
43528 +}
43529 +
43530 +/**
43531 + * Initializes a QTD structure.
43532 + *
43533 + * @param qtd The QTD to initialize.
43534 + * @param urb The URB to use for initialization. */
43535 +void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
43536 +{
43537 + dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
43538 + qtd->urb = urb;
43539 + if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
43540 + /*
43541 + * The only time the QTD data toggle is used is on the data
43542 + * phase of control transfers. This phase always starts with
43543 + * DATA1.
43544 + */
43545 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
43546 + qtd->control_phase = DWC_OTG_CONTROL_SETUP;
43547 + }
43548 +
43549 + /* start split */
43550 + qtd->complete_split = 0;
43551 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
43552 + qtd->isoc_split_offset = 0;
43553 + qtd->in_process = 0;
43554 +
43555 + /* Store the qtd ptr in the urb to reference what QTD. */
43556 + urb->qtd = qtd;
43557 + return;
43558 +}
43559 +
43560 +/**
43561 + * This function adds a QTD to the QTD-list of a QH. It will find the correct
43562 + * QH to place the QTD into. If it does not find a QH, then it will create a
43563 + * new QH. If the QH to which the QTD is added is not currently scheduled, it
43564 + * is placed into the proper schedule based on its EP type.
43565 + *
43566 + * @param[in] qtd The QTD to add
43567 + * @param[in] hcd The DWC HCD structure
43568 + * @param[out] qh out parameter to return queue head
43569 + * @param atomic_alloc Flag to do atomic alloc if needed
43570 + *
43571 + * @return 0 if successful, negative error code otherwise.
43572 + */
43573 +int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
43574 + dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
43575 +{
43576 + int retval = 0;
43577 + dwc_irqflags_t flags;
43578 +
43579 + dwc_otg_hcd_urb_t *urb = qtd->urb;
43580 +
43581 + /*
43582 + * Get the QH which holds the QTD-list to insert to. Create QH if it
43583 + * doesn't exist.
43584 + */
43585 + if (*qh == NULL) {
43586 + *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
43587 + if (*qh == NULL) {
43588 + retval = -1;
43589 + goto done;
43590 + }
43591 + }
43592 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
43593 + retval = dwc_otg_hcd_qh_add(hcd, *qh);
43594 + if (retval == 0) {
43595 + DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
43596 + qtd_list_entry);
43597 + }
43598 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
43599 +
43600 +done:
43601 +
43602 + return retval;
43603 +}
43604 +
43605 +#endif /* DWC_DEVICE_ONLY */
43606 --- /dev/null
43607 +++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
43608 @@ -0,0 +1,185 @@
43609 +#ifndef _DWC_OS_DEP_H_
43610 +#define _DWC_OS_DEP_H_
43611 +
43612 +/**
43613 + * @file
43614 + *
43615 + * This file contains OS dependent structures.
43616 + *
43617 + */
43618 +
43619 +#include <linux/kernel.h>
43620 +#include <linux/module.h>
43621 +#include <linux/moduleparam.h>
43622 +#include <linux/init.h>
43623 +#include <linux/device.h>
43624 +#include <linux/errno.h>
43625 +#include <linux/types.h>
43626 +#include <linux/slab.h>
43627 +#include <linux/list.h>
43628 +#include <linux/interrupt.h>
43629 +#include <linux/ctype.h>
43630 +#include <linux/string.h>
43631 +#include <linux/dma-mapping.h>
43632 +#include <linux/jiffies.h>
43633 +#include <linux/delay.h>
43634 +#include <linux/timer.h>
43635 +#include <linux/workqueue.h>
43636 +#include <linux/stat.h>
43637 +#include <linux/pci.h>
43638 +
43639 +#include <linux/version.h>
43640 +
43641 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
43642 +# include <linux/irq.h>
43643 +#endif
43644 +
43645 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
43646 +# include <linux/usb/ch9.h>
43647 +#else
43648 +# include <linux/usb_ch9.h>
43649 +#endif
43650 +
43651 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
43652 +# include <linux/usb/gadget.h>
43653 +#else
43654 +# include <linux/usb_gadget.h>
43655 +#endif
43656 +
43657 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
43658 +# include <asm/irq.h>
43659 +#endif
43660 +
43661 +#ifdef PCI_INTERFACE
43662 +# include <asm/io.h>
43663 +#endif
43664 +
43665 +#ifdef LM_INTERFACE
43666 +# include <asm/unaligned.h>
43667 +# include <asm/sizes.h>
43668 +# include <asm/param.h>
43669 +# include <asm/io.h>
43670 +# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
43671 +# include <asm/arch/hardware.h>
43672 +# include <asm/arch/lm.h>
43673 +# include <asm/arch/irqs.h>
43674 +# include <asm/arch/regs-irq.h>
43675 +# else
43676 +/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure -
43677 + here we assume that the machine architecture provides definitions
43678 + in its own header
43679 +*/
43680 +# include <mach/lm.h>
43681 +# include <mach/hardware.h>
43682 +# endif
43683 +#endif
43684 +
43685 +#ifdef PLATFORM_INTERFACE
43686 +#include <linux/platform_device.h>
43687 +#include <asm/mach/map.h>
43688 +#endif
43689 +
43690 +/** The OS page size */
43691 +#define DWC_OS_PAGE_SIZE PAGE_SIZE
43692 +
43693 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
43694 +typedef int gfp_t;
43695 +#endif
43696 +
43697 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
43698 +# define IRQF_SHARED SA_SHIRQ
43699 +#endif
43700 +
43701 +typedef struct os_dependent {
43702 + /** Base address returned from ioremap() */
43703 + void *base;
43704 +
43705 + /** Register offset for Diagnostic API */
43706 + uint32_t reg_offset;
43707 +
43708 +#ifdef LM_INTERFACE
43709 + struct lm_device *lmdev;
43710 +#elif defined(PCI_INTERFACE)
43711 + struct pci_dev *pcidev;
43712 +
43713 + /** Start address of a PCI region */
43714 + resource_size_t rsrc_start;
43715 +
43716 + /** Length address of a PCI region */
43717 + resource_size_t rsrc_len;
43718 +#elif defined(PLATFORM_INTERFACE)
43719 + struct platform_device *platformdev;
43720 +#endif
43721 +
43722 +} os_dependent_t;
43723 +
43724 +#ifdef __cplusplus
43725 +}
43726 +#endif
43727 +
43728 +
43729 +
43730 +/* Type for the our device on the chosen bus */
43731 +#if defined(LM_INTERFACE)
43732 +typedef struct lm_device dwc_bus_dev_t;
43733 +#elif defined(PCI_INTERFACE)
43734 +typedef struct pci_dev dwc_bus_dev_t;
43735 +#elif defined(PLATFORM_INTERFACE)
43736 +typedef struct platform_device dwc_bus_dev_t;
43737 +#endif
43738 +
43739 +/* Helper macro to retrieve drvdata from the device on the chosen bus */
43740 +#if defined(LM_INTERFACE)
43741 +#define DWC_OTG_BUSDRVDATA(_dev) lm_get_drvdata(_dev)
43742 +#elif defined(PCI_INTERFACE)
43743 +#define DWC_OTG_BUSDRVDATA(_dev) pci_get_drvdata(_dev)
43744 +#elif defined(PLATFORM_INTERFACE)
43745 +#define DWC_OTG_BUSDRVDATA(_dev) platform_get_drvdata(_dev)
43746 +#endif
43747 +
43748 +/**
43749 + * Helper macro returning the otg_device structure of a given struct device
43750 + *
43751 + * c.f. static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
43752 + */
43753 +#ifdef LM_INTERFACE
43754 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43755 + struct lm_device *lm_dev = \
43756 + container_of(_dev, struct lm_device, dev); \
43757 + _var = lm_get_drvdata(lm_dev); \
43758 + } while (0)
43759 +
43760 +#elif defined(PCI_INTERFACE)
43761 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43762 + _var = dev_get_drvdata(_dev); \
43763 + } while (0)
43764 +
43765 +#elif defined(PLATFORM_INTERFACE)
43766 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43767 + struct platform_device *platform_dev = \
43768 + container_of(_dev, struct platform_device, dev); \
43769 + _var = platform_get_drvdata(platform_dev); \
43770 + } while (0)
43771 +#endif
43772 +
43773 +
43774 +/**
43775 + * Helper macro returning the struct dev of the given struct os_dependent
43776 + *
43777 + * c.f. static struct device *dwc_otg_getdev(struct os_dependent *osdep)
43778 + */
43779 +#ifdef LM_INTERFACE
43780 +#define DWC_OTG_OS_GETDEV(_osdep) \
43781 + ((_osdep).lmdev == NULL? NULL: &(_osdep).lmdev->dev)
43782 +#elif defined(PCI_INTERFACE)
43783 +#define DWC_OTG_OS_GETDEV(_osdep) \
43784 + ((_osdep).pci_dev == NULL? NULL: &(_osdep).pci_dev->dev)
43785 +#elif defined(PLATFORM_INTERFACE)
43786 +#define DWC_OTG_OS_GETDEV(_osdep) \
43787 + ((_osdep).platformdev == NULL? NULL: &(_osdep).platformdev->dev)
43788 +#endif
43789 +
43790 +
43791 +
43792 +
43793 +#endif /* _DWC_OS_DEP_H_ */
43794 --- /dev/null
43795 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.c
43796 @@ -0,0 +1,2708 @@
43797 +/* ==========================================================================
43798 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
43799 + * $Revision: #101 $
43800 + * $Date: 2012/08/10 $
43801 + * $Change: 2047372 $
43802 + *
43803 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
43804 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
43805 + * otherwise expressly agreed to in writing between Synopsys and you.
43806 + *
43807 + * The Software IS NOT an item of Licensed Software or Licensed Product under
43808 + * any End User Software License Agreement or Agreement for Licensed Product
43809 + * with Synopsys or any supplement thereto. You are permitted to use and
43810 + * redistribute this Software in source and binary forms, with or without
43811 + * modification, provided that redistributions of source code must retain this
43812 + * notice. You may not view, use, disclose, copy or distribute this file or
43813 + * any information contained herein except pursuant to this license grant from
43814 + * Synopsys. If you do not agree with this notice, including the disclaimer
43815 + * below, then you are not authorized to use the Software.
43816 + *
43817 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
43818 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43819 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43820 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
43821 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43822 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43823 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
43824 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43825 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43826 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
43827 + * DAMAGE.
43828 + * ========================================================================== */
43829 +#ifndef DWC_HOST_ONLY
43830 +
43831 +/** @file
43832 + * This file implements PCD Core. All code in this file is portable and doesn't
43833 + * use any OS specific functions.
43834 + * PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code>
43835 + * header file, which can be used to implement OS specific PCD interface.
43836 + *
43837 + * An important function of the PCD is managing interrupts generated
43838 + * by the DWC_otg controller. The implementation of the DWC_otg device
43839 + * mode interrupt service routines is in dwc_otg_pcd_intr.c.
43840 + *
43841 + * @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
43842 + * @todo Does it work when the request size is greater than DEPTSIZ
43843 + * transfer size
43844 + *
43845 + */
43846 +
43847 +#include "dwc_otg_pcd.h"
43848 +
43849 +#ifdef DWC_UTE_CFI
43850 +#include "dwc_otg_cfi.h"
43851 +
43852 +extern int init_cfi(cfiobject_t * cfiobj);
43853 +#endif
43854 +
43855 +/**
43856 + * Choose endpoint from ep arrays using usb_ep structure.
43857 + */
43858 +static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
43859 +{
43860 + int i;
43861 + if (pcd->ep0.priv == handle) {
43862 + return &pcd->ep0;
43863 + }
43864 + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
43865 + if (pcd->in_ep[i].priv == handle)
43866 + return &pcd->in_ep[i];
43867 + if (pcd->out_ep[i].priv == handle)
43868 + return &pcd->out_ep[i];
43869 + }
43870 +
43871 + return NULL;
43872 +}
43873 +
43874 +/**
43875 + * This function completes a request. It call's the request call back.
43876 + */
43877 +void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req,
43878 + int32_t status)
43879 +{
43880 + unsigned stopped = ep->stopped;
43881 +
43882 + DWC_DEBUGPL(DBG_PCDV, "%s(ep %p req %p)\n", __func__, ep, req);
43883 + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
43884 +
43885 + /* don't modify queue heads during completion callback */
43886 + ep->stopped = 1;
43887 + /* spin_unlock/spin_lock now done in fops->complete() */
43888 + ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status,
43889 + req->actual);
43890 +
43891 + if (ep->pcd->request_pending > 0) {
43892 + --ep->pcd->request_pending;
43893 + }
43894 +
43895 + ep->stopped = stopped;
43896 + DWC_FREE(req);
43897 +}
43898 +
43899 +/**
43900 + * This function terminates all the requsts in the EP request queue.
43901 + */
43902 +void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep)
43903 +{
43904 + dwc_otg_pcd_request_t *req;
43905 +
43906 + ep->stopped = 1;
43907 +
43908 + /* called with irqs blocked?? */
43909 + while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
43910 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
43911 + dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN);
43912 + }
43913 +}
43914 +
43915 +void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
43916 + const struct dwc_otg_pcd_function_ops *fops)
43917 +{
43918 + pcd->fops = fops;
43919 +}
43920 +
43921 +/**
43922 + * PCD Callback function for initializing the PCD when switching to
43923 + * device mode.
43924 + *
43925 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
43926 + */
43927 +static int32_t dwc_otg_pcd_start_cb(void *p)
43928 +{
43929 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
43930 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
43931 +
43932 + /*
43933 + * Initialized the Core for Device mode.
43934 + */
43935 + if (dwc_otg_is_device_mode(core_if)) {
43936 + dwc_otg_core_dev_init(core_if);
43937 + /* Set core_if's lock pointer to the pcd->lock */
43938 + core_if->lock = pcd->lock;
43939 + }
43940 + return 1;
43941 +}
43942 +
43943 +/** CFI-specific buffer allocation function for EP */
43944 +#ifdef DWC_UTE_CFI
43945 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
43946 + size_t buflen, int flags)
43947 +{
43948 + dwc_otg_pcd_ep_t *ep;
43949 + ep = get_ep_from_handle(pcd, pep);
43950 + if (!ep) {
43951 + DWC_WARN("bad ep\n");
43952 + return -DWC_E_INVALID;
43953 + }
43954 +
43955 + return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen,
43956 + flags);
43957 +}
43958 +#else
43959 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
43960 + size_t buflen, int flags);
43961 +#endif
43962 +
43963 +/**
43964 + * PCD Callback function for notifying the PCD when resuming from
43965 + * suspend.
43966 + *
43967 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
43968 + */
43969 +static int32_t dwc_otg_pcd_resume_cb(void *p)
43970 +{
43971 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
43972 +
43973 + if (pcd->fops->resume) {
43974 + pcd->fops->resume(pcd);
43975 + }
43976 +
43977 + /* Stop the SRP timeout timer. */
43978 + if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS)
43979 + || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {
43980 + if (GET_CORE_IF(pcd)->srp_timer_started) {
43981 + GET_CORE_IF(pcd)->srp_timer_started = 0;
43982 + DWC_TIMER_CANCEL(GET_CORE_IF(pcd)->srp_timer);
43983 + }
43984 + }
43985 + return 1;
43986 +}
43987 +
43988 +/**
43989 + * PCD Callback function for notifying the PCD device is suspended.
43990 + *
43991 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
43992 + */
43993 +static int32_t dwc_otg_pcd_suspend_cb(void *p)
43994 +{
43995 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
43996 +
43997 + if (pcd->fops->suspend) {
43998 + DWC_SPINUNLOCK(pcd->lock);
43999 + pcd->fops->suspend(pcd);
44000 + DWC_SPINLOCK(pcd->lock);
44001 + }
44002 +
44003 + return 1;
44004 +}
44005 +
44006 +/**
44007 + * PCD Callback function for stopping the PCD when switching to Host
44008 + * mode.
44009 + *
44010 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44011 + */
44012 +static int32_t dwc_otg_pcd_stop_cb(void *p)
44013 +{
44014 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44015 + extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);
44016 +
44017 + dwc_otg_pcd_stop(pcd);
44018 + return 1;
44019 +}
44020 +
44021 +/**
44022 + * PCD Callback structure for handling mode switching.
44023 + */
44024 +static dwc_otg_cil_callbacks_t pcd_callbacks = {
44025 + .start = dwc_otg_pcd_start_cb,
44026 + .stop = dwc_otg_pcd_stop_cb,
44027 + .suspend = dwc_otg_pcd_suspend_cb,
44028 + .resume_wakeup = dwc_otg_pcd_resume_cb,
44029 + .p = 0, /* Set at registration */
44030 +};
44031 +
44032 +/**
44033 + * This function allocates a DMA Descriptor chain for the Endpoint
44034 + * buffer to be used for a transfer to/from the specified endpoint.
44035 + */
44036 +dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(dwc_dma_t * dma_desc_addr,
44037 + uint32_t count)
44038 +{
44039 + return DWC_DMA_ALLOC_ATOMIC(count * sizeof(dwc_otg_dev_dma_desc_t),
44040 + dma_desc_addr);
44041 +}
44042 +
44043 +/**
44044 + * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc.
44045 + */
44046 +void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr,
44047 + uint32_t dma_desc_addr, uint32_t count)
44048 +{
44049 + DWC_DMA_FREE(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr,
44050 + dma_desc_addr);
44051 +}
44052 +
44053 +#ifdef DWC_EN_ISOC
44054 +
44055 +/**
44056 + * This function initializes a descriptor chain for Isochronous transfer
44057 + *
44058 + * @param core_if Programming view of DWC_otg controller.
44059 + * @param dwc_ep The EP to start the transfer on.
44060 + *
44061 + */
44062 +void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if,
44063 + dwc_ep_t * dwc_ep)
44064 +{
44065 +
44066 + dsts_data_t dsts = {.d32 = 0 };
44067 + depctl_data_t depctl = {.d32 = 0 };
44068 + volatile uint32_t *addr;
44069 + int i, j;
44070 + uint32_t len;
44071 +
44072 + if (dwc_ep->is_in)
44073 + dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;
44074 + else
44075 + dwc_ep->desc_cnt =
44076 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44077 + dwc_ep->bInterval;
44078 +
44079 + /** Allocate descriptors for double buffering */
44080 + dwc_ep->iso_desc_addr =
44081 + dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr,
44082 + dwc_ep->desc_cnt * 2);
44083 + if (dwc_ep->desc_addr) {
44084 + DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__);
44085 + return;
44086 + }
44087 +
44088 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44089 +
44090 + /** ISO OUT EP */
44091 + if (dwc_ep->is_in == 0) {
44092 + dev_dma_desc_sts_t sts = {.d32 = 0 };
44093 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
44094 + dma_addr_t dma_ad;
44095 + uint32_t data_per_desc;
44096 + dwc_otg_dev_out_ep_regs_t *out_regs =
44097 + core_if->dev_if->out_ep_regs[dwc_ep->num];
44098 + int offset;
44099 +
44100 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
44101 + dma_ad = (dma_addr_t) DWC_READ_REG32(&(out_regs->doepdma));
44102 +
44103 + /** Buffer 0 descriptors setup */
44104 + dma_ad = dwc_ep->dma_addr0;
44105 +
44106 + sts.b_iso_out.bs = BS_HOST_READY;
44107 + sts.b_iso_out.rxsts = 0;
44108 + sts.b_iso_out.l = 0;
44109 + sts.b_iso_out.sp = 0;
44110 + sts.b_iso_out.ioc = 0;
44111 + sts.b_iso_out.pid = 0;
44112 + sts.b_iso_out.framenum = 0;
44113 +
44114 + offset = 0;
44115 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44116 + i += dwc_ep->pkt_per_frm) {
44117 +
44118 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
44119 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44120 + if (len > dwc_ep->data_per_frame)
44121 + data_per_desc =
44122 + dwc_ep->data_per_frame -
44123 + j * dwc_ep->maxpacket;
44124 + else
44125 + data_per_desc = dwc_ep->maxpacket;
44126 + len = data_per_desc % 4;
44127 + if (len)
44128 + data_per_desc += 4 - len;
44129 +
44130 + sts.b_iso_out.rxbytes = data_per_desc;
44131 + dma_desc->buf = dma_ad;
44132 + dma_desc->status.d32 = sts.d32;
44133 +
44134 + offset += data_per_desc;
44135 + dma_desc++;
44136 + dma_ad += data_per_desc;
44137 + }
44138 + }
44139 +
44140 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
44141 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44142 + if (len > dwc_ep->data_per_frame)
44143 + data_per_desc =
44144 + dwc_ep->data_per_frame -
44145 + j * dwc_ep->maxpacket;
44146 + else
44147 + data_per_desc = dwc_ep->maxpacket;
44148 + len = data_per_desc % 4;
44149 + if (len)
44150 + data_per_desc += 4 - len;
44151 + sts.b_iso_out.rxbytes = data_per_desc;
44152 + dma_desc->buf = dma_ad;
44153 + dma_desc->status.d32 = sts.d32;
44154 +
44155 + offset += data_per_desc;
44156 + dma_desc++;
44157 + dma_ad += data_per_desc;
44158 + }
44159 +
44160 + sts.b_iso_out.ioc = 1;
44161 + len = (j + 1) * dwc_ep->maxpacket;
44162 + if (len > dwc_ep->data_per_frame)
44163 + data_per_desc =
44164 + dwc_ep->data_per_frame - j * dwc_ep->maxpacket;
44165 + else
44166 + data_per_desc = dwc_ep->maxpacket;
44167 + len = data_per_desc % 4;
44168 + if (len)
44169 + data_per_desc += 4 - len;
44170 + sts.b_iso_out.rxbytes = data_per_desc;
44171 +
44172 + dma_desc->buf = dma_ad;
44173 + dma_desc->status.d32 = sts.d32;
44174 + dma_desc++;
44175 +
44176 + /** Buffer 1 descriptors setup */
44177 + sts.b_iso_out.ioc = 0;
44178 + dma_ad = dwc_ep->dma_addr1;
44179 +
44180 + offset = 0;
44181 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44182 + i += dwc_ep->pkt_per_frm) {
44183 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
44184 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44185 + if (len > dwc_ep->data_per_frame)
44186 + data_per_desc =
44187 + dwc_ep->data_per_frame -
44188 + j * dwc_ep->maxpacket;
44189 + else
44190 + data_per_desc = dwc_ep->maxpacket;
44191 + len = data_per_desc % 4;
44192 + if (len)
44193 + data_per_desc += 4 - len;
44194 +
44195 + data_per_desc =
44196 + sts.b_iso_out.rxbytes = data_per_desc;
44197 + dma_desc->buf = dma_ad;
44198 + dma_desc->status.d32 = sts.d32;
44199 +
44200 + offset += data_per_desc;
44201 + dma_desc++;
44202 + dma_ad += data_per_desc;
44203 + }
44204 + }
44205 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
44206 + data_per_desc =
44207 + ((j + 1) * dwc_ep->maxpacket >
44208 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
44209 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
44210 + data_per_desc +=
44211 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
44212 + sts.b_iso_out.rxbytes = data_per_desc;
44213 + dma_desc->buf = dma_ad;
44214 + dma_desc->status.d32 = sts.d32;
44215 +
44216 + offset += data_per_desc;
44217 + dma_desc++;
44218 + dma_ad += data_per_desc;
44219 + }
44220 +
44221 + sts.b_iso_out.ioc = 1;
44222 + sts.b_iso_out.l = 1;
44223 + data_per_desc =
44224 + ((j + 1) * dwc_ep->maxpacket >
44225 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
44226 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
44227 + data_per_desc +=
44228 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
44229 + sts.b_iso_out.rxbytes = data_per_desc;
44230 +
44231 + dma_desc->buf = dma_ad;
44232 + dma_desc->status.d32 = sts.d32;
44233 +
44234 + dwc_ep->next_frame = 0;
44235 +
44236 + /** Write dma_ad into DOEPDMA register */
44237 + DWC_WRITE_REG32(&(out_regs->doepdma),
44238 + (uint32_t) dwc_ep->iso_dma_desc_addr);
44239 +
44240 + }
44241 + /** ISO IN EP */
44242 + else {
44243 + dev_dma_desc_sts_t sts = {.d32 = 0 };
44244 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
44245 + dma_addr_t dma_ad;
44246 + dwc_otg_dev_in_ep_regs_t *in_regs =
44247 + core_if->dev_if->in_ep_regs[dwc_ep->num];
44248 + unsigned int frmnumber;
44249 + fifosize_data_t txfifosize, rxfifosize;
44250 +
44251 + txfifosize.d32 =
44252 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[dwc_ep->num]->
44253 + dtxfsts);
44254 + rxfifosize.d32 =
44255 + DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
44256 +
44257 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
44258 +
44259 + dma_ad = dwc_ep->dma_addr0;
44260 +
44261 + dsts.d32 =
44262 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44263 +
44264 + sts.b_iso_in.bs = BS_HOST_READY;
44265 + sts.b_iso_in.txsts = 0;
44266 + sts.b_iso_in.sp =
44267 + (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;
44268 + sts.b_iso_in.ioc = 0;
44269 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
44270 +
44271 + frmnumber = dwc_ep->next_frame;
44272 +
44273 + sts.b_iso_in.framenum = frmnumber;
44274 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
44275 + sts.b_iso_in.l = 0;
44276 +
44277 + /** Buffer 0 descriptors setup */
44278 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
44279 + dma_desc->buf = dma_ad;
44280 + dma_desc->status.d32 = sts.d32;
44281 + dma_desc++;
44282 +
44283 + dma_ad += dwc_ep->data_per_frame;
44284 + sts.b_iso_in.framenum += dwc_ep->bInterval;
44285 + }
44286 +
44287 + sts.b_iso_in.ioc = 1;
44288 + dma_desc->buf = dma_ad;
44289 + dma_desc->status.d32 = sts.d32;
44290 + ++dma_desc;
44291 +
44292 + /** Buffer 1 descriptors setup */
44293 + sts.b_iso_in.ioc = 0;
44294 + dma_ad = dwc_ep->dma_addr1;
44295 +
44296 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44297 + i += dwc_ep->pkt_per_frm) {
44298 + dma_desc->buf = dma_ad;
44299 + dma_desc->status.d32 = sts.d32;
44300 + dma_desc++;
44301 +
44302 + dma_ad += dwc_ep->data_per_frame;
44303 + sts.b_iso_in.framenum += dwc_ep->bInterval;
44304 +
44305 + sts.b_iso_in.ioc = 0;
44306 + }
44307 + sts.b_iso_in.ioc = 1;
44308 + sts.b_iso_in.l = 1;
44309 +
44310 + dma_desc->buf = dma_ad;
44311 + dma_desc->status.d32 = sts.d32;
44312 +
44313 + dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval;
44314 +
44315 + /** Write dma_ad into diepdma register */
44316 + DWC_WRITE_REG32(&(in_regs->diepdma),
44317 + (uint32_t) dwc_ep->iso_dma_desc_addr);
44318 + }
44319 + /** Enable endpoint, clear nak */
44320 + depctl.d32 = 0;
44321 + depctl.b.epena = 1;
44322 + depctl.b.usbactep = 1;
44323 + depctl.b.cnak = 1;
44324 +
44325 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
44326 + depctl.d32 = DWC_READ_REG32(addr);
44327 +}
44328 +
44329 +/**
44330 + * This function initializes a descriptor chain for Isochronous transfer
44331 + *
44332 + * @param core_if Programming view of DWC_otg controller.
44333 + * @param ep The EP to start the transfer on.
44334 + *
44335 + */
44336 +void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
44337 + dwc_ep_t * ep)
44338 +{
44339 + depctl_data_t depctl = {.d32 = 0 };
44340 + volatile uint32_t *addr;
44341 +
44342 + if (ep->is_in) {
44343 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
44344 + } else {
44345 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
44346 + }
44347 +
44348 + if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) {
44349 + return;
44350 + } else {
44351 + deptsiz_data_t deptsiz = {.d32 = 0 };
44352 +
44353 + ep->xfer_len =
44354 + ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval;
44355 + ep->pkt_cnt =
44356 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
44357 + ep->xfer_count = 0;
44358 + ep->xfer_buff =
44359 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
44360 + ep->dma_addr =
44361 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
44362 +
44363 + if (ep->is_in) {
44364 + /* Program the transfer size and packet count
44365 + * as follows: xfersize = N * maxpacket +
44366 + * short_packet pktcnt = N + (short_packet
44367 + * exist ? 1 : 0)
44368 + */
44369 + deptsiz.b.mc = ep->pkt_per_frm;
44370 + deptsiz.b.xfersize = ep->xfer_len;
44371 + deptsiz.b.pktcnt =
44372 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
44373 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
44374 + dieptsiz, deptsiz.d32);
44375 +
44376 + /* Write the DMA register */
44377 + DWC_WRITE_REG32(&
44378 + (core_if->dev_if->in_ep_regs[ep->num]->
44379 + diepdma), (uint32_t) ep->dma_addr);
44380 +
44381 + } else {
44382 + deptsiz.b.pktcnt =
44383 + (ep->xfer_len + (ep->maxpacket - 1)) /
44384 + ep->maxpacket;
44385 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
44386 +
44387 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
44388 + doeptsiz, deptsiz.d32);
44389 +
44390 + /* Write the DMA register */
44391 + DWC_WRITE_REG32(&
44392 + (core_if->dev_if->out_ep_regs[ep->num]->
44393 + doepdma), (uint32_t) ep->dma_addr);
44394 +
44395 + }
44396 + /** Enable endpoint, clear nak */
44397 + depctl.d32 = 0;
44398 + depctl.b.epena = 1;
44399 + depctl.b.cnak = 1;
44400 +
44401 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
44402 + }
44403 +}
44404 +
44405 +/**
44406 + * This function does the setup for a data transfer for an EP and
44407 + * starts the transfer. For an IN transfer, the packets will be
44408 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
44409 + * the packets are unloaded from the Rx FIFO in the ISR.
44410 + *
44411 + * @param core_if Programming view of DWC_otg controller.
44412 + * @param ep The EP to start the transfer on.
44413 + */
44414 +
44415 +static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if,
44416 + dwc_ep_t * ep)
44417 +{
44418 + if (core_if->dma_enable) {
44419 + if (core_if->dma_desc_enable) {
44420 + if (ep->is_in) {
44421 + ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm;
44422 + } else {
44423 + ep->desc_cnt = ep->pkt_cnt;
44424 + }
44425 + dwc_otg_iso_ep_start_ddma_transfer(core_if, ep);
44426 + } else {
44427 + if (core_if->pti_enh_enable) {
44428 + dwc_otg_iso_ep_start_buf_transfer(core_if, ep);
44429 + } else {
44430 + ep->cur_pkt_addr =
44431 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->
44432 + xfer_buff0;
44433 + ep->cur_pkt_dma_addr =
44434 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->
44435 + dma_addr0;
44436 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
44437 + }
44438 + }
44439 + } else {
44440 + ep->cur_pkt_addr =
44441 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
44442 + ep->cur_pkt_dma_addr =
44443 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
44444 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
44445 + }
44446 +}
44447 +
44448 +/**
44449 + * This function stops transfer for an EP and
44450 + * resets the ep's variables.
44451 + *
44452 + * @param core_if Programming view of DWC_otg controller.
44453 + * @param ep The EP to start the transfer on.
44454 + */
44455 +
44456 +void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
44457 +{
44458 + depctl_data_t depctl = {.d32 = 0 };
44459 + volatile uint32_t *addr;
44460 +
44461 + if (ep->is_in == 1) {
44462 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
44463 + } else {
44464 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
44465 + }
44466 +
44467 + /* disable the ep */
44468 + depctl.d32 = DWC_READ_REG32(addr);
44469 +
44470 + depctl.b.epdis = 1;
44471 + depctl.b.snak = 1;
44472 +
44473 + DWC_WRITE_REG32(addr, depctl.d32);
44474 +
44475 + if (core_if->dma_desc_enable &&
44476 + ep->iso_desc_addr && ep->iso_dma_desc_addr) {
44477 + dwc_otg_ep_free_desc_chain(ep->iso_desc_addr,
44478 + ep->iso_dma_desc_addr,
44479 + ep->desc_cnt * 2);
44480 + }
44481 +
44482 + /* reset varibales */
44483 + ep->dma_addr0 = 0;
44484 + ep->dma_addr1 = 0;
44485 + ep->xfer_buff0 = 0;
44486 + ep->xfer_buff1 = 0;
44487 + ep->data_per_frame = 0;
44488 + ep->data_pattern_frame = 0;
44489 + ep->sync_frame = 0;
44490 + ep->buf_proc_intrvl = 0;
44491 + ep->bInterval = 0;
44492 + ep->proc_buf_num = 0;
44493 + ep->pkt_per_frm = 0;
44494 + ep->pkt_per_frm = 0;
44495 + ep->desc_cnt = 0;
44496 + ep->iso_desc_addr = 0;
44497 + ep->iso_dma_desc_addr = 0;
44498 +}
44499 +
44500 +int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
44501 + uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0,
44502 + dwc_dma_t dma1, int sync_frame, int dp_frame,
44503 + int data_per_frame, int start_frame,
44504 + int buf_proc_intrvl, void *req_handle,
44505 + int atomic_alloc)
44506 +{
44507 + dwc_otg_pcd_ep_t *ep;
44508 + dwc_irqflags_t flags = 0;
44509 + dwc_ep_t *dwc_ep;
44510 + int32_t frm_data;
44511 + dsts_data_t dsts;
44512 + dwc_otg_core_if_t *core_if;
44513 +
44514 + ep = get_ep_from_handle(pcd, ep_handle);
44515 +
44516 + if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
44517 + DWC_WARN("bad ep\n");
44518 + return -DWC_E_INVALID;
44519 + }
44520 +
44521 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
44522 + core_if = GET_CORE_IF(pcd);
44523 + dwc_ep = &ep->dwc_ep;
44524 +
44525 + if (ep->iso_req_handle) {
44526 + DWC_WARN("ISO request in progress\n");
44527 + }
44528 +
44529 + dwc_ep->dma_addr0 = dma0;
44530 + dwc_ep->dma_addr1 = dma1;
44531 +
44532 + dwc_ep->xfer_buff0 = buf0;
44533 + dwc_ep->xfer_buff1 = buf1;
44534 +
44535 + dwc_ep->data_per_frame = data_per_frame;
44536 +
44537 + /** @todo - pattern data support is to be implemented in the future */
44538 + dwc_ep->data_pattern_frame = dp_frame;
44539 + dwc_ep->sync_frame = sync_frame;
44540 +
44541 + dwc_ep->buf_proc_intrvl = buf_proc_intrvl;
44542 +
44543 + dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);
44544 +
44545 + dwc_ep->proc_buf_num = 0;
44546 +
44547 + dwc_ep->pkt_per_frm = 0;
44548 + frm_data = ep->dwc_ep.data_per_frame;
44549 + while (frm_data > 0) {
44550 + dwc_ep->pkt_per_frm++;
44551 + frm_data -= ep->dwc_ep.maxpacket;
44552 + }
44553 +
44554 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44555 +
44556 + if (start_frame == -1) {
44557 + dwc_ep->next_frame = dsts.b.soffn + 1;
44558 + if (dwc_ep->bInterval != 1) {
44559 + dwc_ep->next_frame =
44560 + dwc_ep->next_frame + (dwc_ep->bInterval - 1 -
44561 + dwc_ep->next_frame %
44562 + dwc_ep->bInterval);
44563 + }
44564 + } else {
44565 + dwc_ep->next_frame = start_frame;
44566 + }
44567 +
44568 + if (!core_if->pti_enh_enable) {
44569 + dwc_ep->pkt_cnt =
44570 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44571 + dwc_ep->bInterval;
44572 + } else {
44573 + dwc_ep->pkt_cnt =
44574 + (dwc_ep->data_per_frame *
44575 + (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval)
44576 + - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket;
44577 + }
44578 +
44579 + if (core_if->dma_desc_enable) {
44580 + dwc_ep->desc_cnt =
44581 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44582 + dwc_ep->bInterval;
44583 + }
44584 +
44585 + if (atomic_alloc) {
44586 + dwc_ep->pkt_info =
44587 + DWC_ALLOC_ATOMIC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44588 + } else {
44589 + dwc_ep->pkt_info =
44590 + DWC_ALLOC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44591 + }
44592 + if (!dwc_ep->pkt_info) {
44593 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44594 + return -DWC_E_NO_MEMORY;
44595 + }
44596 + if (core_if->pti_enh_enable) {
44597 + dwc_memset(dwc_ep->pkt_info, 0,
44598 + sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44599 + }
44600 +
44601 + dwc_ep->cur_pkt = 0;
44602 + ep->iso_req_handle = req_handle;
44603 +
44604 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44605 + dwc_otg_iso_ep_start_transfer(core_if, dwc_ep);
44606 + return 0;
44607 +}
44608 +
44609 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
44610 + void *req_handle)
44611 +{
44612 + dwc_irqflags_t flags = 0;
44613 + dwc_otg_pcd_ep_t *ep;
44614 + dwc_ep_t *dwc_ep;
44615 +
44616 + ep = get_ep_from_handle(pcd, ep_handle);
44617 + if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
44618 + DWC_WARN("bad ep\n");
44619 + return -DWC_E_INVALID;
44620 + }
44621 + dwc_ep = &ep->dwc_ep;
44622 +
44623 + dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep);
44624 +
44625 + DWC_FREE(dwc_ep->pkt_info);
44626 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
44627 + if (ep->iso_req_handle != req_handle) {
44628 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44629 + return -DWC_E_INVALID;
44630 + }
44631 +
44632 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44633 +
44634 + ep->iso_req_handle = 0;
44635 + return 0;
44636 +}
44637 +
44638 +/**
44639 + * This function is used for perodical data exchnage between PCD and gadget drivers.
44640 + * for Isochronous EPs
44641 + *
44642 + * - Every time a sync period completes this function is called to
44643 + * perform data exchange between PCD and gadget
44644 + */
44645 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
44646 + void *req_handle)
44647 +{
44648 + int i;
44649 + dwc_ep_t *dwc_ep;
44650 +
44651 + dwc_ep = &ep->dwc_ep;
44652 +
44653 + DWC_SPINUNLOCK(ep->pcd->lock);
44654 + pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle,
44655 + dwc_ep->proc_buf_num ^ 0x1);
44656 + DWC_SPINLOCK(ep->pcd->lock);
44657 +
44658 + for (i = 0; i < dwc_ep->pkt_cnt; ++i) {
44659 + dwc_ep->pkt_info[i].status = 0;
44660 + dwc_ep->pkt_info[i].offset = 0;
44661 + dwc_ep->pkt_info[i].length = 0;
44662 + }
44663 +}
44664 +
44665 +int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle,
44666 + void *iso_req_handle)
44667 +{
44668 + dwc_otg_pcd_ep_t *ep;
44669 + dwc_ep_t *dwc_ep;
44670 +
44671 + ep = get_ep_from_handle(pcd, ep_handle);
44672 + if (!ep->desc || ep->dwc_ep.num == 0) {
44673 + DWC_WARN("bad ep\n");
44674 + return -DWC_E_INVALID;
44675 + }
44676 + dwc_ep = &ep->dwc_ep;
44677 +
44678 + return dwc_ep->pkt_cnt;
44679 +}
44680 +
44681 +void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle,
44682 + void *iso_req_handle, int packet,
44683 + int *status, int *actual, int *offset)
44684 +{
44685 + dwc_otg_pcd_ep_t *ep;
44686 + dwc_ep_t *dwc_ep;
44687 +
44688 + ep = get_ep_from_handle(pcd, ep_handle);
44689 + if (!ep)
44690 + DWC_WARN("bad ep\n");
44691 +
44692 + dwc_ep = &ep->dwc_ep;
44693 +
44694 + *status = dwc_ep->pkt_info[packet].status;
44695 + *actual = dwc_ep->pkt_info[packet].length;
44696 + *offset = dwc_ep->pkt_info[packet].offset;
44697 +}
44698 +
44699 +#endif /* DWC_EN_ISOC */
44700 +
44701 +static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
44702 + uint32_t is_in, uint32_t ep_num)
44703 +{
44704 + /* Init EP structure */
44705 + pcd_ep->desc = 0;
44706 + pcd_ep->pcd = pcd;
44707 + pcd_ep->stopped = 1;
44708 + pcd_ep->queue_sof = 0;
44709 +
44710 + /* Init DWC ep structure */
44711 + pcd_ep->dwc_ep.is_in = is_in;
44712 + pcd_ep->dwc_ep.num = ep_num;
44713 + pcd_ep->dwc_ep.active = 0;
44714 + pcd_ep->dwc_ep.tx_fifo_num = 0;
44715 + /* Control until ep is actvated */
44716 + pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
44717 + pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
44718 + pcd_ep->dwc_ep.dma_addr = 0;
44719 + pcd_ep->dwc_ep.start_xfer_buff = 0;
44720 + pcd_ep->dwc_ep.xfer_buff = 0;
44721 + pcd_ep->dwc_ep.xfer_len = 0;
44722 + pcd_ep->dwc_ep.xfer_count = 0;
44723 + pcd_ep->dwc_ep.sent_zlp = 0;
44724 + pcd_ep->dwc_ep.total_len = 0;
44725 + pcd_ep->dwc_ep.desc_addr = 0;
44726 + pcd_ep->dwc_ep.dma_desc_addr = 0;
44727 + DWC_CIRCLEQ_INIT(&pcd_ep->queue);
44728 +}
44729 +
44730 +/**
44731 + * Initialize ep's
44732 + */
44733 +static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
44734 +{
44735 + int i;
44736 + uint32_t hwcfg1;
44737 + dwc_otg_pcd_ep_t *ep;
44738 + int in_ep_cntr, out_ep_cntr;
44739 + uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
44740 + uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
44741 +
44742 + /**
44743 + * Initialize the EP0 structure.
44744 + */
44745 + ep = &pcd->ep0;
44746 + dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
44747 +
44748 + in_ep_cntr = 0;
44749 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
44750 + for (i = 1; in_ep_cntr < num_in_eps; i++) {
44751 + if ((hwcfg1 & 0x1) == 0) {
44752 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr];
44753 + in_ep_cntr++;
44754 + /**
44755 + * @todo NGS: Add direction to EP, based on contents
44756 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
44757 + * sprintf(";r
44758 + */
44759 + dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
44760 +
44761 + DWC_CIRCLEQ_INIT(&ep->queue);
44762 + }
44763 + hwcfg1 >>= 2;
44764 + }
44765 +
44766 + out_ep_cntr = 0;
44767 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
44768 + for (i = 1; out_ep_cntr < num_out_eps; i++) {
44769 + if ((hwcfg1 & 0x1) == 0) {
44770 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr];
44771 + out_ep_cntr++;
44772 + /**
44773 + * @todo NGS: Add direction to EP, based on contents
44774 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
44775 + * sprintf(";r
44776 + */
44777 + dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
44778 + DWC_CIRCLEQ_INIT(&ep->queue);
44779 + }
44780 + hwcfg1 >>= 2;
44781 + }
44782 +
44783 + pcd->ep0state = EP0_DISCONNECT;
44784 + pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
44785 + pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
44786 +}
44787 +
44788 +/**
44789 + * This function is called when the SRP timer expires. The SRP should
44790 + * complete within 6 seconds.
44791 + */
44792 +static void srp_timeout(void *ptr)
44793 +{
44794 + gotgctl_data_t gotgctl;
44795 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
44796 + volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
44797 +
44798 + gotgctl.d32 = DWC_READ_REG32(addr);
44799 +
44800 + core_if->srp_timer_started = 0;
44801 +
44802 + if (core_if->adp_enable) {
44803 + if (gotgctl.b.bsesvld == 0) {
44804 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
44805 + DWC_PRINTF("SRP Timeout BSESSVLD = 0\n");
44806 + /* Power off the core */
44807 + if (core_if->power_down == 2) {
44808 + gpwrdn.b.pwrdnswtch = 1;
44809 + DWC_MODIFY_REG32(&core_if->
44810 + core_global_regs->gpwrdn,
44811 + gpwrdn.d32, 0);
44812 + }
44813 +
44814 + gpwrdn.d32 = 0;
44815 + gpwrdn.b.pmuintsel = 1;
44816 + gpwrdn.b.pmuactv = 1;
44817 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
44818 + gpwrdn.d32);
44819 + dwc_otg_adp_probe_start(core_if);
44820 + } else {
44821 + DWC_PRINTF("SRP Timeout BSESSVLD = 1\n");
44822 + core_if->op_state = B_PERIPHERAL;
44823 + dwc_otg_core_init(core_if);
44824 + dwc_otg_enable_global_interrupts(core_if);
44825 + cil_pcd_start(core_if);
44826 + }
44827 + }
44828 +
44829 + if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
44830 + (core_if->core_params->i2c_enable)) {
44831 + DWC_PRINTF("SRP Timeout\n");
44832 +
44833 + if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {
44834 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
44835 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
44836 + }
44837 +
44838 + /* Clear Session Request */
44839 + gotgctl.d32 = 0;
44840 + gotgctl.b.sesreq = 1;
44841 + DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
44842 + gotgctl.d32, 0);
44843 +
44844 + core_if->srp_success = 0;
44845 + } else {
44846 + __DWC_ERROR("Device not connected/responding\n");
44847 + gotgctl.b.sesreq = 0;
44848 + DWC_WRITE_REG32(addr, gotgctl.d32);
44849 + }
44850 + } else if (gotgctl.b.sesreq) {
44851 + DWC_PRINTF("SRP Timeout\n");
44852 +
44853 + __DWC_ERROR("Device not connected/responding\n");
44854 + gotgctl.b.sesreq = 0;
44855 + DWC_WRITE_REG32(addr, gotgctl.d32);
44856 + } else {
44857 + DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32);
44858 + }
44859 +}
44860 +
44861 +/**
44862 + * Tasklet
44863 + *
44864 + */
44865 +extern void start_next_request(dwc_otg_pcd_ep_t * ep);
44866 +
44867 +static void start_xfer_tasklet_func(void *data)
44868 +{
44869 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
44870 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
44871 +
44872 + int i;
44873 + depctl_data_t diepctl;
44874 +
44875 + DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
44876 +
44877 + diepctl.d32 = DWC_READ_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl);
44878 +
44879 + if (pcd->ep0.queue_sof) {
44880 + pcd->ep0.queue_sof = 0;
44881 + start_next_request(&pcd->ep0);
44882 + // break;
44883 + }
44884 +
44885 + for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
44886 + depctl_data_t diepctl;
44887 + diepctl.d32 =
44888 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
44889 +
44890 + if (pcd->in_ep[i].queue_sof) {
44891 + pcd->in_ep[i].queue_sof = 0;
44892 + start_next_request(&pcd->in_ep[i]);
44893 + // break;
44894 + }
44895 + }
44896 +
44897 + return;
44898 +}
44899 +
44900 +/**
44901 + * This function initialized the PCD portion of the driver.
44902 + *
44903 + */
44904 +dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
44905 +{
44906 + dwc_otg_pcd_t *pcd = NULL;
44907 + dwc_otg_dev_if_t *dev_if;
44908 + int i;
44909 +
44910 + /*
44911 + * Allocate PCD structure
44912 + */
44913 + pcd = DWC_ALLOC(sizeof(dwc_otg_pcd_t));
44914 +
44915 + if (pcd == NULL) {
44916 + return NULL;
44917 + }
44918 +
44919 + pcd->lock = DWC_SPINLOCK_ALLOC();
44920 + DWC_DEBUGPL(DBG_HCDV, "Init of PCD %p given core_if %p\n",
44921 + pcd, core_if);//GRAYG
44922 + if (!pcd->lock) {
44923 + DWC_ERROR("Could not allocate lock for pcd");
44924 + DWC_FREE(pcd);
44925 + return NULL;
44926 + }
44927 + /* Set core_if's lock pointer to hcd->lock */
44928 + core_if->lock = pcd->lock;
44929 + pcd->core_if = core_if;
44930 +
44931 + dev_if = core_if->dev_if;
44932 + dev_if->isoc_ep = NULL;
44933 +
44934 + if (core_if->hwcfg4.b.ded_fifo_en) {
44935 + DWC_PRINTF("Dedicated Tx FIFOs mode\n");
44936 + } else {
44937 + DWC_PRINTF("Shared Tx FIFO mode\n");
44938 + }
44939 +
44940 + /*
44941 + * Initialized the Core for Device mode here if there is nod ADP support.
44942 + * Otherwise it will be done later in dwc_otg_adp_start routine.
44943 + */
44944 + if (dwc_otg_is_device_mode(core_if) /*&& !core_if->adp_enable*/) {
44945 + dwc_otg_core_dev_init(core_if);
44946 + }
44947 +
44948 + /*
44949 + * Register the PCD Callbacks.
44950 + */
44951 + dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd);
44952 +
44953 + /*
44954 + * Initialize the DMA buffer for SETUP packets
44955 + */
44956 + if (GET_CORE_IF(pcd)->dma_enable) {
44957 + pcd->setup_pkt =
44958 + DWC_DMA_ALLOC(sizeof(*pcd->setup_pkt) * 5,
44959 + &pcd->setup_pkt_dma_handle);
44960 + if (pcd->setup_pkt == NULL) {
44961 + DWC_FREE(pcd);
44962 + return NULL;
44963 + }
44964 +
44965 + pcd->status_buf =
44966 + DWC_DMA_ALLOC(sizeof(uint16_t),
44967 + &pcd->status_buf_dma_handle);
44968 + if (pcd->status_buf == NULL) {
44969 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
44970 + pcd->setup_pkt, pcd->setup_pkt_dma_handle);
44971 + DWC_FREE(pcd);
44972 + return NULL;
44973 + }
44974 +
44975 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
44976 + dev_if->setup_desc_addr[0] =
44977 + dwc_otg_ep_alloc_desc_chain
44978 + (&dev_if->dma_setup_desc_addr[0], 1);
44979 + dev_if->setup_desc_addr[1] =
44980 + dwc_otg_ep_alloc_desc_chain
44981 + (&dev_if->dma_setup_desc_addr[1], 1);
44982 + dev_if->in_desc_addr =
44983 + dwc_otg_ep_alloc_desc_chain
44984 + (&dev_if->dma_in_desc_addr, 1);
44985 + dev_if->out_desc_addr =
44986 + dwc_otg_ep_alloc_desc_chain
44987 + (&dev_if->dma_out_desc_addr, 1);
44988 + pcd->data_terminated = 0;
44989 +
44990 + if (dev_if->setup_desc_addr[0] == 0
44991 + || dev_if->setup_desc_addr[1] == 0
44992 + || dev_if->in_desc_addr == 0
44993 + || dev_if->out_desc_addr == 0) {
44994 +
44995 + if (dev_if->out_desc_addr)
44996 + dwc_otg_ep_free_desc_chain
44997 + (dev_if->out_desc_addr,
44998 + dev_if->dma_out_desc_addr, 1);
44999 + if (dev_if->in_desc_addr)
45000 + dwc_otg_ep_free_desc_chain
45001 + (dev_if->in_desc_addr,
45002 + dev_if->dma_in_desc_addr, 1);
45003 + if (dev_if->setup_desc_addr[1])
45004 + dwc_otg_ep_free_desc_chain
45005 + (dev_if->setup_desc_addr[1],
45006 + dev_if->dma_setup_desc_addr[1], 1);
45007 + if (dev_if->setup_desc_addr[0])
45008 + dwc_otg_ep_free_desc_chain
45009 + (dev_if->setup_desc_addr[0],
45010 + dev_if->dma_setup_desc_addr[0], 1);
45011 +
45012 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
45013 + pcd->setup_pkt,
45014 + pcd->setup_pkt_dma_handle);
45015 + DWC_DMA_FREE(sizeof(*pcd->status_buf),
45016 + pcd->status_buf,
45017 + pcd->status_buf_dma_handle);
45018 +
45019 + DWC_FREE(pcd);
45020 +
45021 + return NULL;
45022 + }
45023 + }
45024 + } else {
45025 + pcd->setup_pkt = DWC_ALLOC(sizeof(*pcd->setup_pkt) * 5);
45026 + if (pcd->setup_pkt == NULL) {
45027 + DWC_FREE(pcd);
45028 + return NULL;
45029 + }
45030 +
45031 + pcd->status_buf = DWC_ALLOC(sizeof(uint16_t));
45032 + if (pcd->status_buf == NULL) {
45033 + DWC_FREE(pcd->setup_pkt);
45034 + DWC_FREE(pcd);
45035 + return NULL;
45036 + }
45037 + }
45038 +
45039 + dwc_otg_pcd_reinit(pcd);
45040 +
45041 + /* Allocate the cfi object for the PCD */
45042 +#ifdef DWC_UTE_CFI
45043 + pcd->cfi = DWC_ALLOC(sizeof(cfiobject_t));
45044 + if (NULL == pcd->cfi)
45045 + goto fail;
45046 + if (init_cfi(pcd->cfi)) {
45047 + CFI_INFO("%s: Failed to init the CFI object\n", __func__);
45048 + goto fail;
45049 + }
45050 +#endif
45051 +
45052 + /* Initialize tasklets */
45053 + pcd->start_xfer_tasklet = DWC_TASK_ALLOC("xfer_tasklet",
45054 + start_xfer_tasklet_func, pcd);
45055 + pcd->test_mode_tasklet = DWC_TASK_ALLOC("test_mode_tasklet",
45056 + do_test_mode, pcd);
45057 +
45058 + /* Initialize SRP timer */
45059 + core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
45060 +
45061 + if (core_if->core_params->dev_out_nak) {
45062 + /**
45063 + * Initialize xfer timeout timer. Implemented for
45064 + * 2.93a feature "Device DDMA OUT NAK Enhancement"
45065 + */
45066 + for(i = 0; i < MAX_EPS_CHANNELS; i++) {
45067 + pcd->core_if->ep_xfer_timer[i] =
45068 + DWC_TIMER_ALLOC("ep timer", ep_xfer_timeout,
45069 + &pcd->core_if->ep_xfer_info[i]);
45070 + }
45071 + }
45072 +
45073 + return pcd;
45074 +#ifdef DWC_UTE_CFI
45075 +fail:
45076 +#endif
45077 + if (pcd->setup_pkt)
45078 + DWC_FREE(pcd->setup_pkt);
45079 + if (pcd->status_buf)
45080 + DWC_FREE(pcd->status_buf);
45081 +#ifdef DWC_UTE_CFI
45082 + if (pcd->cfi)
45083 + DWC_FREE(pcd->cfi);
45084 +#endif
45085 + if (pcd)
45086 + DWC_FREE(pcd);
45087 + return NULL;
45088 +
45089 +}
45090 +
45091 +/**
45092 + * Remove PCD specific data
45093 + */
45094 +void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd)
45095 +{
45096 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
45097 + int i;
45098 + if (pcd->core_if->core_params->dev_out_nak) {
45099 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
45100 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[i]);
45101 + pcd->core_if->ep_xfer_info[i].state = 0;
45102 + }
45103 + }
45104 +
45105 + if (GET_CORE_IF(pcd)->dma_enable) {
45106 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt,
45107 + pcd->setup_pkt_dma_handle);
45108 + DWC_DMA_FREE(sizeof(uint16_t), pcd->status_buf,
45109 + pcd->status_buf_dma_handle);
45110 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45111 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0],
45112 + dev_if->dma_setup_desc_addr
45113 + [0], 1);
45114 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1],
45115 + dev_if->dma_setup_desc_addr
45116 + [1], 1);
45117 + dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr,
45118 + dev_if->dma_in_desc_addr, 1);
45119 + dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr,
45120 + dev_if->dma_out_desc_addr,
45121 + 1);
45122 + }
45123 + } else {
45124 + DWC_FREE(pcd->setup_pkt);
45125 + DWC_FREE(pcd->status_buf);
45126 + }
45127 + DWC_SPINLOCK_FREE(pcd->lock);
45128 + /* Set core_if's lock pointer to NULL */
45129 + pcd->core_if->lock = NULL;
45130 +
45131 + DWC_TASK_FREE(pcd->start_xfer_tasklet);
45132 + DWC_TASK_FREE(pcd->test_mode_tasklet);
45133 + if (pcd->core_if->core_params->dev_out_nak) {
45134 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
45135 + if (pcd->core_if->ep_xfer_timer[i]) {
45136 + DWC_TIMER_FREE(pcd->core_if->ep_xfer_timer[i]);
45137 + }
45138 + }
45139 + }
45140 +
45141 +/* Release the CFI object's dynamic memory */
45142 +#ifdef DWC_UTE_CFI
45143 + if (pcd->cfi->ops.release) {
45144 + pcd->cfi->ops.release(pcd->cfi);
45145 + }
45146 +#endif
45147 +
45148 + DWC_FREE(pcd);
45149 +}
45150 +
45151 +/**
45152 + * Returns whether registered pcd is dual speed or not
45153 + */
45154 +uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd)
45155 +{
45156 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45157 +
45158 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) ||
45159 + ((core_if->hwcfg2.b.hs_phy_type == 2) &&
45160 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
45161 + (core_if->core_params->ulpi_fs_ls))) {
45162 + return 0;
45163 + }
45164 +
45165 + return 1;
45166 +}
45167 +
45168 +/**
45169 + * Returns whether registered pcd is OTG capable or not
45170 + */
45171 +uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd)
45172 +{
45173 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45174 + gusbcfg_data_t usbcfg = {.d32 = 0 };
45175 +
45176 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
45177 + if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) {
45178 + return 0;
45179 + }
45180 +
45181 + return 1;
45182 +}
45183 +
45184 +/**
45185 + * This function assigns periodic Tx FIFO to an periodic EP
45186 + * in shared Tx FIFO mode
45187 + */
45188 +static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if)
45189 +{
45190 + uint32_t TxMsk = 1;
45191 + int i;
45192 +
45193 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) {
45194 + if ((TxMsk & core_if->tx_msk) == 0) {
45195 + core_if->tx_msk |= TxMsk;
45196 + return i + 1;
45197 + }
45198 + TxMsk <<= 1;
45199 + }
45200 + return 0;
45201 +}
45202 +
45203 +/**
45204 + * This function assigns periodic Tx FIFO to an periodic EP
45205 + * in shared Tx FIFO mode
45206 + */
45207 +static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if)
45208 +{
45209 + uint32_t PerTxMsk = 1;
45210 + int i;
45211 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) {
45212 + if ((PerTxMsk & core_if->p_tx_msk) == 0) {
45213 + core_if->p_tx_msk |= PerTxMsk;
45214 + return i + 1;
45215 + }
45216 + PerTxMsk <<= 1;
45217 + }
45218 + return 0;
45219 +}
45220 +
45221 +/**
45222 + * This function releases periodic Tx FIFO
45223 + * in shared Tx FIFO mode
45224 + */
45225 +static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if,
45226 + uint32_t fifo_num)
45227 +{
45228 + core_if->p_tx_msk =
45229 + (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
45230 +}
45231 +
45232 +/**
45233 + * This function releases periodic Tx FIFO
45234 + * in shared Tx FIFO mode
45235 + */
45236 +static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num)
45237 +{
45238 + core_if->tx_msk =
45239 + (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
45240 +}
45241 +
45242 +/**
45243 + * This function is being called from gadget
45244 + * to enable PCD endpoint.
45245 + */
45246 +int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
45247 + const uint8_t * ep_desc, void *usb_ep)
45248 +{
45249 + int num, dir;
45250 + dwc_otg_pcd_ep_t *ep = NULL;
45251 + const usb_endpoint_descriptor_t *desc;
45252 + dwc_irqflags_t flags;
45253 + fifosize_data_t dptxfsiz = {.d32 = 0 };
45254 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
45255 + gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
45256 + int retval = 0;
45257 + int i, epcount;
45258 +
45259 + desc = (const usb_endpoint_descriptor_t *)ep_desc;
45260 +
45261 + if (!desc) {
45262 + pcd->ep0.priv = usb_ep;
45263 + ep = &pcd->ep0;
45264 + retval = -DWC_E_INVALID;
45265 + goto out;
45266 + }
45267 +
45268 + num = UE_GET_ADDR(desc->bEndpointAddress);
45269 + dir = UE_GET_DIR(desc->bEndpointAddress);
45270 +
45271 + if (!desc->wMaxPacketSize) {
45272 + DWC_WARN("bad maxpacketsize\n");
45273 + retval = -DWC_E_INVALID;
45274 + goto out;
45275 + }
45276 +
45277 + if (dir == UE_DIR_IN) {
45278 + epcount = pcd->core_if->dev_if->num_in_eps;
45279 + for (i = 0; i < epcount; i++) {
45280 + if (num == pcd->in_ep[i].dwc_ep.num) {
45281 + ep = &pcd->in_ep[i];
45282 + break;
45283 + }
45284 + }
45285 + } else {
45286 + epcount = pcd->core_if->dev_if->num_out_eps;
45287 + for (i = 0; i < epcount; i++) {
45288 + if (num == pcd->out_ep[i].dwc_ep.num) {
45289 + ep = &pcd->out_ep[i];
45290 + break;
45291 + }
45292 + }
45293 + }
45294 +
45295 + if (!ep) {
45296 + DWC_WARN("bad address\n");
45297 + retval = -DWC_E_INVALID;
45298 + goto out;
45299 + }
45300 +
45301 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45302 +
45303 + ep->desc = desc;
45304 + ep->priv = usb_ep;
45305 +
45306 + /*
45307 + * Activate the EP
45308 + */
45309 + ep->stopped = 0;
45310 +
45311 + ep->dwc_ep.is_in = (dir == UE_DIR_IN);
45312 + ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize);
45313 +
45314 + ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE;
45315 +
45316 + if (ep->dwc_ep.is_in) {
45317 + if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45318 + ep->dwc_ep.tx_fifo_num = 0;
45319 +
45320 + if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
45321 + /*
45322 + * if ISOC EP then assign a Periodic Tx FIFO.
45323 + */
45324 + ep->dwc_ep.tx_fifo_num =
45325 + assign_perio_tx_fifo(GET_CORE_IF(pcd));
45326 + }
45327 + } else {
45328 + /*
45329 + * if Dedicated FIFOs mode is on then assign a Tx FIFO.
45330 + */
45331 + ep->dwc_ep.tx_fifo_num =
45332 + assign_tx_fifo(GET_CORE_IF(pcd));
45333 + }
45334 +
45335 + /* Calculating EP info controller base address */
45336 + if (ep->dwc_ep.tx_fifo_num
45337 + && GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45338 + gdfifocfg.d32 =
45339 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
45340 + core_global_regs->gdfifocfg);
45341 + gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
45342 + dptxfsiz.d32 =
45343 + (DWC_READ_REG32
45344 + (&GET_CORE_IF(pcd)->core_global_regs->
45345 + dtxfsiz[ep->dwc_ep.tx_fifo_num - 1]) >> 16);
45346 + gdfifocfg.b.epinfobase =
45347 + gdfifocfgbase.d32 + dptxfsiz.d32;
45348 + if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
45349 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
45350 + core_global_regs->gdfifocfg,
45351 + gdfifocfg.d32);
45352 + }
45353 + }
45354 + }
45355 + /* Set initial data PID. */
45356 + if (ep->dwc_ep.type == UE_BULK) {
45357 + ep->dwc_ep.data_pid_start = 0;
45358 + }
45359 +
45360 + /* Alloc DMA Descriptors */
45361 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45362 +#ifndef DWC_UTE_PER_IO
45363 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
45364 +#endif
45365 + ep->dwc_ep.desc_addr =
45366 + dwc_otg_ep_alloc_desc_chain(&ep->
45367 + dwc_ep.dma_desc_addr,
45368 + MAX_DMA_DESC_CNT);
45369 + if (!ep->dwc_ep.desc_addr) {
45370 + DWC_WARN("%s, can't allocate DMA descriptor\n",
45371 + __func__);
45372 + retval = -DWC_E_SHUTDOWN;
45373 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45374 + goto out;
45375 + }
45376 +#ifndef DWC_UTE_PER_IO
45377 + }
45378 +#endif
45379 + }
45380 +
45381 + DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n",
45382 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
45383 + ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc);
45384 +#ifdef DWC_UTE_PER_IO
45385 + ep->dwc_ep.xiso_bInterval = 1 << (ep->desc->bInterval - 1);
45386 +#endif
45387 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
45388 + ep->dwc_ep.bInterval = 1 << (ep->desc->bInterval - 1);
45389 + ep->dwc_ep.frame_num = 0xFFFFFFFF;
45390 + }
45391 +
45392 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
45393 +
45394 +#ifdef DWC_UTE_CFI
45395 + if (pcd->cfi->ops.ep_enable) {
45396 + pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep);
45397 + }
45398 +#endif
45399 +
45400 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45401 +
45402 +out:
45403 + return retval;
45404 +}
45405 +
45406 +/**
45407 + * This function is being called from gadget
45408 + * to disable PCD endpoint.
45409 + */
45410 +int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle)
45411 +{
45412 + dwc_otg_pcd_ep_t *ep;
45413 + dwc_irqflags_t flags;
45414 + dwc_otg_dev_dma_desc_t *desc_addr;
45415 + dwc_dma_t dma_desc_addr;
45416 + gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
45417 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
45418 + fifosize_data_t dptxfsiz = {.d32 = 0 };
45419 +
45420 + ep = get_ep_from_handle(pcd, ep_handle);
45421 +
45422 + if (!ep || !ep->desc) {
45423 + DWC_DEBUGPL(DBG_PCD, "bad ep address\n");
45424 + return -DWC_E_INVALID;
45425 + }
45426 +
45427 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45428 +
45429 + dwc_otg_request_nuke(ep);
45430 +
45431 + dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep);
45432 + if (pcd->core_if->core_params->dev_out_nak) {
45433 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[ep->dwc_ep.num]);
45434 + pcd->core_if->ep_xfer_info[ep->dwc_ep.num].state = 0;
45435 + }
45436 + ep->desc = NULL;
45437 + ep->stopped = 1;
45438 +
45439 + gdfifocfg.d32 =
45440 + DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg);
45441 + gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
45442 +
45443 + if (ep->dwc_ep.is_in) {
45444 + if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45445 + /* Flush the Tx FIFO */
45446 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd),
45447 + ep->dwc_ep.tx_fifo_num);
45448 + }
45449 + release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
45450 + release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
45451 + if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45452 + /* Decreasing EPinfo Base Addr */
45453 + dptxfsiz.d32 =
45454 + (DWC_READ_REG32
45455 + (&GET_CORE_IF(pcd)->
45456 + core_global_regs->dtxfsiz[ep->dwc_ep.tx_fifo_num-1]) >> 16);
45457 + gdfifocfg.b.epinfobase = gdfifocfgbase.d32 - dptxfsiz.d32;
45458 + if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
45459 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg,
45460 + gdfifocfg.d32);
45461 + }
45462 + }
45463 + }
45464 +
45465 + /* Free DMA Descriptors */
45466 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45467 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
45468 + desc_addr = ep->dwc_ep.desc_addr;
45469 + dma_desc_addr = ep->dwc_ep.dma_desc_addr;
45470 +
45471 + /* Cannot call dma_free_coherent() with IRQs disabled */
45472 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45473 + dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
45474 + MAX_DMA_DESC_CNT);
45475 +
45476 + goto out_unlocked;
45477 + }
45478 + }
45479 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45480 +
45481 +out_unlocked:
45482 + DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num,
45483 + ep->dwc_ep.is_in ? "IN" : "OUT");
45484 + return 0;
45485 +
45486 +}
45487 +
45488 +/******************************************************************************/
45489 +#ifdef DWC_UTE_PER_IO
45490 +
45491 +/**
45492 + * Free the request and its extended parts
45493 + *
45494 + */
45495 +void dwc_pcd_xiso_ereq_free(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req)
45496 +{
45497 + DWC_FREE(req->ext_req.per_io_frame_descs);
45498 + DWC_FREE(req);
45499 +}
45500 +
45501 +/**
45502 + * Start the next request in the endpoint's queue.
45503 + *
45504 + */
45505 +int dwc_otg_pcd_xiso_start_next_request(dwc_otg_pcd_t * pcd,
45506 + dwc_otg_pcd_ep_t * ep)
45507 +{
45508 + int i;
45509 + dwc_otg_pcd_request_t *req = NULL;
45510 + dwc_ep_t *dwcep = NULL;
45511 + struct dwc_iso_xreq_port *ereq = NULL;
45512 + struct dwc_iso_pkt_desc_port *ddesc_iso;
45513 + uint16_t nat;
45514 + depctl_data_t diepctl;
45515 +
45516 + dwcep = &ep->dwc_ep;
45517 +
45518 + if (dwcep->xiso_active_xfers > 0) {
45519 +#if 0 //Disable this to decrease s/w overhead that is crucial for Isoc transfers
45520 + DWC_WARN("There are currently active transfers for EP%d \
45521 + (active=%d; queued=%d)", dwcep->num, dwcep->xiso_active_xfers,
45522 + dwcep->xiso_queued_xfers);
45523 +#endif
45524 + return 0;
45525 + }
45526 +
45527 + nat = UGETW(ep->desc->wMaxPacketSize);
45528 + nat = (nat >> 11) & 0x03;
45529 +
45530 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
45531 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
45532 + ereq = &req->ext_req;
45533 + ep->stopped = 0;
45534 +
45535 + /* Get the frame number */
45536 + dwcep->xiso_frame_num =
45537 + dwc_otg_get_frame_number(GET_CORE_IF(pcd));
45538 + DWC_DEBUG("FRM_NUM=%d", dwcep->xiso_frame_num);
45539 +
45540 + ddesc_iso = ereq->per_io_frame_descs;
45541 +
45542 + if (dwcep->is_in) {
45543 + /* Setup DMA Descriptor chain for IN Isoc request */
45544 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45545 + //if ((i % (nat + 1)) == 0)
45546 + if ( i > 0 )
45547 + dwcep->xiso_frame_num =
45548 + (dwcep->xiso_bInterval +
45549 + dwcep->xiso_frame_num) & 0x3FFF;
45550 + dwcep->desc_addr[i].buf =
45551 + req->dma + ddesc_iso[i].offset;
45552 + dwcep->desc_addr[i].status.b_iso_in.txbytes =
45553 + ddesc_iso[i].length;
45554 + dwcep->desc_addr[i].status.b_iso_in.framenum =
45555 + dwcep->xiso_frame_num;
45556 + dwcep->desc_addr[i].status.b_iso_in.bs =
45557 + BS_HOST_READY;
45558 + dwcep->desc_addr[i].status.b_iso_in.txsts = 0;
45559 + dwcep->desc_addr[i].status.b_iso_in.sp =
45560 + (ddesc_iso[i].length %
45561 + dwcep->maxpacket) ? 1 : 0;
45562 + dwcep->desc_addr[i].status.b_iso_in.ioc = 0;
45563 + dwcep->desc_addr[i].status.b_iso_in.pid = nat + 1;
45564 + dwcep->desc_addr[i].status.b_iso_in.l = 0;
45565 +
45566 + /* Process the last descriptor */
45567 + if (i == ereq->pio_pkt_count - 1) {
45568 + dwcep->desc_addr[i].status.b_iso_in.ioc = 1;
45569 + dwcep->desc_addr[i].status.b_iso_in.l = 1;
45570 + }
45571 + }
45572 +
45573 + /* Setup and start the transfer for this endpoint */
45574 + dwcep->xiso_active_xfers++;
45575 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if->
45576 + in_ep_regs[dwcep->num]->diepdma,
45577 + dwcep->dma_desc_addr);
45578 + diepctl.d32 = 0;
45579 + diepctl.b.epena = 1;
45580 + diepctl.b.cnak = 1;
45581 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
45582 + in_ep_regs[dwcep->num]->diepctl, 0,
45583 + diepctl.d32);
45584 + } else {
45585 + /* Setup DMA Descriptor chain for OUT Isoc request */
45586 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45587 + //if ((i % (nat + 1)) == 0)
45588 + dwcep->xiso_frame_num = (dwcep->xiso_bInterval +
45589 + dwcep->xiso_frame_num) & 0x3FFF;
45590 + dwcep->desc_addr[i].buf =
45591 + req->dma + ddesc_iso[i].offset;
45592 + dwcep->desc_addr[i].status.b_iso_out.rxbytes =
45593 + ddesc_iso[i].length;
45594 + dwcep->desc_addr[i].status.b_iso_out.framenum =
45595 + dwcep->xiso_frame_num;
45596 + dwcep->desc_addr[i].status.b_iso_out.bs =
45597 + BS_HOST_READY;
45598 + dwcep->desc_addr[i].status.b_iso_out.rxsts = 0;
45599 + dwcep->desc_addr[i].status.b_iso_out.sp =
45600 + (ddesc_iso[i].length %
45601 + dwcep->maxpacket) ? 1 : 0;
45602 + dwcep->desc_addr[i].status.b_iso_out.ioc = 0;
45603 + dwcep->desc_addr[i].status.b_iso_out.pid = nat + 1;
45604 + dwcep->desc_addr[i].status.b_iso_out.l = 0;
45605 +
45606 + /* Process the last descriptor */
45607 + if (i == ereq->pio_pkt_count - 1) {
45608 + dwcep->desc_addr[i].status.b_iso_out.ioc = 1;
45609 + dwcep->desc_addr[i].status.b_iso_out.l = 1;
45610 + }
45611 + }
45612 +
45613 + /* Setup and start the transfer for this endpoint */
45614 + dwcep->xiso_active_xfers++;
45615 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
45616 + dev_if->out_ep_regs[dwcep->num]->
45617 + doepdma, dwcep->dma_desc_addr);
45618 + diepctl.d32 = 0;
45619 + diepctl.b.epena = 1;
45620 + diepctl.b.cnak = 1;
45621 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
45622 + dev_if->out_ep_regs[dwcep->num]->
45623 + doepctl, 0, diepctl.d32);
45624 + }
45625 +
45626 + } else {
45627 + ep->stopped = 1;
45628 + }
45629 +
45630 + return 0;
45631 +}
45632 +
45633 +/**
45634 + * - Remove the request from the queue
45635 + */
45636 +void complete_xiso_ep(dwc_otg_pcd_ep_t * ep)
45637 +{
45638 + dwc_otg_pcd_request_t *req = NULL;
45639 + struct dwc_iso_xreq_port *ereq = NULL;
45640 + struct dwc_iso_pkt_desc_port *ddesc_iso = NULL;
45641 + dwc_ep_t *dwcep = NULL;
45642 + int i;
45643 +
45644 + //DWC_DEBUG();
45645 + dwcep = &ep->dwc_ep;
45646 +
45647 + /* Get the first pending request from the queue */
45648 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
45649 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
45650 + if (!req) {
45651 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
45652 + return;
45653 + }
45654 + dwcep->xiso_active_xfers--;
45655 + dwcep->xiso_queued_xfers--;
45656 + /* Remove this request from the queue */
45657 + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
45658 + } else {
45659 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
45660 + return;
45661 + }
45662 +
45663 + ep->stopped = 1;
45664 + ereq = &req->ext_req;
45665 + ddesc_iso = ereq->per_io_frame_descs;
45666 +
45667 + if (dwcep->xiso_active_xfers < 0) {
45668 + DWC_WARN("EP#%d (xiso_active_xfers=%d)", dwcep->num,
45669 + dwcep->xiso_active_xfers);
45670 + }
45671 +
45672 + /* Fill the Isoc descs of portable extended req from dma descriptors */
45673 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45674 + if (dwcep->is_in) { /* IN endpoints */
45675 + ddesc_iso[i].actual_length = ddesc_iso[i].length -
45676 + dwcep->desc_addr[i].status.b_iso_in.txbytes;
45677 + ddesc_iso[i].status =
45678 + dwcep->desc_addr[i].status.b_iso_in.txsts;
45679 + } else { /* OUT endpoints */
45680 + ddesc_iso[i].actual_length = ddesc_iso[i].length -
45681 + dwcep->desc_addr[i].status.b_iso_out.rxbytes;
45682 + ddesc_iso[i].status =
45683 + dwcep->desc_addr[i].status.b_iso_out.rxsts;
45684 + }
45685 + }
45686 +
45687 + DWC_SPINUNLOCK(ep->pcd->lock);
45688 +
45689 + /* Call the completion function in the non-portable logic */
45690 + ep->pcd->fops->xisoc_complete(ep->pcd, ep->priv, req->priv, 0,
45691 + &req->ext_req);
45692 +
45693 + DWC_SPINLOCK(ep->pcd->lock);
45694 +
45695 + /* Free the request - specific freeing needed for extended request object */
45696 + dwc_pcd_xiso_ereq_free(ep, req);
45697 +
45698 + /* Start the next request */
45699 + dwc_otg_pcd_xiso_start_next_request(ep->pcd, ep);
45700 +
45701 + return;
45702 +}
45703 +
45704 +/**
45705 + * Create and initialize the Isoc pkt descriptors of the extended request.
45706 + *
45707 + */
45708 +static int dwc_otg_pcd_xiso_create_pkt_descs(dwc_otg_pcd_request_t * req,
45709 + void *ereq_nonport,
45710 + int atomic_alloc)
45711 +{
45712 + struct dwc_iso_xreq_port *ereq = NULL;
45713 + struct dwc_iso_xreq_port *req_mapped = NULL;
45714 + struct dwc_iso_pkt_desc_port *ipds = NULL; /* To be created in this function */
45715 + uint32_t pkt_count;
45716 + int i;
45717 +
45718 + ereq = &req->ext_req;
45719 + req_mapped = (struct dwc_iso_xreq_port *)ereq_nonport;
45720 + pkt_count = req_mapped->pio_pkt_count;
45721 +
45722 + /* Create the isoc descs */
45723 + if (atomic_alloc) {
45724 + ipds = DWC_ALLOC_ATOMIC(sizeof(*ipds) * pkt_count);
45725 + } else {
45726 + ipds = DWC_ALLOC(sizeof(*ipds) * pkt_count);
45727 + }
45728 +
45729 + if (!ipds) {
45730 + DWC_ERROR("Failed to allocate isoc descriptors");
45731 + return -DWC_E_NO_MEMORY;
45732 + }
45733 +
45734 + /* Initialize the extended request fields */
45735 + ereq->per_io_frame_descs = ipds;
45736 + ereq->error_count = 0;
45737 + ereq->pio_alloc_pkt_count = pkt_count;
45738 + ereq->pio_pkt_count = pkt_count;
45739 + ereq->tr_sub_flags = req_mapped->tr_sub_flags;
45740 +
45741 + /* Init the Isoc descriptors */
45742 + for (i = 0; i < pkt_count; i++) {
45743 + ipds[i].length = req_mapped->per_io_frame_descs[i].length;
45744 + ipds[i].offset = req_mapped->per_io_frame_descs[i].offset;
45745 + ipds[i].status = req_mapped->per_io_frame_descs[i].status; /* 0 */
45746 + ipds[i].actual_length =
45747 + req_mapped->per_io_frame_descs[i].actual_length;
45748 + }
45749 +
45750 + return 0;
45751 +}
45752 +
45753 +static void prn_ext_request(struct dwc_iso_xreq_port *ereq)
45754 +{
45755 + struct dwc_iso_pkt_desc_port *xfd = NULL;
45756 + int i;
45757 +
45758 + DWC_DEBUG("per_io_frame_descs=%p", ereq->per_io_frame_descs);
45759 + DWC_DEBUG("tr_sub_flags=%d", ereq->tr_sub_flags);
45760 + DWC_DEBUG("error_count=%d", ereq->error_count);
45761 + DWC_DEBUG("pio_alloc_pkt_count=%d", ereq->pio_alloc_pkt_count);
45762 + DWC_DEBUG("pio_pkt_count=%d", ereq->pio_pkt_count);
45763 + DWC_DEBUG("res=%d", ereq->res);
45764 +
45765 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45766 + xfd = &ereq->per_io_frame_descs[0];
45767 + DWC_DEBUG("FD #%d", i);
45768 +
45769 + DWC_DEBUG("xfd->actual_length=%d", xfd->actual_length);
45770 + DWC_DEBUG("xfd->length=%d", xfd->length);
45771 + DWC_DEBUG("xfd->offset=%d", xfd->offset);
45772 + DWC_DEBUG("xfd->status=%d", xfd->status);
45773 + }
45774 +}
45775 +
45776 +/**
45777 + *
45778 + */
45779 +int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
45780 + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
45781 + int zero, void *req_handle, int atomic_alloc,
45782 + void *ereq_nonport)
45783 +{
45784 + dwc_otg_pcd_request_t *req = NULL;
45785 + dwc_otg_pcd_ep_t *ep;
45786 + dwc_irqflags_t flags;
45787 + int res;
45788 +
45789 + ep = get_ep_from_handle(pcd, ep_handle);
45790 + if (!ep) {
45791 + DWC_WARN("bad ep\n");
45792 + return -DWC_E_INVALID;
45793 + }
45794 +
45795 + /* We support this extension only for DDMA mode */
45796 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
45797 + if (!GET_CORE_IF(pcd)->dma_desc_enable)
45798 + return -DWC_E_INVALID;
45799 +
45800 + /* Create a dwc_otg_pcd_request_t object */
45801 + if (atomic_alloc) {
45802 + req = DWC_ALLOC_ATOMIC(sizeof(*req));
45803 + } else {
45804 + req = DWC_ALLOC(sizeof(*req));
45805 + }
45806 +
45807 + if (!req) {
45808 + return -DWC_E_NO_MEMORY;
45809 + }
45810 +
45811 + /* Create the Isoc descs for this request which shall be the exact match
45812 + * of the structure sent to us from the non-portable logic */
45813 + res =
45814 + dwc_otg_pcd_xiso_create_pkt_descs(req, ereq_nonport, atomic_alloc);
45815 + if (res) {
45816 + DWC_WARN("Failed to init the Isoc descriptors");
45817 + DWC_FREE(req);
45818 + return res;
45819 + }
45820 +
45821 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45822 +
45823 + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
45824 + req->buf = buf;
45825 + req->dma = dma_buf;
45826 + req->length = buflen;
45827 + req->sent_zlp = zero;
45828 + req->priv = req_handle;
45829 +
45830 + //DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45831 + ep->dwc_ep.dma_addr = dma_buf;
45832 + ep->dwc_ep.start_xfer_buff = buf;
45833 + ep->dwc_ep.xfer_buff = buf;
45834 + ep->dwc_ep.xfer_len = 0;
45835 + ep->dwc_ep.xfer_count = 0;
45836 + ep->dwc_ep.sent_zlp = 0;
45837 + ep->dwc_ep.total_len = buflen;
45838 +
45839 + /* Add this request to the tail */
45840 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
45841 + ep->dwc_ep.xiso_queued_xfers++;
45842 +
45843 +//DWC_DEBUG("CP_0");
45844 +//DWC_DEBUG("req->ext_req.tr_sub_flags=%d", req->ext_req.tr_sub_flags);
45845 +//prn_ext_request((struct dwc_iso_xreq_port *) ereq_nonport);
45846 +//prn_ext_request(&req->ext_req);
45847 +
45848 + //DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45849 +
45850 + /* If the req->status == ASAP then check if there is any active transfer
45851 + * for this endpoint. If no active transfers, then get the first entry
45852 + * from the queue and start that transfer
45853 + */
45854 + if (req->ext_req.tr_sub_flags == DWC_EREQ_TF_ASAP) {
45855 + res = dwc_otg_pcd_xiso_start_next_request(pcd, ep);
45856 + if (res) {
45857 + DWC_WARN("Failed to start the next Isoc transfer");
45858 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45859 + DWC_FREE(req);
45860 + return res;
45861 + }
45862 + }
45863 +
45864 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45865 + return 0;
45866 +}
45867 +
45868 +#endif
45869 +/* END ifdef DWC_UTE_PER_IO ***************************************************/
45870 +int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
45871 + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
45872 + int zero, void *req_handle, int atomic_alloc)
45873 +{
45874 + dwc_irqflags_t flags;
45875 + dwc_otg_pcd_request_t *req;
45876 + dwc_otg_pcd_ep_t *ep;
45877 + uint32_t max_transfer;
45878 +
45879 + ep = get_ep_from_handle(pcd, ep_handle);
45880 + if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
45881 + DWC_WARN("bad ep\n");
45882 + return -DWC_E_INVALID;
45883 + }
45884 +
45885 + if (atomic_alloc) {
45886 + req = DWC_ALLOC_ATOMIC(sizeof(*req));
45887 + } else {
45888 + req = DWC_ALLOC(sizeof(*req));
45889 + }
45890 +
45891 + if (!req) {
45892 + return -DWC_E_NO_MEMORY;
45893 + }
45894 + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
45895 + if (!GET_CORE_IF(pcd)->core_params->opt) {
45896 + if (ep->dwc_ep.num != 0) {
45897 + DWC_ERROR("queue req %p, len %d buf %p\n",
45898 + req_handle, buflen, buf);
45899 + }
45900 + }
45901 +
45902 + req->buf = buf;
45903 + req->dma = dma_buf;
45904 + req->length = buflen;
45905 + req->sent_zlp = zero;
45906 + req->priv = req_handle;
45907 + req->dw_align_buf = NULL;
45908 + if ((dma_buf & 0x3) && GET_CORE_IF(pcd)->dma_enable
45909 + && !GET_CORE_IF(pcd)->dma_desc_enable)
45910 + req->dw_align_buf = DWC_DMA_ALLOC(buflen,
45911 + &req->dw_align_buf_dma);
45912 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45913 +
45914 + /*
45915 + * After adding request to the queue for IN ISOC wait for In Token Received
45916 + * when TX FIFO is empty interrupt and for OUT ISOC wait for OUT Token
45917 + * Received when EP is disabled interrupt to obtain starting microframe
45918 + * (odd/even) start transfer
45919 + */
45920 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
45921 + if (req != 0) {
45922 + depctl_data_t depctl = {.d32 =
45923 + DWC_READ_REG32(&pcd->core_if->dev_if->
45924 + in_ep_regs[ep->dwc_ep.num]->
45925 + diepctl) };
45926 + ++pcd->request_pending;
45927 +
45928 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
45929 + if (ep->dwc_ep.is_in) {
45930 + depctl.b.cnak = 1;
45931 + DWC_WRITE_REG32(&pcd->core_if->dev_if->
45932 + in_ep_regs[ep->dwc_ep.num]->
45933 + diepctl, depctl.d32);
45934 + }
45935 +
45936 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45937 + }
45938 + return 0;
45939 + }
45940 +
45941 + /*
45942 + * For EP0 IN without premature status, zlp is required?
45943 + */
45944 + if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {
45945 + DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num);
45946 + //_req->zero = 1;
45947 + }
45948 +
45949 + /* Start the transfer */
45950 + if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) {
45951 + /* EP0 Transfer? */
45952 + if (ep->dwc_ep.num == 0) {
45953 + switch (pcd->ep0state) {
45954 + case EP0_IN_DATA_PHASE:
45955 + DWC_DEBUGPL(DBG_PCD,
45956 + "%s ep0: EP0_IN_DATA_PHASE\n",
45957 + __func__);
45958 + break;
45959 +
45960 + case EP0_OUT_DATA_PHASE:
45961 + DWC_DEBUGPL(DBG_PCD,
45962 + "%s ep0: EP0_OUT_DATA_PHASE\n",
45963 + __func__);
45964 + if (pcd->request_config) {
45965 + /* Complete STATUS PHASE */
45966 + ep->dwc_ep.is_in = 1;
45967 + pcd->ep0state = EP0_IN_STATUS_PHASE;
45968 + }
45969 + break;
45970 +
45971 + case EP0_IN_STATUS_PHASE:
45972 + DWC_DEBUGPL(DBG_PCD,
45973 + "%s ep0: EP0_IN_STATUS_PHASE\n",
45974 + __func__);
45975 + break;
45976 +
45977 + default:
45978 + DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
45979 + pcd->ep0state);
45980 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45981 + return -DWC_E_SHUTDOWN;
45982 + }
45983 +
45984 + ep->dwc_ep.dma_addr = dma_buf;
45985 + ep->dwc_ep.start_xfer_buff = buf;
45986 + ep->dwc_ep.xfer_buff = buf;
45987 + ep->dwc_ep.xfer_len = buflen;
45988 + ep->dwc_ep.xfer_count = 0;
45989 + ep->dwc_ep.sent_zlp = 0;
45990 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
45991 +
45992 + if (zero) {
45993 + if ((ep->dwc_ep.xfer_len %
45994 + ep->dwc_ep.maxpacket == 0)
45995 + && (ep->dwc_ep.xfer_len != 0)) {
45996 + ep->dwc_ep.sent_zlp = 1;
45997 + }
45998 +
45999 + }
46000 +
46001 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
46002 + &ep->dwc_ep);
46003 + } // non-ep0 endpoints
46004 + else {
46005 +#ifdef DWC_UTE_CFI
46006 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
46007 + /* store the request length */
46008 + ep->dwc_ep.cfi_req_len = buflen;
46009 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd,
46010 + ep, req);
46011 + } else {
46012 +#endif
46013 + max_transfer =
46014 + GET_CORE_IF(ep->pcd)->core_params->
46015 + max_transfer_size;
46016 +
46017 + /* Setup and start the Transfer */
46018 + if (req->dw_align_buf){
46019 + if (ep->dwc_ep.is_in)
46020 + dwc_memcpy(req->dw_align_buf,
46021 + buf, buflen);
46022 + ep->dwc_ep.dma_addr =
46023 + req->dw_align_buf_dma;
46024 + ep->dwc_ep.start_xfer_buff =
46025 + req->dw_align_buf;
46026 + ep->dwc_ep.xfer_buff =
46027 + req->dw_align_buf;
46028 + } else {
46029 + ep->dwc_ep.dma_addr = dma_buf;
46030 + ep->dwc_ep.start_xfer_buff = buf;
46031 + ep->dwc_ep.xfer_buff = buf;
46032 + }
46033 + ep->dwc_ep.xfer_len = 0;
46034 + ep->dwc_ep.xfer_count = 0;
46035 + ep->dwc_ep.sent_zlp = 0;
46036 + ep->dwc_ep.total_len = buflen;
46037 +
46038 + ep->dwc_ep.maxxfer = max_transfer;
46039 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
46040 + uint32_t out_max_xfer =
46041 + DDMA_MAX_TRANSFER_SIZE -
46042 + (DDMA_MAX_TRANSFER_SIZE % 4);
46043 + if (ep->dwc_ep.is_in) {
46044 + if (ep->dwc_ep.maxxfer >
46045 + DDMA_MAX_TRANSFER_SIZE) {
46046 + ep->dwc_ep.maxxfer =
46047 + DDMA_MAX_TRANSFER_SIZE;
46048 + }
46049 + } else {
46050 + if (ep->dwc_ep.maxxfer >
46051 + out_max_xfer) {
46052 + ep->dwc_ep.maxxfer =
46053 + out_max_xfer;
46054 + }
46055 + }
46056 + }
46057 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
46058 + ep->dwc_ep.maxxfer -=
46059 + (ep->dwc_ep.maxxfer %
46060 + ep->dwc_ep.maxpacket);
46061 + }
46062 +
46063 + if (zero) {
46064 + if ((ep->dwc_ep.total_len %
46065 + ep->dwc_ep.maxpacket == 0)
46066 + && (ep->dwc_ep.total_len != 0)) {
46067 + ep->dwc_ep.sent_zlp = 1;
46068 + }
46069 + }
46070 +#ifdef DWC_UTE_CFI
46071 + }
46072 +#endif
46073 + dwc_otg_ep_start_transfer(GET_CORE_IF(pcd),
46074 + &ep->dwc_ep);
46075 + }
46076 + }
46077 +
46078 + if (req != 0) {
46079 + ++pcd->request_pending;
46080 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
46081 + if (ep->dwc_ep.is_in && ep->stopped
46082 + && !(GET_CORE_IF(pcd)->dma_enable)) {
46083 + /** @todo NGS Create a function for this. */
46084 + diepmsk_data_t diepmsk = {.d32 = 0 };
46085 + diepmsk.b.intktxfemp = 1;
46086 + if (GET_CORE_IF(pcd)->multiproc_int_enable) {
46087 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
46088 + dev_if->dev_global_regs->diepeachintmsk
46089 + [ep->dwc_ep.num], 0,
46090 + diepmsk.d32);
46091 + } else {
46092 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
46093 + dev_if->dev_global_regs->
46094 + diepmsk, 0, diepmsk.d32);
46095 + }
46096 +
46097 + }
46098 + }
46099 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46100 +
46101 + return 0;
46102 +}
46103 +
46104 +int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
46105 + void *req_handle)
46106 +{
46107 + dwc_irqflags_t flags;
46108 + dwc_otg_pcd_request_t *req;
46109 + dwc_otg_pcd_ep_t *ep;
46110 +
46111 + ep = get_ep_from_handle(pcd, ep_handle);
46112 + if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
46113 + DWC_WARN("bad argument\n");
46114 + return -DWC_E_INVALID;
46115 + }
46116 +
46117 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46118 +
46119 + /* make sure it's actually queued on this endpoint */
46120 + DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
46121 + if (req->priv == (void *)req_handle) {
46122 + break;
46123 + }
46124 + }
46125 +
46126 + if (req->priv != (void *)req_handle) {
46127 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46128 + return -DWC_E_INVALID;
46129 + }
46130 +
46131 + if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) {
46132 + dwc_otg_request_done(ep, req, -DWC_E_RESTART);
46133 + } else {
46134 + req = NULL;
46135 + }
46136 +
46137 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46138 +
46139 + return req ? 0 : -DWC_E_SHUTDOWN;
46140 +
46141 +}
46142 +
46143 +/**
46144 + * dwc_otg_pcd_ep_wedge - sets the halt feature and ignores clear requests
46145 + *
46146 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
46147 + * requests. If the gadget driver clears the halt status, it will
46148 + * automatically unwedge the endpoint.
46149 + *
46150 + * Returns zero on success, else negative DWC error code.
46151 + */
46152 +int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle)
46153 +{
46154 + dwc_otg_pcd_ep_t *ep;
46155 + dwc_irqflags_t flags;
46156 + int retval = 0;
46157 +
46158 + ep = get_ep_from_handle(pcd, ep_handle);
46159 +
46160 + if ((!ep->desc && ep != &pcd->ep0) ||
46161 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
46162 + DWC_WARN("%s, bad ep\n", __func__);
46163 + return -DWC_E_INVALID;
46164 + }
46165 +
46166 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46167 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
46168 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
46169 + ep->dwc_ep.is_in ? "IN" : "OUT");
46170 + retval = -DWC_E_AGAIN;
46171 + } else {
46172 + /* This code needs to be reviewed */
46173 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
46174 + dtxfsts_data_t txstatus;
46175 + fifosize_data_t txfifosize;
46176 +
46177 + txfifosize.d32 =
46178 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
46179 + core_global_regs->dtxfsiz[ep->dwc_ep.
46180 + tx_fifo_num]);
46181 + txstatus.d32 =
46182 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
46183 + dev_if->in_ep_regs[ep->dwc_ep.num]->
46184 + dtxfsts);
46185 +
46186 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
46187 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
46188 + retval = -DWC_E_AGAIN;
46189 + } else {
46190 + if (ep->dwc_ep.num == 0) {
46191 + pcd->ep0state = EP0_STALL;
46192 + }
46193 +
46194 + ep->stopped = 1;
46195 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
46196 + &ep->dwc_ep);
46197 + }
46198 + } else {
46199 + if (ep->dwc_ep.num == 0) {
46200 + pcd->ep0state = EP0_STALL;
46201 + }
46202 +
46203 + ep->stopped = 1;
46204 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46205 + }
46206 + }
46207 +
46208 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46209 +
46210 + return retval;
46211 +}
46212 +
46213 +int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value)
46214 +{
46215 + dwc_otg_pcd_ep_t *ep;
46216 + dwc_irqflags_t flags;
46217 + int retval = 0;
46218 +
46219 + ep = get_ep_from_handle(pcd, ep_handle);
46220 +
46221 + if (!ep || (!ep->desc && ep != &pcd->ep0) ||
46222 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
46223 + DWC_WARN("%s, bad ep\n", __func__);
46224 + return -DWC_E_INVALID;
46225 + }
46226 +
46227 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46228 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
46229 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
46230 + ep->dwc_ep.is_in ? "IN" : "OUT");
46231 + retval = -DWC_E_AGAIN;
46232 + } else if (value == 0) {
46233 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46234 + } else if (value == 1) {
46235 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
46236 + dtxfsts_data_t txstatus;
46237 + fifosize_data_t txfifosize;
46238 +
46239 + txfifosize.d32 =
46240 + DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->
46241 + dtxfsiz[ep->dwc_ep.tx_fifo_num]);
46242 + txstatus.d32 =
46243 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
46244 + in_ep_regs[ep->dwc_ep.num]->dtxfsts);
46245 +
46246 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
46247 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
46248 + retval = -DWC_E_AGAIN;
46249 + } else {
46250 + if (ep->dwc_ep.num == 0) {
46251 + pcd->ep0state = EP0_STALL;
46252 + }
46253 +
46254 + ep->stopped = 1;
46255 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
46256 + &ep->dwc_ep);
46257 + }
46258 + } else {
46259 + if (ep->dwc_ep.num == 0) {
46260 + pcd->ep0state = EP0_STALL;
46261 + }
46262 +
46263 + ep->stopped = 1;
46264 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46265 + }
46266 + } else if (value == 2) {
46267 + ep->dwc_ep.stall_clear_flag = 0;
46268 + } else if (value == 3) {
46269 + ep->dwc_ep.stall_clear_flag = 1;
46270 + }
46271 +
46272 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46273 +
46274 + return retval;
46275 +}
46276 +
46277 +/**
46278 + * This function initiates remote wakeup of the host from suspend state.
46279 + */
46280 +void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set)
46281 +{
46282 + dctl_data_t dctl = { 0 };
46283 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46284 + dsts_data_t dsts;
46285 +
46286 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
46287 + if (!dsts.b.suspsts) {
46288 + DWC_WARN("Remote wakeup while is not in suspend state\n");
46289 + }
46290 + /* Check if DEVICE_REMOTE_WAKEUP feature enabled */
46291 + if (pcd->remote_wakeup_enable) {
46292 + if (set) {
46293 +
46294 + if (core_if->adp_enable) {
46295 + gpwrdn_data_t gpwrdn;
46296 +
46297 + dwc_otg_adp_probe_stop(core_if);
46298 +
46299 + /* Mask SRP detected interrupt from Power Down Logic */
46300 + gpwrdn.d32 = 0;
46301 + gpwrdn.b.srp_det_msk = 1;
46302 + DWC_MODIFY_REG32(&core_if->
46303 + core_global_regs->gpwrdn,
46304 + gpwrdn.d32, 0);
46305 +
46306 + /* Disable Power Down Logic */
46307 + gpwrdn.d32 = 0;
46308 + gpwrdn.b.pmuactv = 1;
46309 + DWC_MODIFY_REG32(&core_if->
46310 + core_global_regs->gpwrdn,
46311 + gpwrdn.d32, 0);
46312 +
46313 + /*
46314 + * Initialize the Core for Device mode.
46315 + */
46316 + core_if->op_state = B_PERIPHERAL;
46317 + dwc_otg_core_init(core_if);
46318 + dwc_otg_enable_global_interrupts(core_if);
46319 + cil_pcd_start(core_if);
46320 +
46321 + dwc_otg_initiate_srp(core_if);
46322 + }
46323 +
46324 + dctl.b.rmtwkupsig = 1;
46325 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
46326 + dctl, 0, dctl.d32);
46327 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
46328 +
46329 + dwc_mdelay(2);
46330 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
46331 + dctl, dctl.d32, 0);
46332 + DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
46333 + }
46334 + } else {
46335 + DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
46336 + }
46337 +}
46338 +
46339 +#ifdef CONFIG_USB_DWC_OTG_LPM
46340 +/**
46341 + * This function initiates remote wakeup of the host from L1 sleep state.
46342 + */
46343 +void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set)
46344 +{
46345 + glpmcfg_data_t lpmcfg;
46346 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46347 +
46348 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
46349 +
46350 + /* Check if we are in L1 state */
46351 + if (!lpmcfg.b.prt_sleep_sts) {
46352 + DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n");
46353 + return;
46354 + }
46355 +
46356 + /* Check if host allows remote wakeup */
46357 + if (!lpmcfg.b.rem_wkup_en) {
46358 + DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n");
46359 + return;
46360 + }
46361 +
46362 + /* Check if Resume OK */
46363 + if (!lpmcfg.b.sleep_state_resumeok) {
46364 + DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n");
46365 + return;
46366 + }
46367 +
46368 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
46369 + lpmcfg.b.en_utmi_sleep = 0;
46370 + lpmcfg.b.hird_thres &= (~(1 << 4));
46371 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
46372 +
46373 + if (set) {
46374 + dctl_data_t dctl = {.d32 = 0 };
46375 + dctl.b.rmtwkupsig = 1;
46376 + /* Set RmtWkUpSig bit to start remote wakup signaling.
46377 + * Hardware will automatically clear this bit.
46378 + */
46379 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl,
46380 + 0, dctl.d32);
46381 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
46382 + }
46383 +
46384 +}
46385 +#endif
46386 +
46387 +/**
46388 + * Performs remote wakeup.
46389 + */
46390 +void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set)
46391 +{
46392 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46393 + dwc_irqflags_t flags;
46394 + if (dwc_otg_is_device_mode(core_if)) {
46395 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46396 +#ifdef CONFIG_USB_DWC_OTG_LPM
46397 + if (core_if->lx_state == DWC_OTG_L1) {
46398 + dwc_otg_pcd_rem_wkup_from_sleep(pcd, set);
46399 + } else {
46400 +#endif
46401 + dwc_otg_pcd_rem_wkup_from_suspend(pcd, set);
46402 +#ifdef CONFIG_USB_DWC_OTG_LPM
46403 + }
46404 +#endif
46405 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46406 + }
46407 + return;
46408 +}
46409 +
46410 +void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs)
46411 +{
46412 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46413 + dctl_data_t dctl = { 0 };
46414 +
46415 + if (dwc_otg_is_device_mode(core_if)) {
46416 + dctl.b.sftdiscon = 1;
46417 + DWC_PRINTF("Soft disconnect for %d useconds\n",no_of_usecs);
46418 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
46419 + dwc_udelay(no_of_usecs);
46420 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32,0);
46421 +
46422 + } else{
46423 + DWC_PRINTF("NOT SUPPORTED IN HOST MODE\n");
46424 + }
46425 + return;
46426 +
46427 +}
46428 +
46429 +int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd)
46430 +{
46431 + dsts_data_t dsts;
46432 + gotgctl_data_t gotgctl;
46433 +
46434 + /*
46435 + * This function starts the Protocol if no session is in progress. If
46436 + * a session is already in progress, but the device is suspended,
46437 + * remote wakeup signaling is started.
46438 + */
46439 +
46440 + /* Check if valid session */
46441 + gotgctl.d32 =
46442 + DWC_READ_REG32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
46443 + if (gotgctl.b.bsesvld) {
46444 + /* Check if suspend state */
46445 + dsts.d32 =
46446 + DWC_READ_REG32(&
46447 + (GET_CORE_IF(pcd)->dev_if->
46448 + dev_global_regs->dsts));
46449 + if (dsts.b.suspsts) {
46450 + dwc_otg_pcd_remote_wakeup(pcd, 1);
46451 + }
46452 + } else {
46453 + dwc_otg_pcd_initiate_srp(pcd);
46454 + }
46455 +
46456 + return 0;
46457 +
46458 +}
46459 +
46460 +/**
46461 + * Start the SRP timer to detect when the SRP does not complete within
46462 + * 6 seconds.
46463 + *
46464 + * @param pcd the pcd structure.
46465 + */
46466 +void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd)
46467 +{
46468 + dwc_irqflags_t flags;
46469 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46470 + dwc_otg_initiate_srp(GET_CORE_IF(pcd));
46471 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46472 +}
46473 +
46474 +int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd)
46475 +{
46476 + return dwc_otg_get_frame_number(GET_CORE_IF(pcd));
46477 +}
46478 +
46479 +int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd)
46480 +{
46481 + return GET_CORE_IF(pcd)->core_params->lpm_enable;
46482 +}
46483 +
46484 +uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd)
46485 +{
46486 + return pcd->b_hnp_enable;
46487 +}
46488 +
46489 +uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd)
46490 +{
46491 + return pcd->a_hnp_support;
46492 +}
46493 +
46494 +uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd)
46495 +{
46496 + return pcd->a_alt_hnp_support;
46497 +}
46498 +
46499 +int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd)
46500 +{
46501 + return pcd->remote_wakeup_enable;
46502 +}
46503 +
46504 +#endif /* DWC_HOST_ONLY */
46505 --- /dev/null
46506 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.h
46507 @@ -0,0 +1,266 @@
46508 +/* ==========================================================================
46509 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $
46510 + * $Revision: #48 $
46511 + * $Date: 2012/08/10 $
46512 + * $Change: 2047372 $
46513 + *
46514 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
46515 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
46516 + * otherwise expressly agreed to in writing between Synopsys and you.
46517 + *
46518 + * The Software IS NOT an item of Licensed Software or Licensed Product under
46519 + * any End User Software License Agreement or Agreement for Licensed Product
46520 + * with Synopsys or any supplement thereto. You are permitted to use and
46521 + * redistribute this Software in source and binary forms, with or without
46522 + * modification, provided that redistributions of source code must retain this
46523 + * notice. You may not view, use, disclose, copy or distribute this file or
46524 + * any information contained herein except pursuant to this license grant from
46525 + * Synopsys. If you do not agree with this notice, including the disclaimer
46526 + * below, then you are not authorized to use the Software.
46527 + *
46528 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
46529 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46530 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46531 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
46532 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46533 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
46534 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
46535 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46536 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46537 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46538 + * DAMAGE.
46539 + * ========================================================================== */
46540 +#ifndef DWC_HOST_ONLY
46541 +#if !defined(__DWC_PCD_H__)
46542 +#define __DWC_PCD_H__
46543 +
46544 +#include "dwc_otg_os_dep.h"
46545 +#include "usb.h"
46546 +#include "dwc_otg_cil.h"
46547 +#include "dwc_otg_pcd_if.h"
46548 +struct cfiobject;
46549 +
46550 +/**
46551 + * @file
46552 + *
46553 + * This file contains the structures, constants, and interfaces for
46554 + * the Perpherial Contoller Driver (PCD).
46555 + *
46556 + * The Peripheral Controller Driver (PCD) for Linux will implement the
46557 + * Gadget API, so that the existing Gadget drivers can be used. For
46558 + * the Mass Storage Function driver the File-backed USB Storage Gadget
46559 + * (FBS) driver will be used. The FBS driver supports the
46560 + * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only
46561 + * transports.
46562 + *
46563 + */
46564 +
46565 +/** Invalid DMA Address */
46566 +#define DWC_DMA_ADDR_INVALID (~(dwc_dma_t)0)
46567 +
46568 +/** Max Transfer size for any EP */
46569 +#define DDMA_MAX_TRANSFER_SIZE 65535
46570 +
46571 +/**
46572 + * Get the pointer to the core_if from the pcd pointer.
46573 + */
46574 +#define GET_CORE_IF( _pcd ) (_pcd->core_if)
46575 +
46576 +/**
46577 + * States of EP0.
46578 + */
46579 +typedef enum ep0_state {
46580 + EP0_DISCONNECT, /* no host */
46581 + EP0_IDLE,
46582 + EP0_IN_DATA_PHASE,
46583 + EP0_OUT_DATA_PHASE,
46584 + EP0_IN_STATUS_PHASE,
46585 + EP0_OUT_STATUS_PHASE,
46586 + EP0_STALL,
46587 +} ep0state_e;
46588 +
46589 +/** Fordward declaration.*/
46590 +struct dwc_otg_pcd;
46591 +
46592 +/** DWC_otg iso request structure.
46593 + *
46594 + */
46595 +typedef struct usb_iso_request dwc_otg_pcd_iso_request_t;
46596 +
46597 +#ifdef DWC_UTE_PER_IO
46598 +
46599 +/**
46600 + * This shall be the exact analogy of the same type structure defined in the
46601 + * usb_gadget.h. Each descriptor contains
46602 + */
46603 +struct dwc_iso_pkt_desc_port {
46604 + uint32_t offset;
46605 + uint32_t length; /* expected length */
46606 + uint32_t actual_length;
46607 + uint32_t status;
46608 +};
46609 +
46610 +struct dwc_iso_xreq_port {
46611 + /** transfer/submission flag */
46612 + uint32_t tr_sub_flags;
46613 + /** Start the request ASAP */
46614 +#define DWC_EREQ_TF_ASAP 0x00000002
46615 + /** Just enqueue the request w/o initiating a transfer */
46616 +#define DWC_EREQ_TF_ENQUEUE 0x00000004
46617 +
46618 + /**
46619 + * count of ISO packets attached to this request - shall
46620 + * not exceed the pio_alloc_pkt_count
46621 + */
46622 + uint32_t pio_pkt_count;
46623 + /** count of ISO packets allocated for this request */
46624 + uint32_t pio_alloc_pkt_count;
46625 + /** number of ISO packet errors */
46626 + uint32_t error_count;
46627 + /** reserved for future extension */
46628 + uint32_t res;
46629 + /** Will be allocated and freed in the UTE gadget and based on the CFC value */
46630 + struct dwc_iso_pkt_desc_port *per_io_frame_descs;
46631 +};
46632 +#endif
46633 +/** DWC_otg request structure.
46634 + * This structure is a list of requests.
46635 + */
46636 +typedef struct dwc_otg_pcd_request {
46637 + void *priv;
46638 + void *buf;
46639 + dwc_dma_t dma;
46640 + uint32_t length;
46641 + uint32_t actual;
46642 + unsigned sent_zlp:1;
46643 + /**
46644 + * Used instead of original buffer if
46645 + * it(physical address) is not dword-aligned.
46646 + **/
46647 + uint8_t *dw_align_buf;
46648 + dwc_dma_t dw_align_buf_dma;
46649 +
46650 + DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry;
46651 +#ifdef DWC_UTE_PER_IO
46652 + struct dwc_iso_xreq_port ext_req;
46653 + //void *priv_ereq_nport; /* */
46654 +#endif
46655 +} dwc_otg_pcd_request_t;
46656 +
46657 +DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request);
46658 +
46659 +/** PCD EP structure.
46660 + * This structure describes an EP, there is an array of EPs in the PCD
46661 + * structure.
46662 + */
46663 +typedef struct dwc_otg_pcd_ep {
46664 + /** USB EP Descriptor */
46665 + const usb_endpoint_descriptor_t *desc;
46666 +
46667 + /** queue of dwc_otg_pcd_requests. */
46668 + struct req_list queue;
46669 + unsigned stopped:1;
46670 + unsigned disabling:1;
46671 + unsigned dma:1;
46672 + unsigned queue_sof:1;
46673 +
46674 +#ifdef DWC_EN_ISOC
46675 + /** ISOC req handle passed */
46676 + void *iso_req_handle;
46677 +#endif //_EN_ISOC_
46678 +
46679 + /** DWC_otg ep data. */
46680 + dwc_ep_t dwc_ep;
46681 +
46682 + /** Pointer to PCD */
46683 + struct dwc_otg_pcd *pcd;
46684 +
46685 + void *priv;
46686 +} dwc_otg_pcd_ep_t;
46687 +
46688 +/** DWC_otg PCD Structure.
46689 + * This structure encapsulates the data for the dwc_otg PCD.
46690 + */
46691 +struct dwc_otg_pcd {
46692 + const struct dwc_otg_pcd_function_ops *fops;
46693 + /** The DWC otg device pointer */
46694 + struct dwc_otg_device *otg_dev;
46695 + /** Core Interface */
46696 + dwc_otg_core_if_t *core_if;
46697 + /** State of EP0 */
46698 + ep0state_e ep0state;
46699 + /** EP0 Request is pending */
46700 + unsigned ep0_pending:1;
46701 + /** Indicates when SET CONFIGURATION Request is in process */
46702 + unsigned request_config:1;
46703 + /** The state of the Remote Wakeup Enable. */
46704 + unsigned remote_wakeup_enable:1;
46705 + /** The state of the B-Device HNP Enable. */
46706 + unsigned b_hnp_enable:1;
46707 + /** The state of A-Device HNP Support. */
46708 + unsigned a_hnp_support:1;
46709 + /** The state of the A-Device Alt HNP support. */
46710 + unsigned a_alt_hnp_support:1;
46711 + /** Count of pending Requests */
46712 + unsigned request_pending;
46713 +
46714 + /** SETUP packet for EP0
46715 + * This structure is allocated as a DMA buffer on PCD initialization
46716 + * with enough space for up to 3 setup packets.
46717 + */
46718 + union {
46719 + usb_device_request_t req;
46720 + uint32_t d32[2];
46721 + } *setup_pkt;
46722 +
46723 + dwc_dma_t setup_pkt_dma_handle;
46724 +
46725 + /* Additional buffer and flag for CTRL_WR premature case */
46726 + uint8_t *backup_buf;
46727 + unsigned data_terminated;
46728 +
46729 + /** 2-byte dma buffer used to return status from GET_STATUS */
46730 + uint16_t *status_buf;
46731 + dwc_dma_t status_buf_dma_handle;
46732 +
46733 + /** EP0 */
46734 + dwc_otg_pcd_ep_t ep0;
46735 +
46736 + /** Array of IN EPs. */
46737 + dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1];
46738 + /** Array of OUT EPs. */
46739 + dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1];
46740 + /** number of valid EPs in the above array. */
46741 +// unsigned num_eps : 4;
46742 + dwc_spinlock_t *lock;
46743 +
46744 + /** Tasklet to defer starting of TEST mode transmissions until
46745 + * Status Phase has been completed.
46746 + */
46747 + dwc_tasklet_t *test_mode_tasklet;
46748 +
46749 + /** Tasklet to delay starting of xfer in DMA mode */
46750 + dwc_tasklet_t *start_xfer_tasklet;
46751 +
46752 + /** The test mode to enter when the tasklet is executed. */
46753 + unsigned test_mode;
46754 + /** The cfi_api structure that implements most of the CFI API
46755 + * and OTG specific core configuration functionality
46756 + */
46757 +#ifdef DWC_UTE_CFI
46758 + struct cfiobject *cfi;
46759 +#endif
46760 +
46761 +};
46762 +
46763 +//FIXME this functions should be static, and this prototypes should be removed
46764 +extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep);
46765 +extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep,
46766 + dwc_otg_pcd_request_t * req, int32_t status);
46767 +
46768 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
46769 + void *req_handle);
46770 +
46771 +extern void do_test_mode(void *data);
46772 +#endif
46773 +#endif /* DWC_HOST_ONLY */
46774 --- /dev/null
46775 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
46776 @@ -0,0 +1,360 @@
46777 +/* ==========================================================================
46778 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $
46779 + * $Revision: #11 $
46780 + * $Date: 2011/10/26 $
46781 + * $Change: 1873028 $
46782 + *
46783 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
46784 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
46785 + * otherwise expressly agreed to in writing between Synopsys and you.
46786 + *
46787 + * The Software IS NOT an item of Licensed Software or Licensed Product under
46788 + * any End User Software License Agreement or Agreement for Licensed Product
46789 + * with Synopsys or any supplement thereto. You are permitted to use and
46790 + * redistribute this Software in source and binary forms, with or without
46791 + * modification, provided that redistributions of source code must retain this
46792 + * notice. You may not view, use, disclose, copy or distribute this file or
46793 + * any information contained herein except pursuant to this license grant from
46794 + * Synopsys. If you do not agree with this notice, including the disclaimer
46795 + * below, then you are not authorized to use the Software.
46796 + *
46797 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
46798 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46799 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46800 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
46801 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46802 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
46803 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
46804 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46805 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46806 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46807 + * DAMAGE.
46808 + * ========================================================================== */
46809 +#ifndef DWC_HOST_ONLY
46810 +
46811 +#if !defined(__DWC_PCD_IF_H__)
46812 +#define __DWC_PCD_IF_H__
46813 +
46814 +//#include "dwc_os.h"
46815 +#include "dwc_otg_core_if.h"
46816 +
46817 +/** @file
46818 + * This file defines DWC_OTG PCD Core API.
46819 + */
46820 +
46821 +struct dwc_otg_pcd;
46822 +typedef struct dwc_otg_pcd dwc_otg_pcd_t;
46823 +
46824 +/** Maxpacket size for EP0 */
46825 +#define MAX_EP0_SIZE 64
46826 +/** Maxpacket size for any EP */
46827 +#define MAX_PACKET_SIZE 1024
46828 +
46829 +/** @name Function Driver Callbacks */
46830 +/** @{ */
46831 +
46832 +/** This function will be called whenever a previously queued request has
46833 + * completed. The status value will be set to -DWC_E_SHUTDOWN to indicated a
46834 + * failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset,
46835 + * or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid
46836 + * parameters. */
46837 +typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
46838 + void *req_handle, int32_t status,
46839 + uint32_t actual);
46840 +/**
46841 + * This function will be called whenever a previousle queued ISOC request has
46842 + * completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count
46843 + * function.
46844 + * The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_*
46845 + * functions.
46846 + */
46847 +typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
46848 + void *req_handle, int proc_buf_num);
46849 +/** This function should handle any SETUP request that cannot be handled by the
46850 + * PCD Core. This includes most GET_DESCRIPTORs, SET_CONFIGS, Any
46851 + * class-specific requests, etc. The function must non-blocking.
46852 + *
46853 + * Returns 0 on success.
46854 + * Returns -DWC_E_NOT_SUPPORTED if the request is not supported.
46855 + * Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes.
46856 + * Returns -DWC_E_SHUTDOWN on any other error. */
46857 +typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes);
46858 +/** This is called whenever the device has been disconnected. The function
46859 + * driver should take appropriate action to clean up all pending requests in the
46860 + * PCD Core, remove all endpoints (except ep0), and initialize back to reset
46861 + * state. */
46862 +typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd);
46863 +/** This function is called when device has been connected. */
46864 +typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed);
46865 +/** This function is called when device has been suspended */
46866 +typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd);
46867 +/** This function is called when device has received LPM tokens, i.e.
46868 + * device has been sent to sleep state. */
46869 +typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd);
46870 +/** This function is called when device has been resumed
46871 + * from suspend(L2) or L1 sleep state. */
46872 +typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd);
46873 +/** This function is called whenever hnp params has been changed.
46874 + * User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions
46875 + * to get hnp parameters. */
46876 +typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd);
46877 +/** This function is called whenever USB RESET is detected. */
46878 +typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd);
46879 +
46880 +typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes);
46881 +
46882 +/**
46883 + *
46884 + * @param ep_handle Void pointer to the usb_ep structure
46885 + * @param ereq_port Pointer to the extended request structure created in the
46886 + * portable part.
46887 + */
46888 +typedef int (*xiso_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
46889 + void *req_handle, int32_t status,
46890 + void *ereq_port);
46891 +/** Function Driver Ops Data Structure */
46892 +struct dwc_otg_pcd_function_ops {
46893 + dwc_connect_cb_t connect;
46894 + dwc_disconnect_cb_t disconnect;
46895 + dwc_setup_cb_t setup;
46896 + dwc_completion_cb_t complete;
46897 + dwc_isoc_completion_cb_t isoc_complete;
46898 + dwc_suspend_cb_t suspend;
46899 + dwc_sleep_cb_t sleep;
46900 + dwc_resume_cb_t resume;
46901 + dwc_reset_cb_t reset;
46902 + dwc_hnp_params_changed_cb_t hnp_changed;
46903 + cfi_setup_cb_t cfi_setup;
46904 +#ifdef DWC_UTE_PER_IO
46905 + xiso_completion_cb_t xisoc_complete;
46906 +#endif
46907 +};
46908 +/** @} */
46909 +
46910 +/** @name Function Driver Functions */
46911 +/** @{ */
46912 +
46913 +/** Call this function to get pointer on dwc_otg_pcd_t,
46914 + * this pointer will be used for all PCD API functions.
46915 + *
46916 + * @param core_if The DWC_OTG Core
46917 + */
46918 +extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if);
46919 +
46920 +/** Frees PCD allocated by dwc_otg_pcd_init
46921 + *
46922 + * @param pcd The PCD
46923 + */
46924 +extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd);
46925 +
46926 +/** Call this to bind the function driver to the PCD Core.
46927 + *
46928 + * @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
46929 + * @param fops The Function Driver Ops data structure containing pointers to all callbacks.
46930 + */
46931 +extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
46932 + const struct dwc_otg_pcd_function_ops *fops);
46933 +
46934 +/** Enables an endpoint for use. This function enables an endpoint in
46935 + * the PCD. The endpoint is described by the ep_desc which has the
46936 + * same format as a USB ep descriptor. The ep_handle parameter is used to refer
46937 + * to the endpoint from other API functions and in callbacks. Normally this
46938 + * should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the
46939 + * core for that interface.
46940 + *
46941 + * Returns -DWC_E_INVALID if invalid parameters were passed.
46942 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
46943 + * Returns 0 on success.
46944 + *
46945 + * @param pcd The PCD
46946 + * @param ep_desc Endpoint descriptor
46947 + * @param usb_ep Handle on endpoint, that will be used to identify endpoint.
46948 + */
46949 +extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
46950 + const uint8_t * ep_desc, void *usb_ep);
46951 +
46952 +/** Disable the endpoint referenced by ep_handle.
46953 + *
46954 + * Returns -DWC_E_INVALID if invalid parameters were passed.
46955 + * Returns -DWC_E_SHUTDOWN if any other error occurred.
46956 + * Returns 0 on success. */
46957 +extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle);
46958 +
46959 +/** Queue a data transfer request on the endpoint referenced by ep_handle.
46960 + * After the transfer is completes, the complete callback will be called with
46961 + * the request status.
46962 + *
46963 + * @param pcd The PCD
46964 + * @param ep_handle The handle of the endpoint
46965 + * @param buf The buffer for the data
46966 + * @param dma_buf The DMA buffer for the data
46967 + * @param buflen The length of the data transfer
46968 + * @param zero Specifies whether to send zero length last packet.
46969 + * @param req_handle Set this handle to any value to use to reference this
46970 + * request in the ep_dequeue function or from the complete callback
46971 + * @param atomic_alloc If driver need to perform atomic allocations
46972 + * for internal data structures.
46973 + *
46974 + * Returns -DWC_E_INVALID if invalid parameters were passed.
46975 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
46976 + * Returns 0 on success. */
46977 +extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
46978 + uint8_t * buf, dwc_dma_t dma_buf,
46979 + uint32_t buflen, int zero, void *req_handle,
46980 + int atomic_alloc);
46981 +#ifdef DWC_UTE_PER_IO
46982 +/**
46983 + *
46984 + * @param ereq_nonport Pointer to the extended request part of the
46985 + * usb_request structure defined in usb_gadget.h file.
46986 + */
46987 +extern int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
46988 + uint8_t * buf, dwc_dma_t dma_buf,
46989 + uint32_t buflen, int zero,
46990 + void *req_handle, int atomic_alloc,
46991 + void *ereq_nonport);
46992 +
46993 +#endif
46994 +
46995 +/** De-queue the specified data transfer that has not yet completed.
46996 + *
46997 + * Returns -DWC_E_INVALID if invalid parameters were passed.
46998 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
46999 + * Returns 0 on success. */
47000 +extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
47001 + void *req_handle);
47002 +
47003 +/** Halt (STALL) an endpoint or clear it.
47004 + *
47005 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47006 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47007 + * Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later
47008 + * Returns 0 on success. */
47009 +extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value);
47010 +
47011 +/** This function */
47012 +extern int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle);
47013 +
47014 +/** This function should be called on every hardware interrupt */
47015 +extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd);
47016 +
47017 +/** This function returns current frame number */
47018 +extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd);
47019 +
47020 +/**
47021 + * Start isochronous transfers on the endpoint referenced by ep_handle.
47022 + * For isochronous transfers duble buffering is used.
47023 + * After processing each of buffers comlete callback will be called with
47024 + * status for each transaction.
47025 + *
47026 + * @param pcd The PCD
47027 + * @param ep_handle The handle of the endpoint
47028 + * @param buf0 The virtual address of first data buffer
47029 + * @param buf1 The virtual address of second data buffer
47030 + * @param dma0 The DMA address of first data buffer
47031 + * @param dma1 The DMA address of second data buffer
47032 + * @param sync_frame Data pattern frame number
47033 + * @param dp_frame Data size for pattern frame
47034 + * @param data_per_frame Data size for regular frame
47035 + * @param start_frame Frame number to start transfers, if -1 then start transfers ASAP.
47036 + * @param buf_proc_intrvl Interval of ISOC Buffer processing
47037 + * @param req_handle Handle of ISOC request
47038 + * @param atomic_alloc Specefies whether to perform atomic allocation for
47039 + * internal data structures.
47040 + *
47041 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
47042 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function.
47043 + * Returns -DW_E_SHUTDOWN for any other error.
47044 + * Returns 0 on success
47045 + */
47046 +extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
47047 + uint8_t * buf0, uint8_t * buf1,
47048 + dwc_dma_t dma0, dwc_dma_t dma1,
47049 + int sync_frame, int dp_frame,
47050 + int data_per_frame, int start_frame,
47051 + int buf_proc_intrvl, void *req_handle,
47052 + int atomic_alloc);
47053 +
47054 +/** Stop ISOC transfers on endpoint referenced by ep_handle.
47055 + *
47056 + * @param pcd The PCD
47057 + * @param ep_handle The handle of the endpoint
47058 + * @param req_handle Handle of ISOC request
47059 + *
47060 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function
47061 + * Returns 0 on success
47062 + */
47063 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
47064 + void *req_handle);
47065 +
47066 +/** Get ISOC packet status.
47067 + *
47068 + * @param pcd The PCD
47069 + * @param ep_handle The handle of the endpoint
47070 + * @param iso_req_handle Isochronoush request handle
47071 + * @param packet Number of packet
47072 + * @param status Out parameter for returning status
47073 + * @param actual Out parameter for returning actual length
47074 + * @param offset Out parameter for returning offset
47075 + *
47076 + */
47077 +extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd,
47078 + void *ep_handle,
47079 + void *iso_req_handle, int packet,
47080 + int *status, int *actual,
47081 + int *offset);
47082 +
47083 +/** Get ISOC packet count.
47084 + *
47085 + * @param pcd The PCD
47086 + * @param ep_handle The handle of the endpoint
47087 + * @param iso_req_handle
47088 + */
47089 +extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd,
47090 + void *ep_handle,
47091 + void *iso_req_handle);
47092 +
47093 +/** This function starts the SRP Protocol if no session is in progress. If
47094 + * a session is already in progress, but the device is suspended,
47095 + * remote wakeup signaling is started.
47096 + */
47097 +extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd);
47098 +
47099 +/** This function returns 1 if LPM support is enabled, and 0 otherwise. */
47100 +extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd);
47101 +
47102 +/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */
47103 +extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd);
47104 +
47105 +/** Initiate SRP */
47106 +extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd);
47107 +
47108 +/** Starts remote wakeup signaling. */
47109 +extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set);
47110 +
47111 +/** Starts micorsecond soft disconnect. */
47112 +extern void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs);
47113 +/** This function returns whether device is dualspeed.*/
47114 +extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd);
47115 +
47116 +/** This function returns whether device is otg. */
47117 +extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd);
47118 +
47119 +/** These functions allow to get hnp parameters */
47120 +extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd);
47121 +extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd);
47122 +extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd);
47123 +
47124 +/** CFI specific Interface functions */
47125 +/** Allocate a cfi buffer */
47126 +extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep,
47127 + dwc_dma_t * addr, size_t buflen,
47128 + int flags);
47129 +
47130 +/******************************************************************************/
47131 +
47132 +/** @} */
47133 +
47134 +#endif /* __DWC_PCD_IF_H__ */
47135 +
47136 +#endif /* DWC_HOST_ONLY */
47137 --- /dev/null
47138 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
47139 @@ -0,0 +1,5147 @@
47140 +/* ==========================================================================
47141 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $
47142 + * $Revision: #116 $
47143 + * $Date: 2012/08/10 $
47144 + * $Change: 2047372 $
47145 + *
47146 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
47147 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
47148 + * otherwise expressly agreed to in writing between Synopsys and you.
47149 + *
47150 + * The Software IS NOT an item of Licensed Software or Licensed Product under
47151 + * any End User Software License Agreement or Agreement for Licensed Product
47152 + * with Synopsys or any supplement thereto. You are permitted to use and
47153 + * redistribute this Software in source and binary forms, with or without
47154 + * modification, provided that redistributions of source code must retain this
47155 + * notice. You may not view, use, disclose, copy or distribute this file or
47156 + * any information contained herein except pursuant to this license grant from
47157 + * Synopsys. If you do not agree with this notice, including the disclaimer
47158 + * below, then you are not authorized to use the Software.
47159 + *
47160 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
47161 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47162 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47163 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
47164 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
47165 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
47166 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
47167 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47168 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47169 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
47170 + * DAMAGE.
47171 + * ========================================================================== */
47172 +#ifndef DWC_HOST_ONLY
47173 +
47174 +#include "dwc_otg_pcd.h"
47175 +
47176 +#ifdef DWC_UTE_CFI
47177 +#include "dwc_otg_cfi.h"
47178 +#endif
47179 +
47180 +#ifdef DWC_UTE_PER_IO
47181 +extern void complete_xiso_ep(dwc_otg_pcd_ep_t * ep);
47182 +#endif
47183 +//#define PRINT_CFI_DMA_DESCS
47184 +
47185 +#define DEBUG_EP0
47186 +
47187 +/**
47188 + * This function updates OTG.
47189 + */
47190 +static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset)
47191 +{
47192 +
47193 + if (reset) {
47194 + pcd->b_hnp_enable = 0;
47195 + pcd->a_hnp_support = 0;
47196 + pcd->a_alt_hnp_support = 0;
47197 + }
47198 +
47199 + if (pcd->fops->hnp_changed) {
47200 + pcd->fops->hnp_changed(pcd);
47201 + }
47202 +}
47203 +
47204 +/** @file
47205 + * This file contains the implementation of the PCD Interrupt handlers.
47206 + *
47207 + * The PCD handles the device interrupts. Many conditions can cause a
47208 + * device interrupt. When an interrupt occurs, the device interrupt
47209 + * service routine determines the cause of the interrupt and
47210 + * dispatches handling to the appropriate function. These interrupt
47211 + * handling functions are described below.
47212 + * All interrupt registers are processed from LSB to MSB.
47213 + */
47214 +
47215 +/**
47216 + * This function prints the ep0 state for debug purposes.
47217 + */
47218 +static inline void print_ep0_state(dwc_otg_pcd_t * pcd)
47219 +{
47220 +#ifdef DEBUG
47221 + char str[40];
47222 +
47223 + switch (pcd->ep0state) {
47224 + case EP0_DISCONNECT:
47225 + dwc_strcpy(str, "EP0_DISCONNECT");
47226 + break;
47227 + case EP0_IDLE:
47228 + dwc_strcpy(str, "EP0_IDLE");
47229 + break;
47230 + case EP0_IN_DATA_PHASE:
47231 + dwc_strcpy(str, "EP0_IN_DATA_PHASE");
47232 + break;
47233 + case EP0_OUT_DATA_PHASE:
47234 + dwc_strcpy(str, "EP0_OUT_DATA_PHASE");
47235 + break;
47236 + case EP0_IN_STATUS_PHASE:
47237 + dwc_strcpy(str, "EP0_IN_STATUS_PHASE");
47238 + break;
47239 + case EP0_OUT_STATUS_PHASE:
47240 + dwc_strcpy(str, "EP0_OUT_STATUS_PHASE");
47241 + break;
47242 + case EP0_STALL:
47243 + dwc_strcpy(str, "EP0_STALL");
47244 + break;
47245 + default:
47246 + dwc_strcpy(str, "EP0_INVALID");
47247 + }
47248 +
47249 + DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state);
47250 +#endif
47251 +}
47252 +
47253 +/**
47254 + * This function calculate the size of the payload in the memory
47255 + * for out endpoints and prints size for debug purposes(used in
47256 + * 2.93a DevOutNak feature).
47257 + */
47258 +static inline void print_memory_payload(dwc_otg_pcd_t * pcd, dwc_ep_t * ep)
47259 +{
47260 +#ifdef DEBUG
47261 + deptsiz_data_t deptsiz_init = {.d32 = 0 };
47262 + deptsiz_data_t deptsiz_updt = {.d32 = 0 };
47263 + int pack_num;
47264 + unsigned payload;
47265 +
47266 + deptsiz_init.d32 = pcd->core_if->start_doeptsiz_val[ep->num];
47267 + deptsiz_updt.d32 =
47268 + DWC_READ_REG32(&pcd->core_if->dev_if->
47269 + out_ep_regs[ep->num]->doeptsiz);
47270 + /* Payload will be */
47271 + payload = deptsiz_init.b.xfersize - deptsiz_updt.b.xfersize;
47272 + /* Packet count is decremented every time a packet
47273 + * is written to the RxFIFO not in to the external memory
47274 + * So, if payload == 0, then it means no packet was sent to ext memory*/
47275 + pack_num = (!payload) ? 0 : (deptsiz_init.b.pktcnt - deptsiz_updt.b.pktcnt);
47276 + DWC_DEBUGPL(DBG_PCDV,
47277 + "Payload for EP%d-%s\n",
47278 + ep->num, (ep->is_in ? "IN" : "OUT"));
47279 + DWC_DEBUGPL(DBG_PCDV,
47280 + "Number of transfered bytes = 0x%08x\n", payload);
47281 + DWC_DEBUGPL(DBG_PCDV,
47282 + "Number of transfered packets = %d\n", pack_num);
47283 +#endif
47284 +}
47285 +
47286 +
47287 +#ifdef DWC_UTE_CFI
47288 +static inline void print_desc(struct dwc_otg_dma_desc *ddesc,
47289 + const uint8_t * epname, int descnum)
47290 +{
47291 + CFI_INFO
47292 + ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n",
47293 + epname, descnum, ddesc->buf, ddesc->status.b.bytes,
47294 + ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts,
47295 + ddesc->status.b.bs);
47296 +}
47297 +#endif
47298 +
47299 +/**
47300 + * This function returns pointer to in ep struct with number ep_num
47301 + */
47302 +static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
47303 +{
47304 + int i;
47305 + int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
47306 + if (ep_num == 0) {
47307 + return &pcd->ep0;
47308 + } else {
47309 + for (i = 0; i < num_in_eps; ++i) {
47310 + if (pcd->in_ep[i].dwc_ep.num == ep_num)
47311 + return &pcd->in_ep[i];
47312 + }
47313 + return 0;
47314 + }
47315 +}
47316 +
47317 +/**
47318 + * This function returns pointer to out ep struct with number ep_num
47319 + */
47320 +static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
47321 +{
47322 + int i;
47323 + int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
47324 + if (ep_num == 0) {
47325 + return &pcd->ep0;
47326 + } else {
47327 + for (i = 0; i < num_out_eps; ++i) {
47328 + if (pcd->out_ep[i].dwc_ep.num == ep_num)
47329 + return &pcd->out_ep[i];
47330 + }
47331 + return 0;
47332 + }
47333 +}
47334 +
47335 +/**
47336 + * This functions gets a pointer to an EP from the wIndex address
47337 + * value of the control request.
47338 + */
47339 +dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex)
47340 +{
47341 + dwc_otg_pcd_ep_t *ep;
47342 + uint32_t ep_num = UE_GET_ADDR(wIndex);
47343 +
47344 + if (ep_num == 0) {
47345 + ep = &pcd->ep0;
47346 + } else if (UE_GET_DIR(wIndex) == UE_DIR_IN) { /* in ep */
47347 + ep = &pcd->in_ep[ep_num - 1];
47348 + } else {
47349 + ep = &pcd->out_ep[ep_num - 1];
47350 + }
47351 +
47352 + return ep;
47353 +}
47354 +
47355 +/**
47356 + * This function checks the EP request queue, if the queue is not
47357 + * empty the next request is started.
47358 + */
47359 +void start_next_request(dwc_otg_pcd_ep_t * ep)
47360 +{
47361 + dwc_otg_pcd_request_t *req = 0;
47362 + uint32_t max_transfer =
47363 + GET_CORE_IF(ep->pcd)->core_params->max_transfer_size;
47364 +
47365 +#ifdef DWC_UTE_CFI
47366 + struct dwc_otg_pcd *pcd;
47367 + pcd = ep->pcd;
47368 +#endif
47369 +
47370 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
47371 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
47372 +
47373 +#ifdef DWC_UTE_CFI
47374 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
47375 + ep->dwc_ep.cfi_req_len = req->length;
47376 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req);
47377 + } else {
47378 +#endif
47379 + /* Setup and start the Transfer */
47380 + if (req->dw_align_buf) {
47381 + ep->dwc_ep.dma_addr = req->dw_align_buf_dma;
47382 + ep->dwc_ep.start_xfer_buff = req->dw_align_buf;
47383 + ep->dwc_ep.xfer_buff = req->dw_align_buf;
47384 + } else {
47385 + ep->dwc_ep.dma_addr = req->dma;
47386 + ep->dwc_ep.start_xfer_buff = req->buf;
47387 + ep->dwc_ep.xfer_buff = req->buf;
47388 + }
47389 + ep->dwc_ep.sent_zlp = 0;
47390 + ep->dwc_ep.total_len = req->length;
47391 + ep->dwc_ep.xfer_len = 0;
47392 + ep->dwc_ep.xfer_count = 0;
47393 +
47394 + ep->dwc_ep.maxxfer = max_transfer;
47395 + if (GET_CORE_IF(ep->pcd)->dma_desc_enable) {
47396 + uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE
47397 + - (DDMA_MAX_TRANSFER_SIZE % 4);
47398 + if (ep->dwc_ep.is_in) {
47399 + if (ep->dwc_ep.maxxfer >
47400 + DDMA_MAX_TRANSFER_SIZE) {
47401 + ep->dwc_ep.maxxfer =
47402 + DDMA_MAX_TRANSFER_SIZE;
47403 + }
47404 + } else {
47405 + if (ep->dwc_ep.maxxfer > out_max_xfer) {
47406 + ep->dwc_ep.maxxfer =
47407 + out_max_xfer;
47408 + }
47409 + }
47410 + }
47411 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
47412 + ep->dwc_ep.maxxfer -=
47413 + (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket);
47414 + }
47415 + if (req->sent_zlp) {
47416 + if ((ep->dwc_ep.total_len %
47417 + ep->dwc_ep.maxpacket == 0)
47418 + && (ep->dwc_ep.total_len != 0)) {
47419 + ep->dwc_ep.sent_zlp = 1;
47420 + }
47421 +
47422 + }
47423 +#ifdef DWC_UTE_CFI
47424 + }
47425 +#endif
47426 + dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep);
47427 + } else if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
47428 + DWC_PRINTF("There are no more ISOC requests \n");
47429 + ep->dwc_ep.frame_num = 0xFFFFFFFF;
47430 + }
47431 +}
47432 +
47433 +/**
47434 + * This function handles the SOF Interrupts. At this time the SOF
47435 + * Interrupt is disabled.
47436 + */
47437 +int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd)
47438 +{
47439 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47440 +
47441 + gintsts_data_t gintsts;
47442 +
47443 + DWC_DEBUGPL(DBG_PCD, "SOF\n");
47444 +
47445 + /* Clear interrupt */
47446 + gintsts.d32 = 0;
47447 + gintsts.b.sofintr = 1;
47448 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
47449 +
47450 + return 1;
47451 +}
47452 +
47453 +/**
47454 + * This function handles the Rx Status Queue Level Interrupt, which
47455 + * indicates that there is a least one packet in the Rx FIFO. The
47456 + * packets are moved from the FIFO to memory, where they will be
47457 + * processed when the Endpoint Interrupt Register indicates Transfer
47458 + * Complete or SETUP Phase Done.
47459 + *
47460 + * Repeat the following until the Rx Status Queue is empty:
47461 + * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
47462 + * info
47463 + * -# If Receive FIFO is empty then skip to step Clear the interrupt
47464 + * and exit
47465 + * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
47466 + * SETUP data to the buffer
47467 + * -# If OUT Data Packet call dwc_otg_read_packet to copy the data
47468 + * to the destination buffer
47469 + */
47470 +int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd)
47471 +{
47472 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47473 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
47474 + gintmsk_data_t gintmask = {.d32 = 0 };
47475 + device_grxsts_data_t status;
47476 + dwc_otg_pcd_ep_t *ep;
47477 + gintsts_data_t gintsts;
47478 +#ifdef DEBUG
47479 + static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" };
47480 +#endif
47481 +
47482 + //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
47483 + /* Disable the Rx Status Queue Level interrupt */
47484 + gintmask.b.rxstsqlvl = 1;
47485 + DWC_MODIFY_REG32(&global_regs->gintmsk, gintmask.d32, 0);
47486 +
47487 + /* Get the Status from the top of the FIFO */
47488 + status.d32 = DWC_READ_REG32(&global_regs->grxstsp);
47489 +
47490 + DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
47491 + "pktsts:%x Frame:%d(0x%0x)\n",
47492 + status.b.epnum, status.b.bcnt,
47493 + dpid_str[status.b.dpid],
47494 + status.b.pktsts, status.b.fn, status.b.fn);
47495 + /* Get pointer to EP structure */
47496 + ep = get_out_ep(pcd, status.b.epnum);
47497 +
47498 + switch (status.b.pktsts) {
47499 + case DWC_DSTS_GOUT_NAK:
47500 + DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
47501 + break;
47502 + case DWC_STS_DATA_UPDT:
47503 + DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
47504 + if (status.b.bcnt && ep->dwc_ep.xfer_buff) {
47505 + /** @todo NGS Check for buffer overflow? */
47506 + dwc_otg_read_packet(core_if,
47507 + ep->dwc_ep.xfer_buff,
47508 + status.b.bcnt);
47509 + ep->dwc_ep.xfer_count += status.b.bcnt;
47510 + ep->dwc_ep.xfer_buff += status.b.bcnt;
47511 + }
47512 + break;
47513 + case DWC_STS_XFER_COMP:
47514 + DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
47515 + break;
47516 + case DWC_DSTS_SETUP_COMP:
47517 +#ifdef DEBUG_EP0
47518 + DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
47519 +#endif
47520 + break;
47521 + case DWC_DSTS_SETUP_UPDT:
47522 + dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32);
47523 +#ifdef DEBUG_EP0
47524 + DWC_DEBUGPL(DBG_PCD,
47525 + "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
47526 + pcd->setup_pkt->req.bmRequestType,
47527 + pcd->setup_pkt->req.bRequest,
47528 + UGETW(pcd->setup_pkt->req.wValue),
47529 + UGETW(pcd->setup_pkt->req.wIndex),
47530 + UGETW(pcd->setup_pkt->req.wLength));
47531 +#endif
47532 + ep->dwc_ep.xfer_count += status.b.bcnt;
47533 + break;
47534 + default:
47535 + DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
47536 + status.b.pktsts);
47537 + break;
47538 + }
47539 +
47540 + /* Enable the Rx Status Queue Level interrupt */
47541 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmask.d32);
47542 + /* Clear interrupt */
47543 + gintsts.d32 = 0;
47544 + gintsts.b.rxstsqlvl = 1;
47545 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
47546 +
47547 + //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
47548 + return 1;
47549 +}
47550 +
47551 +/**
47552 + * This function examines the Device IN Token Learning Queue to
47553 + * determine the EP number of the last IN token received. This
47554 + * implementation is for the Mass Storage device where there are only
47555 + * 2 IN EPs (Control-IN and BULK-IN).
47556 + *
47557 + * The EP numbers for the first six IN Tokens are in DTKNQR1 and there
47558 + * are 8 EP Numbers in each of the other possible DTKNQ Registers.
47559 + *
47560 + * @param core_if Programming view of DWC_otg controller.
47561 + *
47562 + */
47563 +static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if)
47564 +{
47565 + dwc_otg_device_global_regs_t *dev_global_regs =
47566 + core_if->dev_if->dev_global_regs;
47567 + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
47568 + /* Number of Token Queue Registers */
47569 + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
47570 + dtknq1_data_t dtknqr1;
47571 + uint32_t in_tkn_epnums[4];
47572 + int ndx = 0;
47573 + int i = 0;
47574 + volatile uint32_t *addr = &dev_global_regs->dtknqr1;
47575 + int epnum = 0;
47576 +
47577 + //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
47578 +
47579 + /* Read the DTKNQ Registers */
47580 + for (i = 0; i < DTKNQ_REG_CNT; i++) {
47581 + in_tkn_epnums[i] = DWC_READ_REG32(addr);
47582 + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
47583 + in_tkn_epnums[i]);
47584 + if (addr == &dev_global_regs->dvbusdis) {
47585 + addr = &dev_global_regs->dtknqr3_dthrctl;
47586 + } else {
47587 + ++addr;
47588 + }
47589 +
47590 + }
47591 +
47592 + /* Copy the DTKNQR1 data to the bit field. */
47593 + dtknqr1.d32 = in_tkn_epnums[0];
47594 + /* Get the EP numbers */
47595 + in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
47596 + ndx = dtknqr1.b.intknwptr - 1;
47597 +
47598 + //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
47599 + if (ndx == -1) {
47600 + /** @todo Find a simpler way to calculate the max
47601 + * queue position.*/
47602 + int cnt = TOKEN_Q_DEPTH;
47603 + if (TOKEN_Q_DEPTH <= 6) {
47604 + cnt = TOKEN_Q_DEPTH - 1;
47605 + } else if (TOKEN_Q_DEPTH <= 14) {
47606 + cnt = TOKEN_Q_DEPTH - 7;
47607 + } else if (TOKEN_Q_DEPTH <= 22) {
47608 + cnt = TOKEN_Q_DEPTH - 15;
47609 + } else {
47610 + cnt = TOKEN_Q_DEPTH - 23;
47611 + }
47612 + epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF;
47613 + } else {
47614 + if (ndx <= 5) {
47615 + epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
47616 + } else if (ndx <= 13) {
47617 + ndx -= 6;
47618 + epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
47619 + } else if (ndx <= 21) {
47620 + ndx -= 14;
47621 + epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
47622 + } else if (ndx <= 29) {
47623 + ndx -= 22;
47624 + epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
47625 + }
47626 + }
47627 + //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
47628 + return epnum;
47629 +}
47630 +
47631 +/**
47632 + * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
47633 + * The active request is checked for the next packet to be loaded into
47634 + * the non-periodic Tx FIFO.
47635 + */
47636 +int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd)
47637 +{
47638 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47639 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
47640 + dwc_otg_dev_in_ep_regs_t *ep_regs;
47641 + gnptxsts_data_t txstatus = {.d32 = 0 };
47642 + gintsts_data_t gintsts;
47643 +
47644 + int epnum = 0;
47645 + dwc_otg_pcd_ep_t *ep = 0;
47646 + uint32_t len = 0;
47647 + int dwords;
47648 +
47649 + /* Get the epnum from the IN Token Learning Queue. */
47650 + epnum = get_ep_of_last_in_token(core_if);
47651 + ep = get_in_ep(pcd, epnum);
47652 +
47653 + DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum);
47654 +
47655 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
47656 +
47657 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47658 + if (len > ep->dwc_ep.maxpacket) {
47659 + len = ep->dwc_ep.maxpacket;
47660 + }
47661 + dwords = (len + 3) / 4;
47662 +
47663 + /* While there is space in the queue and space in the FIFO and
47664 + * More data to tranfer, Write packets to the Tx FIFO */
47665 + txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
47666 + DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32);
47667 +
47668 + while (txstatus.b.nptxqspcavail > 0 &&
47669 + txstatus.b.nptxfspcavail > dwords &&
47670 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) {
47671 + /* Write the FIFO */
47672 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
47673 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47674 +
47675 + if (len > ep->dwc_ep.maxpacket) {
47676 + len = ep->dwc_ep.maxpacket;
47677 + }
47678 +
47679 + dwords = (len + 3) / 4;
47680 + txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
47681 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32);
47682 + }
47683 +
47684 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
47685 + DWC_READ_REG32(&global_regs->gnptxsts));
47686 +
47687 + /* Clear interrupt */
47688 + gintsts.d32 = 0;
47689 + gintsts.b.nptxfempty = 1;
47690 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
47691 +
47692 + return 1;
47693 +}
47694 +
47695 +/**
47696 + * This function is called when dedicated Tx FIFO Empty interrupt occurs.
47697 + * The active request is checked for the next packet to be loaded into
47698 + * apropriate Tx FIFO.
47699 + */
47700 +static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum)
47701 +{
47702 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47703 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
47704 + dwc_otg_dev_in_ep_regs_t *ep_regs;
47705 + dtxfsts_data_t txstatus = {.d32 = 0 };
47706 + dwc_otg_pcd_ep_t *ep = 0;
47707 + uint32_t len = 0;
47708 + int dwords;
47709 +
47710 + ep = get_in_ep(pcd, epnum);
47711 +
47712 + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
47713 +
47714 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
47715 +
47716 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47717 +
47718 + if (len > ep->dwc_ep.maxpacket) {
47719 + len = ep->dwc_ep.maxpacket;
47720 + }
47721 +
47722 + dwords = (len + 3) / 4;
47723 +
47724 + /* While there is space in the queue and space in the FIFO and
47725 + * More data to tranfer, Write packets to the Tx FIFO */
47726 + txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
47727 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
47728 +
47729 + while (txstatus.b.txfspcavail > dwords &&
47730 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
47731 + ep->dwc_ep.xfer_len != 0) {
47732 + /* Write the FIFO */
47733 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
47734 +
47735 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47736 + if (len > ep->dwc_ep.maxpacket) {
47737 + len = ep->dwc_ep.maxpacket;
47738 + }
47739 +
47740 + dwords = (len + 3) / 4;
47741 + txstatus.d32 =
47742 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
47743 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
47744 + txstatus.d32);
47745 + }
47746 +
47747 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
47748 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
47749 +
47750 + return 1;
47751 +}
47752 +
47753 +/**
47754 + * This function is called when the Device is disconnected. It stops
47755 + * any active requests and informs the Gadget driver of the
47756 + * disconnect.
47757 + */
47758 +void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd)
47759 +{
47760 + int i, num_in_eps, num_out_eps;
47761 + dwc_otg_pcd_ep_t *ep;
47762 +
47763 + gintmsk_data_t intr_mask = {.d32 = 0 };
47764 +
47765 + DWC_SPINLOCK(pcd->lock);
47766 +
47767 + num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
47768 + num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
47769 +
47770 + DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__);
47771 + /* don't disconnect drivers more than once */
47772 + if (pcd->ep0state == EP0_DISCONNECT) {
47773 + DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__);
47774 + DWC_SPINUNLOCK(pcd->lock);
47775 + return;
47776 + }
47777 + pcd->ep0state = EP0_DISCONNECT;
47778 +
47779 + /* Reset the OTG state. */
47780 + dwc_otg_pcd_update_otg(pcd, 1);
47781 +
47782 + /* Disable the NP Tx Fifo Empty Interrupt. */
47783 + intr_mask.b.nptxfempty = 1;
47784 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
47785 + intr_mask.d32, 0);
47786 +
47787 + /* Flush the FIFOs */
47788 + /**@todo NGS Flush Periodic FIFOs */
47789 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10);
47790 + dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd));
47791 +
47792 + /* prevent new request submissions, kill any outstanding requests */
47793 + ep = &pcd->ep0;
47794 + dwc_otg_request_nuke(ep);
47795 + /* prevent new request submissions, kill any outstanding requests */
47796 + for (i = 0; i < num_in_eps; i++) {
47797 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i];
47798 + dwc_otg_request_nuke(ep);
47799 + }
47800 + /* prevent new request submissions, kill any outstanding requests */
47801 + for (i = 0; i < num_out_eps; i++) {
47802 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i];
47803 + dwc_otg_request_nuke(ep);
47804 + }
47805 +
47806 + /* report disconnect; the driver is already quiesced */
47807 + if (pcd->fops->disconnect) {
47808 + DWC_SPINUNLOCK(pcd->lock);
47809 + pcd->fops->disconnect(pcd);
47810 + DWC_SPINLOCK(pcd->lock);
47811 + }
47812 + DWC_SPINUNLOCK(pcd->lock);
47813 +}
47814 +
47815 +/**
47816 + * This interrupt indicates that ...
47817 + */
47818 +int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd)
47819 +{
47820 + gintmsk_data_t intr_mask = {.d32 = 0 };
47821 + gintsts_data_t gintsts;
47822 +
47823 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr");
47824 + intr_mask.b.i2cintr = 1;
47825 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
47826 + intr_mask.d32, 0);
47827 +
47828 + /* Clear interrupt */
47829 + gintsts.d32 = 0;
47830 + gintsts.b.i2cintr = 1;
47831 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
47832 + gintsts.d32);
47833 + return 1;
47834 +}
47835 +
47836 +/**
47837 + * This interrupt indicates that ...
47838 + */
47839 +int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd)
47840 +{
47841 + gintsts_data_t gintsts;
47842 +#if defined(VERBOSE)
47843 + DWC_PRINTF("Early Suspend Detected\n");
47844 +#endif
47845 +
47846 + /* Clear interrupt */
47847 + gintsts.d32 = 0;
47848 + gintsts.b.erlysuspend = 1;
47849 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
47850 + gintsts.d32);
47851 + return 1;
47852 +}
47853 +
47854 +/**
47855 + * This function configures EPO to receive SETUP packets.
47856 + *
47857 + * @todo NGS: Update the comments from the HW FS.
47858 + *
47859 + * -# Program the following fields in the endpoint specific registers
47860 + * for Control OUT EP 0, in order to receive a setup packet
47861 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
47862 + * setup packets)
47863 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
47864 + * to back setup packets)
47865 + * - In DMA mode, DOEPDMA0 Register with a memory address to
47866 + * store any setup packets received
47867 + *
47868 + * @param core_if Programming view of DWC_otg controller.
47869 + * @param pcd Programming view of the PCD.
47870 + */
47871 +static inline void ep0_out_start(dwc_otg_core_if_t * core_if,
47872 + dwc_otg_pcd_t * pcd)
47873 +{
47874 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
47875 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
47876 + dwc_otg_dev_dma_desc_t *dma_desc;
47877 + depctl_data_t doepctl = {.d32 = 0 };
47878 +
47879 +#ifdef VERBOSE
47880 + DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__,
47881 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
47882 +#endif
47883 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
47884 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
47885 + if (doepctl.b.epena) {
47886 + return;
47887 + }
47888 + }
47889 +
47890 + doeptsize0.b.supcnt = 3;
47891 + doeptsize0.b.pktcnt = 1;
47892 + doeptsize0.b.xfersize = 8 * 3;
47893 +
47894 + if (core_if->dma_enable) {
47895 + if (!core_if->dma_desc_enable) {
47896 + /** put here as for Hermes mode deptisz register should not be written */
47897 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
47898 + doeptsize0.d32);
47899 +
47900 + /** @todo dma needs to handle multiple setup packets (up to 3) */
47901 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
47902 + pcd->setup_pkt_dma_handle);
47903 + } else {
47904 + dev_if->setup_desc_index =
47905 + (dev_if->setup_desc_index + 1) & 1;
47906 + dma_desc =
47907 + dev_if->setup_desc_addr[dev_if->setup_desc_index];
47908 +
47909 + /** DMA Descriptor Setup */
47910 + dma_desc->status.b.bs = BS_HOST_BUSY;
47911 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
47912 + dma_desc->status.b.sr = 0;
47913 + dma_desc->status.b.mtrf = 0;
47914 + }
47915 + dma_desc->status.b.l = 1;
47916 + dma_desc->status.b.ioc = 1;
47917 + dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket;
47918 + dma_desc->buf = pcd->setup_pkt_dma_handle;
47919 + dma_desc->status.b.sts = 0;
47920 + dma_desc->status.b.bs = BS_HOST_READY;
47921 +
47922 + /** DOEPDMA0 Register write */
47923 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
47924 + dev_if->dma_setup_desc_addr
47925 + [dev_if->setup_desc_index]);
47926 + }
47927 +
47928 + } else {
47929 + /** put here as for Hermes mode deptisz register should not be written */
47930 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
47931 + doeptsize0.d32);
47932 + }
47933 +
47934 + /** DOEPCTL0 Register write cnak will be set after setup interrupt */
47935 + doepctl.d32 = 0;
47936 + doepctl.b.epena = 1;
47937 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
47938 + doepctl.b.cnak = 1;
47939 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
47940 + } else {
47941 + DWC_MODIFY_REG32(&dev_if->out_ep_regs[0]->doepctl, 0, doepctl.d32);
47942 + }
47943 +
47944 +#ifdef VERBOSE
47945 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
47946 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
47947 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
47948 + DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
47949 +#endif
47950 +}
47951 +
47952 +/**
47953 + * This interrupt occurs when a USB Reset is detected. When the USB
47954 + * Reset Interrupt occurs the device state is set to DEFAULT and the
47955 + * EP0 state is set to IDLE.
47956 + * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
47957 + * -# Unmask the following interrupt bits
47958 + * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
47959 + * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
47960 + * - DOEPMSK.SETUP = 1
47961 + * - DOEPMSK.XferCompl = 1
47962 + * - DIEPMSK.XferCompl = 1
47963 + * - DIEPMSK.TimeOut = 1
47964 + * -# Program the following fields in the endpoint specific registers
47965 + * for Control OUT EP 0, in order to receive a setup packet
47966 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
47967 + * setup packets)
47968 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
47969 + * to back setup packets)
47970 + * - In DMA mode, DOEPDMA0 Register with a memory address to
47971 + * store any setup packets received
47972 + * At this point, all the required initialization, except for enabling
47973 + * the control 0 OUT endpoint is done, for receiving SETUP packets.
47974 + */
47975 +int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd)
47976 +{
47977 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47978 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
47979 + depctl_data_t doepctl = {.d32 = 0 };
47980 + depctl_data_t diepctl = {.d32 = 0 };
47981 + daint_data_t daintmsk = {.d32 = 0 };
47982 + doepmsk_data_t doepmsk = {.d32 = 0 };
47983 + diepmsk_data_t diepmsk = {.d32 = 0 };
47984 + dcfg_data_t dcfg = {.d32 = 0 };
47985 + grstctl_t resetctl = {.d32 = 0 };
47986 + dctl_data_t dctl = {.d32 = 0 };
47987 + int i = 0;
47988 + gintsts_data_t gintsts;
47989 + pcgcctl_data_t power = {.d32 = 0 };
47990 +
47991 + power.d32 = DWC_READ_REG32(core_if->pcgcctl);
47992 + if (power.b.stoppclk) {
47993 + power.d32 = 0;
47994 + power.b.stoppclk = 1;
47995 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
47996 +
47997 + power.b.pwrclmp = 1;
47998 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
47999 +
48000 + power.b.rstpdwnmodule = 1;
48001 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
48002 + }
48003 +
48004 + core_if->lx_state = DWC_OTG_L0;
48005 +
48006 + DWC_PRINTF("USB RESET\n");
48007 +#ifdef DWC_EN_ISOC
48008 + for (i = 1; i < 16; ++i) {
48009 + dwc_otg_pcd_ep_t *ep;
48010 + dwc_ep_t *dwc_ep;
48011 + ep = get_in_ep(pcd, i);
48012 + if (ep != 0) {
48013 + dwc_ep = &ep->dwc_ep;
48014 + dwc_ep->next_frame = 0xffffffff;
48015 + }
48016 + }
48017 +#endif /* DWC_EN_ISOC */
48018 +
48019 + /* reset the HNP settings */
48020 + dwc_otg_pcd_update_otg(pcd, 1);
48021 +
48022 + /* Clear the Remote Wakeup Signalling */
48023 + dctl.b.rmtwkupsig = 1;
48024 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
48025 +
48026 + /* Set NAK for all OUT EPs */
48027 + doepctl.b.snak = 1;
48028 + for (i = 0; i <= dev_if->num_out_eps; i++) {
48029 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
48030 + }
48031 +
48032 + /* Flush the NP Tx FIFO */
48033 + dwc_otg_flush_tx_fifo(core_if, 0x10);
48034 + /* Flush the Learning Queue */
48035 + resetctl.b.intknqflsh = 1;
48036 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
48037 +
48038 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
48039 + core_if->start_predict = 0;
48040 + for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
48041 + core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
48042 + }
48043 + core_if->nextep_seq[0] = 0;
48044 + core_if->first_in_nextep_seq = 0;
48045 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
48046 + diepctl.b.nextep = 0;
48047 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
48048 +
48049 + /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
48050 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
48051 + dcfg.b.epmscnt = 2;
48052 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
48053 +
48054 + DWC_DEBUGPL(DBG_PCDV,
48055 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
48056 + __func__, core_if->first_in_nextep_seq);
48057 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
48058 + DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
48059 + }
48060 + }
48061 +
48062 + if (core_if->multiproc_int_enable) {
48063 + daintmsk.b.inep0 = 1;
48064 + daintmsk.b.outep0 = 1;
48065 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk,
48066 + daintmsk.d32);
48067 +
48068 + doepmsk.b.setup = 1;
48069 + doepmsk.b.xfercompl = 1;
48070 + doepmsk.b.ahberr = 1;
48071 + doepmsk.b.epdisabled = 1;
48072 +
48073 + if ((core_if->dma_desc_enable) ||
48074 + (core_if->dma_enable
48075 + && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
48076 + doepmsk.b.stsphsercvd = 1;
48077 + }
48078 + if (core_if->dma_desc_enable)
48079 + doepmsk.b.bna = 1;
48080 +/*
48081 + doepmsk.b.babble = 1;
48082 + doepmsk.b.nyet = 1;
48083 +
48084 + if (core_if->dma_enable) {
48085 + doepmsk.b.nak = 1;
48086 + }
48087 +*/
48088 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepeachintmsk[0],
48089 + doepmsk.d32);
48090 +
48091 + diepmsk.b.xfercompl = 1;
48092 + diepmsk.b.timeout = 1;
48093 + diepmsk.b.epdisabled = 1;
48094 + diepmsk.b.ahberr = 1;
48095 + diepmsk.b.intknepmis = 1;
48096 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
48097 + diepmsk.b.intknepmis = 0;
48098 +
48099 +/* if (core_if->dma_desc_enable) {
48100 + diepmsk.b.bna = 1;
48101 + }
48102 +*/
48103 +/*
48104 + if (core_if->dma_enable) {
48105 + diepmsk.b.nak = 1;
48106 + }
48107 +*/
48108 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepeachintmsk[0],
48109 + diepmsk.d32);
48110 + } else {
48111 + daintmsk.b.inep0 = 1;
48112 + daintmsk.b.outep0 = 1;
48113 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk,
48114 + daintmsk.d32);
48115 +
48116 + doepmsk.b.setup = 1;
48117 + doepmsk.b.xfercompl = 1;
48118 + doepmsk.b.ahberr = 1;
48119 + doepmsk.b.epdisabled = 1;
48120 +
48121 + if ((core_if->dma_desc_enable) ||
48122 + (core_if->dma_enable
48123 + && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
48124 + doepmsk.b.stsphsercvd = 1;
48125 + }
48126 + if (core_if->dma_desc_enable)
48127 + doepmsk.b.bna = 1;
48128 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32);
48129 +
48130 + diepmsk.b.xfercompl = 1;
48131 + diepmsk.b.timeout = 1;
48132 + diepmsk.b.epdisabled = 1;
48133 + diepmsk.b.ahberr = 1;
48134 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
48135 + diepmsk.b.intknepmis = 0;
48136 +/*
48137 + if (core_if->dma_desc_enable) {
48138 + diepmsk.b.bna = 1;
48139 + }
48140 +*/
48141 +
48142 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32);
48143 + }
48144 +
48145 + /* Reset Device Address */
48146 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
48147 + dcfg.b.devaddr = 0;
48148 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
48149 +
48150 + /* setup EP0 to receive SETUP packets */
48151 + if (core_if->snpsid <= OTG_CORE_REV_2_94a)
48152 + ep0_out_start(core_if, pcd);
48153 +
48154 + /* Clear interrupt */
48155 + gintsts.d32 = 0;
48156 + gintsts.b.usbreset = 1;
48157 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48158 +
48159 + return 1;
48160 +}
48161 +
48162 +/**
48163 + * Get the device speed from the device status register and convert it
48164 + * to USB speed constant.
48165 + *
48166 + * @param core_if Programming view of DWC_otg controller.
48167 + */
48168 +static int get_device_speed(dwc_otg_core_if_t * core_if)
48169 +{
48170 + dsts_data_t dsts;
48171 + int speed = 0;
48172 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
48173 +
48174 + switch (dsts.b.enumspd) {
48175 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
48176 + speed = USB_SPEED_HIGH;
48177 + break;
48178 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
48179 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
48180 + speed = USB_SPEED_FULL;
48181 + break;
48182 +
48183 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
48184 + speed = USB_SPEED_LOW;
48185 + break;
48186 + }
48187 +
48188 + return speed;
48189 +}
48190 +
48191 +/**
48192 + * Read the device status register and set the device speed in the
48193 + * data structure.
48194 + * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
48195 + */
48196 +int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd)
48197 +{
48198 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48199 + gintsts_data_t gintsts;
48200 + gusbcfg_data_t gusbcfg;
48201 + dwc_otg_core_global_regs_t *global_regs =
48202 + GET_CORE_IF(pcd)->core_global_regs;
48203 + uint8_t utmi16b, utmi8b;
48204 + int speed;
48205 + DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
48206 +
48207 + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
48208 + utmi16b = 6; //vahrama old value was 6;
48209 + utmi8b = 9;
48210 + } else {
48211 + utmi16b = 4;
48212 + utmi8b = 8;
48213 + }
48214 + dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep);
48215 + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a) {
48216 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48217 + }
48218 +
48219 +#ifdef DEBUG_EP0
48220 + print_ep0_state(pcd);
48221 +#endif
48222 +
48223 + if (pcd->ep0state == EP0_DISCONNECT) {
48224 + pcd->ep0state = EP0_IDLE;
48225 + } else if (pcd->ep0state == EP0_STALL) {
48226 + pcd->ep0state = EP0_IDLE;
48227 + }
48228 +
48229 + pcd->ep0state = EP0_IDLE;
48230 +
48231 + ep0->stopped = 0;
48232 +
48233 + speed = get_device_speed(GET_CORE_IF(pcd));
48234 + pcd->fops->connect(pcd, speed);
48235 +
48236 + /* Set USB turnaround time based on device speed and PHY interface. */
48237 + gusbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
48238 + if (speed == USB_SPEED_HIGH) {
48239 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48240 + DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
48241 + /* ULPI interface */
48242 + gusbcfg.b.usbtrdtim = 9;
48243 + }
48244 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48245 + DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
48246 + /* UTMI+ interface */
48247 + if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) {
48248 + gusbcfg.b.usbtrdtim = utmi8b;
48249 + } else if (GET_CORE_IF(pcd)->hwcfg4.
48250 + b.utmi_phy_data_width == 1) {
48251 + gusbcfg.b.usbtrdtim = utmi16b;
48252 + } else if (GET_CORE_IF(pcd)->
48253 + core_params->phy_utmi_width == 8) {
48254 + gusbcfg.b.usbtrdtim = utmi8b;
48255 + } else {
48256 + gusbcfg.b.usbtrdtim = utmi16b;
48257 + }
48258 + }
48259 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48260 + DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
48261 + /* UTMI+ OR ULPI interface */
48262 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
48263 + /* ULPI interface */
48264 + gusbcfg.b.usbtrdtim = 9;
48265 + } else {
48266 + /* UTMI+ interface */
48267 + if (GET_CORE_IF(pcd)->
48268 + core_params->phy_utmi_width == 16) {
48269 + gusbcfg.b.usbtrdtim = utmi16b;
48270 + } else {
48271 + gusbcfg.b.usbtrdtim = utmi8b;
48272 + }
48273 + }
48274 + }
48275 + } else {
48276 + /* Full or low speed */
48277 + gusbcfg.b.usbtrdtim = 9;
48278 + }
48279 + DWC_WRITE_REG32(&global_regs->gusbcfg, gusbcfg.d32);
48280 +
48281 + /* Clear interrupt */
48282 + gintsts.d32 = 0;
48283 + gintsts.b.enumdone = 1;
48284 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48285 + gintsts.d32);
48286 + return 1;
48287 +}
48288 +
48289 +/**
48290 + * This interrupt indicates that the ISO OUT Packet was dropped due to
48291 + * Rx FIFO full or Rx Status Queue Full. If this interrupt occurs
48292 + * read all the data from the Rx FIFO.
48293 + */
48294 +int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd)
48295 +{
48296 + gintmsk_data_t intr_mask = {.d32 = 0 };
48297 + gintsts_data_t gintsts;
48298 +
48299 + DWC_WARN("INTERRUPT Handler not implemented for %s\n",
48300 + "ISOC Out Dropped");
48301 +
48302 + intr_mask.b.isooutdrop = 1;
48303 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48304 + intr_mask.d32, 0);
48305 +
48306 + /* Clear interrupt */
48307 + gintsts.d32 = 0;
48308 + gintsts.b.isooutdrop = 1;
48309 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48310 + gintsts.d32);
48311 +
48312 + return 1;
48313 +}
48314 +
48315 +/**
48316 + * This interrupt indicates the end of the portion of the micro-frame
48317 + * for periodic transactions. If there is a periodic transaction for
48318 + * the next frame, load the packets into the EP periodic Tx FIFO.
48319 + */
48320 +int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd)
48321 +{
48322 + gintmsk_data_t intr_mask = {.d32 = 0 };
48323 + gintsts_data_t gintsts;
48324 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP");
48325 +
48326 + intr_mask.b.eopframe = 1;
48327 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48328 + intr_mask.d32, 0);
48329 +
48330 + /* Clear interrupt */
48331 + gintsts.d32 = 0;
48332 + gintsts.b.eopframe = 1;
48333 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48334 + gintsts.d32);
48335 +
48336 + return 1;
48337 +}
48338 +
48339 +/**
48340 + * This interrupt indicates that EP of the packet on the top of the
48341 + * non-periodic Tx FIFO does not match EP of the IN Token received.
48342 + *
48343 + * The "Device IN Token Queue" Registers are read to determine the
48344 + * order the IN Tokens have been received. The non-periodic Tx FIFO
48345 + * is flushed, so it can be reloaded in the order seen in the IN Token
48346 + * Queue.
48347 + */
48348 +int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_pcd_t * pcd)
48349 +{
48350 + gintsts_data_t gintsts;
48351 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48352 + dctl_data_t dctl;
48353 + gintmsk_data_t intr_mask = {.d32 = 0 };
48354 +
48355 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable) {
48356 + core_if->start_predict = 1;
48357 +
48358 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
48359 +
48360 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
48361 + if (!gintsts.b.ginnakeff) {
48362 + /* Disable EP Mismatch interrupt */
48363 + intr_mask.d32 = 0;
48364 + intr_mask.b.epmismatch = 1;
48365 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
48366 + /* Enable the Global IN NAK Effective Interrupt */
48367 + intr_mask.d32 = 0;
48368 + intr_mask.b.ginnakeff = 1;
48369 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
48370 + /* Set the global non-periodic IN NAK handshake */
48371 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
48372 + dctl.b.sgnpinnak = 1;
48373 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
48374 + } else {
48375 + DWC_PRINTF("gintsts.b.ginnakeff = 1! dctl.b.sgnpinnak not set\n");
48376 + }
48377 + /* Disabling of all EP's will be done in dwc_otg_pcd_handle_in_nak_effective()
48378 + * handler after Global IN NAK Effective interrupt will be asserted */
48379 + }
48380 + /* Clear interrupt */
48381 + gintsts.d32 = 0;
48382 + gintsts.b.epmismatch = 1;
48383 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48384 +
48385 + return 1;
48386 +}
48387 +
48388 +/**
48389 + * This interrupt is valid only in DMA mode. This interrupt indicates that the
48390 + * core has stopped fetching data for IN endpoints due to the unavailability of
48391 + * TxFIFO space or Request Queue space. This interrupt is used by the
48392 + * application for an endpoint mismatch algorithm.
48393 + *
48394 + * @param pcd The PCD
48395 + */
48396 +int32_t dwc_otg_pcd_handle_ep_fetsusp_intr(dwc_otg_pcd_t * pcd)
48397 +{
48398 + gintsts_data_t gintsts;
48399 + gintmsk_data_t gintmsk_data;
48400 + dctl_data_t dctl;
48401 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48402 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
48403 +
48404 + /* Clear the global non-periodic IN NAK handshake */
48405 + dctl.d32 = 0;
48406 + dctl.b.cgnpinnak = 1;
48407 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
48408 +
48409 + /* Mask GINTSTS.FETSUSP interrupt */
48410 + gintmsk_data.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
48411 + gintmsk_data.b.fetsusp = 0;
48412 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_data.d32);
48413 +
48414 + /* Clear interrupt */
48415 + gintsts.d32 = 0;
48416 + gintsts.b.fetsusp = 1;
48417 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48418 +
48419 + return 1;
48420 +}
48421 +/**
48422 + * This funcion stalls EP0.
48423 + */
48424 +static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val)
48425 +{
48426 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48427 + usb_device_request_t *ctrl = &pcd->setup_pkt->req;
48428 + DWC_WARN("req %02x.%02x protocol STALL; err %d\n",
48429 + ctrl->bmRequestType, ctrl->bRequest, err_val);
48430 +
48431 + ep0->dwc_ep.is_in = 1;
48432 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep);
48433 + pcd->ep0.stopped = 1;
48434 + pcd->ep0state = EP0_IDLE;
48435 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48436 +}
48437 +
48438 +/**
48439 + * This functions delegates the setup command to the gadget driver.
48440 + */
48441 +static inline void do_gadget_setup(dwc_otg_pcd_t * pcd,
48442 + usb_device_request_t * ctrl)
48443 +{
48444 + int ret = 0;
48445 + DWC_SPINUNLOCK(pcd->lock);
48446 + ret = pcd->fops->setup(pcd, (uint8_t *) ctrl);
48447 + DWC_SPINLOCK(pcd->lock);
48448 + if (ret < 0) {
48449 + ep0_do_stall(pcd, ret);
48450 + }
48451 +
48452 + /** @todo This is a g_file_storage gadget driver specific
48453 + * workaround: a DELAYED_STATUS result from the fsg_setup
48454 + * routine will result in the gadget queueing a EP0 IN status
48455 + * phase for a two-stage control transfer. Exactly the same as
48456 + * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
48457 + * specific request. Need a generic way to know when the gadget
48458 + * driver will queue the status phase. Can we assume when we
48459 + * call the gadget driver setup() function that it will always
48460 + * queue and require the following flag? Need to look into
48461 + * this.
48462 + */
48463 +
48464 + if (ret == 256 + 999) {
48465 + pcd->request_config = 1;
48466 + }
48467 +}
48468 +
48469 +#ifdef DWC_UTE_CFI
48470 +/**
48471 + * This functions delegates the CFI setup commands to the gadget driver.
48472 + * This function will return a negative value to indicate a failure.
48473 + */
48474 +static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd,
48475 + struct cfi_usb_ctrlrequest *ctrl_req)
48476 +{
48477 + int ret = 0;
48478 +
48479 + if (pcd->fops && pcd->fops->cfi_setup) {
48480 + DWC_SPINUNLOCK(pcd->lock);
48481 + ret = pcd->fops->cfi_setup(pcd, ctrl_req);
48482 + DWC_SPINLOCK(pcd->lock);
48483 + if (ret < 0) {
48484 + ep0_do_stall(pcd, ret);
48485 + return ret;
48486 + }
48487 + }
48488 +
48489 + return ret;
48490 +}
48491 +#endif
48492 +
48493 +/**
48494 + * This function starts the Zero-Length Packet for the IN status phase
48495 + * of a 2 stage control transfer.
48496 + */
48497 +static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd)
48498 +{
48499 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48500 + if (pcd->ep0state == EP0_STALL) {
48501 + return;
48502 + }
48503 +
48504 + pcd->ep0state = EP0_IN_STATUS_PHASE;
48505 +
48506 + /* Prepare for more SETUP Packets */
48507 + DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
48508 + if ((GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a)
48509 + && (pcd->core_if->dma_desc_enable)
48510 + && (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len)) {
48511 + DWC_DEBUGPL(DBG_PCDV,
48512 + "Data terminated wait next packet in out_desc_addr\n");
48513 + pcd->backup_buf = phys_to_virt(ep0->dwc_ep.dma_addr);
48514 + pcd->data_terminated = 1;
48515 + }
48516 + ep0->dwc_ep.xfer_len = 0;
48517 + ep0->dwc_ep.xfer_count = 0;
48518 + ep0->dwc_ep.is_in = 1;
48519 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
48520 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48521 +
48522 + /* Prepare for more SETUP Packets */
48523 + //ep0_out_start(GET_CORE_IF(pcd), pcd);
48524 +}
48525 +
48526 +/**
48527 + * This function starts the Zero-Length Packet for the OUT status phase
48528 + * of a 2 stage control transfer.
48529 + */
48530 +static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd)
48531 +{
48532 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48533 + if (pcd->ep0state == EP0_STALL) {
48534 + DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
48535 + return;
48536 + }
48537 + pcd->ep0state = EP0_OUT_STATUS_PHASE;
48538 +
48539 + DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
48540 + ep0->dwc_ep.xfer_len = 0;
48541 + ep0->dwc_ep.xfer_count = 0;
48542 + ep0->dwc_ep.is_in = 0;
48543 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
48544 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48545 +
48546 + /* Prepare for more SETUP Packets */
48547 + if (GET_CORE_IF(pcd)->dma_enable == 0) {
48548 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48549 + }
48550 +}
48551 +
48552 +/**
48553 + * Clear the EP halt (STALL) and if pending requests start the
48554 + * transfer.
48555 + */
48556 +static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
48557 +{
48558 + if (ep->dwc_ep.stall_clear_flag == 0)
48559 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
48560 +
48561 + /* Reactive the EP */
48562 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
48563 + if (ep->stopped) {
48564 + ep->stopped = 0;
48565 + /* If there is a request in the EP queue start it */
48566 +
48567 + /** @todo FIXME: this causes an EP mismatch in DMA mode.
48568 + * epmismatch not yet implemented. */
48569 +
48570 + /*
48571 + * Above fixme is solved by implmenting a tasklet to call the
48572 + * start_next_request(), outside of interrupt context at some
48573 + * time after the current time, after a clear-halt setup packet.
48574 + * Still need to implement ep mismatch in the future if a gadget
48575 + * ever uses more than one endpoint at once
48576 + */
48577 + ep->queue_sof = 1;
48578 + DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet);
48579 + }
48580 + /* Start Control Status Phase */
48581 + do_setup_in_status_phase(pcd);
48582 +}
48583 +
48584 +/**
48585 + * This function is called when the SET_FEATURE TEST_MODE Setup packet
48586 + * is sent from the host. The Device Control register is written with
48587 + * the Test Mode bits set to the specified Test Mode. This is done as
48588 + * a tasklet so that the "Status" phase of the control transfer
48589 + * completes before transmitting the TEST packets.
48590 + *
48591 + * @todo This has not been tested since the tasklet struct was put
48592 + * into the PCD struct!
48593 + *
48594 + */
48595 +void do_test_mode(void *data)
48596 +{
48597 + dctl_data_t dctl;
48598 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
48599 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48600 + int test_mode = pcd->test_mode;
48601 +
48602 +// DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
48603 +
48604 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
48605 + switch (test_mode) {
48606 + case 1: // TEST_J
48607 + dctl.b.tstctl = 1;
48608 + break;
48609 +
48610 + case 2: // TEST_K
48611 + dctl.b.tstctl = 2;
48612 + break;
48613 +
48614 + case 3: // TEST_SE0_NAK
48615 + dctl.b.tstctl = 3;
48616 + break;
48617 +
48618 + case 4: // TEST_PACKET
48619 + dctl.b.tstctl = 4;
48620 + break;
48621 +
48622 + case 5: // TEST_FORCE_ENABLE
48623 + dctl.b.tstctl = 5;
48624 + break;
48625 + }
48626 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
48627 +}
48628 +
48629 +/**
48630 + * This function process the GET_STATUS Setup Commands.
48631 + */
48632 +static inline void do_get_status(dwc_otg_pcd_t * pcd)
48633 +{
48634 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48635 + dwc_otg_pcd_ep_t *ep;
48636 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48637 + uint16_t *status = pcd->status_buf;
48638 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48639 +
48640 +#ifdef DEBUG_EP0
48641 + DWC_DEBUGPL(DBG_PCD,
48642 + "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
48643 + ctrl.bmRequestType, ctrl.bRequest,
48644 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48645 + UGETW(ctrl.wLength));
48646 +#endif
48647 +
48648 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48649 + case UT_DEVICE:
48650 + if(UGETW(ctrl.wIndex) == 0xF000) { /* OTG Status selector */
48651 + DWC_PRINTF("wIndex - %d\n", UGETW(ctrl.wIndex));
48652 + DWC_PRINTF("OTG VERSION - %d\n", core_if->otg_ver);
48653 + DWC_PRINTF("OTG CAP - %d, %d\n",
48654 + core_if->core_params->otg_cap,
48655 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
48656 + if (core_if->otg_ver == 1
48657 + && core_if->core_params->otg_cap ==
48658 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48659 + uint8_t *otgsts = (uint8_t*)pcd->status_buf;
48660 + *otgsts = (core_if->otg_sts & 0x1);
48661 + pcd->ep0_pending = 1;
48662 + ep0->dwc_ep.start_xfer_buff =
48663 + (uint8_t *) otgsts;
48664 + ep0->dwc_ep.xfer_buff = (uint8_t *) otgsts;
48665 + ep0->dwc_ep.dma_addr =
48666 + pcd->status_buf_dma_handle;
48667 + ep0->dwc_ep.xfer_len = 1;
48668 + ep0->dwc_ep.xfer_count = 0;
48669 + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
48670 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
48671 + &ep0->dwc_ep);
48672 + return;
48673 + } else {
48674 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48675 + return;
48676 + }
48677 + break;
48678 + } else {
48679 + *status = 0x1; /* Self powered */
48680 + *status |= pcd->remote_wakeup_enable << 1;
48681 + break;
48682 + }
48683 + case UT_INTERFACE:
48684 + *status = 0;
48685 + break;
48686 +
48687 + case UT_ENDPOINT:
48688 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
48689 + if (ep == 0 || UGETW(ctrl.wLength) > 2) {
48690 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48691 + return;
48692 + }
48693 + /** @todo check for EP stall */
48694 + *status = ep->stopped;
48695 + break;
48696 + }
48697 + pcd->ep0_pending = 1;
48698 + ep0->dwc_ep.start_xfer_buff = (uint8_t *) status;
48699 + ep0->dwc_ep.xfer_buff = (uint8_t *) status;
48700 + ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle;
48701 + ep0->dwc_ep.xfer_len = 2;
48702 + ep0->dwc_ep.xfer_count = 0;
48703 + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
48704 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48705 +}
48706 +
48707 +/**
48708 + * This function process the SET_FEATURE Setup Commands.
48709 + */
48710 +static inline void do_set_feature(dwc_otg_pcd_t * pcd)
48711 +{
48712 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48713 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
48714 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48715 + dwc_otg_pcd_ep_t *ep = 0;
48716 + int32_t otg_cap_param = core_if->core_params->otg_cap;
48717 + gotgctl_data_t gotgctl = {.d32 = 0 };
48718 +
48719 + DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
48720 + ctrl.bmRequestType, ctrl.bRequest,
48721 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48722 + UGETW(ctrl.wLength));
48723 + DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param);
48724 +
48725 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48726 + case UT_DEVICE:
48727 + switch (UGETW(ctrl.wValue)) {
48728 + case UF_DEVICE_REMOTE_WAKEUP:
48729 + pcd->remote_wakeup_enable = 1;
48730 + break;
48731 +
48732 + case UF_TEST_MODE:
48733 + /* Setup the Test Mode tasklet to do the Test
48734 + * Packet generation after the SETUP Status
48735 + * phase has completed. */
48736 +
48737 + /** @todo This has not been tested since the
48738 + * tasklet struct was put into the PCD
48739 + * struct! */
48740 + pcd->test_mode = UGETW(ctrl.wIndex) >> 8;
48741 + DWC_TASK_SCHEDULE(pcd->test_mode_tasklet);
48742 + break;
48743 +
48744 + case UF_DEVICE_B_HNP_ENABLE:
48745 + DWC_DEBUGPL(DBG_PCDV,
48746 + "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
48747 +
48748 + /* dev may initiate HNP */
48749 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48750 + pcd->b_hnp_enable = 1;
48751 + dwc_otg_pcd_update_otg(pcd, 0);
48752 + DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
48753 + /**@todo Is the gotgctl.devhnpen cleared
48754 + * by a USB Reset? */
48755 + gotgctl.b.devhnpen = 1;
48756 + gotgctl.b.hnpreq = 1;
48757 + DWC_WRITE_REG32(&global_regs->gotgctl,
48758 + gotgctl.d32);
48759 + } else {
48760 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48761 + return;
48762 + }
48763 + break;
48764 +
48765 + case UF_DEVICE_A_HNP_SUPPORT:
48766 + /* RH port supports HNP */
48767 + DWC_DEBUGPL(DBG_PCDV,
48768 + "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
48769 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48770 + pcd->a_hnp_support = 1;
48771 + dwc_otg_pcd_update_otg(pcd, 0);
48772 + } else {
48773 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48774 + return;
48775 + }
48776 + break;
48777 +
48778 + case UF_DEVICE_A_ALT_HNP_SUPPORT:
48779 + /* other RH port does */
48780 + DWC_DEBUGPL(DBG_PCDV,
48781 + "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
48782 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48783 + pcd->a_alt_hnp_support = 1;
48784 + dwc_otg_pcd_update_otg(pcd, 0);
48785 + } else {
48786 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48787 + return;
48788 + }
48789 + break;
48790 +
48791 + default:
48792 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48793 + return;
48794 +
48795 + }
48796 + do_setup_in_status_phase(pcd);
48797 + break;
48798 +
48799 + case UT_INTERFACE:
48800 + do_gadget_setup(pcd, &ctrl);
48801 + break;
48802 +
48803 + case UT_ENDPOINT:
48804 + if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) {
48805 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
48806 + if (ep == 0) {
48807 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48808 + return;
48809 + }
48810 + ep->stopped = 1;
48811 + dwc_otg_ep_set_stall(core_if, &ep->dwc_ep);
48812 + }
48813 + do_setup_in_status_phase(pcd);
48814 + break;
48815 + }
48816 +}
48817 +
48818 +/**
48819 + * This function process the CLEAR_FEATURE Setup Commands.
48820 + */
48821 +static inline void do_clear_feature(dwc_otg_pcd_t * pcd)
48822 +{
48823 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48824 + dwc_otg_pcd_ep_t *ep = 0;
48825 +
48826 + DWC_DEBUGPL(DBG_PCD,
48827 + "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
48828 + ctrl.bmRequestType, ctrl.bRequest,
48829 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48830 + UGETW(ctrl.wLength));
48831 +
48832 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48833 + case UT_DEVICE:
48834 + switch (UGETW(ctrl.wValue)) {
48835 + case UF_DEVICE_REMOTE_WAKEUP:
48836 + pcd->remote_wakeup_enable = 0;
48837 + break;
48838 +
48839 + case UF_TEST_MODE:
48840 + /** @todo Add CLEAR_FEATURE for TEST modes. */
48841 + break;
48842 +
48843 + default:
48844 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48845 + return;
48846 + }
48847 + do_setup_in_status_phase(pcd);
48848 + break;
48849 +
48850 + case UT_ENDPOINT:
48851 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
48852 + if (ep == 0) {
48853 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48854 + return;
48855 + }
48856 +
48857 + pcd_clear_halt(pcd, ep);
48858 +
48859 + break;
48860 + }
48861 +}
48862 +
48863 +/**
48864 + * This function process the SET_ADDRESS Setup Commands.
48865 + */
48866 +static inline void do_set_address(dwc_otg_pcd_t * pcd)
48867 +{
48868 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
48869 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48870 +
48871 + if (ctrl.bmRequestType == UT_DEVICE) {
48872 + dcfg_data_t dcfg = {.d32 = 0 };
48873 +
48874 +#ifdef DEBUG_EP0
48875 +// DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
48876 +#endif
48877 + dcfg.b.devaddr = UGETW(ctrl.wValue);
48878 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32);
48879 + do_setup_in_status_phase(pcd);
48880 + }
48881 +}
48882 +
48883 +/**
48884 + * This function processes SETUP commands. In Linux, the USB Command
48885 + * processing is done in two places - the first being the PCD and the
48886 + * second in the Gadget Driver (for example, the File-Backed Storage
48887 + * Gadget Driver).
48888 + *
48889 + * <table>
48890 + * <tr><td>Command </td><td>Driver </td><td>Description</td></tr>
48891 + *
48892 + * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as
48893 + * defined in chapter 9 of the USB 2.0 Specification chapter 9
48894 + * </td></tr>
48895 + *
48896 + * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint
48897 + * requests are the ENDPOINT_HALT feature is procesed, all others the
48898 + * interface requests are ignored.</td></tr>
48899 + *
48900 + * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint
48901 + * requests are processed by the PCD. Interface requests are passed
48902 + * to the Gadget Driver.</td></tr>
48903 + *
48904 + * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg,
48905 + * with device address received </td></tr>
48906 + *
48907 + * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the
48908 + * requested descriptor</td></tr>
48909 + *
48910 + * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional -
48911 + * not implemented by any of the existing Gadget Drivers.</td></tr>
48912 + *
48913 + * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable
48914 + * all EPs and enable EPs for new configuration.</td></tr>
48915 + *
48916 + * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return
48917 + * the current configuration</td></tr>
48918 + *
48919 + * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all
48920 + * EPs and enable EPs for new configuration.</td></tr>
48921 + *
48922 + * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the
48923 + * current interface.</td></tr>
48924 + *
48925 + * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug
48926 + * message.</td></tr>
48927 + * </table>
48928 + *
48929 + * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are
48930 + * processed by pcd_setup. Calling the Function Driver's setup function from
48931 + * pcd_setup processes the gadget SETUP commands.
48932 + */
48933 +static inline void pcd_setup(dwc_otg_pcd_t * pcd)
48934 +{
48935 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48936 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
48937 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48938 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48939 +
48940 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
48941 +
48942 +#ifdef DWC_UTE_CFI
48943 + int retval = 0;
48944 + struct cfi_usb_ctrlrequest cfi_req;
48945 +#endif
48946 +
48947 + doeptsize0.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doeptsiz);
48948 +
48949 + /** In BDMA more then 1 setup packet is not supported till 3.00a */
48950 + if (core_if->dma_enable && core_if->dma_desc_enable == 0
48951 + && (doeptsize0.b.supcnt < 2)
48952 + && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
48953 + DWC_ERROR
48954 + ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n");
48955 + }
48956 + if ((core_if->snpsid >= OTG_CORE_REV_3_00a)
48957 + && (core_if->dma_enable == 1) && (core_if->dma_desc_enable == 0)) {
48958 + ctrl =
48959 + (pcd->setup_pkt +
48960 + (3 - doeptsize0.b.supcnt - 1 +
48961 + ep0->dwc_ep.stp_rollover))->req;
48962 + }
48963 +#ifdef DEBUG_EP0
48964 + DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
48965 + ctrl.bmRequestType, ctrl.bRequest,
48966 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48967 + UGETW(ctrl.wLength));
48968 +#endif
48969 +
48970 + /* Clean up the request queue */
48971 + dwc_otg_request_nuke(ep0);
48972 + ep0->stopped = 0;
48973 +
48974 + if (ctrl.bmRequestType & UE_DIR_IN) {
48975 + ep0->dwc_ep.is_in = 1;
48976 + pcd->ep0state = EP0_IN_DATA_PHASE;
48977 + } else {
48978 + ep0->dwc_ep.is_in = 0;
48979 + pcd->ep0state = EP0_OUT_DATA_PHASE;
48980 + }
48981 +
48982 + if (UGETW(ctrl.wLength) == 0) {
48983 + ep0->dwc_ep.is_in = 1;
48984 + pcd->ep0state = EP0_IN_STATUS_PHASE;
48985 + }
48986 +
48987 + if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) {
48988 +
48989 +#ifdef DWC_UTE_CFI
48990 + DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t));
48991 +
48992 + //printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n",
48993 + ctrl.bRequestType, ctrl.bRequest);
48994 + if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) {
48995 + if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) {
48996 + retval = cfi_setup(pcd, &cfi_req);
48997 + if (retval < 0) {
48998 + ep0_do_stall(pcd, retval);
48999 + pcd->ep0_pending = 0;
49000 + return;
49001 + }
49002 +
49003 + /* if need gadget setup then call it and check the retval */
49004 + if (pcd->cfi->need_gadget_att) {
49005 + retval =
49006 + cfi_gadget_setup(pcd,
49007 + &pcd->
49008 + cfi->ctrl_req);
49009 + if (retval < 0) {
49010 + pcd->ep0_pending = 0;
49011 + return;
49012 + }
49013 + }
49014 +
49015 + if (pcd->cfi->need_status_in_complete) {
49016 + do_setup_in_status_phase(pcd);
49017 + }
49018 + return;
49019 + }
49020 + }
49021 +#endif
49022 +
49023 + /* handle non-standard (class/vendor) requests in the gadget driver */
49024 + do_gadget_setup(pcd, &ctrl);
49025 + return;
49026 + }
49027 +
49028 + /** @todo NGS: Handle bad setup packet? */
49029 +
49030 +///////////////////////////////////////////
49031 +//// --- Standard Request handling --- ////
49032 +
49033 + switch (ctrl.bRequest) {
49034 + case UR_GET_STATUS:
49035 + do_get_status(pcd);
49036 + break;
49037 +
49038 + case UR_CLEAR_FEATURE:
49039 + do_clear_feature(pcd);
49040 + break;
49041 +
49042 + case UR_SET_FEATURE:
49043 + do_set_feature(pcd);
49044 + break;
49045 +
49046 + case UR_SET_ADDRESS:
49047 + do_set_address(pcd);
49048 + break;
49049 +
49050 + case UR_SET_INTERFACE:
49051 + case UR_SET_CONFIG:
49052 +// _pcd->request_config = 1; /* Configuration changed */
49053 + do_gadget_setup(pcd, &ctrl);
49054 + break;
49055 +
49056 + case UR_SYNCH_FRAME:
49057 + do_gadget_setup(pcd, &ctrl);
49058 + break;
49059 +
49060 + default:
49061 + /* Call the Gadget Driver's setup functions */
49062 + do_gadget_setup(pcd, &ctrl);
49063 + break;
49064 + }
49065 +}
49066 +
49067 +/**
49068 + * This function completes the ep0 control transfer.
49069 + */
49070 +static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep)
49071 +{
49072 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
49073 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49074 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
49075 + dev_if->in_ep_regs[ep->dwc_ep.num];
49076 +#ifdef DEBUG_EP0
49077 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
49078 + dev_if->out_ep_regs[ep->dwc_ep.num];
49079 +#endif
49080 + deptsiz0_data_t deptsiz;
49081 + dev_dma_desc_sts_t desc_sts;
49082 + dwc_otg_pcd_request_t *req;
49083 + int is_last = 0;
49084 + dwc_otg_pcd_t *pcd = ep->pcd;
49085 +
49086 +#ifdef DWC_UTE_CFI
49087 + struct cfi_usb_ctrlrequest *ctrlreq;
49088 + int retval = -DWC_E_NOT_SUPPORTED;
49089 +#endif
49090 +
49091 + desc_sts.b.bytes = 0;
49092 +
49093 + if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49094 + if (ep->dwc_ep.is_in) {
49095 +#ifdef DEBUG_EP0
49096 + DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
49097 +#endif
49098 + do_setup_out_status_phase(pcd);
49099 + } else {
49100 +#ifdef DEBUG_EP0
49101 + DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
49102 +#endif
49103 +
49104 +#ifdef DWC_UTE_CFI
49105 + ctrlreq = &pcd->cfi->ctrl_req;
49106 +
49107 + if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) {
49108 + if (ctrlreq->bRequest > 0xB0
49109 + && ctrlreq->bRequest < 0xBF) {
49110 +
49111 + /* Return if the PCD failed to handle the request */
49112 + if ((retval =
49113 + pcd->cfi->ops.
49114 + ctrl_write_complete(pcd->cfi,
49115 + pcd)) < 0) {
49116 + CFI_INFO
49117 + ("ERROR setting a new value in the PCD(%d)\n",
49118 + retval);
49119 + ep0_do_stall(pcd, retval);
49120 + pcd->ep0_pending = 0;
49121 + return 0;
49122 + }
49123 +
49124 + /* If the gadget needs to be notified on the request */
49125 + if (pcd->cfi->need_gadget_att == 1) {
49126 + //retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req);
49127 + retval =
49128 + cfi_gadget_setup(pcd,
49129 + &pcd->cfi->
49130 + ctrl_req);
49131 +
49132 + /* Return from the function if the gadget failed to process
49133 + * the request properly - this should never happen !!!
49134 + */
49135 + if (retval < 0) {
49136 + CFI_INFO
49137 + ("ERROR setting a new value in the gadget(%d)\n",
49138 + retval);
49139 + pcd->ep0_pending = 0;
49140 + return 0;
49141 + }
49142 + }
49143 +
49144 + CFI_INFO("%s: RETVAL=%d\n", __func__,
49145 + retval);
49146 + /* If we hit here then the PCD and the gadget has properly
49147 + * handled the request - so send the ZLP IN to the host.
49148 + */
49149 + /* @todo: MAS - decide whether we need to start the setup
49150 + * stage based on the need_setup value of the cfi object
49151 + */
49152 + do_setup_in_status_phase(pcd);
49153 + pcd->ep0_pending = 0;
49154 + return 1;
49155 + }
49156 + }
49157 +#endif
49158 +
49159 + do_setup_in_status_phase(pcd);
49160 + }
49161 + pcd->ep0_pending = 0;
49162 + return 1;
49163 + }
49164 +
49165 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49166 + return 0;
49167 + }
49168 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
49169 +
49170 + if (pcd->ep0state == EP0_OUT_STATUS_PHASE
49171 + || pcd->ep0state == EP0_IN_STATUS_PHASE) {
49172 + is_last = 1;
49173 + } else if (ep->dwc_ep.is_in) {
49174 + deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
49175 + if (core_if->dma_desc_enable != 0)
49176 + desc_sts = dev_if->in_desc_addr->status;
49177 +#ifdef DEBUG_EP0
49178 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xfersize=%d pktcnt=%d\n",
49179 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
49180 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49181 +#endif
49182 +
49183 + if (((core_if->dma_desc_enable == 0)
49184 + && (deptsiz.b.xfersize == 0))
49185 + || ((core_if->dma_desc_enable != 0)
49186 + && (desc_sts.b.bytes == 0))) {
49187 + req->actual = ep->dwc_ep.xfer_count;
49188 + /* Is a Zero Len Packet needed? */
49189 + if (req->sent_zlp) {
49190 +#ifdef DEBUG_EP0
49191 + DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
49192 +#endif
49193 + req->sent_zlp = 0;
49194 + }
49195 + do_setup_out_status_phase(pcd);
49196 + }
49197 + } else {
49198 + /* ep0-OUT */
49199 +#ifdef DEBUG_EP0
49200 + deptsiz.d32 = DWC_READ_REG32(&out_ep_regs->doeptsiz);
49201 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n",
49202 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
49203 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49204 +#endif
49205 + req->actual = ep->dwc_ep.xfer_count;
49206 +
49207 + /* Is a Zero Len Packet needed? */
49208 + if (req->sent_zlp) {
49209 +#ifdef DEBUG_EP0
49210 + DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
49211 +#endif
49212 + req->sent_zlp = 0;
49213 + }
49214 + /* For older cores do setup in status phase in Slave/BDMA modes,
49215 + * starting from 3.00 do that only in slave, and for DMA modes
49216 + * just re-enable ep 0 OUT here*/
49217 + if (core_if->dma_enable == 0
49218 + || (core_if->dma_desc_enable == 0
49219 + && core_if->snpsid <= OTG_CORE_REV_2_94a)) {
49220 + do_setup_in_status_phase(pcd);
49221 + } else if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
49222 + DWC_DEBUGPL(DBG_PCDV,
49223 + "Enable out ep before in status phase\n");
49224 + ep0_out_start(core_if, pcd);
49225 + }
49226 + }
49227 +
49228 + /* Complete the request */
49229 + if (is_last) {
49230 + dwc_otg_request_done(ep, req, 0);
49231 + ep->dwc_ep.start_xfer_buff = 0;
49232 + ep->dwc_ep.xfer_buff = 0;
49233 + ep->dwc_ep.xfer_len = 0;
49234 + return 1;
49235 + }
49236 + return 0;
49237 +}
49238 +
49239 +#ifdef DWC_UTE_CFI
49240 +/**
49241 + * This function calculates traverses all the CFI DMA descriptors and
49242 + * and accumulates the bytes that are left to be transfered.
49243 + *
49244 + * @return The total bytes left to transfered, or a negative value as failure
49245 + */
49246 +static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep)
49247 +{
49248 + int32_t ret = 0;
49249 + int i;
49250 + struct dwc_otg_dma_desc *ddesc = NULL;
49251 + struct cfi_ep *cfiep;
49252 +
49253 + /* See if the pcd_ep has its respective cfi_ep mapped */
49254 + cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep);
49255 + if (!cfiep) {
49256 + CFI_INFO("%s: Failed to find ep\n", __func__);
49257 + return -1;
49258 + }
49259 +
49260 + ddesc = ep->dwc_ep.descs;
49261 +
49262 + for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) {
49263 +
49264 +#if defined(PRINT_CFI_DMA_DESCS)
49265 + print_desc(ddesc, ep->ep.name, i);
49266 +#endif
49267 + ret += ddesc->status.b.bytes;
49268 + ddesc++;
49269 + }
49270 +
49271 + if (ret)
49272 + CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__,
49273 + ret);
49274 +
49275 + return ret;
49276 +}
49277 +#endif
49278 +
49279 +/**
49280 + * This function completes the request for the EP. If there are
49281 + * additional requests for the EP in the queue they will be started.
49282 + */
49283 +static void complete_ep(dwc_otg_pcd_ep_t * ep)
49284 +{
49285 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
49286 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49287 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
49288 + dev_if->in_ep_regs[ep->dwc_ep.num];
49289 + deptsiz_data_t deptsiz;
49290 + dev_dma_desc_sts_t desc_sts;
49291 + dwc_otg_pcd_request_t *req = 0;
49292 + dwc_otg_dev_dma_desc_t *dma_desc;
49293 + uint32_t byte_count = 0;
49294 + int is_last = 0;
49295 + int i;
49296 +
49297 + DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num,
49298 + (ep->dwc_ep.is_in ? "IN" : "OUT"));
49299 +
49300 + /* Get any pending requests */
49301 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49302 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
49303 + if (!req) {
49304 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
49305 + return;
49306 + }
49307 + } else {
49308 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
49309 + return;
49310 + }
49311 +
49312 + DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending);
49313 +
49314 + if (ep->dwc_ep.is_in) {
49315 + deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
49316 +
49317 + if (core_if->dma_enable) {
49318 + if (core_if->dma_desc_enable == 0) {
49319 + if (deptsiz.b.xfersize == 0
49320 + && deptsiz.b.pktcnt == 0) {
49321 + byte_count =
49322 + ep->dwc_ep.xfer_len -
49323 + ep->dwc_ep.xfer_count;
49324 +
49325 + ep->dwc_ep.xfer_buff += byte_count;
49326 + ep->dwc_ep.dma_addr += byte_count;
49327 + ep->dwc_ep.xfer_count += byte_count;
49328 +
49329 + DWC_DEBUGPL(DBG_PCDV,
49330 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
49331 + ep->dwc_ep.num,
49332 + (ep->dwc_ep.
49333 + is_in ? "IN" : "OUT"),
49334 + ep->dwc_ep.xfer_len,
49335 + deptsiz.b.xfersize,
49336 + deptsiz.b.pktcnt);
49337 +
49338 + if (ep->dwc_ep.xfer_len <
49339 + ep->dwc_ep.total_len) {
49340 + dwc_otg_ep_start_transfer
49341 + (core_if, &ep->dwc_ep);
49342 + } else if (ep->dwc_ep.sent_zlp) {
49343 + /*
49344 + * This fragment of code should initiate 0
49345 + * length transfer in case if it is queued
49346 + * a transfer with size divisible to EPs max
49347 + * packet size and with usb_request zero field
49348 + * is set, which means that after data is transfered,
49349 + * it is also should be transfered
49350 + * a 0 length packet at the end. For Slave and
49351 + * Buffer DMA modes in this case SW has
49352 + * to initiate 2 transfers one with transfer size,
49353 + * and the second with 0 size. For Descriptor
49354 + * DMA mode SW is able to initiate a transfer,
49355 + * which will handle all the packets including
49356 + * the last 0 length.
49357 + */
49358 + ep->dwc_ep.sent_zlp = 0;
49359 + dwc_otg_ep_start_zl_transfer
49360 + (core_if, &ep->dwc_ep);
49361 + } else {
49362 + is_last = 1;
49363 + }
49364 + } else {
49365 + if (ep->dwc_ep.type ==
49366 + DWC_OTG_EP_TYPE_ISOC) {
49367 + req->actual = 0;
49368 + dwc_otg_request_done(ep, req, 0);
49369 +
49370 + ep->dwc_ep.start_xfer_buff = 0;
49371 + ep->dwc_ep.xfer_buff = 0;
49372 + ep->dwc_ep.xfer_len = 0;
49373 +
49374 + /* If there is a request in the queue start it. */
49375 + start_next_request(ep);
49376 + } else
49377 + DWC_WARN
49378 + ("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n",
49379 + ep->dwc_ep.num,
49380 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
49381 + deptsiz.b.xfersize,
49382 + deptsiz.b.pktcnt);
49383 + }
49384 + } else {
49385 + dma_desc = ep->dwc_ep.desc_addr;
49386 + byte_count = 0;
49387 + ep->dwc_ep.sent_zlp = 0;
49388 +
49389 +#ifdef DWC_UTE_CFI
49390 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
49391 + ep->dwc_ep.buff_mode);
49392 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49393 + int residue;
49394 +
49395 + residue = cfi_calc_desc_residue(ep);
49396 + if (residue < 0)
49397 + return;
49398 +
49399 + byte_count = residue;
49400 + } else {
49401 +#endif
49402 + for (i = 0; i < ep->dwc_ep.desc_cnt;
49403 + ++i) {
49404 + desc_sts = dma_desc->status;
49405 + byte_count += desc_sts.b.bytes;
49406 + dma_desc++;
49407 + }
49408 +#ifdef DWC_UTE_CFI
49409 + }
49410 +#endif
49411 + if (byte_count == 0) {
49412 + ep->dwc_ep.xfer_count =
49413 + ep->dwc_ep.total_len;
49414 + is_last = 1;
49415 + } else {
49416 + DWC_WARN("Incomplete transfer\n");
49417 + }
49418 + }
49419 + } else {
49420 + if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) {
49421 + DWC_DEBUGPL(DBG_PCDV,
49422 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
49423 + ep->dwc_ep.num,
49424 + ep->dwc_ep.is_in ? "IN" : "OUT",
49425 + ep->dwc_ep.xfer_len,
49426 + deptsiz.b.xfersize,
49427 + deptsiz.b.pktcnt);
49428 +
49429 + /* Check if the whole transfer was completed,
49430 + * if no, setup transfer for next portion of data
49431 + */
49432 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49433 + dwc_otg_ep_start_transfer(core_if,
49434 + &ep->dwc_ep);
49435 + } else if (ep->dwc_ep.sent_zlp) {
49436 + /*
49437 + * This fragment of code should initiate 0
49438 + * length trasfer in case if it is queued
49439 + * a trasfer with size divisible to EPs max
49440 + * packet size and with usb_request zero field
49441 + * is set, which means that after data is transfered,
49442 + * it is also should be transfered
49443 + * a 0 length packet at the end. For Slave and
49444 + * Buffer DMA modes in this case SW has
49445 + * to initiate 2 transfers one with transfer size,
49446 + * and the second with 0 size. For Desriptor
49447 + * DMA mode SW is able to initiate a transfer,
49448 + * which will handle all the packets including
49449 + * the last 0 legth.
49450 + */
49451 + ep->dwc_ep.sent_zlp = 0;
49452 + dwc_otg_ep_start_zl_transfer(core_if,
49453 + &ep->dwc_ep);
49454 + } else {
49455 + is_last = 1;
49456 + }
49457 + } else {
49458 + DWC_WARN
49459 + ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n",
49460 + ep->dwc_ep.num,
49461 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
49462 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49463 + }
49464 + }
49465 + } else {
49466 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
49467 + dev_if->out_ep_regs[ep->dwc_ep.num];
49468 + desc_sts.d32 = 0;
49469 + if (core_if->dma_enable) {
49470 + if (core_if->dma_desc_enable) {
49471 + dma_desc = ep->dwc_ep.desc_addr;
49472 + byte_count = 0;
49473 + ep->dwc_ep.sent_zlp = 0;
49474 +
49475 +#ifdef DWC_UTE_CFI
49476 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
49477 + ep->dwc_ep.buff_mode);
49478 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49479 + int residue;
49480 + residue = cfi_calc_desc_residue(ep);
49481 + if (residue < 0)
49482 + return;
49483 + byte_count = residue;
49484 + } else {
49485 +#endif
49486 +
49487 + for (i = 0; i < ep->dwc_ep.desc_cnt;
49488 + ++i) {
49489 + desc_sts = dma_desc->status;
49490 + byte_count += desc_sts.b.bytes;
49491 + dma_desc++;
49492 + }
49493 +
49494 +#ifdef DWC_UTE_CFI
49495 + }
49496 +#endif
49497 + /* Checking for interrupt Out transfers with not
49498 + * dword aligned mps sizes
49499 + */
49500 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_INTR &&
49501 + (ep->dwc_ep.maxpacket%4)) {
49502 + ep->dwc_ep.xfer_count =
49503 + ep->dwc_ep.total_len - byte_count;
49504 + if ((ep->dwc_ep.xfer_len %
49505 + ep->dwc_ep.maxpacket)
49506 + && (ep->dwc_ep.xfer_len /
49507 + ep->dwc_ep.maxpacket <
49508 + MAX_DMA_DESC_CNT))
49509 + ep->dwc_ep.xfer_len -=
49510 + (ep->dwc_ep.desc_cnt -
49511 + 1) * ep->dwc_ep.maxpacket +
49512 + ep->dwc_ep.xfer_len %
49513 + ep->dwc_ep.maxpacket;
49514 + else
49515 + ep->dwc_ep.xfer_len -=
49516 + ep->dwc_ep.desc_cnt *
49517 + ep->dwc_ep.maxpacket;
49518 + if (ep->dwc_ep.xfer_len > 0) {
49519 + dwc_otg_ep_start_transfer
49520 + (core_if, &ep->dwc_ep);
49521 + } else {
49522 + is_last = 1;
49523 + }
49524 + } else {
49525 + ep->dwc_ep.xfer_count =
49526 + ep->dwc_ep.total_len - byte_count +
49527 + ((4 -
49528 + (ep->dwc_ep.
49529 + total_len & 0x3)) & 0x3);
49530 + is_last = 1;
49531 + }
49532 + } else {
49533 + deptsiz.d32 = 0;
49534 + deptsiz.d32 =
49535 + DWC_READ_REG32(&out_ep_regs->doeptsiz);
49536 +
49537 + byte_count = (ep->dwc_ep.xfer_len -
49538 + ep->dwc_ep.xfer_count -
49539 + deptsiz.b.xfersize);
49540 + ep->dwc_ep.xfer_buff += byte_count;
49541 + ep->dwc_ep.dma_addr += byte_count;
49542 + ep->dwc_ep.xfer_count += byte_count;
49543 +
49544 + /* Check if the whole transfer was completed,
49545 + * if no, setup transfer for next portion of data
49546 + */
49547 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49548 + dwc_otg_ep_start_transfer(core_if,
49549 + &ep->dwc_ep);
49550 + } else if (ep->dwc_ep.sent_zlp) {
49551 + /*
49552 + * This fragment of code should initiate 0
49553 + * length trasfer in case if it is queued
49554 + * a trasfer with size divisible to EPs max
49555 + * packet size and with usb_request zero field
49556 + * is set, which means that after data is transfered,
49557 + * it is also should be transfered
49558 + * a 0 length packet at the end. For Slave and
49559 + * Buffer DMA modes in this case SW has
49560 + * to initiate 2 transfers one with transfer size,
49561 + * and the second with 0 size. For Desriptor
49562 + * DMA mode SW is able to initiate a transfer,
49563 + * which will handle all the packets including
49564 + * the last 0 legth.
49565 + */
49566 + ep->dwc_ep.sent_zlp = 0;
49567 + dwc_otg_ep_start_zl_transfer(core_if,
49568 + &ep->dwc_ep);
49569 + } else {
49570 + is_last = 1;
49571 + }
49572 + }
49573 + } else {
49574 + /* Check if the whole transfer was completed,
49575 + * if no, setup transfer for next portion of data
49576 + */
49577 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49578 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
49579 + } else if (ep->dwc_ep.sent_zlp) {
49580 + /*
49581 + * This fragment of code should initiate 0
49582 + * length transfer in case if it is queued
49583 + * a transfer with size divisible to EPs max
49584 + * packet size and with usb_request zero field
49585 + * is set, which means that after data is transfered,
49586 + * it is also should be transfered
49587 + * a 0 length packet at the end. For Slave and
49588 + * Buffer DMA modes in this case SW has
49589 + * to initiate 2 transfers one with transfer size,
49590 + * and the second with 0 size. For Descriptor
49591 + * DMA mode SW is able to initiate a transfer,
49592 + * which will handle all the packets including
49593 + * the last 0 length.
49594 + */
49595 + ep->dwc_ep.sent_zlp = 0;
49596 + dwc_otg_ep_start_zl_transfer(core_if,
49597 + &ep->dwc_ep);
49598 + } else {
49599 + is_last = 1;
49600 + }
49601 + }
49602 +
49603 + DWC_DEBUGPL(DBG_PCDV,
49604 + "addr %p, %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n",
49605 + &out_ep_regs->doeptsiz, ep->dwc_ep.num,
49606 + ep->dwc_ep.is_in ? "IN" : "OUT",
49607 + ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count,
49608 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49609 + }
49610 +
49611 + /* Complete the request */
49612 + if (is_last) {
49613 +#ifdef DWC_UTE_CFI
49614 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49615 + req->actual = ep->dwc_ep.cfi_req_len - byte_count;
49616 + } else {
49617 +#endif
49618 + req->actual = ep->dwc_ep.xfer_count;
49619 +#ifdef DWC_UTE_CFI
49620 + }
49621 +#endif
49622 + if (req->dw_align_buf) {
49623 + if (!ep->dwc_ep.is_in) {
49624 + dwc_memcpy(req->buf, req->dw_align_buf, req->length);
49625 + }
49626 + DWC_DMA_FREE(req->length, req->dw_align_buf,
49627 + req->dw_align_buf_dma);
49628 + }
49629 +
49630 + dwc_otg_request_done(ep, req, 0);
49631 +
49632 + ep->dwc_ep.start_xfer_buff = 0;
49633 + ep->dwc_ep.xfer_buff = 0;
49634 + ep->dwc_ep.xfer_len = 0;
49635 +
49636 + /* If there is a request in the queue start it. */
49637 + start_next_request(ep);
49638 + }
49639 +}
49640 +
49641 +#ifdef DWC_EN_ISOC
49642 +
49643 +/**
49644 + * This function BNA interrupt for Isochronous EPs
49645 + *
49646 + */
49647 +static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep)
49648 +{
49649 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
49650 + volatile uint32_t *addr;
49651 + depctl_data_t depctl = {.d32 = 0 };
49652 + dwc_otg_pcd_t *pcd = ep->pcd;
49653 + dwc_otg_dev_dma_desc_t *dma_desc;
49654 + int i;
49655 +
49656 + dma_desc =
49657 + dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num);
49658 +
49659 + if (dwc_ep->is_in) {
49660 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49661 + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
49662 + sts.d32 = dma_desc->status.d32;
49663 + sts.b_iso_in.bs = BS_HOST_READY;
49664 + dma_desc->status.d32 = sts.d32;
49665 + }
49666 + } else {
49667 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49668 + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
49669 + sts.d32 = dma_desc->status.d32;
49670 + sts.b_iso_out.bs = BS_HOST_READY;
49671 + dma_desc->status.d32 = sts.d32;
49672 + }
49673 + }
49674 +
49675 + if (dwc_ep->is_in == 0) {
49676 + addr =
49677 + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->
49678 + num]->doepctl;
49679 + } else {
49680 + addr =
49681 + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
49682 + }
49683 + depctl.b.epena = 1;
49684 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
49685 +}
49686 +
49687 +/**
49688 + * This function sets latest iso packet information(non-PTI mode)
49689 + *
49690 + * @param core_if Programming view of DWC_otg controller.
49691 + * @param ep The EP to start the transfer on.
49692 + *
49693 + */
49694 +void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
49695 +{
49696 + deptsiz_data_t deptsiz = {.d32 = 0 };
49697 + dma_addr_t dma_addr;
49698 + uint32_t offset;
49699 +
49700 + if (ep->proc_buf_num)
49701 + dma_addr = ep->dma_addr1;
49702 + else
49703 + dma_addr = ep->dma_addr0;
49704 +
49705 + if (ep->is_in) {
49706 + deptsiz.d32 =
49707 + DWC_READ_REG32(&core_if->dev_if->
49708 + in_ep_regs[ep->num]->dieptsiz);
49709 + offset = ep->data_per_frame;
49710 + } else {
49711 + deptsiz.d32 =
49712 + DWC_READ_REG32(&core_if->dev_if->
49713 + out_ep_regs[ep->num]->doeptsiz);
49714 + offset =
49715 + ep->data_per_frame +
49716 + (0x4 & (0x4 - (ep->data_per_frame & 0x3)));
49717 + }
49718 +
49719 + if (!deptsiz.b.xfersize) {
49720 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
49721 + ep->pkt_info[ep->cur_pkt].offset =
49722 + ep->cur_pkt_dma_addr - dma_addr;
49723 + ep->pkt_info[ep->cur_pkt].status = 0;
49724 + } else {
49725 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
49726 + ep->pkt_info[ep->cur_pkt].offset =
49727 + ep->cur_pkt_dma_addr - dma_addr;
49728 + ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA;
49729 + }
49730 + ep->cur_pkt_addr += offset;
49731 + ep->cur_pkt_dma_addr += offset;
49732 + ep->cur_pkt++;
49733 +}
49734 +
49735 +/**
49736 + * This function sets latest iso packet information(DDMA mode)
49737 + *
49738 + * @param core_if Programming view of DWC_otg controller.
49739 + * @param dwc_ep The EP to start the transfer on.
49740 + *
49741 + */
49742 +static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if,
49743 + dwc_ep_t * dwc_ep)
49744 +{
49745 + dwc_otg_dev_dma_desc_t *dma_desc;
49746 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49747 + iso_pkt_info_t *iso_packet;
49748 + uint32_t data_per_desc;
49749 + uint32_t offset;
49750 + int i, j;
49751 +
49752 + iso_packet = dwc_ep->pkt_info;
49753 +
49754 + /** Reinit closed DMA Descriptors*/
49755 + /** ISO OUT EP */
49756 + if (dwc_ep->is_in == 0) {
49757 + dma_desc =
49758 + dwc_ep->iso_desc_addr +
49759 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
49760 + offset = 0;
49761 +
49762 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
49763 + i += dwc_ep->pkt_per_frm) {
49764 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
49765 + data_per_desc =
49766 + ((j + 1) * dwc_ep->maxpacket >
49767 + dwc_ep->
49768 + data_per_frame) ? dwc_ep->data_per_frame -
49769 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49770 + data_per_desc +=
49771 + (data_per_desc % 4) ? (4 -
49772 + data_per_desc %
49773 + 4) : 0;
49774 +
49775 + sts.d32 = dma_desc->status.d32;
49776 +
49777 + /* Write status in iso_packet_decsriptor */
49778 + iso_packet->status =
49779 + sts.b_iso_out.rxsts +
49780 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
49781 + if (iso_packet->status) {
49782 + iso_packet->status = -DWC_E_NO_DATA;
49783 + }
49784 +
49785 + /* Received data length */
49786 + if (!sts.b_iso_out.rxbytes) {
49787 + iso_packet->length =
49788 + data_per_desc -
49789 + sts.b_iso_out.rxbytes;
49790 + } else {
49791 + iso_packet->length =
49792 + data_per_desc -
49793 + sts.b_iso_out.rxbytes + (4 -
49794 + dwc_ep->data_per_frame
49795 + % 4);
49796 + }
49797 +
49798 + iso_packet->offset = offset;
49799 +
49800 + offset += data_per_desc;
49801 + dma_desc++;
49802 + iso_packet++;
49803 + }
49804 + }
49805 +
49806 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
49807 + data_per_desc =
49808 + ((j + 1) * dwc_ep->maxpacket >
49809 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
49810 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49811 + data_per_desc +=
49812 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
49813 +
49814 + sts.d32 = dma_desc->status.d32;
49815 +
49816 + /* Write status in iso_packet_decsriptor */
49817 + iso_packet->status =
49818 + sts.b_iso_out.rxsts +
49819 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
49820 + if (iso_packet->status) {
49821 + iso_packet->status = -DWC_E_NO_DATA;
49822 + }
49823 +
49824 + /* Received data length */
49825 + iso_packet->length =
49826 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
49827 +
49828 + iso_packet->offset = offset;
49829 +
49830 + offset += data_per_desc;
49831 + iso_packet++;
49832 + dma_desc++;
49833 + }
49834 +
49835 + sts.d32 = dma_desc->status.d32;
49836 +
49837 + /* Write status in iso_packet_decsriptor */
49838 + iso_packet->status =
49839 + sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE);
49840 + if (iso_packet->status) {
49841 + iso_packet->status = -DWC_E_NO_DATA;
49842 + }
49843 + /* Received data length */
49844 + if (!sts.b_iso_out.rxbytes) {
49845 + iso_packet->length =
49846 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
49847 + } else {
49848 + iso_packet->length =
49849 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes +
49850 + (4 - dwc_ep->data_per_frame % 4);
49851 + }
49852 +
49853 + iso_packet->offset = offset;
49854 + } else {
49855 +/** ISO IN EP */
49856 +
49857 + dma_desc =
49858 + dwc_ep->iso_desc_addr +
49859 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
49860 +
49861 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
49862 + sts.d32 = dma_desc->status.d32;
49863 +
49864 + /* Write status in iso packet descriptor */
49865 + iso_packet->status =
49866 + sts.b_iso_in.txsts +
49867 + (sts.b_iso_in.bs ^ BS_DMA_DONE);
49868 + if (iso_packet->status != 0) {
49869 + iso_packet->status = -DWC_E_NO_DATA;
49870 +
49871 + }
49872 + /* Bytes has been transfered */
49873 + iso_packet->length =
49874 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
49875 +
49876 + dma_desc++;
49877 + iso_packet++;
49878 + }
49879 +
49880 + sts.d32 = dma_desc->status.d32;
49881 + while (sts.b_iso_in.bs == BS_DMA_BUSY) {
49882 + sts.d32 = dma_desc->status.d32;
49883 + }
49884 +
49885 + /* Write status in iso packet descriptor ??? do be done with ERROR codes */
49886 + iso_packet->status =
49887 + sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE);
49888 + if (iso_packet->status != 0) {
49889 + iso_packet->status = -DWC_E_NO_DATA;
49890 + }
49891 +
49892 + /* Bytes has been transfered */
49893 + iso_packet->length =
49894 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
49895 + }
49896 +}
49897 +
49898 +/**
49899 + * This function reinitialize DMA Descriptors for Isochronous transfer
49900 + *
49901 + * @param core_if Programming view of DWC_otg controller.
49902 + * @param dwc_ep The EP to start the transfer on.
49903 + *
49904 + */
49905 +static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
49906 +{
49907 + int i, j;
49908 + dwc_otg_dev_dma_desc_t *dma_desc;
49909 + dma_addr_t dma_ad;
49910 + volatile uint32_t *addr;
49911 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49912 + uint32_t data_per_desc;
49913 +
49914 + if (dwc_ep->is_in == 0) {
49915 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
49916 + } else {
49917 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
49918 + }
49919 +
49920 + if (dwc_ep->proc_buf_num == 0) {
49921 + /** Buffer 0 descriptors setup */
49922 + dma_ad = dwc_ep->dma_addr0;
49923 + } else {
49924 + /** Buffer 1 descriptors setup */
49925 + dma_ad = dwc_ep->dma_addr1;
49926 + }
49927 +
49928 + /** Reinit closed DMA Descriptors*/
49929 + /** ISO OUT EP */
49930 + if (dwc_ep->is_in == 0) {
49931 + dma_desc =
49932 + dwc_ep->iso_desc_addr +
49933 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
49934 +
49935 + sts.b_iso_out.bs = BS_HOST_READY;
49936 + sts.b_iso_out.rxsts = 0;
49937 + sts.b_iso_out.l = 0;
49938 + sts.b_iso_out.sp = 0;
49939 + sts.b_iso_out.ioc = 0;
49940 + sts.b_iso_out.pid = 0;
49941 + sts.b_iso_out.framenum = 0;
49942 +
49943 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
49944 + i += dwc_ep->pkt_per_frm) {
49945 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
49946 + data_per_desc =
49947 + ((j + 1) * dwc_ep->maxpacket >
49948 + dwc_ep->
49949 + data_per_frame) ? dwc_ep->data_per_frame -
49950 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49951 + data_per_desc +=
49952 + (data_per_desc % 4) ? (4 -
49953 + data_per_desc %
49954 + 4) : 0;
49955 + sts.b_iso_out.rxbytes = data_per_desc;
49956 + dma_desc->buf = dma_ad;
49957 + dma_desc->status.d32 = sts.d32;
49958 +
49959 + dma_ad += data_per_desc;
49960 + dma_desc++;
49961 + }
49962 + }
49963 +
49964 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
49965 +
49966 + data_per_desc =
49967 + ((j + 1) * dwc_ep->maxpacket >
49968 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
49969 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49970 + data_per_desc +=
49971 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
49972 + sts.b_iso_out.rxbytes = data_per_desc;
49973 +
49974 + dma_desc->buf = dma_ad;
49975 + dma_desc->status.d32 = sts.d32;
49976 +
49977 + dma_desc++;
49978 + dma_ad += data_per_desc;
49979 + }
49980 +
49981 + sts.b_iso_out.ioc = 1;
49982 + sts.b_iso_out.l = dwc_ep->proc_buf_num;
49983 +
49984 + data_per_desc =
49985 + ((j + 1) * dwc_ep->maxpacket >
49986 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
49987 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49988 + data_per_desc +=
49989 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
49990 + sts.b_iso_out.rxbytes = data_per_desc;
49991 +
49992 + dma_desc->buf = dma_ad;
49993 + dma_desc->status.d32 = sts.d32;
49994 + } else {
49995 +/** ISO IN EP */
49996 +
49997 + dma_desc =
49998 + dwc_ep->iso_desc_addr +
49999 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
50000 +
50001 + sts.b_iso_in.bs = BS_HOST_READY;
50002 + sts.b_iso_in.txsts = 0;
50003 + sts.b_iso_in.sp = 0;
50004 + sts.b_iso_in.ioc = 0;
50005 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
50006 + sts.b_iso_in.framenum = dwc_ep->next_frame;
50007 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
50008 + sts.b_iso_in.l = 0;
50009 +
50010 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
50011 + dma_desc->buf = dma_ad;
50012 + dma_desc->status.d32 = sts.d32;
50013 +
50014 + sts.b_iso_in.framenum += dwc_ep->bInterval;
50015 + dma_ad += dwc_ep->data_per_frame;
50016 + dma_desc++;
50017 + }
50018 +
50019 + sts.b_iso_in.ioc = 1;
50020 + sts.b_iso_in.l = dwc_ep->proc_buf_num;
50021 +
50022 + dma_desc->buf = dma_ad;
50023 + dma_desc->status.d32 = sts.d32;
50024 +
50025 + dwc_ep->next_frame =
50026 + sts.b_iso_in.framenum + dwc_ep->bInterval * 1;
50027 + }
50028 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
50029 +}
50030 +
50031 +/**
50032 + * This function is to handle Iso EP transfer complete interrupt
50033 + * in case Iso out packet was dropped
50034 + *
50035 + * @param core_if Programming view of DWC_otg controller.
50036 + * @param dwc_ep The EP for wihich transfer complete was asserted
50037 + *
50038 + */
50039 +static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if,
50040 + dwc_ep_t * dwc_ep)
50041 +{
50042 + uint32_t dma_addr;
50043 + uint32_t drp_pkt;
50044 + uint32_t drp_pkt_cnt;
50045 + deptsiz_data_t deptsiz = {.d32 = 0 };
50046 + depctl_data_t depctl = {.d32 = 0 };
50047 + int i;
50048 +
50049 + deptsiz.d32 =
50050 + DWC_READ_REG32(&core_if->dev_if->
50051 + out_ep_regs[dwc_ep->num]->doeptsiz);
50052 +
50053 + drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt;
50054 + drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm);
50055 +
50056 + /* Setting dropped packets status */
50057 + for (i = 0; i < drp_pkt_cnt; ++i) {
50058 + dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA;
50059 + drp_pkt++;
50060 + deptsiz.b.pktcnt--;
50061 + }
50062 +
50063 + if (deptsiz.b.pktcnt > 0) {
50064 + deptsiz.b.xfersize =
50065 + dwc_ep->xfer_len - (dwc_ep->pkt_cnt -
50066 + deptsiz.b.pktcnt) * dwc_ep->maxpacket;
50067 + } else {
50068 + deptsiz.b.xfersize = 0;
50069 + deptsiz.b.pktcnt = 0;
50070 + }
50071 +
50072 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz,
50073 + deptsiz.d32);
50074 +
50075 + if (deptsiz.b.pktcnt > 0) {
50076 + if (dwc_ep->proc_buf_num) {
50077 + dma_addr =
50078 + dwc_ep->dma_addr1 + dwc_ep->xfer_len -
50079 + deptsiz.b.xfersize;
50080 + } else {
50081 + dma_addr =
50082 + dwc_ep->dma_addr0 + dwc_ep->xfer_len -
50083 + deptsiz.b.xfersize;;
50084 + }
50085 +
50086 + DWC_WRITE_REG32(&core_if->dev_if->
50087 + out_ep_regs[dwc_ep->num]->doepdma, dma_addr);
50088 +
50089 + /** Re-enable endpoint, clear nak */
50090 + depctl.d32 = 0;
50091 + depctl.b.epena = 1;
50092 + depctl.b.cnak = 1;
50093 +
50094 + DWC_MODIFY_REG32(&core_if->dev_if->
50095 + out_ep_regs[dwc_ep->num]->doepctl, depctl.d32,
50096 + depctl.d32);
50097 + return 0;
50098 + } else {
50099 + return 1;
50100 + }
50101 +}
50102 +
50103 +/**
50104 + * This function sets iso packets information(PTI mode)
50105 + *
50106 + * @param core_if Programming view of DWC_otg controller.
50107 + * @param ep The EP to start the transfer on.
50108 + *
50109 + */
50110 +static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
50111 +{
50112 + int i, j;
50113 + dma_addr_t dma_ad;
50114 + iso_pkt_info_t *packet_info = ep->pkt_info;
50115 + uint32_t offset;
50116 + uint32_t frame_data;
50117 + deptsiz_data_t deptsiz;
50118 +
50119 + if (ep->proc_buf_num == 0) {
50120 + /** Buffer 0 descriptors setup */
50121 + dma_ad = ep->dma_addr0;
50122 + } else {
50123 + /** Buffer 1 descriptors setup */
50124 + dma_ad = ep->dma_addr1;
50125 + }
50126 +
50127 + if (ep->is_in) {
50128 + deptsiz.d32 =
50129 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
50130 + dieptsiz);
50131 + } else {
50132 + deptsiz.d32 =
50133 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
50134 + doeptsiz);
50135 + }
50136 +
50137 + if (!deptsiz.b.xfersize) {
50138 + offset = 0;
50139 + for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) {
50140 + frame_data = ep->data_per_frame;
50141 + for (j = 0; j < ep->pkt_per_frm; ++j) {
50142 +
50143 + /* Packet status - is not set as initially
50144 + * it is set to 0 and if packet was sent
50145 + successfully, status field will remain 0*/
50146 +
50147 + /* Bytes has been transfered */
50148 + packet_info->length =
50149 + (ep->maxpacket <
50150 + frame_data) ? ep->maxpacket : frame_data;
50151 +
50152 + /* Received packet offset */
50153 + packet_info->offset = offset;
50154 + offset += packet_info->length;
50155 + frame_data -= packet_info->length;
50156 +
50157 + packet_info++;
50158 + }
50159 + }
50160 + return 1;
50161 + } else {
50162 + /* This is a workaround for in case of Transfer Complete with
50163 + * PktDrpSts interrupts merging - in this case Transfer complete
50164 + * interrupt for Isoc Out Endpoint is asserted without PktDrpSts
50165 + * set and with DOEPTSIZ register non zero. Investigations showed,
50166 + * that this happens when Out packet is dropped, but because of
50167 + * interrupts merging during first interrupt handling PktDrpSts
50168 + * bit is cleared and for next merged interrupts it is not reset.
50169 + * In this case SW hadles the interrupt as if PktDrpSts bit is set.
50170 + */
50171 + if (ep->is_in) {
50172 + return 1;
50173 + } else {
50174 + return handle_iso_out_pkt_dropped(core_if, ep);
50175 + }
50176 + }
50177 +}
50178 +
50179 +/**
50180 + * This function is to handle Iso EP transfer complete interrupt
50181 + *
50182 + * @param pcd The PCD
50183 + * @param ep The EP for which transfer complete was asserted
50184 + *
50185 + */
50186 +static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
50187 +{
50188 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
50189 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
50190 + uint8_t is_last = 0;
50191 +
50192 + if (ep->dwc_ep.next_frame == 0xffffffff) {
50193 + DWC_WARN("Next frame is not set!\n");
50194 + return;
50195 + }
50196 +
50197 + if (core_if->dma_enable) {
50198 + if (core_if->dma_desc_enable) {
50199 + set_ddma_iso_pkts_info(core_if, dwc_ep);
50200 + reinit_ddma_iso_xfer(core_if, dwc_ep);
50201 + is_last = 1;
50202 + } else {
50203 + if (core_if->pti_enh_enable) {
50204 + if (set_iso_pkts_info(core_if, dwc_ep)) {
50205 + dwc_ep->proc_buf_num =
50206 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
50207 + dwc_otg_iso_ep_start_buf_transfer
50208 + (core_if, dwc_ep);
50209 + is_last = 1;
50210 + }
50211 + } else {
50212 + set_current_pkt_info(core_if, dwc_ep);
50213 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
50214 + is_last = 1;
50215 + dwc_ep->cur_pkt = 0;
50216 + dwc_ep->proc_buf_num =
50217 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
50218 + if (dwc_ep->proc_buf_num) {
50219 + dwc_ep->cur_pkt_addr =
50220 + dwc_ep->xfer_buff1;
50221 + dwc_ep->cur_pkt_dma_addr =
50222 + dwc_ep->dma_addr1;
50223 + } else {
50224 + dwc_ep->cur_pkt_addr =
50225 + dwc_ep->xfer_buff0;
50226 + dwc_ep->cur_pkt_dma_addr =
50227 + dwc_ep->dma_addr0;
50228 + }
50229 +
50230 + }
50231 + dwc_otg_iso_ep_start_frm_transfer(core_if,
50232 + dwc_ep);
50233 + }
50234 + }
50235 + } else {
50236 + set_current_pkt_info(core_if, dwc_ep);
50237 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
50238 + is_last = 1;
50239 + dwc_ep->cur_pkt = 0;
50240 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
50241 + if (dwc_ep->proc_buf_num) {
50242 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1;
50243 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1;
50244 + } else {
50245 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0;
50246 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0;
50247 + }
50248 +
50249 + }
50250 + dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep);
50251 + }
50252 + if (is_last)
50253 + dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle);
50254 +}
50255 +#endif /* DWC_EN_ISOC */
50256 +
50257 +/**
50258 + * This function handle BNA interrupt for Non Isochronous EPs
50259 + *
50260 + */
50261 +static void dwc_otg_pcd_handle_noniso_bna(dwc_otg_pcd_ep_t * ep)
50262 +{
50263 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
50264 + volatile uint32_t *addr;
50265 + depctl_data_t depctl = {.d32 = 0 };
50266 + dwc_otg_pcd_t *pcd = ep->pcd;
50267 + dwc_otg_dev_dma_desc_t *dma_desc;
50268 + dev_dma_desc_sts_t sts = {.d32 = 0 };
50269 + dwc_otg_core_if_t *core_if = ep->pcd->core_if;
50270 + int i, start;
50271 +
50272 + if (!dwc_ep->desc_cnt)
50273 + DWC_WARN("Ep%d %s Descriptor count = %d \n", dwc_ep->num,
50274 + (dwc_ep->is_in ? "IN" : "OUT"), dwc_ep->desc_cnt);
50275 +
50276 + if (core_if->core_params->cont_on_bna && !dwc_ep->is_in
50277 + && dwc_ep->type != DWC_OTG_EP_TYPE_CONTROL) {
50278 + uint32_t doepdma;
50279 + dwc_otg_dev_out_ep_regs_t *out_regs =
50280 + core_if->dev_if->out_ep_regs[dwc_ep->num];
50281 + doepdma = DWC_READ_REG32(&(out_regs->doepdma));
50282 + start = (doepdma - dwc_ep->dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t);
50283 + dma_desc = &(dwc_ep->desc_addr[start]);
50284 + } else {
50285 + start = 0;
50286 + dma_desc = dwc_ep->desc_addr;
50287 + }
50288 +
50289 +
50290 + for (i = start; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
50291 + sts.d32 = dma_desc->status.d32;
50292 + sts.b.bs = BS_HOST_READY;
50293 + dma_desc->status.d32 = sts.d32;
50294 + }
50295 +
50296 + if (dwc_ep->is_in == 0) {
50297 + addr =
50298 + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->
50299 + doepctl;
50300 + } else {
50301 + addr =
50302 + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
50303 + }
50304 + depctl.b.epena = 1;
50305 + depctl.b.cnak = 1;
50306 + DWC_MODIFY_REG32(addr, 0, depctl.d32);
50307 +}
50308 +
50309 +/**
50310 + * This function handles EP0 Control transfers.
50311 + *
50312 + * The state of the control transfers are tracked in
50313 + * <code>ep0state</code>.
50314 + */
50315 +static void handle_ep0(dwc_otg_pcd_t * pcd)
50316 +{
50317 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50318 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
50319 + dev_dma_desc_sts_t desc_sts;
50320 + deptsiz0_data_t deptsiz;
50321 + uint32_t byte_count;
50322 +
50323 +#ifdef DEBUG_EP0
50324 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
50325 + print_ep0_state(pcd);
50326 +#endif
50327 +
50328 +// DWC_PRINTF("HANDLE EP0\n");
50329 +
50330 + switch (pcd->ep0state) {
50331 + case EP0_DISCONNECT:
50332 + break;
50333 +
50334 + case EP0_IDLE:
50335 + pcd->request_config = 0;
50336 +
50337 + pcd_setup(pcd);
50338 + break;
50339 +
50340 + case EP0_IN_DATA_PHASE:
50341 +#ifdef DEBUG_EP0
50342 + DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
50343 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
50344 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
50345 +#endif
50346 +
50347 + if (core_if->dma_enable != 0) {
50348 + /*
50349 + * For EP0 we can only program 1 packet at a time so we
50350 + * need to do the make calculations after each complete.
50351 + * Call write_packet to make the calculations, as in
50352 + * slave mode, and use those values to determine if we
50353 + * can complete.
50354 + */
50355 + if (core_if->dma_desc_enable == 0) {
50356 + deptsiz.d32 =
50357 + DWC_READ_REG32(&core_if->
50358 + dev_if->in_ep_regs[0]->
50359 + dieptsiz);
50360 + byte_count =
50361 + ep0->dwc_ep.xfer_len - deptsiz.b.xfersize;
50362 + } else {
50363 + desc_sts =
50364 + core_if->dev_if->in_desc_addr->status;
50365 + byte_count =
50366 + ep0->dwc_ep.xfer_len - desc_sts.b.bytes;
50367 + }
50368 + ep0->dwc_ep.xfer_count += byte_count;
50369 + ep0->dwc_ep.xfer_buff += byte_count;
50370 + ep0->dwc_ep.dma_addr += byte_count;
50371 + }
50372 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
50373 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50374 + &ep0->dwc_ep);
50375 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
50376 + } else if (ep0->dwc_ep.sent_zlp) {
50377 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50378 + &ep0->dwc_ep);
50379 + ep0->dwc_ep.sent_zlp = 0;
50380 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
50381 + } else {
50382 + ep0_complete_request(ep0);
50383 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
50384 + }
50385 + break;
50386 + case EP0_OUT_DATA_PHASE:
50387 +#ifdef DEBUG_EP0
50388 + DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
50389 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
50390 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
50391 +#endif
50392 + if (core_if->dma_enable != 0) {
50393 + if (core_if->dma_desc_enable == 0) {
50394 + deptsiz.d32 =
50395 + DWC_READ_REG32(&core_if->
50396 + dev_if->out_ep_regs[0]->
50397 + doeptsiz);
50398 + byte_count =
50399 + ep0->dwc_ep.maxpacket - deptsiz.b.xfersize;
50400 + } else {
50401 + desc_sts =
50402 + core_if->dev_if->out_desc_addr->status;
50403 + byte_count =
50404 + ep0->dwc_ep.maxpacket - desc_sts.b.bytes;
50405 + }
50406 + ep0->dwc_ep.xfer_count += byte_count;
50407 + ep0->dwc_ep.xfer_buff += byte_count;
50408 + ep0->dwc_ep.dma_addr += byte_count;
50409 + }
50410 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
50411 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50412 + &ep0->dwc_ep);
50413 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
50414 + } else if (ep0->dwc_ep.sent_zlp) {
50415 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50416 + &ep0->dwc_ep);
50417 + ep0->dwc_ep.sent_zlp = 0;
50418 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
50419 + } else {
50420 + ep0_complete_request(ep0);
50421 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
50422 + }
50423 + break;
50424 +
50425 + case EP0_IN_STATUS_PHASE:
50426 + case EP0_OUT_STATUS_PHASE:
50427 + DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
50428 + ep0_complete_request(ep0);
50429 + pcd->ep0state = EP0_IDLE;
50430 + ep0->stopped = 1;
50431 + ep0->dwc_ep.is_in = 0; /* OUT for next SETUP */
50432 +
50433 + /* Prepare for more SETUP Packets */
50434 + if (core_if->dma_enable) {
50435 + ep0_out_start(core_if, pcd);
50436 + }
50437 + break;
50438 +
50439 + case EP0_STALL:
50440 + DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
50441 + break;
50442 + }
50443 +#ifdef DEBUG_EP0
50444 + print_ep0_state(pcd);
50445 +#endif
50446 +}
50447 +
50448 +/**
50449 + * Restart transfer
50450 + */
50451 +static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum)
50452 +{
50453 + dwc_otg_core_if_t *core_if;
50454 + dwc_otg_dev_if_t *dev_if;
50455 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50456 + dwc_otg_pcd_ep_t *ep;
50457 +
50458 + ep = get_in_ep(pcd, epnum);
50459 +
50460 +#ifdef DWC_EN_ISOC
50461 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
50462 + return;
50463 + }
50464 +#endif /* DWC_EN_ISOC */
50465 +
50466 + core_if = GET_CORE_IF(pcd);
50467 + dev_if = core_if->dev_if;
50468 +
50469 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
50470 +
50471 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x"
50472 + " stopped=%d\n", ep->dwc_ep.xfer_buff,
50473 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped);
50474 + /*
50475 + * If xfersize is 0 and pktcnt in not 0, resend the last packet.
50476 + */
50477 + if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
50478 + ep->dwc_ep.start_xfer_buff != 0) {
50479 + if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) {
50480 + ep->dwc_ep.xfer_count = 0;
50481 + ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
50482 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
50483 + } else {
50484 + ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
50485 + /* convert packet size to dwords. */
50486 + ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
50487 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
50488 + }
50489 + ep->stopped = 0;
50490 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x "
50491 + "xfer_len=%0x stopped=%d\n",
50492 + ep->dwc_ep.xfer_buff,
50493 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len,
50494 + ep->stopped);
50495 + if (epnum == 0) {
50496 + dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
50497 + } else {
50498 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
50499 + }
50500 + }
50501 +}
50502 +
50503 +/*
50504 + * This function create new nextep sequnce based on Learn Queue.
50505 + *
50506 + * @param core_if Programming view of DWC_otg controller
50507 + */
50508 +void predict_nextep_seq( dwc_otg_core_if_t * core_if)
50509 +{
50510 + dwc_otg_device_global_regs_t *dev_global_regs =
50511 + core_if->dev_if->dev_global_regs;
50512 + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
50513 + /* Number of Token Queue Registers */
50514 + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
50515 + dtknq1_data_t dtknqr1;
50516 + uint32_t in_tkn_epnums[4];
50517 + uint8_t seqnum[MAX_EPS_CHANNELS];
50518 + uint8_t intkn_seq[TOKEN_Q_DEPTH];
50519 + grstctl_t resetctl = {.d32 = 0 };
50520 + uint8_t temp;
50521 + int ndx = 0;
50522 + int start = 0;
50523 + int end = 0;
50524 + int sort_done = 0;
50525 + int i = 0;
50526 + volatile uint32_t *addr = &dev_global_regs->dtknqr1;
50527 +
50528 +
50529 + DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
50530 +
50531 + /* Read the DTKNQ Registers */
50532 + for (i = 0; i < DTKNQ_REG_CNT; i++) {
50533 + in_tkn_epnums[i] = DWC_READ_REG32(addr);
50534 + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
50535 + in_tkn_epnums[i]);
50536 + if (addr == &dev_global_regs->dvbusdis) {
50537 + addr = &dev_global_regs->dtknqr3_dthrctl;
50538 + } else {
50539 + ++addr;
50540 + }
50541 +
50542 + }
50543 +
50544 + /* Copy the DTKNQR1 data to the bit field. */
50545 + dtknqr1.d32 = in_tkn_epnums[0];
50546 + if (dtknqr1.b.wrap_bit) {
50547 + ndx = dtknqr1.b.intknwptr;
50548 + end = ndx -1;
50549 + if (end < 0)
50550 + end = TOKEN_Q_DEPTH -1;
50551 + } else {
50552 + ndx = 0;
50553 + end = dtknqr1.b.intknwptr -1;
50554 + if (end < 0)
50555 + end = 0;
50556 + }
50557 + start = ndx;
50558 +
50559 + /* Fill seqnum[] by initial values: EP number + 31 */
50560 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
50561 + seqnum[i] = i +31;
50562 + }
50563 +
50564 + /* Fill intkn_seq[] from in_tkn_epnums[0] */
50565 + for (i=0; i < 6; i++)
50566 + intkn_seq[i] = (in_tkn_epnums[0] >> ((7-i) * 4)) & 0xf;
50567 +
50568 + if (TOKEN_Q_DEPTH > 6) {
50569 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50570 + for (i=6; i < 14; i++)
50571 + intkn_seq[i] =
50572 + (in_tkn_epnums[1] >> ((7 - (i - 6)) * 4)) & 0xf;
50573 + }
50574 +
50575 + if (TOKEN_Q_DEPTH > 14) {
50576 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50577 + for (i=14; i < 22; i++)
50578 + intkn_seq[i] =
50579 + (in_tkn_epnums[2] >> ((7 - (i - 14)) * 4)) & 0xf;
50580 + }
50581 +
50582 + if (TOKEN_Q_DEPTH > 22) {
50583 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50584 + for (i=22; i < 30; i++)
50585 + intkn_seq[i] =
50586 + (in_tkn_epnums[3] >> ((7 - (i - 22)) * 4)) & 0xf;
50587 + }
50588 +
50589 + DWC_DEBUGPL(DBG_PCDV, "%s start=%d end=%d intkn_seq[]:\n", __func__,
50590 + start, end);
50591 + for (i=0; i<TOKEN_Q_DEPTH; i++)
50592 + DWC_DEBUGPL(DBG_PCDV,"%d\n", intkn_seq[i]);
50593 +
50594 + /* Update seqnum based on intkn_seq[] */
50595 + i = 0;
50596 + do {
50597 + seqnum[intkn_seq[ndx]] = i;
50598 + ndx++;
50599 + i++;
50600 + if (ndx == TOKEN_Q_DEPTH)
50601 + ndx = 0;
50602 + } while ( i < TOKEN_Q_DEPTH );
50603 +
50604 + /* Mark non active EP's in seqnum[] by 0xff */
50605 + for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
50606 + if (core_if->nextep_seq[i] == 0xff )
50607 + seqnum[i] = 0xff;
50608 + }
50609 +
50610 + /* Sort seqnum[] */
50611 + sort_done = 0;
50612 + while (!sort_done) {
50613 + sort_done = 1;
50614 + for (i=0; i<core_if->dev_if->num_in_eps; i++) {
50615 + if (seqnum[i] > seqnum[i+1]) {
50616 + temp = seqnum[i];
50617 + seqnum[i] = seqnum[i+1];
50618 + seqnum[i+1] = temp;
50619 + sort_done = 0;
50620 + }
50621 + }
50622 + }
50623 +
50624 + ndx = start + seqnum[0];
50625 + if (ndx >= TOKEN_Q_DEPTH)
50626 + ndx = ndx % TOKEN_Q_DEPTH;
50627 + core_if->first_in_nextep_seq = intkn_seq[ndx];
50628 +
50629 + /* Update seqnum[] by EP numbers */
50630 + for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
50631 + ndx = start + i;
50632 + if (seqnum[i] < 31) {
50633 + ndx = start + seqnum[i];
50634 + if (ndx >= TOKEN_Q_DEPTH)
50635 + ndx = ndx % TOKEN_Q_DEPTH;
50636 + seqnum[i] = intkn_seq[ndx];
50637 + } else {
50638 + if (seqnum[i] < 0xff) {
50639 + seqnum[i] = seqnum[i] - 31;
50640 + } else {
50641 + break;
50642 + }
50643 + }
50644 + }
50645 +
50646 + /* Update nextep_seq[] based on seqnum[] */
50647 + for (i=0; i<core_if->dev_if->num_in_eps; i++) {
50648 + if (seqnum[i] != 0xff) {
50649 + if (seqnum[i+1] != 0xff) {
50650 + core_if->nextep_seq[seqnum[i]] = seqnum[i+1];
50651 + } else {
50652 + core_if->nextep_seq[seqnum[i]] = core_if->first_in_nextep_seq;
50653 + break;
50654 + }
50655 + } else {
50656 + break;
50657 + }
50658 + }
50659 +
50660 + DWC_DEBUGPL(DBG_PCDV, "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
50661 + __func__, core_if->first_in_nextep_seq);
50662 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
50663 + DWC_DEBUGPL(DBG_PCDV,"%2d\n", core_if->nextep_seq[i]);
50664 + }
50665 +
50666 + /* Flush the Learning Queue */
50667 + resetctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->grstctl);
50668 + resetctl.b.intknqflsh = 1;
50669 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
50670 +
50671 +
50672 +}
50673 +
50674 +/**
50675 + * handle the IN EP disable interrupt.
50676 + */
50677 +static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd,
50678 + const uint32_t epnum)
50679 +{
50680 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50681 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
50682 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50683 + dctl_data_t dctl = {.d32 = 0 };
50684 + dwc_otg_pcd_ep_t *ep;
50685 + dwc_ep_t *dwc_ep;
50686 + gintmsk_data_t gintmsk_data;
50687 + depctl_data_t depctl;
50688 + uint32_t diepdma;
50689 + uint32_t remain_to_transfer = 0;
50690 + uint8_t i;
50691 + uint32_t xfer_size;
50692 +
50693 + ep = get_in_ep(pcd, epnum);
50694 + dwc_ep = &ep->dwc_ep;
50695 +
50696 + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
50697 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
50698 + complete_ep(ep);
50699 + return;
50700 + }
50701 +
50702 + DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum,
50703 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl));
50704 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
50705 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
50706 +
50707 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
50708 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
50709 +
50710 + if ((core_if->start_predict == 0) || (depctl.b.eptype & 1)) {
50711 + if (ep->stopped) {
50712 + if (core_if->en_multiple_tx_fifo)
50713 + /* Flush the Tx FIFO */
50714 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
50715 + /* Clear the Global IN NP NAK */
50716 + dctl.d32 = 0;
50717 + dctl.b.cgnpinnak = 1;
50718 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
50719 + /* Restart the transaction */
50720 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
50721 + restart_transfer(pcd, epnum);
50722 + }
50723 + } else {
50724 + /* Restart the transaction */
50725 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
50726 + restart_transfer(pcd, epnum);
50727 + }
50728 + DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
50729 + }
50730 + return;
50731 + }
50732 +
50733 + if (core_if->start_predict > 2) { // NP IN EP
50734 + core_if->start_predict--;
50735 + return;
50736 + }
50737 +
50738 + core_if->start_predict--;
50739 +
50740 + if (core_if->start_predict == 1) { // All NP IN Ep's disabled now
50741 +
50742 + predict_nextep_seq(core_if);
50743 +
50744 + /* Update all active IN EP's NextEP field based of nextep_seq[] */
50745 + for ( i = 0; i <= core_if->dev_if->num_in_eps; i++) {
50746 + depctl.d32 =
50747 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50748 + if (core_if->nextep_seq[i] != 0xff) { // Active NP IN EP
50749 + depctl.b.nextep = core_if->nextep_seq[i];
50750 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
50751 + }
50752 + }
50753 + /* Flush Shared NP TxFIFO */
50754 + dwc_otg_flush_tx_fifo(core_if, 0);
50755 + /* Rewind buffers */
50756 + if (!core_if->dma_desc_enable) {
50757 + i = core_if->first_in_nextep_seq;
50758 + do {
50759 + ep = get_in_ep(pcd, i);
50760 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
50761 + xfer_size = ep->dwc_ep.total_len - ep->dwc_ep.xfer_count;
50762 + if (xfer_size > ep->dwc_ep.maxxfer)
50763 + xfer_size = ep->dwc_ep.maxxfer;
50764 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50765 + if (dieptsiz.b.pktcnt != 0) {
50766 + if (xfer_size == 0) {
50767 + remain_to_transfer = 0;
50768 + } else {
50769 + if ((xfer_size % ep->dwc_ep.maxpacket) == 0) {
50770 + remain_to_transfer =
50771 + dieptsiz.b.pktcnt * ep->dwc_ep.maxpacket;
50772 + } else {
50773 + remain_to_transfer = ((dieptsiz.b.pktcnt -1) * ep->dwc_ep.maxpacket)
50774 + + (xfer_size % ep->dwc_ep.maxpacket);
50775 + }
50776 + }
50777 + diepdma = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepdma);
50778 + dieptsiz.b.xfersize = remain_to_transfer;
50779 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, dieptsiz.d32);
50780 + diepdma = ep->dwc_ep.dma_addr + (xfer_size - remain_to_transfer);
50781 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, diepdma);
50782 + }
50783 + i = core_if->nextep_seq[i];
50784 + } while (i != core_if->first_in_nextep_seq);
50785 + } else { // dma_desc_enable
50786 + DWC_PRINTF("%s Learning Queue not supported in DDMA\n", __func__);
50787 + }
50788 +
50789 + /* Restart transfers in predicted sequences */
50790 + i = core_if->first_in_nextep_seq;
50791 + do {
50792 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
50793 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50794 + if (dieptsiz.b.pktcnt != 0) {
50795 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50796 + depctl.b.epena = 1;
50797 + depctl.b.cnak = 1;
50798 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
50799 + }
50800 + i = core_if->nextep_seq[i];
50801 + } while (i != core_if->first_in_nextep_seq);
50802 +
50803 + /* Clear the global non-periodic IN NAK handshake */
50804 + dctl.d32 = 0;
50805 + dctl.b.cgnpinnak = 1;
50806 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
50807 +
50808 + /* Unmask EP Mismatch interrupt */
50809 + gintmsk_data.d32 = 0;
50810 + gintmsk_data.b.epmismatch = 1;
50811 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk_data.d32);
50812 +
50813 + core_if->start_predict = 0;
50814 +
50815 + }
50816 +}
50817 +
50818 +/**
50819 + * Handler for the IN EP timeout handshake interrupt.
50820 + */
50821 +static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd,
50822 + const uint32_t epnum)
50823 +{
50824 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50825 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
50826 +
50827 +#ifdef DEBUG
50828 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50829 + uint32_t num = 0;
50830 +#endif
50831 + dctl_data_t dctl = {.d32 = 0 };
50832 + dwc_otg_pcd_ep_t *ep;
50833 +
50834 + gintmsk_data_t intr_mask = {.d32 = 0 };
50835 +
50836 + ep = get_in_ep(pcd, epnum);
50837 +
50838 + /* Disable the NP Tx Fifo Empty Interrrupt */
50839 + if (!core_if->dma_enable) {
50840 + intr_mask.b.nptxfempty = 1;
50841 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
50842 + intr_mask.d32, 0);
50843 + }
50844 + /** @todo NGS Check EP type.
50845 + * Implement for Periodic EPs */
50846 + /*
50847 + * Non-periodic EP
50848 + */
50849 + /* Enable the Global IN NAK Effective Interrupt */
50850 + intr_mask.b.ginnakeff = 1;
50851 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
50852 +
50853 + /* Set Global IN NAK */
50854 + dctl.b.sgnpinnak = 1;
50855 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
50856 +
50857 + ep->stopped = 1;
50858 +
50859 +#ifdef DEBUG
50860 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[num]->dieptsiz);
50861 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
50862 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
50863 +#endif
50864 +
50865 +#ifdef DISABLE_PERIODIC_EP
50866 + /*
50867 + * Set the NAK bit for this EP to
50868 + * start the disable process.
50869 + */
50870 + diepctl.d32 = 0;
50871 + diepctl.b.snak = 1;
50872 + DWC_MODIFY_REG32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32,
50873 + diepctl.d32);
50874 + ep->disabling = 1;
50875 + ep->stopped = 1;
50876 +#endif
50877 +}
50878 +
50879 +/**
50880 + * Handler for the IN EP NAK interrupt.
50881 + */
50882 +static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd,
50883 + const uint32_t epnum)
50884 +{
50885 + /** @todo implement ISR */
50886 + dwc_otg_core_if_t *core_if;
50887 + diepmsk_data_t intr_mask = {.d32 = 0 };
50888 +
50889 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK");
50890 + core_if = GET_CORE_IF(pcd);
50891 + intr_mask.b.nak = 1;
50892 +
50893 + if (core_if->multiproc_int_enable) {
50894 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
50895 + diepeachintmsk[epnum], intr_mask.d32, 0);
50896 + } else {
50897 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->diepmsk,
50898 + intr_mask.d32, 0);
50899 + }
50900 +
50901 + return 1;
50902 +}
50903 +
50904 +/**
50905 + * Handler for the OUT EP Babble interrupt.
50906 + */
50907 +static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd,
50908 + const uint32_t epnum)
50909 +{
50910 + /** @todo implement ISR */
50911 + dwc_otg_core_if_t *core_if;
50912 + doepmsk_data_t intr_mask = {.d32 = 0 };
50913 +
50914 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
50915 + "OUT EP Babble");
50916 + core_if = GET_CORE_IF(pcd);
50917 + intr_mask.b.babble = 1;
50918 +
50919 + if (core_if->multiproc_int_enable) {
50920 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
50921 + doepeachintmsk[epnum], intr_mask.d32, 0);
50922 + } else {
50923 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
50924 + intr_mask.d32, 0);
50925 + }
50926 +
50927 + return 1;
50928 +}
50929 +
50930 +/**
50931 + * Handler for the OUT EP NAK interrupt.
50932 + */
50933 +static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd,
50934 + const uint32_t epnum)
50935 +{
50936 + /** @todo implement ISR */
50937 + dwc_otg_core_if_t *core_if;
50938 + doepmsk_data_t intr_mask = {.d32 = 0 };
50939 +
50940 + DWC_DEBUGPL(DBG_ANY, "INTERRUPT Handler not implemented for %s\n", "OUT EP NAK");
50941 + core_if = GET_CORE_IF(pcd);
50942 + intr_mask.b.nak = 1;
50943 +
50944 + if (core_if->multiproc_int_enable) {
50945 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
50946 + doepeachintmsk[epnum], intr_mask.d32, 0);
50947 + } else {
50948 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
50949 + intr_mask.d32, 0);
50950 + }
50951 +
50952 + return 1;
50953 +}
50954 +
50955 +/**
50956 + * Handler for the OUT EP NYET interrupt.
50957 + */
50958 +static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd,
50959 + const uint32_t epnum)
50960 +{
50961 + /** @todo implement ISR */
50962 + dwc_otg_core_if_t *core_if;
50963 + doepmsk_data_t intr_mask = {.d32 = 0 };
50964 +
50965 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET");
50966 + core_if = GET_CORE_IF(pcd);
50967 + intr_mask.b.nyet = 1;
50968 +
50969 + if (core_if->multiproc_int_enable) {
50970 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
50971 + doepeachintmsk[epnum], intr_mask.d32, 0);
50972 + } else {
50973 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
50974 + intr_mask.d32, 0);
50975 + }
50976 +
50977 + return 1;
50978 +}
50979 +
50980 +/**
50981 + * This interrupt indicates that an IN EP has a pending Interrupt.
50982 + * The sequence for handling the IN EP interrupt is shown below:
50983 + * -# Read the Device All Endpoint Interrupt register
50984 + * -# Repeat the following for each IN EP interrupt bit set (from
50985 + * LSB to MSB).
50986 + * -# Read the Device Endpoint Interrupt (DIEPINTn) register
50987 + * -# If "Transfer Complete" call the request complete function
50988 + * -# If "Endpoint Disabled" complete the EP disable procedure.
50989 + * -# If "AHB Error Interrupt" log error
50990 + * -# If "Time-out Handshake" log error
50991 + * -# If "IN Token Received when TxFIFO Empty" write packet to Tx
50992 + * FIFO.
50993 + * -# If "IN Token EP Mismatch" (disable, this is handled by EP
50994 + * Mismatch Interrupt)
50995 + */
50996 +static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd)
50997 +{
50998 +#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
50999 +do { \
51000 + diepint_data_t diepint = {.d32=0}; \
51001 + diepint.b.__intr = 1; \
51002 + DWC_WRITE_REG32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
51003 + diepint.d32); \
51004 +} while (0)
51005 +
51006 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
51007 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
51008 + diepint_data_t diepint = {.d32 = 0 };
51009 + depctl_data_t depctl = {.d32 = 0 };
51010 + uint32_t ep_intr;
51011 + uint32_t epnum = 0;
51012 + dwc_otg_pcd_ep_t *ep;
51013 + dwc_ep_t *dwc_ep;
51014 + gintmsk_data_t intr_mask = {.d32 = 0 };
51015 +
51016 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd);
51017 +
51018 + /* Read in the device interrupt bits */
51019 + ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if);
51020 +
51021 + /* Service the Device IN interrupts for each endpoint */
51022 + while (ep_intr) {
51023 + if (ep_intr & 0x1) {
51024 + uint32_t empty_msk;
51025 + /* Get EP pointer */
51026 + ep = get_in_ep(pcd, epnum);
51027 + dwc_ep = &ep->dwc_ep;
51028 +
51029 + depctl.d32 =
51030 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
51031 + empty_msk =
51032 + DWC_READ_REG32(&dev_if->
51033 + dev_global_regs->dtknqr4_fifoemptymsk);
51034 +
51035 + DWC_DEBUGPL(DBG_PCDV,
51036 + "IN EP INTERRUPT - %d\nepmty_msk - %8x diepctl - %8x\n",
51037 + epnum, empty_msk, depctl.d32);
51038 +
51039 + DWC_DEBUGPL(DBG_PCD,
51040 + "EP%d-%s: type=%d, mps=%d\n",
51041 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
51042 + dwc_ep->type, dwc_ep->maxpacket);
51043 +
51044 + diepint.d32 =
51045 + dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep);
51046 +
51047 + DWC_DEBUGPL(DBG_PCDV,
51048 + "EP %d Interrupt Register - 0x%x\n", epnum,
51049 + diepint.d32);
51050 + /* Transfer complete */
51051 + if (diepint.b.xfercompl) {
51052 + /* Disable the NP Tx FIFO Empty
51053 + * Interrupt */
51054 + if (core_if->en_multiple_tx_fifo == 0) {
51055 + intr_mask.b.nptxfempty = 1;
51056 + DWC_MODIFY_REG32
51057 + (&core_if->core_global_regs->gintmsk,
51058 + intr_mask.d32, 0);
51059 + } else {
51060 + /* Disable the Tx FIFO Empty Interrupt for this EP */
51061 + uint32_t fifoemptymsk =
51062 + 0x1 << dwc_ep->num;
51063 + DWC_MODIFY_REG32(&core_if->
51064 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
51065 + fifoemptymsk, 0);
51066 + }
51067 + /* Clear the bit in DIEPINTn for this interrupt */
51068 + CLEAR_IN_EP_INTR(core_if, epnum, xfercompl);
51069 +
51070 + /* Complete the transfer */
51071 + if (epnum == 0) {
51072 + handle_ep0(pcd);
51073 + }
51074 +#ifdef DWC_EN_ISOC
51075 + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51076 + if (!ep->stopped)
51077 + complete_iso_ep(pcd, ep);
51078 + }
51079 +#endif /* DWC_EN_ISOC */
51080 +#ifdef DWC_UTE_PER_IO
51081 + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51082 + if (!ep->stopped)
51083 + complete_xiso_ep(ep);
51084 + }
51085 +#endif /* DWC_UTE_PER_IO */
51086 + else {
51087 + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC &&
51088 + dwc_ep->bInterval > 1) {
51089 + dwc_ep->frame_num += dwc_ep->bInterval;
51090 + if (dwc_ep->frame_num > 0x3FFF)
51091 + {
51092 + dwc_ep->frm_overrun = 1;
51093 + dwc_ep->frame_num &= 0x3FFF;
51094 + } else
51095 + dwc_ep->frm_overrun = 0;
51096 + }
51097 + complete_ep(ep);
51098 + if(diepint.b.nak)
51099 + CLEAR_IN_EP_INTR(core_if, epnum, nak);
51100 + }
51101 + }
51102 + /* Endpoint disable */
51103 + if (diepint.b.epdisabled) {
51104 + DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n",
51105 + epnum);
51106 + handle_in_ep_disable_intr(pcd, epnum);
51107 +
51108 + /* Clear the bit in DIEPINTn for this interrupt */
51109 + CLEAR_IN_EP_INTR(core_if, epnum, epdisabled);
51110 + }
51111 + /* AHB Error */
51112 + if (diepint.b.ahberr) {
51113 + DWC_ERROR("EP%d IN AHB Error\n", epnum);
51114 + /* Clear the bit in DIEPINTn for this interrupt */
51115 + CLEAR_IN_EP_INTR(core_if, epnum, ahberr);
51116 + }
51117 + /* TimeOUT Handshake (non-ISOC IN EPs) */
51118 + if (diepint.b.timeout) {
51119 + DWC_ERROR("EP%d IN Time-out\n", epnum);
51120 + handle_in_ep_timeout_intr(pcd, epnum);
51121 +
51122 + CLEAR_IN_EP_INTR(core_if, epnum, timeout);
51123 + }
51124 + /** IN Token received with TxF Empty */
51125 + if (diepint.b.intktxfemp) {
51126 + DWC_DEBUGPL(DBG_ANY,
51127 + "EP%d IN TKN TxFifo Empty\n",
51128 + epnum);
51129 + if (!ep->stopped && epnum != 0) {
51130 +
51131 + diepmsk_data_t diepmsk = {.d32 = 0 };
51132 + diepmsk.b.intktxfemp = 1;
51133 +
51134 + if (core_if->multiproc_int_enable) {
51135 + DWC_MODIFY_REG32
51136 + (&dev_if->dev_global_regs->diepeachintmsk
51137 + [epnum], diepmsk.d32, 0);
51138 + } else {
51139 + DWC_MODIFY_REG32
51140 + (&dev_if->dev_global_regs->diepmsk,
51141 + diepmsk.d32, 0);
51142 + }
51143 + } else if (core_if->dma_desc_enable
51144 + && epnum == 0
51145 + && pcd->ep0state ==
51146 + EP0_OUT_STATUS_PHASE) {
51147 + // EP0 IN set STALL
51148 + depctl.d32 =
51149 + DWC_READ_REG32(&dev_if->in_ep_regs
51150 + [epnum]->diepctl);
51151 +
51152 + /* set the disable and stall bits */
51153 + if (depctl.b.epena) {
51154 + depctl.b.epdis = 1;
51155 + }
51156 + depctl.b.stall = 1;
51157 + DWC_WRITE_REG32(&dev_if->in_ep_regs
51158 + [epnum]->diepctl,
51159 + depctl.d32);
51160 + }
51161 + CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp);
51162 + }
51163 + /** IN Token Received with EP mismatch */
51164 + if (diepint.b.intknepmis) {
51165 + DWC_DEBUGPL(DBG_ANY,
51166 + "EP%d IN TKN EP Mismatch\n", epnum);
51167 + CLEAR_IN_EP_INTR(core_if, epnum, intknepmis);
51168 + }
51169 + /** IN Endpoint NAK Effective */
51170 + if (diepint.b.inepnakeff) {
51171 + DWC_DEBUGPL(DBG_ANY,
51172 + "EP%d IN EP NAK Effective\n",
51173 + epnum);
51174 + /* Periodic EP */
51175 + if (ep->disabling) {
51176 + depctl.d32 = 0;
51177 + depctl.b.snak = 1;
51178 + depctl.b.epdis = 1;
51179 + DWC_MODIFY_REG32(&dev_if->in_ep_regs
51180 + [epnum]->diepctl,
51181 + depctl.d32,
51182 + depctl.d32);
51183 + }
51184 + CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff);
51185 +
51186 + }
51187 +
51188 + /** IN EP Tx FIFO Empty Intr */
51189 + if (diepint.b.emptyintr) {
51190 + DWC_DEBUGPL(DBG_ANY,
51191 + "EP%d Tx FIFO Empty Intr \n",
51192 + epnum);
51193 + write_empty_tx_fifo(pcd, epnum);
51194 +
51195 + CLEAR_IN_EP_INTR(core_if, epnum, emptyintr);
51196 +
51197 + }
51198 +
51199 + /** IN EP BNA Intr */
51200 + if (diepint.b.bna) {
51201 + CLEAR_IN_EP_INTR(core_if, epnum, bna);
51202 + if (core_if->dma_desc_enable) {
51203 +#ifdef DWC_EN_ISOC
51204 + if (dwc_ep->type ==
51205 + DWC_OTG_EP_TYPE_ISOC) {
51206 + /*
51207 + * This checking is performed to prevent first "false" BNA
51208 + * handling occuring right after reconnect
51209 + */
51210 + if (dwc_ep->next_frame !=
51211 + 0xffffffff)
51212 + dwc_otg_pcd_handle_iso_bna(ep);
51213 + } else
51214 +#endif /* DWC_EN_ISOC */
51215 + {
51216 + dwc_otg_pcd_handle_noniso_bna(ep);
51217 + }
51218 + }
51219 + }
51220 + /* NAK Interrutp */
51221 + if (diepint.b.nak) {
51222 + DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n",
51223 + epnum);
51224 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
51225 + depctl_data_t depctl;
51226 + if (ep->dwc_ep.frame_num == 0xFFFFFFFF) {
51227 + ep->dwc_ep.frame_num = core_if->frame_num;
51228 + if (ep->dwc_ep.bInterval > 1) {
51229 + depctl.d32 = 0;
51230 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
51231 + if (ep->dwc_ep.frame_num & 0x1) {
51232 + depctl.b.setd1pid = 1;
51233 + depctl.b.setd0pid = 0;
51234 + } else {
51235 + depctl.b.setd0pid = 1;
51236 + depctl.b.setd1pid = 0;
51237 + }
51238 + DWC_WRITE_REG32(&dev_if->in_ep_regs[epnum]->diepctl, depctl.d32);
51239 + }
51240 + start_next_request(ep);
51241 + }
51242 + ep->dwc_ep.frame_num += ep->dwc_ep.bInterval;
51243 + if (dwc_ep->frame_num > 0x3FFF) {
51244 + dwc_ep->frm_overrun = 1;
51245 + dwc_ep->frame_num &= 0x3FFF;
51246 + } else
51247 + dwc_ep->frm_overrun = 0;
51248 + }
51249 +
51250 + CLEAR_IN_EP_INTR(core_if, epnum, nak);
51251 + }
51252 + }
51253 + epnum++;
51254 + ep_intr >>= 1;
51255 + }
51256 +
51257 + return 1;
51258 +#undef CLEAR_IN_EP_INTR
51259 +}
51260 +
51261 +/**
51262 + * This interrupt indicates that an OUT EP has a pending Interrupt.
51263 + * The sequence for handling the OUT EP interrupt is shown below:
51264 + * -# Read the Device All Endpoint Interrupt register
51265 + * -# Repeat the following for each OUT EP interrupt bit set (from
51266 + * LSB to MSB).
51267 + * -# Read the Device Endpoint Interrupt (DOEPINTn) register
51268 + * -# If "Transfer Complete" call the request complete function
51269 + * -# If "Endpoint Disabled" complete the EP disable procedure.
51270 + * -# If "AHB Error Interrupt" log error
51271 + * -# If "Setup Phase Done" process Setup Packet (See Standard USB
51272 + * Command Processing)
51273 + */
51274 +static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd)
51275 +{
51276 +#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
51277 +do { \
51278 + doepint_data_t doepint = {.d32=0}; \
51279 + doepint.b.__intr = 1; \
51280 + DWC_WRITE_REG32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
51281 + doepint.d32); \
51282 +} while (0)
51283 +
51284 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
51285 + uint32_t ep_intr;
51286 + doepint_data_t doepint = {.d32 = 0 };
51287 + uint32_t epnum = 0;
51288 + dwc_otg_pcd_ep_t *ep;
51289 + dwc_ep_t *dwc_ep;
51290 + dctl_data_t dctl = {.d32 = 0 };
51291 + gintmsk_data_t gintmsk = {.d32 = 0 };
51292 +
51293 +
51294 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
51295 +
51296 + /* Read in the device interrupt bits */
51297 + ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if);
51298 +
51299 + while (ep_intr) {
51300 + if (ep_intr & 0x1) {
51301 + /* Get EP pointer */
51302 + ep = get_out_ep(pcd, epnum);
51303 + dwc_ep = &ep->dwc_ep;
51304 +
51305 +#ifdef VERBOSE
51306 + DWC_DEBUGPL(DBG_PCDV,
51307 + "EP%d-%s: type=%d, mps=%d\n",
51308 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
51309 + dwc_ep->type, dwc_ep->maxpacket);
51310 +#endif
51311 + doepint.d32 =
51312 + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
51313 + /* Moved this interrupt upper due to core deffect of asserting
51314 + * OUT EP 0 xfercompl along with stsphsrcvd in BDMA */
51315 + if (doepint.b.stsphsercvd) {
51316 + deptsiz0_data_t deptsiz;
51317 + CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd);
51318 + deptsiz.d32 =
51319 + DWC_READ_REG32(&core_if->dev_if->
51320 + out_ep_regs[0]->doeptsiz);
51321 + if (core_if->snpsid >= OTG_CORE_REV_3_00a
51322 + && core_if->dma_enable
51323 + && core_if->dma_desc_enable == 0
51324 + && doepint.b.xfercompl
51325 + && deptsiz.b.xfersize == 24) {
51326 + CLEAR_OUT_EP_INTR(core_if, epnum,
51327 + xfercompl);
51328 + doepint.b.xfercompl = 0;
51329 + ep0_out_start(core_if, pcd);
51330 + }
51331 + if ((core_if->dma_desc_enable) ||
51332 + (core_if->dma_enable
51333 + && core_if->snpsid >=
51334 + OTG_CORE_REV_3_00a)) {
51335 + do_setup_in_status_phase(pcd);
51336 + }
51337 + }
51338 + /* Transfer complete */
51339 + if (doepint.b.xfercompl) {
51340 +
51341 + if (epnum == 0) {
51342 + /* Clear the bit in DOEPINTn for this interrupt */
51343 + CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
51344 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
51345 + DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
51346 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepint),
51347 + doepint.d32);
51348 + DWC_DEBUGPL(DBG_PCDV, "DOEPCTL=%x \n",
51349 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepctl));
51350 +
51351 + if (core_if->snpsid >= OTG_CORE_REV_3_00a
51352 + && core_if->dma_enable == 0) {
51353 + doepint_data_t doepint;
51354 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51355 + out_ep_regs[0]->doepint);
51356 + if (pcd->ep0state == EP0_IDLE && doepint.b.sr) {
51357 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51358 + goto exit_xfercompl;
51359 + }
51360 + }
51361 + /* In case of DDMA look at SR bit to go to the Data Stage */
51362 + if (core_if->dma_desc_enable) {
51363 + dev_dma_desc_sts_t status = {.d32 = 0};
51364 + if (pcd->ep0state == EP0_IDLE) {
51365 + status.d32 = core_if->dev_if->setup_desc_addr[core_if->
51366 + dev_if->setup_desc_index]->status.d32;
51367 + if(pcd->data_terminated) {
51368 + pcd->data_terminated = 0;
51369 + status.d32 = core_if->dev_if->out_desc_addr->status.d32;
51370 + dwc_memcpy(&pcd->setup_pkt->req, pcd->backup_buf, 8);
51371 + }
51372 + if (status.b.sr) {
51373 + if (doepint.b.setup) {
51374 + DWC_DEBUGPL(DBG_PCDV, "DMA DESC EP0_IDLE SR=1 setup=1\n");
51375 + /* Already started data stage, clear setup */
51376 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51377 + doepint.b.setup = 0;
51378 + handle_ep0(pcd);
51379 + /* Prepare for more setup packets */
51380 + if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
51381 + pcd->ep0state == EP0_IN_DATA_PHASE) {
51382 + ep0_out_start(core_if, pcd);
51383 + }
51384 +
51385 + goto exit_xfercompl;
51386 + } else {
51387 + /* Prepare for more setup packets */
51388 + DWC_DEBUGPL(DBG_PCDV,
51389 + "EP0_IDLE SR=1 setup=0 new setup comes\n");
51390 + ep0_out_start(core_if, pcd);
51391 + }
51392 + }
51393 + } else {
51394 + dwc_otg_pcd_request_t *req;
51395 + dev_dma_desc_sts_t status = {.d32 = 0};
51396 + diepint_data_t diepint0;
51397 + diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
51398 + in_ep_regs[0]->diepint);
51399 +
51400 + if (pcd->ep0state == EP0_STALL || pcd->ep0state == EP0_DISCONNECT) {
51401 + DWC_ERROR("EP0 is stalled/disconnected\n");
51402 + }
51403 +
51404 + /* Clear IN xfercompl if set */
51405 + if (diepint0.b.xfercompl && (pcd->ep0state == EP0_IN_STATUS_PHASE
51406 + || pcd->ep0state == EP0_IN_DATA_PHASE)) {
51407 + DWC_WRITE_REG32(&core_if->dev_if->
51408 + in_ep_regs[0]->diepint, diepint0.d32);
51409 + }
51410 +
51411 + status.d32 = core_if->dev_if->setup_desc_addr[core_if->
51412 + dev_if->setup_desc_index]->status.d32;
51413 +
51414 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len
51415 + && (pcd->ep0state == EP0_OUT_DATA_PHASE))
51416 + status.d32 = core_if->dev_if->out_desc_addr->status.d32;
51417 + if (pcd->ep0state == EP0_OUT_STATUS_PHASE)
51418 + status.d32 = status.d32 = core_if->dev_if->
51419 + out_desc_addr->status.d32;
51420 +
51421 + if (status.b.sr) {
51422 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51423 + DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
51424 + } else {
51425 + DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
51426 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51427 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
51428 + pcd->ep0state == EP0_OUT_DATA_PHASE) {
51429 + /* Read arrived setup packet from req->buf */
51430 + dwc_memcpy(&pcd->setup_pkt->req,
51431 + req->buf + ep->dwc_ep.xfer_count, 8);
51432 + }
51433 + req->actual = ep->dwc_ep.xfer_count;
51434 + dwc_otg_request_done(ep, req, -ECONNRESET);
51435 + ep->dwc_ep.start_xfer_buff = 0;
51436 + ep->dwc_ep.xfer_buff = 0;
51437 + ep->dwc_ep.xfer_len = 0;
51438 + }
51439 + pcd->ep0state = EP0_IDLE;
51440 + if (doepint.b.setup) {
51441 + DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
51442 + /* Data stage started, clear setup */
51443 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51444 + doepint.b.setup = 0;
51445 + handle_ep0(pcd);
51446 + /* Prepare for setup packets if ep0in was enabled*/
51447 + if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
51448 + ep0_out_start(core_if, pcd);
51449 + }
51450 +
51451 + goto exit_xfercompl;
51452 + } else {
51453 + /* Prepare for more setup packets */
51454 + DWC_DEBUGPL(DBG_PCDV,
51455 + "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
51456 + ep0_out_start(core_if, pcd);
51457 + }
51458 + }
51459 + }
51460 + }
51461 + if (core_if->snpsid >= OTG_CORE_REV_2_94a && core_if->dma_enable
51462 + && core_if->dma_desc_enable == 0) {
51463 + doepint_data_t doepint_temp = {.d32 = 0};
51464 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
51465 + doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
51466 + out_ep_regs[ep->dwc_ep.num]->doepint);
51467 + doeptsize0.d32 = DWC_READ_REG32(&core_if->dev_if->
51468 + out_ep_regs[ep->dwc_ep.num]->doeptsiz);
51469 + if (pcd->ep0state == EP0_IDLE) {
51470 + if (doepint_temp.b.sr) {
51471 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51472 + }
51473 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51474 + out_ep_regs[0]->doepint);
51475 + if (doeptsize0.b.supcnt == 3) {
51476 + DWC_DEBUGPL(DBG_ANY, "Rolling over!!!!!!!\n");
51477 + ep->dwc_ep.stp_rollover = 1;
51478 + }
51479 + if (doepint.b.setup) {
51480 +retry:
51481 + /* Already started data stage, clear setup */
51482 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51483 + doepint.b.setup = 0;
51484 + handle_ep0(pcd);
51485 + ep->dwc_ep.stp_rollover = 0;
51486 + /* Prepare for more setup packets */
51487 + if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
51488 + pcd->ep0state == EP0_IN_DATA_PHASE) {
51489 + ep0_out_start(core_if, pcd);
51490 + }
51491 + goto exit_xfercompl;
51492 + } else {
51493 + /* Prepare for more setup packets */
51494 + DWC_DEBUGPL(DBG_ANY,
51495 + "EP0_IDLE SR=1 setup=0 new setup comes\n");
51496 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51497 + out_ep_regs[0]->doepint);
51498 + if(doepint.b.setup)
51499 + goto retry;
51500 + ep0_out_start(core_if, pcd);
51501 + }
51502 + } else {
51503 + dwc_otg_pcd_request_t *req;
51504 + diepint_data_t diepint0 = {.d32 = 0};
51505 + doepint_data_t doepint_temp = {.d32 = 0};
51506 + depctl_data_t diepctl0;
51507 + diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
51508 + in_ep_regs[0]->diepint);
51509 + diepctl0.d32 = DWC_READ_REG32(&core_if->dev_if->
51510 + in_ep_regs[0]->diepctl);
51511 +
51512 + if (pcd->ep0state == EP0_IN_DATA_PHASE
51513 + || pcd->ep0state == EP0_IN_STATUS_PHASE) {
51514 + if (diepint0.b.xfercompl) {
51515 + DWC_WRITE_REG32(&core_if->dev_if->
51516 + in_ep_regs[0]->diepint, diepint0.d32);
51517 + }
51518 + if (diepctl0.b.epena) {
51519 + diepint_data_t diepint = {.d32 = 0};
51520 + diepctl0.b.snak = 1;
51521 + DWC_WRITE_REG32(&core_if->dev_if->
51522 + in_ep_regs[0]->diepctl, diepctl0.d32);
51523 + do {
51524 + dwc_udelay(10);
51525 + diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51526 + in_ep_regs[0]->diepint);
51527 + } while (!diepint.b.inepnakeff);
51528 + diepint.b.inepnakeff = 1;
51529 + DWC_WRITE_REG32(&core_if->dev_if->
51530 + in_ep_regs[0]->diepint, diepint.d32);
51531 + diepctl0.d32 = 0;
51532 + diepctl0.b.epdis = 1;
51533 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl,
51534 + diepctl0.d32);
51535 + do {
51536 + dwc_udelay(10);
51537 + diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51538 + in_ep_regs[0]->diepint);
51539 + } while (!diepint.b.epdisabled);
51540 + diepint.b.epdisabled = 1;
51541 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepint,
51542 + diepint.d32);
51543 + }
51544 + }
51545 + doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
51546 + out_ep_regs[ep->dwc_ep.num]->doepint);
51547 + if (doepint_temp.b.sr) {
51548 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51549 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51550 + DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
51551 + } else {
51552 + DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
51553 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51554 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
51555 + pcd->ep0state == EP0_OUT_DATA_PHASE) {
51556 + /* Read arrived setup packet from req->buf */
51557 + dwc_memcpy(&pcd->setup_pkt->req,
51558 + req->buf + ep->dwc_ep.xfer_count, 8);
51559 + }
51560 + req->actual = ep->dwc_ep.xfer_count;
51561 + dwc_otg_request_done(ep, req, -ECONNRESET);
51562 + ep->dwc_ep.start_xfer_buff = 0;
51563 + ep->dwc_ep.xfer_buff = 0;
51564 + ep->dwc_ep.xfer_len = 0;
51565 + }
51566 + pcd->ep0state = EP0_IDLE;
51567 + if (doepint.b.setup) {
51568 + DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
51569 + /* Data stage started, clear setup */
51570 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51571 + doepint.b.setup = 0;
51572 + handle_ep0(pcd);
51573 + /* Prepare for setup packets if ep0in was enabled*/
51574 + if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
51575 + ep0_out_start(core_if, pcd);
51576 + }
51577 + goto exit_xfercompl;
51578 + } else {
51579 + /* Prepare for more setup packets */
51580 + DWC_DEBUGPL(DBG_PCDV,
51581 + "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
51582 + ep0_out_start(core_if, pcd);
51583 + }
51584 + }
51585 + }
51586 + }
51587 + if (core_if->dma_enable == 0 || pcd->ep0state != EP0_IDLE)
51588 + handle_ep0(pcd);
51589 +exit_xfercompl:
51590 + DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
51591 + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep), doepint.d32);
51592 + } else {
51593 + if (core_if->dma_desc_enable == 0
51594 + || pcd->ep0state != EP0_IDLE)
51595 + handle_ep0(pcd);
51596 + }
51597 +#ifdef DWC_EN_ISOC
51598 + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51599 + if (doepint.b.pktdrpsts == 0) {
51600 + /* Clear the bit in DOEPINTn for this interrupt */
51601 + CLEAR_OUT_EP_INTR(core_if,
51602 + epnum,
51603 + xfercompl);
51604 + complete_iso_ep(pcd, ep);
51605 + } else {
51606 +
51607 + doepint_data_t doepint = {.d32 = 0 };
51608 + doepint.b.xfercompl = 1;
51609 + doepint.b.pktdrpsts = 1;
51610 + DWC_WRITE_REG32
51611 + (&core_if->dev_if->out_ep_regs
51612 + [epnum]->doepint,
51613 + doepint.d32);
51614 + if (handle_iso_out_pkt_dropped
51615 + (core_if, dwc_ep)) {
51616 + complete_iso_ep(pcd,
51617 + ep);
51618 + }
51619 + }
51620 +#endif /* DWC_EN_ISOC */
51621 +#ifdef DWC_UTE_PER_IO
51622 + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51623 + CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
51624 + if (!ep->stopped)
51625 + complete_xiso_ep(ep);
51626 +#endif /* DWC_UTE_PER_IO */
51627 + } else {
51628 + /* Clear the bit in DOEPINTn for this interrupt */
51629 + CLEAR_OUT_EP_INTR(core_if, epnum,
51630 + xfercompl);
51631 +
51632 + if (core_if->core_params->dev_out_nak) {
51633 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[epnum]);
51634 + pcd->core_if->ep_xfer_info[epnum].state = 0;
51635 +#ifdef DEBUG
51636 + print_memory_payload(pcd, dwc_ep);
51637 +#endif
51638 + }
51639 + complete_ep(ep);
51640 + }
51641 +
51642 + }
51643 +
51644 + /* Endpoint disable */
51645 + if (doepint.b.epdisabled) {
51646 +
51647 + /* Clear the bit in DOEPINTn for this interrupt */
51648 + CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled);
51649 + if (core_if->core_params->dev_out_nak) {
51650 +#ifdef DEBUG
51651 + print_memory_payload(pcd, dwc_ep);
51652 +#endif
51653 + /* In case of timeout condition */
51654 + if (core_if->ep_xfer_info[epnum].state == 2) {
51655 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51656 + dev_global_regs->dctl);
51657 + dctl.b.cgoutnak = 1;
51658 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
51659 + dctl.d32);
51660 + /* Unmask goutnakeff interrupt which was masked
51661 + * during handle nak out interrupt */
51662 + gintmsk.b.goutnakeff = 1;
51663 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
51664 + 0, gintmsk.d32);
51665 +
51666 + complete_ep(ep);
51667 + }
51668 + }
51669 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
51670 + {
51671 + dctl_data_t dctl;
51672 + gintmsk_data_t intr_mask = {.d32 = 0};
51673 + dwc_otg_pcd_request_t *req = 0;
51674 +
51675 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51676 + dev_global_regs->dctl);
51677 + dctl.b.cgoutnak = 1;
51678 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
51679 + dctl.d32);
51680 +
51681 + intr_mask.d32 = 0;
51682 + intr_mask.b.incomplisoout = 1;
51683 +
51684 + /* Get any pending requests */
51685 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51686 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51687 + if (!req) {
51688 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
51689 + } else {
51690 + dwc_otg_request_done(ep, req, 0);
51691 + start_next_request(ep);
51692 + }
51693 + } else {
51694 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
51695 + }
51696 + }
51697 + }
51698 + /* AHB Error */
51699 + if (doepint.b.ahberr) {
51700 + DWC_ERROR("EP%d OUT AHB Error\n", epnum);
51701 + DWC_ERROR("EP%d DEPDMA=0x%08x \n",
51702 + epnum, core_if->dev_if->out_ep_regs[epnum]->doepdma);
51703 + CLEAR_OUT_EP_INTR(core_if, epnum, ahberr);
51704 + }
51705 + /* Setup Phase Done (contorl EPs) */
51706 + if (doepint.b.setup) {
51707 +#ifdef DEBUG_EP0
51708 + DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n", epnum);
51709 +#endif
51710 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51711 +
51712 + handle_ep0(pcd);
51713 + }
51714 +
51715 + /** OUT EP BNA Intr */
51716 + if (doepint.b.bna) {
51717 + CLEAR_OUT_EP_INTR(core_if, epnum, bna);
51718 + if (core_if->dma_desc_enable) {
51719 +#ifdef DWC_EN_ISOC
51720 + if (dwc_ep->type ==
51721 + DWC_OTG_EP_TYPE_ISOC) {
51722 + /*
51723 + * This checking is performed to prevent first "false" BNA
51724 + * handling occuring right after reconnect
51725 + */
51726 + if (dwc_ep->next_frame !=
51727 + 0xffffffff)
51728 + dwc_otg_pcd_handle_iso_bna(ep);
51729 + } else
51730 +#endif /* DWC_EN_ISOC */
51731 + {
51732 + dwc_otg_pcd_handle_noniso_bna(ep);
51733 + }
51734 + }
51735 + }
51736 + /* Babble Interrupt */
51737 + if (doepint.b.babble) {
51738 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n",
51739 + epnum);
51740 + handle_out_ep_babble_intr(pcd, epnum);
51741 +
51742 + CLEAR_OUT_EP_INTR(core_if, epnum, babble);
51743 + }
51744 + if (doepint.b.outtknepdis) {
51745 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Token received when EP is \
51746 + disabled\n",epnum);
51747 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
51748 + doepmsk_data_t doepmsk = {.d32 = 0};
51749 + ep->dwc_ep.frame_num = core_if->frame_num;
51750 + if (ep->dwc_ep.bInterval > 1) {
51751 + depctl_data_t depctl;
51752 + depctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51753 + out_ep_regs[epnum]->doepctl);
51754 + if (ep->dwc_ep.frame_num & 0x1) {
51755 + depctl.b.setd1pid = 1;
51756 + depctl.b.setd0pid = 0;
51757 + } else {
51758 + depctl.b.setd0pid = 1;
51759 + depctl.b.setd1pid = 0;
51760 + }
51761 + DWC_WRITE_REG32(&core_if->dev_if->
51762 + out_ep_regs[epnum]->doepctl, depctl.d32);
51763 + }
51764 + start_next_request(ep);
51765 + doepmsk.b.outtknepdis = 1;
51766 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51767 + doepmsk.d32, 0);
51768 + }
51769 + CLEAR_OUT_EP_INTR(core_if, epnum, outtknepdis);
51770 + }
51771 +
51772 + /* NAK Interrutp */
51773 + if (doepint.b.nak) {
51774 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum);
51775 + handle_out_ep_nak_intr(pcd, epnum);
51776 +
51777 + CLEAR_OUT_EP_INTR(core_if, epnum, nak);
51778 + }
51779 + /* NYET Interrutp */
51780 + if (doepint.b.nyet) {
51781 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum);
51782 + handle_out_ep_nyet_intr(pcd, epnum);
51783 +
51784 + CLEAR_OUT_EP_INTR(core_if, epnum, nyet);
51785 + }
51786 + }
51787 +
51788 + epnum++;
51789 + ep_intr >>= 1;
51790 + }
51791 +
51792 + return 1;
51793 +
51794 +#undef CLEAR_OUT_EP_INTR
51795 +}
51796 +static int drop_transfer(uint32_t trgt_fr, uint32_t curr_fr, uint8_t frm_overrun)
51797 +{
51798 + int retval = 0;
51799 + if(!frm_overrun && curr_fr >= trgt_fr)
51800 + retval = 1;
51801 + else if (frm_overrun
51802 + && (curr_fr >= trgt_fr && ((curr_fr - trgt_fr) < 0x3FFF / 2)))
51803 + retval = 1;
51804 + return retval;
51805 +}
51806 +/**
51807 + * Incomplete ISO IN Transfer Interrupt.
51808 + * This interrupt indicates one of the following conditions occurred
51809 + * while transmitting an ISOC transaction.
51810 + * - Corrupted IN Token for ISOC EP.
51811 + * - Packet not complete in FIFO.
51812 + * The follow actions will be taken:
51813 + * -# Determine the EP
51814 + * -# Set incomplete flag in dwc_ep structure
51815 + * -# Disable EP; when "Endpoint Disabled" interrupt is received
51816 + * Flush FIFO
51817 + */
51818 +int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd)
51819 +{
51820 + gintsts_data_t gintsts;
51821 +
51822 +#ifdef DWC_EN_ISOC
51823 + dwc_otg_dev_if_t *dev_if;
51824 + deptsiz_data_t deptsiz = {.d32 = 0 };
51825 + depctl_data_t depctl = {.d32 = 0 };
51826 + dsts_data_t dsts = {.d32 = 0 };
51827 + dwc_ep_t *dwc_ep;
51828 + int i;
51829 +
51830 + dev_if = GET_CORE_IF(pcd)->dev_if;
51831 +
51832 + for (i = 1; i <= dev_if->num_in_eps; ++i) {
51833 + dwc_ep = &pcd->in_ep[i].dwc_ep;
51834 + if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51835 + deptsiz.d32 =
51836 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
51837 + depctl.d32 =
51838 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
51839 +
51840 + if (depctl.b.epdis && deptsiz.d32) {
51841 + set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep);
51842 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
51843 + dwc_ep->cur_pkt = 0;
51844 + dwc_ep->proc_buf_num =
51845 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
51846 +
51847 + if (dwc_ep->proc_buf_num) {
51848 + dwc_ep->cur_pkt_addr =
51849 + dwc_ep->xfer_buff1;
51850 + dwc_ep->cur_pkt_dma_addr =
51851 + dwc_ep->dma_addr1;
51852 + } else {
51853 + dwc_ep->cur_pkt_addr =
51854 + dwc_ep->xfer_buff0;
51855 + dwc_ep->cur_pkt_dma_addr =
51856 + dwc_ep->dma_addr0;
51857 + }
51858 +
51859 + }
51860 +
51861 + dsts.d32 =
51862 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
51863 + dev_global_regs->dsts);
51864 + dwc_ep->next_frame = dsts.b.soffn;
51865 +
51866 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
51867 + (pcd),
51868 + dwc_ep);
51869 + }
51870 + }
51871 + }
51872 +
51873 +#else
51874 + depctl_data_t depctl = {.d32 = 0 };
51875 + dwc_ep_t *dwc_ep;
51876 + dwc_otg_dev_if_t *dev_if;
51877 + int i;
51878 + dev_if = GET_CORE_IF(pcd)->dev_if;
51879 +
51880 + DWC_DEBUGPL(DBG_PCD,"Incomplete ISO IN \n");
51881 +
51882 + for (i = 1; i <= dev_if->num_in_eps; ++i) {
51883 + dwc_ep = &pcd->in_ep[i-1].dwc_ep;
51884 + depctl.d32 =
51885 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
51886 + if (depctl.b.epena && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51887 + if (drop_transfer(dwc_ep->frame_num, GET_CORE_IF(pcd)->frame_num,
51888 + dwc_ep->frm_overrun))
51889 + {
51890 + depctl.d32 =
51891 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
51892 + depctl.b.snak = 1;
51893 + depctl.b.epdis = 1;
51894 + DWC_MODIFY_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32, depctl.d32);
51895 + }
51896 + }
51897 + }
51898 +
51899 + /*intr_mask.b.incomplisoin = 1;
51900 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
51901 + intr_mask.d32, 0); */
51902 +#endif //DWC_EN_ISOC
51903 +
51904 + /* Clear interrupt */
51905 + gintsts.d32 = 0;
51906 + gintsts.b.incomplisoin = 1;
51907 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
51908 + gintsts.d32);
51909 +
51910 + return 1;
51911 +}
51912 +
51913 +/**
51914 + * Incomplete ISO OUT Transfer Interrupt.
51915 + *
51916 + * This interrupt indicates that the core has dropped an ISO OUT
51917 + * packet. The following conditions can be the cause:
51918 + * - FIFO Full, the entire packet would not fit in the FIFO.
51919 + * - CRC Error
51920 + * - Corrupted Token
51921 + * The follow actions will be taken:
51922 + * -# Determine the EP
51923 + * -# Set incomplete flag in dwc_ep structure
51924 + * -# Read any data from the FIFO
51925 + * -# Disable EP. When "Endpoint Disabled" interrupt is received
51926 + * re-enable EP.
51927 + */
51928 +int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd)
51929 +{
51930 +
51931 + gintsts_data_t gintsts;
51932 +
51933 +#ifdef DWC_EN_ISOC
51934 + dwc_otg_dev_if_t *dev_if;
51935 + deptsiz_data_t deptsiz = {.d32 = 0 };
51936 + depctl_data_t depctl = {.d32 = 0 };
51937 + dsts_data_t dsts = {.d32 = 0 };
51938 + dwc_ep_t *dwc_ep;
51939 + int i;
51940 +
51941 + dev_if = GET_CORE_IF(pcd)->dev_if;
51942 +
51943 + for (i = 1; i <= dev_if->num_out_eps; ++i) {
51944 + dwc_ep = &pcd->in_ep[i].dwc_ep;
51945 + if (pcd->out_ep[i].dwc_ep.active &&
51946 + pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
51947 + deptsiz.d32 =
51948 + DWC_READ_REG32(&dev_if->out_ep_regs[i]->doeptsiz);
51949 + depctl.d32 =
51950 + DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
51951 +
51952 + if (depctl.b.epdis && deptsiz.d32) {
51953 + set_current_pkt_info(GET_CORE_IF(pcd),
51954 + &pcd->out_ep[i].dwc_ep);
51955 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
51956 + dwc_ep->cur_pkt = 0;
51957 + dwc_ep->proc_buf_num =
51958 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
51959 +
51960 + if (dwc_ep->proc_buf_num) {
51961 + dwc_ep->cur_pkt_addr =
51962 + dwc_ep->xfer_buff1;
51963 + dwc_ep->cur_pkt_dma_addr =
51964 + dwc_ep->dma_addr1;
51965 + } else {
51966 + dwc_ep->cur_pkt_addr =
51967 + dwc_ep->xfer_buff0;
51968 + dwc_ep->cur_pkt_dma_addr =
51969 + dwc_ep->dma_addr0;
51970 + }
51971 +
51972 + }
51973 +
51974 + dsts.d32 =
51975 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
51976 + dev_global_regs->dsts);
51977 + dwc_ep->next_frame = dsts.b.soffn;
51978 +
51979 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
51980 + (pcd),
51981 + dwc_ep);
51982 + }
51983 + }
51984 + }
51985 +#else
51986 + /** @todo implement ISR */
51987 + gintmsk_data_t intr_mask = {.d32 = 0 };
51988 + dwc_otg_core_if_t *core_if;
51989 + deptsiz_data_t deptsiz = {.d32 = 0 };
51990 + depctl_data_t depctl = {.d32 = 0 };
51991 + dctl_data_t dctl = {.d32 = 0 };
51992 + dwc_ep_t *dwc_ep = NULL;
51993 + int i;
51994 + core_if = GET_CORE_IF(pcd);
51995 +
51996 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
51997 + dwc_ep = &pcd->out_ep[i].dwc_ep;
51998 + depctl.d32 =
51999 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
52000 + if (depctl.b.epena && depctl.b.dpid == (core_if->frame_num & 0x1)) {
52001 + core_if->dev_if->isoc_ep = dwc_ep;
52002 + deptsiz.d32 =
52003 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz);
52004 + break;
52005 + }
52006 + }
52007 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
52008 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
52009 + intr_mask.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
52010 +
52011 + if (!intr_mask.b.goutnakeff) {
52012 + /* Unmask it */
52013 + intr_mask.b.goutnakeff = 1;
52014 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32);
52015 + }
52016 + if (!gintsts.b.goutnakeff) {
52017 + dctl.b.sgoutnak = 1;
52018 + }
52019 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
52020 +
52021 + depctl.d32 = DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
52022 + if (depctl.b.epena) {
52023 + depctl.b.epdis = 1;
52024 + depctl.b.snak = 1;
52025 + }
52026 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl, depctl.d32);
52027 +
52028 + intr_mask.d32 = 0;
52029 + intr_mask.b.incomplisoout = 1;
52030 +
52031 +#endif /* DWC_EN_ISOC */
52032 +
52033 + /* Clear interrupt */
52034 + gintsts.d32 = 0;
52035 + gintsts.b.incomplisoout = 1;
52036 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52037 + gintsts.d32);
52038 +
52039 + return 1;
52040 +}
52041 +
52042 +/**
52043 + * This function handles the Global IN NAK Effective interrupt.
52044 + *
52045 + */
52046 +int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd)
52047 +{
52048 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
52049 + depctl_data_t diepctl = {.d32 = 0 };
52050 + gintmsk_data_t intr_mask = {.d32 = 0 };
52051 + gintsts_data_t gintsts;
52052 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
52053 + int i;
52054 +
52055 + DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
52056 +
52057 + /* Disable all active IN EPs */
52058 + for (i = 0; i <= dev_if->num_in_eps; i++) {
52059 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52060 + if (!(diepctl.b.eptype & 1) && diepctl.b.epena) {
52061 + if (core_if->start_predict > 0)
52062 + core_if->start_predict++;
52063 + diepctl.b.epdis = 1;
52064 + diepctl.b.snak = 1;
52065 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, diepctl.d32);
52066 + }
52067 + }
52068 +
52069 +
52070 + /* Disable the Global IN NAK Effective Interrupt */
52071 + intr_mask.b.ginnakeff = 1;
52072 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52073 + intr_mask.d32, 0);
52074 +
52075 + /* Clear interrupt */
52076 + gintsts.d32 = 0;
52077 + gintsts.b.ginnakeff = 1;
52078 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52079 + gintsts.d32);
52080 +
52081 + return 1;
52082 +}
52083 +
52084 +/**
52085 + * OUT NAK Effective.
52086 + *
52087 + */
52088 +int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd)
52089 +{
52090 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
52091 + gintmsk_data_t intr_mask = {.d32 = 0 };
52092 + gintsts_data_t gintsts;
52093 + depctl_data_t doepctl;
52094 + int i;
52095 +
52096 + /* Disable the Global OUT NAK Effective Interrupt */
52097 + intr_mask.b.goutnakeff = 1;
52098 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52099 + intr_mask.d32, 0);
52100 +
52101 + /* If DEV OUT NAK enabled*/
52102 + if (pcd->core_if->core_params->dev_out_nak) {
52103 + /* Run over all out endpoints to determine the ep number on
52104 + * which the timeout has happened
52105 + */
52106 + for (i = 0; i <= dev_if->num_out_eps; i++) {
52107 + if ( pcd->core_if->ep_xfer_info[i].state == 2 )
52108 + break;
52109 + }
52110 + if (i > dev_if->num_out_eps) {
52111 + dctl_data_t dctl;
52112 + dctl.d32 =
52113 + DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
52114 + dctl.b.cgoutnak = 1;
52115 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl,
52116 + dctl.d32);
52117 + goto out;
52118 + }
52119 +
52120 + /* Disable the endpoint */
52121 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
52122 + if (doepctl.b.epena) {
52123 + doepctl.b.epdis = 1;
52124 + doepctl.b.snak = 1;
52125 + }
52126 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
52127 + return 1;
52128 + }
52129 + /* We come here from Incomplete ISO OUT handler */
52130 + if (dev_if->isoc_ep) {
52131 + dwc_ep_t *dwc_ep = (dwc_ep_t *)dev_if->isoc_ep;
52132 + uint32_t epnum = dwc_ep->num;
52133 + doepint_data_t doepint;
52134 + doepint.d32 =
52135 + DWC_READ_REG32(&dev_if->out_ep_regs[dwc_ep->num]->doepint);
52136 + dev_if->isoc_ep = NULL;
52137 + doepctl.d32 =
52138 + DWC_READ_REG32(&dev_if->out_ep_regs[epnum]->doepctl);
52139 + DWC_PRINTF("Before disable DOEPCTL = %08x\n", doepctl.d32);
52140 + if (doepctl.b.epena) {
52141 + doepctl.b.epdis = 1;
52142 + doepctl.b.snak = 1;
52143 + }
52144 + DWC_WRITE_REG32(&dev_if->out_ep_regs[epnum]->doepctl,
52145 + doepctl.d32);
52146 + return 1;
52147 + } else
52148 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
52149 + "Global OUT NAK Effective\n");
52150 +
52151 +out:
52152 + /* Clear interrupt */
52153 + gintsts.d32 = 0;
52154 + gintsts.b.goutnakeff = 1;
52155 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52156 + gintsts.d32);
52157 +
52158 + return 1;
52159 +}
52160 +
52161 +/**
52162 + * PCD interrupt handler.
52163 + *
52164 + * The PCD handles the device interrupts. Many conditions can cause a
52165 + * device interrupt. When an interrupt occurs, the device interrupt
52166 + * service routine determines the cause of the interrupt and
52167 + * dispatches handling to the appropriate function. These interrupt
52168 + * handling functions are described below.
52169 + *
52170 + * All interrupt registers are processed from LSB to MSB.
52171 + *
52172 + */
52173 +int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd)
52174 +{
52175 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
52176 +#ifdef VERBOSE
52177 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
52178 +#endif
52179 + gintsts_data_t gintr_status;
52180 + int32_t retval = 0;
52181 +
52182 + /* Exit from ISR if core is hibernated */
52183 + if (core_if->hibernation_suspend == 1) {
52184 + return retval;
52185 + }
52186 +#ifdef VERBOSE
52187 + DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x gintmsk=%08x\n",
52188 + __func__,
52189 + DWC_READ_REG32(&global_regs->gintsts),
52190 + DWC_READ_REG32(&global_regs->gintmsk));
52191 +#endif
52192 +
52193 + if (dwc_otg_is_device_mode(core_if)) {
52194 + DWC_SPINLOCK(pcd->lock);
52195 +#ifdef VERBOSE
52196 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x gintmsk=%08x\n",
52197 + __func__,
52198 + DWC_READ_REG32(&global_regs->gintsts),
52199 + DWC_READ_REG32(&global_regs->gintmsk));
52200 +#endif
52201 +
52202 + gintr_status.d32 = dwc_otg_read_core_intr(core_if);
52203 +
52204 + DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
52205 + __func__, gintr_status.d32);
52206 +
52207 + if (gintr_status.b.sofintr) {
52208 + retval |= dwc_otg_pcd_handle_sof_intr(pcd);
52209 + }
52210 + if (gintr_status.b.rxstsqlvl) {
52211 + retval |=
52212 + dwc_otg_pcd_handle_rx_status_q_level_intr(pcd);
52213 + }
52214 + if (gintr_status.b.nptxfempty) {
52215 + retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd);
52216 + }
52217 + if (gintr_status.b.goutnakeff) {
52218 + retval |= dwc_otg_pcd_handle_out_nak_effective(pcd);
52219 + }
52220 + if (gintr_status.b.i2cintr) {
52221 + retval |= dwc_otg_pcd_handle_i2c_intr(pcd);
52222 + }
52223 + if (gintr_status.b.erlysuspend) {
52224 + retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd);
52225 + }
52226 + if (gintr_status.b.usbreset) {
52227 + retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd);
52228 + }
52229 + if (gintr_status.b.enumdone) {
52230 + retval |= dwc_otg_pcd_handle_enum_done_intr(pcd);
52231 + }
52232 + if (gintr_status.b.isooutdrop) {
52233 + retval |=
52234 + dwc_otg_pcd_handle_isoc_out_packet_dropped_intr
52235 + (pcd);
52236 + }
52237 + if (gintr_status.b.eopframe) {
52238 + retval |=
52239 + dwc_otg_pcd_handle_end_periodic_frame_intr(pcd);
52240 + }
52241 + if (gintr_status.b.inepint) {
52242 + if (!core_if->multiproc_int_enable) {
52243 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
52244 + }
52245 + }
52246 + if (gintr_status.b.outepintr) {
52247 + if (!core_if->multiproc_int_enable) {
52248 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
52249 + }
52250 + }
52251 + if (gintr_status.b.epmismatch) {
52252 + retval |= dwc_otg_pcd_handle_ep_mismatch_intr(pcd);
52253 + }
52254 + if (gintr_status.b.fetsusp) {
52255 + retval |= dwc_otg_pcd_handle_ep_fetsusp_intr(pcd);
52256 + }
52257 + if (gintr_status.b.ginnakeff) {
52258 + retval |= dwc_otg_pcd_handle_in_nak_effective(pcd);
52259 + }
52260 + if (gintr_status.b.incomplisoin) {
52261 + retval |=
52262 + dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd);
52263 + }
52264 + if (gintr_status.b.incomplisoout) {
52265 + retval |=
52266 + dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd);
52267 + }
52268 +
52269 + /* In MPI mode Device Endpoints interrupts are asserted
52270 + * without setting outepintr and inepint bits set, so these
52271 + * Interrupt handlers are called without checking these bit-fields
52272 + */
52273 + if (core_if->multiproc_int_enable) {
52274 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
52275 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
52276 + }
52277 +#ifdef VERBOSE
52278 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
52279 + DWC_READ_REG32(&global_regs->gintsts));
52280 +#endif
52281 + DWC_SPINUNLOCK(pcd->lock);
52282 + }
52283 + return retval;
52284 +}
52285 +
52286 +#endif /* DWC_HOST_ONLY */
52287 --- /dev/null
52288 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
52289 @@ -0,0 +1,1358 @@
52290 + /* ==========================================================================
52291 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
52292 + * $Revision: #21 $
52293 + * $Date: 2012/08/10 $
52294 + * $Change: 2047372 $
52295 + *
52296 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
52297 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
52298 + * otherwise expressly agreed to in writing between Synopsys and you.
52299 + *
52300 + * The Software IS NOT an item of Licensed Software or Licensed Product under
52301 + * any End User Software License Agreement or Agreement for Licensed Product
52302 + * with Synopsys or any supplement thereto. You are permitted to use and
52303 + * redistribute this Software in source and binary forms, with or without
52304 + * modification, provided that redistributions of source code must retain this
52305 + * notice. You may not view, use, disclose, copy or distribute this file or
52306 + * any information contained herein except pursuant to this license grant from
52307 + * Synopsys. If you do not agree with this notice, including the disclaimer
52308 + * below, then you are not authorized to use the Software.
52309 + *
52310 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
52311 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52312 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52313 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
52314 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
52315 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
52316 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
52317 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52318 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52319 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
52320 + * DAMAGE.
52321 + * ========================================================================== */
52322 +#ifndef DWC_HOST_ONLY
52323 +
52324 +/** @file
52325 + * This file implements the Peripheral Controller Driver.
52326 + *
52327 + * The Peripheral Controller Driver (PCD) is responsible for
52328 + * translating requests from the Function Driver into the appropriate
52329 + * actions on the DWC_otg controller. It isolates the Function Driver
52330 + * from the specifics of the controller by providing an API to the
52331 + * Function Driver.
52332 + *
52333 + * The Peripheral Controller Driver for Linux will implement the
52334 + * Gadget API, so that the existing Gadget drivers can be used.
52335 + * (Gadget Driver is the Linux terminology for a Function Driver.)
52336 + *
52337 + * The Linux Gadget API is defined in the header file
52338 + * <code><linux/usb_gadget.h></code>. The USB EP operations API is
52339 + * defined in the structure <code>usb_ep_ops</code> and the USB
52340 + * Controller API is defined in the structure
52341 + * <code>usb_gadget_ops</code>.
52342 + *
52343 + */
52344 +
52345 +#include "dwc_otg_os_dep.h"
52346 +#include "dwc_otg_pcd_if.h"
52347 +#include "dwc_otg_pcd.h"
52348 +#include "dwc_otg_driver.h"
52349 +#include "dwc_otg_dbg.h"
52350 +
52351 +static struct gadget_wrapper {
52352 + dwc_otg_pcd_t *pcd;
52353 +
52354 + struct usb_gadget gadget;
52355 + struct usb_gadget_driver *driver;
52356 +
52357 + struct usb_ep ep0;
52358 + struct usb_ep in_ep[16];
52359 + struct usb_ep out_ep[16];
52360 +
52361 +} *gadget_wrapper;
52362 +
52363 +/* Display the contents of the buffer */
52364 +extern void dump_msg(const u8 * buf, unsigned int length);
52365 +/**
52366 + * Get the dwc_otg_pcd_ep_t* from usb_ep* pointer - NULL in case
52367 + * if the endpoint is not found
52368 + */
52369 +static struct dwc_otg_pcd_ep *ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
52370 +{
52371 + int i;
52372 + if (pcd->ep0.priv == handle) {
52373 + return &pcd->ep0;
52374 + }
52375 +
52376 + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
52377 + if (pcd->in_ep[i].priv == handle)
52378 + return &pcd->in_ep[i];
52379 + if (pcd->out_ep[i].priv == handle)
52380 + return &pcd->out_ep[i];
52381 + }
52382 +
52383 + return NULL;
52384 +}
52385 +
52386 +/* USB Endpoint Operations */
52387 +/*
52388 + * The following sections briefly describe the behavior of the Gadget
52389 + * API endpoint operations implemented in the DWC_otg driver
52390 + * software. Detailed descriptions of the generic behavior of each of
52391 + * these functions can be found in the Linux header file
52392 + * include/linux/usb_gadget.h.
52393 + *
52394 + * The Gadget API provides wrapper functions for each of the function
52395 + * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
52396 + * function, which then calls the underlying PCD function. The
52397 + * following sections are named according to the wrapper
52398 + * functions. Within each section, the corresponding DWC_otg PCD
52399 + * function name is specified.
52400 + *
52401 + */
52402 +
52403 +/**
52404 + * This function is called by the Gadget Driver for each EP to be
52405 + * configured for the current configuration (SET_CONFIGURATION).
52406 + *
52407 + * This function initializes the dwc_otg_ep_t data structure, and then
52408 + * calls dwc_otg_ep_activate.
52409 + */
52410 +static int ep_enable(struct usb_ep *usb_ep,
52411 + const struct usb_endpoint_descriptor *ep_desc)
52412 +{
52413 + int retval;
52414 +
52415 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
52416 +
52417 + if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
52418 + DWC_WARN("%s, bad ep or descriptor\n", __func__);
52419 + return -EINVAL;
52420 + }
52421 + if (usb_ep == &gadget_wrapper->ep0) {
52422 + DWC_WARN("%s, bad ep(0)\n", __func__);
52423 + return -EINVAL;
52424 + }
52425 +
52426 + /* Check FIFO size? */
52427 + if (!ep_desc->wMaxPacketSize) {
52428 + DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
52429 + return -ERANGE;
52430 + }
52431 +
52432 + if (!gadget_wrapper->driver ||
52433 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52434 + DWC_WARN("%s, bogus device state\n", __func__);
52435 + return -ESHUTDOWN;
52436 + }
52437 +
52438 + /* Delete after check - MAS */
52439 +#if 0
52440 + nat = (uint32_t) ep_desc->wMaxPacketSize;
52441 + printk(KERN_ALERT "%s: nat (before) =%d\n", __func__, nat);
52442 + nat = (nat >> 11) & 0x03;
52443 + printk(KERN_ALERT "%s: nat (after) =%d\n", __func__, nat);
52444 +#endif
52445 + retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
52446 + (const uint8_t *)ep_desc,
52447 + (void *)usb_ep);
52448 + if (retval) {
52449 + DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
52450 + return -EINVAL;
52451 + }
52452 +
52453 + usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
52454 +
52455 + return 0;
52456 +}
52457 +
52458 +/**
52459 + * This function is called when an EP is disabled due to disconnect or
52460 + * change in configuration. Any pending requests will terminate with a
52461 + * status of -ESHUTDOWN.
52462 + *
52463 + * This function modifies the dwc_otg_ep_t data structure for this EP,
52464 + * and then calls dwc_otg_ep_deactivate.
52465 + */
52466 +static int ep_disable(struct usb_ep *usb_ep)
52467 +{
52468 + int retval;
52469 +
52470 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
52471 + if (!usb_ep) {
52472 + DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
52473 + usb_ep ? usb_ep->name : NULL);
52474 + return -EINVAL;
52475 + }
52476 +
52477 + retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
52478 + if (retval) {
52479 + retval = -EINVAL;
52480 + }
52481 +
52482 + return retval;
52483 +}
52484 +
52485 +/**
52486 + * This function allocates a request object to use with the specified
52487 + * endpoint.
52488 + *
52489 + * @param ep The endpoint to be used with with the request
52490 + * @param gfp_flags the GFP_* flags to use.
52491 + */
52492 +static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
52493 + gfp_t gfp_flags)
52494 +{
52495 + struct usb_request *usb_req;
52496 +
52497 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
52498 + if (0 == ep) {
52499 + DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
52500 + return 0;
52501 + }
52502 + usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
52503 + if (0 == usb_req) {
52504 + DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
52505 + return 0;
52506 + }
52507 + memset(usb_req, 0, sizeof(*usb_req));
52508 + usb_req->dma = DWC_DMA_ADDR_INVALID;
52509 +
52510 + return usb_req;
52511 +}
52512 +
52513 +/**
52514 + * This function frees a request object.
52515 + *
52516 + * @param ep The endpoint associated with the request
52517 + * @param req The request being freed
52518 + */
52519 +static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
52520 +{
52521 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
52522 +
52523 + if (0 == ep || 0 == req) {
52524 + DWC_WARN("%s() %s\n", __func__,
52525 + "Invalid ep or req argument!\n");
52526 + return;
52527 + }
52528 +
52529 + kfree(req);
52530 +}
52531 +
52532 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52533 +/**
52534 + * This function allocates an I/O buffer to be used for a transfer
52535 + * to/from the specified endpoint.
52536 + *
52537 + * @param usb_ep The endpoint to be used with with the request
52538 + * @param bytes The desired number of bytes for the buffer
52539 + * @param dma Pointer to the buffer's DMA address; must be valid
52540 + * @param gfp_flags the GFP_* flags to use.
52541 + * @return address of a new buffer or null is buffer could not be allocated.
52542 + */
52543 +static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
52544 + dma_addr_t * dma, gfp_t gfp_flags)
52545 +{
52546 + void *buf;
52547 + dwc_otg_pcd_t *pcd = 0;
52548 +
52549 + pcd = gadget_wrapper->pcd;
52550 +
52551 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
52552 + dma, gfp_flags);
52553 +
52554 + /* Check dword alignment */
52555 + if ((bytes & 0x3UL) != 0) {
52556 + DWC_WARN("%s() Buffer size is not a multiple of"
52557 + "DWORD size (%d)", __func__, bytes);
52558 + }
52559 +
52560 + buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
52561 +
52562 + /* Check dword alignment */
52563 + if (((int)buf & 0x3UL) != 0) {
52564 + DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
52565 + __func__, buf);
52566 + }
52567 +
52568 + return buf;
52569 +}
52570 +
52571 +/**
52572 + * This function frees an I/O buffer that was allocated by alloc_buffer.
52573 + *
52574 + * @param usb_ep the endpoint associated with the buffer
52575 + * @param buf address of the buffer
52576 + * @param dma The buffer's DMA address
52577 + * @param bytes The number of bytes of the buffer
52578 + */
52579 +static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
52580 + dma_addr_t dma, unsigned bytes)
52581 +{
52582 + dwc_otg_pcd_t *pcd = 0;
52583 +
52584 + pcd = gadget_wrapper->pcd;
52585 +
52586 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
52587 +
52588 + dma_free_coherent(NULL, bytes, buf, dma);
52589 +}
52590 +#endif
52591 +
52592 +/**
52593 + * This function is used to submit an I/O Request to an EP.
52594 + *
52595 + * - When the request completes the request's completion callback
52596 + * is called to return the request to the driver.
52597 + * - An EP, except control EPs, may have multiple requests
52598 + * pending.
52599 + * - Once submitted the request cannot be examined or modified.
52600 + * - Each request is turned into one or more packets.
52601 + * - A BULK EP can queue any amount of data; the transfer is
52602 + * packetized.
52603 + * - Zero length Packets are specified with the request 'zero'
52604 + * flag.
52605 + */
52606 +static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
52607 + gfp_t gfp_flags)
52608 +{
52609 + dwc_otg_pcd_t *pcd;
52610 + struct dwc_otg_pcd_ep *ep = NULL;
52611 + int retval = 0, is_isoc_ep = 0;
52612 + dma_addr_t dma_addr = DWC_DMA_ADDR_INVALID;
52613 +
52614 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
52615 + __func__, usb_ep, usb_req, gfp_flags);
52616 +
52617 + if (!usb_req || !usb_req->complete || !usb_req->buf) {
52618 + DWC_WARN("bad params\n");
52619 + return -EINVAL;
52620 + }
52621 +
52622 + if (!usb_ep) {
52623 + DWC_WARN("bad ep\n");
52624 + return -EINVAL;
52625 + }
52626 +
52627 + pcd = gadget_wrapper->pcd;
52628 + if (!gadget_wrapper->driver ||
52629 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52630 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
52631 + gadget_wrapper->gadget.speed);
52632 + DWC_WARN("bogus device state\n");
52633 + return -ESHUTDOWN;
52634 + }
52635 +
52636 + DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
52637 + usb_ep->name, usb_req, usb_req->length, usb_req->buf);
52638 +
52639 + usb_req->status = -EINPROGRESS;
52640 + usb_req->actual = 0;
52641 +
52642 + ep = ep_from_handle(pcd, usb_ep);
52643 + if (ep == NULL)
52644 + is_isoc_ep = 0;
52645 + else
52646 + is_isoc_ep = (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ? 1 : 0;
52647 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52648 + dma_addr = usb_req->dma;
52649 +#else
52650 + if (GET_CORE_IF(pcd)->dma_enable) {
52651 + dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
52652 + struct device *dev = NULL;
52653 +
52654 + if (otg_dev != NULL)
52655 + dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
52656 +
52657 + if (usb_req->length != 0 &&
52658 + usb_req->dma == DWC_DMA_ADDR_INVALID) {
52659 + dma_addr = dma_map_single(dev, usb_req->buf,
52660 + usb_req->length,
52661 + ep->dwc_ep.is_in ?
52662 + DMA_TO_DEVICE:
52663 + DMA_FROM_DEVICE);
52664 + }
52665 + }
52666 +#endif
52667 +
52668 +#ifdef DWC_UTE_PER_IO
52669 + if (is_isoc_ep == 1) {
52670 + retval = dwc_otg_pcd_xiso_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
52671 + usb_req->length, usb_req->zero, usb_req,
52672 + gfp_flags == GFP_ATOMIC ? 1 : 0, &usb_req->ext_req);
52673 + if (retval)
52674 + return -EINVAL;
52675 +
52676 + return 0;
52677 + }
52678 +#endif
52679 + retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
52680 + usb_req->length, usb_req->zero, usb_req,
52681 + gfp_flags == GFP_ATOMIC ? 1 : 0);
52682 + if (retval) {
52683 + return -EINVAL;
52684 + }
52685 +
52686 + return 0;
52687 +}
52688 +
52689 +/**
52690 + * This function cancels an I/O request from an EP.
52691 + */
52692 +static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
52693 +{
52694 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
52695 +
52696 + if (!usb_ep || !usb_req) {
52697 + DWC_WARN("bad argument\n");
52698 + return -EINVAL;
52699 + }
52700 + if (!gadget_wrapper->driver ||
52701 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52702 + DWC_WARN("bogus device state\n");
52703 + return -ESHUTDOWN;
52704 + }
52705 + if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
52706 + return -EINVAL;
52707 + }
52708 +
52709 + return 0;
52710 +}
52711 +
52712 +/**
52713 + * usb_ep_set_halt stalls an endpoint.
52714 + *
52715 + * usb_ep_clear_halt clears an endpoint halt and resets its data
52716 + * toggle.
52717 + *
52718 + * Both of these functions are implemented with the same underlying
52719 + * function. The behavior depends on the value argument.
52720 + *
52721 + * @param[in] usb_ep the Endpoint to halt or clear halt.
52722 + * @param[in] value
52723 + * - 0 means clear_halt.
52724 + * - 1 means set_halt,
52725 + * - 2 means clear stall lock flag.
52726 + * - 3 means set stall lock flag.
52727 + */
52728 +static int ep_halt(struct usb_ep *usb_ep, int value)
52729 +{
52730 + int retval = 0;
52731 +
52732 + DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
52733 +
52734 + if (!usb_ep) {
52735 + DWC_WARN("bad ep\n");
52736 + return -EINVAL;
52737 + }
52738 +
52739 + retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
52740 + if (retval == -DWC_E_AGAIN) {
52741 + return -EAGAIN;
52742 + } else if (retval) {
52743 + retval = -EINVAL;
52744 + }
52745 +
52746 + return retval;
52747 +}
52748 +
52749 +//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
52750 +#if 0
52751 +/**
52752 + * ep_wedge: sets the halt feature and ignores clear requests
52753 + *
52754 + * @usb_ep: the endpoint being wedged
52755 + *
52756 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
52757 + * requests. If the gadget driver clears the halt status, it will
52758 + * automatically unwedge the endpoint.
52759 + *
52760 + * Returns zero on success, else negative errno. *
52761 + * Check usb_ep_set_wedge() at "usb_gadget.h" for details
52762 + */
52763 +static int ep_wedge(struct usb_ep *usb_ep)
52764 +{
52765 + int retval = 0;
52766 +
52767 + DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name);
52768 +
52769 + if (!usb_ep) {
52770 + DWC_WARN("bad ep\n");
52771 + return -EINVAL;
52772 + }
52773 +
52774 + retval = dwc_otg_pcd_ep_wedge(gadget_wrapper->pcd, usb_ep);
52775 + if (retval == -DWC_E_AGAIN) {
52776 + retval = -EAGAIN;
52777 + } else if (retval) {
52778 + retval = -EINVAL;
52779 + }
52780 +
52781 + return retval;
52782 +}
52783 +#endif
52784 +
52785 +#ifdef DWC_EN_ISOC
52786 +/**
52787 + * This function is used to submit an ISOC Transfer Request to an EP.
52788 + *
52789 + * - Every time a sync period completes the request's completion callback
52790 + * is called to provide data to the gadget driver.
52791 + * - Once submitted the request cannot be modified.
52792 + * - Each request is turned into periodic data packets untill ISO
52793 + * Transfer is stopped..
52794 + */
52795 +static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
52796 + gfp_t gfp_flags)
52797 +{
52798 + int retval = 0;
52799 +
52800 + if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
52801 + DWC_WARN("bad params\n");
52802 + return -EINVAL;
52803 + }
52804 +
52805 + if (!usb_ep) {
52806 + DWC_PRINTF("bad params\n");
52807 + return -EINVAL;
52808 + }
52809 +
52810 + req->status = -EINPROGRESS;
52811 +
52812 + retval =
52813 + dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
52814 + req->buf1, req->dma0, req->dma1,
52815 + req->sync_frame, req->data_pattern_frame,
52816 + req->data_per_frame,
52817 + req->
52818 + flags & USB_REQ_ISO_ASAP ? -1 :
52819 + req->start_frame, req->buf_proc_intrvl,
52820 + req, gfp_flags == GFP_ATOMIC ? 1 : 0);
52821 +
52822 + if (retval) {
52823 + return -EINVAL;
52824 + }
52825 +
52826 + return retval;
52827 +}
52828 +
52829 +/**
52830 + * This function stops ISO EP Periodic Data Transfer.
52831 + */
52832 +static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
52833 +{
52834 + int retval = 0;
52835 + if (!usb_ep) {
52836 + DWC_WARN("bad ep\n");
52837 + }
52838 +
52839 + if (!gadget_wrapper->driver ||
52840 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52841 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
52842 + gadget_wrapper->gadget.speed);
52843 + DWC_WARN("bogus device state\n");
52844 + }
52845 +
52846 + dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
52847 + if (retval) {
52848 + retval = -EINVAL;
52849 + }
52850 +
52851 + return retval;
52852 +}
52853 +
52854 +static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
52855 + int packets, gfp_t gfp_flags)
52856 +{
52857 + struct usb_iso_request *pReq = NULL;
52858 + uint32_t req_size;
52859 +
52860 + req_size = sizeof(struct usb_iso_request);
52861 + req_size +=
52862 + (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
52863 +
52864 + pReq = kmalloc(req_size, gfp_flags);
52865 + if (!pReq) {
52866 + DWC_WARN("Can't allocate Iso Request\n");
52867 + return 0;
52868 + }
52869 + pReq->iso_packet_desc0 = (void *)(pReq + 1);
52870 +
52871 + pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
52872 +
52873 + return pReq;
52874 +}
52875 +
52876 +static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
52877 +{
52878 + kfree(req);
52879 +}
52880 +
52881 +static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
52882 + .ep_ops = {
52883 + .enable = ep_enable,
52884 + .disable = ep_disable,
52885 +
52886 + .alloc_request = dwc_otg_pcd_alloc_request,
52887 + .free_request = dwc_otg_pcd_free_request,
52888 +
52889 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52890 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
52891 + .free_buffer = dwc_otg_pcd_free_buffer,
52892 +#endif
52893 +
52894 + .queue = ep_queue,
52895 + .dequeue = ep_dequeue,
52896 +
52897 + .set_halt = ep_halt,
52898 + .fifo_status = 0,
52899 + .fifo_flush = 0,
52900 + },
52901 + .iso_ep_start = iso_ep_start,
52902 + .iso_ep_stop = iso_ep_stop,
52903 + .alloc_iso_request = alloc_iso_request,
52904 + .free_iso_request = free_iso_request,
52905 +};
52906 +
52907 +#else
52908 +
52909 + int (*enable) (struct usb_ep *ep,
52910 + const struct usb_endpoint_descriptor *desc);
52911 + int (*disable) (struct usb_ep *ep);
52912 +
52913 + struct usb_request *(*alloc_request) (struct usb_ep *ep,
52914 + gfp_t gfp_flags);
52915 + void (*free_request) (struct usb_ep *ep, struct usb_request *req);
52916 +
52917 + int (*queue) (struct usb_ep *ep, struct usb_request *req,
52918 + gfp_t gfp_flags);
52919 + int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
52920 +
52921 + int (*set_halt) (struct usb_ep *ep, int value);
52922 + int (*set_wedge) (struct usb_ep *ep);
52923 +
52924 + int (*fifo_status) (struct usb_ep *ep);
52925 + void (*fifo_flush) (struct usb_ep *ep);
52926 +static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
52927 + .enable = ep_enable,
52928 + .disable = ep_disable,
52929 +
52930 + .alloc_request = dwc_otg_pcd_alloc_request,
52931 + .free_request = dwc_otg_pcd_free_request,
52932 +
52933 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52934 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
52935 + .free_buffer = dwc_otg_pcd_free_buffer,
52936 +#else
52937 + /* .set_wedge = ep_wedge, */
52938 + .set_wedge = NULL, /* uses set_halt instead */
52939 +#endif
52940 +
52941 + .queue = ep_queue,
52942 + .dequeue = ep_dequeue,
52943 +
52944 + .set_halt = ep_halt,
52945 + .fifo_status = 0,
52946 + .fifo_flush = 0,
52947 +
52948 +};
52949 +
52950 +#endif /* _EN_ISOC_ */
52951 +/* Gadget Operations */
52952 +/**
52953 + * The following gadget operations will be implemented in the DWC_otg
52954 + * PCD. Functions in the API that are not described below are not
52955 + * implemented.
52956 + *
52957 + * The Gadget API provides wrapper functions for each of the function
52958 + * pointers defined in usb_gadget_ops. The Gadget Driver calls the
52959 + * wrapper function, which then calls the underlying PCD function. The
52960 + * following sections are named according to the wrapper functions
52961 + * (except for ioctl, which doesn't have a wrapper function). Within
52962 + * each section, the corresponding DWC_otg PCD function name is
52963 + * specified.
52964 + *
52965 + */
52966 +
52967 +/**
52968 + *Gets the USB Frame number of the last SOF.
52969 + */
52970 +static int get_frame_number(struct usb_gadget *gadget)
52971 +{
52972 + struct gadget_wrapper *d;
52973 +
52974 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
52975 +
52976 + if (gadget == 0) {
52977 + return -ENODEV;
52978 + }
52979 +
52980 + d = container_of(gadget, struct gadget_wrapper, gadget);
52981 + return dwc_otg_pcd_get_frame_number(d->pcd);
52982 +}
52983 +
52984 +#ifdef CONFIG_USB_DWC_OTG_LPM
52985 +static int test_lpm_enabled(struct usb_gadget *gadget)
52986 +{
52987 + struct gadget_wrapper *d;
52988 +
52989 + d = container_of(gadget, struct gadget_wrapper, gadget);
52990 +
52991 + return dwc_otg_pcd_is_lpm_enabled(d->pcd);
52992 +}
52993 +#endif
52994 +
52995 +/**
52996 + * Initiates Session Request Protocol (SRP) to wakeup the host if no
52997 + * session is in progress. If a session is already in progress, but
52998 + * the device is suspended, remote wakeup signaling is started.
52999 + *
53000 + */
53001 +static int wakeup(struct usb_gadget *gadget)
53002 +{
53003 + struct gadget_wrapper *d;
53004 +
53005 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
53006 +
53007 + if (gadget == 0) {
53008 + return -ENODEV;
53009 + } else {
53010 + d = container_of(gadget, struct gadget_wrapper, gadget);
53011 + }
53012 + dwc_otg_pcd_wakeup(d->pcd);
53013 + return 0;
53014 +}
53015 +
53016 +static const struct usb_gadget_ops dwc_otg_pcd_ops = {
53017 + .get_frame = get_frame_number,
53018 + .wakeup = wakeup,
53019 +#ifdef CONFIG_USB_DWC_OTG_LPM
53020 + .lpm_support = test_lpm_enabled,
53021 +#endif
53022 + // current versions must always be self-powered
53023 +};
53024 +
53025 +static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
53026 +{
53027 + int retval = -DWC_E_NOT_SUPPORTED;
53028 + if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
53029 + retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
53030 + (struct usb_ctrlrequest
53031 + *)bytes);
53032 + }
53033 +
53034 + if (retval == -ENOTSUPP) {
53035 + retval = -DWC_E_NOT_SUPPORTED;
53036 + } else if (retval < 0) {
53037 + retval = -DWC_E_INVALID;
53038 + }
53039 +
53040 + return retval;
53041 +}
53042 +
53043 +#ifdef DWC_EN_ISOC
53044 +static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53045 + void *req_handle, int proc_buf_num)
53046 +{
53047 + int i, packet_count;
53048 + struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
53049 + struct usb_iso_request *iso_req = req_handle;
53050 +
53051 + if (proc_buf_num) {
53052 + iso_packet = iso_req->iso_packet_desc1;
53053 + } else {
53054 + iso_packet = iso_req->iso_packet_desc0;
53055 + }
53056 + packet_count =
53057 + dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
53058 + for (i = 0; i < packet_count; ++i) {
53059 + int status;
53060 + int actual;
53061 + int offset;
53062 + dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
53063 + i, &status, &actual, &offset);
53064 + switch (status) {
53065 + case -DWC_E_NO_DATA:
53066 + status = -ENODATA;
53067 + break;
53068 + default:
53069 + if (status) {
53070 + DWC_PRINTF("unknown status in isoc packet\n");
53071 + }
53072 +
53073 + }
53074 + iso_packet[i].status = status;
53075 + iso_packet[i].offset = offset;
53076 + iso_packet[i].actual_length = actual;
53077 + }
53078 +
53079 + iso_req->status = 0;
53080 + iso_req->process_buffer(ep_handle, iso_req);
53081 +
53082 + return 0;
53083 +}
53084 +#endif /* DWC_EN_ISOC */
53085 +
53086 +#ifdef DWC_UTE_PER_IO
53087 +/**
53088 + * Copy the contents of the extended request to the Linux usb_request's
53089 + * extended part and call the gadget's completion.
53090 + *
53091 + * @param pcd Pointer to the pcd structure
53092 + * @param ep_handle Void pointer to the usb_ep structure
53093 + * @param req_handle Void pointer to the usb_request structure
53094 + * @param status Request status returned from the portable logic
53095 + * @param ereq_port Void pointer to the extended request structure
53096 + * created in the the portable part that contains the
53097 + * results of the processed iso packets.
53098 + */
53099 +static int _xisoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53100 + void *req_handle, int32_t status, void *ereq_port)
53101 +{
53102 + struct dwc_ute_iso_req_ext *ereqorg = NULL;
53103 + struct dwc_iso_xreq_port *ereqport = NULL;
53104 + struct dwc_ute_iso_packet_descriptor *desc_org = NULL;
53105 + int i;
53106 + struct usb_request *req;
53107 + //struct dwc_ute_iso_packet_descriptor *
53108 + //int status = 0;
53109 +
53110 + req = (struct usb_request *)req_handle;
53111 + ereqorg = &req->ext_req;
53112 + ereqport = (struct dwc_iso_xreq_port *)ereq_port;
53113 + desc_org = ereqorg->per_io_frame_descs;
53114 +
53115 + if (req && req->complete) {
53116 + /* Copy the request data from the portable logic to our request */
53117 + for (i = 0; i < ereqport->pio_pkt_count; i++) {
53118 + desc_org[i].actual_length =
53119 + ereqport->per_io_frame_descs[i].actual_length;
53120 + desc_org[i].status =
53121 + ereqport->per_io_frame_descs[i].status;
53122 + }
53123 +
53124 + switch (status) {
53125 + case -DWC_E_SHUTDOWN:
53126 + req->status = -ESHUTDOWN;
53127 + break;
53128 + case -DWC_E_RESTART:
53129 + req->status = -ECONNRESET;
53130 + break;
53131 + case -DWC_E_INVALID:
53132 + req->status = -EINVAL;
53133 + break;
53134 + case -DWC_E_TIMEOUT:
53135 + req->status = -ETIMEDOUT;
53136 + break;
53137 + default:
53138 + req->status = status;
53139 + }
53140 +
53141 + /* And call the gadget's completion */
53142 + req->complete(ep_handle, req);
53143 + }
53144 +
53145 + return 0;
53146 +}
53147 +#endif /* DWC_UTE_PER_IO */
53148 +
53149 +static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53150 + void *req_handle, int32_t status, uint32_t actual)
53151 +{
53152 + struct usb_request *req = (struct usb_request *)req_handle;
53153 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
53154 + struct dwc_otg_pcd_ep *ep = NULL;
53155 +#endif
53156 +
53157 + if (req && req->complete) {
53158 + switch (status) {
53159 + case -DWC_E_SHUTDOWN:
53160 + req->status = -ESHUTDOWN;
53161 + break;
53162 + case -DWC_E_RESTART:
53163 + req->status = -ECONNRESET;
53164 + break;
53165 + case -DWC_E_INVALID:
53166 + req->status = -EINVAL;
53167 + break;
53168 + case -DWC_E_TIMEOUT:
53169 + req->status = -ETIMEDOUT;
53170 + break;
53171 + default:
53172 + req->status = status;
53173 +
53174 + }
53175 +
53176 + req->actual = actual;
53177 + DWC_SPINUNLOCK(pcd->lock);
53178 + req->complete(ep_handle, req);
53179 + DWC_SPINLOCK(pcd->lock);
53180 + }
53181 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
53182 + ep = ep_from_handle(pcd, ep_handle);
53183 + if (GET_CORE_IF(pcd)->dma_enable) {
53184 + if (req->length != 0) {
53185 + dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
53186 + struct device *dev = NULL;
53187 +
53188 + if (otg_dev != NULL)
53189 + dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
53190 +
53191 + dma_unmap_single(dev, req->dma, req->length,
53192 + ep->dwc_ep.is_in ?
53193 + DMA_TO_DEVICE: DMA_FROM_DEVICE);
53194 + }
53195 + }
53196 +#endif
53197 +
53198 + return 0;
53199 +}
53200 +
53201 +static int _connect(dwc_otg_pcd_t * pcd, int speed)
53202 +{
53203 + gadget_wrapper->gadget.speed = speed;
53204 + return 0;
53205 +}
53206 +
53207 +static int _disconnect(dwc_otg_pcd_t * pcd)
53208 +{
53209 + if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
53210 + gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
53211 + }
53212 + return 0;
53213 +}
53214 +
53215 +static int _resume(dwc_otg_pcd_t * pcd)
53216 +{
53217 + if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
53218 + gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
53219 + }
53220 +
53221 + return 0;
53222 +}
53223 +
53224 +static int _suspend(dwc_otg_pcd_t * pcd)
53225 +{
53226 + if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
53227 + gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
53228 + }
53229 + return 0;
53230 +}
53231 +
53232 +/**
53233 + * This function updates the otg values in the gadget structure.
53234 + */
53235 +static int _hnp_changed(dwc_otg_pcd_t * pcd)
53236 +{
53237 +
53238 + if (!gadget_wrapper->gadget.is_otg)
53239 + return 0;
53240 +
53241 + gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
53242 + gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
53243 + gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
53244 + return 0;
53245 +}
53246 +
53247 +static int _reset(dwc_otg_pcd_t * pcd)
53248 +{
53249 + return 0;
53250 +}
53251 +
53252 +#ifdef DWC_UTE_CFI
53253 +static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
53254 +{
53255 + int retval = -DWC_E_INVALID;
53256 + if (gadget_wrapper->driver->cfi_feature_setup) {
53257 + retval =
53258 + gadget_wrapper->driver->
53259 + cfi_feature_setup(&gadget_wrapper->gadget,
53260 + (struct cfi_usb_ctrlrequest *)cfi_req);
53261 + }
53262 +
53263 + return retval;
53264 +}
53265 +#endif
53266 +
53267 +static const struct dwc_otg_pcd_function_ops fops = {
53268 + .complete = _complete,
53269 +#ifdef DWC_EN_ISOC
53270 + .isoc_complete = _isoc_complete,
53271 +#endif
53272 + .setup = _setup,
53273 + .disconnect = _disconnect,
53274 + .connect = _connect,
53275 + .resume = _resume,
53276 + .suspend = _suspend,
53277 + .hnp_changed = _hnp_changed,
53278 + .reset = _reset,
53279 +#ifdef DWC_UTE_CFI
53280 + .cfi_setup = _cfi_setup,
53281 +#endif
53282 +#ifdef DWC_UTE_PER_IO
53283 + .xisoc_complete = _xisoc_complete,
53284 +#endif
53285 +};
53286 +
53287 +/**
53288 + * This function is the top level PCD interrupt handler.
53289 + */
53290 +static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
53291 +{
53292 + dwc_otg_pcd_t *pcd = dev;
53293 + int32_t retval = IRQ_NONE;
53294 +
53295 + retval = dwc_otg_pcd_handle_intr(pcd);
53296 + if (retval != 0) {
53297 + S3C2410X_CLEAR_EINTPEND();
53298 + }
53299 + return IRQ_RETVAL(retval);
53300 +}
53301 +
53302 +/**
53303 + * This function initialized the usb_ep structures to there default
53304 + * state.
53305 + *
53306 + * @param d Pointer on gadget_wrapper.
53307 + */
53308 +void gadget_add_eps(struct gadget_wrapper *d)
53309 +{
53310 + static const char *names[] = {
53311 +
53312 + "ep0",
53313 + "ep1in",
53314 + "ep2in",
53315 + "ep3in",
53316 + "ep4in",
53317 + "ep5in",
53318 + "ep6in",
53319 + "ep7in",
53320 + "ep8in",
53321 + "ep9in",
53322 + "ep10in",
53323 + "ep11in",
53324 + "ep12in",
53325 + "ep13in",
53326 + "ep14in",
53327 + "ep15in",
53328 + "ep1out",
53329 + "ep2out",
53330 + "ep3out",
53331 + "ep4out",
53332 + "ep5out",
53333 + "ep6out",
53334 + "ep7out",
53335 + "ep8out",
53336 + "ep9out",
53337 + "ep10out",
53338 + "ep11out",
53339 + "ep12out",
53340 + "ep13out",
53341 + "ep14out",
53342 + "ep15out"
53343 + };
53344 +
53345 + int i;
53346 + struct usb_ep *ep;
53347 + int8_t dev_endpoints;
53348 +
53349 + DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
53350 +
53351 + INIT_LIST_HEAD(&d->gadget.ep_list);
53352 + d->gadget.ep0 = &d->ep0;
53353 + d->gadget.speed = USB_SPEED_UNKNOWN;
53354 +
53355 + INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
53356 +
53357 + /**
53358 + * Initialize the EP0 structure.
53359 + */
53360 + ep = &d->ep0;
53361 +
53362 + /* Init the usb_ep structure. */
53363 + ep->name = names[0];
53364 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53365 +
53366 + /**
53367 + * @todo NGS: What should the max packet size be set to
53368 + * here? Before EP type is set?
53369 + */
53370 + ep->maxpacket = MAX_PACKET_SIZE;
53371 + dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
53372 +
53373 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53374 +
53375 + /**
53376 + * Initialize the EP structures.
53377 + */
53378 + dev_endpoints = d->pcd->core_if->dev_if->num_in_eps;
53379 +
53380 + for (i = 0; i < dev_endpoints; i++) {
53381 + ep = &d->in_ep[i];
53382 +
53383 + /* Init the usb_ep structure. */
53384 + ep->name = names[d->pcd->in_ep[i].dwc_ep.num];
53385 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53386 +
53387 + /**
53388 + * @todo NGS: What should the max packet size be set to
53389 + * here? Before EP type is set?
53390 + */
53391 + ep->maxpacket = MAX_PACKET_SIZE;
53392 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53393 + }
53394 +
53395 + dev_endpoints = d->pcd->core_if->dev_if->num_out_eps;
53396 +
53397 + for (i = 0; i < dev_endpoints; i++) {
53398 + ep = &d->out_ep[i];
53399 +
53400 + /* Init the usb_ep structure. */
53401 + ep->name = names[15 + d->pcd->out_ep[i].dwc_ep.num];
53402 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53403 +
53404 + /**
53405 + * @todo NGS: What should the max packet size be set to
53406 + * here? Before EP type is set?
53407 + */
53408 + ep->maxpacket = MAX_PACKET_SIZE;
53409 +
53410 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53411 + }
53412 +
53413 + /* remove ep0 from the list. There is a ep0 pointer. */
53414 + list_del_init(&d->ep0.ep_list);
53415 +
53416 + d->ep0.maxpacket = MAX_EP0_SIZE;
53417 +}
53418 +
53419 +/**
53420 + * This function releases the Gadget device.
53421 + * required by device_unregister().
53422 + *
53423 + * @todo Should this do something? Should it free the PCD?
53424 + */
53425 +static void dwc_otg_pcd_gadget_release(struct device *dev)
53426 +{
53427 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
53428 +}
53429 +
53430 +static struct gadget_wrapper *alloc_wrapper(dwc_bus_dev_t *_dev)
53431 +{
53432 + static char pcd_name[] = "dwc_otg_pcd";
53433 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53434 + struct gadget_wrapper *d;
53435 + int retval;
53436 +
53437 + d = DWC_ALLOC(sizeof(*d));
53438 + if (d == NULL) {
53439 + return NULL;
53440 + }
53441 +
53442 + memset(d, 0, sizeof(*d));
53443 +
53444 + d->gadget.name = pcd_name;
53445 + d->pcd = otg_dev->pcd;
53446 +
53447 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
53448 + strcpy(d->gadget.dev.bus_id, "gadget");
53449 +#else
53450 + dev_set_name(&d->gadget.dev, "%s", "gadget");
53451 +#endif
53452 +
53453 + d->gadget.dev.parent = &_dev->dev;
53454 + d->gadget.dev.release = dwc_otg_pcd_gadget_release;
53455 + d->gadget.ops = &dwc_otg_pcd_ops;
53456 + d->gadget.max_speed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd) ? USB_SPEED_HIGH:USB_SPEED_FULL;
53457 + d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
53458 +
53459 + d->driver = 0;
53460 + /* Register the gadget device */
53461 + retval = device_register(&d->gadget.dev);
53462 + if (retval != 0) {
53463 + DWC_ERROR("device_register failed\n");
53464 + DWC_FREE(d);
53465 + return NULL;
53466 + }
53467 +
53468 + return d;
53469 +}
53470 +
53471 +static void free_wrapper(struct gadget_wrapper *d)
53472 +{
53473 + if (d->driver) {
53474 + /* should have been done already by driver model core */
53475 + DWC_WARN("driver '%s' is still registered\n",
53476 + d->driver->driver.name);
53477 + usb_gadget_unregister_driver(d->driver);
53478 + }
53479 +
53480 + device_unregister(&d->gadget.dev);
53481 + DWC_FREE(d);
53482 +}
53483 +
53484 +/**
53485 + * This function initialized the PCD portion of the driver.
53486 + *
53487 + */
53488 +int pcd_init(dwc_bus_dev_t *_dev)
53489 +{
53490 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53491 + int retval = 0;
53492 +
53493 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev=%p\n", __func__, _dev, otg_dev);
53494 +
53495 + otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
53496 +
53497 + if (!otg_dev->pcd) {
53498 + DWC_ERROR("dwc_otg_pcd_init failed\n");
53499 + return -ENOMEM;
53500 + }
53501 +
53502 + otg_dev->pcd->otg_dev = otg_dev;
53503 + gadget_wrapper = alloc_wrapper(_dev);
53504 +
53505 + /*
53506 + * Initialize EP structures
53507 + */
53508 + gadget_add_eps(gadget_wrapper);
53509 + /*
53510 + * Setup interupt handler
53511 + */
53512 +#ifdef PLATFORM_INTERFACE
53513 + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
53514 + platform_get_irq(_dev, 0));
53515 + retval = request_irq(platform_get_irq(_dev, 0), dwc_otg_pcd_irq,
53516 + IRQF_SHARED, gadget_wrapper->gadget.name,
53517 + otg_dev->pcd);
53518 + if (retval != 0) {
53519 + DWC_ERROR("request of irq%d failed\n",
53520 + platform_get_irq(_dev, 0));
53521 + free_wrapper(gadget_wrapper);
53522 + return -EBUSY;
53523 + }
53524 +#else
53525 + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
53526 + _dev->irq);
53527 + retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
53528 + IRQF_SHARED | IRQF_DISABLED,
53529 + gadget_wrapper->gadget.name, otg_dev->pcd);
53530 + if (retval != 0) {
53531 + DWC_ERROR("request of irq%d failed\n", _dev->irq);
53532 + free_wrapper(gadget_wrapper);
53533 + return -EBUSY;
53534 + }
53535 +#endif
53536 +
53537 + dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
53538 +
53539 + return retval;
53540 +}
53541 +
53542 +/**
53543 + * Cleanup the PCD.
53544 + */
53545 +void pcd_remove(dwc_bus_dev_t *_dev)
53546 +{
53547 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53548 + dwc_otg_pcd_t *pcd = otg_dev->pcd;
53549 +
53550 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
53551 +
53552 + /*
53553 + * Free the IRQ
53554 + */
53555 +#ifdef PLATFORM_INTERFACE
53556 + free_irq(platform_get_irq(_dev, 0), pcd);
53557 +#else
53558 + free_irq(_dev->irq, pcd);
53559 +#endif
53560 + dwc_otg_pcd_remove(otg_dev->pcd);
53561 + free_wrapper(gadget_wrapper);
53562 + otg_dev->pcd = 0;
53563 +}
53564 +
53565 +/**
53566 + * This function registers a gadget driver with the PCD.
53567 + *
53568 + * When a driver is successfully registered, it will receive control
53569 + * requests including set_configuration(), which enables non-control
53570 + * requests. then usb traffic follows until a disconnect is reported.
53571 + * then a host may connect again, or the driver might get unbound.
53572 + *
53573 + * @param driver The driver being registered
53574 + * @param bind The bind function of gadget driver
53575 + */
53576 +
53577 +int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
53578 +{
53579 + int retval;
53580 +
53581 + DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
53582 + driver->driver.name);
53583 +
53584 + if (!driver || driver->max_speed == USB_SPEED_UNKNOWN ||
53585 + !driver->bind ||
53586 + !driver->unbind || !driver->disconnect || !driver->setup) {
53587 + DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
53588 + return -EINVAL;
53589 + }
53590 + if (gadget_wrapper == 0) {
53591 + DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
53592 + return -ENODEV;
53593 + }
53594 + if (gadget_wrapper->driver != 0) {
53595 + DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
53596 + return -EBUSY;
53597 + }
53598 +
53599 + /* hook up the driver */
53600 + gadget_wrapper->driver = driver;
53601 + gadget_wrapper->gadget.dev.driver = &driver->driver;
53602 +
53603 + DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
53604 + retval = driver->bind(&gadget_wrapper->gadget, gadget_wrapper->driver);
53605 + if (retval) {
53606 + DWC_ERROR("bind to driver %s --> error %d\n",
53607 + driver->driver.name, retval);
53608 + gadget_wrapper->driver = 0;
53609 + gadget_wrapper->gadget.dev.driver = 0;
53610 + return retval;
53611 + }
53612 + DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
53613 + driver->driver.name);
53614 + return 0;
53615 +}
53616 +EXPORT_SYMBOL(usb_gadget_probe_driver);
53617 +
53618 +/**
53619 + * This function unregisters a gadget driver
53620 + *
53621 + * @param driver The driver being unregistered
53622 + */
53623 +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
53624 +{
53625 + //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
53626 +
53627 + if (gadget_wrapper == 0) {
53628 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
53629 + -ENODEV);
53630 + return -ENODEV;
53631 + }
53632 + if (driver == 0 || driver != gadget_wrapper->driver) {
53633 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
53634 + -EINVAL);
53635 + return -EINVAL;
53636 + }
53637 +
53638 + driver->unbind(&gadget_wrapper->gadget);
53639 + gadget_wrapper->driver = 0;
53640 +
53641 + DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
53642 + return 0;
53643 +}
53644 +
53645 +EXPORT_SYMBOL(usb_gadget_unregister_driver);
53646 +
53647 +#endif /* DWC_HOST_ONLY */
53648 --- /dev/null
53649 +++ b/drivers/usb/host/dwc_otg/dwc_otg_regs.h
53650 @@ -0,0 +1,2550 @@
53651 +/* ==========================================================================
53652 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $
53653 + * $Revision: #98 $
53654 + * $Date: 2012/08/10 $
53655 + * $Change: 2047372 $
53656 + *
53657 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
53658 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
53659 + * otherwise expressly agreed to in writing between Synopsys and you.
53660 + *
53661 + * The Software IS NOT an item of Licensed Software or Licensed Product under
53662 + * any End User Software License Agreement or Agreement for Licensed Product
53663 + * with Synopsys or any supplement thereto. You are permitted to use and
53664 + * redistribute this Software in source and binary forms, with or without
53665 + * modification, provided that redistributions of source code must retain this
53666 + * notice. You may not view, use, disclose, copy or distribute this file or
53667 + * any information contained herein except pursuant to this license grant from
53668 + * Synopsys. If you do not agree with this notice, including the disclaimer
53669 + * below, then you are not authorized to use the Software.
53670 + *
53671 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
53672 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53673 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53674 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
53675 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53676 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53677 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
53678 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53679 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53680 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
53681 + * DAMAGE.
53682 + * ========================================================================== */
53683 +
53684 +#ifndef __DWC_OTG_REGS_H__
53685 +#define __DWC_OTG_REGS_H__
53686 +
53687 +#include "dwc_otg_core_if.h"
53688 +
53689 +/**
53690 + * @file
53691 + *
53692 + * This file contains the data structures for accessing the DWC_otg core registers.
53693 + *
53694 + * The application interfaces with the HS OTG core by reading from and
53695 + * writing to the Control and Status Register (CSR) space through the
53696 + * AHB Slave interface. These registers are 32 bits wide, and the
53697 + * addresses are 32-bit-block aligned.
53698 + * CSRs are classified as follows:
53699 + * - Core Global Registers
53700 + * - Device Mode Registers
53701 + * - Device Global Registers
53702 + * - Device Endpoint Specific Registers
53703 + * - Host Mode Registers
53704 + * - Host Global Registers
53705 + * - Host Port CSRs
53706 + * - Host Channel Specific Registers
53707 + *
53708 + * Only the Core Global registers can be accessed in both Device and
53709 + * Host modes. When the HS OTG core is operating in one mode, either
53710 + * Device or Host, the application must not access registers from the
53711 + * other mode. When the core switches from one mode to another, the
53712 + * registers in the new mode of operation must be reprogrammed as they
53713 + * would be after a power-on reset.
53714 + */
53715 +
53716 +/****************************************************************************/
53717 +/** DWC_otg Core registers .
53718 + * The dwc_otg_core_global_regs structure defines the size
53719 + * and relative field offsets for the Core Global registers.
53720 + */
53721 +typedef struct dwc_otg_core_global_regs {
53722 + /** OTG Control and Status Register. <i>Offset: 000h</i> */
53723 + volatile uint32_t gotgctl;
53724 + /** OTG Interrupt Register. <i>Offset: 004h</i> */
53725 + volatile uint32_t gotgint;
53726 + /**Core AHB Configuration Register. <i>Offset: 008h</i> */
53727 + volatile uint32_t gahbcfg;
53728 +
53729 +#define DWC_GLBINTRMASK 0x0001
53730 +#define DWC_DMAENABLE 0x0020
53731 +#define DWC_NPTXEMPTYLVL_EMPTY 0x0080
53732 +#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000
53733 +#define DWC_PTXEMPTYLVL_EMPTY 0x0100
53734 +#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000
53735 +
53736 + /**Core USB Configuration Register. <i>Offset: 00Ch</i> */
53737 + volatile uint32_t gusbcfg;
53738 + /**Core Reset Register. <i>Offset: 010h</i> */
53739 + volatile uint32_t grstctl;
53740 + /**Core Interrupt Register. <i>Offset: 014h</i> */
53741 + volatile uint32_t gintsts;
53742 + /**Core Interrupt Mask Register. <i>Offset: 018h</i> */
53743 + volatile uint32_t gintmsk;
53744 + /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */
53745 + volatile uint32_t grxstsr;
53746 + /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/
53747 + volatile uint32_t grxstsp;
53748 + /**Receive FIFO Size Register. <i>Offset: 024h</i> */
53749 + volatile uint32_t grxfsiz;
53750 + /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */
53751 + volatile uint32_t gnptxfsiz;
53752 + /**Non Periodic Transmit FIFO/Queue Status Register (Read
53753 + * Only). <i>Offset: 02Ch</i> */
53754 + volatile uint32_t gnptxsts;
53755 + /**I2C Access Register. <i>Offset: 030h</i> */
53756 + volatile uint32_t gi2cctl;
53757 + /**PHY Vendor Control Register. <i>Offset: 034h</i> */
53758 + volatile uint32_t gpvndctl;
53759 + /**General Purpose Input/Output Register. <i>Offset: 038h</i> */
53760 + volatile uint32_t ggpio;
53761 + /**User ID Register. <i>Offset: 03Ch</i> */
53762 + volatile uint32_t guid;
53763 + /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */
53764 + volatile uint32_t gsnpsid;
53765 + /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */
53766 + volatile uint32_t ghwcfg1;
53767 + /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */
53768 + volatile uint32_t ghwcfg2;
53769 +#define DWC_SLAVE_ONLY_ARCH 0
53770 +#define DWC_EXT_DMA_ARCH 1
53771 +#define DWC_INT_DMA_ARCH 2
53772 +
53773 +#define DWC_MODE_HNP_SRP_CAPABLE 0
53774 +#define DWC_MODE_SRP_ONLY_CAPABLE 1
53775 +#define DWC_MODE_NO_HNP_SRP_CAPABLE 2
53776 +#define DWC_MODE_SRP_CAPABLE_DEVICE 3
53777 +#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4
53778 +#define DWC_MODE_SRP_CAPABLE_HOST 5
53779 +#define DWC_MODE_NO_SRP_CAPABLE_HOST 6
53780 +
53781 + /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */
53782 + volatile uint32_t ghwcfg3;
53783 + /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/
53784 + volatile uint32_t ghwcfg4;
53785 + /** Core LPM Configuration register <i>Offset: 054h</i>*/
53786 + volatile uint32_t glpmcfg;
53787 + /** Global PowerDn Register <i>Offset: 058h</i> */
53788 + volatile uint32_t gpwrdn;
53789 + /** Global DFIFO SW Config Register <i>Offset: 05Ch</i> */
53790 + volatile uint32_t gdfifocfg;
53791 + /** ADP Control Register <i>Offset: 060h</i> */
53792 + volatile uint32_t adpctl;
53793 + /** Reserved <i>Offset: 064h-0FFh</i> */
53794 + volatile uint32_t reserved39[39];
53795 + /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */
53796 + volatile uint32_t hptxfsiz;
53797 + /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled,
53798 + otherwise Device Transmit FIFO#n Register.
53799 + * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */
53800 + volatile uint32_t dtxfsiz[15];
53801 +} dwc_otg_core_global_regs_t;
53802 +
53803 +/**
53804 + * This union represents the bit fields of the Core OTG Control
53805 + * and Status Register (GOTGCTL). Set the bits using the bit
53806 + * fields then write the <i>d32</i> value to the register.
53807 + */
53808 +typedef union gotgctl_data {
53809 + /** raw register data */
53810 + uint32_t d32;
53811 + /** register bits */
53812 + struct {
53813 + unsigned sesreqscs:1;
53814 + unsigned sesreq:1;
53815 + unsigned vbvalidoven:1;
53816 + unsigned vbvalidovval:1;
53817 + unsigned avalidoven:1;
53818 + unsigned avalidovval:1;
53819 + unsigned bvalidoven:1;
53820 + unsigned bvalidovval:1;
53821 + unsigned hstnegscs:1;
53822 + unsigned hnpreq:1;
53823 + unsigned hstsethnpen:1;
53824 + unsigned devhnpen:1;
53825 + unsigned reserved12_15:4;
53826 + unsigned conidsts:1;
53827 + unsigned dbnctime:1;
53828 + unsigned asesvld:1;
53829 + unsigned bsesvld:1;
53830 + unsigned otgver:1;
53831 + unsigned reserved1:1;
53832 + unsigned multvalidbc:5;
53833 + unsigned chirpen:1;
53834 + unsigned reserved28_31:4;
53835 + } b;
53836 +} gotgctl_data_t;
53837 +
53838 +/**
53839 + * This union represents the bit fields of the Core OTG Interrupt Register
53840 + * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i>
53841 + * value to the register.
53842 + */
53843 +typedef union gotgint_data {
53844 + /** raw register data */
53845 + uint32_t d32;
53846 + /** register bits */
53847 + struct {
53848 + /** Current Mode */
53849 + unsigned reserved0_1:2;
53850 +
53851 + /** Session End Detected */
53852 + unsigned sesenddet:1;
53853 +
53854 + unsigned reserved3_7:5;
53855 +
53856 + /** Session Request Success Status Change */
53857 + unsigned sesreqsucstschng:1;
53858 + /** Host Negotiation Success Status Change */
53859 + unsigned hstnegsucstschng:1;
53860 +
53861 + unsigned reserved10_16:7;
53862 +
53863 + /** Host Negotiation Detected */
53864 + unsigned hstnegdet:1;
53865 + /** A-Device Timeout Change */
53866 + unsigned adevtoutchng:1;
53867 + /** Debounce Done */
53868 + unsigned debdone:1;
53869 + /** Multi-Valued input changed */
53870 + unsigned mvic:1;
53871 +
53872 + unsigned reserved31_21:11;
53873 +
53874 + } b;
53875 +} gotgint_data_t;
53876 +
53877 +/**
53878 + * This union represents the bit fields of the Core AHB Configuration
53879 + * Register (GAHBCFG). Set/clear the bits using the bit fields then
53880 + * write the <i>d32</i> value to the register.
53881 + */
53882 +typedef union gahbcfg_data {
53883 + /** raw register data */
53884 + uint32_t d32;
53885 + /** register bits */
53886 + struct {
53887 + unsigned glblintrmsk:1;
53888 +#define DWC_GAHBCFG_GLBINT_ENABLE 1
53889 +
53890 + unsigned hburstlen:4;
53891 +#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0
53892 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1
53893 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3
53894 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5
53895 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7
53896 +
53897 + unsigned dmaenable:1;
53898 +#define DWC_GAHBCFG_DMAENABLE 1
53899 + unsigned reserved:1;
53900 + unsigned nptxfemplvl_txfemplvl:1;
53901 + unsigned ptxfemplvl:1;
53902 +#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1
53903 +#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0
53904 + unsigned reserved9_20:12;
53905 + unsigned remmemsupp:1;
53906 + unsigned notialldmawrit:1;
53907 + unsigned ahbsingle:1;
53908 + unsigned reserved24_31:8;
53909 + } b;
53910 +} gahbcfg_data_t;
53911 +
53912 +/**
53913 + * This union represents the bit fields of the Core USB Configuration
53914 + * Register (GUSBCFG). Set the bits using the bit fields then write
53915 + * the <i>d32</i> value to the register.
53916 + */
53917 +typedef union gusbcfg_data {
53918 + /** raw register data */
53919 + uint32_t d32;
53920 + /** register bits */
53921 + struct {
53922 + unsigned toutcal:3;
53923 + unsigned phyif:1;
53924 + unsigned ulpi_utmi_sel:1;
53925 + unsigned fsintf:1;
53926 + unsigned physel:1;
53927 + unsigned ddrsel:1;
53928 + unsigned srpcap:1;
53929 + unsigned hnpcap:1;
53930 + unsigned usbtrdtim:4;
53931 + unsigned reserved1:1;
53932 + unsigned phylpwrclksel:1;
53933 + unsigned otgutmifssel:1;
53934 + unsigned ulpi_fsls:1;
53935 + unsigned ulpi_auto_res:1;
53936 + unsigned ulpi_clk_sus_m:1;
53937 + unsigned ulpi_ext_vbus_drv:1;
53938 + unsigned ulpi_int_vbus_indicator:1;
53939 + unsigned term_sel_dl_pulse:1;
53940 + unsigned indicator_complement:1;
53941 + unsigned indicator_pass_through:1;
53942 + unsigned ulpi_int_prot_dis:1;
53943 + unsigned ic_usb_cap:1;
53944 + unsigned ic_traffic_pull_remove:1;
53945 + unsigned tx_end_delay:1;
53946 + unsigned force_host_mode:1;
53947 + unsigned force_dev_mode:1;
53948 + unsigned reserved31:1;
53949 + } b;
53950 +} gusbcfg_data_t;
53951 +
53952 +/**
53953 + * This union represents the bit fields of the Core Reset Register
53954 + * (GRSTCTL). Set/clear the bits using the bit fields then write the
53955 + * <i>d32</i> value to the register.
53956 + */
53957 +typedef union grstctl_data {
53958 + /** raw register data */
53959 + uint32_t d32;
53960 + /** register bits */
53961 + struct {
53962 + /** Core Soft Reset (CSftRst) (Device and Host)
53963 + *
53964 + * The application can flush the control logic in the
53965 + * entire core using this bit. This bit resets the
53966 + * pipelines in the AHB Clock domain as well as the
53967 + * PHY Clock domain.
53968 + *
53969 + * The state machines are reset to an IDLE state, the
53970 + * control bits in the CSRs are cleared, all the
53971 + * transmit FIFOs and the receive FIFO are flushed.
53972 + *
53973 + * The status mask bits that control the generation of
53974 + * the interrupt, are cleared, to clear the
53975 + * interrupt. The interrupt status bits are not
53976 + * cleared, so the application can get the status of
53977 + * any events that occurred in the core after it has
53978 + * set this bit.
53979 + *
53980 + * Any transactions on the AHB are terminated as soon
53981 + * as possible following the protocol. Any
53982 + * transactions on the USB are terminated immediately.
53983 + *
53984 + * The configuration settings in the CSRs are
53985 + * unchanged, so the software doesn't have to
53986 + * reprogram these registers (Device
53987 + * Configuration/Host Configuration/Core System
53988 + * Configuration/Core PHY Configuration).
53989 + *
53990 + * The application can write to this bit, any time it
53991 + * wants to reset the core. This is a self clearing
53992 + * bit and the core clears this bit after all the
53993 + * necessary logic is reset in the core, which may
53994 + * take several clocks, depending on the current state
53995 + * of the core.
53996 + */
53997 + unsigned csftrst:1;
53998 + /** Hclk Soft Reset
53999 + *
54000 + * The application uses this bit to reset the control logic in
54001 + * the AHB clock domain. Only AHB clock domain pipelines are
54002 + * reset.
54003 + */
54004 + unsigned hsftrst:1;
54005 + /** Host Frame Counter Reset (Host Only)<br>
54006 + *
54007 + * The application can reset the (micro)frame number
54008 + * counter inside the core, using this bit. When the
54009 + * (micro)frame counter is reset, the subsequent SOF
54010 + * sent out by the core, will have a (micro)frame
54011 + * number of 0.
54012 + */
54013 + unsigned hstfrm:1;
54014 + /** In Token Sequence Learning Queue Flush
54015 + * (INTknQFlsh) (Device Only)
54016 + */
54017 + unsigned intknqflsh:1;
54018 + /** RxFIFO Flush (RxFFlsh) (Device and Host)
54019 + *
54020 + * The application can flush the entire Receive FIFO
54021 + * using this bit. The application must first
54022 + * ensure that the core is not in the middle of a
54023 + * transaction. The application should write into
54024 + * this bit, only after making sure that neither the
54025 + * DMA engine is reading from the RxFIFO nor the MAC
54026 + * is writing the data in to the FIFO. The
54027 + * application should wait until the bit is cleared
54028 + * before performing any other operations. This bit
54029 + * will takes 8 clocks (slowest of PHY or AHB clock)
54030 + * to clear.
54031 + */
54032 + unsigned rxfflsh:1;
54033 + /** TxFIFO Flush (TxFFlsh) (Device and Host).
54034 + *
54035 + * This bit is used to selectively flush a single or
54036 + * all transmit FIFOs. The application must first
54037 + * ensure that the core is not in the middle of a
54038 + * transaction. The application should write into
54039 + * this bit, only after making sure that neither the
54040 + * DMA engine is writing into the TxFIFO nor the MAC
54041 + * is reading the data out of the FIFO. The
54042 + * application should wait until the core clears this
54043 + * bit, before performing any operations. This bit
54044 + * will takes 8 clocks (slowest of PHY or AHB clock)
54045 + * to clear.
54046 + */
54047 + unsigned txfflsh:1;
54048 +
54049 + /** TxFIFO Number (TxFNum) (Device and Host).
54050 + *
54051 + * This is the FIFO number which needs to be flushed,
54052 + * using the TxFIFO Flush bit. This field should not
54053 + * be changed until the TxFIFO Flush bit is cleared by
54054 + * the core.
54055 + * - 0x0 : Non Periodic TxFIFO Flush
54056 + * - 0x1 : Periodic TxFIFO #1 Flush in device mode
54057 + * or Periodic TxFIFO in host mode
54058 + * - 0x2 : Periodic TxFIFO #2 Flush in device mode.
54059 + * - ...
54060 + * - 0xF : Periodic TxFIFO #15 Flush in device mode
54061 + * - 0x10: Flush all the Transmit NonPeriodic and
54062 + * Transmit Periodic FIFOs in the core
54063 + */
54064 + unsigned txfnum:5;
54065 + /** Reserved */
54066 + unsigned reserved11_29:19;
54067 + /** DMA Request Signal. Indicated DMA request is in
54068 + * probress. Used for debug purpose. */
54069 + unsigned dmareq:1;
54070 + /** AHB Master Idle. Indicates the AHB Master State
54071 + * Machine is in IDLE condition. */
54072 + unsigned ahbidle:1;
54073 + } b;
54074 +} grstctl_t;
54075 +
54076 +/**
54077 + * This union represents the bit fields of the Core Interrupt Mask
54078 + * Register (GINTMSK). Set/clear the bits using the bit fields then
54079 + * write the <i>d32</i> value to the register.
54080 + */
54081 +typedef union gintmsk_data {
54082 + /** raw register data */
54083 + uint32_t d32;
54084 + /** register bits */
54085 + struct {
54086 + unsigned reserved0:1;
54087 + unsigned modemismatch:1;
54088 + unsigned otgintr:1;
54089 + unsigned sofintr:1;
54090 + unsigned rxstsqlvl:1;
54091 + unsigned nptxfempty:1;
54092 + unsigned ginnakeff:1;
54093 + unsigned goutnakeff:1;
54094 + unsigned ulpickint:1;
54095 + unsigned i2cintr:1;
54096 + unsigned erlysuspend:1;
54097 + unsigned usbsuspend:1;
54098 + unsigned usbreset:1;
54099 + unsigned enumdone:1;
54100 + unsigned isooutdrop:1;
54101 + unsigned eopframe:1;
54102 + unsigned restoredone:1;
54103 + unsigned epmismatch:1;
54104 + unsigned inepintr:1;
54105 + unsigned outepintr:1;
54106 + unsigned incomplisoin:1;
54107 + unsigned incomplisoout:1;
54108 + unsigned fetsusp:1;
54109 + unsigned resetdet:1;
54110 + unsigned portintr:1;
54111 + unsigned hcintr:1;
54112 + unsigned ptxfempty:1;
54113 + unsigned lpmtranrcvd:1;
54114 + unsigned conidstschng:1;
54115 + unsigned disconnect:1;
54116 + unsigned sessreqintr:1;
54117 + unsigned wkupintr:1;
54118 + } b;
54119 +} gintmsk_data_t;
54120 +/**
54121 + * This union represents the bit fields of the Core Interrupt Register
54122 + * (GINTSTS). Set/clear the bits using the bit fields then write the
54123 + * <i>d32</i> value to the register.
54124 + */
54125 +typedef union gintsts_data {
54126 + /** raw register data */
54127 + uint32_t d32;
54128 +#define DWC_SOF_INTR_MASK 0x0008
54129 + /** register bits */
54130 + struct {
54131 +#define DWC_HOST_MODE 1
54132 + unsigned curmode:1;
54133 + unsigned modemismatch:1;
54134 + unsigned otgintr:1;
54135 + unsigned sofintr:1;
54136 + unsigned rxstsqlvl:1;
54137 + unsigned nptxfempty:1;
54138 + unsigned ginnakeff:1;
54139 + unsigned goutnakeff:1;
54140 + unsigned ulpickint:1;
54141 + unsigned i2cintr:1;
54142 + unsigned erlysuspend:1;
54143 + unsigned usbsuspend:1;
54144 + unsigned usbreset:1;
54145 + unsigned enumdone:1;
54146 + unsigned isooutdrop:1;
54147 + unsigned eopframe:1;
54148 + unsigned restoredone:1;
54149 + unsigned epmismatch:1;
54150 + unsigned inepint:1;
54151 + unsigned outepintr:1;
54152 + unsigned incomplisoin:1;
54153 + unsigned incomplisoout:1;
54154 + unsigned fetsusp:1;
54155 + unsigned resetdet:1;
54156 + unsigned portintr:1;
54157 + unsigned hcintr:1;
54158 + unsigned ptxfempty:1;
54159 + unsigned lpmtranrcvd:1;
54160 + unsigned conidstschng:1;
54161 + unsigned disconnect:1;
54162 + unsigned sessreqintr:1;
54163 + unsigned wkupintr:1;
54164 + } b;
54165 +} gintsts_data_t;
54166 +
54167 +/**
54168 + * This union represents the bit fields in the Device Receive Status Read and
54169 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
54170 + * element then read out the bits using the <i>b</i>it elements.
54171 + */
54172 +typedef union device_grxsts_data {
54173 + /** raw register data */
54174 + uint32_t d32;
54175 + /** register bits */
54176 + struct {
54177 + unsigned epnum:4;
54178 + unsigned bcnt:11;
54179 + unsigned dpid:2;
54180 +
54181 +#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet
54182 +#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete
54183 +
54184 +#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK
54185 +#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete
54186 +#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet
54187 + unsigned pktsts:4;
54188 + unsigned fn:4;
54189 + unsigned reserved25_31:7;
54190 + } b;
54191 +} device_grxsts_data_t;
54192 +
54193 +/**
54194 + * This union represents the bit fields in the Host Receive Status Read and
54195 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
54196 + * element then read out the bits using the <i>b</i>it elements.
54197 + */
54198 +typedef union host_grxsts_data {
54199 + /** raw register data */
54200 + uint32_t d32;
54201 + /** register bits */
54202 + struct {
54203 + unsigned chnum:4;
54204 + unsigned bcnt:11;
54205 + unsigned dpid:2;
54206 +
54207 + unsigned pktsts:4;
54208 +#define DWC_GRXSTS_PKTSTS_IN 0x2
54209 +#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3
54210 +#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
54211 +#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7
54212 +
54213 + unsigned reserved21_31:11;
54214 + } b;
54215 +} host_grxsts_data_t;
54216 +
54217 +/**
54218 + * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ,
54219 + * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the <i>d32</i> element
54220 + * then read out the bits using the <i>b</i>it elements.
54221 + */
54222 +typedef union fifosize_data {
54223 + /** raw register data */
54224 + uint32_t d32;
54225 + /** register bits */
54226 + struct {
54227 + unsigned startaddr:16;
54228 + unsigned depth:16;
54229 + } b;
54230 +} fifosize_data_t;
54231 +
54232 +/**
54233 + * This union represents the bit fields in the Non-Periodic Transmit
54234 + * FIFO/Queue Status Register (GNPTXSTS). Read the register into the
54235 + * <i>d32</i> element then read out the bits using the <i>b</i>it
54236 + * elements.
54237 + */
54238 +typedef union gnptxsts_data {
54239 + /** raw register data */
54240 + uint32_t d32;
54241 + /** register bits */
54242 + struct {
54243 + unsigned nptxfspcavail:16;
54244 + unsigned nptxqspcavail:8;
54245 + /** Top of the Non-Periodic Transmit Request Queue
54246 + * - bit 24 - Terminate (Last entry for the selected
54247 + * channel/EP)
54248 + * - bits 26:25 - Token Type
54249 + * - 2'b00 - IN/OUT
54250 + * - 2'b01 - Zero Length OUT
54251 + * - 2'b10 - PING/Complete Split
54252 + * - 2'b11 - Channel Halt
54253 + * - bits 30:27 - Channel/EP Number
54254 + */
54255 + unsigned nptxqtop_terminate:1;
54256 + unsigned nptxqtop_token:2;
54257 + unsigned nptxqtop_chnep:4;
54258 + unsigned reserved:1;
54259 + } b;
54260 +} gnptxsts_data_t;
54261 +
54262 +/**
54263 + * This union represents the bit fields in the Transmit
54264 + * FIFO Status Register (DTXFSTS). Read the register into the
54265 + * <i>d32</i> element then read out the bits using the <i>b</i>it
54266 + * elements.
54267 + */
54268 +typedef union dtxfsts_data {
54269 + /** raw register data */
54270 + uint32_t d32;
54271 + /** register bits */
54272 + struct {
54273 + unsigned txfspcavail:16;
54274 + unsigned reserved:16;
54275 + } b;
54276 +} dtxfsts_data_t;
54277 +
54278 +/**
54279 + * This union represents the bit fields in the I2C Control Register
54280 + * (I2CCTL). Read the register into the <i>d32</i> element then read out the
54281 + * bits using the <i>b</i>it elements.
54282 + */
54283 +typedef union gi2cctl_data {
54284 + /** raw register data */
54285 + uint32_t d32;
54286 + /** register bits */
54287 + struct {
54288 + unsigned rwdata:8;
54289 + unsigned regaddr:8;
54290 + unsigned addr:7;
54291 + unsigned i2cen:1;
54292 + unsigned ack:1;
54293 + unsigned i2csuspctl:1;
54294 + unsigned i2cdevaddr:2;
54295 + unsigned i2cdatse0:1;
54296 + unsigned reserved:1;
54297 + unsigned rw:1;
54298 + unsigned bsydne:1;
54299 + } b;
54300 +} gi2cctl_data_t;
54301 +
54302 +/**
54303 + * This union represents the bit fields in the PHY Vendor Control Register
54304 + * (GPVNDCTL). Read the register into the <i>d32</i> element then read out the
54305 + * bits using the <i>b</i>it elements.
54306 + */
54307 +typedef union gpvndctl_data {
54308 + /** raw register data */
54309 + uint32_t d32;
54310 + /** register bits */
54311 + struct {
54312 + unsigned regdata:8;
54313 + unsigned vctrl:8;
54314 + unsigned regaddr16_21:6;
54315 + unsigned regwr:1;
54316 + unsigned reserved23_24:2;
54317 + unsigned newregreq:1;
54318 + unsigned vstsbsy:1;
54319 + unsigned vstsdone:1;
54320 + unsigned reserved28_30:3;
54321 + unsigned disulpidrvr:1;
54322 + } b;
54323 +} gpvndctl_data_t;
54324 +
54325 +/**
54326 + * This union represents the bit fields in the General Purpose
54327 + * Input/Output Register (GGPIO).
54328 + * Read the register into the <i>d32</i> element then read out the
54329 + * bits using the <i>b</i>it elements.
54330 + */
54331 +typedef union ggpio_data {
54332 + /** raw register data */
54333 + uint32_t d32;
54334 + /** register bits */
54335 + struct {
54336 + unsigned gpi:16;
54337 + unsigned gpo:16;
54338 + } b;
54339 +} ggpio_data_t;
54340 +
54341 +/**
54342 + * This union represents the bit fields in the User ID Register
54343 + * (GUID). Read the register into the <i>d32</i> element then read out the
54344 + * bits using the <i>b</i>it elements.
54345 + */
54346 +typedef union guid_data {
54347 + /** raw register data */
54348 + uint32_t d32;
54349 + /** register bits */
54350 + struct {
54351 + unsigned rwdata:32;
54352 + } b;
54353 +} guid_data_t;
54354 +
54355 +/**
54356 + * This union represents the bit fields in the Synopsys ID Register
54357 + * (GSNPSID). Read the register into the <i>d32</i> element then read out the
54358 + * bits using the <i>b</i>it elements.
54359 + */
54360 +typedef union gsnpsid_data {
54361 + /** raw register data */
54362 + uint32_t d32;
54363 + /** register bits */
54364 + struct {
54365 + unsigned rwdata:32;
54366 + } b;
54367 +} gsnpsid_data_t;
54368 +
54369 +/**
54370 + * This union represents the bit fields in the User HW Config1
54371 + * Register. Read the register into the <i>d32</i> element then read
54372 + * out the bits using the <i>b</i>it elements.
54373 + */
54374 +typedef union hwcfg1_data {
54375 + /** raw register data */
54376 + uint32_t d32;
54377 + /** register bits */
54378 + struct {
54379 + unsigned ep_dir0:2;
54380 + unsigned ep_dir1:2;
54381 + unsigned ep_dir2:2;
54382 + unsigned ep_dir3:2;
54383 + unsigned ep_dir4:2;
54384 + unsigned ep_dir5:2;
54385 + unsigned ep_dir6:2;
54386 + unsigned ep_dir7:2;
54387 + unsigned ep_dir8:2;
54388 + unsigned ep_dir9:2;
54389 + unsigned ep_dir10:2;
54390 + unsigned ep_dir11:2;
54391 + unsigned ep_dir12:2;
54392 + unsigned ep_dir13:2;
54393 + unsigned ep_dir14:2;
54394 + unsigned ep_dir15:2;
54395 + } b;
54396 +} hwcfg1_data_t;
54397 +
54398 +/**
54399 + * This union represents the bit fields in the User HW Config2
54400 + * Register. Read the register into the <i>d32</i> element then read
54401 + * out the bits using the <i>b</i>it elements.
54402 + */
54403 +typedef union hwcfg2_data {
54404 + /** raw register data */
54405 + uint32_t d32;
54406 + /** register bits */
54407 + struct {
54408 + /* GHWCFG2 */
54409 + unsigned op_mode:3;
54410 +#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
54411 +#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
54412 +#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
54413 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
54414 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
54415 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
54416 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
54417 +
54418 + unsigned architecture:2;
54419 + unsigned point2point:1;
54420 + unsigned hs_phy_type:2;
54421 +#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
54422 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
54423 +#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
54424 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
54425 +
54426 + unsigned fs_phy_type:2;
54427 + unsigned num_dev_ep:4;
54428 + unsigned num_host_chan:4;
54429 + unsigned perio_ep_supported:1;
54430 + unsigned dynamic_fifo:1;
54431 + unsigned multi_proc_int:1;
54432 + unsigned reserved21:1;
54433 + unsigned nonperio_tx_q_depth:2;
54434 + unsigned host_perio_tx_q_depth:2;
54435 + unsigned dev_token_q_depth:5;
54436 + unsigned otg_enable_ic_usb:1;
54437 + } b;
54438 +} hwcfg2_data_t;
54439 +
54440 +/**
54441 + * This union represents the bit fields in the User HW Config3
54442 + * Register. Read the register into the <i>d32</i> element then read
54443 + * out the bits using the <i>b</i>it elements.
54444 + */
54445 +typedef union hwcfg3_data {
54446 + /** raw register data */
54447 + uint32_t d32;
54448 + /** register bits */
54449 + struct {
54450 + /* GHWCFG3 */
54451 + unsigned xfer_size_cntr_width:4;
54452 + unsigned packet_size_cntr_width:3;
54453 + unsigned otg_func:1;
54454 + unsigned i2c:1;
54455 + unsigned vendor_ctrl_if:1;
54456 + unsigned optional_features:1;
54457 + unsigned synch_reset_type:1;
54458 + unsigned adp_supp:1;
54459 + unsigned otg_enable_hsic:1;
54460 + unsigned bc_support:1;
54461 + unsigned otg_lpm_en:1;
54462 + unsigned dfifo_depth:16;
54463 + } b;
54464 +} hwcfg3_data_t;
54465 +
54466 +/**
54467 + * This union represents the bit fields in the User HW Config4
54468 + * Register. Read the register into the <i>d32</i> element then read
54469 + * out the bits using the <i>b</i>it elements.
54470 + */
54471 +typedef union hwcfg4_data {
54472 + /** raw register data */
54473 + uint32_t d32;
54474 + /** register bits */
54475 + struct {
54476 + unsigned num_dev_perio_in_ep:4;
54477 + unsigned power_optimiz:1;
54478 + unsigned min_ahb_freq:1;
54479 + unsigned hiber:1;
54480 + unsigned xhiber:1;
54481 + unsigned reserved:6;
54482 + unsigned utmi_phy_data_width:2;
54483 + unsigned num_dev_mode_ctrl_ep:4;
54484 + unsigned iddig_filt_en:1;
54485 + unsigned vbus_valid_filt_en:1;
54486 + unsigned a_valid_filt_en:1;
54487 + unsigned b_valid_filt_en:1;
54488 + unsigned session_end_filt_en:1;
54489 + unsigned ded_fifo_en:1;
54490 + unsigned num_in_eps:4;
54491 + unsigned desc_dma:1;
54492 + unsigned desc_dma_dyn:1;
54493 + } b;
54494 +} hwcfg4_data_t;
54495 +
54496 +/**
54497 + * This union represents the bit fields of the Core LPM Configuration
54498 + * Register (GLPMCFG). Set the bits using bit fields then write
54499 + * the <i>d32</i> value to the register.
54500 + */
54501 +typedef union glpmctl_data {
54502 + /** raw register data */
54503 + uint32_t d32;
54504 + /** register bits */
54505 + struct {
54506 + /** LPM-Capable (LPMCap) (Device and Host)
54507 + * The application uses this bit to control
54508 + * the DWC_otg core LPM capabilities.
54509 + */
54510 + unsigned lpm_cap_en:1;
54511 + /** LPM response programmed by application (AppL1Res) (Device)
54512 + * Handshake response to LPM token pre-programmed
54513 + * by device application software.
54514 + */
54515 + unsigned appl_resp:1;
54516 + /** Host Initiated Resume Duration (HIRD) (Device and Host)
54517 + * In Host mode this field indicates the value of HIRD
54518 + * to be sent in an LPM transaction.
54519 + * In Device mode this field is updated with the
54520 + * Received LPM Token HIRD bmAttribute
54521 + * when an ACK/NYET/STALL response is sent
54522 + * to an LPM transaction.
54523 + */
54524 + unsigned hird:4;
54525 + /** RemoteWakeEnable (bRemoteWake) (Device and Host)
54526 + * In Host mode this bit indicates the value of remote
54527 + * wake up to be sent in wIndex field of LPM transaction.
54528 + * In Device mode this field is updated with the
54529 + * Received LPM Token bRemoteWake bmAttribute
54530 + * when an ACK/NYET/STALL response is sent
54531 + * to an LPM transaction.
54532 + */
54533 + unsigned rem_wkup_en:1;
54534 + /** Enable utmi_sleep_n (EnblSlpM) (Device and Host)
54535 + * The application uses this bit to control
54536 + * the utmi_sleep_n assertion to the PHY when in L1 state.
54537 + */
54538 + unsigned en_utmi_sleep:1;
54539 + /** HIRD Threshold (HIRD_Thres) (Device and Host)
54540 + */
54541 + unsigned hird_thres:5;
54542 + /** LPM Response (CoreL1Res) (Device and Host)
54543 + * In Host mode this bit contains handsake response to
54544 + * LPM transaction.
54545 + * In Device mode the response of the core to
54546 + * LPM transaction received is reflected in these two bits.
54547 + - 0x0 : ERROR (No handshake response)
54548 + - 0x1 : STALL
54549 + - 0x2 : NYET
54550 + - 0x3 : ACK
54551 + */
54552 + unsigned lpm_resp:2;
54553 + /** Port Sleep Status (SlpSts) (Device and Host)
54554 + * This bit is set as long as a Sleep condition
54555 + * is present on the USB bus.
54556 + */
54557 + unsigned prt_sleep_sts:1;
54558 + /** Sleep State Resume OK (L1ResumeOK) (Device and Host)
54559 + * Indicates that the application or host
54560 + * can start resume from Sleep state.
54561 + */
54562 + unsigned sleep_state_resumeok:1;
54563 + /** LPM channel Index (LPM_Chnl_Indx) (Host)
54564 + * The channel number on which the LPM transaction
54565 + * has to be applied while sending
54566 + * an LPM transaction to the local device.
54567 + */
54568 + unsigned lpm_chan_index:4;
54569 + /** LPM Retry Count (LPM_Retry_Cnt) (Host)
54570 + * Number host retries that would be performed
54571 + * if the device response was not valid response.
54572 + */
54573 + unsigned retry_count:3;
54574 + /** Send LPM Transaction (SndLPM) (Host)
54575 + * When set by application software,
54576 + * an LPM transaction containing two tokens
54577 + * is sent.
54578 + */
54579 + unsigned send_lpm:1;
54580 + /** LPM Retry status (LPM_RetryCnt_Sts) (Host)
54581 + * Number of LPM Host Retries still remaining
54582 + * to be transmitted for the current LPM sequence
54583 + */
54584 + unsigned retry_count_sts:3;
54585 + unsigned reserved28_29:2;
54586 + /** In host mode once this bit is set, the host
54587 + * configures to drive the HSIC Idle state on the bus.
54588 + * It then waits for the device to initiate the Connect sequence.
54589 + * In device mode once this bit is set, the device waits for
54590 + * the HSIC Idle line state on the bus. Upon receving the Idle
54591 + * line state, it initiates the HSIC Connect sequence.
54592 + */
54593 + unsigned hsic_connect:1;
54594 + /** This bit overrides and functionally inverts
54595 + * the if_select_hsic input port signal.
54596 + */
54597 + unsigned inv_sel_hsic:1;
54598 + } b;
54599 +} glpmcfg_data_t;
54600 +
54601 +/**
54602 + * This union represents the bit fields of the Core ADP Timer, Control and
54603 + * Status Register (ADPTIMCTLSTS). Set the bits using bit fields then write
54604 + * the <i>d32</i> value to the register.
54605 + */
54606 +typedef union adpctl_data {
54607 + /** raw register data */
54608 + uint32_t d32;
54609 + /** register bits */
54610 + struct {
54611 + /** Probe Discharge (PRB_DSCHG)
54612 + * These bits set the times for TADP_DSCHG.
54613 + * These bits are defined as follows:
54614 + * 2'b00 - 4 msec
54615 + * 2'b01 - 8 msec
54616 + * 2'b10 - 16 msec
54617 + * 2'b11 - 32 msec
54618 + */
54619 + unsigned prb_dschg:2;
54620 + /** Probe Delta (PRB_DELTA)
54621 + * These bits set the resolution for RTIM value.
54622 + * The bits are defined in units of 32 kHz clock cycles as follows:
54623 + * 2'b00 - 1 cycles
54624 + * 2'b01 - 2 cycles
54625 + * 2'b10 - 3 cycles
54626 + * 2'b11 - 4 cycles
54627 + * For example if this value is chosen to 2'b01, it means that RTIM
54628 + * increments for every 3(three) 32Khz clock cycles.
54629 + */
54630 + unsigned prb_delta:2;
54631 + /** Probe Period (PRB_PER)
54632 + * These bits sets the TADP_PRD as shown in Figure 4 as follows:
54633 + * 2'b00 - 0.625 to 0.925 sec (typical 0.775 sec)
54634 + * 2'b01 - 1.25 to 1.85 sec (typical 1.55 sec)
54635 + * 2'b10 - 1.9 to 2.6 sec (typical 2.275 sec)
54636 + * 2'b11 - Reserved
54637 + */
54638 + unsigned prb_per:2;
54639 + /** These bits capture the latest time it took for VBUS to ramp from
54640 + * VADP_SINK to VADP_PRB.
54641 + * 0x000 - 1 cycles
54642 + * 0x001 - 2 cycles
54643 + * 0x002 - 3 cycles
54644 + * etc
54645 + * 0x7FF - 2048 cycles
54646 + * A time of 1024 cycles at 32 kHz corresponds to a time of 32 msec.
54647 + */
54648 + unsigned rtim:11;
54649 + /** Enable Probe (EnaPrb)
54650 + * When programmed to 1'b1, the core performs a probe operation.
54651 + * This bit is valid only if OTG_Ver = 1'b1.
54652 + */
54653 + unsigned enaprb:1;
54654 + /** Enable Sense (EnaSns)
54655 + * When programmed to 1'b1, the core performs a Sense operation.
54656 + * This bit is valid only if OTG_Ver = 1'b1.
54657 + */
54658 + unsigned enasns:1;
54659 + /** ADP Reset (ADPRes)
54660 + * When set, ADP controller is reset.
54661 + * This bit is valid only if OTG_Ver = 1'b1.
54662 + */
54663 + unsigned adpres:1;
54664 + /** ADP Enable (ADPEn)
54665 + * When set, the core performs either ADP probing or sensing
54666 + * based on EnaPrb or EnaSns.
54667 + * This bit is valid only if OTG_Ver = 1'b1.
54668 + */
54669 + unsigned adpen:1;
54670 + /** ADP Probe Interrupt (ADP_PRB_INT)
54671 + * When this bit is set, it means that the VBUS
54672 + * voltage is greater than VADP_PRB or VADP_PRB is reached.
54673 + * This bit is valid only if OTG_Ver = 1'b1.
54674 + */
54675 + unsigned adp_prb_int:1;
54676 + /**
54677 + * ADP Sense Interrupt (ADP_SNS_INT)
54678 + * When this bit is set, it means that the VBUS voltage is greater than
54679 + * VADP_SNS value or VADP_SNS is reached.
54680 + * This bit is valid only if OTG_Ver = 1'b1.
54681 + */
54682 + unsigned adp_sns_int:1;
54683 + /** ADP Tomeout Interrupt (ADP_TMOUT_INT)
54684 + * This bit is relevant only for an ADP probe.
54685 + * When this bit is set, it means that the ramp time has
54686 + * completed ie ADPCTL.RTIM has reached its terminal value
54687 + * of 0x7FF. This is a debug feature that allows software
54688 + * to read the ramp time after each cycle.
54689 + * This bit is valid only if OTG_Ver = 1'b1.
54690 + */
54691 + unsigned adp_tmout_int:1;
54692 + /** ADP Probe Interrupt Mask (ADP_PRB_INT_MSK)
54693 + * When this bit is set, it unmasks the interrupt due to ADP_PRB_INT.
54694 + * This bit is valid only if OTG_Ver = 1'b1.
54695 + */
54696 + unsigned adp_prb_int_msk:1;
54697 + /** ADP Sense Interrupt Mask (ADP_SNS_INT_MSK)
54698 + * When this bit is set, it unmasks the interrupt due to ADP_SNS_INT.
54699 + * This bit is valid only if OTG_Ver = 1'b1.
54700 + */
54701 + unsigned adp_sns_int_msk:1;
54702 + /** ADP Timoeout Interrupt Mask (ADP_TMOUT_MSK)
54703 + * When this bit is set, it unmasks the interrupt due to ADP_TMOUT_INT.
54704 + * This bit is valid only if OTG_Ver = 1'b1.
54705 + */
54706 + unsigned adp_tmout_int_msk:1;
54707 + /** Access Request
54708 + * 2'b00 - Read/Write Valid (updated by the core)
54709 + * 2'b01 - Read
54710 + * 2'b00 - Write
54711 + * 2'b00 - Reserved
54712 + */
54713 + unsigned ar:2;
54714 + /** Reserved */
54715 + unsigned reserved29_31:3;
54716 + } b;
54717 +} adpctl_data_t;
54718 +
54719 +////////////////////////////////////////////
54720 +// Device Registers
54721 +/**
54722 + * Device Global Registers. <i>Offsets 800h-BFFh</i>
54723 + *
54724 + * The following structures define the size and relative field offsets
54725 + * for the Device Mode Registers.
54726 + *
54727 + * <i>These registers are visible only in Device mode and must not be
54728 + * accessed in Host mode, as the results are unknown.</i>
54729 + */
54730 +typedef struct dwc_otg_dev_global_regs {
54731 + /** Device Configuration Register. <i>Offset 800h</i> */
54732 + volatile uint32_t dcfg;
54733 + /** Device Control Register. <i>Offset: 804h</i> */
54734 + volatile uint32_t dctl;
54735 + /** Device Status Register (Read Only). <i>Offset: 808h</i> */
54736 + volatile uint32_t dsts;
54737 + /** Reserved. <i>Offset: 80Ch</i> */
54738 + uint32_t unused;
54739 + /** Device IN Endpoint Common Interrupt Mask
54740 + * Register. <i>Offset: 810h</i> */
54741 + volatile uint32_t diepmsk;
54742 + /** Device OUT Endpoint Common Interrupt Mask
54743 + * Register. <i>Offset: 814h</i> */
54744 + volatile uint32_t doepmsk;
54745 + /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */
54746 + volatile uint32_t daint;
54747 + /** Device All Endpoints Interrupt Mask Register. <i>Offset:
54748 + * 81Ch</i> */
54749 + volatile uint32_t daintmsk;
54750 + /** Device IN Token Queue Read Register-1 (Read Only).
54751 + * <i>Offset: 820h</i> */
54752 + volatile uint32_t dtknqr1;
54753 + /** Device IN Token Queue Read Register-2 (Read Only).
54754 + * <i>Offset: 824h</i> */
54755 + volatile uint32_t dtknqr2;
54756 + /** Device VBUS discharge Register. <i>Offset: 828h</i> */
54757 + volatile uint32_t dvbusdis;
54758 + /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */
54759 + volatile uint32_t dvbuspulse;
54760 + /** Device IN Token Queue Read Register-3 (Read Only). /
54761 + * Device Thresholding control register (Read/Write)
54762 + * <i>Offset: 830h</i> */
54763 + volatile uint32_t dtknqr3_dthrctl;
54764 + /** Device IN Token Queue Read Register-4 (Read Only). /
54765 + * Device IN EPs empty Inr. Mask Register (Read/Write)
54766 + * <i>Offset: 834h</i> */
54767 + volatile uint32_t dtknqr4_fifoemptymsk;
54768 + /** Device Each Endpoint Interrupt Register (Read Only). /
54769 + * <i>Offset: 838h</i> */
54770 + volatile uint32_t deachint;
54771 + /** Device Each Endpoint Interrupt mask Register (Read/Write). /
54772 + * <i>Offset: 83Ch</i> */
54773 + volatile uint32_t deachintmsk;
54774 + /** Device Each In Endpoint Interrupt mask Register (Read/Write). /
54775 + * <i>Offset: 840h</i> */
54776 + volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS];
54777 + /** Device Each Out Endpoint Interrupt mask Register (Read/Write). /
54778 + * <i>Offset: 880h</i> */
54779 + volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS];
54780 +} dwc_otg_device_global_regs_t;
54781 +
54782 +/**
54783 + * This union represents the bit fields in the Device Configuration
54784 + * Register. Read the register into the <i>d32</i> member then
54785 + * set/clear the bits using the <i>b</i>it elements. Write the
54786 + * <i>d32</i> member to the dcfg register.
54787 + */
54788 +typedef union dcfg_data {
54789 + /** raw register data */
54790 + uint32_t d32;
54791 + /** register bits */
54792 + struct {
54793 + /** Device Speed */
54794 + unsigned devspd:2;
54795 + /** Non Zero Length Status OUT Handshake */
54796 + unsigned nzstsouthshk:1;
54797 +#define DWC_DCFG_SEND_STALL 1
54798 +
54799 + unsigned ena32khzs:1;
54800 + /** Device Addresses */
54801 + unsigned devaddr:7;
54802 + /** Periodic Frame Interval */
54803 + unsigned perfrint:2;
54804 +#define DWC_DCFG_FRAME_INTERVAL_80 0
54805 +#define DWC_DCFG_FRAME_INTERVAL_85 1
54806 +#define DWC_DCFG_FRAME_INTERVAL_90 2
54807 +#define DWC_DCFG_FRAME_INTERVAL_95 3
54808 +
54809 + /** Enable Device OUT NAK for bulk in DDMA mode */
54810 + unsigned endevoutnak:1;
54811 +
54812 + unsigned reserved14_17:4;
54813 + /** In Endpoint Mis-match count */
54814 + unsigned epmscnt:5;
54815 + /** Enable Descriptor DMA in Device mode */
54816 + unsigned descdma:1;
54817 + unsigned perschintvl:2;
54818 + unsigned resvalid:6;
54819 + } b;
54820 +} dcfg_data_t;
54821 +
54822 +/**
54823 + * This union represents the bit fields in the Device Control
54824 + * Register. Read the register into the <i>d32</i> member then
54825 + * set/clear the bits using the <i>b</i>it elements.
54826 + */
54827 +typedef union dctl_data {
54828 + /** raw register data */
54829 + uint32_t d32;
54830 + /** register bits */
54831 + struct {
54832 + /** Remote Wakeup */
54833 + unsigned rmtwkupsig:1;
54834 + /** Soft Disconnect */
54835 + unsigned sftdiscon:1;
54836 + /** Global Non-Periodic IN NAK Status */
54837 + unsigned gnpinnaksts:1;
54838 + /** Global OUT NAK Status */
54839 + unsigned goutnaksts:1;
54840 + /** Test Control */
54841 + unsigned tstctl:3;
54842 + /** Set Global Non-Periodic IN NAK */
54843 + unsigned sgnpinnak:1;
54844 + /** Clear Global Non-Periodic IN NAK */
54845 + unsigned cgnpinnak:1;
54846 + /** Set Global OUT NAK */
54847 + unsigned sgoutnak:1;
54848 + /** Clear Global OUT NAK */
54849 + unsigned cgoutnak:1;
54850 + /** Power-On Programming Done */
54851 + unsigned pwronprgdone:1;
54852 + /** Reserved */
54853 + unsigned reserved:1;
54854 + /** Global Multi Count */
54855 + unsigned gmc:2;
54856 + /** Ignore Frame Number for ISOC EPs */
54857 + unsigned ifrmnum:1;
54858 + /** NAK on Babble */
54859 + unsigned nakonbble:1;
54860 + /** Enable Continue on BNA */
54861 + unsigned encontonbna:1;
54862 +
54863 + unsigned reserved18_31:14;
54864 + } b;
54865 +} dctl_data_t;
54866 +
54867 +/**
54868 + * This union represents the bit fields in the Device Status
54869 + * Register. Read the register into the <i>d32</i> member then
54870 + * set/clear the bits using the <i>b</i>it elements.
54871 + */
54872 +typedef union dsts_data {
54873 + /** raw register data */
54874 + uint32_t d32;
54875 + /** register bits */
54876 + struct {
54877 + /** Suspend Status */
54878 + unsigned suspsts:1;
54879 + /** Enumerated Speed */
54880 + unsigned enumspd:2;
54881 +#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
54882 +#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
54883 +#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2
54884 +#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3
54885 + /** Erratic Error */
54886 + unsigned errticerr:1;
54887 + unsigned reserved4_7:4;
54888 + /** Frame or Microframe Number of the received SOF */
54889 + unsigned soffn:14;
54890 + unsigned reserved22_31:10;
54891 + } b;
54892 +} dsts_data_t;
54893 +
54894 +/**
54895 + * This union represents the bit fields in the Device IN EP Interrupt
54896 + * Register and the Device IN EP Common Mask Register.
54897 + *
54898 + * - Read the register into the <i>d32</i> member then set/clear the
54899 + * bits using the <i>b</i>it elements.
54900 + */
54901 +typedef union diepint_data {
54902 + /** raw register data */
54903 + uint32_t d32;
54904 + /** register bits */
54905 + struct {
54906 + /** Transfer complete mask */
54907 + unsigned xfercompl:1;
54908 + /** Endpoint disable mask */
54909 + unsigned epdisabled:1;
54910 + /** AHB Error mask */
54911 + unsigned ahberr:1;
54912 + /** TimeOUT Handshake mask (non-ISOC EPs) */
54913 + unsigned timeout:1;
54914 + /** IN Token received with TxF Empty mask */
54915 + unsigned intktxfemp:1;
54916 + /** IN Token Received with EP mismatch mask */
54917 + unsigned intknepmis:1;
54918 + /** IN Endpoint NAK Effective mask */
54919 + unsigned inepnakeff:1;
54920 + /** Reserved */
54921 + unsigned emptyintr:1;
54922 +
54923 + unsigned txfifoundrn:1;
54924 +
54925 + /** BNA Interrupt mask */
54926 + unsigned bna:1;
54927 +
54928 + unsigned reserved10_12:3;
54929 + /** BNA Interrupt mask */
54930 + unsigned nak:1;
54931 +
54932 + unsigned reserved14_31:18;
54933 + } b;
54934 +} diepint_data_t;
54935 +
54936 +/**
54937 + * This union represents the bit fields in the Device IN EP
54938 + * Common/Dedicated Interrupt Mask Register.
54939 + */
54940 +typedef union diepint_data diepmsk_data_t;
54941 +
54942 +/**
54943 + * This union represents the bit fields in the Device OUT EP Interrupt
54944 + * Registerand Device OUT EP Common Interrupt Mask Register.
54945 + *
54946 + * - Read the register into the <i>d32</i> member then set/clear the
54947 + * bits using the <i>b</i>it elements.
54948 + */
54949 +typedef union doepint_data {
54950 + /** raw register data */
54951 + uint32_t d32;
54952 + /** register bits */
54953 + struct {
54954 + /** Transfer complete */
54955 + unsigned xfercompl:1;
54956 + /** Endpoint disable */
54957 + unsigned epdisabled:1;
54958 + /** AHB Error */
54959 + unsigned ahberr:1;
54960 + /** Setup Phase Done (contorl EPs) */
54961 + unsigned setup:1;
54962 + /** OUT Token Received when Endpoint Disabled */
54963 + unsigned outtknepdis:1;
54964 +
54965 + unsigned stsphsercvd:1;
54966 + /** Back-to-Back SETUP Packets Received */
54967 + unsigned back2backsetup:1;
54968 +
54969 + unsigned reserved7:1;
54970 + /** OUT packet Error */
54971 + unsigned outpkterr:1;
54972 + /** BNA Interrupt */
54973 + unsigned bna:1;
54974 +
54975 + unsigned reserved10:1;
54976 + /** Packet Drop Status */
54977 + unsigned pktdrpsts:1;
54978 + /** Babble Interrupt */
54979 + unsigned babble:1;
54980 + /** NAK Interrupt */
54981 + unsigned nak:1;
54982 + /** NYET Interrupt */
54983 + unsigned nyet:1;
54984 + /** Bit indicating setup packet received */
54985 + unsigned sr:1;
54986 +
54987 + unsigned reserved16_31:16;
54988 + } b;
54989 +} doepint_data_t;
54990 +
54991 +/**
54992 + * This union represents the bit fields in the Device OUT EP
54993 + * Common/Dedicated Interrupt Mask Register.
54994 + */
54995 +typedef union doepint_data doepmsk_data_t;
54996 +
54997 +/**
54998 + * This union represents the bit fields in the Device All EP Interrupt
54999 + * and Mask Registers.
55000 + * - Read the register into the <i>d32</i> member then set/clear the
55001 + * bits using the <i>b</i>it elements.
55002 + */
55003 +typedef union daint_data {
55004 + /** raw register data */
55005 + uint32_t d32;
55006 + /** register bits */
55007 + struct {
55008 + /** IN Endpoint bits */
55009 + unsigned in:16;
55010 + /** OUT Endpoint bits */
55011 + unsigned out:16;
55012 + } ep;
55013 + struct {
55014 + /** IN Endpoint bits */
55015 + unsigned inep0:1;
55016 + unsigned inep1:1;
55017 + unsigned inep2:1;
55018 + unsigned inep3:1;
55019 + unsigned inep4:1;
55020 + unsigned inep5:1;
55021 + unsigned inep6:1;
55022 + unsigned inep7:1;
55023 + unsigned inep8:1;
55024 + unsigned inep9:1;
55025 + unsigned inep10:1;
55026 + unsigned inep11:1;
55027 + unsigned inep12:1;
55028 + unsigned inep13:1;
55029 + unsigned inep14:1;
55030 + unsigned inep15:1;
55031 + /** OUT Endpoint bits */
55032 + unsigned outep0:1;
55033 + unsigned outep1:1;
55034 + unsigned outep2:1;
55035 + unsigned outep3:1;
55036 + unsigned outep4:1;
55037 + unsigned outep5:1;
55038 + unsigned outep6:1;
55039 + unsigned outep7:1;
55040 + unsigned outep8:1;
55041 + unsigned outep9:1;
55042 + unsigned outep10:1;
55043 + unsigned outep11:1;
55044 + unsigned outep12:1;
55045 + unsigned outep13:1;
55046 + unsigned outep14:1;
55047 + unsigned outep15:1;
55048 + } b;
55049 +} daint_data_t;
55050 +
55051 +/**
55052 + * This union represents the bit fields in the Device IN Token Queue
55053 + * Read Registers.
55054 + * - Read the register into the <i>d32</i> member.
55055 + * - READ-ONLY Register
55056 + */
55057 +typedef union dtknq1_data {
55058 + /** raw register data */
55059 + uint32_t d32;
55060 + /** register bits */
55061 + struct {
55062 + /** In Token Queue Write Pointer */
55063 + unsigned intknwptr:5;
55064 + /** Reserved */
55065 + unsigned reserved05_06:2;
55066 + /** write pointer has wrapped. */
55067 + unsigned wrap_bit:1;
55068 + /** EP Numbers of IN Tokens 0 ... 4 */
55069 + unsigned epnums0_5:24;
55070 + } b;
55071 +} dtknq1_data_t;
55072 +
55073 +/**
55074 + * This union represents Threshold control Register
55075 + * - Read and write the register into the <i>d32</i> member.
55076 + * - READ-WRITABLE Register
55077 + */
55078 +typedef union dthrctl_data {
55079 + /** raw register data */
55080 + uint32_t d32;
55081 + /** register bits */
55082 + struct {
55083 + /** non ISO Tx Thr. Enable */
55084 + unsigned non_iso_thr_en:1;
55085 + /** ISO Tx Thr. Enable */
55086 + unsigned iso_thr_en:1;
55087 + /** Tx Thr. Length */
55088 + unsigned tx_thr_len:9;
55089 + /** AHB Threshold ratio */
55090 + unsigned ahb_thr_ratio:2;
55091 + /** Reserved */
55092 + unsigned reserved13_15:3;
55093 + /** Rx Thr. Enable */
55094 + unsigned rx_thr_en:1;
55095 + /** Rx Thr. Length */
55096 + unsigned rx_thr_len:9;
55097 + unsigned reserved26:1;
55098 + /** Arbiter Parking Enable*/
55099 + unsigned arbprken:1;
55100 + /** Reserved */
55101 + unsigned reserved28_31:4;
55102 + } b;
55103 +} dthrctl_data_t;
55104 +
55105 +/**
55106 + * Device Logical IN Endpoint-Specific Registers. <i>Offsets
55107 + * 900h-AFCh</i>
55108 + *
55109 + * There will be one set of endpoint registers per logical endpoint
55110 + * implemented.
55111 + *
55112 + * <i>These registers are visible only in Device mode and must not be
55113 + * accessed in Host mode, as the results are unknown.</i>
55114 + */
55115 +typedef struct dwc_otg_dev_in_ep_regs {
55116 + /** Device IN Endpoint Control Register. <i>Offset:900h +
55117 + * (ep_num * 20h) + 00h</i> */
55118 + volatile uint32_t diepctl;
55119 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */
55120 + uint32_t reserved04;
55121 + /** Device IN Endpoint Interrupt Register. <i>Offset:900h +
55122 + * (ep_num * 20h) + 08h</i> */
55123 + volatile uint32_t diepint;
55124 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */
55125 + uint32_t reserved0C;
55126 + /** Device IN Endpoint Transfer Size
55127 + * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */
55128 + volatile uint32_t dieptsiz;
55129 + /** Device IN Endpoint DMA Address Register. <i>Offset:900h +
55130 + * (ep_num * 20h) + 14h</i> */
55131 + volatile uint32_t diepdma;
55132 + /** Device IN Endpoint Transmit FIFO Status Register. <i>Offset:900h +
55133 + * (ep_num * 20h) + 18h</i> */
55134 + volatile uint32_t dtxfsts;
55135 + /** Device IN Endpoint DMA Buffer Register. <i>Offset:900h +
55136 + * (ep_num * 20h) + 1Ch</i> */
55137 + volatile uint32_t diepdmab;
55138 +} dwc_otg_dev_in_ep_regs_t;
55139 +
55140 +/**
55141 + * Device Logical OUT Endpoint-Specific Registers. <i>Offsets:
55142 + * B00h-CFCh</i>
55143 + *
55144 + * There will be one set of endpoint registers per logical endpoint
55145 + * implemented.
55146 + *
55147 + * <i>These registers are visible only in Device mode and must not be
55148 + * accessed in Host mode, as the results are unknown.</i>
55149 + */
55150 +typedef struct dwc_otg_dev_out_ep_regs {
55151 + /** Device OUT Endpoint Control Register. <i>Offset:B00h +
55152 + * (ep_num * 20h) + 00h</i> */
55153 + volatile uint32_t doepctl;
55154 + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 04h</i> */
55155 + uint32_t reserved04;
55156 + /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h +
55157 + * (ep_num * 20h) + 08h</i> */
55158 + volatile uint32_t doepint;
55159 + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */
55160 + uint32_t reserved0C;
55161 + /** Device OUT Endpoint Transfer Size Register. <i>Offset:
55162 + * B00h + (ep_num * 20h) + 10h</i> */
55163 + volatile uint32_t doeptsiz;
55164 + /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h
55165 + * + (ep_num * 20h) + 14h</i> */
55166 + volatile uint32_t doepdma;
55167 + /** Reserved. <i>Offset:B00h + * (ep_num * 20h) + 18h</i> */
55168 + uint32_t unused;
55169 + /** Device OUT Endpoint DMA Buffer Register. <i>Offset:B00h
55170 + * + (ep_num * 20h) + 1Ch</i> */
55171 + uint32_t doepdmab;
55172 +} dwc_otg_dev_out_ep_regs_t;
55173 +
55174 +/**
55175 + * This union represents the bit fields in the Device EP Control
55176 + * Register. Read the register into the <i>d32</i> member then
55177 + * set/clear the bits using the <i>b</i>it elements.
55178 + */
55179 +typedef union depctl_data {
55180 + /** raw register data */
55181 + uint32_t d32;
55182 + /** register bits */
55183 + struct {
55184 + /** Maximum Packet Size
55185 + * IN/OUT EPn
55186 + * IN/OUT EP0 - 2 bits
55187 + * 2'b00: 64 Bytes
55188 + * 2'b01: 32
55189 + * 2'b10: 16
55190 + * 2'b11: 8 */
55191 + unsigned mps:11;
55192 +#define DWC_DEP0CTL_MPS_64 0
55193 +#define DWC_DEP0CTL_MPS_32 1
55194 +#define DWC_DEP0CTL_MPS_16 2
55195 +#define DWC_DEP0CTL_MPS_8 3
55196 +
55197 + /** Next Endpoint
55198 + * IN EPn/IN EP0
55199 + * OUT EPn/OUT EP0 - reserved */
55200 + unsigned nextep:4;
55201 +
55202 + /** USB Active Endpoint */
55203 + unsigned usbactep:1;
55204 +
55205 + /** Endpoint DPID (INTR/Bulk IN and OUT endpoints)
55206 + * This field contains the PID of the packet going to
55207 + * be received or transmitted on this endpoint. The
55208 + * application should program the PID of the first
55209 + * packet going to be received or transmitted on this
55210 + * endpoint , after the endpoint is
55211 + * activated. Application use the SetD1PID and
55212 + * SetD0PID fields of this register to program either
55213 + * D0 or D1 PID.
55214 + *
55215 + * The encoding for this field is
55216 + * - 0: D0
55217 + * - 1: D1
55218 + */
55219 + unsigned dpid:1;
55220 +
55221 + /** NAK Status */
55222 + unsigned naksts:1;
55223 +
55224 + /** Endpoint Type
55225 + * 2'b00: Control
55226 + * 2'b01: Isochronous
55227 + * 2'b10: Bulk
55228 + * 2'b11: Interrupt */
55229 + unsigned eptype:2;
55230 +
55231 + /** Snoop Mode
55232 + * OUT EPn/OUT EP0
55233 + * IN EPn/IN EP0 - reserved */
55234 + unsigned snp:1;
55235 +
55236 + /** Stall Handshake */
55237 + unsigned stall:1;
55238 +
55239 + /** Tx Fifo Number
55240 + * IN EPn/IN EP0
55241 + * OUT EPn/OUT EP0 - reserved */
55242 + unsigned txfnum:4;
55243 +
55244 + /** Clear NAK */
55245 + unsigned cnak:1;
55246 + /** Set NAK */
55247 + unsigned snak:1;
55248 + /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints)
55249 + * Writing to this field sets the Endpoint DPID (DPID)
55250 + * field in this register to DATA0. Set Even
55251 + * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints)
55252 + * Writing to this field sets the Even/Odd
55253 + * (micro)frame (EO_FrNum) field to even (micro)
55254 + * frame.
55255 + */
55256 + unsigned setd0pid:1;
55257 + /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints)
55258 + * Writing to this field sets the Endpoint DPID (DPID)
55259 + * field in this register to DATA1 Set Odd
55260 + * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints)
55261 + * Writing to this field sets the Even/Odd
55262 + * (micro)frame (EO_FrNum) field to odd (micro) frame.
55263 + */
55264 + unsigned setd1pid:1;
55265 +
55266 + /** Endpoint Disable */
55267 + unsigned epdis:1;
55268 + /** Endpoint Enable */
55269 + unsigned epena:1;
55270 + } b;
55271 +} depctl_data_t;
55272 +
55273 +/**
55274 + * This union represents the bit fields in the Device EP Transfer
55275 + * Size Register. Read the register into the <i>d32</i> member then
55276 + * set/clear the bits using the <i>b</i>it elements.
55277 + */
55278 +typedef union deptsiz_data {
55279 + /** raw register data */
55280 + uint32_t d32;
55281 + /** register bits */
55282 + struct {
55283 + /** Transfer size */
55284 + unsigned xfersize:19;
55285 +/** Max packet count for EP (pow(2,10)-1) */
55286 +#define MAX_PKT_CNT 1023
55287 + /** Packet Count */
55288 + unsigned pktcnt:10;
55289 + /** Multi Count - Periodic IN endpoints */
55290 + unsigned mc:2;
55291 + unsigned reserved:1;
55292 + } b;
55293 +} deptsiz_data_t;
55294 +
55295 +/**
55296 + * This union represents the bit fields in the Device EP 0 Transfer
55297 + * Size Register. Read the register into the <i>d32</i> member then
55298 + * set/clear the bits using the <i>b</i>it elements.
55299 + */
55300 +typedef union deptsiz0_data {
55301 + /** raw register data */
55302 + uint32_t d32;
55303 + /** register bits */
55304 + struct {
55305 + /** Transfer size */
55306 + unsigned xfersize:7;
55307 + /** Reserved */
55308 + unsigned reserved7_18:12;
55309 + /** Packet Count */
55310 + unsigned pktcnt:2;
55311 + /** Reserved */
55312 + unsigned reserved21_28:8;
55313 + /**Setup Packet Count (DOEPTSIZ0 Only) */
55314 + unsigned supcnt:2;
55315 + unsigned reserved31;
55316 + } b;
55317 +} deptsiz0_data_t;
55318 +
55319 +/////////////////////////////////////////////////
55320 +// DMA Descriptor Specific Structures
55321 +//
55322 +
55323 +/** Buffer status definitions */
55324 +
55325 +#define BS_HOST_READY 0x0
55326 +#define BS_DMA_BUSY 0x1
55327 +#define BS_DMA_DONE 0x2
55328 +#define BS_HOST_BUSY 0x3
55329 +
55330 +/** Receive/Transmit status definitions */
55331 +
55332 +#define RTS_SUCCESS 0x0
55333 +#define RTS_BUFFLUSH 0x1
55334 +#define RTS_RESERVED 0x2
55335 +#define RTS_BUFERR 0x3
55336 +
55337 +/**
55338 + * This union represents the bit fields in the DMA Descriptor
55339 + * status quadlet. Read the quadlet into the <i>d32</i> member then
55340 + * set/clear the bits using the <i>b</i>it, <i>b_iso_out</i> and
55341 + * <i>b_iso_in</i> elements.
55342 + */
55343 +typedef union dev_dma_desc_sts {
55344 + /** raw register data */
55345 + uint32_t d32;
55346 + /** quadlet bits */
55347 + struct {
55348 + /** Received number of bytes */
55349 + unsigned bytes:16;
55350 + /** NAK bit - only for OUT EPs */
55351 + unsigned nak:1;
55352 + unsigned reserved17_22:6;
55353 + /** Multiple Transfer - only for OUT EPs */
55354 + unsigned mtrf:1;
55355 + /** Setup Packet received - only for OUT EPs */
55356 + unsigned sr:1;
55357 + /** Interrupt On Complete */
55358 + unsigned ioc:1;
55359 + /** Short Packet */
55360 + unsigned sp:1;
55361 + /** Last */
55362 + unsigned l:1;
55363 + /** Receive Status */
55364 + unsigned sts:2;
55365 + /** Buffer Status */
55366 + unsigned bs:2;
55367 + } b;
55368 +
55369 +//#ifdef DWC_EN_ISOC
55370 + /** iso out quadlet bits */
55371 + struct {
55372 + /** Received number of bytes */
55373 + unsigned rxbytes:11;
55374 +
55375 + unsigned reserved11:1;
55376 + /** Frame Number */
55377 + unsigned framenum:11;
55378 + /** Received ISO Data PID */
55379 + unsigned pid:2;
55380 + /** Interrupt On Complete */
55381 + unsigned ioc:1;
55382 + /** Short Packet */
55383 + unsigned sp:1;
55384 + /** Last */
55385 + unsigned l:1;
55386 + /** Receive Status */
55387 + unsigned rxsts:2;
55388 + /** Buffer Status */
55389 + unsigned bs:2;
55390 + } b_iso_out;
55391 +
55392 + /** iso in quadlet bits */
55393 + struct {
55394 + /** Transmited number of bytes */
55395 + unsigned txbytes:12;
55396 + /** Frame Number */
55397 + unsigned framenum:11;
55398 + /** Transmited ISO Data PID */
55399 + unsigned pid:2;
55400 + /** Interrupt On Complete */
55401 + unsigned ioc:1;
55402 + /** Short Packet */
55403 + unsigned sp:1;
55404 + /** Last */
55405 + unsigned l:1;
55406 + /** Transmit Status */
55407 + unsigned txsts:2;
55408 + /** Buffer Status */
55409 + unsigned bs:2;
55410 + } b_iso_in;
55411 +//#endif /* DWC_EN_ISOC */
55412 +} dev_dma_desc_sts_t;
55413 +
55414 +/**
55415 + * DMA Descriptor structure
55416 + *
55417 + * DMA Descriptor structure contains two quadlets:
55418 + * Status quadlet and Data buffer pointer.
55419 + */
55420 +typedef struct dwc_otg_dev_dma_desc {
55421 + /** DMA Descriptor status quadlet */
55422 + dev_dma_desc_sts_t status;
55423 + /** DMA Descriptor data buffer pointer */
55424 + uint32_t buf;
55425 +} dwc_otg_dev_dma_desc_t;
55426 +
55427 +/**
55428 + * The dwc_otg_dev_if structure contains information needed to manage
55429 + * the DWC_otg controller acting in device mode. It represents the
55430 + * programming view of the device-specific aspects of the controller.
55431 + */
55432 +typedef struct dwc_otg_dev_if {
55433 + /** Pointer to device Global registers.
55434 + * Device Global Registers starting at offset 800h
55435 + */
55436 + dwc_otg_device_global_regs_t *dev_global_regs;
55437 +#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
55438 +
55439 + /**
55440 + * Device Logical IN Endpoint-Specific Registers 900h-AFCh
55441 + */
55442 + dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS];
55443 +#define DWC_DEV_IN_EP_REG_OFFSET 0x900
55444 +#define DWC_EP_REG_OFFSET 0x20
55445 +
55446 + /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
55447 + dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];
55448 +#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
55449 +
55450 + /* Device configuration information */
55451 + uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */
55452 + uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */
55453 + uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/
55454 +
55455 + /** Size of periodic FIFOs (Bytes) */
55456 + uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS];
55457 +
55458 + /** Size of Tx FIFOs (Bytes) */
55459 + uint16_t tx_fifo_size[MAX_TX_FIFOS];
55460 +
55461 + /** Thresholding enable flags and length varaiables **/
55462 + uint16_t rx_thr_en;
55463 + uint16_t iso_tx_thr_en;
55464 + uint16_t non_iso_tx_thr_en;
55465 +
55466 + uint16_t rx_thr_length;
55467 + uint16_t tx_thr_length;
55468 +
55469 + /**
55470 + * Pointers to the DMA Descriptors for EP0 Control
55471 + * transfers (virtual and physical)
55472 + */
55473 +
55474 + /** 2 descriptors for SETUP packets */
55475 + dwc_dma_t dma_setup_desc_addr[2];
55476 + dwc_otg_dev_dma_desc_t *setup_desc_addr[2];
55477 +
55478 + /** Pointer to Descriptor with latest SETUP packet */
55479 + dwc_otg_dev_dma_desc_t *psetup;
55480 +
55481 + /** Index of current SETUP handler descriptor */
55482 + uint32_t setup_desc_index;
55483 +
55484 + /** Descriptor for Data In or Status In phases */
55485 + dwc_dma_t dma_in_desc_addr;
55486 + dwc_otg_dev_dma_desc_t *in_desc_addr;
55487 +
55488 + /** Descriptor for Data Out or Status Out phases */
55489 + dwc_dma_t dma_out_desc_addr;
55490 + dwc_otg_dev_dma_desc_t *out_desc_addr;
55491 +
55492 + /** Setup Packet Detected - if set clear NAK when queueing */
55493 + uint32_t spd;
55494 + /** Isoc ep pointer on which incomplete happens */
55495 + void *isoc_ep;
55496 +
55497 +} dwc_otg_dev_if_t;
55498 +
55499 +/////////////////////////////////////////////////
55500 +// Host Mode Register Structures
55501 +//
55502 +/**
55503 + * The Host Global Registers structure defines the size and relative
55504 + * field offsets for the Host Mode Global Registers. Host Global
55505 + * Registers offsets 400h-7FFh.
55506 +*/
55507 +typedef struct dwc_otg_host_global_regs {
55508 + /** Host Configuration Register. <i>Offset: 400h</i> */
55509 + volatile uint32_t hcfg;
55510 + /** Host Frame Interval Register. <i>Offset: 404h</i> */
55511 + volatile uint32_t hfir;
55512 + /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */
55513 + volatile uint32_t hfnum;
55514 + /** Reserved. <i>Offset: 40Ch</i> */
55515 + uint32_t reserved40C;
55516 + /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */
55517 + volatile uint32_t hptxsts;
55518 + /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */
55519 + volatile uint32_t haint;
55520 + /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */
55521 + volatile uint32_t haintmsk;
55522 + /** Host Frame List Base Address Register . <i>Offset: 41Ch</i> */
55523 + volatile uint32_t hflbaddr;
55524 +} dwc_otg_host_global_regs_t;
55525 +
55526 +/**
55527 + * This union represents the bit fields in the Host Configuration Register.
55528 + * Read the register into the <i>d32</i> member then set/clear the bits using
55529 + * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register.
55530 + */
55531 +typedef union hcfg_data {
55532 + /** raw register data */
55533 + uint32_t d32;
55534 +
55535 + /** register bits */
55536 + struct {
55537 + /** FS/LS Phy Clock Select */
55538 + unsigned fslspclksel:2;
55539 +#define DWC_HCFG_30_60_MHZ 0
55540 +#define DWC_HCFG_48_MHZ 1
55541 +#define DWC_HCFG_6_MHZ 2
55542 +
55543 + /** FS/LS Only Support */
55544 + unsigned fslssupp:1;
55545 + unsigned reserved3_6:4;
55546 + /** Enable 32-KHz Suspend Mode */
55547 + unsigned ena32khzs:1;
55548 + /** Resume Validation Periiod */
55549 + unsigned resvalid:8;
55550 + unsigned reserved16_22:7;
55551 + /** Enable Scatter/gather DMA in Host mode */
55552 + unsigned descdma:1;
55553 + /** Frame List Entries */
55554 + unsigned frlisten:2;
55555 + /** Enable Periodic Scheduling */
55556 + unsigned perschedena:1;
55557 + unsigned reserved27_30:4;
55558 + unsigned modechtimen:1;
55559 + } b;
55560 +} hcfg_data_t;
55561 +
55562 +/**
55563 + * This union represents the bit fields in the Host Frame Remaing/Number
55564 + * Register.
55565 + */
55566 +typedef union hfir_data {
55567 + /** raw register data */
55568 + uint32_t d32;
55569 +
55570 + /** register bits */
55571 + struct {
55572 + unsigned frint:16;
55573 + unsigned hfirrldctrl:1;
55574 + unsigned reserved:15;
55575 + } b;
55576 +} hfir_data_t;
55577 +
55578 +/**
55579 + * This union represents the bit fields in the Host Frame Remaing/Number
55580 + * Register.
55581 + */
55582 +typedef union hfnum_data {
55583 + /** raw register data */
55584 + uint32_t d32;
55585 +
55586 + /** register bits */
55587 + struct {
55588 + unsigned frnum:16;
55589 +#define DWC_HFNUM_MAX_FRNUM 0x3FFF
55590 + unsigned frrem:16;
55591 + } b;
55592 +} hfnum_data_t;
55593 +
55594 +typedef union hptxsts_data {
55595 + /** raw register data */
55596 + uint32_t d32;
55597 +
55598 + /** register bits */
55599 + struct {
55600 + unsigned ptxfspcavail:16;
55601 + unsigned ptxqspcavail:8;
55602 + /** Top of the Periodic Transmit Request Queue
55603 + * - bit 24 - Terminate (last entry for the selected channel)
55604 + * - bits 26:25 - Token Type
55605 + * - 2'b00 - Zero length
55606 + * - 2'b01 - Ping
55607 + * - 2'b10 - Disable
55608 + * - bits 30:27 - Channel Number
55609 + * - bit 31 - Odd/even microframe
55610 + */
55611 + unsigned ptxqtop_terminate:1;
55612 + unsigned ptxqtop_token:2;
55613 + unsigned ptxqtop_chnum:4;
55614 + unsigned ptxqtop_odd:1;
55615 + } b;
55616 +} hptxsts_data_t;
55617 +
55618 +/**
55619 + * This union represents the bit fields in the Host Port Control and Status
55620 + * Register. Read the register into the <i>d32</i> member then set/clear the
55621 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55622 + * hprt0 register.
55623 + */
55624 +typedef union hprt0_data {
55625 + /** raw register data */
55626 + uint32_t d32;
55627 + /** register bits */
55628 + struct {
55629 + unsigned prtconnsts:1;
55630 + unsigned prtconndet:1;
55631 + unsigned prtena:1;
55632 + unsigned prtenchng:1;
55633 + unsigned prtovrcurract:1;
55634 + unsigned prtovrcurrchng:1;
55635 + unsigned prtres:1;
55636 + unsigned prtsusp:1;
55637 + unsigned prtrst:1;
55638 + unsigned reserved9:1;
55639 + unsigned prtlnsts:2;
55640 + unsigned prtpwr:1;
55641 + unsigned prttstctl:4;
55642 + unsigned prtspd:2;
55643 +#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
55644 +#define DWC_HPRT0_PRTSPD_FULL_SPEED 1
55645 +#define DWC_HPRT0_PRTSPD_LOW_SPEED 2
55646 + unsigned reserved19_31:13;
55647 + } b;
55648 +} hprt0_data_t;
55649 +
55650 +/**
55651 + * This union represents the bit fields in the Host All Interrupt
55652 + * Register.
55653 + */
55654 +typedef union haint_data {
55655 + /** raw register data */
55656 + uint32_t d32;
55657 + /** register bits */
55658 + struct {
55659 + unsigned ch0:1;
55660 + unsigned ch1:1;
55661 + unsigned ch2:1;
55662 + unsigned ch3:1;
55663 + unsigned ch4:1;
55664 + unsigned ch5:1;
55665 + unsigned ch6:1;
55666 + unsigned ch7:1;
55667 + unsigned ch8:1;
55668 + unsigned ch9:1;
55669 + unsigned ch10:1;
55670 + unsigned ch11:1;
55671 + unsigned ch12:1;
55672 + unsigned ch13:1;
55673 + unsigned ch14:1;
55674 + unsigned ch15:1;
55675 + unsigned reserved:16;
55676 + } b;
55677 +
55678 + struct {
55679 + unsigned chint:16;
55680 + unsigned reserved:16;
55681 + } b2;
55682 +} haint_data_t;
55683 +
55684 +/**
55685 + * This union represents the bit fields in the Host All Interrupt
55686 + * Register.
55687 + */
55688 +typedef union haintmsk_data {
55689 + /** raw register data */
55690 + uint32_t d32;
55691 + /** register bits */
55692 + struct {
55693 + unsigned ch0:1;
55694 + unsigned ch1:1;
55695 + unsigned ch2:1;
55696 + unsigned ch3:1;
55697 + unsigned ch4:1;
55698 + unsigned ch5:1;
55699 + unsigned ch6:1;
55700 + unsigned ch7:1;
55701 + unsigned ch8:1;
55702 + unsigned ch9:1;
55703 + unsigned ch10:1;
55704 + unsigned ch11:1;
55705 + unsigned ch12:1;
55706 + unsigned ch13:1;
55707 + unsigned ch14:1;
55708 + unsigned ch15:1;
55709 + unsigned reserved:16;
55710 + } b;
55711 +
55712 + struct {
55713 + unsigned chint:16;
55714 + unsigned reserved:16;
55715 + } b2;
55716 +} haintmsk_data_t;
55717 +
55718 +/**
55719 + * Host Channel Specific Registers. <i>500h-5FCh</i>
55720 + */
55721 +typedef struct dwc_otg_hc_regs {
55722 + /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */
55723 + volatile uint32_t hcchar;
55724 + /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */
55725 + volatile uint32_t hcsplt;
55726 + /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */
55727 + volatile uint32_t hcint;
55728 + /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */
55729 + volatile uint32_t hcintmsk;
55730 + /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */
55731 + volatile uint32_t hctsiz;
55732 + /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */
55733 + volatile uint32_t hcdma;
55734 + volatile uint32_t reserved;
55735 + /** Host Channel 0 DMA Buffer Address Register. <i>Offset: 500h + (chan_num * 20h) + 1Ch</i> */
55736 + volatile uint32_t hcdmab;
55737 +} dwc_otg_hc_regs_t;
55738 +
55739 +/**
55740 + * This union represents the bit fields in the Host Channel Characteristics
55741 + * Register. Read the register into the <i>d32</i> member then set/clear the
55742 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55743 + * hcchar register.
55744 + */
55745 +typedef union hcchar_data {
55746 + /** raw register data */
55747 + uint32_t d32;
55748 +
55749 + /** register bits */
55750 + struct {
55751 + /** Maximum packet size in bytes */
55752 + unsigned mps:11;
55753 +
55754 + /** Endpoint number */
55755 + unsigned epnum:4;
55756 +
55757 + /** 0: OUT, 1: IN */
55758 + unsigned epdir:1;
55759 +
55760 + unsigned reserved:1;
55761 +
55762 + /** 0: Full/high speed device, 1: Low speed device */
55763 + unsigned lspddev:1;
55764 +
55765 + /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
55766 + unsigned eptype:2;
55767 +
55768 + /** Packets per frame for periodic transfers. 0 is reserved. */
55769 + unsigned multicnt:2;
55770 +
55771 + /** Device address */
55772 + unsigned devaddr:7;
55773 +
55774 + /**
55775 + * Frame to transmit periodic transaction.
55776 + * 0: even, 1: odd
55777 + */
55778 + unsigned oddfrm:1;
55779 +
55780 + /** Channel disable */
55781 + unsigned chdis:1;
55782 +
55783 + /** Channel enable */
55784 + unsigned chen:1;
55785 + } b;
55786 +} hcchar_data_t;
55787 +
55788 +typedef union hcsplt_data {
55789 + /** raw register data */
55790 + uint32_t d32;
55791 +
55792 + /** register bits */
55793 + struct {
55794 + /** Port Address */
55795 + unsigned prtaddr:7;
55796 +
55797 + /** Hub Address */
55798 + unsigned hubaddr:7;
55799 +
55800 + /** Transaction Position */
55801 + unsigned xactpos:2;
55802 +#define DWC_HCSPLIT_XACTPOS_MID 0
55803 +#define DWC_HCSPLIT_XACTPOS_END 1
55804 +#define DWC_HCSPLIT_XACTPOS_BEGIN 2
55805 +#define DWC_HCSPLIT_XACTPOS_ALL 3
55806 +
55807 + /** Do Complete Split */
55808 + unsigned compsplt:1;
55809 +
55810 + /** Reserved */
55811 + unsigned reserved:14;
55812 +
55813 + /** Split Enble */
55814 + unsigned spltena:1;
55815 + } b;
55816 +} hcsplt_data_t;
55817 +
55818 +/**
55819 + * This union represents the bit fields in the Host All Interrupt
55820 + * Register.
55821 + */
55822 +typedef union hcint_data {
55823 + /** raw register data */
55824 + uint32_t d32;
55825 + /** register bits */
55826 + struct {
55827 + /** Transfer Complete */
55828 + unsigned xfercomp:1;
55829 + /** Channel Halted */
55830 + unsigned chhltd:1;
55831 + /** AHB Error */
55832 + unsigned ahberr:1;
55833 + /** STALL Response Received */
55834 + unsigned stall:1;
55835 + /** NAK Response Received */
55836 + unsigned nak:1;
55837 + /** ACK Response Received */
55838 + unsigned ack:1;
55839 + /** NYET Response Received */
55840 + unsigned nyet:1;
55841 + /** Transaction Err */
55842 + unsigned xacterr:1;
55843 + /** Babble Error */
55844 + unsigned bblerr:1;
55845 + /** Frame Overrun */
55846 + unsigned frmovrun:1;
55847 + /** Data Toggle Error */
55848 + unsigned datatglerr:1;
55849 + /** Buffer Not Available (only for DDMA mode) */
55850 + unsigned bna:1;
55851 + /** Exessive transaction error (only for DDMA mode) */
55852 + unsigned xcs_xact:1;
55853 + /** Frame List Rollover interrupt */
55854 + unsigned frm_list_roll:1;
55855 + /** Reserved */
55856 + unsigned reserved14_31:18;
55857 + } b;
55858 +} hcint_data_t;
55859 +
55860 +/**
55861 + * This union represents the bit fields in the Host Channel Interrupt Mask
55862 + * Register. Read the register into the <i>d32</i> member then set/clear the
55863 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55864 + * hcintmsk register.
55865 + */
55866 +typedef union hcintmsk_data {
55867 + /** raw register data */
55868 + uint32_t d32;
55869 +
55870 + /** register bits */
55871 + struct {
55872 + unsigned xfercompl:1;
55873 + unsigned chhltd:1;
55874 + unsigned ahberr:1;
55875 + unsigned stall:1;
55876 + unsigned nak:1;
55877 + unsigned ack:1;
55878 + unsigned nyet:1;
55879 + unsigned xacterr:1;
55880 + unsigned bblerr:1;
55881 + unsigned frmovrun:1;
55882 + unsigned datatglerr:1;
55883 + unsigned bna:1;
55884 + unsigned xcs_xact:1;
55885 + unsigned frm_list_roll:1;
55886 + unsigned reserved14_31:18;
55887 + } b;
55888 +} hcintmsk_data_t;
55889 +
55890 +/**
55891 + * This union represents the bit fields in the Host Channel Transfer Size
55892 + * Register. Read the register into the <i>d32</i> member then set/clear the
55893 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55894 + * hcchar register.
55895 + */
55896 +
55897 +typedef union hctsiz_data {
55898 + /** raw register data */
55899 + uint32_t d32;
55900 +
55901 + /** register bits */
55902 + struct {
55903 + /** Total transfer size in bytes */
55904 + unsigned xfersize:19;
55905 +
55906 + /** Data packets to transfer */
55907 + unsigned pktcnt:10;
55908 +
55909 + /**
55910 + * Packet ID for next data packet
55911 + * 0: DATA0
55912 + * 1: DATA2
55913 + * 2: DATA1
55914 + * 3: MDATA (non-Control), SETUP (Control)
55915 + */
55916 + unsigned pid:2;
55917 +#define DWC_HCTSIZ_DATA0 0
55918 +#define DWC_HCTSIZ_DATA1 2
55919 +#define DWC_HCTSIZ_DATA2 1
55920 +#define DWC_HCTSIZ_MDATA 3
55921 +#define DWC_HCTSIZ_SETUP 3
55922 +
55923 + /** Do PING protocol when 1 */
55924 + unsigned dopng:1;
55925 + } b;
55926 +
55927 + /** register bits */
55928 + struct {
55929 + /** Scheduling information */
55930 + unsigned schinfo:8;
55931 +
55932 + /** Number of transfer descriptors.
55933 + * Max value:
55934 + * 64 in general,
55935 + * 256 only for HS isochronous endpoint.
55936 + */
55937 + unsigned ntd:8;
55938 +
55939 + /** Data packets to transfer */
55940 + unsigned reserved16_28:13;
55941 +
55942 + /**
55943 + * Packet ID for next data packet
55944 + * 0: DATA0
55945 + * 1: DATA2
55946 + * 2: DATA1
55947 + * 3: MDATA (non-Control)
55948 + */
55949 + unsigned pid:2;
55950 +
55951 + /** Do PING protocol when 1 */
55952 + unsigned dopng:1;
55953 + } b_ddma;
55954 +} hctsiz_data_t;
55955 +
55956 +/**
55957 + * This union represents the bit fields in the Host DMA Address
55958 + * Register used in Descriptor DMA mode.
55959 + */
55960 +typedef union hcdma_data {
55961 + /** raw register data */
55962 + uint32_t d32;
55963 + /** register bits */
55964 + struct {
55965 + unsigned reserved0_2:3;
55966 + /** Current Transfer Descriptor. Not used for ISOC */
55967 + unsigned ctd:8;
55968 + /** Start Address of Descriptor List */
55969 + unsigned dma_addr:21;
55970 + } b;
55971 +} hcdma_data_t;
55972 +
55973 +/**
55974 + * This union represents the bit fields in the DMA Descriptor
55975 + * status quadlet for host mode. Read the quadlet into the <i>d32</i> member then
55976 + * set/clear the bits using the <i>b</i>it elements.
55977 + */
55978 +typedef union host_dma_desc_sts {
55979 + /** raw register data */
55980 + uint32_t d32;
55981 + /** quadlet bits */
55982 +
55983 + /* for non-isochronous */
55984 + struct {
55985 + /** Number of bytes */
55986 + unsigned n_bytes:17;
55987 + /** QTD offset to jump when Short Packet received - only for IN EPs */
55988 + unsigned qtd_offset:6;
55989 + /**
55990 + * Set to request the core to jump to alternate QTD if
55991 + * Short Packet received - only for IN EPs
55992 + */
55993 + unsigned a_qtd:1;
55994 + /**
55995 + * Setup Packet bit. When set indicates that buffer contains
55996 + * setup packet.
55997 + */
55998 + unsigned sup:1;
55999 + /** Interrupt On Complete */
56000 + unsigned ioc:1;
56001 + /** End of List */
56002 + unsigned eol:1;
56003 + unsigned reserved27:1;
56004 + /** Rx/Tx Status */
56005 + unsigned sts:2;
56006 +#define DMA_DESC_STS_PKTERR 1
56007 + unsigned reserved30:1;
56008 + /** Active Bit */
56009 + unsigned a:1;
56010 + } b;
56011 + /* for isochronous */
56012 + struct {
56013 + /** Number of bytes */
56014 + unsigned n_bytes:12;
56015 + unsigned reserved12_24:13;
56016 + /** Interrupt On Complete */
56017 + unsigned ioc:1;
56018 + unsigned reserved26_27:2;
56019 + /** Rx/Tx Status */
56020 + unsigned sts:2;
56021 + unsigned reserved30:1;
56022 + /** Active Bit */
56023 + unsigned a:1;
56024 + } b_isoc;
56025 +} host_dma_desc_sts_t;
56026 +
56027 +#define MAX_DMA_DESC_SIZE 131071
56028 +#define MAX_DMA_DESC_NUM_GENERIC 64
56029 +#define MAX_DMA_DESC_NUM_HS_ISOC 256
56030 +#define MAX_FRLIST_EN_NUM 64
56031 +/**
56032 + * Host-mode DMA Descriptor structure
56033 + *
56034 + * DMA Descriptor structure contains two quadlets:
56035 + * Status quadlet and Data buffer pointer.
56036 + */
56037 +typedef struct dwc_otg_host_dma_desc {
56038 + /** DMA Descriptor status quadlet */
56039 + host_dma_desc_sts_t status;
56040 + /** DMA Descriptor data buffer pointer */
56041 + uint32_t buf;
56042 +} dwc_otg_host_dma_desc_t;
56043 +
56044 +/** OTG Host Interface Structure.
56045 + *
56046 + * The OTG Host Interface Structure structure contains information
56047 + * needed to manage the DWC_otg controller acting in host mode. It
56048 + * represents the programming view of the host-specific aspects of the
56049 + * controller.
56050 + */
56051 +typedef struct dwc_otg_host_if {
56052 + /** Host Global Registers starting at offset 400h.*/
56053 + dwc_otg_host_global_regs_t *host_global_regs;
56054 +#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
56055 +
56056 + /** Host Port 0 Control and Status Register */
56057 + volatile uint32_t *hprt0;
56058 +#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
56059 +
56060 + /** Host Channel Specific Registers at offsets 500h-5FCh. */
56061 + dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS];
56062 +#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
56063 +#define DWC_OTG_CHAN_REGS_OFFSET 0x20
56064 +
56065 + /* Host configuration information */
56066 + /** Number of Host Channels (range: 1-16) */
56067 + uint8_t num_host_channels;
56068 + /** Periodic EPs supported (0: no, 1: yes) */
56069 + uint8_t perio_eps_supported;
56070 + /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */
56071 + uint16_t perio_tx_fifo_size;
56072 +
56073 +} dwc_otg_host_if_t;
56074 +
56075 +/**
56076 + * This union represents the bit fields in the Power and Clock Gating Control
56077 + * Register. Read the register into the <i>d32</i> member then set/clear the
56078 + * bits using the <i>b</i>it elements.
56079 + */
56080 +typedef union pcgcctl_data {
56081 + /** raw register data */
56082 + uint32_t d32;
56083 +
56084 + /** register bits */
56085 + struct {
56086 + /** Stop Pclk */
56087 + unsigned stoppclk:1;
56088 + /** Gate Hclk */
56089 + unsigned gatehclk:1;
56090 + /** Power Clamp */
56091 + unsigned pwrclmp:1;
56092 + /** Reset Power Down Modules */
56093 + unsigned rstpdwnmodule:1;
56094 + /** Reserved */
56095 + unsigned reserved:1;
56096 + /** Enable Sleep Clock Gating (Enbl_L1Gating) */
56097 + unsigned enbl_sleep_gating:1;
56098 + /** PHY In Sleep (PhySleep) */
56099 + unsigned phy_in_sleep:1;
56100 + /** Deep Sleep*/
56101 + unsigned deep_sleep:1;
56102 + unsigned resetaftsusp:1;
56103 + unsigned restoremode:1;
56104 + unsigned enbl_extnd_hiber:1;
56105 + unsigned extnd_hiber_pwrclmp:1;
56106 + unsigned extnd_hiber_switch:1;
56107 + unsigned ess_reg_restored:1;
56108 + unsigned prt_clk_sel:2;
56109 + unsigned port_power:1;
56110 + unsigned max_xcvrselect:2;
56111 + unsigned max_termsel:1;
56112 + unsigned mac_dev_addr:7;
56113 + unsigned p2hd_dev_enum_spd:2;
56114 + unsigned p2hd_prt_spd:2;
56115 + unsigned if_dev_mode:1;
56116 + } b;
56117 +} pcgcctl_data_t;
56118 +
56119 +/**
56120 + * This union represents the bit fields in the Global Data FIFO Software
56121 + * Configuration Register. Read the register into the <i>d32</i> member then
56122 + * set/clear the bits using the <i>b</i>it elements.
56123 + */
56124 +typedef union gdfifocfg_data {
56125 + /* raw register data */
56126 + uint32_t d32;
56127 + /** register bits */
56128 + struct {
56129 + /** OTG Data FIFO depth */
56130 + unsigned gdfifocfg:16;
56131 + /** Start address of EP info controller */
56132 + unsigned epinfobase:16;
56133 + } b;
56134 +} gdfifocfg_data_t;
56135 +
56136 +/**
56137 + * This union represents the bit fields in the Global Power Down Register
56138 + * Register. Read the register into the <i>d32</i> member then set/clear the
56139 + * bits using the <i>b</i>it elements.
56140 + */
56141 +typedef union gpwrdn_data {
56142 + /* raw register data */
56143 + uint32_t d32;
56144 +
56145 + /** register bits */
56146 + struct {
56147 + /** PMU Interrupt Select */
56148 + unsigned pmuintsel:1;
56149 + /** PMU Active */
56150 + unsigned pmuactv:1;
56151 + /** Restore */
56152 + unsigned restore:1;
56153 + /** Power Down Clamp */
56154 + unsigned pwrdnclmp:1;
56155 + /** Power Down Reset */
56156 + unsigned pwrdnrstn:1;
56157 + /** Power Down Switch */
56158 + unsigned pwrdnswtch:1;
56159 + /** Disable VBUS */
56160 + unsigned dis_vbus:1;
56161 + /** Line State Change */
56162 + unsigned lnstschng:1;
56163 + /** Line state change mask */
56164 + unsigned lnstchng_msk:1;
56165 + /** Reset Detected */
56166 + unsigned rst_det:1;
56167 + /** Reset Detect mask */
56168 + unsigned rst_det_msk:1;
56169 + /** Disconnect Detected */
56170 + unsigned disconn_det:1;
56171 + /** Disconnect Detect mask */
56172 + unsigned disconn_det_msk:1;
56173 + /** Connect Detected*/
56174 + unsigned connect_det:1;
56175 + /** Connect Detected Mask*/
56176 + unsigned connect_det_msk:1;
56177 + /** SRP Detected */
56178 + unsigned srp_det:1;
56179 + /** SRP Detect mask */
56180 + unsigned srp_det_msk:1;
56181 + /** Status Change Interrupt */
56182 + unsigned sts_chngint:1;
56183 + /** Status Change Interrupt Mask */
56184 + unsigned sts_chngint_msk:1;
56185 + /** Line State */
56186 + unsigned linestate:2;
56187 + /** Indicates current mode(status of IDDIG signal) */
56188 + unsigned idsts:1;
56189 + /** B Session Valid signal status*/
56190 + unsigned bsessvld:1;
56191 + /** ADP Event Detected */
56192 + unsigned adp_int:1;
56193 + /** Multi Valued ID pin */
56194 + unsigned mult_val_id_bc:5;
56195 + /** Reserved 24_31 */
56196 + unsigned reserved29_31:3;
56197 + } b;
56198 +} gpwrdn_data_t;
56199 +
56200 +#endif
56201 --- /dev/null
56202 +++ b/drivers/usb/host/dwc_otg/test/Makefile
56203 @@ -0,0 +1,16 @@
56204 +
56205 +PERL=/usr/bin/perl
56206 +PL_TESTS=test_sysfs.pl test_mod_param.pl
56207 +
56208 +.PHONY : test
56209 +test : perl_tests
56210 +
56211 +perl_tests :
56212 + @echo
56213 + @echo Running perl tests
56214 + @for test in $(PL_TESTS); do \
56215 + if $(PERL) ./$$test ; then \
56216 + echo "=======> $$test, PASSED" ; \
56217 + else echo "=======> $$test, FAILED" ; \
56218 + fi \
56219 + done
56220 --- /dev/null
56221 +++ b/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
56222 @@ -0,0 +1,337 @@
56223 +package dwc_otg_test;
56224 +
56225 +use strict;
56226 +use Exporter ();
56227 +
56228 +use vars qw(@ISA @EXPORT
56229 +$sysfsdir $paramdir $errors $params
56230 +);
56231 +
56232 +@ISA = qw(Exporter);
56233 +
56234 +#
56235 +# Globals
56236 +#
56237 +$sysfsdir = "/sys/devices/lm0";
56238 +$paramdir = "/sys/module/dwc_otg";
56239 +$errors = 0;
56240 +
56241 +$params = [
56242 + {
56243 + NAME => "otg_cap",
56244 + DEFAULT => 0,
56245 + ENUM => [],
56246 + LOW => 0,
56247 + HIGH => 2
56248 + },
56249 + {
56250 + NAME => "dma_enable",
56251 + DEFAULT => 0,
56252 + ENUM => [],
56253 + LOW => 0,
56254 + HIGH => 1
56255 + },
56256 + {
56257 + NAME => "dma_burst_size",
56258 + DEFAULT => 32,
56259 + ENUM => [1, 4, 8, 16, 32, 64, 128, 256],
56260 + LOW => 1,
56261 + HIGH => 256
56262 + },
56263 + {
56264 + NAME => "host_speed",
56265 + DEFAULT => 0,
56266 + ENUM => [],
56267 + LOW => 0,
56268 + HIGH => 1
56269 + },
56270 + {
56271 + NAME => "host_support_fs_ls_low_power",
56272 + DEFAULT => 0,
56273 + ENUM => [],
56274 + LOW => 0,
56275 + HIGH => 1
56276 + },
56277 + {
56278 + NAME => "host_ls_low_power_phy_clk",
56279 + DEFAULT => 0,
56280 + ENUM => [],
56281 + LOW => 0,
56282 + HIGH => 1
56283 + },
56284 + {
56285 + NAME => "dev_speed",
56286 + DEFAULT => 0,
56287 + ENUM => [],
56288 + LOW => 0,
56289 + HIGH => 1
56290 + },
56291 + {
56292 + NAME => "enable_dynamic_fifo",
56293 + DEFAULT => 1,
56294 + ENUM => [],
56295 + LOW => 0,
56296 + HIGH => 1
56297 + },
56298 + {
56299 + NAME => "data_fifo_size",
56300 + DEFAULT => 8192,
56301 + ENUM => [],
56302 + LOW => 32,
56303 + HIGH => 32768
56304 + },
56305 + {
56306 + NAME => "dev_rx_fifo_size",
56307 + DEFAULT => 1064,
56308 + ENUM => [],
56309 + LOW => 16,
56310 + HIGH => 32768
56311 + },
56312 + {
56313 + NAME => "dev_nperio_tx_fifo_size",
56314 + DEFAULT => 1024,
56315 + ENUM => [],
56316 + LOW => 16,
56317 + HIGH => 32768
56318 + },
56319 + {
56320 + NAME => "dev_perio_tx_fifo_size_1",
56321 + DEFAULT => 256,
56322 + ENUM => [],
56323 + LOW => 4,
56324 + HIGH => 768
56325 + },
56326 + {
56327 + NAME => "dev_perio_tx_fifo_size_2",
56328 + DEFAULT => 256,
56329 + ENUM => [],
56330 + LOW => 4,
56331 + HIGH => 768
56332 + },
56333 + {
56334 + NAME => "dev_perio_tx_fifo_size_3",
56335 + DEFAULT => 256,
56336 + ENUM => [],
56337 + LOW => 4,
56338 + HIGH => 768
56339 + },
56340 + {
56341 + NAME => "dev_perio_tx_fifo_size_4",
56342 + DEFAULT => 256,
56343 + ENUM => [],
56344 + LOW => 4,
56345 + HIGH => 768
56346 + },
56347 + {
56348 + NAME => "dev_perio_tx_fifo_size_5",
56349 + DEFAULT => 256,
56350 + ENUM => [],
56351 + LOW => 4,
56352 + HIGH => 768
56353 + },
56354 + {
56355 + NAME => "dev_perio_tx_fifo_size_6",
56356 + DEFAULT => 256,
56357 + ENUM => [],
56358 + LOW => 4,
56359 + HIGH => 768
56360 + },
56361 + {
56362 + NAME => "dev_perio_tx_fifo_size_7",
56363 + DEFAULT => 256,
56364 + ENUM => [],
56365 + LOW => 4,
56366 + HIGH => 768
56367 + },
56368 + {
56369 + NAME => "dev_perio_tx_fifo_size_8",
56370 + DEFAULT => 256,
56371 + ENUM => [],
56372 + LOW => 4,
56373 + HIGH => 768
56374 + },
56375 + {
56376 + NAME => "dev_perio_tx_fifo_size_9",
56377 + DEFAULT => 256,
56378 + ENUM => [],
56379 + LOW => 4,
56380 + HIGH => 768
56381 + },
56382 + {
56383 + NAME => "dev_perio_tx_fifo_size_10",
56384 + DEFAULT => 256,
56385 + ENUM => [],
56386 + LOW => 4,
56387 + HIGH => 768
56388 + },
56389 + {
56390 + NAME => "dev_perio_tx_fifo_size_11",
56391 + DEFAULT => 256,
56392 + ENUM => [],
56393 + LOW => 4,
56394 + HIGH => 768
56395 + },
56396 + {
56397 + NAME => "dev_perio_tx_fifo_size_12",
56398 + DEFAULT => 256,
56399 + ENUM => [],
56400 + LOW => 4,
56401 + HIGH => 768
56402 + },
56403 + {
56404 + NAME => "dev_perio_tx_fifo_size_13",
56405 + DEFAULT => 256,
56406 + ENUM => [],
56407 + LOW => 4,
56408 + HIGH => 768
56409 + },
56410 + {
56411 + NAME => "dev_perio_tx_fifo_size_14",
56412 + DEFAULT => 256,
56413 + ENUM => [],
56414 + LOW => 4,
56415 + HIGH => 768
56416 + },
56417 + {
56418 + NAME => "dev_perio_tx_fifo_size_15",
56419 + DEFAULT => 256,
56420 + ENUM => [],
56421 + LOW => 4,
56422 + HIGH => 768
56423 + },
56424 + {
56425 + NAME => "host_rx_fifo_size",
56426 + DEFAULT => 1024,
56427 + ENUM => [],
56428 + LOW => 16,
56429 + HIGH => 32768
56430 + },
56431 + {
56432 + NAME => "host_nperio_tx_fifo_size",
56433 + DEFAULT => 1024,
56434 + ENUM => [],
56435 + LOW => 16,
56436 + HIGH => 32768
56437 + },
56438 + {
56439 + NAME => "host_perio_tx_fifo_size",
56440 + DEFAULT => 1024,
56441 + ENUM => [],
56442 + LOW => 16,
56443 + HIGH => 32768
56444 + },
56445 + {
56446 + NAME => "max_transfer_size",
56447 + DEFAULT => 65535,
56448 + ENUM => [],
56449 + LOW => 2047,
56450 + HIGH => 65535
56451 + },
56452 + {
56453 + NAME => "max_packet_count",
56454 + DEFAULT => 511,
56455 + ENUM => [],
56456 + LOW => 15,
56457 + HIGH => 511
56458 + },
56459 + {
56460 + NAME => "host_channels",
56461 + DEFAULT => 12,
56462 + ENUM => [],
56463 + LOW => 1,
56464 + HIGH => 16
56465 + },
56466 + {
56467 + NAME => "dev_endpoints",
56468 + DEFAULT => 6,
56469 + ENUM => [],
56470 + LOW => 1,
56471 + HIGH => 15
56472 + },
56473 + {
56474 + NAME => "phy_type",
56475 + DEFAULT => 1,
56476 + ENUM => [],
56477 + LOW => 0,
56478 + HIGH => 2
56479 + },
56480 + {
56481 + NAME => "phy_utmi_width",
56482 + DEFAULT => 16,
56483 + ENUM => [8, 16],
56484 + LOW => 8,
56485 + HIGH => 16
56486 + },
56487 + {
56488 + NAME => "phy_ulpi_ddr",
56489 + DEFAULT => 0,
56490 + ENUM => [],
56491 + LOW => 0,
56492 + HIGH => 1
56493 + },
56494 + ];
56495 +
56496 +
56497 +#
56498 +#
56499 +sub check_arch {
56500 + $_ = `uname -m`;
56501 + chomp;
56502 + unless (m/armv4tl/) {
56503 + warn "# \n# Can't execute on $_. Run on integrator platform.\n# \n";
56504 + return 0;
56505 + }
56506 + return 1;
56507 +}
56508 +
56509 +#
56510 +#
56511 +sub load_module {
56512 + my $params = shift;
56513 + print "\nRemoving Module\n";
56514 + system "rmmod dwc_otg";
56515 + print "Loading Module\n";
56516 + if ($params ne "") {
56517 + print "Module Parameters: $params\n";
56518 + }
56519 + if (system("modprobe dwc_otg $params")) {
56520 + warn "Unable to load module\n";
56521 + return 0;
56522 + }
56523 + return 1;
56524 +}
56525 +
56526 +#
56527 +#
56528 +sub test_status {
56529 + my $arg = shift;
56530 +
56531 + print "\n";
56532 +
56533 + if (defined $arg) {
56534 + warn "WARNING: $arg\n";
56535 + }
56536 +
56537 + if ($errors > 0) {
56538 + warn "TEST FAILED with $errors errors\n";
56539 + return 0;
56540 + } else {
56541 + print "TEST PASSED\n";
56542 + return 0 if (defined $arg);
56543 + }
56544 + return 1;
56545 +}
56546 +
56547 +#
56548 +#
56549 +@EXPORT = qw(
56550 +$sysfsdir
56551 +$paramdir
56552 +$params
56553 +$errors
56554 +check_arch
56555 +load_module
56556 +test_status
56557 +);
56558 +
56559 +1;
56560 --- /dev/null
56561 +++ b/drivers/usb/host/dwc_otg/test/test_mod_param.pl
56562 @@ -0,0 +1,133 @@
56563 +#!/usr/bin/perl -w
56564 +#
56565 +# Run this program on the integrator.
56566 +#
56567 +# - Tests module parameter default values.
56568 +# - Tests setting of valid module parameter values via modprobe.
56569 +# - Tests invalid module parameter values.
56570 +# -----------------------------------------------------------------------------
56571 +use strict;
56572 +use dwc_otg_test;
56573 +
56574 +check_arch() or die;
56575 +
56576 +#
56577 +#
56578 +sub test {
56579 + my ($param,$expected) = @_;
56580 + my $value = get($param);
56581 +
56582 + if ($value == $expected) {
56583 + print "$param = $value, okay\n";
56584 + }
56585 +
56586 + else {
56587 + warn "ERROR: value of $param != $expected, $value\n";
56588 + $errors ++;
56589 + }
56590 +}
56591 +
56592 +#
56593 +#
56594 +sub get {
56595 + my $param = shift;
56596 + my $tmp = `cat $paramdir/$param`;
56597 + chomp $tmp;
56598 + return $tmp;
56599 +}
56600 +
56601 +#
56602 +#
56603 +sub test_main {
56604 +
56605 + print "\nTesting Module Parameters\n";
56606 +
56607 + load_module("") or die;
56608 +
56609 + # Test initial values
56610 + print "\nTesting Default Values\n";
56611 + foreach (@{$params}) {
56612 + test ($_->{NAME}, $_->{DEFAULT});
56613 + }
56614 +
56615 + # Test low value
56616 + print "\nTesting Low Value\n";
56617 + my $cmd_params = "";
56618 + foreach (@{$params}) {
56619 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{LOW} ";
56620 + }
56621 + load_module($cmd_params) or die;
56622 +
56623 + foreach (@{$params}) {
56624 + test ($_->{NAME}, $_->{LOW});
56625 + }
56626 +
56627 + # Test high value
56628 + print "\nTesting High Value\n";
56629 + $cmd_params = "";
56630 + foreach (@{$params}) {
56631 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{HIGH} ";
56632 + }
56633 + load_module($cmd_params) or die;
56634 +
56635 + foreach (@{$params}) {
56636 + test ($_->{NAME}, $_->{HIGH});
56637 + }
56638 +
56639 + # Test Enum
56640 + print "\nTesting Enumerated\n";
56641 + foreach (@{$params}) {
56642 + if (defined $_->{ENUM}) {
56643 + my $value;
56644 + foreach $value (@{$_->{ENUM}}) {
56645 + $cmd_params = "$_->{NAME}=$value";
56646 + load_module($cmd_params) or die;
56647 + test ($_->{NAME}, $value);
56648 + }
56649 + }
56650 + }
56651 +
56652 + # Test Invalid Values
56653 + print "\nTesting Invalid Values\n";
56654 + $cmd_params = "";
56655 + foreach (@{$params}) {
56656 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{LOW}-1;
56657 + }
56658 + load_module($cmd_params) or die;
56659 +
56660 + foreach (@{$params}) {
56661 + test ($_->{NAME}, $_->{DEFAULT});
56662 + }
56663 +
56664 + $cmd_params = "";
56665 + foreach (@{$params}) {
56666 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{HIGH}+1;
56667 + }
56668 + load_module($cmd_params) or die;
56669 +
56670 + foreach (@{$params}) {
56671 + test ($_->{NAME}, $_->{DEFAULT});
56672 + }
56673 +
56674 + print "\nTesting Enumerated\n";
56675 + foreach (@{$params}) {
56676 + if (defined $_->{ENUM}) {
56677 + my $value;
56678 + foreach $value (@{$_->{ENUM}}) {
56679 + $value = $value + 1;
56680 + $cmd_params = "$_->{NAME}=$value";
56681 + load_module($cmd_params) or die;
56682 + test ($_->{NAME}, $_->{DEFAULT});
56683 + $value = $value - 2;
56684 + $cmd_params = "$_->{NAME}=$value";
56685 + load_module($cmd_params) or die;
56686 + test ($_->{NAME}, $_->{DEFAULT});
56687 + }
56688 + }
56689 + }
56690 +
56691 + test_status() or die;
56692 +}
56693 +
56694 +test_main();
56695 +0;
56696 --- /dev/null
56697 +++ b/drivers/usb/host/dwc_otg/test/test_sysfs.pl
56698 @@ -0,0 +1,193 @@
56699 +#!/usr/bin/perl -w
56700 +#
56701 +# Run this program on the integrator
56702 +# - Tests select sysfs attributes.
56703 +# - Todo ... test more attributes, hnp/srp, buspower/bussuspend, etc.
56704 +# -----------------------------------------------------------------------------
56705 +use strict;
56706 +use dwc_otg_test;
56707 +
56708 +check_arch() or die;
56709 +
56710 +#
56711 +#
56712 +sub test {
56713 + my ($attr,$expected) = @_;
56714 + my $string = get($attr);
56715 +
56716 + if ($string eq $expected) {
56717 + printf("$attr = $string, okay\n");
56718 + }
56719 + else {
56720 + warn "ERROR: value of $attr != $expected, $string\n";
56721 + $errors ++;
56722 + }
56723 +}
56724 +
56725 +#
56726 +#
56727 +sub set {
56728 + my ($reg, $value) = @_;
56729 + system "echo $value > $sysfsdir/$reg";
56730 +}
56731 +
56732 +#
56733 +#
56734 +sub get {
56735 + my $attr = shift;
56736 + my $string = `cat $sysfsdir/$attr`;
56737 + chomp $string;
56738 + if ($string =~ m/\s\=\s/) {
56739 + my $tmp;
56740 + ($tmp, $string) = split /\s=\s/, $string;
56741 + }
56742 + return $string;
56743 +}
56744 +
56745 +#
56746 +#
56747 +sub test_main {
56748 + print("\nTesting Sysfs Attributes\n");
56749 +
56750 + load_module("") or die;
56751 +
56752 + # Test initial values of regoffset/regvalue/guid/gsnpsid
56753 + print("\nTesting Default Values\n");
56754 +
56755 + test("regoffset", "0xffffffff");
56756 + test("regvalue", "invalid offset");
56757 + test("guid", "0x12345678"); # this will fail if it has been changed
56758 + test("gsnpsid", "0x4f54200a");
56759 +
56760 + # Test operation of regoffset/regvalue
56761 + print("\nTesting regoffset\n");
56762 + set('regoffset', '5a5a5a5a');
56763 + test("regoffset", "0xffffffff");
56764 +
56765 + set('regoffset', '0');
56766 + test("regoffset", "0x00000000");
56767 +
56768 + set('regoffset', '40000');
56769 + test("regoffset", "0x00000000");
56770 +
56771 + set('regoffset', '3ffff');
56772 + test("regoffset", "0x0003ffff");
56773 +
56774 + set('regoffset', '1');
56775 + test("regoffset", "0x00000001");
56776 +
56777 + print("\nTesting regvalue\n");
56778 + set('regoffset', '3c');
56779 + test("regvalue", "0x12345678");
56780 + set('regvalue', '5a5a5a5a');
56781 + test("regvalue", "0x5a5a5a5a");
56782 + set('regvalue','a5a5a5a5');
56783 + test("regvalue", "0xa5a5a5a5");
56784 + set('guid','12345678');
56785 +
56786 + # Test HNP Capable
56787 + print("\nTesting HNP Capable bit\n");
56788 + set('hnpcapable', '1');
56789 + test("hnpcapable", "0x1");
56790 + set('hnpcapable','0');
56791 + test("hnpcapable", "0x0");
56792 +
56793 + set('regoffset','0c');
56794 +
56795 + my $old = get('gusbcfg');
56796 + print("setting hnpcapable\n");
56797 + set('hnpcapable', '1');
56798 + test("hnpcapable", "0x1");
56799 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<9)));
56800 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<9)));
56801 +
56802 + $old = get('gusbcfg');
56803 + print("clearing hnpcapable\n");
56804 + set('hnpcapable', '0');
56805 + test("hnpcapable", "0x0");
56806 + test ('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<9)));
56807 + test ('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<9)));
56808 +
56809 + # Test SRP Capable
56810 + print("\nTesting SRP Capable bit\n");
56811 + set('srpcapable', '1');
56812 + test("srpcapable", "0x1");
56813 + set('srpcapable','0');
56814 + test("srpcapable", "0x0");
56815 +
56816 + set('regoffset','0c');
56817 +
56818 + $old = get('gusbcfg');
56819 + print("setting srpcapable\n");
56820 + set('srpcapable', '1');
56821 + test("srpcapable", "0x1");
56822 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<8)));
56823 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<8)));
56824 +
56825 + $old = get('gusbcfg');
56826 + print("clearing srpcapable\n");
56827 + set('srpcapable', '0');
56828 + test("srpcapable", "0x0");
56829 + test('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<8)));
56830 + test('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<8)));
56831 +
56832 + # Test GGPIO
56833 + print("\nTesting GGPIO\n");
56834 + set('ggpio','5a5a5a5a');
56835 + test('ggpio','0x5a5a0000');
56836 + set('ggpio','a5a5a5a5');
56837 + test('ggpio','0xa5a50000');
56838 + set('ggpio','11110000');
56839 + test('ggpio','0x11110000');
56840 + set('ggpio','00001111');
56841 + test('ggpio','0x00000000');
56842 +
56843 + # Test DEVSPEED
56844 + print("\nTesting DEVSPEED\n");
56845 + set('regoffset','800');
56846 + $old = get('regvalue');
56847 + set('devspeed','0');
56848 + test('devspeed','0x0');
56849 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
56850 + set('devspeed','1');
56851 + test('devspeed','0x1');
56852 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
56853 + set('devspeed','2');
56854 + test('devspeed','0x2');
56855 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 2));
56856 + set('devspeed','3');
56857 + test('devspeed','0x3');
56858 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 3));
56859 + set('devspeed','4');
56860 + test('devspeed','0x0');
56861 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
56862 + set('devspeed','5');
56863 + test('devspeed','0x1');
56864 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
56865 +
56866 +
56867 + # mode Returns the current mode:0 for device mode1 for host mode Read
56868 + # hnp Initiate the Host Negotiation Protocol. Read returns the status. Read/Write
56869 + # srp Initiate the Session Request Protocol. Read returns the status. Read/Write
56870 + # buspower Get or Set the Power State of the bus (0 - Off or 1 - On) Read/Write
56871 + # bussuspend Suspend the USB bus. Read/Write
56872 + # busconnected Get the connection status of the bus Read
56873 +
56874 + # gotgctl Get or set the Core Control Status Register. Read/Write
56875 + ## gusbcfg Get or set the Core USB Configuration Register Read/Write
56876 + # grxfsiz Get or set the Receive FIFO Size Register Read/Write
56877 + # gnptxfsiz Get or set the non-periodic Transmit Size Register Read/Write
56878 + # gpvndctl Get or set the PHY Vendor Control Register Read/Write
56879 + ## ggpio Get the value in the lower 16-bits of the General Purpose IO Register or Set the upper 16 bits. Read/Write
56880 + ## guid Get or set the value of the User ID Register Read/Write
56881 + ## gsnpsid Get the value of the Synopsys ID Regester Read
56882 + ## devspeed Get or set the device speed setting in the DCFG register Read/Write
56883 + # enumspeed Gets the device enumeration Speed. Read
56884 + # hptxfsiz Get the value of the Host Periodic Transmit FIFO Read
56885 + # hprt0 Get or Set the value in the Host Port Control and Status Register Read/Write
56886 +
56887 + test_status("TEST NYI") or die;
56888 +}
56889 +
56890 +test_main();
56891 +0;