1 From 9964a43723df02a84b7f132695193cd452d45b58 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 004/114] Add dwc_otg driver
6 Signed-off-by: popcornmix <popcornmix@gmail.com>
8 usb: dwc: fix lockdep false positive
10 Signed-off-by: Kari Suvanto <karis79@gmail.com>
12 usb: dwc: fix inconsistent lock state
14 Signed-off-by: Kari Suvanto <karis79@gmail.com>
16 drivers/usb/Makefile | 1 +
17 drivers/usb/core/generic.c | 1 +
18 drivers/usb/core/message.c | 79 +
19 drivers/usb/core/otg_whitelist.h | 114 +-
20 drivers/usb/gadget/file_storage.c | 3676 ++++++++++
21 drivers/usb/host/Kconfig | 13 +
22 drivers/usb/host/Makefile | 2 +
23 drivers/usb/host/dwc_common_port/Makefile | 58 +
24 drivers/usb/host/dwc_common_port/Makefile.fbsd | 17 +
25 drivers/usb/host/dwc_common_port/Makefile.linux | 49 +
26 drivers/usb/host/dwc_common_port/changes.txt | 174 +
27 drivers/usb/host/dwc_common_port/doc/doxygen.cfg | 270 +
28 drivers/usb/host/dwc_common_port/dwc_cc.c | 532 ++
29 drivers/usb/host/dwc_common_port/dwc_cc.h | 224 +
30 drivers/usb/host/dwc_common_port/dwc_common_fbsd.c | 1308 ++++
31 .../usb/host/dwc_common_port/dwc_common_linux.c | 1429 ++++
32 drivers/usb/host/dwc_common_port/dwc_common_nbsd.c | 1275 ++++
33 drivers/usb/host/dwc_common_port/dwc_crypto.c | 308 +
34 drivers/usb/host/dwc_common_port/dwc_crypto.h | 111 +
35 drivers/usb/host/dwc_common_port/dwc_dh.c | 291 +
36 drivers/usb/host/dwc_common_port/dwc_dh.h | 106 +
37 drivers/usb/host/dwc_common_port/dwc_list.h | 594 ++
38 drivers/usb/host/dwc_common_port/dwc_mem.c | 245 +
39 drivers/usb/host/dwc_common_port/dwc_modpow.c | 636 ++
40 drivers/usb/host/dwc_common_port/dwc_modpow.h | 34 +
41 drivers/usb/host/dwc_common_port/dwc_notifier.c | 319 +
42 drivers/usb/host/dwc_common_port/dwc_notifier.h | 122 +
43 drivers/usb/host/dwc_common_port/dwc_os.h | 1274 ++++
44 drivers/usb/host/dwc_common_port/usb.h | 946 +++
45 drivers/usb/host/dwc_otg/Makefile | 80 +
46 drivers/usb/host/dwc_otg/doc/doxygen.cfg | 224 +
47 drivers/usb/host/dwc_otg/dummy_audio.c | 1575 +++++
48 drivers/usb/host/dwc_otg/dwc_cfi_common.h | 142 +
49 drivers/usb/host/dwc_otg/dwc_otg_adp.c | 854 +++
50 drivers/usb/host/dwc_otg/dwc_otg_adp.h | 80 +
51 drivers/usb/host/dwc_otg/dwc_otg_attr.c | 1210 ++++
52 drivers/usb/host/dwc_otg/dwc_otg_attr.h | 89 +
53 drivers/usb/host/dwc_otg/dwc_otg_cfi.c | 1876 +++++
54 drivers/usb/host/dwc_otg/dwc_otg_cfi.h | 320 +
55 drivers/usb/host/dwc_otg/dwc_otg_cil.c | 7151 ++++++++++++++++++++
56 drivers/usb/host/dwc_otg/dwc_otg_cil.h | 1464 ++++
57 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 1563 +++++
58 drivers/usb/host/dwc_otg/dwc_otg_core_if.h | 705 ++
59 drivers/usb/host/dwc_otg/dwc_otg_dbg.h | 116 +
60 drivers/usb/host/dwc_otg/dwc_otg_driver.c | 1700 +++++
61 drivers/usb/host/dwc_otg/dwc_otg_driver.h | 86 +
62 drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 3479 ++++++++++
63 drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 824 +++
64 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 1133 ++++
65 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 412 ++
66 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2106 ++++++
67 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 893 +++
68 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 923 +++
69 drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 185 +
70 drivers/usb/host/dwc_otg/dwc_otg_pcd.c | 2712 ++++++++
71 drivers/usb/host/dwc_otg/dwc_otg_pcd.h | 266 +
72 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h | 360 +
73 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 5147 ++++++++++++++
74 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 1358 ++++
75 drivers/usb/host/dwc_otg/dwc_otg_regs.h | 2550 +++++++
76 drivers/usb/host/dwc_otg/test/Makefile | 16 +
77 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm | 337 +
78 drivers/usb/host/dwc_otg/test/test_mod_param.pl | 133 +
79 drivers/usb/host/dwc_otg/test/test_sysfs.pl | 193 +
80 64 files changed, 56458 insertions(+), 12 deletions(-)
81 create mode 100644 drivers/usb/gadget/file_storage.c
82 create mode 100644 drivers/usb/host/dwc_common_port/Makefile
83 create mode 100644 drivers/usb/host/dwc_common_port/Makefile.fbsd
84 create mode 100644 drivers/usb/host/dwc_common_port/Makefile.linux
85 create mode 100644 drivers/usb/host/dwc_common_port/changes.txt
86 create mode 100644 drivers/usb/host/dwc_common_port/doc/doxygen.cfg
87 create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.c
88 create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.h
89 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
90 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_linux.c
91 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
92 create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.c
93 create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.h
94 create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.c
95 create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.h
96 create mode 100644 drivers/usb/host/dwc_common_port/dwc_list.h
97 create mode 100644 drivers/usb/host/dwc_common_port/dwc_mem.c
98 create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.c
99 create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.h
100 create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.c
101 create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.h
102 create mode 100644 drivers/usb/host/dwc_common_port/dwc_os.h
103 create mode 100644 drivers/usb/host/dwc_common_port/usb.h
104 create mode 100644 drivers/usb/host/dwc_otg/Makefile
105 create mode 100644 drivers/usb/host/dwc_otg/doc/doxygen.cfg
106 create mode 100644 drivers/usb/host/dwc_otg/dummy_audio.c
107 create mode 100644 drivers/usb/host/dwc_otg/dwc_cfi_common.h
108 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.c
109 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.h
110 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.c
111 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.h
112 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.c
113 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.h
114 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.c
115 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.h
116 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
117 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_core_if.h
118 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_dbg.h
119 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.c
120 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.h
121 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.c
122 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.h
123 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
124 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
125 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
126 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
127 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
128 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
129 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.c
130 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.h
131 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
132 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
133 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
134 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_regs.h
135 create mode 100644 drivers/usb/host/dwc_otg/test/Makefile
136 create mode 100644 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
137 create mode 100644 drivers/usb/host/dwc_otg/test/test_mod_param.pl
138 create mode 100644 drivers/usb/host/dwc_otg/test/test_sysfs.pl
140 --- a/drivers/usb/Makefile
141 +++ b/drivers/usb/Makefile
142 @@ -24,6 +24,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/
143 obj-$(CONFIG_USB_R8A66597_HCD) += host/
144 obj-$(CONFIG_USB_HWA_HCD) += host/
145 obj-$(CONFIG_USB_ISP1760_HCD) += host/
146 +obj-$(CONFIG_USB_DWCOTG) += host/
147 obj-$(CONFIG_USB_IMX21_HCD) += host/
148 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
149 obj-$(CONFIG_USB_FUSBH200_HCD) += host/
150 --- a/drivers/usb/core/generic.c
151 +++ b/drivers/usb/core/generic.c
152 @@ -152,6 +152,7 @@ int usb_choose_configuration(struct usb_
154 "no configuration chosen from %d choice%s\n",
155 num_configs, plural(num_configs));
156 + dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA);
160 --- a/drivers/usb/core/message.c
161 +++ b/drivers/usb/core/message.c
162 @@ -1872,6 +1872,85 @@ free_interfaces:
163 if (cp->string == NULL &&
164 !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
165 cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
166 +/* Uncomment this define to enable the HS Electrical Test support */
167 +#define DWC_HS_ELECT_TST 1
168 +#ifdef DWC_HS_ELECT_TST
169 + /* Here we implement the HS Electrical Test support. The
170 + * tester uses a vendor ID of 0x1A0A to indicate we should
171 + * run a special test sequence. The product ID tells us
172 + * which sequence to run. We invoke the test sequence by
173 + * sending a non-standard SetFeature command to our root
174 + * hub port. Our dwc_otg_hcd_hub_control() routine will
175 + * recognize the command and perform the desired test
178 + if (dev->descriptor.idVendor == 0x1A0A) {
179 + /* HSOTG Electrical Test */
180 + dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n");
182 + if (dev->bus && dev->bus->root_hub) {
183 + struct usb_device *hdev = dev->bus->root_hub;
184 + dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct);
186 + switch (dev->descriptor.idProduct) {
187 + case 0x0101: /* TEST_SE0_NAK */
188 + dev_warn(&dev->dev, "TEST_SE0_NAK\n");
189 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
190 + USB_REQ_SET_FEATURE, USB_RT_PORT,
191 + USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ);
194 + case 0x0102: /* TEST_J */
195 + dev_warn(&dev->dev, "TEST_J\n");
196 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
197 + USB_REQ_SET_FEATURE, USB_RT_PORT,
198 + USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ);
201 + case 0x0103: /* TEST_K */
202 + dev_warn(&dev->dev, "TEST_K\n");
203 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
204 + USB_REQ_SET_FEATURE, USB_RT_PORT,
205 + USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ);
208 + case 0x0104: /* TEST_PACKET */
209 + dev_warn(&dev->dev, "TEST_PACKET\n");
210 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
211 + USB_REQ_SET_FEATURE, USB_RT_PORT,
212 + USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ);
215 + case 0x0105: /* TEST_FORCE_ENABLE */
216 + dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n");
217 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
218 + USB_REQ_SET_FEATURE, USB_RT_PORT,
219 + USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ);
222 + case 0x0106: /* HS_HOST_PORT_SUSPEND_RESUME */
223 + dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n");
224 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
225 + USB_REQ_SET_FEATURE, USB_RT_PORT,
226 + USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ);
229 + case 0x0107: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
230 + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n");
231 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
232 + USB_REQ_SET_FEATURE, USB_RT_PORT,
233 + USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ);
236 + case 0x0108: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
237 + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n");
238 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
239 + USB_REQ_SET_FEATURE, USB_RT_PORT,
240 + USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ);
244 +#endif /* DWC_HS_ELECT_TST */
246 /* Now that the interfaces are installed, re-enable LPM. */
247 usb_unlocked_enable_lpm(dev);
248 --- a/drivers/usb/core/otg_whitelist.h
249 +++ b/drivers/usb/core/otg_whitelist.h
251 static struct usb_device_id whitelist_table [] = {
253 /* hubs are optional in OTG, but very handy ... */
254 +#define CERT_WITHOUT_HUBS
255 +#if defined(CERT_WITHOUT_HUBS)
256 +{ USB_DEVICE( 0x0000, 0x0000 ), }, /* Root HUB Only*/
258 { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
259 { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
260 +{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), },
263 #ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
264 /* FIXME actually, printers are NOT supposed to use device classes;
265 * they're supposed to use interface classes...
267 -{ USB_DEVICE_INFO(7, 1, 1) },
268 -{ USB_DEVICE_INFO(7, 1, 2) },
269 -{ USB_DEVICE_INFO(7, 1, 3) },
270 +//{ USB_DEVICE_INFO(7, 1, 1) },
271 +//{ USB_DEVICE_INFO(7, 1, 2) },
272 +//{ USB_DEVICE_INFO(7, 1, 3) },
275 #ifdef CONFIG_USB_NET_CDCETHER
276 /* Linux-USB CDC Ethernet gadget */
277 -{ USB_DEVICE(0x0525, 0xa4a1), },
278 +//{ USB_DEVICE(0x0525, 0xa4a1), },
279 /* Linux-USB CDC Ethernet + RNDIS gadget */
280 -{ USB_DEVICE(0x0525, 0xa4a2), },
281 +//{ USB_DEVICE(0x0525, 0xa4a2), },
284 #if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
285 /* gadget zero, for testing */
286 -{ USB_DEVICE(0x0525, 0xa4a0), },
287 +//{ USB_DEVICE(0x0525, 0xa4a0), },
291 +{ USB_DEVICE( 0x1a0a, 0x0101 ), }, /* TEST_SE0_NAK */
292 +{ USB_DEVICE( 0x1a0a, 0x0102 ), }, /* Test_J */
293 +{ USB_DEVICE( 0x1a0a, 0x0103 ), }, /* Test_K */
294 +{ USB_DEVICE( 0x1a0a, 0x0104 ), }, /* Test_PACKET */
295 +{ USB_DEVICE( 0x1a0a, 0x0105 ), }, /* Test_FORCE_ENABLE */
296 +{ USB_DEVICE( 0x1a0a, 0x0106 ), }, /* HS_PORT_SUSPEND_RESUME */
297 +{ USB_DEVICE( 0x1a0a, 0x0107 ), }, /* SINGLE_STEP_GET_DESCRIPTOR setup */
298 +{ USB_DEVICE( 0x1a0a, 0x0108 ), }, /* SINGLE_STEP_GET_DESCRIPTOR execute */
301 +{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), },
303 +/* Memory Devices */
304 +//{ USB_DEVICE( 0x0781, 0x5150 ), }, /* SanDisk */
305 +//{ USB_DEVICE( 0x05DC, 0x0080 ), }, /* Lexar */
306 +//{ USB_DEVICE( 0x4146, 0x9281 ), }, /* IOMEGA */
307 +//{ USB_DEVICE( 0x067b, 0x2507 ), }, /* Hammer 20GB External HD */
308 +{ USB_DEVICE( 0x0EA0, 0x2168 ), }, /* Ours Technology Inc. (BUFFALO ClipDrive)*/
309 +//{ USB_DEVICE( 0x0457, 0x0150 ), }, /* Silicon Integrated Systems Corp. */
312 +//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */
313 +//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */
316 +//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */
317 +//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */
319 { } /* Terminating entry */
322 +static inline void report_errors(struct usb_device *dev)
324 + /* OTG MESSAGE: report errors here, customize to match your product */
325 + dev_info(&dev->dev, "device Vendor:%04x Product:%04x is not supported\n",
326 + le16_to_cpu(dev->descriptor.idVendor),
327 + le16_to_cpu(dev->descriptor.idProduct));
328 + if (USB_CLASS_HUB == dev->descriptor.bDeviceClass){
329 + dev_printk(KERN_CRIT, &dev->dev, "Unsupported Hub Topology\n");
331 + dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n");
336 static int is_targeted(struct usb_device *dev)
338 struct usb_device_id *id = whitelist_table;
339 @@ -95,16 +144,57 @@ static int is_targeted(struct usb_device
344 + /* NOTE: can't use usb_match_id() since interface caches
345 + * aren't set up yet. this is cut/paste from that code.
347 + for (id = whitelist_table; id->match_flags; id++) {
350 + "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
354 + id->bDeviceSubClass,
355 + id->bDeviceProtocol);
358 - /* add other match criteria here ... */
359 + if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
360 + id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
363 + if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
364 + id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
367 + /* No need to test id->bcdDevice_lo != 0, since 0 is never
368 + greater than any unsigned number. */
369 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
370 + (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
373 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
374 + (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
377 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
378 + (id->bDeviceClass != dev->descriptor.bDeviceClass))
381 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
382 + (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
385 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
386 + (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
393 - /* OTG MESSAGE: report errors here, customize to match your product */
394 - dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
395 - le16_to_cpu(dev->descriptor.idVendor),
396 - le16_to_cpu(dev->descriptor.idProduct));
397 + /* add other match criteria here ... */
399 + report_errors(dev);
404 +++ b/drivers/usb/gadget/file_storage.c
407 + * file_storage.c -- File-backed USB Storage Gadget, for USB development
409 + * Copyright (C) 2003-2008 Alan Stern
410 + * All rights reserved.
412 + * Redistribution and use in source and binary forms, with or without
413 + * modification, are permitted provided that the following conditions
415 + * 1. Redistributions of source code must retain the above copyright
416 + * notice, this list of conditions, and the following disclaimer,
417 + * without modification.
418 + * 2. Redistributions in binary form must reproduce the above copyright
419 + * notice, this list of conditions and the following disclaimer in the
420 + * documentation and/or other materials provided with the distribution.
421 + * 3. The names of the above-listed copyright holders may not be used
422 + * to endorse or promote products derived from this software without
423 + * specific prior written permission.
425 + * ALTERNATIVELY, this software may be distributed under the terms of the
426 + * GNU General Public License ("GPL") as published by the Free Software
427 + * Foundation, either version 2 of that License or (at your option) any
430 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
431 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
432 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
433 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
434 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
435 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
436 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
437 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
438 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
439 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
440 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
445 + * The File-backed Storage Gadget acts as a USB Mass Storage device,
446 + * appearing to the host as a disk drive or as a CD-ROM drive. In addition
447 + * to providing an example of a genuinely useful gadget driver for a USB
448 + * device, it also illustrates a technique of double-buffering for increased
449 + * throughput. Last but not least, it gives an easy way to probe the
450 + * behavior of the Mass Storage drivers in a USB host.
452 + * Backing storage is provided by a regular file or a block device, specified
453 + * by the "file" module parameter. Access can be limited to read-only by
454 + * setting the optional "ro" module parameter. (For CD-ROM emulation,
455 + * access is always read-only.) The gadget will indicate that it has
456 + * removable media if the optional "removable" module parameter is set.
458 + * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
459 + * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
460 + * by the optional "transport" module parameter. It also supports the
461 + * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
462 + * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
463 + * the optional "protocol" module parameter. In addition, the default
464 + * Vendor ID, Product ID, release number and serial number can be overridden.
466 + * There is support for multiple logical units (LUNs), each of which has
467 + * its own backing file. The number of LUNs can be set using the optional
468 + * "luns" module parameter (anywhere from 1 to 8), and the corresponding
469 + * files are specified using comma-separated lists for "file" and "ro".
470 + * The default number of LUNs is taken from the number of "file" elements;
471 + * it is 1 if "file" is not given. If "removable" is not set then a backing
472 + * file must be specified for each LUN. If it is set, then an unspecified
473 + * or empty backing filename means the LUN's medium is not loaded. Ideally
474 + * each LUN would be settable independently as a disk drive or a CD-ROM
475 + * drive, but currently all LUNs have to be the same type. The CD-ROM
476 + * emulation includes a single data track and no audio tracks; hence there
477 + * need be only one backing file per LUN.
479 + * Requirements are modest; only a bulk-in and a bulk-out endpoint are
480 + * needed (an interrupt-out endpoint is also needed for CBI). The memory
481 + * requirement amounts to two 16K buffers, size configurable by a parameter.
482 + * Support is included for both full-speed and high-speed operation.
484 + * Note that the driver is slightly non-portable in that it assumes a
485 + * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
486 + * interrupt-in endpoints. With most device controllers this isn't an
487 + * issue, but there may be some with hardware restrictions that prevent
488 + * a buffer from being used by more than one endpoint.
492 + * file=filename[,filename...]
493 + * Required if "removable" is not set, names of
494 + * the files or block devices used for
496 + * serial=HHHH... Required serial number (string of hex chars)
497 + * ro=b[,b...] Default false, booleans for read-only access
498 + * removable Default false, boolean for removable media
499 + * luns=N Default N = number of filenames, number of
501 + * nofua=b[,b...] Default false, booleans for ignore FUA flag
502 + * in SCSI WRITE(10,12) commands
503 + * stall Default determined according to the type of
504 + * USB device controller (usually true),
505 + * boolean to permit the driver to halt
507 + * cdrom Default false, boolean for whether to emulate
509 + * transport=XXX Default BBB, transport name (CB, CBI, or BBB)
510 + * protocol=YYY Default SCSI, protocol name (RBC, 8020 or
511 + * ATAPI, QIC, UFI, 8070, or SCSI;
513 + * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
514 + * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
515 + * release=0xRRRR Override the USB release number (bcdDevice)
516 + * buflen=N Default N=16384, buffer size used (will be
517 + * rounded down to a multiple of
520 + * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro",
521 + * "removable", "luns", "nofua", "stall", and "cdrom" options are available;
522 + * default values are used for everything else.
524 + * The pathnames of the backing files and the ro settings are available in
525 + * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of
526 + * the gadget's sysfs directory. If the "removable" option is set, writing to
527 + * these files will simulate ejecting/loading the medium (writing an empty
528 + * line means eject) and adjusting a write-enable tab. Changes to the ro
529 + * setting are not allowed when the medium is loaded or if CD-ROM emulation
532 + * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
533 + * The driver's SCSI command interface was based on the "Information
534 + * technology - Small Computer System Interface - 2" document from
535 + * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at
536 + * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception
537 + * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the
538 + * "Universal Serial Bus Mass Storage Class UFI Command Specification"
539 + * document, Revision 1.0, December 14, 1998, available at
540 + * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
547 + * The FSG driver is fairly straightforward. There is a main kernel
548 + * thread that handles most of the work. Interrupt routines field
549 + * callbacks from the controller driver: bulk- and interrupt-request
550 + * completion notifications, endpoint-0 events, and disconnect events.
551 + * Completion events are passed to the main thread by wakeup calls. Many
552 + * ep0 requests are handled at interrupt time, but SetInterface,
553 + * SetConfiguration, and device reset requests are forwarded to the
554 + * thread in the form of "exceptions" using SIGUSR1 signals (since they
555 + * should interrupt any ongoing file I/O operations).
557 + * The thread's main routine implements the standard command/data/status
558 + * parts of a SCSI interaction. It and its subroutines are full of tests
559 + * for pending signals/exceptions -- all this polling is necessary since
560 + * the kernel has no setjmp/longjmp equivalents. (Maybe this is an
561 + * indication that the driver really wants to be running in userspace.)
562 + * An important point is that so long as the thread is alive it keeps an
563 + * open reference to the backing file. This will prevent unmounting
564 + * the backing file's underlying filesystem and could cause problems
565 + * during system shutdown, for example. To prevent such problems, the
566 + * thread catches INT, TERM, and KILL signals and converts them into
567 + * an EXIT exception.
569 + * In normal operation the main thread is started during the gadget's
570 + * fsg_bind() callback and stopped during fsg_unbind(). But it can also
571 + * exit when it receives a signal, and there's no point leaving the
572 + * gadget running when the thread is dead. So just before the thread
573 + * exits, it deregisters the gadget driver. This makes things a little
574 + * tricky: The driver is deregistered at two places, and the exiting
575 + * thread can indirectly call fsg_unbind() which in turn can tell the
576 + * thread to exit. The first problem is resolved through the use of the
577 + * REGISTERED atomic bitflag; the driver will only be deregistered once.
578 + * The second problem is resolved by having fsg_unbind() check
579 + * fsg->state; it won't try to stop the thread if the state is already
580 + * FSG_STATE_TERMINATED.
582 + * To provide maximum throughput, the driver uses a circular pipeline of
583 + * buffer heads (struct fsg_buffhd). In principle the pipeline can be
584 + * arbitrarily long; in practice the benefits don't justify having more
585 + * than 2 stages (i.e., double buffering). But it helps to think of the
586 + * pipeline as being a long one. Each buffer head contains a bulk-in and
587 + * a bulk-out request pointer (since the buffer can be used for both
588 + * output and input -- directions always are given from the host's
589 + * point of view) as well as a pointer to the buffer and various state
592 + * Use of the pipeline follows a simple protocol. There is a variable
593 + * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
594 + * At any time that buffer head may still be in use from an earlier
595 + * request, so each buffer head has a state variable indicating whether
596 + * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the
597 + * buffer head to be EMPTY, filling the buffer either by file I/O or by
598 + * USB I/O (during which the buffer head is BUSY), and marking the buffer
599 + * head FULL when the I/O is complete. Then the buffer will be emptied
600 + * (again possibly by USB I/O, during which it is marked BUSY) and
601 + * finally marked EMPTY again (possibly by a completion routine).
603 + * A module parameter tells the driver to avoid stalling the bulk
604 + * endpoints wherever the transport specification allows. This is
605 + * necessary for some UDCs like the SuperH, which cannot reliably clear a
606 + * halt on a bulk endpoint. However, under certain circumstances the
607 + * Bulk-only specification requires a stall. In such cases the driver
608 + * will halt the endpoint and set a flag indicating that it should clear
609 + * the halt in software during the next device reset. Hopefully this
610 + * will permit everything to work correctly. Furthermore, although the
611 + * specification allows the bulk-out endpoint to halt when the host sends
612 + * too much data, implementing this would cause an unavoidable race.
613 + * The driver will always use the "no-stall" approach for OUT transfers.
615 + * One subtle point concerns sending status-stage responses for ep0
616 + * requests. Some of these requests, such as device reset, can involve
617 + * interrupting an ongoing file I/O operation, which might take an
618 + * arbitrarily long time. During that delay the host might give up on
619 + * the original ep0 request and issue a new one. When that happens the
620 + * driver should not notify the host about completion of the original
621 + * request, as the host will no longer be waiting for it. So the driver
622 + * assigns to each ep0 request a unique tag, and it keeps track of the
623 + * tag value of the request associated with a long-running exception
624 + * (device-reset, interface-change, or configuration-change). When the
625 + * exception handler is finished, the status-stage response is submitted
626 + * only if the current ep0 request tag is equal to the exception request
627 + * tag. Thus only the most recently received ep0 request will get a
628 + * status-stage response.
630 + * Warning: This driver source file is too long. It ought to be split up
631 + * into a header file plus about 3 separate .c files, to handle the details
632 + * of the Gadget, USB Mass Storage, and SCSI protocols.
636 +/* #define VERBOSE_DEBUG */
637 +/* #define DUMP_MSGS */
640 +#include <linux/blkdev.h>
641 +#include <linux/completion.h>
642 +#include <linux/dcache.h>
643 +#include <linux/delay.h>
644 +#include <linux/device.h>
645 +#include <linux/fcntl.h>
646 +#include <linux/file.h>
647 +#include <linux/fs.h>
648 +#include <linux/kref.h>
649 +#include <linux/kthread.h>
650 +#include <linux/limits.h>
651 +#include <linux/module.h>
652 +#include <linux/rwsem.h>
653 +#include <linux/slab.h>
654 +#include <linux/spinlock.h>
655 +#include <linux/string.h>
656 +#include <linux/freezer.h>
657 +#include <linux/utsname.h>
659 +#include <linux/usb/ch9.h>
660 +#include <linux/usb/gadget.h>
662 +#include "gadget_chips.h"
667 + * Kbuild is not very cooperative with respect to linking separately
668 + * compiled library objects into one module. So for now we won't use
669 + * separate compilation ... ensuring init/exit sections work to shrink
670 + * the runtime footprint, and giving us at least some parts of what
671 + * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
673 +#include "usbstring.c"
675 +#include "epautoconf.c"
677 +/*-------------------------------------------------------------------------*/
679 +#define DRIVER_DESC "File-backed Storage Gadget"
680 +#define DRIVER_NAME "g_file_storage"
681 +#define DRIVER_VERSION "1 September 2010"
683 +static char fsg_string_manufacturer[64];
684 +static const char fsg_string_product[] = DRIVER_DESC;
685 +static const char fsg_string_config[] = "Self-powered";
686 +static const char fsg_string_interface[] = "Mass Storage";
689 +#include "storage_common.c"
692 +MODULE_DESCRIPTION(DRIVER_DESC);
693 +MODULE_AUTHOR("Alan Stern");
694 +MODULE_LICENSE("Dual BSD/GPL");
697 + * This driver assumes self-powered hardware and has no way for users to
698 + * trigger remote wakeup. It uses autoconfiguration to select endpoints
699 + * and endpoint addresses.
703 +/*-------------------------------------------------------------------------*/
706 +/* Encapsulate the module parameter settings */
709 + char *file[FSG_MAX_LUNS];
711 + bool ro[FSG_MAX_LUNS];
712 + bool nofua[FSG_MAX_LUNS];
713 + unsigned int num_filenames;
714 + unsigned int num_ros;
715 + unsigned int num_nofuas;
716 + unsigned int nluns;
722 + char *transport_parm;
723 + char *protocol_parm;
724 + unsigned short vendor;
725 + unsigned short product;
726 + unsigned short release;
727 + unsigned int buflen;
729 + int transport_type;
730 + char *transport_name;
732 + char *protocol_name;
734 +} mod_data = { // Default values
735 + .transport_parm = "BBB",
736 + .protocol_parm = "SCSI",
740 + .vendor = FSG_VENDOR_ID,
741 + .product = FSG_PRODUCT_ID,
742 + .release = 0xffff, // Use controller chip type
747 +module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
749 +MODULE_PARM_DESC(file, "names of backing files or devices");
751 +module_param_named(serial, mod_data.serial, charp, S_IRUGO);
752 +MODULE_PARM_DESC(serial, "USB serial number");
754 +module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
755 +MODULE_PARM_DESC(ro, "true to force read-only");
757 +module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas,
759 +MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit");
761 +module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
762 +MODULE_PARM_DESC(luns, "number of LUNs");
764 +module_param_named(removable, mod_data.removable, bool, S_IRUGO);
765 +MODULE_PARM_DESC(removable, "true to simulate removable media");
767 +module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
768 +MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
770 +module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
771 +MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
773 +/* In the non-TEST version, only the module parameters listed above
774 + * are available. */
775 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
777 +module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO);
778 +MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");
780 +module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO);
781 +MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, "
784 +module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO);
785 +MODULE_PARM_DESC(vendor, "USB Vendor ID");
787 +module_param_named(product, mod_data.product, ushort, S_IRUGO);
788 +MODULE_PARM_DESC(product, "USB Product ID");
790 +module_param_named(release, mod_data.release, ushort, S_IRUGO);
791 +MODULE_PARM_DESC(release, "USB release number");
793 +module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
794 +MODULE_PARM_DESC(buflen, "I/O buffer size");
796 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
800 + * These definitions will permit the compiler to avoid generating code for
801 + * parts of the driver that aren't used in the non-TEST version. Even gcc
802 + * can recognize when a test of a constant expression yields a dead code
806 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
808 +#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK)
809 +#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI)
810 +#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI)
814 +#define transport_is_bbb() 1
815 +#define transport_is_cbi() 0
816 +#define protocol_is_scsi() 1
818 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
821 +/*-------------------------------------------------------------------------*/
825 + /* lock protects: state, all the req_busy's, and cbbuf_cmnd */
827 + struct usb_gadget *gadget;
829 + /* filesem protects: backing files in use */
830 + struct rw_semaphore filesem;
832 + /* reference counting: wait until all LUNs are released */
835 + struct usb_ep *ep0; // Handy copy of gadget->ep0
836 + struct usb_request *ep0req; // For control responses
837 + unsigned int ep0_req_tag;
838 + const char *ep0req_name;
840 + struct usb_request *intreq; // For interrupt responses
842 + struct fsg_buffhd *intr_buffhd;
844 + unsigned int bulk_out_maxpacket;
845 + enum fsg_state state; // For exception handling
846 + unsigned int exception_req_tag;
848 + u8 config, new_config;
850 + unsigned int running : 1;
851 + unsigned int bulk_in_enabled : 1;
852 + unsigned int bulk_out_enabled : 1;
853 + unsigned int intr_in_enabled : 1;
854 + unsigned int phase_error : 1;
855 + unsigned int short_packet_received : 1;
856 + unsigned int bad_lun_okay : 1;
858 + unsigned long atomic_bitflags;
859 +#define REGISTERED 0
860 +#define IGNORE_BULK_OUT 1
863 + struct usb_ep *bulk_in;
864 + struct usb_ep *bulk_out;
865 + struct usb_ep *intr_in;
867 + struct fsg_buffhd *next_buffhd_to_fill;
868 + struct fsg_buffhd *next_buffhd_to_drain;
870 + int thread_wakeup_needed;
871 + struct completion thread_notifier;
872 + struct task_struct *thread_task;
875 + u8 cmnd[MAX_COMMAND_SIZE];
876 + enum data_direction data_dir;
878 + u32 data_size_from_cmnd;
882 + u32 usb_amount_left;
884 + /* The CB protocol offers no way for a host to know when a command
885 + * has completed. As a result the next command may arrive early,
886 + * and we will still have to handle it. For that reason we need
887 + * a buffer to store new commands when using CB (or CBI, which
888 + * does not oblige a host to wait for command completion either). */
889 + int cbbuf_cmnd_size;
890 + u8 cbbuf_cmnd[MAX_COMMAND_SIZE];
892 + unsigned int nluns;
893 + struct fsg_lun *luns;
894 + struct fsg_lun *curlun;
895 + /* Must be the last entry */
896 + struct fsg_buffhd buffhds[];
899 +typedef void (*fsg_routine_t)(struct fsg_dev *);
901 +static int exception_in_progress(struct fsg_dev *fsg)
903 + return (fsg->state > FSG_STATE_IDLE);
906 +/* Make bulk-out requests be divisible by the maxpacket size */
907 +static void set_bulk_out_req_length(struct fsg_dev *fsg,
908 + struct fsg_buffhd *bh, unsigned int length)
912 + bh->bulk_out_intended_length = length;
913 + rem = length % fsg->bulk_out_maxpacket;
915 + length += fsg->bulk_out_maxpacket - rem;
916 + bh->outreq->length = length;
919 +static struct fsg_dev *the_fsg;
920 +static struct usb_gadget_driver fsg_driver;
923 +/*-------------------------------------------------------------------------*/
925 +static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
929 + if (ep == fsg->bulk_in)
931 + else if (ep == fsg->bulk_out)
935 + DBG(fsg, "%s set halt\n", name);
936 + return usb_ep_set_halt(ep);
940 +/*-------------------------------------------------------------------------*/
943 + * DESCRIPTORS ... most are static, but strings and (full) configuration
944 + * descriptors are built on demand. Also the (static) config and interface
945 + * descriptors are adjusted during fsg_bind().
948 +/* There is only one configuration. */
949 +#define CONFIG_VALUE 1
951 +static struct usb_device_descriptor
953 + .bLength = sizeof device_desc,
954 + .bDescriptorType = USB_DT_DEVICE,
956 + .bcdUSB = cpu_to_le16(0x0200),
957 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
959 + /* The next three values can be overridden by module parameters */
960 + .idVendor = cpu_to_le16(FSG_VENDOR_ID),
961 + .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
962 + .bcdDevice = cpu_to_le16(0xffff),
964 + .iManufacturer = FSG_STRING_MANUFACTURER,
965 + .iProduct = FSG_STRING_PRODUCT,
966 + .iSerialNumber = FSG_STRING_SERIAL,
967 + .bNumConfigurations = 1,
970 +static struct usb_config_descriptor
972 + .bLength = sizeof config_desc,
973 + .bDescriptorType = USB_DT_CONFIG,
975 + /* wTotalLength computed by usb_gadget_config_buf() */
976 + .bNumInterfaces = 1,
977 + .bConfigurationValue = CONFIG_VALUE,
978 + .iConfiguration = FSG_STRING_CONFIG,
979 + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
980 + .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
984 +static struct usb_qualifier_descriptor
986 + .bLength = sizeof dev_qualifier,
987 + .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
989 + .bcdUSB = cpu_to_le16(0x0200),
990 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
992 + .bNumConfigurations = 1,
995 +static int populate_bos(struct fsg_dev *fsg, u8 *buf)
997 + memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
998 + buf += USB_DT_BOS_SIZE;
1000 + memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
1001 + buf += USB_DT_USB_EXT_CAP_SIZE;
1003 + memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
1005 + return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
1006 + + USB_DT_USB_EXT_CAP_SIZE;
1010 + * Config descriptors must agree with the code that sets configurations
1011 + * and with code managing interfaces and their altsettings. They must
1012 + * also handle different speeds and other-speed requests.
1014 +static int populate_config_buf(struct usb_gadget *gadget,
1015 + u8 *buf, u8 type, unsigned index)
1017 + enum usb_device_speed speed = gadget->speed;
1019 + const struct usb_descriptor_header **function;
1024 + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
1025 + speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
1026 + function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH
1027 + ? (const struct usb_descriptor_header **)fsg_hs_function
1028 + : (const struct usb_descriptor_header **)fsg_fs_function;
1030 + /* for now, don't advertise srp-only devices */
1031 + if (!gadget_is_otg(gadget))
1034 + len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
1035 + ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
1040 +/*-------------------------------------------------------------------------*/
1042 +/* These routines may be called in process context or in_irq */
1044 +/* Caller must hold fsg->lock */
1045 +static void wakeup_thread(struct fsg_dev *fsg)
1047 + /* Tell the main thread that something has happened */
1048 + fsg->thread_wakeup_needed = 1;
1049 + if (fsg->thread_task)
1050 + wake_up_process(fsg->thread_task);
1054 +static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
1056 + unsigned long flags;
1058 + /* Do nothing if a higher-priority exception is already in progress.
1059 + * If a lower-or-equal priority exception is in progress, preempt it
1060 + * and notify the main thread by sending it a signal. */
1061 + spin_lock_irqsave(&fsg->lock, flags);
1062 + if (fsg->state <= new_state) {
1063 + fsg->exception_req_tag = fsg->ep0_req_tag;
1064 + fsg->state = new_state;
1065 + if (fsg->thread_task)
1066 + send_sig_info(SIGUSR1, SEND_SIG_FORCED,
1067 + fsg->thread_task);
1069 + spin_unlock_irqrestore(&fsg->lock, flags);
1073 +/*-------------------------------------------------------------------------*/
1075 +/* The disconnect callback and ep0 routines. These always run in_irq,
1076 + * except that ep0_queue() is called in the main thread to acknowledge
1077 + * completion of various requests: set config, set interface, and
1078 + * Bulk-only device reset. */
1080 +static void fsg_disconnect(struct usb_gadget *gadget)
1082 + struct fsg_dev *fsg = get_gadget_data(gadget);
1084 + DBG(fsg, "disconnect or port reset\n");
1085 + raise_exception(fsg, FSG_STATE_DISCONNECT);
1089 +static int ep0_queue(struct fsg_dev *fsg)
1093 + rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
1094 + if (rc != 0 && rc != -ESHUTDOWN) {
1096 + /* We can't do much more than wait for a reset */
1097 + WARNING(fsg, "error in submission: %s --> %d\n",
1098 + fsg->ep0->name, rc);
1103 +static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
1105 + struct fsg_dev *fsg = ep->driver_data;
1107 + if (req->actual > 0)
1108 + dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
1109 + if (req->status || req->actual != req->length)
1110 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1111 + req->status, req->actual, req->length);
1112 + if (req->status == -ECONNRESET) // Request was cancelled
1113 + usb_ep_fifo_flush(ep);
1115 + if (req->status == 0 && req->context)
1116 + ((fsg_routine_t) (req->context))(fsg);
1120 +/*-------------------------------------------------------------------------*/
1122 +/* Bulk and interrupt endpoint completion handlers.
1123 + * These always run in_irq. */
1125 +static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
1127 + struct fsg_dev *fsg = ep->driver_data;
1128 + struct fsg_buffhd *bh = req->context;
1130 + if (req->status || req->actual != req->length)
1131 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1132 + req->status, req->actual, req->length);
1133 + if (req->status == -ECONNRESET) // Request was cancelled
1134 + usb_ep_fifo_flush(ep);
1136 + /* Hold the lock while we update the request and buffer states */
1138 + spin_lock(&fsg->lock);
1139 + bh->inreq_busy = 0;
1140 + bh->state = BUF_STATE_EMPTY;
1141 + wakeup_thread(fsg);
1142 + spin_unlock(&fsg->lock);
1145 +static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
1147 + struct fsg_dev *fsg = ep->driver_data;
1148 + struct fsg_buffhd *bh = req->context;
1150 + dump_msg(fsg, "bulk-out", req->buf, req->actual);
1151 + if (req->status || req->actual != bh->bulk_out_intended_length)
1152 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1153 + req->status, req->actual,
1154 + bh->bulk_out_intended_length);
1155 + if (req->status == -ECONNRESET) // Request was cancelled
1156 + usb_ep_fifo_flush(ep);
1158 + /* Hold the lock while we update the request and buffer states */
1160 + spin_lock(&fsg->lock);
1161 + bh->outreq_busy = 0;
1162 + bh->state = BUF_STATE_FULL;
1163 + wakeup_thread(fsg);
1164 + spin_unlock(&fsg->lock);
1168 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
1169 +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
1171 + struct fsg_dev *fsg = ep->driver_data;
1172 + struct fsg_buffhd *bh = req->context;
1174 + if (req->status || req->actual != req->length)
1175 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1176 + req->status, req->actual, req->length);
1177 + if (req->status == -ECONNRESET) // Request was cancelled
1178 + usb_ep_fifo_flush(ep);
1180 + /* Hold the lock while we update the request and buffer states */
1182 + spin_lock(&fsg->lock);
1183 + fsg->intreq_busy = 0;
1184 + bh->state = BUF_STATE_EMPTY;
1185 + wakeup_thread(fsg);
1186 + spin_unlock(&fsg->lock);
1190 +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
1192 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
1195 +/*-------------------------------------------------------------------------*/
1197 +/* Ep0 class-specific handlers. These always run in_irq. */
1199 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
1200 +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1202 + struct usb_request *req = fsg->ep0req;
1203 + static u8 cbi_reset_cmnd[6] = {
1204 + SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
1206 + /* Error in command transfer? */
1207 + if (req->status || req->length != req->actual ||
1208 + req->actual < 6 || req->actual > MAX_COMMAND_SIZE) {
1210 + /* Not all controllers allow a protocol stall after
1211 + * receiving control-out data, but we'll try anyway. */
1212 + fsg_set_halt(fsg, fsg->ep0);
1213 + return; // Wait for reset
1216 + /* Is it the special reset command? */
1217 + if (req->actual >= sizeof cbi_reset_cmnd &&
1218 + memcmp(req->buf, cbi_reset_cmnd,
1219 + sizeof cbi_reset_cmnd) == 0) {
1221 + /* Raise an exception to stop the current operation
1222 + * and reinitialize our state. */
1223 + DBG(fsg, "cbi reset request\n");
1224 + raise_exception(fsg, FSG_STATE_RESET);
1228 + VDBG(fsg, "CB[I] accept device-specific command\n");
1229 + spin_lock(&fsg->lock);
1231 + /* Save the command for later */
1232 + if (fsg->cbbuf_cmnd_size)
1233 + WARNING(fsg, "CB[I] overwriting previous command\n");
1234 + fsg->cbbuf_cmnd_size = req->actual;
1235 + memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
1237 + wakeup_thread(fsg);
1238 + spin_unlock(&fsg->lock);
1242 +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1244 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
1247 +static int class_setup_req(struct fsg_dev *fsg,
1248 + const struct usb_ctrlrequest *ctrl)
1250 + struct usb_request *req = fsg->ep0req;
1251 + int value = -EOPNOTSUPP;
1252 + u16 w_index = le16_to_cpu(ctrl->wIndex);
1253 + u16 w_value = le16_to_cpu(ctrl->wValue);
1254 + u16 w_length = le16_to_cpu(ctrl->wLength);
1259 + /* Handle Bulk-only class-specific requests */
1260 + if (transport_is_bbb()) {
1261 + switch (ctrl->bRequest) {
1263 + case US_BULK_RESET_REQUEST:
1264 + if (ctrl->bRequestType != (USB_DIR_OUT |
1265 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1267 + if (w_index != 0 || w_value != 0 || w_length != 0) {
1272 + /* Raise an exception to stop the current operation
1273 + * and reinitialize our state. */
1274 + DBG(fsg, "bulk reset request\n");
1275 + raise_exception(fsg, FSG_STATE_RESET);
1276 + value = DELAYED_STATUS;
1279 + case US_BULK_GET_MAX_LUN:
1280 + if (ctrl->bRequestType != (USB_DIR_IN |
1281 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1283 + if (w_index != 0 || w_value != 0 || w_length != 1) {
1287 + VDBG(fsg, "get max LUN\n");
1288 + *(u8 *) req->buf = fsg->nluns - 1;
1294 + /* Handle CBI class-specific requests */
1296 + switch (ctrl->bRequest) {
1298 + case USB_CBI_ADSC_REQUEST:
1299 + if (ctrl->bRequestType != (USB_DIR_OUT |
1300 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1302 + if (w_index != 0 || w_value != 0) {
1306 + if (w_length > MAX_COMMAND_SIZE) {
1307 + value = -EOVERFLOW;
1311 + fsg->ep0req->context = received_cbi_adsc;
1316 + if (value == -EOPNOTSUPP)
1318 + "unknown class-specific control req "
1319 + "%02x.%02x v%04x i%04x l%u\n",
1320 + ctrl->bRequestType, ctrl->bRequest,
1321 + le16_to_cpu(ctrl->wValue), w_index, w_length);
1326 +/*-------------------------------------------------------------------------*/
1328 +/* Ep0 standard request handlers. These always run in_irq. */
1330 +static int standard_setup_req(struct fsg_dev *fsg,
1331 + const struct usb_ctrlrequest *ctrl)
1333 + struct usb_request *req = fsg->ep0req;
1334 + int value = -EOPNOTSUPP;
1335 + u16 w_index = le16_to_cpu(ctrl->wIndex);
1336 + u16 w_value = le16_to_cpu(ctrl->wValue);
1338 + /* Usually this just stores reply data in the pre-allocated ep0 buffer,
1339 + * but config change events will also reconfigure hardware. */
1340 + switch (ctrl->bRequest) {
1342 + case USB_REQ_GET_DESCRIPTOR:
1343 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1344 + USB_RECIP_DEVICE))
1346 + switch (w_value >> 8) {
1348 + case USB_DT_DEVICE:
1349 + VDBG(fsg, "get device descriptor\n");
1350 + device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
1351 + value = sizeof device_desc;
1352 + memcpy(req->buf, &device_desc, value);
1354 + case USB_DT_DEVICE_QUALIFIER:
1355 + VDBG(fsg, "get device qualifier\n");
1356 + if (!gadget_is_dualspeed(fsg->gadget) ||
1357 + fsg->gadget->speed == USB_SPEED_SUPER)
1360 + * Assume ep0 uses the same maxpacket value for both
1363 + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
1364 + value = sizeof dev_qualifier;
1365 + memcpy(req->buf, &dev_qualifier, value);
1368 + case USB_DT_OTHER_SPEED_CONFIG:
1369 + VDBG(fsg, "get other-speed config descriptor\n");
1370 + if (!gadget_is_dualspeed(fsg->gadget) ||
1371 + fsg->gadget->speed == USB_SPEED_SUPER)
1374 + case USB_DT_CONFIG:
1375 + VDBG(fsg, "get configuration descriptor\n");
1377 + value = populate_config_buf(fsg->gadget,
1383 + case USB_DT_STRING:
1384 + VDBG(fsg, "get string descriptor\n");
1386 + /* wIndex == language code */
1387 + value = usb_gadget_get_string(&fsg_stringtab,
1388 + w_value & 0xff, req->buf);
1392 + VDBG(fsg, "get bos descriptor\n");
1394 + if (gadget_is_superspeed(fsg->gadget))
1395 + value = populate_bos(fsg, req->buf);
1401 + /* One config, two speeds */
1402 + case USB_REQ_SET_CONFIGURATION:
1403 + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
1404 + USB_RECIP_DEVICE))
1406 + VDBG(fsg, "set configuration\n");
1407 + if (w_value == CONFIG_VALUE || w_value == 0) {
1408 + fsg->new_config = w_value;
1410 + /* Raise an exception to wipe out previous transaction
1411 + * state (queued bufs, etc) and set the new config. */
1412 + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
1413 + value = DELAYED_STATUS;
1416 + case USB_REQ_GET_CONFIGURATION:
1417 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1418 + USB_RECIP_DEVICE))
1420 + VDBG(fsg, "get configuration\n");
1421 + *(u8 *) req->buf = fsg->config;
1425 + case USB_REQ_SET_INTERFACE:
1426 + if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
1427 + USB_RECIP_INTERFACE))
1429 + if (fsg->config && w_index == 0) {
1431 + /* Raise an exception to wipe out previous transaction
1432 + * state (queued bufs, etc) and install the new
1433 + * interface altsetting. */
1434 + raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
1435 + value = DELAYED_STATUS;
1438 + case USB_REQ_GET_INTERFACE:
1439 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1440 + USB_RECIP_INTERFACE))
1444 + if (w_index != 0) {
1448 + VDBG(fsg, "get interface\n");
1449 + *(u8 *) req->buf = 0;
1455 + "unknown control req %02x.%02x v%04x i%04x l%u\n",
1456 + ctrl->bRequestType, ctrl->bRequest,
1457 + w_value, w_index, le16_to_cpu(ctrl->wLength));
1464 +static int fsg_setup(struct usb_gadget *gadget,
1465 + const struct usb_ctrlrequest *ctrl)
1467 + struct fsg_dev *fsg = get_gadget_data(gadget);
1469 + int w_length = le16_to_cpu(ctrl->wLength);
1471 + ++fsg->ep0_req_tag; // Record arrival of a new request
1472 + fsg->ep0req->context = NULL;
1473 + fsg->ep0req->length = 0;
1474 + dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
1476 + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
1477 + rc = class_setup_req(fsg, ctrl);
1479 + rc = standard_setup_req(fsg, ctrl);
1481 + /* Respond with data/status or defer until later? */
1482 + if (rc >= 0 && rc != DELAYED_STATUS) {
1483 + rc = min(rc, w_length);
1484 + fsg->ep0req->length = rc;
1485 + fsg->ep0req->zero = rc < w_length;
1486 + fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
1487 + "ep0-in" : "ep0-out");
1488 + rc = ep0_queue(fsg);
1491 + /* Device either stalls (rc < 0) or reports success */
1496 +/*-------------------------------------------------------------------------*/
1498 +/* All the following routines run in process context */
1501 +/* Use this for bulk or interrupt transfers, not ep0 */
1502 +static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
1503 + struct usb_request *req, int *pbusy,
1504 + enum fsg_buffer_state *state)
1508 + if (ep == fsg->bulk_in)
1509 + dump_msg(fsg, "bulk-in", req->buf, req->length);
1510 + else if (ep == fsg->intr_in)
1511 + dump_msg(fsg, "intr-in", req->buf, req->length);
1513 + spin_lock_irq(&fsg->lock);
1515 + *state = BUF_STATE_BUSY;
1516 + spin_unlock_irq(&fsg->lock);
1517 + rc = usb_ep_queue(ep, req, GFP_KERNEL);
1520 + *state = BUF_STATE_EMPTY;
1522 + /* We can't do much more than wait for a reset */
1524 + /* Note: currently the net2280 driver fails zero-length
1525 + * submissions if DMA is enabled. */
1526 + if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
1527 + req->length == 0))
1528 + WARNING(fsg, "error in submission: %s --> %d\n",
1534 +static int sleep_thread(struct fsg_dev *fsg)
1538 + /* Wait until a signal arrives or we are woken up */
1541 + set_current_state(TASK_INTERRUPTIBLE);
1542 + if (signal_pending(current)) {
1546 + if (fsg->thread_wakeup_needed)
1550 + __set_current_state(TASK_RUNNING);
1551 + fsg->thread_wakeup_needed = 0;
1556 +/*-------------------------------------------------------------------------*/
1558 +static int do_read(struct fsg_dev *fsg)
1560 + struct fsg_lun *curlun = fsg->curlun;
1562 + struct fsg_buffhd *bh;
1565 + loff_t file_offset, file_offset_tmp;
1566 + unsigned int amount;
1569 + /* Get the starting Logical Block Address and check that it's
1571 + if (fsg->cmnd[0] == READ_6)
1572 + lba = get_unaligned_be24(&fsg->cmnd[1]);
1574 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1576 + /* We allow DPO (Disable Page Out = don't save data in the
1577 + * cache) and FUA (Force Unit Access = don't read from the
1578 + * cache), but we don't implement them. */
1579 + if ((fsg->cmnd[1] & ~0x18) != 0) {
1580 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1584 + if (lba >= curlun->num_sectors) {
1585 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1588 + file_offset = ((loff_t) lba) << curlun->blkbits;
1590 + /* Carry out the file reads */
1591 + amount_left = fsg->data_size_from_cmnd;
1592 + if (unlikely(amount_left == 0))
1593 + return -EIO; // No default reply
1597 + /* Figure out how much we need to read:
1598 + * Try to read the remaining amount.
1599 + * But don't read more than the buffer size.
1600 + * And don't try to read past the end of the file.
1602 + amount = min((unsigned int) amount_left, mod_data.buflen);
1603 + amount = min((loff_t) amount,
1604 + curlun->file_length - file_offset);
1606 + /* Wait for the next buffer to become available */
1607 + bh = fsg->next_buffhd_to_fill;
1608 + while (bh->state != BUF_STATE_EMPTY) {
1609 + rc = sleep_thread(fsg);
1614 + /* If we were asked to read past the end of file,
1615 + * end with an empty buffer. */
1616 + if (amount == 0) {
1617 + curlun->sense_data =
1618 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1619 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1620 + curlun->info_valid = 1;
1621 + bh->inreq->length = 0;
1622 + bh->state = BUF_STATE_FULL;
1626 + /* Perform the read */
1627 + file_offset_tmp = file_offset;
1628 + nread = vfs_read(curlun->filp,
1629 + (char __user *) bh->buf,
1630 + amount, &file_offset_tmp);
1631 + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
1632 + (unsigned long long) file_offset,
1634 + if (signal_pending(current))
1638 + LDBG(curlun, "error in file read: %d\n",
1641 + } else if (nread < amount) {
1642 + LDBG(curlun, "partial file read: %d/%u\n",
1643 + (int) nread, amount);
1644 + nread = round_down(nread, curlun->blksize);
1646 + file_offset += nread;
1647 + amount_left -= nread;
1648 + fsg->residue -= nread;
1650 + /* Except at the end of the transfer, nread will be
1651 + * equal to the buffer size, which is divisible by the
1652 + * bulk-in maxpacket size.
1654 + bh->inreq->length = nread;
1655 + bh->state = BUF_STATE_FULL;
1657 + /* If an error occurred, report it and its position */
1658 + if (nread < amount) {
1659 + curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
1660 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1661 + curlun->info_valid = 1;
1665 + if (amount_left == 0)
1666 + break; // No more left to read
1668 + /* Send this buffer and go read some more */
1669 + bh->inreq->zero = 0;
1670 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
1671 + &bh->inreq_busy, &bh->state);
1672 + fsg->next_buffhd_to_fill = bh->next;
1675 + return -EIO; // No default reply
1679 +/*-------------------------------------------------------------------------*/
1681 +static int do_write(struct fsg_dev *fsg)
1683 + struct fsg_lun *curlun = fsg->curlun;
1685 + struct fsg_buffhd *bh;
1686 + int get_some_more;
1687 + u32 amount_left_to_req, amount_left_to_write;
1688 + loff_t usb_offset, file_offset, file_offset_tmp;
1689 + unsigned int amount;
1694 + curlun->sense_data = SS_WRITE_PROTECTED;
1697 + spin_lock(&curlun->filp->f_lock);
1698 + curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait
1699 + spin_unlock(&curlun->filp->f_lock);
1701 + /* Get the starting Logical Block Address and check that it's
1703 + if (fsg->cmnd[0] == WRITE_6)
1704 + lba = get_unaligned_be24(&fsg->cmnd[1]);
1706 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1708 + /* We allow DPO (Disable Page Out = don't save data in the
1709 + * cache) and FUA (Force Unit Access = write directly to the
1710 + * medium). We don't implement DPO; we implement FUA by
1711 + * performing synchronous output. */
1712 + if ((fsg->cmnd[1] & ~0x18) != 0) {
1713 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1717 + if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) {
1718 + spin_lock(&curlun->filp->f_lock);
1719 + curlun->filp->f_flags |= O_DSYNC;
1720 + spin_unlock(&curlun->filp->f_lock);
1723 + if (lba >= curlun->num_sectors) {
1724 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1728 + /* Carry out the file writes */
1729 + get_some_more = 1;
1730 + file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
1731 + amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
1733 + while (amount_left_to_write > 0) {
1735 + /* Queue a request for more data from the host */
1736 + bh = fsg->next_buffhd_to_fill;
1737 + if (bh->state == BUF_STATE_EMPTY && get_some_more) {
1739 + /* Figure out how much we want to get:
1740 + * Try to get the remaining amount,
1741 + * but not more than the buffer size.
1743 + amount = min(amount_left_to_req, mod_data.buflen);
1745 + /* Beyond the end of the backing file? */
1746 + if (usb_offset >= curlun->file_length) {
1747 + get_some_more = 0;
1748 + curlun->sense_data =
1749 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1750 + curlun->sense_data_info = usb_offset >> curlun->blkbits;
1751 + curlun->info_valid = 1;
1755 + /* Get the next buffer */
1756 + usb_offset += amount;
1757 + fsg->usb_amount_left -= amount;
1758 + amount_left_to_req -= amount;
1759 + if (amount_left_to_req == 0)
1760 + get_some_more = 0;
1762 + /* Except at the end of the transfer, amount will be
1763 + * equal to the buffer size, which is divisible by
1764 + * the bulk-out maxpacket size.
1766 + set_bulk_out_req_length(fsg, bh, amount);
1767 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
1768 + &bh->outreq_busy, &bh->state);
1769 + fsg->next_buffhd_to_fill = bh->next;
1773 + /* Write the received data to the backing file */
1774 + bh = fsg->next_buffhd_to_drain;
1775 + if (bh->state == BUF_STATE_EMPTY && !get_some_more)
1776 + break; // We stopped early
1777 + if (bh->state == BUF_STATE_FULL) {
1779 + fsg->next_buffhd_to_drain = bh->next;
1780 + bh->state = BUF_STATE_EMPTY;
1782 + /* Did something go wrong with the transfer? */
1783 + if (bh->outreq->status != 0) {
1784 + curlun->sense_data = SS_COMMUNICATION_FAILURE;
1785 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1786 + curlun->info_valid = 1;
1790 + amount = bh->outreq->actual;
1791 + if (curlun->file_length - file_offset < amount) {
1793 + "write %u @ %llu beyond end %llu\n",
1794 + amount, (unsigned long long) file_offset,
1795 + (unsigned long long) curlun->file_length);
1796 + amount = curlun->file_length - file_offset;
1799 + /* Don't accept excess data. The spec doesn't say
1800 + * what to do in this case. We'll ignore the error.
1802 + amount = min(amount, bh->bulk_out_intended_length);
1804 + /* Don't write a partial block */
1805 + amount = round_down(amount, curlun->blksize);
1809 + /* Perform the write */
1810 + file_offset_tmp = file_offset;
1811 + nwritten = vfs_write(curlun->filp,
1812 + (char __user *) bh->buf,
1813 + amount, &file_offset_tmp);
1814 + VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
1815 + (unsigned long long) file_offset,
1817 + if (signal_pending(current))
1818 + return -EINTR; // Interrupted!
1820 + if (nwritten < 0) {
1821 + LDBG(curlun, "error in file write: %d\n",
1824 + } else if (nwritten < amount) {
1825 + LDBG(curlun, "partial file write: %d/%u\n",
1826 + (int) nwritten, amount);
1827 + nwritten = round_down(nwritten, curlun->blksize);
1829 + file_offset += nwritten;
1830 + amount_left_to_write -= nwritten;
1831 + fsg->residue -= nwritten;
1833 + /* If an error occurred, report it and its position */
1834 + if (nwritten < amount) {
1835 + curlun->sense_data = SS_WRITE_ERROR;
1836 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1837 + curlun->info_valid = 1;
1842 + /* Did the host decide to stop early? */
1843 + if (bh->outreq->actual < bh->bulk_out_intended_length) {
1844 + fsg->short_packet_received = 1;
1850 + /* Wait for something to happen */
1851 + rc = sleep_thread(fsg);
1856 + return -EIO; // No default reply
1860 +/*-------------------------------------------------------------------------*/
1862 +static int do_synchronize_cache(struct fsg_dev *fsg)
1864 + struct fsg_lun *curlun = fsg->curlun;
1867 + /* We ignore the requested LBA and write out all file's
1868 + * dirty data buffers. */
1869 + rc = fsg_lun_fsync_sub(curlun);
1871 + curlun->sense_data = SS_WRITE_ERROR;
1876 +/*-------------------------------------------------------------------------*/
1878 +static void invalidate_sub(struct fsg_lun *curlun)
1880 + struct file *filp = curlun->filp;
1881 + struct inode *inode = filp->f_path.dentry->d_inode;
1884 + rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
1885 + VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
1888 +static int do_verify(struct fsg_dev *fsg)
1890 + struct fsg_lun *curlun = fsg->curlun;
1892 + u32 verification_length;
1893 + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
1894 + loff_t file_offset, file_offset_tmp;
1896 + unsigned int amount;
1899 + /* Get the starting Logical Block Address and check that it's
1901 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1902 + if (lba >= curlun->num_sectors) {
1903 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1907 + /* We allow DPO (Disable Page Out = don't save data in the
1908 + * cache) but we don't implement it. */
1909 + if ((fsg->cmnd[1] & ~0x10) != 0) {
1910 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1914 + verification_length = get_unaligned_be16(&fsg->cmnd[7]);
1915 + if (unlikely(verification_length == 0))
1916 + return -EIO; // No default reply
1918 + /* Prepare to carry out the file verify */
1919 + amount_left = verification_length << curlun->blkbits;
1920 + file_offset = ((loff_t) lba) << curlun->blkbits;
1922 + /* Write out all the dirty buffers before invalidating them */
1923 + fsg_lun_fsync_sub(curlun);
1924 + if (signal_pending(current))
1927 + invalidate_sub(curlun);
1928 + if (signal_pending(current))
1931 + /* Just try to read the requested blocks */
1932 + while (amount_left > 0) {
1934 + /* Figure out how much we need to read:
1935 + * Try to read the remaining amount, but not more than
1936 + * the buffer size.
1937 + * And don't try to read past the end of the file.
1939 + amount = min((unsigned int) amount_left, mod_data.buflen);
1940 + amount = min((loff_t) amount,
1941 + curlun->file_length - file_offset);
1942 + if (amount == 0) {
1943 + curlun->sense_data =
1944 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1945 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1946 + curlun->info_valid = 1;
1950 + /* Perform the read */
1951 + file_offset_tmp = file_offset;
1952 + nread = vfs_read(curlun->filp,
1953 + (char __user *) bh->buf,
1954 + amount, &file_offset_tmp);
1955 + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
1956 + (unsigned long long) file_offset,
1958 + if (signal_pending(current))
1962 + LDBG(curlun, "error in file verify: %d\n",
1965 + } else if (nread < amount) {
1966 + LDBG(curlun, "partial file verify: %d/%u\n",
1967 + (int) nread, amount);
1968 + nread = round_down(nread, curlun->blksize);
1971 + curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
1972 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1973 + curlun->info_valid = 1;
1976 + file_offset += nread;
1977 + amount_left -= nread;
1983 +/*-------------------------------------------------------------------------*/
1985 +static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1987 + u8 *buf = (u8 *) bh->buf;
1989 + static char vendor_id[] = "Linux ";
1990 + static char product_disk_id[] = "File-Stor Gadget";
1991 + static char product_cdrom_id[] = "File-CD Gadget ";
1993 + if (!fsg->curlun) { // Unsupported LUNs are okay
1994 + fsg->bad_lun_okay = 1;
1995 + memset(buf, 0, 36);
1996 + buf[0] = 0x7f; // Unsupported, no device-type
1997 + buf[4] = 31; // Additional length
2001 + memset(buf, 0, 8);
2002 + buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK);
2003 + if (mod_data.removable)
2005 + buf[2] = 2; // ANSI SCSI level 2
2006 + buf[3] = 2; // SCSI-2 INQUIRY data format
2007 + buf[4] = 31; // Additional length
2008 + // No special options
2009 + sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
2010 + (mod_data.cdrom ? product_cdrom_id :
2012 + mod_data.release);
2017 +static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2019 + struct fsg_lun *curlun = fsg->curlun;
2020 + u8 *buf = (u8 *) bh->buf;
2025 + * From the SCSI-2 spec., section 7.9 (Unit attention condition):
2027 + * If a REQUEST SENSE command is received from an initiator
2028 + * with a pending unit attention condition (before the target
2029 + * generates the contingent allegiance condition), then the
2030 + * target shall either:
2031 + * a) report any pending sense data and preserve the unit
2032 + * attention condition on the logical unit, or,
2033 + * b) report the unit attention condition, may discard any
2034 + * pending sense data, and clear the unit attention
2035 + * condition on the logical unit for that initiator.
2037 + * FSG normally uses option a); enable this code to use option b).
2040 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
2041 + curlun->sense_data = curlun->unit_attention_data;
2042 + curlun->unit_attention_data = SS_NO_SENSE;
2046 + if (!curlun) { // Unsupported LUNs are okay
2047 + fsg->bad_lun_okay = 1;
2048 + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
2052 + sd = curlun->sense_data;
2053 + sdinfo = curlun->sense_data_info;
2054 + valid = curlun->info_valid << 7;
2055 + curlun->sense_data = SS_NO_SENSE;
2056 + curlun->sense_data_info = 0;
2057 + curlun->info_valid = 0;
2060 + memset(buf, 0, 18);
2061 + buf[0] = valid | 0x70; // Valid, current error
2063 + put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */
2064 + buf[7] = 18 - 8; // Additional sense length
2065 + buf[12] = ASC(sd);
2066 + buf[13] = ASCQ(sd);
2071 +static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2073 + struct fsg_lun *curlun = fsg->curlun;
2074 + u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
2075 + int pmi = fsg->cmnd[8];
2076 + u8 *buf = (u8 *) bh->buf;
2078 + /* Check the PMI and LBA fields */
2079 + if (pmi > 1 || (pmi == 0 && lba != 0)) {
2080 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2084 + put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
2085 + /* Max logical block */
2086 + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
2091 +static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2093 + struct fsg_lun *curlun = fsg->curlun;
2094 + int msf = fsg->cmnd[1] & 0x02;
2095 + u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
2096 + u8 *buf = (u8 *) bh->buf;
2098 + if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
2099 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2102 + if (lba >= curlun->num_sectors) {
2103 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
2107 + memset(buf, 0, 8);
2108 + buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */
2109 + store_cdrom_address(&buf[4], msf, lba);
2114 +static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2116 + struct fsg_lun *curlun = fsg->curlun;
2117 + int msf = fsg->cmnd[1] & 0x02;
2118 + int start_track = fsg->cmnd[6];
2119 + u8 *buf = (u8 *) bh->buf;
2121 + if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
2122 + start_track > 1) {
2123 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2127 + memset(buf, 0, 20);
2128 + buf[1] = (20-2); /* TOC data length */
2129 + buf[2] = 1; /* First track number */
2130 + buf[3] = 1; /* Last track number */
2131 + buf[5] = 0x16; /* Data track, copying allowed */
2132 + buf[6] = 0x01; /* Only track is number 1 */
2133 + store_cdrom_address(&buf[8], msf, 0);
2135 + buf[13] = 0x16; /* Lead-out track is data */
2136 + buf[14] = 0xAA; /* Lead-out track number */
2137 + store_cdrom_address(&buf[16], msf, curlun->num_sectors);
2142 +static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2144 + struct fsg_lun *curlun = fsg->curlun;
2145 + int mscmnd = fsg->cmnd[0];
2146 + u8 *buf = (u8 *) bh->buf;
2148 + int pc, page_code;
2149 + int changeable_values, all_pages;
2150 + int valid_page = 0;
2153 + if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD
2154 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2157 + pc = fsg->cmnd[2] >> 6;
2158 + page_code = fsg->cmnd[2] & 0x3f;
2160 + curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
2163 + changeable_values = (pc == 1);
2164 + all_pages = (page_code == 0x3f);
2166 + /* Write the mode parameter header. Fixed values are: default
2167 + * medium type, no cache control (DPOFUA), and no block descriptors.
2168 + * The only variable value is the WriteProtect bit. We will fill in
2169 + * the mode data length later. */
2170 + memset(buf, 0, 8);
2171 + if (mscmnd == MODE_SENSE) {
2172 + buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
2175 + } else { // MODE_SENSE_10
2176 + buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
2178 + limit = 65535; // Should really be mod_data.buflen
2181 + /* No block descriptors */
2183 + /* The mode pages, in numerical order. The only page we support
2184 + * is the Caching page. */
2185 + if (page_code == 0x08 || all_pages) {
2187 + buf[0] = 0x08; // Page code
2188 + buf[1] = 10; // Page length
2189 + memset(buf+2, 0, 10); // None of the fields are changeable
2191 + if (!changeable_values) {
2192 + buf[2] = 0x04; // Write cache enable,
2193 + // Read cache not disabled
2194 + // No cache retention priorities
2195 + put_unaligned_be16(0xffff, &buf[4]);
2196 + /* Don't disable prefetch */
2197 + /* Minimum prefetch = 0 */
2198 + put_unaligned_be16(0xffff, &buf[8]);
2199 + /* Maximum prefetch */
2200 + put_unaligned_be16(0xffff, &buf[10]);
2201 + /* Maximum prefetch ceiling */
2206 + /* Check that a valid page was requested and the mode data length
2207 + * isn't too long. */
2209 + if (!valid_page || len > limit) {
2210 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2214 + /* Store the mode data length */
2215 + if (mscmnd == MODE_SENSE)
2216 + buf0[0] = len - 1;
2218 + put_unaligned_be16(len - 2, buf0);
2223 +static int do_start_stop(struct fsg_dev *fsg)
2225 + struct fsg_lun *curlun = fsg->curlun;
2228 + if (!mod_data.removable) {
2229 + curlun->sense_data = SS_INVALID_COMMAND;
2233 + // int immed = fsg->cmnd[1] & 0x01;
2234 + loej = fsg->cmnd[4] & 0x02;
2235 + start = fsg->cmnd[4] & 0x01;
2237 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
2238 + if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed
2239 + (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start
2240 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2246 + /* Are we allowed to unload the media? */
2247 + if (curlun->prevent_medium_removal) {
2248 + LDBG(curlun, "unload attempt prevented\n");
2249 + curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
2252 + if (loej) { // Simulate an unload/eject
2253 + up_read(&fsg->filesem);
2254 + down_write(&fsg->filesem);
2255 + fsg_lun_close(curlun);
2256 + up_write(&fsg->filesem);
2257 + down_read(&fsg->filesem);
2261 + /* Our emulation doesn't support mounting; the medium is
2262 + * available for use as soon as it is loaded. */
2263 + if (!fsg_lun_is_open(curlun)) {
2264 + curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
2273 +static int do_prevent_allow(struct fsg_dev *fsg)
2275 + struct fsg_lun *curlun = fsg->curlun;
2278 + if (!mod_data.removable) {
2279 + curlun->sense_data = SS_INVALID_COMMAND;
2283 + prevent = fsg->cmnd[4] & 0x01;
2284 + if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent
2285 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2289 + if (curlun->prevent_medium_removal && !prevent)
2290 + fsg_lun_fsync_sub(curlun);
2291 + curlun->prevent_medium_removal = prevent;
2296 +static int do_read_format_capacities(struct fsg_dev *fsg,
2297 + struct fsg_buffhd *bh)
2299 + struct fsg_lun *curlun = fsg->curlun;
2300 + u8 *buf = (u8 *) bh->buf;
2302 + buf[0] = buf[1] = buf[2] = 0;
2303 + buf[3] = 8; // Only the Current/Maximum Capacity Descriptor
2306 + put_unaligned_be32(curlun->num_sectors, &buf[0]);
2307 + /* Number of blocks */
2308 + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
2309 + buf[4] = 0x02; /* Current capacity */
2314 +static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2316 + struct fsg_lun *curlun = fsg->curlun;
2318 + /* We don't support MODE SELECT */
2319 + curlun->sense_data = SS_INVALID_COMMAND;
2324 +/*-------------------------------------------------------------------------*/
2326 +static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
2330 + rc = fsg_set_halt(fsg, fsg->bulk_in);
2331 + if (rc == -EAGAIN)
2332 + VDBG(fsg, "delayed bulk-in endpoint halt\n");
2334 + if (rc != -EAGAIN) {
2335 + WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
2340 + /* Wait for a short time and then try again */
2341 + if (msleep_interruptible(100) != 0)
2343 + rc = usb_ep_set_halt(fsg->bulk_in);
2348 +static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
2352 + DBG(fsg, "bulk-in set wedge\n");
2353 + rc = usb_ep_set_wedge(fsg->bulk_in);
2354 + if (rc == -EAGAIN)
2355 + VDBG(fsg, "delayed bulk-in endpoint wedge\n");
2357 + if (rc != -EAGAIN) {
2358 + WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
2363 + /* Wait for a short time and then try again */
2364 + if (msleep_interruptible(100) != 0)
2366 + rc = usb_ep_set_wedge(fsg->bulk_in);
2371 +static int throw_away_data(struct fsg_dev *fsg)
2373 + struct fsg_buffhd *bh;
2377 + while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY ||
2378 + fsg->usb_amount_left > 0) {
2380 + /* Throw away the data in a filled buffer */
2381 + if (bh->state == BUF_STATE_FULL) {
2383 + bh->state = BUF_STATE_EMPTY;
2384 + fsg->next_buffhd_to_drain = bh->next;
2386 + /* A short packet or an error ends everything */
2387 + if (bh->outreq->actual < bh->bulk_out_intended_length ||
2388 + bh->outreq->status != 0) {
2389 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2395 + /* Try to submit another request if we need one */
2396 + bh = fsg->next_buffhd_to_fill;
2397 + if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
2398 + amount = min(fsg->usb_amount_left,
2399 + (u32) mod_data.buflen);
2401 + /* Except at the end of the transfer, amount will be
2402 + * equal to the buffer size, which is divisible by
2403 + * the bulk-out maxpacket size.
2405 + set_bulk_out_req_length(fsg, bh, amount);
2406 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
2407 + &bh->outreq_busy, &bh->state);
2408 + fsg->next_buffhd_to_fill = bh->next;
2409 + fsg->usb_amount_left -= amount;
2413 + /* Otherwise wait for something to happen */
2414 + rc = sleep_thread(fsg);
2422 +static int finish_reply(struct fsg_dev *fsg)
2424 + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
2427 + switch (fsg->data_dir) {
2428 + case DATA_DIR_NONE:
2429 + break; // Nothing to send
2431 + /* If we don't know whether the host wants to read or write,
2432 + * this must be CB or CBI with an unknown command. We mustn't
2433 + * try to send or receive any data. So stall both bulk pipes
2434 + * if we can and wait for a reset. */
2435 + case DATA_DIR_UNKNOWN:
2436 + if (mod_data.can_stall) {
2437 + fsg_set_halt(fsg, fsg->bulk_out);
2438 + rc = halt_bulk_in_endpoint(fsg);
2442 + /* All but the last buffer of data must have already been sent */
2443 + case DATA_DIR_TO_HOST:
2444 + if (fsg->data_size == 0)
2445 + ; // Nothing to send
2447 + /* If there's no residue, simply send the last buffer */
2448 + else if (fsg->residue == 0) {
2449 + bh->inreq->zero = 0;
2450 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2451 + &bh->inreq_busy, &bh->state);
2452 + fsg->next_buffhd_to_fill = bh->next;
2455 + /* There is a residue. For CB and CBI, simply mark the end
2456 + * of the data with a short packet. However, if we are
2457 + * allowed to stall, there was no data at all (residue ==
2458 + * data_size), and the command failed (invalid LUN or
2459 + * sense data is set), then halt the bulk-in endpoint
2461 + else if (!transport_is_bbb()) {
2462 + if (mod_data.can_stall &&
2463 + fsg->residue == fsg->data_size &&
2464 + (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) {
2465 + bh->state = BUF_STATE_EMPTY;
2466 + rc = halt_bulk_in_endpoint(fsg);
2468 + bh->inreq->zero = 1;
2469 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2470 + &bh->inreq_busy, &bh->state);
2471 + fsg->next_buffhd_to_fill = bh->next;
2476 + * For Bulk-only, mark the end of the data with a short
2477 + * packet. If we are allowed to stall, halt the bulk-in
2478 + * endpoint. (Note: This violates the Bulk-Only Transport
2479 + * specification, which requires us to pad the data if we
2480 + * don't halt the endpoint. Presumably nobody will mind.)
2483 + bh->inreq->zero = 1;
2484 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2485 + &bh->inreq_busy, &bh->state);
2486 + fsg->next_buffhd_to_fill = bh->next;
2487 + if (mod_data.can_stall)
2488 + rc = halt_bulk_in_endpoint(fsg);
2492 + /* We have processed all we want from the data the host has sent.
2493 + * There may still be outstanding bulk-out requests. */
2494 + case DATA_DIR_FROM_HOST:
2495 + if (fsg->residue == 0)
2496 + ; // Nothing to receive
2498 + /* Did the host stop sending unexpectedly early? */
2499 + else if (fsg->short_packet_received) {
2500 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2504 + /* We haven't processed all the incoming data. Even though
2505 + * we may be allowed to stall, doing so would cause a race.
2506 + * The controller may already have ACK'ed all the remaining
2507 + * bulk-out packets, in which case the host wouldn't see a
2508 + * STALL. Not realizing the endpoint was halted, it wouldn't
2509 + * clear the halt -- leading to problems later on. */
2511 + else if (mod_data.can_stall) {
2512 + fsg_set_halt(fsg, fsg->bulk_out);
2513 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2518 + /* We can't stall. Read in the excess data and throw it
2521 + rc = throw_away_data(fsg);
2528 +static int send_status(struct fsg_dev *fsg)
2530 + struct fsg_lun *curlun = fsg->curlun;
2531 + struct fsg_buffhd *bh;
2533 + u8 status = US_BULK_STAT_OK;
2534 + u32 sd, sdinfo = 0;
2536 + /* Wait for the next buffer to become available */
2537 + bh = fsg->next_buffhd_to_fill;
2538 + while (bh->state != BUF_STATE_EMPTY) {
2539 + rc = sleep_thread(fsg);
2545 + sd = curlun->sense_data;
2546 + sdinfo = curlun->sense_data_info;
2547 + } else if (fsg->bad_lun_okay)
2550 + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
2552 + if (fsg->phase_error) {
2553 + DBG(fsg, "sending phase-error status\n");
2554 + status = US_BULK_STAT_PHASE;
2555 + sd = SS_INVALID_COMMAND;
2556 + } else if (sd != SS_NO_SENSE) {
2557 + DBG(fsg, "sending command-failure status\n");
2558 + status = US_BULK_STAT_FAIL;
2559 + VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
2561 + SK(sd), ASC(sd), ASCQ(sd), sdinfo);
2564 + if (transport_is_bbb()) {
2565 + struct bulk_cs_wrap *csw = bh->buf;
2567 + /* Store and send the Bulk-only CSW */
2568 + csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
2569 + csw->Tag = fsg->tag;
2570 + csw->Residue = cpu_to_le32(fsg->residue);
2571 + csw->Status = status;
2573 + bh->inreq->length = US_BULK_CS_WRAP_LEN;
2574 + bh->inreq->zero = 0;
2575 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2576 + &bh->inreq_busy, &bh->state);
2578 + } else if (mod_data.transport_type == USB_PR_CB) {
2580 + /* Control-Bulk transport has no status phase! */
2583 + } else { // USB_PR_CBI
2584 + struct interrupt_data *buf = bh->buf;
2586 + /* Store and send the Interrupt data. UFI sends the ASC
2587 + * and ASCQ bytes. Everything else sends a Type (which
2588 + * is always 0) and the status Value. */
2589 + if (mod_data.protocol_type == USB_SC_UFI) {
2590 + buf->bType = ASC(sd);
2591 + buf->bValue = ASCQ(sd);
2594 + buf->bValue = status;
2596 + fsg->intreq->length = CBI_INTERRUPT_DATA_LEN;
2598 + fsg->intr_buffhd = bh; // Point to the right buffhd
2599 + fsg->intreq->buf = bh->inreq->buf;
2600 + fsg->intreq->context = bh;
2601 + start_transfer(fsg, fsg->intr_in, fsg->intreq,
2602 + &fsg->intreq_busy, &bh->state);
2605 + fsg->next_buffhd_to_fill = bh->next;
2610 +/*-------------------------------------------------------------------------*/
2612 +/* Check whether the command is properly formed and whether its data size
2613 + * and direction agree with the values we already have. */
2614 +static int check_command(struct fsg_dev *fsg, int cmnd_size,
2615 + enum data_direction data_dir, unsigned int mask,
2616 + int needs_medium, const char *name)
2619 + int lun = fsg->cmnd[1] >> 5;
2620 + static const char dirletter[4] = {'u', 'o', 'i', 'n'};
2622 + struct fsg_lun *curlun;
2624 + /* Adjust the expected cmnd_size for protocol encapsulation padding.
2625 + * Transparent SCSI doesn't pad. */
2626 + if (protocol_is_scsi())
2629 + /* There's some disagreement as to whether RBC pads commands or not.
2630 + * We'll play it safe and accept either form. */
2631 + else if (mod_data.protocol_type == USB_SC_RBC) {
2632 + if (fsg->cmnd_size == 12)
2635 + /* All the other protocols pad to 12 bytes */
2640 + if (fsg->data_dir != DATA_DIR_UNKNOWN)
2641 + sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir],
2643 + VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
2644 + name, cmnd_size, dirletter[(int) data_dir],
2645 + fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen);
2647 + /* We can't reply at all until we know the correct data direction
2649 + if (fsg->data_size_from_cmnd == 0)
2650 + data_dir = DATA_DIR_NONE;
2651 + if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI
2652 + fsg->data_dir = data_dir;
2653 + fsg->data_size = fsg->data_size_from_cmnd;
2655 + } else { // Bulk-only
2656 + if (fsg->data_size < fsg->data_size_from_cmnd) {
2658 + /* Host data size < Device data size is a phase error.
2659 + * Carry out the command, but only transfer as much
2660 + * as we are allowed. */
2661 + fsg->data_size_from_cmnd = fsg->data_size;
2662 + fsg->phase_error = 1;
2665 + fsg->residue = fsg->usb_amount_left = fsg->data_size;
2667 + /* Conflicting data directions is a phase error */
2668 + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) {
2669 + fsg->phase_error = 1;
2673 + /* Verify the length of the command itself */
2674 + if (cmnd_size != fsg->cmnd_size) {
2676 + /* Special case workaround: There are plenty of buggy SCSI
2677 + * implementations. Many have issues with cbw->Length
2678 + * field passing a wrong command size. For those cases we
2679 + * always try to work around the problem by using the length
2680 + * sent by the host side provided it is at least as large
2681 + * as the correct command length.
2682 + * Examples of such cases would be MS-Windows, which issues
2683 + * REQUEST SENSE with cbw->Length == 12 where it should
2684 + * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
2685 + * REQUEST SENSE with cbw->Length == 10 where it should
2688 + if (cmnd_size <= fsg->cmnd_size) {
2689 + DBG(fsg, "%s is buggy! Expected length %d "
2690 + "but we got %d\n", name,
2691 + cmnd_size, fsg->cmnd_size);
2692 + cmnd_size = fsg->cmnd_size;
2694 + fsg->phase_error = 1;
2699 + /* Check that the LUN values are consistent */
2700 + if (transport_is_bbb()) {
2701 + if (fsg->lun != lun)
2702 + DBG(fsg, "using LUN %d from CBW, "
2703 + "not LUN %d from CDB\n",
2707 + /* Check the LUN */
2708 + curlun = fsg->curlun;
2710 + if (fsg->cmnd[0] != REQUEST_SENSE) {
2711 + curlun->sense_data = SS_NO_SENSE;
2712 + curlun->sense_data_info = 0;
2713 + curlun->info_valid = 0;
2716 + fsg->bad_lun_okay = 0;
2718 + /* INQUIRY and REQUEST SENSE commands are explicitly allowed
2719 + * to use unsupported LUNs; all others may not. */
2720 + if (fsg->cmnd[0] != INQUIRY &&
2721 + fsg->cmnd[0] != REQUEST_SENSE) {
2722 + DBG(fsg, "unsupported LUN %d\n", fsg->lun);
2727 + /* If a unit attention condition exists, only INQUIRY and
2728 + * REQUEST SENSE commands are allowed; anything else must fail. */
2729 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
2730 + fsg->cmnd[0] != INQUIRY &&
2731 + fsg->cmnd[0] != REQUEST_SENSE) {
2732 + curlun->sense_data = curlun->unit_attention_data;
2733 + curlun->unit_attention_data = SS_NO_SENSE;
2737 + /* Check that only command bytes listed in the mask are non-zero */
2738 + fsg->cmnd[1] &= 0x1f; // Mask away the LUN
2739 + for (i = 1; i < cmnd_size; ++i) {
2740 + if (fsg->cmnd[i] && !(mask & (1 << i))) {
2742 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2747 + /* If the medium isn't mounted and the command needs to access
2748 + * it, return an error. */
2749 + if (curlun && !fsg_lun_is_open(curlun) && needs_medium) {
2750 + curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
2757 +/* wrapper of check_command for data size in blocks handling */
2758 +static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
2759 + enum data_direction data_dir, unsigned int mask,
2760 + int needs_medium, const char *name)
2763 + fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
2764 + return check_command(fsg, cmnd_size, data_dir,
2765 + mask, needs_medium, name);
2768 +static int do_scsi_command(struct fsg_dev *fsg)
2770 + struct fsg_buffhd *bh;
2772 + int reply = -EINVAL;
2774 + static char unknown[16];
2778 + /* Wait for the next buffer to become available for data or status */
2779 + bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
2780 + while (bh->state != BUF_STATE_EMPTY) {
2781 + rc = sleep_thread(fsg);
2785 + fsg->phase_error = 0;
2786 + fsg->short_packet_received = 0;
2788 + down_read(&fsg->filesem); // We're using the backing file
2789 + switch (fsg->cmnd[0]) {
2792 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2793 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2796 + reply = do_inquiry(fsg, bh);
2800 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2801 + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
2802 + (1<<1) | (1<<4), 0,
2803 + "MODE SELECT(6)")) == 0)
2804 + reply = do_mode_select(fsg, bh);
2807 + case MODE_SELECT_10:
2808 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2809 + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
2810 + (1<<1) | (3<<7), 0,
2811 + "MODE SELECT(10)")) == 0)
2812 + reply = do_mode_select(fsg, bh);
2816 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2817 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2818 + (1<<1) | (1<<2) | (1<<4), 0,
2819 + "MODE SENSE(6)")) == 0)
2820 + reply = do_mode_sense(fsg, bh);
2823 + case MODE_SENSE_10:
2824 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2825 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2826 + (1<<1) | (1<<2) | (3<<7), 0,
2827 + "MODE SENSE(10)")) == 0)
2828 + reply = do_mode_sense(fsg, bh);
2831 + case ALLOW_MEDIUM_REMOVAL:
2832 + fsg->data_size_from_cmnd = 0;
2833 + if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
2835 + "PREVENT-ALLOW MEDIUM REMOVAL")) == 0)
2836 + reply = do_prevent_allow(fsg);
2841 + fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
2842 + if ((reply = check_command_size_in_blocks(fsg, 6,
2844 + (7<<1) | (1<<4), 1,
2846 + reply = do_read(fsg);
2850 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2851 + if ((reply = check_command_size_in_blocks(fsg, 10,
2853 + (1<<1) | (0xf<<2) | (3<<7), 1,
2854 + "READ(10)")) == 0)
2855 + reply = do_read(fsg);
2859 + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
2860 + if ((reply = check_command_size_in_blocks(fsg, 12,
2862 + (1<<1) | (0xf<<2) | (0xf<<6), 1,
2863 + "READ(12)")) == 0)
2864 + reply = do_read(fsg);
2867 + case READ_CAPACITY:
2868 + fsg->data_size_from_cmnd = 8;
2869 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2870 + (0xf<<2) | (1<<8), 1,
2871 + "READ CAPACITY")) == 0)
2872 + reply = do_read_capacity(fsg, bh);
2876 + if (!mod_data.cdrom)
2877 + goto unknown_cmnd;
2878 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2879 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2880 + (3<<7) | (0x1f<<1), 1,
2881 + "READ HEADER")) == 0)
2882 + reply = do_read_header(fsg, bh);
2886 + if (!mod_data.cdrom)
2887 + goto unknown_cmnd;
2888 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2889 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2890 + (7<<6) | (1<<1), 1,
2891 + "READ TOC")) == 0)
2892 + reply = do_read_toc(fsg, bh);
2895 + case READ_FORMAT_CAPACITIES:
2896 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2897 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2899 + "READ FORMAT CAPACITIES")) == 0)
2900 + reply = do_read_format_capacities(fsg, bh);
2903 + case REQUEST_SENSE:
2904 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2905 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2907 + "REQUEST SENSE")) == 0)
2908 + reply = do_request_sense(fsg, bh);
2912 + fsg->data_size_from_cmnd = 0;
2913 + if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
2914 + (1<<1) | (1<<4), 0,
2915 + "START-STOP UNIT")) == 0)
2916 + reply = do_start_stop(fsg);
2919 + case SYNCHRONIZE_CACHE:
2920 + fsg->data_size_from_cmnd = 0;
2921 + if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
2922 + (0xf<<2) | (3<<7), 1,
2923 + "SYNCHRONIZE CACHE")) == 0)
2924 + reply = do_synchronize_cache(fsg);
2927 + case TEST_UNIT_READY:
2928 + fsg->data_size_from_cmnd = 0;
2929 + reply = check_command(fsg, 6, DATA_DIR_NONE,
2931 + "TEST UNIT READY");
2934 + /* Although optional, this command is used by MS-Windows. We
2935 + * support a minimal version: BytChk must be 0. */
2937 + fsg->data_size_from_cmnd = 0;
2938 + if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
2939 + (1<<1) | (0xf<<2) | (3<<7), 1,
2941 + reply = do_verify(fsg);
2946 + fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
2947 + if ((reply = check_command_size_in_blocks(fsg, 6,
2948 + DATA_DIR_FROM_HOST,
2949 + (7<<1) | (1<<4), 1,
2950 + "WRITE(6)")) == 0)
2951 + reply = do_write(fsg);
2955 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2956 + if ((reply = check_command_size_in_blocks(fsg, 10,
2957 + DATA_DIR_FROM_HOST,
2958 + (1<<1) | (0xf<<2) | (3<<7), 1,
2959 + "WRITE(10)")) == 0)
2960 + reply = do_write(fsg);
2964 + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
2965 + if ((reply = check_command_size_in_blocks(fsg, 12,
2966 + DATA_DIR_FROM_HOST,
2967 + (1<<1) | (0xf<<2) | (0xf<<6), 1,
2968 + "WRITE(12)")) == 0)
2969 + reply = do_write(fsg);
2972 + /* Some mandatory commands that we recognize but don't implement.
2973 + * They don't mean much in this setting. It's left as an exercise
2974 + * for anyone interested to implement RESERVE and RELEASE in terms
2975 + * of Posix locks. */
2979 + case SEND_DIAGNOSTIC:
2984 + fsg->data_size_from_cmnd = 0;
2985 + sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
2986 + if ((reply = check_command(fsg, fsg->cmnd_size,
2987 + DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) {
2988 + fsg->curlun->sense_data = SS_INVALID_COMMAND;
2993 + up_read(&fsg->filesem);
2995 + if (reply == -EINTR || signal_pending(current))
2998 + /* Set up the single reply buffer for finish_reply() */
2999 + if (reply == -EINVAL)
3000 + reply = 0; // Error reply length
3001 + if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
3002 + reply = min((u32) reply, fsg->data_size_from_cmnd);
3003 + bh->inreq->length = reply;
3004 + bh->state = BUF_STATE_FULL;
3005 + fsg->residue -= reply;
3006 + } // Otherwise it's already set
3012 +/*-------------------------------------------------------------------------*/
3014 +static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
3016 + struct usb_request *req = bh->outreq;
3017 + struct bulk_cb_wrap *cbw = req->buf;
3019 + /* Was this a real packet? Should it be ignored? */
3020 + if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
3023 + /* Is the CBW valid? */
3024 + if (req->actual != US_BULK_CB_WRAP_LEN ||
3025 + cbw->Signature != cpu_to_le32(
3026 + US_BULK_CB_SIGN)) {
3027 + DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
3029 + le32_to_cpu(cbw->Signature));
3031 + /* The Bulk-only spec says we MUST stall the IN endpoint
3032 + * (6.6.1), so it's unavoidable. It also says we must
3033 + * retain this state until the next reset, but there's
3034 + * no way to tell the controller driver it should ignore
3035 + * Clear-Feature(HALT) requests.
3037 + * We aren't required to halt the OUT endpoint; instead
3038 + * we can simply accept and discard any data received
3039 + * until the next reset. */
3040 + wedge_bulk_in_endpoint(fsg);
3041 + set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
3045 + /* Is the CBW meaningful? */
3046 + if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
3047 + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
3048 + DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
3050 + cbw->Lun, cbw->Flags, cbw->Length);
3052 + /* We can do anything we want here, so let's stall the
3053 + * bulk pipes if we are allowed to. */
3054 + if (mod_data.can_stall) {
3055 + fsg_set_halt(fsg, fsg->bulk_out);
3056 + halt_bulk_in_endpoint(fsg);
3061 + /* Save the command for later */
3062 + fsg->cmnd_size = cbw->Length;
3063 + memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
3064 + if (cbw->Flags & US_BULK_FLAG_IN)
3065 + fsg->data_dir = DATA_DIR_TO_HOST;
3067 + fsg->data_dir = DATA_DIR_FROM_HOST;
3068 + fsg->data_size = le32_to_cpu(cbw->DataTransferLength);
3069 + if (fsg->data_size == 0)
3070 + fsg->data_dir = DATA_DIR_NONE;
3071 + fsg->lun = cbw->Lun;
3072 + fsg->tag = cbw->Tag;
3077 +static int get_next_command(struct fsg_dev *fsg)
3079 + struct fsg_buffhd *bh;
3082 + if (transport_is_bbb()) {
3084 + /* Wait for the next buffer to become available */
3085 + bh = fsg->next_buffhd_to_fill;
3086 + while (bh->state != BUF_STATE_EMPTY) {
3087 + rc = sleep_thread(fsg);
3092 + /* Queue a request to read a Bulk-only CBW */
3093 + set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN);
3094 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
3095 + &bh->outreq_busy, &bh->state);
3097 + /* We will drain the buffer in software, which means we
3098 + * can reuse it for the next filling. No need to advance
3099 + * next_buffhd_to_fill. */
3101 + /* Wait for the CBW to arrive */
3102 + while (bh->state != BUF_STATE_FULL) {
3103 + rc = sleep_thread(fsg);
3108 + rc = received_cbw(fsg, bh);
3109 + bh->state = BUF_STATE_EMPTY;
3111 + } else { // USB_PR_CB or USB_PR_CBI
3113 + /* Wait for the next command to arrive */
3114 + while (fsg->cbbuf_cmnd_size == 0) {
3115 + rc = sleep_thread(fsg);
3120 + /* Is the previous status interrupt request still busy?
3121 + * The host is allowed to skip reading the status,
3122 + * so we must cancel it. */
3123 + if (fsg->intreq_busy)
3124 + usb_ep_dequeue(fsg->intr_in, fsg->intreq);
3126 + /* Copy the command and mark the buffer empty */
3127 + fsg->data_dir = DATA_DIR_UNKNOWN;
3128 + spin_lock_irq(&fsg->lock);
3129 + fsg->cmnd_size = fsg->cbbuf_cmnd_size;
3130 + memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
3131 + fsg->cbbuf_cmnd_size = 0;
3132 + spin_unlock_irq(&fsg->lock);
3134 + /* Use LUN from the command */
3135 + fsg->lun = fsg->cmnd[1] >> 5;
3138 + /* Update current lun */
3139 + if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
3140 + fsg->curlun = &fsg->luns[fsg->lun];
3142 + fsg->curlun = NULL;
3148 +/*-------------------------------------------------------------------------*/
3150 +static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
3151 + const struct usb_endpoint_descriptor *d)
3155 + ep->driver_data = fsg;
3157 + rc = usb_ep_enable(ep);
3159 + ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
3163 +static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep,
3164 + struct usb_request **preq)
3166 + *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
3169 + ERROR(fsg, "can't allocate request for %s\n", ep->name);
3174 + * Reset interface setting and re-init endpoint state (toggle etc).
3175 + * Call with altsetting < 0 to disable the interface. The only other
3176 + * available altsetting is 0, which enables the interface.
3178 +static int do_set_interface(struct fsg_dev *fsg, int altsetting)
3182 + const struct usb_endpoint_descriptor *d;
3185 + DBG(fsg, "reset interface\n");
3188 + /* Deallocate the requests */
3189 + for (i = 0; i < fsg_num_buffers; ++i) {
3190 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3193 + usb_ep_free_request(fsg->bulk_in, bh->inreq);
3197 + usb_ep_free_request(fsg->bulk_out, bh->outreq);
3198 + bh->outreq = NULL;
3201 + if (fsg->intreq) {
3202 + usb_ep_free_request(fsg->intr_in, fsg->intreq);
3203 + fsg->intreq = NULL;
3206 + /* Disable the endpoints */
3207 + if (fsg->bulk_in_enabled) {
3208 + usb_ep_disable(fsg->bulk_in);
3209 + fsg->bulk_in_enabled = 0;
3211 + if (fsg->bulk_out_enabled) {
3212 + usb_ep_disable(fsg->bulk_out);
3213 + fsg->bulk_out_enabled = 0;
3215 + if (fsg->intr_in_enabled) {
3216 + usb_ep_disable(fsg->intr_in);
3217 + fsg->intr_in_enabled = 0;
3221 + if (altsetting < 0 || rc != 0)
3224 + DBG(fsg, "set interface %d\n", altsetting);
3226 + /* Enable the endpoints */
3227 + d = fsg_ep_desc(fsg->gadget,
3228 + &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
3229 + &fsg_ss_bulk_in_desc);
3230 + if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
3232 + fsg->bulk_in_enabled = 1;
3234 + d = fsg_ep_desc(fsg->gadget,
3235 + &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
3236 + &fsg_ss_bulk_out_desc);
3237 + if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
3239 + fsg->bulk_out_enabled = 1;
3240 + fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
3241 + clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
3243 + if (transport_is_cbi()) {
3244 + d = fsg_ep_desc(fsg->gadget,
3245 + &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
3246 + &fsg_ss_intr_in_desc);
3247 + if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
3249 + fsg->intr_in_enabled = 1;
3252 + /* Allocate the requests */
3253 + for (i = 0; i < fsg_num_buffers; ++i) {
3254 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3256 + if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
3258 + if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
3260 + bh->inreq->buf = bh->outreq->buf = bh->buf;
3261 + bh->inreq->context = bh->outreq->context = bh;
3262 + bh->inreq->complete = bulk_in_complete;
3263 + bh->outreq->complete = bulk_out_complete;
3265 + if (transport_is_cbi()) {
3266 + if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0)
3268 + fsg->intreq->complete = intr_in_complete;
3272 + for (i = 0; i < fsg->nluns; ++i)
3273 + fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
3279 + * Change our operational configuration. This code must agree with the code
3280 + * that returns config descriptors, and with interface altsetting code.
3282 + * It's also responsible for power management interactions. Some
3283 + * configurations might not work with our current power sources.
3284 + * For now we just assume the gadget is always self-powered.
3286 +static int do_set_config(struct fsg_dev *fsg, u8 new_config)
3290 + /* Disable the single interface */
3291 + if (fsg->config != 0) {
3292 + DBG(fsg, "reset config\n");
3294 + rc = do_set_interface(fsg, -1);
3297 + /* Enable the interface */
3298 + if (new_config != 0) {
3299 + fsg->config = new_config;
3300 + if ((rc = do_set_interface(fsg, 0)) != 0)
3301 + fsg->config = 0; // Reset on errors
3303 + INFO(fsg, "%s config #%d\n",
3304 + usb_speed_string(fsg->gadget->speed),
3311 +/*-------------------------------------------------------------------------*/
3313 +static void handle_exception(struct fsg_dev *fsg)
3319 + struct fsg_buffhd *bh;
3320 + enum fsg_state old_state;
3322 + struct fsg_lun *curlun;
3323 + unsigned int exception_req_tag;
3326 + /* Clear the existing signals. Anything but SIGUSR1 is converted
3327 + * into a high-priority EXIT exception. */
3329 + sig = dequeue_signal_lock(current, ¤t->blocked, &info);
3332 + if (sig != SIGUSR1) {
3333 + if (fsg->state < FSG_STATE_EXIT)
3334 + DBG(fsg, "Main thread exiting on signal\n");
3335 + raise_exception(fsg, FSG_STATE_EXIT);
3339 + /* Cancel all the pending transfers */
3340 + if (fsg->intreq_busy)
3341 + usb_ep_dequeue(fsg->intr_in, fsg->intreq);
3342 + for (i = 0; i < fsg_num_buffers; ++i) {
3343 + bh = &fsg->buffhds[i];
3344 + if (bh->inreq_busy)
3345 + usb_ep_dequeue(fsg->bulk_in, bh->inreq);
3346 + if (bh->outreq_busy)
3347 + usb_ep_dequeue(fsg->bulk_out, bh->outreq);
3350 + /* Wait until everything is idle */
3352 + num_active = fsg->intreq_busy;
3353 + for (i = 0; i < fsg_num_buffers; ++i) {
3354 + bh = &fsg->buffhds[i];
3355 + num_active += bh->inreq_busy + bh->outreq_busy;
3357 + if (num_active == 0)
3359 + if (sleep_thread(fsg))
3363 + /* Clear out the controller's fifos */
3364 + if (fsg->bulk_in_enabled)
3365 + usb_ep_fifo_flush(fsg->bulk_in);
3366 + if (fsg->bulk_out_enabled)
3367 + usb_ep_fifo_flush(fsg->bulk_out);
3368 + if (fsg->intr_in_enabled)
3369 + usb_ep_fifo_flush(fsg->intr_in);
3371 + /* Reset the I/O buffer states and pointers, the SCSI
3372 + * state, and the exception. Then invoke the handler. */
3373 + spin_lock_irq(&fsg->lock);
3375 + for (i = 0; i < fsg_num_buffers; ++i) {
3376 + bh = &fsg->buffhds[i];
3377 + bh->state = BUF_STATE_EMPTY;
3379 + fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain =
3382 + exception_req_tag = fsg->exception_req_tag;
3383 + new_config = fsg->new_config;
3384 + old_state = fsg->state;
3386 + if (old_state == FSG_STATE_ABORT_BULK_OUT)
3387 + fsg->state = FSG_STATE_STATUS_PHASE;
3389 + for (i = 0; i < fsg->nluns; ++i) {
3390 + curlun = &fsg->luns[i];
3391 + curlun->prevent_medium_removal = 0;
3392 + curlun->sense_data = curlun->unit_attention_data =
3394 + curlun->sense_data_info = 0;
3395 + curlun->info_valid = 0;
3397 + fsg->state = FSG_STATE_IDLE;
3399 + spin_unlock_irq(&fsg->lock);
3401 + /* Carry out any extra actions required for the exception */
3402 + switch (old_state) {
3406 + case FSG_STATE_ABORT_BULK_OUT:
3408 + spin_lock_irq(&fsg->lock);
3409 + if (fsg->state == FSG_STATE_STATUS_PHASE)
3410 + fsg->state = FSG_STATE_IDLE;
3411 + spin_unlock_irq(&fsg->lock);
3414 + case FSG_STATE_RESET:
3415 + /* In case we were forced against our will to halt a
3416 + * bulk endpoint, clear the halt now. (The SuperH UDC
3417 + * requires this.) */
3418 + if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
3419 + usb_ep_clear_halt(fsg->bulk_in);
3421 + if (transport_is_bbb()) {
3422 + if (fsg->ep0_req_tag == exception_req_tag)
3423 + ep0_queue(fsg); // Complete the status stage
3425 + } else if (transport_is_cbi())
3426 + send_status(fsg); // Status by interrupt pipe
3428 + /* Technically this should go here, but it would only be
3429 + * a waste of time. Ditto for the INTERFACE_CHANGE and
3430 + * CONFIG_CHANGE cases. */
3431 + // for (i = 0; i < fsg->nluns; ++i)
3432 + // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
3435 + case FSG_STATE_INTERFACE_CHANGE:
3436 + rc = do_set_interface(fsg, 0);
3437 + if (fsg->ep0_req_tag != exception_req_tag)
3439 + if (rc != 0) // STALL on errors
3440 + fsg_set_halt(fsg, fsg->ep0);
3441 + else // Complete the status stage
3445 + case FSG_STATE_CONFIG_CHANGE:
3446 + rc = do_set_config(fsg, new_config);
3447 + if (fsg->ep0_req_tag != exception_req_tag)
3449 + if (rc != 0) // STALL on errors
3450 + fsg_set_halt(fsg, fsg->ep0);
3451 + else // Complete the status stage
3455 + case FSG_STATE_DISCONNECT:
3456 + for (i = 0; i < fsg->nluns; ++i)
3457 + fsg_lun_fsync_sub(fsg->luns + i);
3458 + do_set_config(fsg, 0); // Unconfigured state
3461 + case FSG_STATE_EXIT:
3462 + case FSG_STATE_TERMINATED:
3463 + do_set_config(fsg, 0); // Free resources
3464 + spin_lock_irq(&fsg->lock);
3465 + fsg->state = FSG_STATE_TERMINATED; // Stop the thread
3466 + spin_unlock_irq(&fsg->lock);
3472 +/*-------------------------------------------------------------------------*/
3474 +static int fsg_main_thread(void *fsg_)
3476 + struct fsg_dev *fsg = fsg_;
3478 + /* Allow the thread to be killed by a signal, but set the signal mask
3479 + * to block everything but INT, TERM, KILL, and USR1. */
3480 + allow_signal(SIGINT);
3481 + allow_signal(SIGTERM);
3482 + allow_signal(SIGKILL);
3483 + allow_signal(SIGUSR1);
3485 + /* Allow the thread to be frozen */
3488 + /* Arrange for userspace references to be interpreted as kernel
3489 + * pointers. That way we can pass a kernel pointer to a routine
3490 + * that expects a __user pointer and it will work okay. */
3493 + /* The main loop */
3494 + while (fsg->state != FSG_STATE_TERMINATED) {
3495 + if (exception_in_progress(fsg) || signal_pending(current)) {
3496 + handle_exception(fsg);
3500 + if (!fsg->running) {
3501 + sleep_thread(fsg);
3505 + if (get_next_command(fsg))
3508 + spin_lock_irq(&fsg->lock);
3509 + if (!exception_in_progress(fsg))
3510 + fsg->state = FSG_STATE_DATA_PHASE;
3511 + spin_unlock_irq(&fsg->lock);
3513 + if (do_scsi_command(fsg) || finish_reply(fsg))
3516 + spin_lock_irq(&fsg->lock);
3517 + if (!exception_in_progress(fsg))
3518 + fsg->state = FSG_STATE_STATUS_PHASE;
3519 + spin_unlock_irq(&fsg->lock);
3521 + if (send_status(fsg))
3524 + spin_lock_irq(&fsg->lock);
3525 + if (!exception_in_progress(fsg))
3526 + fsg->state = FSG_STATE_IDLE;
3527 + spin_unlock_irq(&fsg->lock);
3530 + spin_lock_irq(&fsg->lock);
3531 + fsg->thread_task = NULL;
3532 + spin_unlock_irq(&fsg->lock);
3534 + /* If we are exiting because of a signal, unregister the
3535 + * gadget driver. */
3536 + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
3537 + usb_gadget_unregister_driver(&fsg_driver);
3539 + /* Let the unbind and cleanup routines know the thread has exited */
3540 + complete_and_exit(&fsg->thread_notifier, 0);
3544 +/*-------------------------------------------------------------------------*/
3547 +/* The write permissions and store_xxx pointers are set in fsg_bind() */
3548 +static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL);
3549 +static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL);
3550 +static DEVICE_ATTR(file, 0444, fsg_show_file, NULL);
3553 +/*-------------------------------------------------------------------------*/
3555 +static void fsg_release(struct kref *ref)
3557 + struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref);
3563 +static void lun_release(struct device *dev)
3565 + struct rw_semaphore *filesem = dev_get_drvdata(dev);
3566 + struct fsg_dev *fsg =
3567 + container_of(filesem, struct fsg_dev, filesem);
3569 + kref_put(&fsg->ref, fsg_release);
3572 +static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
3574 + struct fsg_dev *fsg = get_gadget_data(gadget);
3576 + struct fsg_lun *curlun;
3577 + struct usb_request *req = fsg->ep0req;
3579 + DBG(fsg, "unbind\n");
3580 + clear_bit(REGISTERED, &fsg->atomic_bitflags);
3582 + /* If the thread isn't already dead, tell it to exit now */
3583 + if (fsg->state != FSG_STATE_TERMINATED) {
3584 + raise_exception(fsg, FSG_STATE_EXIT);
3585 + wait_for_completion(&fsg->thread_notifier);
3587 + /* The cleanup routine waits for this completion also */
3588 + complete(&fsg->thread_notifier);
3591 + /* Unregister the sysfs attribute files and the LUNs */
3592 + for (i = 0; i < fsg->nluns; ++i) {
3593 + curlun = &fsg->luns[i];
3594 + if (curlun->registered) {
3595 + device_remove_file(&curlun->dev, &dev_attr_nofua);
3596 + device_remove_file(&curlun->dev, &dev_attr_ro);
3597 + device_remove_file(&curlun->dev, &dev_attr_file);
3598 + fsg_lun_close(curlun);
3599 + device_unregister(&curlun->dev);
3600 + curlun->registered = 0;
3604 + /* Free the data buffers */
3605 + for (i = 0; i < fsg_num_buffers; ++i)
3606 + kfree(fsg->buffhds[i].buf);
3608 + /* Free the request and buffer for endpoint 0 */
3611 + usb_ep_free_request(fsg->ep0, req);
3614 + set_gadget_data(gadget, NULL);
3618 +static int __init check_parameters(struct fsg_dev *fsg)
3623 + /* Store the default values */
3624 + mod_data.transport_type = USB_PR_BULK;
3625 + mod_data.transport_name = "Bulk-only";
3626 + mod_data.protocol_type = USB_SC_SCSI;
3627 + mod_data.protocol_name = "Transparent SCSI";
3629 + /* Some peripheral controllers are known not to be able to
3630 + * halt bulk endpoints correctly. If one of them is present,
3633 + if (gadget_is_at91(fsg->gadget))
3634 + mod_data.can_stall = 0;
3636 + if (mod_data.release == 0xffff) { // Parameter wasn't set
3637 + gcnum = usb_gadget_controller_number(fsg->gadget);
3639 + mod_data.release = 0x0300 + gcnum;
3641 + WARNING(fsg, "controller '%s' not recognized\n",
3642 + fsg->gadget->name);
3643 + mod_data.release = 0x0399;
3647 + prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
3649 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
3650 + if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) {
3651 + ; // Use default setting
3652 + } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) {
3653 + mod_data.transport_type = USB_PR_CB;
3654 + mod_data.transport_name = "Control-Bulk";
3655 + } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) {
3656 + mod_data.transport_type = USB_PR_CBI;
3657 + mod_data.transport_name = "Control-Bulk-Interrupt";
3659 + ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm);
3663 + if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 ||
3664 + prot == USB_SC_SCSI) {
3665 + ; // Use default setting
3666 + } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 ||
3667 + prot == USB_SC_RBC) {
3668 + mod_data.protocol_type = USB_SC_RBC;
3669 + mod_data.protocol_name = "RBC";
3670 + } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 ||
3671 + strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 ||
3672 + prot == USB_SC_8020) {
3673 + mod_data.protocol_type = USB_SC_8020;
3674 + mod_data.protocol_name = "8020i (ATAPI)";
3675 + } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 ||
3676 + prot == USB_SC_QIC) {
3677 + mod_data.protocol_type = USB_SC_QIC;
3678 + mod_data.protocol_name = "QIC-157";
3679 + } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 ||
3680 + prot == USB_SC_UFI) {
3681 + mod_data.protocol_type = USB_SC_UFI;
3682 + mod_data.protocol_name = "UFI";
3683 + } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 ||
3684 + prot == USB_SC_8070) {
3685 + mod_data.protocol_type = USB_SC_8070;
3686 + mod_data.protocol_name = "8070i";
3688 + ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm);
3692 + mod_data.buflen &= PAGE_CACHE_MASK;
3693 + if (mod_data.buflen <= 0) {
3694 + ERROR(fsg, "invalid buflen\n");
3695 + return -ETOOSMALL;
3698 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
3700 + /* Serial string handling.
3701 + * On a real device, the serial string would be loaded
3702 + * from permanent storage. */
3703 + if (mod_data.serial) {
3708 + * The CB[I] specification limits the serial string to
3709 + * 12 uppercase hexadecimal characters.
3710 + * BBB need at least 12 uppercase hexadecimal characters,
3711 + * with a maximum of 126. */
3712 + for (ch = mod_data.serial; *ch; ++ch) {
3714 + if ((*ch < '0' || *ch > '9') &&
3715 + (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
3717 + "Invalid serial string character: %c\n",
3723 + (mod_data.transport_type == USB_PR_BULK && len < 12) ||
3724 + (mod_data.transport_type != USB_PR_BULK && len > 12)) {
3725 + WARNING(fsg, "Invalid serial string length!\n");
3728 + fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial;
3730 + WARNING(fsg, "No serial-number string provided!\n");
3732 + device_desc.iSerialNumber = 0;
3739 +static int __init fsg_bind(struct usb_gadget *gadget)
3741 + struct fsg_dev *fsg = the_fsg;
3744 + struct fsg_lun *curlun;
3745 + struct usb_ep *ep;
3746 + struct usb_request *req;
3747 + char *pathbuf, *p;
3749 + fsg->gadget = gadget;
3750 + set_gadget_data(gadget, fsg);
3751 + fsg->ep0 = gadget->ep0;
3752 + fsg->ep0->driver_data = fsg;
3754 + if ((rc = check_parameters(fsg)) != 0)
3757 + if (mod_data.removable) { // Enable the store_xxx attributes
3758 + dev_attr_file.attr.mode = 0644;
3759 + dev_attr_file.store = fsg_store_file;
3760 + if (!mod_data.cdrom) {
3761 + dev_attr_ro.attr.mode = 0644;
3762 + dev_attr_ro.store = fsg_store_ro;
3766 + /* Only for removable media? */
3767 + dev_attr_nofua.attr.mode = 0644;
3768 + dev_attr_nofua.store = fsg_store_nofua;
3770 + /* Find out how many LUNs there should be */
3771 + i = mod_data.nluns;
3773 + i = max(mod_data.num_filenames, 1u);
3774 + if (i > FSG_MAX_LUNS) {
3775 + ERROR(fsg, "invalid number of LUNs: %d\n", i);
3780 + /* Create the LUNs, open their backing files, and register the
3781 + * LUN devices in sysfs. */
3782 + fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL);
3789 + for (i = 0; i < fsg->nluns; ++i) {
3790 + curlun = &fsg->luns[i];
3791 + curlun->cdrom = !!mod_data.cdrom;
3792 + curlun->ro = mod_data.cdrom || mod_data.ro[i];
3793 + curlun->initially_ro = curlun->ro;
3794 + curlun->removable = mod_data.removable;
3795 + curlun->nofua = mod_data.nofua[i];
3796 + curlun->dev.release = lun_release;
3797 + curlun->dev.parent = &gadget->dev;
3798 + curlun->dev.driver = &fsg_driver.driver;
3799 + dev_set_drvdata(&curlun->dev, &fsg->filesem);
3800 + dev_set_name(&curlun->dev,"%s-lun%d",
3801 + dev_name(&gadget->dev), i);
3803 + kref_get(&fsg->ref);
3804 + rc = device_register(&curlun->dev);
3806 + INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
3807 + put_device(&curlun->dev);
3810 + curlun->registered = 1;
3812 + rc = device_create_file(&curlun->dev, &dev_attr_ro);
3815 + rc = device_create_file(&curlun->dev, &dev_attr_nofua);
3818 + rc = device_create_file(&curlun->dev, &dev_attr_file);
3822 + if (mod_data.file[i] && *mod_data.file[i]) {
3823 + rc = fsg_lun_open(curlun, mod_data.file[i]);
3826 + } else if (!mod_data.removable) {
3827 + ERROR(fsg, "no file given for LUN%d\n", i);
3833 + /* Find all the endpoints we will use */
3834 + usb_ep_autoconfig_reset(gadget);
3835 + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
3837 + goto autoconf_fail;
3838 + ep->driver_data = fsg; // claim the endpoint
3839 + fsg->bulk_in = ep;
3841 + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
3843 + goto autoconf_fail;
3844 + ep->driver_data = fsg; // claim the endpoint
3845 + fsg->bulk_out = ep;
3847 + if (transport_is_cbi()) {
3848 + ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc);
3850 + goto autoconf_fail;
3851 + ep->driver_data = fsg; // claim the endpoint
3852 + fsg->intr_in = ep;
3855 + /* Fix up the descriptors */
3856 + device_desc.idVendor = cpu_to_le16(mod_data.vendor);
3857 + device_desc.idProduct = cpu_to_le16(mod_data.product);
3858 + device_desc.bcdDevice = cpu_to_le16(mod_data.release);
3860 + i = (transport_is_cbi() ? 3 : 2); // Number of endpoints
3861 + fsg_intf_desc.bNumEndpoints = i;
3862 + fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type;
3863 + fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type;
3864 + fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3866 + if (gadget_is_dualspeed(gadget)) {
3867 + fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3869 + /* Assume endpoint addresses are the same for both speeds */
3870 + fsg_hs_bulk_in_desc.bEndpointAddress =
3871 + fsg_fs_bulk_in_desc.bEndpointAddress;
3872 + fsg_hs_bulk_out_desc.bEndpointAddress =
3873 + fsg_fs_bulk_out_desc.bEndpointAddress;
3874 + fsg_hs_intr_in_desc.bEndpointAddress =
3875 + fsg_fs_intr_in_desc.bEndpointAddress;
3878 + if (gadget_is_superspeed(gadget)) {
3879 + unsigned max_burst;
3881 + fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3883 + /* Calculate bMaxBurst, we know packet size is 1024 */
3884 + max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
3886 + /* Assume endpoint addresses are the same for both speeds */
3887 + fsg_ss_bulk_in_desc.bEndpointAddress =
3888 + fsg_fs_bulk_in_desc.bEndpointAddress;
3889 + fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
3891 + fsg_ss_bulk_out_desc.bEndpointAddress =
3892 + fsg_fs_bulk_out_desc.bEndpointAddress;
3893 + fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
3896 + if (gadget_is_otg(gadget))
3897 + fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
3901 + /* Allocate the request and buffer for endpoint 0 */
3902 + fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
3905 + req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
3908 + req->complete = ep0_complete;
3910 + /* Allocate the data buffers */
3911 + for (i = 0; i < fsg_num_buffers; ++i) {
3912 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3914 + /* Allocate for the bulk-in endpoint. We assume that
3915 + * the buffer will also work with the bulk-out (and
3916 + * interrupt-in) endpoint. */
3917 + bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
3920 + bh->next = bh + 1;
3922 + fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0];
3924 + /* This should reflect the actual gadget power source */
3925 + usb_gadget_set_selfpowered(gadget);
3927 + snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer,
3929 + init_utsname()->sysname, init_utsname()->release,
3932 + fsg->thread_task = kthread_create(fsg_main_thread, fsg,
3933 + "file-storage-gadget");
3934 + if (IS_ERR(fsg->thread_task)) {
3935 + rc = PTR_ERR(fsg->thread_task);
3939 + INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
3940 + INFO(fsg, "NOTE: This driver is deprecated. "
3941 + "Consider using g_mass_storage instead.\n");
3942 + INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
3944 + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
3945 + for (i = 0; i < fsg->nluns; ++i) {
3946 + curlun = &fsg->luns[i];
3947 + if (fsg_lun_is_open(curlun)) {
3950 + p = d_path(&curlun->filp->f_path,
3951 + pathbuf, PATH_MAX);
3955 + LINFO(curlun, "ro=%d, nofua=%d, file: %s\n",
3956 + curlun->ro, curlun->nofua, (p ? p : "(error)"));
3961 + DBG(fsg, "transport=%s (x%02x)\n",
3962 + mod_data.transport_name, mod_data.transport_type);
3963 + DBG(fsg, "protocol=%s (x%02x)\n",
3964 + mod_data.protocol_name, mod_data.protocol_type);
3965 + DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
3966 + mod_data.vendor, mod_data.product, mod_data.release);
3967 + DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n",
3968 + mod_data.removable, mod_data.can_stall,
3969 + mod_data.cdrom, mod_data.buflen);
3970 + DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
3972 + set_bit(REGISTERED, &fsg->atomic_bitflags);
3974 + /* Tell the thread to start working */
3975 + wake_up_process(fsg->thread_task);
3979 + ERROR(fsg, "unable to autoconfigure all endpoints\n");
3983 + fsg->state = FSG_STATE_TERMINATED; // The thread is dead
3984 + fsg_unbind(gadget);
3985 + complete(&fsg->thread_notifier);
3990 +/*-------------------------------------------------------------------------*/
3992 +static void fsg_suspend(struct usb_gadget *gadget)
3994 + struct fsg_dev *fsg = get_gadget_data(gadget);
3996 + DBG(fsg, "suspend\n");
3997 + set_bit(SUSPENDED, &fsg->atomic_bitflags);
4000 +static void fsg_resume(struct usb_gadget *gadget)
4002 + struct fsg_dev *fsg = get_gadget_data(gadget);
4004 + DBG(fsg, "resume\n");
4005 + clear_bit(SUSPENDED, &fsg->atomic_bitflags);
4009 +/*-------------------------------------------------------------------------*/
4011 +static struct usb_gadget_driver fsg_driver = {
4012 + .max_speed = USB_SPEED_SUPER,
4013 + .function = (char *) fsg_string_product,
4014 + .unbind = fsg_unbind,
4015 + .disconnect = fsg_disconnect,
4016 + .setup = fsg_setup,
4017 + .suspend = fsg_suspend,
4018 + .resume = fsg_resume,
4021 + .name = DRIVER_NAME,
4022 + .owner = THIS_MODULE,
4030 +static int __init fsg_alloc(void)
4032 + struct fsg_dev *fsg;
4034 + fsg = kzalloc(sizeof *fsg +
4035 + fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL);
4039 + spin_lock_init(&fsg->lock);
4040 + init_rwsem(&fsg->filesem);
4041 + kref_init(&fsg->ref);
4042 + init_completion(&fsg->thread_notifier);
4049 +static int __init fsg_init(void)
4052 + struct fsg_dev *fsg;
4054 + rc = fsg_num_buffers_validate();
4058 + if ((rc = fsg_alloc()) != 0)
4061 + if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
4062 + kref_put(&fsg->ref, fsg_release);
4065 +module_init(fsg_init);
4068 +static void __exit fsg_cleanup(void)
4070 + struct fsg_dev *fsg = the_fsg;
4072 + /* Unregister the driver iff the thread hasn't already done so */
4073 + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
4074 + usb_gadget_unregister_driver(&fsg_driver);
4076 + /* Wait for the thread to finish up */
4077 + wait_for_completion(&fsg->thread_notifier);
4079 + kref_put(&fsg->ref, fsg_release);
4081 +module_exit(fsg_cleanup);
4082 --- a/drivers/usb/host/Kconfig
4083 +++ b/drivers/usb/host/Kconfig
4084 @@ -751,6 +751,19 @@ config USB_HWA_HCD
4085 To compile this driver a module, choose M here: the module
4086 will be called "hwa-hc".
4089 + tristate "Synopsis DWC host support"
4092 + The Synopsis DWC controller is a dual-role
4093 + host/peripheral/OTG ("On The Go") USB controllers.
4095 + Enable this option to support this IP in host controller mode.
4098 + To compile this driver as a module, choose M here: the
4099 + modules built will be called dwc_otg and dwc_common_port.
4101 config USB_IMX21_HCD
4102 tristate "i.MX21 HCD support"
4103 depends on ARM && ARCH_MXC
4104 --- a/drivers/usb/host/Makefile
4105 +++ b/drivers/usb/host/Makefile
4106 @@ -71,6 +71,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
4107 obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
4108 obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
4109 obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
4111 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/
4112 obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
4113 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
4114 obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
4116 +++ b/drivers/usb/host/dwc_common_port/Makefile
4119 +# Makefile for DWC_common library
4122 +ifneq ($(KERNELRELEASE),)
4124 +ccflags-y += -DDWC_LINUX
4125 +#ccflags-y += -DDEBUG
4126 +#ccflags-y += -DDWC_DEBUG_REGS
4127 +#ccflags-y += -DDWC_DEBUG_MEMORY
4129 +ccflags-y += -DDWC_LIBMODULE
4130 +ccflags-y += -DDWC_CCLIB
4131 +#ccflags-y += -DDWC_CRYPTOLIB
4132 +ccflags-y += -DDWC_NOTIFYLIB
4133 +ccflags-y += -DDWC_UTFLIB
4135 +obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o
4136 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
4137 + dwc_crypto.o dwc_notifier.o \
4138 + dwc_common_linux.o dwc_mem.o
4140 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
4141 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
4143 +ifneq ($(kernrel3),2.6.20)
4144 +# grayg - I only know that we use ccflags-y in 2.6.31 actually
4145 +ccflags-y += $(CPPFLAGS)
4151 +#$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
4155 +$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
4156 + cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
4164 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
4166 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
4167 + $(DOXYGEN) doc/doxygen.cfg
4169 +tags: $(wildcard *.[hc])
4170 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
4175 + rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
4177 +++ b/drivers/usb/host/dwc_common_port/Makefile.fbsd
4179 +CFLAGS += -I/sys/i386/compile/GENERIC -I/sys/i386/include -I/usr/include
4180 +CFLAGS += -DDWC_FREEBSD
4182 +#CFLAGS += -DDWC_DEBUG_REGS
4183 +#CFLAGS += -DDWC_DEBUG_MEMORY
4185 +#CFLAGS += -DDWC_LIBMODULE
4186 +#CFLAGS += -DDWC_CCLIB
4187 +#CFLAGS += -DDWC_CRYPTOLIB
4188 +#CFLAGS += -DDWC_NOTIFYLIB
4189 +#CFLAGS += -DDWC_UTFLIB
4191 +KMOD = dwc_common_port_lib
4192 +SRCS = dwc_cc.c dwc_modpow.c dwc_dh.c dwc_crypto.c dwc_notifier.c \
4193 + dwc_common_fbsd.c dwc_mem.c
4195 +.include <bsd.kmod.mk>
4197 +++ b/drivers/usb/host/dwc_common_port/Makefile.linux
4200 +# Makefile for DWC_common library
4202 +ifneq ($(KERNELRELEASE),)
4204 +ccflags-y += -DDWC_LINUX
4205 +#ccflags-y += -DDEBUG
4206 +#ccflags-y += -DDWC_DEBUG_REGS
4207 +#ccflags-y += -DDWC_DEBUG_MEMORY
4209 +ccflags-y += -DDWC_LIBMODULE
4210 +ccflags-y += -DDWC_CCLIB
4211 +ccflags-y += -DDWC_CRYPTOLIB
4212 +ccflags-y += -DDWC_NOTIFYLIB
4213 +ccflags-y += -DDWC_UTFLIB
4215 +obj-m := dwc_common_port_lib.o
4216 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
4217 + dwc_crypto.o dwc_notifier.o \
4218 + dwc_common_linux.o dwc_mem.o
4223 +$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
4227 +$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
4228 + cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
4236 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
4238 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
4239 + $(DOXYGEN) doc/doxygen.cfg
4241 +tags: $(wildcard *.[hc])
4242 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
4247 + rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
4249 +++ b/drivers/usb/host/dwc_common_port/changes.txt
4252 +dwc_read_reg32() and friends now take an additional parameter, a pointer to an
4253 +IO context struct. The IO context struct should live in an os-dependent struct
4254 +in your driver. As an example, the dwc_usb3 driver has an os-dependent struct
4255 +named 'os_dep' embedded in the main device struct. So there these calls look
4258 + dwc_read_reg32(&usb3_dev->os_dep.ioctx, &pcd->dev_global_regs->dcfg);
4260 + dwc_write_reg32(&usb3_dev->os_dep.ioctx,
4261 + &pcd->dev_global_regs->dcfg, 0);
4263 +Note that for the existing Linux driver ports, it is not necessary to actually
4264 +define the 'ioctx' member in the os-dependent struct. Since Linux does not
4265 +require an IO context, its macros for dwc_read_reg32() and friends do not
4266 +use the context pointer, so it is optimized away by the compiler. But it is
4267 +necessary to add the pointer parameter to all of the call sites, to be ready
4268 +for any future ports (such as FreeBSD) which do require an IO context.
4271 +Similarly, dwc_alloc(), dwc_alloc_atomic(), dwc_strdup(), and dwc_free() now
4272 +take an additional parameter, a pointer to a memory context. Examples:
4274 + addr = dwc_alloc(&usb3_dev->os_dep.memctx, size);
4276 + dwc_free(&usb3_dev->os_dep.memctx, addr);
4278 +Again, for the Linux ports, it is not necessary to actually define the memctx
4279 +member, but it is necessary to add the pointer parameter to all of the call
4283 +Same for dwc_dma_alloc() and dwc_dma_free(). Examples:
4285 + virt_addr = dwc_dma_alloc(&usb3_dev->os_dep.dmactx, size, &phys_addr);
4287 + dwc_dma_free(&usb3_dev->os_dep.dmactx, size, virt_addr, phys_addr);
4290 +Same for dwc_mutex_alloc() and dwc_mutex_free(). Examples:
4292 + mutex = dwc_mutex_alloc(&usb3_dev->os_dep.mtxctx);
4294 + dwc_mutex_free(&usb3_dev->os_dep.mtxctx, mutex);
4297 +Same for dwc_spinlock_alloc() and dwc_spinlock_free(). Examples:
4299 + lock = dwc_spinlock_alloc(&usb3_dev->osdep.splctx);
4301 + dwc_spinlock_free(&usb3_dev->osdep.splctx, lock);
4304 +Same for dwc_timer_alloc(). Example:
4306 + timer = dwc_timer_alloc(&usb3_dev->os_dep.tmrctx, "dwc_usb3_tmr1",
4307 + cb_func, cb_data);
4310 +Same for dwc_waitq_alloc(). Example:
4312 + waitq = dwc_waitq_alloc(&usb3_dev->os_dep.wtqctx);
4315 +Same for dwc_thread_run(). Example:
4317 + thread = dwc_thread_run(&usb3_dev->os_dep.thdctx, func,
4318 + "dwc_usb3_thd1", data);
4321 +Same for dwc_workq_alloc(). Example:
4323 + workq = dwc_workq_alloc(&usb3_dev->osdep.wkqctx, "dwc_usb3_wkq1");
4326 +Same for dwc_task_alloc(). Example:
4328 + task = dwc_task_alloc(&usb3_dev->os_dep.tskctx, "dwc_usb3_tsk1",
4329 + cb_func, cb_data);
4332 +In addition to the context pointer additions, a few core functions have had
4333 +other changes made to their parameters:
4335 +The 'flags' parameter to dwc_spinlock_irqsave() and dwc_spinunlock_irqrestore()
4336 +has been changed from a uint64_t to a dwc_irqflags_t.
4338 +dwc_thread_should_stop() now takes a 'dwc_thread_t *' parameter, because the
4339 +FreeBSD equivalent of that function requires it.
4341 +And, in addition to the context pointer, dwc_task_alloc() also adds a
4342 +'char *name' parameter, to be consistent with dwc_thread_run() and
4343 +dwc_workq_alloc(), and because the FreeBSD equivalent of that function
4344 +requires a unique name.
4347 +Here is a complete list of the core functions that now take a pointer to a
4348 +context as their first parameter:
4364 + dwc_spinlock_alloc
4370 + dwc_task_alloc Also adds a 'char *name' as its 2nd parameter
4372 +And here are the core functions that have other changes to their parameters:
4374 + dwc_spinlock_irqsave 'flags' param is now a 'dwc_irqflags_t *'
4375 + dwc_spinunlock_irqrestore 'flags' param is now a 'dwc_irqflags_t'
4376 + dwc_thread_should_stop Adds a 'dwc_thread_t *' parameter
4380 +The changes to the core functions also require some of the other library
4381 +functions to change:
4383 + dwc_cc_if_alloc() and dwc_cc_if_free() now take a 'void *memctx'
4384 + (for memory allocation) as the 1st param and a 'void *mtxctx'
4385 + (for mutex allocation) as the 2nd param.
4387 + dwc_cc_clear(), dwc_cc_add(), dwc_cc_change(), dwc_cc_remove(),
4388 + dwc_cc_data_for_save(), and dwc_cc_restore_from_data() now take a
4389 + 'void *memctx' as the 1st param.
4391 + dwc_dh_modpow(), dwc_dh_pk(), and dwc_dh_derive_keys() now take a
4392 + 'void *memctx' as the 1st param.
4394 + dwc_modpow() now takes a 'void *memctx' as the 1st param.
4396 + dwc_alloc_notification_manager() now takes a 'void *memctx' as the
4397 + 1st param and a 'void *wkqctx' (for work queue allocation) as the 2nd
4398 + param, and also now returns an integer value that is non-zero if
4399 + allocation of its data structures or work queue fails.
4401 + dwc_register_notifier() now takes a 'void *memctx' as the 1st param.
4403 + dwc_memory_debug_start() now takes a 'void *mem_ctx' as the first
4404 + param, and also now returns an integer value that is non-zero if
4405 + allocation of its data structures fails.
4409 +Other miscellaneous changes:
4411 +The DEBUG_MEMORY and DEBUG_REGS #define's have been renamed to
4412 +DWC_DEBUG_MEMORY and DWC_DEBUG_REGS.
4414 +The following #define's have been added to allow selectively compiling library
4422 +A DWC_LIBMODULE #define has also been added. If this is not defined, then the
4423 +module code in dwc_common_linux.c is not compiled in. This allows linking the
4424 +library code directly into a driver module, instead of as a standalone module.
4426 +++ b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
4430 +#---------------------------------------------------------------------------
4431 +# Project related configuration options
4432 +#---------------------------------------------------------------------------
4433 +PROJECT_NAME = "Synopsys DWC Portability and Common Library for UWB"
4435 +OUTPUT_DIRECTORY = doc
4436 +CREATE_SUBDIRS = NO
4437 +OUTPUT_LANGUAGE = English
4438 +BRIEF_MEMBER_DESC = YES
4440 +ABBREVIATE_BRIEF = "The $name class" \
4441 + "The $name widget" \
4442 + "The $name file" \
4451 +ALWAYS_DETAILED_SEC = YES
4452 +INLINE_INHERITED_MEMB = NO
4453 +FULL_PATH_NAMES = NO
4454 +STRIP_FROM_PATH = ..
4455 +STRIP_FROM_INC_PATH =
4457 +JAVADOC_AUTOBRIEF = YES
4458 +MULTILINE_CPP_IS_BRIEF = NO
4459 +DETAILS_AT_TOP = YES
4461 +SEPARATE_MEMBER_PAGES = NO
4464 +OPTIMIZE_OUTPUT_FOR_C = YES
4465 +OPTIMIZE_OUTPUT_JAVA = NO
4466 +BUILTIN_STL_SUPPORT = NO
4467 +DISTRIBUTE_GROUP_DOC = NO
4469 +#---------------------------------------------------------------------------
4470 +# Build related configuration options
4471 +#---------------------------------------------------------------------------
4473 +EXTRACT_PRIVATE = NO
4474 +EXTRACT_STATIC = YES
4475 +EXTRACT_LOCAL_CLASSES = NO
4476 +EXTRACT_LOCAL_METHODS = NO
4477 +HIDE_UNDOC_MEMBERS = NO
4478 +HIDE_UNDOC_CLASSES = NO
4479 +HIDE_FRIEND_COMPOUNDS = NO
4480 +HIDE_IN_BODY_DOCS = NO
4482 +CASE_SENSE_NAMES = YES
4483 +HIDE_SCOPE_NAMES = NO
4484 +SHOW_INCLUDE_FILES = NO
4486 +SORT_MEMBER_DOCS = NO
4487 +SORT_BRIEF_DOCS = NO
4488 +SORT_BY_SCOPE_NAME = NO
4489 +GENERATE_TODOLIST = YES
4490 +GENERATE_TESTLIST = YES
4491 +GENERATE_BUGLIST = YES
4492 +GENERATE_DEPRECATEDLIST= YES
4494 +MAX_INITIALIZER_LINES = 30
4495 +SHOW_USED_FILES = YES
4496 +SHOW_DIRECTORIES = YES
4497 +FILE_VERSION_FILTER =
4498 +#---------------------------------------------------------------------------
4499 +# configuration options related to warning and progress messages
4500 +#---------------------------------------------------------------------------
4503 +WARN_IF_UNDOCUMENTED = NO
4504 +WARN_IF_DOC_ERROR = YES
4505 +WARN_NO_PARAMDOC = YES
4506 +WARN_FORMAT = "$file:$line: $text"
4508 +#---------------------------------------------------------------------------
4509 +# configuration options related to the input files
4510 +#---------------------------------------------------------------------------
4512 +FILE_PATTERNS = *.c \
4555 +EXCLUDE_SYMLINKS = NO
4558 +EXAMPLE_PATTERNS = *
4559 +EXAMPLE_RECURSIVE = NO
4563 +FILTER_SOURCE_FILES = NO
4564 +#---------------------------------------------------------------------------
4565 +# configuration options related to source browsing
4566 +#---------------------------------------------------------------------------
4567 +SOURCE_BROWSER = NO
4568 +INLINE_SOURCES = NO
4569 +STRIP_CODE_COMMENTS = YES
4570 +REFERENCED_BY_RELATION = YES
4571 +REFERENCES_RELATION = YES
4573 +VERBATIM_HEADERS = NO
4574 +#---------------------------------------------------------------------------
4575 +# configuration options related to the alphabetical class index
4576 +#---------------------------------------------------------------------------
4577 +ALPHABETICAL_INDEX = NO
4578 +COLS_IN_ALPHA_INDEX = 5
4580 +#---------------------------------------------------------------------------
4581 +# configuration options related to the HTML output
4582 +#---------------------------------------------------------------------------
4583 +GENERATE_HTML = YES
4585 +HTML_FILE_EXTENSION = .html
4589 +HTML_ALIGN_MEMBERS = YES
4590 +GENERATE_HTMLHELP = NO
4597 +ENUM_VALUES_PER_LINE = 4
4598 +GENERATE_TREEVIEW = YES
4599 +TREEVIEW_WIDTH = 250
4600 +#---------------------------------------------------------------------------
4601 +# configuration options related to the LaTeX output
4602 +#---------------------------------------------------------------------------
4603 +GENERATE_LATEX = NO
4604 +LATEX_OUTPUT = latex
4605 +LATEX_CMD_NAME = latex
4606 +MAKEINDEX_CMD_NAME = makeindex
4608 +PAPER_TYPE = a4wide
4611 +PDF_HYPERLINKS = NO
4613 +LATEX_BATCHMODE = NO
4614 +LATEX_HIDE_INDICES = NO
4615 +#---------------------------------------------------------------------------
4616 +# configuration options related to the RTF output
4617 +#---------------------------------------------------------------------------
4621 +RTF_HYPERLINKS = NO
4622 +RTF_STYLESHEET_FILE =
4623 +RTF_EXTENSIONS_FILE =
4624 +#---------------------------------------------------------------------------
4625 +# configuration options related to the man page output
4626 +#---------------------------------------------------------------------------
4631 +#---------------------------------------------------------------------------
4632 +# configuration options related to the XML output
4633 +#---------------------------------------------------------------------------
4638 +XML_PROGRAMLISTING = YES
4639 +#---------------------------------------------------------------------------
4640 +# configuration options for the AutoGen Definitions output
4641 +#---------------------------------------------------------------------------
4642 +GENERATE_AUTOGEN_DEF = NO
4643 +#---------------------------------------------------------------------------
4644 +# configuration options related to the Perl module output
4645 +#---------------------------------------------------------------------------
4646 +GENERATE_PERLMOD = NO
4648 +PERLMOD_PRETTY = YES
4649 +PERLMOD_MAKEVAR_PREFIX =
4650 +#---------------------------------------------------------------------------
4651 +# Configuration options related to the preprocessor
4652 +#---------------------------------------------------------------------------
4653 +ENABLE_PREPROCESSING = YES
4654 +MACRO_EXPANSION = NO
4655 +EXPAND_ONLY_PREDEF = NO
4656 +SEARCH_INCLUDES = YES
4658 +INCLUDE_FILE_PATTERNS =
4659 +PREDEFINED = DEBUG DEBUG_MEMORY
4660 +EXPAND_AS_DEFINED =
4661 +SKIP_FUNCTION_MACROS = YES
4662 +#---------------------------------------------------------------------------
4663 +# Configuration::additions related to external references
4664 +#---------------------------------------------------------------------------
4668 +EXTERNAL_GROUPS = YES
4669 +PERL_PATH = /usr/bin/perl
4670 +#---------------------------------------------------------------------------
4671 +# Configuration options related to the dot tool
4672 +#---------------------------------------------------------------------------
4673 +CLASS_DIAGRAMS = YES
4674 +HIDE_UNDOC_RELATIONS = YES
4677 +COLLABORATION_GRAPH = YES
4680 +TEMPLATE_RELATIONS = NO
4682 +INCLUDED_BY_GRAPH = YES
4684 +GRAPHICAL_HIERARCHY = YES
4685 +DIRECTORY_GRAPH = YES
4686 +DOT_IMAGE_FORMAT = png
4689 +MAX_DOT_GRAPH_DEPTH = 1000
4690 +DOT_TRANSPARENT = NO
4691 +DOT_MULTI_TARGETS = NO
4692 +GENERATE_LEGEND = YES
4694 +#---------------------------------------------------------------------------
4695 +# Configuration::additions related to the search engine
4696 +#---------------------------------------------------------------------------
4699 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.c
4701 +/* =========================================================================
4702 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
4704 + * $Date: 2010/11/04 $
4705 + * $Change: 1621692 $
4707 + * Synopsys Portability Library Software and documentation
4708 + * (hereinafter, "Software") is an Unsupported proprietary work of
4709 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
4710 + * between Synopsys and you.
4712 + * The Software IS NOT an item of Licensed Software or Licensed Product
4713 + * under any End User Software License Agreement or Agreement for
4714 + * Licensed Product with Synopsys or any supplement thereto. You are
4715 + * permitted to use and redistribute this Software in source and binary
4716 + * forms, with or without modification, provided that redistributions
4717 + * of source code must retain this notice. You may not view, use,
4718 + * disclose, copy or distribute this file or any information contained
4719 + * herein except pursuant to this license grant from Synopsys. If you
4720 + * do not agree with this notice, including the disclaimer below, then
4721 + * you are not authorized to use the Software.
4723 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
4724 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4725 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
4726 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
4727 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
4728 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
4729 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
4730 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
4731 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4732 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
4733 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
4735 + * ========================================================================= */
4738 +#include "dwc_cc.h"
4740 +typedef struct dwc_cc
4748 + DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
4751 +DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
4753 +/** The main structure for CC management. */
4756 + dwc_mutex_t *mutex;
4759 + unsigned is_host:1;
4761 + dwc_notifier_t *notifier;
4763 + struct context_list list;
4767 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
4770 + DWC_PRINTF("%s: ", name);
4771 + for (i=0; i<len; i++) {
4772 + DWC_PRINTF("%02x ", bytes[i]);
4777 +#define dump_bytes(x...)
4780 +static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
4782 + dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
4786 + DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
4789 + cc->length = length;
4790 + cc->name = dwc_alloc(mem_ctx, length);
4792 + dwc_free(mem_ctx, cc);
4796 + DWC_MEMCPY(cc->name, name, length);
4802 +static void free_cc(void *mem_ctx, dwc_cc_t *cc)
4805 + dwc_free(mem_ctx, cc->name);
4807 + dwc_free(mem_ctx, cc);
4810 +static uint32_t next_uid(dwc_cc_if_t *cc_if)
4814 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4815 + if (cc->uid > uid) {
4827 +static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
4830 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4831 + if (cc->uid == uid) {
4838 +static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
4840 + unsigned int size = 0;
4842 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4845 + size += cc->length;
4851 +static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
4856 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4857 + if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
4864 +static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
4869 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4870 + if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
4878 +/* Internal cc_add */
4879 +static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
4880 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
4885 + if (cc_if->is_host) {
4886 + uid = cc_match_cdid(cc_if, cdid);
4889 + uid = cc_match_chid(cc_if, chid);
4893 + DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
4894 + cc = cc_find(cc_if, uid);
4897 + cc = alloc_cc(mem_ctx, name, length);
4898 + cc->uid = next_uid(cc_if);
4899 + DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
4902 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
4903 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
4904 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
4906 + DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
4907 + dump_bytes("CHID", cc->chid, 16);
4908 + dump_bytes("CDID", cc->cdid, 16);
4909 + dump_bytes("CK", cc->ck, 16);
4913 +/* Internal cc_clear */
4914 +static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
4916 + while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
4917 + dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
4918 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
4919 + free_cc(mem_ctx, cc);
4923 +dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
4924 + dwc_notifier_t *notifier, unsigned is_host)
4926 + dwc_cc_if_t *cc_if = NULL;
4928 + /* Allocate a common_cc_if structure */
4929 + cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
4934 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
4935 + DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
4937 + cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
4939 + if (!cc_if->mutex) {
4940 + dwc_free(mem_ctx, cc_if);
4944 + DWC_CIRCLEQ_INIT(&cc_if->list);
4945 + cc_if->is_host = is_host;
4946 + cc_if->notifier = notifier;
4950 +void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
4952 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
4953 + DWC_MUTEX_FREE(cc_if->mutex);
4955 + dwc_mutex_free(mtx_ctx, cc_if->mutex);
4957 + cc_clear(mem_ctx, cc_if);
4958 + dwc_free(mem_ctx, cc_if);
4961 +static void cc_changed(dwc_cc_if_t *cc_if)
4963 + if (cc_if->notifier) {
4964 + dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
4968 +void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
4970 + DWC_MUTEX_LOCK(cc_if->mutex);
4971 + cc_clear(mem_ctx, cc_if);
4972 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4973 + cc_changed(cc_if);
4976 +int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
4977 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
4981 + DWC_MUTEX_LOCK(cc_if->mutex);
4982 + uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
4983 + DWC_MUTEX_UNLOCK(cc_if->mutex);
4984 + cc_changed(cc_if);
4989 +void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
4990 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
4994 + DWC_DEBUGC("Change connection context %d", id);
4996 + DWC_MUTEX_LOCK(cc_if->mutex);
4997 + cc = cc_find(cc_if, id);
4999 + DWC_ERROR("Uid %d not found in cc list\n", id);
5000 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5005 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
5008 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
5011 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
5016 + dwc_free(mem_ctx, cc->name);
5018 + cc->name = dwc_alloc(mem_ctx, length);
5020 + DWC_ERROR("Out of memory in dwc_cc_change()\n");
5021 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5024 + cc->length = length;
5025 + DWC_MEMCPY(cc->name, name, length);
5028 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5030 + cc_changed(cc_if);
5032 + DWC_DEBUGC("Changed connection context id=%d\n", id);
5033 + dump_bytes("New CHID", cc->chid, 16);
5034 + dump_bytes("New CDID", cc->cdid, 16);
5035 + dump_bytes("New CK", cc->ck, 16);
5038 +void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
5042 + DWC_DEBUGC("Removing connection context %d", id);
5044 + DWC_MUTEX_LOCK(cc_if->mutex);
5045 + cc = cc_find(cc_if, id);
5047 + DWC_ERROR("Uid %d not found in cc list\n", id);
5048 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5052 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
5053 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5054 + free_cc(mem_ctx, cc);
5056 + cc_changed(cc_if);
5059 +uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
5065 + DWC_MUTEX_LOCK(cc_if->mutex);
5066 + *length = cc_data_size(cc_if);
5068 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5072 + DWC_DEBUGC("Creating data for saving (length=%d)", *length);
5074 + buf = dwc_alloc(mem_ctx, *length);
5077 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5082 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
5083 + DWC_MEMCPY(x, cc->chid, 16);
5085 + DWC_MEMCPY(x, cc->cdid, 16);
5087 + DWC_MEMCPY(x, cc->ck, 16);
5090 + DWC_MEMCPY(x, &cc->length, 1);
5092 + DWC_MEMCPY(x, cc->name, cc->length);
5096 + DWC_MEMCPY(x, &zero, 1);
5100 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5105 +void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
5107 + uint8_t name_length;
5114 + DWC_MUTEX_LOCK(cc_if->mutex);
5115 + cc_clear(mem_ctx, cc_if);
5117 + while (i < length) {
5125 + name_length = data[i];
5128 + if (name_length) {
5136 + /* check to see if we haven't overflown the buffer */
5138 + DWC_ERROR("Data format error while attempting to load CCs "
5139 + "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
5143 + cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
5145 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5147 + cc_changed(cc_if);
5150 +uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
5154 + DWC_MUTEX_LOCK(cc_if->mutex);
5155 + uid = cc_match_chid(cc_if, chid);
5156 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5159 +uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
5163 + DWC_MUTEX_LOCK(cc_if->mutex);
5164 + uid = cc_match_cdid(cc_if, cdid);
5165 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5169 +uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
5171 + uint8_t *ck = NULL;
5174 + DWC_MUTEX_LOCK(cc_if->mutex);
5175 + cc = cc_find(cc_if, id);
5179 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5185 +uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
5187 + uint8_t *retval = NULL;
5190 + DWC_MUTEX_LOCK(cc_if->mutex);
5191 + cc = cc_find(cc_if, id);
5193 + retval = cc->chid;
5195 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5200 +uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
5202 + uint8_t *retval = NULL;
5205 + DWC_MUTEX_LOCK(cc_if->mutex);
5206 + cc = cc_find(cc_if, id);
5208 + retval = cc->cdid;
5210 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5215 +uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
5217 + uint8_t *retval = NULL;
5220 + DWC_MUTEX_LOCK(cc_if->mutex);
5222 + cc = cc_find(cc_if, id);
5224 + *length = cc->length;
5225 + retval = cc->name;
5227 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5232 +#endif /* DWC_CCLIB */
5234 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.h
5236 +/* =========================================================================
5237 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $
5239 + * $Date: 2010/09/28 $
5240 + * $Change: 1596182 $
5242 + * Synopsys Portability Library Software and documentation
5243 + * (hereinafter, "Software") is an Unsupported proprietary work of
5244 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
5245 + * between Synopsys and you.
5247 + * The Software IS NOT an item of Licensed Software or Licensed Product
5248 + * under any End User Software License Agreement or Agreement for
5249 + * Licensed Product with Synopsys or any supplement thereto. You are
5250 + * permitted to use and redistribute this Software in source and binary
5251 + * forms, with or without modification, provided that redistributions
5252 + * of source code must retain this notice. You may not view, use,
5253 + * disclose, copy or distribute this file or any information contained
5254 + * herein except pursuant to this license grant from Synopsys. If you
5255 + * do not agree with this notice, including the disclaimer below, then
5256 + * you are not authorized to use the Software.
5258 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
5259 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5260 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
5261 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
5262 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
5263 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
5264 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
5265 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
5266 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5267 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
5268 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
5270 + * ========================================================================= */
5280 + * This file defines the Context Context library.
5282 + * The main data structure is dwc_cc_if_t which is returned by either the
5283 + * dwc_cc_if_alloc function or returned by the module to the user via a provided
5284 + * function. The data structure is opaque and should only be manipulated via the
5285 + * functions provied in this API.
5287 + * It manages a list of connection contexts and operations can be performed to
5288 + * add, remove, query, search, and change, those contexts. Additionally,
5289 + * a dwc_notifier_t object can be requested from the manager so that
5290 + * the user can be notified whenever the context list has changed.
5293 +#include "dwc_os.h"
5294 +#include "dwc_list.h"
5295 +#include "dwc_notifier.h"
5298 +/* Notifications */
5299 +#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
5302 +typedef struct dwc_cc_if dwc_cc_if_t;
5305 +/** @name Connection Context Operations */
5308 +/** This function allocates memory for a dwc_cc_if_t structure, initializes
5309 + * fields to default values, and returns a pointer to the structure or NULL on
5311 +extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
5312 + dwc_notifier_t *notifier, unsigned is_host);
5314 +/** Frees the memory for the specified CC structure allocated from
5315 + * dwc_cc_if_alloc(). */
5316 +extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if);
5318 +/** Removes all contexts from the connection context list */
5319 +extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if);
5321 +/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
5322 + * If a CHID already exists, the CK and name are overwritten. Statistics are
5323 + * not overwritten.
5325 + * @param cc_if The cc_if structure.
5326 + * @param chid A pointer to the 16-byte CHID. This value will be copied.
5327 + * @param ck A pointer to the 16-byte CK. This value will be copied.
5328 + * @param cdid A pointer to the 16-byte CDID. This value will be copied.
5329 + * @param name An optional host friendly name as defined in the association model
5330 + * spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name.
5331 + * @param length The length othe unicode string.
5332 + * @return A unique identifier used to refer to this context that is valid for
5333 + * as long as this context is still in the list. */
5334 +extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
5335 + uint8_t *cdid, uint8_t *ck, uint8_t *name,
5338 +/** Changes the CHID, CK, CDID, or Name values of a connection context in the
5339 + * list, preserving any accumulated statistics. This would typically be called
5340 + * if the host decideds to change the context with a SET_CONNECTION request.
5342 + * @param cc_if The cc_if structure.
5343 + * @param id The identifier of the connection context.
5344 + * @param chid A pointer to the 16-byte CHID. This value will be copied. NULL
5345 + * indicates no change.
5346 + * @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL
5347 + * indicates no change.
5348 + * @param ck A pointer to the 16-byte CK. This value will be copied. NULL
5349 + * indicates no change.
5350 + * @param name Host friendly name UTF16-LE. NULL indicates no change.
5351 + * @param length Length of name. */
5352 +extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id,
5353 + uint8_t *chid, uint8_t *cdid, uint8_t *ck,
5354 + uint8_t *name, uint8_t length);
5356 +/** Remove the specified connection context.
5357 + * @param cc_if The cc_if structure.
5358 + * @param id The identifier of the connection context to remove. */
5359 +extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id);
5361 +/** Get a binary block of data for the connection context list and attributes.
5362 + * This data can be used by the OS specific driver to save the connection
5363 + * context list into non-volatile memory.
5365 + * @param cc_if The cc_if structure.
5366 + * @param length Return the length of the data buffer.
5367 + * @return A pointer to the data buffer. The memory for this buffer should be
5368 + * freed with DWC_FREE() after use. */
5369 +extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if,
5370 + unsigned int *length);
5372 +/** Restore the connection context list from the binary data that was previously
5373 + * returned from a call to dwc_cc_data_for_save. This can be used by the OS specific
5374 + * driver to load a connection context list from non-volatile memory.
5376 + * @param cc_if The cc_if structure.
5377 + * @param data The data bytes as returned from dwc_cc_data_for_save.
5378 + * @param length The length of the data. */
5379 +extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if,
5380 + uint8_t *data, unsigned int length);
5382 +/** Find the connection context from the specified CHID.
5384 + * @param cc_if The cc_if structure.
5385 + * @param chid A pointer to the CHID data.
5386 + * @return A non-zero identifier of the connection context if the CHID matches.
5387 + * Otherwise returns 0. */
5388 +extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
5390 +/** Find the connection context from the specified CDID.
5392 + * @param cc_if The cc_if structure.
5393 + * @param cdid A pointer to the CDID data.
5394 + * @return A non-zero identifier of the connection context if the CHID matches.
5395 + * Otherwise returns 0. */
5396 +extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
5398 +/** Retrieve the CK from the specified connection context.
5400 + * @param cc_if The cc_if structure.
5401 + * @param id The identifier of the connection context.
5402 + * @return A pointer to the CK data. The memory does not need to be freed. */
5403 +extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
5405 +/** Retrieve the CHID from the specified connection context.
5407 + * @param cc_if The cc_if structure.
5408 + * @param id The identifier of the connection context.
5409 + * @return A pointer to the CHID data. The memory does not need to be freed. */
5410 +extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
5412 +/** Retrieve the CDID from the specified connection context.
5414 + * @param cc_if The cc_if structure.
5415 + * @param id The identifier of the connection context.
5416 + * @return A pointer to the CDID data. The memory does not need to be freed. */
5417 +extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
5419 +extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
5421 +/** Checks a buffer for non-zero.
5422 + * @param id A pointer to a 16 byte buffer.
5423 + * @return true if the 16 byte value is non-zero. */
5424 +static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
5426 + for (i=0; i<16; i++) {
5427 + if (id[i]) return 1;
5432 +/** Checks a buffer for zero.
5433 + * @param id A pointer to a 16 byte buffer.
5434 + * @return true if the 16 byte value is zero. */
5435 +static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
5436 + return !dwc_assoc_is_not_zero_id(id);
5439 +/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
5441 +static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
5442 + char *ptr = buffer;
5444 + for (i=0; i<16; i++) {
5445 + ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
5447 + ptr += DWC_SPRINTF(ptr, " ");
5450 + return ptr - buffer;
5459 +#endif /* _DWC_CC_H_ */
5461 +++ b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
5463 +#include "dwc_os.h"
5464 +#include "dwc_list.h"
5467 +# include "dwc_cc.h"
5470 +#ifdef DWC_CRYPTOLIB
5471 +# include "dwc_modpow.h"
5472 +# include "dwc_dh.h"
5473 +# include "dwc_crypto.h"
5476 +#ifdef DWC_NOTIFYLIB
5477 +# include "dwc_notifier.h"
5480 +/* OS-Level Implementations */
5482 +/* This is the FreeBSD 7.0 kernel implementation of the DWC platform library. */
5487 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
5489 + return memset(dest, byte, size);
5492 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
5494 + return memcpy(dest, src, size);
5497 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
5499 + bcopy(src, dest, size);
5503 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
5505 + return memcmp(m1, m2, size);
5508 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
5510 + return strncmp(s1, s2, size);
5513 +int DWC_STRCMP(void *s1, void *s2)
5515 + return strcmp(s1, s2);
5518 +int DWC_STRLEN(char const *str)
5520 + return strlen(str);
5523 +char *DWC_STRCPY(char *to, char const *from)
5525 + return strcpy(to, from);
5528 +char *DWC_STRDUP(char const *str)
5530 + int len = DWC_STRLEN(str) + 1;
5531 + char *new = DWC_ALLOC_ATOMIC(len);
5537 + DWC_MEMCPY(new, str, len);
5541 +int DWC_ATOI(char *str, int32_t *value)
5545 + *value = strtol(str, &end, 0);
5546 + if (*end == '\0') {
5553 +int DWC_ATOUI(char *str, uint32_t *value)
5557 + *value = strtoul(str, &end, 0);
5558 + if (*end == '\0') {
5567 +/* From usbstring.c */
5569 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
5575 + /* this insists on correct encodings, though not minimal ones.
5576 + * BUT it currently rejects legit 4-byte UTF-8 code points,
5577 + * which need surrogate pairs. (Unicode 3.1 can use them.)
5579 + while (len != 0 && (c = (u8) *s++) != 0) {
5580 + if (unlikely(c & 0x80)) {
5581 + // 2-byte sequence:
5582 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
5583 + if ((c & 0xe0) == 0xc0) {
5584 + uchar = (c & 0x1f) << 6;
5587 + if ((c & 0xc0) != 0xc0)
5592 + // 3-byte sequence (most CJKV characters):
5593 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
5594 + } else if ((c & 0xf0) == 0xe0) {
5595 + uchar = (c & 0x0f) << 12;
5598 + if ((c & 0xc0) != 0xc0)
5604 + if ((c & 0xc0) != 0xc0)
5609 + /* no bogus surrogates */
5610 + if (0xd800 <= uchar && uchar <= 0xdfff)
5613 + // 4-byte sequence (surrogate pairs, currently rare):
5614 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
5615 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
5616 + // (uuuuu = wwww + 1)
5617 + // FIXME accept the surrogate code points (only)
5622 + put_unaligned (cpu_to_le16 (uchar), cp++);
5631 +#endif /* DWC_UTFLIB */
5636 +dwc_bool_t DWC_IN_IRQ(void)
5638 +// return in_irq();
5642 +dwc_bool_t DWC_IN_BH(void)
5644 +// return in_softirq();
5648 +void DWC_VPRINTF(char *format, va_list args)
5650 + vprintf(format, args);
5653 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
5655 + return vsnprintf(str, size, format, args);
5658 +void DWC_PRINTF(char *format, ...)
5662 + va_start(args, format);
5663 + DWC_VPRINTF(format, args);
5667 +int DWC_SPRINTF(char *buffer, char *format, ...)
5672 + va_start(args, format);
5673 + retval = vsprintf(buffer, format, args);
5678 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
5683 + va_start(args, format);
5684 + retval = vsnprintf(buffer, size, format, args);
5689 +void __DWC_WARN(char *format, ...)
5693 + va_start(args, format);
5694 + DWC_VPRINTF(format, args);
5698 +void __DWC_ERROR(char *format, ...)
5702 + va_start(args, format);
5703 + DWC_VPRINTF(format, args);
5707 +void DWC_EXCEPTION(char *format, ...)
5711 + va_start(args, format);
5712 + DWC_VPRINTF(format, args);
5718 +void __DWC_DEBUG(char *format, ...)
5722 + va_start(args, format);
5723 + DWC_VPRINTF(format, args);
5732 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
5736 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
5737 + size, align, alloc);
5738 + return (dwc_pool_t *)pool;
5741 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
5743 + dma_pool_destroy((struct dma_pool *)pool);
5746 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
5748 +// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
5749 + return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
5752 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
5754 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
5758 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
5760 + dma_pool_free(pool, vaddr, daddr);
5764 +static void dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
5768 + *(bus_addr_t *)arg = segs[0].ds_addr;
5771 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
5773 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
5776 + error = bus_dma_tag_create(
5777 +#if __FreeBSD_version >= 700000
5778 + bus_get_dma_tag(dma->dev), /* parent */
5780 + NULL, /* parent */
5782 + 4, 0, /* alignment, bounds */
5783 + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
5784 + BUS_SPACE_MAXADDR, /* highaddr */
5785 + NULL, NULL, /* filter, filterarg */
5786 + size, /* maxsize */
5787 + 1, /* nsegments */
5788 + size, /* maxsegsize */
5790 + NULL, /* lockfunc */
5791 + NULL, /* lockarg */
5794 + device_printf(dma->dev, "%s: bus_dma_tag_create failed: %d\n",
5799 + error = bus_dmamem_alloc(dma->dma_tag, &dma->dma_vaddr,
5800 + BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map);
5802 + device_printf(dma->dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n",
5803 + __func__, (uintmax_t)size, error);
5807 + dma->dma_paddr = 0;
5808 + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size,
5809 + dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT);
5810 + if (error || dma->dma_paddr == 0) {
5811 + device_printf(dma->dev, "%s: bus_dmamap_load failed: %d\n",
5816 + *dma_addr = dma->dma_paddr;
5817 + return dma->dma_vaddr;
5820 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
5822 + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
5823 + bus_dma_tag_destroy(dma->dma_tag);
5825 + dma->dma_map = NULL;
5826 + dma->dma_tag = NULL;
5831 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
5833 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
5835 + if (dma->dma_tag == NULL)
5837 + if (dma->dma_map != NULL) {
5838 + bus_dmamap_sync(dma->dma_tag, dma->dma_map,
5839 + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
5840 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
5841 + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
5842 + dma->dma_map = NULL;
5845 + bus_dma_tag_destroy(dma->dma_tag);
5846 + dma->dma_tag = NULL;
5849 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
5851 + return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
5854 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
5856 + return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
5859 +void __DWC_FREE(void *mem_ctx, void *addr)
5861 + free(addr, M_DEVBUF);
5865 +#ifdef DWC_CRYPTOLIB
5868 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
5870 + get_random_bytes(buffer, length);
5873 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
5875 + struct crypto_blkcipher *tfm;
5876 + struct blkcipher_desc desc;
5877 + struct scatterlist sgd;
5878 + struct scatterlist sgs;
5880 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
5881 + if (tfm == NULL) {
5882 + printk("failed to load transform for aes CBC\n");
5886 + crypto_blkcipher_setkey(tfm, key, keylen);
5887 + crypto_blkcipher_set_iv(tfm, iv, 16);
5889 + sg_init_one(&sgd, out, messagelen);
5890 + sg_init_one(&sgs, message, messagelen);
5895 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
5896 + crypto_free_blkcipher(tfm);
5897 + DWC_ERROR("AES CBC encryption failed");
5901 + crypto_free_blkcipher(tfm);
5905 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
5907 + struct crypto_hash *tfm;
5908 + struct hash_desc desc;
5909 + struct scatterlist sg;
5911 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
5912 + if (IS_ERR(tfm)) {
5913 + DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
5919 + sg_init_one(&sg, message, len);
5920 + crypto_hash_digest(&desc, &sg, len, out);
5921 + crypto_free_hash(tfm);
5926 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
5927 + uint8_t *key, uint32_t keylen, uint8_t *out)
5929 + struct crypto_hash *tfm;
5930 + struct hash_desc desc;
5931 + struct scatterlist sg;
5933 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
5934 + if (IS_ERR(tfm)) {
5935 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
5941 + sg_init_one(&sg, message, messagelen);
5942 + crypto_hash_setkey(tfm, key, keylen);
5943 + crypto_hash_digest(&desc, &sg, messagelen, out);
5944 + crypto_free_hash(tfm);
5949 +#endif /* DWC_CRYPTOLIB */
5952 +/* Byte Ordering Conversions */
5954 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
5956 +#ifdef __LITTLE_ENDIAN
5959 + uint8_t *u_p = (uint8_t *)p;
5961 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
5965 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
5967 +#ifdef __BIG_ENDIAN
5970 + uint8_t *u_p = (uint8_t *)p;
5972 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
5976 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
5978 +#ifdef __LITTLE_ENDIAN
5981 + uint8_t *u_p = (uint8_t *)p;
5983 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
5987 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
5989 +#ifdef __BIG_ENDIAN
5992 + uint8_t *u_p = (uint8_t *)p;
5994 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
5998 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
6000 +#ifdef __LITTLE_ENDIAN
6003 + uint8_t *u_p = (uint8_t *)p;
6004 + return (u_p[1] | (u_p[0] << 8));
6008 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
6010 +#ifdef __BIG_ENDIAN
6013 + uint8_t *u_p = (uint8_t *)p;
6014 + return (u_p[1] | (u_p[0] << 8));
6018 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
6020 +#ifdef __LITTLE_ENDIAN
6023 + uint8_t *u_p = (uint8_t *)p;
6024 + return (u_p[1] | (u_p[0] << 8));
6028 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
6030 +#ifdef __BIG_ENDIAN
6033 + uint8_t *u_p = (uint8_t *)p;
6034 + return (u_p[1] | (u_p[0] << 8));
6041 +uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
6043 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6044 + bus_size_t ior = (bus_size_t)reg;
6046 + return bus_space_read_4(io->iot, io->ioh, ior);
6050 +uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
6052 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6053 + bus_size_t ior = (bus_size_t)reg;
6055 + return bus_space_read_8(io->iot, io->ioh, ior);
6059 +void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
6061 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6062 + bus_size_t ior = (bus_size_t)reg;
6064 + bus_space_write_4(io->iot, io->ioh, ior, value);
6068 +void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
6070 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6071 + bus_size_t ior = (bus_size_t)reg;
6073 + bus_space_write_8(io->iot, io->ioh, ior, value);
6077 +void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
6078 + uint32_t set_mask)
6080 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6081 + bus_size_t ior = (bus_size_t)reg;
6083 + bus_space_write_4(io->iot, io->ioh, ior,
6084 + (bus_space_read_4(io->iot, io->ioh, ior) &
6085 + ~clear_mask) | set_mask);
6089 +void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
6090 + uint64_t set_mask)
6092 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6093 + bus_size_t ior = (bus_size_t)reg;
6095 + bus_space_write_8(io->iot, io->ioh, ior,
6096 + (bus_space_read_8(io->iot, io->ioh, ior) &
6097 + ~clear_mask) | set_mask);
6104 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
6106 + struct mtx *sl = DWC_ALLOC(sizeof(*sl));
6109 + DWC_ERROR("Cannot allocate memory for spinlock");
6113 + mtx_init(sl, "dw3spn", NULL, MTX_SPIN);
6114 + return (dwc_spinlock_t *)sl;
6117 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
6119 + struct mtx *sl = (struct mtx *)lock;
6125 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
6127 + mtx_lock_spin((struct mtx *)lock); // ???
6130 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
6132 + mtx_unlock_spin((struct mtx *)lock); // ???
6135 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
6137 + mtx_lock_spin((struct mtx *)lock);
6140 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
6142 + mtx_unlock_spin((struct mtx *)lock);
6145 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
6148 + dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mtx));
6151 + DWC_ERROR("Cannot allocate memory for mutex");
6155 + m = (struct mtx *)mutex;
6156 + mtx_init(m, "dw3mtx", NULL, MTX_DEF);
6160 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
6162 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
6164 + mtx_destroy((struct mtx *)mutex);
6169 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
6171 + struct mtx *m = (struct mtx *)mutex;
6176 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
6178 + struct mtx *m = (struct mtx *)mutex;
6180 + return mtx_trylock(m);
6183 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
6185 + struct mtx *m = (struct mtx *)mutex;
6193 +void DWC_UDELAY(uint32_t usecs)
6198 +void DWC_MDELAY(uint32_t msecs)
6202 + } while (--msecs);
6205 +void DWC_MSLEEP(uint32_t msecs)
6207 + struct timeval tv;
6209 + tv.tv_sec = msecs / 1000;
6210 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
6211 + pause("dw3slp", tvtohz(&tv));
6214 +uint32_t DWC_TIME(void)
6216 + struct timeval tv;
6218 + microuptime(&tv); // or getmicrouptime? (less precise, but faster)
6219 + return tv.tv_sec * 1000 + tv.tv_usec / 1000;
6228 + dwc_spinlock_t *lock;
6229 + dwc_timer_callback_t cb;
6233 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
6235 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
6238 + DWC_ERROR("Cannot allocate memory for timer");
6242 + callout_init(&t->t, 1);
6244 + t->name = DWC_STRDUP(name);
6246 + DWC_ERROR("Cannot allocate memory for timer->name");
6250 + t->lock = DWC_SPINLOCK_ALLOC();
6252 + DWC_ERROR("Cannot allocate memory for lock");
6262 + DWC_FREE(t->name);
6269 +void DWC_TIMER_FREE(dwc_timer_t *timer)
6271 + callout_stop(&timer->t);
6272 + DWC_SPINLOCK_FREE(timer->lock);
6273 + DWC_FREE(timer->name);
6277 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
6279 + struct timeval tv;
6281 + tv.tv_sec = time / 1000;
6282 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
6283 + callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
6286 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
6288 + callout_stop(&timer->t);
6299 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
6301 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
6304 + DWC_ERROR("Cannot allocate memory for waitqueue");
6308 + mtx_init(&wq->lock, "dw3wtq", NULL, MTX_DEF);
6314 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
6316 + mtx_destroy(&wq->lock);
6320 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
6325 + mtx_lock(&wq->lock);
6328 + /* Skip the sleep if already aborted or triggered */
6329 + if (!wq->abort && !cond(data)) {
6331 + result = msleep(wq, &wq->lock, PCATCH, "dw3wat", 0); // infinite timeout
6335 + if (result == ERESTART) { // signaled - restart
6336 + result = -DWC_E_RESTART;
6338 + } else if (result == EINTR) { // signaled - interrupt
6339 + result = -DWC_E_ABORT;
6341 + } else if (wq->abort) {
6342 + result = -DWC_E_ABORT;
6350 + mtx_unlock(&wq->lock);
6354 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
6355 + void *data, int32_t msecs)
6357 + struct timeval tv, tv1, tv2;
6361 + tv.tv_sec = msecs / 1000;
6362 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
6364 + mtx_lock(&wq->lock);
6367 + /* Skip the sleep if already aborted or triggered */
6368 + if (!wq->abort && !cond(data)) {
6370 + getmicrouptime(&tv1);
6371 + result = msleep(wq, &wq->lock, PCATCH, "dw3wto", tvtohz(&tv));
6372 + getmicrouptime(&tv2);
6376 + if (result == 0) { // awoken
6378 + result = -DWC_E_ABORT;
6380 + tv2.tv_usec -= tv1.tv_usec;
6381 + if (tv2.tv_usec < 0) {
6382 + tv2.tv_usec += 1000000;
6386 + tv2.tv_sec -= tv1.tv_sec;
6387 + result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
6388 + result = msecs - result;
6392 + } else if (result == ERESTART) { // signaled - restart
6393 + result = -DWC_E_RESTART;
6395 + } else if (result == EINTR) { // signaled - interrupt
6396 + result = -DWC_E_ABORT;
6398 + } else { // timed out
6399 + result = -DWC_E_TIMEOUT;
6404 + mtx_unlock(&wq->lock);
6408 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
6413 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
6417 + mtx_lock(&wq->lock);
6422 + mtx_unlock(&wq->lock);
6428 +struct dwc_thread {
6429 + struct proc *proc;
6433 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
6436 + dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
6442 + thread->abort = 0;
6443 + retval = kthread_create((void (*)(void *))func, data, &thread->proc,
6444 + RFPROC | RFNOWAIT, 0, "%s", name);
6453 +int DWC_THREAD_STOP(dwc_thread_t *thread)
6457 + thread->abort = 1;
6458 + retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
6460 + if (retval == 0) {
6461 + /* DWC_THREAD_EXIT() will free the thread struct */
6465 + /* NOTE: We leak the thread struct if thread doesn't die */
6467 + if (retval == EWOULDBLOCK) {
6468 + return -DWC_E_TIMEOUT;
6471 + return -DWC_E_UNKNOWN;
6474 +dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
6476 + return thread->abort;
6479 +void DWC_THREAD_EXIT(dwc_thread_t *thread)
6481 + wakeup(&thread->abort);
6488 + - Runs in interrupt context (cannot sleep)
6489 + - Each tasklet runs on a single CPU [ How can we ensure this on FreeBSD? Does it matter? ]
6490 + - Different tasklets can be running simultaneously on different CPUs [ shouldn't matter ]
6492 +struct dwc_tasklet {
6494 + dwc_tasklet_callback_t cb;
6498 +static void tasklet_callback(void *data, int pending) // what to do with pending ???
6500 + dwc_tasklet_t *task = (dwc_tasklet_t *)data;
6502 + task->cb(task->data);
6505 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
6507 + dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
6511 + task->data = data;
6512 + TASK_INIT(&task->t, 0, tasklet_callback, task);
6514 + DWC_ERROR("Cannot allocate memory for tasklet");
6520 +void DWC_TASK_FREE(dwc_tasklet_t *task)
6522 + taskqueue_drain(taskqueue_fast, &task->t); // ???
6526 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
6528 + /* Uses predefined system queue */
6529 + taskqueue_enqueue_fast(taskqueue_fast, &task->t);
6534 + - Runs in process context (can sleep)
6536 +typedef struct work_container {
6537 + dwc_work_callback_t cb;
6544 + DWC_CIRCLEQ_ENTRY(work_container) entry;
6547 +} work_container_t;
6550 +DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
6554 + struct taskqueue *taskq;
6555 + dwc_spinlock_t *lock;
6556 + dwc_waitq_t *waitq;
6560 + struct work_container_queue entries;
6564 +static void do_work(void *data, int pending) // what to do with pending ???
6566 + work_container_t *container = (work_container_t *)data;
6567 + dwc_workq_t *wq = container->wq;
6568 + dwc_irqflags_t flags;
6570 + if (container->hz) {
6571 + pause("dw3wrk", container->hz);
6574 + container->cb(container->data);
6575 + DWC_DEBUG("Work done: %s, container=%p", container->name, container);
6577 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6580 + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
6582 + if (container->name)
6583 + DWC_FREE(container->name);
6584 + DWC_FREE(container);
6586 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6587 + DWC_WAITQ_TRIGGER(wq->waitq);
6590 +static int work_done(void *data)
6592 + dwc_workq_t *workq = (dwc_workq_t *)data;
6594 + return workq->pending == 0;
6597 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
6599 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
6602 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
6604 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
6607 + DWC_ERROR("Cannot allocate memory for workqueue");
6611 + wq->taskq = taskqueue_create(name, M_NOWAIT, taskqueue_thread_enqueue, &wq->taskq);
6613 + DWC_ERROR("Cannot allocate memory for taskqueue");
6619 + wq->lock = DWC_SPINLOCK_ALLOC();
6621 + DWC_ERROR("Cannot allocate memory for spinlock");
6625 + wq->waitq = DWC_WAITQ_ALLOC();
6627 + DWC_ERROR("Cannot allocate memory for waitqueue");
6631 + taskqueue_start_threads(&wq->taskq, 1, PWAIT, "%s taskq", "dw3tsk");
6634 + DWC_CIRCLEQ_INIT(&wq->entries);
6639 + DWC_SPINLOCK_FREE(wq->lock);
6641 + taskqueue_free(wq->taskq);
6648 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
6651 + dwc_irqflags_t flags;
6653 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6655 + if (wq->pending != 0) {
6656 + struct work_container *container;
6658 + DWC_ERROR("Destroying work queue with pending work");
6660 + DWC_CIRCLEQ_FOREACH(container, &wq->entries, entry) {
6661 + DWC_ERROR("Work %s still pending", container->name);
6665 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6667 + DWC_WAITQ_FREE(wq->waitq);
6668 + DWC_SPINLOCK_FREE(wq->lock);
6669 + taskqueue_free(wq->taskq);
6673 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
6674 + char *format, ...)
6676 + dwc_irqflags_t flags;
6677 + work_container_t *container;
6678 + static char name[128];
6681 + va_start(args, format);
6682 + DWC_VSNPRINTF(name, 128, format, args);
6685 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6687 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6688 + DWC_WAITQ_TRIGGER(wq->waitq);
6690 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
6692 + DWC_ERROR("Cannot allocate memory for container");
6696 + container->name = DWC_STRDUP(name);
6697 + if (!container->name) {
6698 + DWC_ERROR("Cannot allocate memory for container->name");
6699 + DWC_FREE(container);
6703 + container->cb = cb;
6704 + container->data = data;
6705 + container->wq = wq;
6706 + container->hz = 0;
6708 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
6710 + TASK_INIT(&container->task, 0, do_work, container);
6713 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
6715 + taskqueue_enqueue_fast(wq->taskq, &container->task);
6718 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
6719 + void *data, uint32_t time, char *format, ...)
6721 + dwc_irqflags_t flags;
6722 + work_container_t *container;
6723 + static char name[128];
6724 + struct timeval tv;
6727 + va_start(args, format);
6728 + DWC_VSNPRINTF(name, 128, format, args);
6731 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6733 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6734 + DWC_WAITQ_TRIGGER(wq->waitq);
6736 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
6738 + DWC_ERROR("Cannot allocate memory for container");
6742 + container->name = DWC_STRDUP(name);
6743 + if (!container->name) {
6744 + DWC_ERROR("Cannot allocate memory for container->name");
6745 + DWC_FREE(container);
6749 + container->cb = cb;
6750 + container->data = data;
6751 + container->wq = wq;
6753 + tv.tv_sec = time / 1000;
6754 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
6755 + container->hz = tvtohz(&tv);
6757 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
6759 + TASK_INIT(&container->task, 0, do_work, container);
6762 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
6764 + taskqueue_enqueue_fast(wq->taskq, &container->task);
6767 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
6769 + return wq->pending;
6772 +++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
6774 +#include <linux/kernel.h>
6775 +#include <linux/init.h>
6776 +#include <linux/module.h>
6777 +#include <linux/kthread.h>
6780 +# include "dwc_cc.h"
6783 +#ifdef DWC_CRYPTOLIB
6784 +# include "dwc_modpow.h"
6785 +# include "dwc_dh.h"
6786 +# include "dwc_crypto.h"
6789 +#ifdef DWC_NOTIFYLIB
6790 +# include "dwc_notifier.h"
6793 +/* OS-Level Implementations */
6795 +/* This is the Linux kernel implementation of the DWC platform library. */
6796 +#include <linux/moduleparam.h>
6797 +#include <linux/ctype.h>
6798 +#include <linux/crypto.h>
6799 +#include <linux/delay.h>
6800 +#include <linux/device.h>
6801 +#include <linux/dma-mapping.h>
6802 +#include <linux/cdev.h>
6803 +#include <linux/errno.h>
6804 +#include <linux/interrupt.h>
6805 +#include <linux/jiffies.h>
6806 +#include <linux/list.h>
6807 +#include <linux/pci.h>
6808 +#include <linux/random.h>
6809 +#include <linux/scatterlist.h>
6810 +#include <linux/slab.h>
6811 +#include <linux/stat.h>
6812 +#include <linux/string.h>
6813 +#include <linux/timer.h>
6814 +#include <linux/usb.h>
6816 +#include <linux/version.h>
6818 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
6819 +# include <linux/usb/gadget.h>
6821 +# include <linux/usb_gadget.h>
6824 +#include <asm/io.h>
6825 +#include <asm/page.h>
6826 +#include <asm/uaccess.h>
6827 +#include <asm/unaligned.h>
6829 +#include "dwc_os.h"
6830 +#include "dwc_list.h"
6835 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
6837 + return memset(dest, byte, size);
6840 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
6842 + return memcpy(dest, src, size);
6845 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
6847 + return memmove(dest, src, size);
6850 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
6852 + return memcmp(m1, m2, size);
6855 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
6857 + return strncmp(s1, s2, size);
6860 +int DWC_STRCMP(void *s1, void *s2)
6862 + return strcmp(s1, s2);
6865 +int DWC_STRLEN(char const *str)
6867 + return strlen(str);
6870 +char *DWC_STRCPY(char *to, char const *from)
6872 + return strcpy(to, from);
6875 +char *DWC_STRDUP(char const *str)
6877 + int len = DWC_STRLEN(str) + 1;
6878 + char *new = DWC_ALLOC_ATOMIC(len);
6884 + DWC_MEMCPY(new, str, len);
6888 +int DWC_ATOI(const char *str, int32_t *value)
6892 + *value = simple_strtol(str, &end, 0);
6893 + if (*end == '\0') {
6900 +int DWC_ATOUI(const char *str, uint32_t *value)
6904 + *value = simple_strtoul(str, &end, 0);
6905 + if (*end == '\0') {
6914 +/* From usbstring.c */
6916 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
6922 + /* this insists on correct encodings, though not minimal ones.
6923 + * BUT it currently rejects legit 4-byte UTF-8 code points,
6924 + * which need surrogate pairs. (Unicode 3.1 can use them.)
6926 + while (len != 0 && (c = (u8) *s++) != 0) {
6927 + if (unlikely(c & 0x80)) {
6928 + // 2-byte sequence:
6929 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
6930 + if ((c & 0xe0) == 0xc0) {
6931 + uchar = (c & 0x1f) << 6;
6934 + if ((c & 0xc0) != 0xc0)
6939 + // 3-byte sequence (most CJKV characters):
6940 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
6941 + } else if ((c & 0xf0) == 0xe0) {
6942 + uchar = (c & 0x0f) << 12;
6945 + if ((c & 0xc0) != 0xc0)
6951 + if ((c & 0xc0) != 0xc0)
6956 + /* no bogus surrogates */
6957 + if (0xd800 <= uchar && uchar <= 0xdfff)
6960 + // 4-byte sequence (surrogate pairs, currently rare):
6961 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
6962 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
6963 + // (uuuuu = wwww + 1)
6964 + // FIXME accept the surrogate code points (only)
6969 + put_unaligned (cpu_to_le16 (uchar), cp++);
6977 +#endif /* DWC_UTFLIB */
6982 +dwc_bool_t DWC_IN_IRQ(void)
6987 +dwc_bool_t DWC_IN_BH(void)
6989 + return in_softirq();
6992 +void DWC_VPRINTF(char *format, va_list args)
6994 + vprintk(format, args);
6997 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
6999 + return vsnprintf(str, size, format, args);
7002 +void DWC_PRINTF(char *format, ...)
7006 + va_start(args, format);
7007 + DWC_VPRINTF(format, args);
7011 +int DWC_SPRINTF(char *buffer, char *format, ...)
7016 + va_start(args, format);
7017 + retval = vsprintf(buffer, format, args);
7022 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
7027 + va_start(args, format);
7028 + retval = vsnprintf(buffer, size, format, args);
7033 +void __DWC_WARN(char *format, ...)
7037 + va_start(args, format);
7038 + DWC_PRINTF(KERN_WARNING);
7039 + DWC_VPRINTF(format, args);
7043 +void __DWC_ERROR(char *format, ...)
7047 + va_start(args, format);
7048 + DWC_PRINTF(KERN_ERR);
7049 + DWC_VPRINTF(format, args);
7053 +void DWC_EXCEPTION(char *format, ...)
7057 + va_start(args, format);
7058 + DWC_PRINTF(KERN_ERR);
7059 + DWC_VPRINTF(format, args);
7065 +void __DWC_DEBUG(char *format, ...)
7069 + va_start(args, format);
7070 + DWC_PRINTF(KERN_DEBUG);
7071 + DWC_VPRINTF(format, args);
7080 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
7084 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
7085 + size, align, alloc);
7086 + return (dwc_pool_t *)pool;
7089 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
7091 + dma_pool_destroy((struct dma_pool *)pool);
7094 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
7096 + return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
7099 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
7101 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
7105 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
7107 + dma_pool_free(pool, vaddr, daddr);
7111 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
7113 +#ifdef xxCOSIM /* Only works for 32-bit cosim */
7114 + void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL);
7116 + void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL | GFP_DMA32);
7122 + memset(buf, 0, (size_t)size);
7126 +void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
7128 + void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC);
7132 + memset(buf, 0, (size_t)size);
7136 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
7138 + dma_free_coherent(dma_ctx, size, virt_addr, dma_addr);
7141 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
7143 + return kzalloc(size, GFP_KERNEL);
7146 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
7148 + return kzalloc(size, GFP_ATOMIC);
7151 +void __DWC_FREE(void *mem_ctx, void *addr)
7157 +#ifdef DWC_CRYPTOLIB
7160 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
7162 + get_random_bytes(buffer, length);
7165 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
7167 + struct crypto_blkcipher *tfm;
7168 + struct blkcipher_desc desc;
7169 + struct scatterlist sgd;
7170 + struct scatterlist sgs;
7172 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
7173 + if (tfm == NULL) {
7174 + printk("failed to load transform for aes CBC\n");
7178 + crypto_blkcipher_setkey(tfm, key, keylen);
7179 + crypto_blkcipher_set_iv(tfm, iv, 16);
7181 + sg_init_one(&sgd, out, messagelen);
7182 + sg_init_one(&sgs, message, messagelen);
7187 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
7188 + crypto_free_blkcipher(tfm);
7189 + DWC_ERROR("AES CBC encryption failed");
7193 + crypto_free_blkcipher(tfm);
7197 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
7199 + struct crypto_hash *tfm;
7200 + struct hash_desc desc;
7201 + struct scatterlist sg;
7203 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
7204 + if (IS_ERR(tfm)) {
7205 + DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm));
7211 + sg_init_one(&sg, message, len);
7212 + crypto_hash_digest(&desc, &sg, len, out);
7213 + crypto_free_hash(tfm);
7218 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
7219 + uint8_t *key, uint32_t keylen, uint8_t *out)
7221 + struct crypto_hash *tfm;
7222 + struct hash_desc desc;
7223 + struct scatterlist sg;
7225 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
7226 + if (IS_ERR(tfm)) {
7227 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm));
7233 + sg_init_one(&sg, message, messagelen);
7234 + crypto_hash_setkey(tfm, key, keylen);
7235 + crypto_hash_digest(&desc, &sg, messagelen, out);
7236 + crypto_free_hash(tfm);
7240 +#endif /* DWC_CRYPTOLIB */
7243 +/* Byte Ordering Conversions */
7245 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
7247 +#ifdef __LITTLE_ENDIAN
7250 + uint8_t *u_p = (uint8_t *)p;
7252 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7256 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
7258 +#ifdef __BIG_ENDIAN
7261 + uint8_t *u_p = (uint8_t *)p;
7263 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7267 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
7269 +#ifdef __LITTLE_ENDIAN
7272 + uint8_t *u_p = (uint8_t *)p;
7274 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7278 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
7280 +#ifdef __BIG_ENDIAN
7283 + uint8_t *u_p = (uint8_t *)p;
7285 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7289 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
7291 +#ifdef __LITTLE_ENDIAN
7294 + uint8_t *u_p = (uint8_t *)p;
7295 + return (u_p[1] | (u_p[0] << 8));
7299 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
7301 +#ifdef __BIG_ENDIAN
7304 + uint8_t *u_p = (uint8_t *)p;
7305 + return (u_p[1] | (u_p[0] << 8));
7309 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
7311 +#ifdef __LITTLE_ENDIAN
7314 + uint8_t *u_p = (uint8_t *)p;
7315 + return (u_p[1] | (u_p[0] << 8));
7319 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
7321 +#ifdef __BIG_ENDIAN
7324 + uint8_t *u_p = (uint8_t *)p;
7325 + return (u_p[1] | (u_p[0] << 8));
7332 +uint32_t DWC_READ_REG32(uint32_t volatile *reg)
7334 + return readl(reg);
7338 +uint64_t DWC_READ_REG64(uint64_t volatile *reg)
7343 +void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
7345 + writel(value, reg);
7349 +void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
7354 +void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
7356 + writel((readl(reg) & ~clear_mask) | set_mask, reg);
7360 +void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask)
7368 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
7370 + spinlock_t *sl = (spinlock_t *)1;
7372 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7373 + sl = DWC_ALLOC(sizeof(*sl));
7375 + DWC_ERROR("Cannot allocate memory for spinlock\n");
7379 + spin_lock_init(sl);
7381 + return (dwc_spinlock_t *)sl;
7384 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
7386 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7391 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
7393 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7394 + spin_lock((spinlock_t *)lock);
7398 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
7400 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7401 + spin_unlock((spinlock_t *)lock);
7405 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
7409 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7410 + spin_lock_irqsave((spinlock_t *)lock, f);
7412 + local_irq_save(f);
7417 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
7419 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7420 + spin_unlock_irqrestore((spinlock_t *)lock, flags);
7422 + local_irq_restore(flags);
7426 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
7429 + dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex));
7432 + DWC_ERROR("Cannot allocate memory for mutex\n");
7436 + m = (struct mutex *)mutex;
7441 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
7443 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
7445 + mutex_destroy((struct mutex *)mutex);
7450 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
7452 + struct mutex *m = (struct mutex *)mutex;
7456 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
7458 + struct mutex *m = (struct mutex *)mutex;
7459 + return mutex_trylock(m);
7462 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
7464 + struct mutex *m = (struct mutex *)mutex;
7471 +void DWC_UDELAY(uint32_t usecs)
7476 +void DWC_MDELAY(uint32_t msecs)
7481 +void DWC_MSLEEP(uint32_t msecs)
7486 +uint32_t DWC_TIME(void)
7488 + return jiffies_to_msecs(jiffies);
7495 + struct timer_list *t;
7497 + dwc_timer_callback_t cb;
7499 + uint8_t scheduled;
7500 + dwc_spinlock_t *lock;
7503 +static void timer_callback(unsigned long data)
7505 + dwc_timer_t *timer = (dwc_timer_t *)data;
7506 + dwc_irqflags_t flags;
7508 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7509 + timer->scheduled = 0;
7510 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7511 + DWC_DEBUGC("Timer %s callback", timer->name);
7512 + timer->cb(timer->data);
7515 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
7517 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
7520 + DWC_ERROR("Cannot allocate memory for timer");
7524 + t->t = DWC_ALLOC(sizeof(*t->t));
7526 + DWC_ERROR("Cannot allocate memory for timer->t");
7530 + t->name = DWC_STRDUP(name);
7532 + DWC_ERROR("Cannot allocate memory for timer->name");
7536 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK))
7537 + DWC_SPINLOCK_ALLOC_LINUX_DEBUG(t->lock);
7539 + t->lock = DWC_SPINLOCK_ALLOC();
7542 + DWC_ERROR("Cannot allocate memory for lock");
7547 + t->t->base = &boot_tvec_bases;
7548 + t->t->expires = jiffies;
7549 + setup_timer(t->t, timer_callback, (unsigned long)t);
7557 + DWC_FREE(t->name);
7565 +void DWC_TIMER_FREE(dwc_timer_t *timer)
7567 + dwc_irqflags_t flags;
7569 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7571 + if (timer->scheduled) {
7572 + del_timer(timer->t);
7573 + timer->scheduled = 0;
7576 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7577 + DWC_SPINLOCK_FREE(timer->lock);
7578 + DWC_FREE(timer->t);
7579 + DWC_FREE(timer->name);
7583 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
7585 + dwc_irqflags_t flags;
7587 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7589 + if (!timer->scheduled) {
7590 + timer->scheduled = 1;
7591 + DWC_DEBUGC("Scheduling timer %s to expire in +%d msec", timer->name, time);
7592 + timer->t->expires = jiffies + msecs_to_jiffies(time);
7593 + add_timer(timer->t);
7595 + DWC_DEBUGC("Modifying timer %s to expire in +%d msec", timer->name, time);
7596 + mod_timer(timer->t, jiffies + msecs_to_jiffies(time));
7599 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7602 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
7604 + del_timer(timer->t);
7611 + wait_queue_head_t queue;
7615 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
7617 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
7620 + DWC_ERROR("Cannot allocate memory for waitqueue\n");
7624 + init_waitqueue_head(&wq->queue);
7629 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
7634 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
7636 + int result = wait_event_interruptible(wq->queue,
7637 + cond(data) || wq->abort);
7638 + if (result == -ERESTARTSYS) {
7640 + return -DWC_E_RESTART;
7643 + if (wq->abort == 1) {
7645 + return -DWC_E_ABORT;
7650 + if (result == 0) {
7654 + return -DWC_E_UNKNOWN;
7657 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
7658 + void *data, int32_t msecs)
7661 + int result = wait_event_interruptible_timeout(wq->queue,
7662 + cond(data) || wq->abort,
7663 + msecs_to_jiffies(msecs));
7664 + if (result == -ERESTARTSYS) {
7666 + return -DWC_E_RESTART;
7669 + if (wq->abort == 1) {
7671 + return -DWC_E_ABORT;
7677 + tmsecs = jiffies_to_msecs(result);
7685 + if (result == 0) {
7686 + return -DWC_E_TIMEOUT;
7689 + return -DWC_E_UNKNOWN;
7692 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
7695 + wake_up_interruptible(&wq->queue);
7698 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
7701 + wake_up_interruptible(&wq->queue);
7707 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
7709 + struct task_struct *thread = kthread_run(func, data, name);
7711 + if (thread == ERR_PTR(-ENOMEM)) {
7715 + return (dwc_thread_t *)thread;
7718 +int DWC_THREAD_STOP(dwc_thread_t *thread)
7720 + return kthread_stop((struct task_struct *)thread);
7723 +dwc_bool_t DWC_THREAD_SHOULD_STOP(void)
7725 + return kthread_should_stop();
7730 + - run in interrupt context (cannot sleep)
7731 + - each tasklet runs on a single CPU
7732 + - different tasklets can be running simultaneously on different CPUs
7734 +struct dwc_tasklet {
7735 + struct tasklet_struct t;
7736 + dwc_tasklet_callback_t cb;
7740 +static void tasklet_callback(unsigned long data)
7742 + dwc_tasklet_t *t = (dwc_tasklet_t *)data;
7746 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
7748 + dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t));
7753 + tasklet_init(&t->t, tasklet_callback, (unsigned long)t);
7755 + DWC_ERROR("Cannot allocate memory for tasklet\n");
7761 +void DWC_TASK_FREE(dwc_tasklet_t *task)
7766 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
7768 + tasklet_schedule(&task->t);
7773 + - run in process context (can sleep)
7775 +typedef struct work_container {
7776 + dwc_work_callback_t cb;
7782 + DWC_CIRCLEQ_ENTRY(work_container) entry;
7784 + struct delayed_work work;
7785 +} work_container_t;
7788 +DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
7792 + struct workqueue_struct *wq;
7793 + dwc_spinlock_t *lock;
7794 + dwc_waitq_t *waitq;
7798 + struct work_container_queue entries;
7802 +static void do_work(struct work_struct *work)
7804 + dwc_irqflags_t flags;
7805 + struct delayed_work *dw = container_of(work, struct delayed_work, work);
7806 + work_container_t *container = container_of(dw, struct work_container, work);
7807 + dwc_workq_t *wq = container->wq;
7809 + container->cb(container->data);
7812 + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
7814 + DWC_DEBUGC("Work done: %s, container=%p", container->name, container);
7815 + if (container->name) {
7816 + DWC_FREE(container->name);
7818 + DWC_FREE(container);
7820 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
7822 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
7823 + DWC_WAITQ_TRIGGER(wq->waitq);
7826 +static int work_done(void *data)
7828 + dwc_workq_t *workq = (dwc_workq_t *)data;
7829 + return workq->pending == 0;
7832 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
7834 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
7837 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
7839 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
7845 + wq->wq = create_singlethread_workqueue(name);
7852 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK))
7853 + DWC_SPINLOCK_ALLOC_LINUX_DEBUG(wq->lock);
7855 + wq->lock = DWC_SPINLOCK_ALLOC();
7861 + wq->waitq = DWC_WAITQ_ALLOC();
7867 + DWC_CIRCLEQ_INIT(&wq->entries);
7872 + DWC_SPINLOCK_FREE(wq->lock);
7874 + destroy_workqueue(wq->wq);
7881 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
7884 + if (wq->pending != 0) {
7885 + struct work_container *wc;
7886 + DWC_ERROR("Destroying work queue with pending work");
7887 + DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) {
7888 + DWC_ERROR("Work %s still pending", wc->name);
7892 + destroy_workqueue(wq->wq);
7893 + DWC_SPINLOCK_FREE(wq->lock);
7894 + DWC_WAITQ_FREE(wq->waitq);
7898 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
7899 + char *format, ...)
7901 + dwc_irqflags_t flags;
7902 + work_container_t *container;
7903 + static char name[128];
7906 + va_start(args, format);
7907 + DWC_VSNPRINTF(name, 128, format, args);
7910 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
7912 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
7913 + DWC_WAITQ_TRIGGER(wq->waitq);
7915 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
7917 + DWC_ERROR("Cannot allocate memory for container\n");
7921 + container->name = DWC_STRDUP(name);
7922 + if (!container->name) {
7923 + DWC_ERROR("Cannot allocate memory for container->name\n");
7924 + DWC_FREE(container);
7928 + container->cb = cb;
7929 + container->data = data;
7930 + container->wq = wq;
7931 + DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
7932 + INIT_WORK(&container->work.work, do_work);
7935 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
7937 + queue_work(wq->wq, &container->work.work);
7940 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
7941 + void *data, uint32_t time, char *format, ...)
7943 + dwc_irqflags_t flags;
7944 + work_container_t *container;
7945 + static char name[128];
7948 + va_start(args, format);
7949 + DWC_VSNPRINTF(name, 128, format, args);
7952 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
7954 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
7955 + DWC_WAITQ_TRIGGER(wq->waitq);
7957 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
7959 + DWC_ERROR("Cannot allocate memory for container\n");
7963 + container->name = DWC_STRDUP(name);
7964 + if (!container->name) {
7965 + DWC_ERROR("Cannot allocate memory for container->name\n");
7966 + DWC_FREE(container);
7970 + container->cb = cb;
7971 + container->data = data;
7972 + container->wq = wq;
7973 + DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
7974 + INIT_DELAYED_WORK(&container->work, do_work);
7977 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
7979 + queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time));
7982 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
7984 + return wq->pending;
7988 +#ifdef DWC_LIBMODULE
7992 +EXPORT_SYMBOL(dwc_cc_if_alloc);
7993 +EXPORT_SYMBOL(dwc_cc_if_free);
7994 +EXPORT_SYMBOL(dwc_cc_clear);
7995 +EXPORT_SYMBOL(dwc_cc_add);
7996 +EXPORT_SYMBOL(dwc_cc_remove);
7997 +EXPORT_SYMBOL(dwc_cc_change);
7998 +EXPORT_SYMBOL(dwc_cc_data_for_save);
7999 +EXPORT_SYMBOL(dwc_cc_restore_from_data);
8000 +EXPORT_SYMBOL(dwc_cc_match_chid);
8001 +EXPORT_SYMBOL(dwc_cc_match_cdid);
8002 +EXPORT_SYMBOL(dwc_cc_ck);
8003 +EXPORT_SYMBOL(dwc_cc_chid);
8004 +EXPORT_SYMBOL(dwc_cc_cdid);
8005 +EXPORT_SYMBOL(dwc_cc_name);
8006 +#endif /* DWC_CCLIB */
8008 +#ifdef DWC_CRYPTOLIB
8009 +# ifndef CONFIG_MACH_IPMATE
8011 +EXPORT_SYMBOL(dwc_modpow);
8014 +EXPORT_SYMBOL(dwc_dh_modpow);
8015 +EXPORT_SYMBOL(dwc_dh_derive_keys);
8016 +EXPORT_SYMBOL(dwc_dh_pk);
8017 +# endif /* CONFIG_MACH_IPMATE */
8020 +EXPORT_SYMBOL(dwc_wusb_aes_encrypt);
8021 +EXPORT_SYMBOL(dwc_wusb_cmf);
8022 +EXPORT_SYMBOL(dwc_wusb_prf);
8023 +EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce);
8024 +EXPORT_SYMBOL(dwc_wusb_gen_nonce);
8025 +EXPORT_SYMBOL(dwc_wusb_gen_key);
8026 +EXPORT_SYMBOL(dwc_wusb_gen_mic);
8027 +#endif /* DWC_CRYPTOLIB */
8030 +#ifdef DWC_NOTIFYLIB
8031 +EXPORT_SYMBOL(dwc_alloc_notification_manager);
8032 +EXPORT_SYMBOL(dwc_free_notification_manager);
8033 +EXPORT_SYMBOL(dwc_register_notifier);
8034 +EXPORT_SYMBOL(dwc_unregister_notifier);
8035 +EXPORT_SYMBOL(dwc_add_observer);
8036 +EXPORT_SYMBOL(dwc_remove_observer);
8037 +EXPORT_SYMBOL(dwc_notify);
8040 +/* Memory Debugging Routines */
8041 +#ifdef DWC_DEBUG_MEMORY
8042 +EXPORT_SYMBOL(dwc_alloc_debug);
8043 +EXPORT_SYMBOL(dwc_alloc_atomic_debug);
8044 +EXPORT_SYMBOL(dwc_free_debug);
8045 +EXPORT_SYMBOL(dwc_dma_alloc_debug);
8046 +EXPORT_SYMBOL(dwc_dma_free_debug);
8049 +EXPORT_SYMBOL(DWC_MEMSET);
8050 +EXPORT_SYMBOL(DWC_MEMCPY);
8051 +EXPORT_SYMBOL(DWC_MEMMOVE);
8052 +EXPORT_SYMBOL(DWC_MEMCMP);
8053 +EXPORT_SYMBOL(DWC_STRNCMP);
8054 +EXPORT_SYMBOL(DWC_STRCMP);
8055 +EXPORT_SYMBOL(DWC_STRLEN);
8056 +EXPORT_SYMBOL(DWC_STRCPY);
8057 +EXPORT_SYMBOL(DWC_STRDUP);
8058 +EXPORT_SYMBOL(DWC_ATOI);
8059 +EXPORT_SYMBOL(DWC_ATOUI);
8062 +EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE);
8063 +#endif /* DWC_UTFLIB */
8065 +EXPORT_SYMBOL(DWC_IN_IRQ);
8066 +EXPORT_SYMBOL(DWC_IN_BH);
8067 +EXPORT_SYMBOL(DWC_VPRINTF);
8068 +EXPORT_SYMBOL(DWC_VSNPRINTF);
8069 +EXPORT_SYMBOL(DWC_PRINTF);
8070 +EXPORT_SYMBOL(DWC_SPRINTF);
8071 +EXPORT_SYMBOL(DWC_SNPRINTF);
8072 +EXPORT_SYMBOL(__DWC_WARN);
8073 +EXPORT_SYMBOL(__DWC_ERROR);
8074 +EXPORT_SYMBOL(DWC_EXCEPTION);
8077 +EXPORT_SYMBOL(__DWC_DEBUG);
8080 +EXPORT_SYMBOL(__DWC_DMA_ALLOC);
8081 +EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC);
8082 +EXPORT_SYMBOL(__DWC_DMA_FREE);
8083 +EXPORT_SYMBOL(__DWC_ALLOC);
8084 +EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC);
8085 +EXPORT_SYMBOL(__DWC_FREE);
8087 +#ifdef DWC_CRYPTOLIB
8088 +EXPORT_SYMBOL(DWC_RANDOM_BYTES);
8089 +EXPORT_SYMBOL(DWC_AES_CBC);
8090 +EXPORT_SYMBOL(DWC_SHA256);
8091 +EXPORT_SYMBOL(DWC_HMAC_SHA256);
8094 +EXPORT_SYMBOL(DWC_CPU_TO_LE32);
8095 +EXPORT_SYMBOL(DWC_CPU_TO_BE32);
8096 +EXPORT_SYMBOL(DWC_LE32_TO_CPU);
8097 +EXPORT_SYMBOL(DWC_BE32_TO_CPU);
8098 +EXPORT_SYMBOL(DWC_CPU_TO_LE16);
8099 +EXPORT_SYMBOL(DWC_CPU_TO_BE16);
8100 +EXPORT_SYMBOL(DWC_LE16_TO_CPU);
8101 +EXPORT_SYMBOL(DWC_BE16_TO_CPU);
8102 +EXPORT_SYMBOL(DWC_READ_REG32);
8103 +EXPORT_SYMBOL(DWC_WRITE_REG32);
8104 +EXPORT_SYMBOL(DWC_MODIFY_REG32);
8107 +EXPORT_SYMBOL(DWC_READ_REG64);
8108 +EXPORT_SYMBOL(DWC_WRITE_REG64);
8109 +EXPORT_SYMBOL(DWC_MODIFY_REG64);
8112 +EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC);
8113 +EXPORT_SYMBOL(DWC_SPINLOCK_FREE);
8114 +EXPORT_SYMBOL(DWC_SPINLOCK);
8115 +EXPORT_SYMBOL(DWC_SPINUNLOCK);
8116 +EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE);
8117 +EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE);
8118 +EXPORT_SYMBOL(DWC_MUTEX_ALLOC);
8120 +#if (!defined(DWC_LINUX) || !defined(CONFIG_DEBUG_MUTEXES))
8121 +EXPORT_SYMBOL(DWC_MUTEX_FREE);
8124 +EXPORT_SYMBOL(DWC_MUTEX_LOCK);
8125 +EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK);
8126 +EXPORT_SYMBOL(DWC_MUTEX_UNLOCK);
8127 +EXPORT_SYMBOL(DWC_UDELAY);
8128 +EXPORT_SYMBOL(DWC_MDELAY);
8129 +EXPORT_SYMBOL(DWC_MSLEEP);
8130 +EXPORT_SYMBOL(DWC_TIME);
8131 +EXPORT_SYMBOL(DWC_TIMER_ALLOC);
8132 +EXPORT_SYMBOL(DWC_TIMER_FREE);
8133 +EXPORT_SYMBOL(DWC_TIMER_SCHEDULE);
8134 +EXPORT_SYMBOL(DWC_TIMER_CANCEL);
8135 +EXPORT_SYMBOL(DWC_WAITQ_ALLOC);
8136 +EXPORT_SYMBOL(DWC_WAITQ_FREE);
8137 +EXPORT_SYMBOL(DWC_WAITQ_WAIT);
8138 +EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT);
8139 +EXPORT_SYMBOL(DWC_WAITQ_TRIGGER);
8140 +EXPORT_SYMBOL(DWC_WAITQ_ABORT);
8141 +EXPORT_SYMBOL(DWC_THREAD_RUN);
8142 +EXPORT_SYMBOL(DWC_THREAD_STOP);
8143 +EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP);
8144 +EXPORT_SYMBOL(DWC_TASK_ALLOC);
8145 +EXPORT_SYMBOL(DWC_TASK_FREE);
8146 +EXPORT_SYMBOL(DWC_TASK_SCHEDULE);
8147 +EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE);
8148 +EXPORT_SYMBOL(DWC_WORKQ_ALLOC);
8149 +EXPORT_SYMBOL(DWC_WORKQ_FREE);
8150 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE);
8151 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED);
8152 +EXPORT_SYMBOL(DWC_WORKQ_PENDING);
8154 +static int dwc_common_port_init_module(void)
8158 + printk(KERN_DEBUG "Module dwc_common_port init\n" );
8160 +#ifdef DWC_DEBUG_MEMORY
8161 + result = dwc_memory_debug_start(NULL);
8164 + "dwc_memory_debug_start() failed with error %d\n",
8170 +#ifdef DWC_NOTIFYLIB
8171 + result = dwc_alloc_notification_manager(NULL, NULL);
8174 + "dwc_alloc_notification_manager() failed with error %d\n",
8182 +static void dwc_common_port_exit_module(void)
8184 + printk(KERN_DEBUG "Module dwc_common_port exit\n" );
8186 +#ifdef DWC_NOTIFYLIB
8187 + dwc_free_notification_manager();
8190 +#ifdef DWC_DEBUG_MEMORY
8191 + dwc_memory_debug_stop();
8195 +module_init(dwc_common_port_init_module);
8196 +module_exit(dwc_common_port_exit_module);
8198 +MODULE_DESCRIPTION("DWC Common Library - Portable version");
8199 +MODULE_AUTHOR("Synopsys Inc.");
8200 +MODULE_LICENSE ("GPL");
8202 +#endif /* DWC_LIBMODULE */
8204 +++ b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
8206 +#include "dwc_os.h"
8207 +#include "dwc_list.h"
8210 +# include "dwc_cc.h"
8213 +#ifdef DWC_CRYPTOLIB
8214 +# include "dwc_modpow.h"
8215 +# include "dwc_dh.h"
8216 +# include "dwc_crypto.h"
8219 +#ifdef DWC_NOTIFYLIB
8220 +# include "dwc_notifier.h"
8223 +/* OS-Level Implementations */
8225 +/* This is the NetBSD 4.0.1 kernel implementation of the DWC platform library. */
8230 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
8232 + return memset(dest, byte, size);
8235 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
8237 + return memcpy(dest, src, size);
8240 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
8242 + bcopy(src, dest, size);
8246 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
8248 + return memcmp(m1, m2, size);
8251 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
8253 + return strncmp(s1, s2, size);
8256 +int DWC_STRCMP(void *s1, void *s2)
8258 + return strcmp(s1, s2);
8261 +int DWC_STRLEN(char const *str)
8263 + return strlen(str);
8266 +char *DWC_STRCPY(char *to, char const *from)
8268 + return strcpy(to, from);
8271 +char *DWC_STRDUP(char const *str)
8273 + int len = DWC_STRLEN(str) + 1;
8274 + char *new = DWC_ALLOC_ATOMIC(len);
8280 + DWC_MEMCPY(new, str, len);
8284 +int DWC_ATOI(char *str, int32_t *value)
8288 + /* NetBSD doesn't have 'strtol' in the kernel, but 'strtoul'
8289 + * should be equivalent on 2's complement machines
8291 + *value = strtoul(str, &end, 0);
8292 + if (*end == '\0') {
8299 +int DWC_ATOUI(char *str, uint32_t *value)
8303 + *value = strtoul(str, &end, 0);
8304 + if (*end == '\0') {
8313 +/* From usbstring.c */
8315 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
8321 + /* this insists on correct encodings, though not minimal ones.
8322 + * BUT it currently rejects legit 4-byte UTF-8 code points,
8323 + * which need surrogate pairs. (Unicode 3.1 can use them.)
8325 + while (len != 0 && (c = (u8) *s++) != 0) {
8326 + if (unlikely(c & 0x80)) {
8327 + // 2-byte sequence:
8328 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
8329 + if ((c & 0xe0) == 0xc0) {
8330 + uchar = (c & 0x1f) << 6;
8333 + if ((c & 0xc0) != 0xc0)
8338 + // 3-byte sequence (most CJKV characters):
8339 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
8340 + } else if ((c & 0xf0) == 0xe0) {
8341 + uchar = (c & 0x0f) << 12;
8344 + if ((c & 0xc0) != 0xc0)
8350 + if ((c & 0xc0) != 0xc0)
8355 + /* no bogus surrogates */
8356 + if (0xd800 <= uchar && uchar <= 0xdfff)
8359 + // 4-byte sequence (surrogate pairs, currently rare):
8360 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
8361 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
8362 + // (uuuuu = wwww + 1)
8363 + // FIXME accept the surrogate code points (only)
8368 + put_unaligned (cpu_to_le16 (uchar), cp++);
8377 +#endif /* DWC_UTFLIB */
8382 +dwc_bool_t DWC_IN_IRQ(void)
8384 +// return in_irq();
8388 +dwc_bool_t DWC_IN_BH(void)
8390 +// return in_softirq();
8394 +void DWC_VPRINTF(char *format, va_list args)
8396 + vprintf(format, args);
8399 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
8401 + return vsnprintf(str, size, format, args);
8404 +void DWC_PRINTF(char *format, ...)
8408 + va_start(args, format);
8409 + DWC_VPRINTF(format, args);
8413 +int DWC_SPRINTF(char *buffer, char *format, ...)
8418 + va_start(args, format);
8419 + retval = vsprintf(buffer, format, args);
8424 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
8429 + va_start(args, format);
8430 + retval = vsnprintf(buffer, size, format, args);
8435 +void __DWC_WARN(char *format, ...)
8439 + va_start(args, format);
8440 + DWC_VPRINTF(format, args);
8444 +void __DWC_ERROR(char *format, ...)
8448 + va_start(args, format);
8449 + DWC_VPRINTF(format, args);
8453 +void DWC_EXCEPTION(char *format, ...)
8457 + va_start(args, format);
8458 + DWC_VPRINTF(format, args);
8464 +void __DWC_DEBUG(char *format, ...)
8468 + va_start(args, format);
8469 + DWC_VPRINTF(format, args);
8478 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
8482 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
8483 + size, align, alloc);
8484 + return (dwc_pool_t *)pool;
8487 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
8489 + dma_pool_destroy((struct dma_pool *)pool);
8492 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
8494 +// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
8495 + return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
8498 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
8500 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
8504 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
8506 + dma_pool_free(pool, vaddr, daddr);
8510 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
8512 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
8515 + error = bus_dmamem_alloc(dma->dma_tag, size, 1, size, dma->segs,
8516 + sizeof(dma->segs) / sizeof(dma->segs[0]),
8517 + &dma->nsegs, BUS_DMA_NOWAIT);
8519 + printf("%s: bus_dmamem_alloc(%ju) failed: %d\n", __func__,
8520 + (uintmax_t)size, error);
8524 + error = bus_dmamem_map(dma->dma_tag, dma->segs, dma->nsegs, size,
8525 + (caddr_t *)&dma->dma_vaddr,
8526 + BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
8528 + printf("%s: bus_dmamem_map failed: %d\n", __func__, error);
8532 + error = bus_dmamap_create(dma->dma_tag, size, 1, size, 0,
8533 + BUS_DMA_NOWAIT, &dma->dma_map);
8535 + printf("%s: bus_dmamap_create failed: %d\n", __func__, error);
8539 + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
8540 + size, NULL, BUS_DMA_NOWAIT);
8542 + printf("%s: bus_dmamap_load failed: %d\n", __func__, error);
8546 + dma->dma_paddr = (bus_addr_t)dma->segs[0].ds_addr;
8547 + *dma_addr = dma->dma_paddr;
8548 + return dma->dma_vaddr;
8551 + bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
8553 + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
8555 + bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
8557 + dma->dma_map = NULL;
8558 + dma->dma_vaddr = NULL;
8564 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
8566 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
8568 + if (dma->dma_map != NULL) {
8569 + bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, size,
8570 + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
8571 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
8572 + bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
8573 + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
8574 + bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
8575 + dma->dma_paddr = 0;
8576 + dma->dma_map = NULL;
8577 + dma->dma_vaddr = NULL;
8582 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
8584 + return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
8587 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
8589 + return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
8592 +void __DWC_FREE(void *mem_ctx, void *addr)
8594 + free(addr, M_DEVBUF);
8598 +#ifdef DWC_CRYPTOLIB
8601 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
8603 + get_random_bytes(buffer, length);
8606 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
8608 + struct crypto_blkcipher *tfm;
8609 + struct blkcipher_desc desc;
8610 + struct scatterlist sgd;
8611 + struct scatterlist sgs;
8613 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
8614 + if (tfm == NULL) {
8615 + printk("failed to load transform for aes CBC\n");
8619 + crypto_blkcipher_setkey(tfm, key, keylen);
8620 + crypto_blkcipher_set_iv(tfm, iv, 16);
8622 + sg_init_one(&sgd, out, messagelen);
8623 + sg_init_one(&sgs, message, messagelen);
8628 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
8629 + crypto_free_blkcipher(tfm);
8630 + DWC_ERROR("AES CBC encryption failed");
8634 + crypto_free_blkcipher(tfm);
8638 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
8640 + struct crypto_hash *tfm;
8641 + struct hash_desc desc;
8642 + struct scatterlist sg;
8644 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
8645 + if (IS_ERR(tfm)) {
8646 + DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
8652 + sg_init_one(&sg, message, len);
8653 + crypto_hash_digest(&desc, &sg, len, out);
8654 + crypto_free_hash(tfm);
8659 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
8660 + uint8_t *key, uint32_t keylen, uint8_t *out)
8662 + struct crypto_hash *tfm;
8663 + struct hash_desc desc;
8664 + struct scatterlist sg;
8666 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
8667 + if (IS_ERR(tfm)) {
8668 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
8674 + sg_init_one(&sg, message, messagelen);
8675 + crypto_hash_setkey(tfm, key, keylen);
8676 + crypto_hash_digest(&desc, &sg, messagelen, out);
8677 + crypto_free_hash(tfm);
8682 +#endif /* DWC_CRYPTOLIB */
8685 +/* Byte Ordering Conversions */
8687 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
8689 +#ifdef __LITTLE_ENDIAN
8692 + uint8_t *u_p = (uint8_t *)p;
8694 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8698 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
8700 +#ifdef __BIG_ENDIAN
8703 + uint8_t *u_p = (uint8_t *)p;
8705 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8709 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
8711 +#ifdef __LITTLE_ENDIAN
8714 + uint8_t *u_p = (uint8_t *)p;
8716 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8720 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
8722 +#ifdef __BIG_ENDIAN
8725 + uint8_t *u_p = (uint8_t *)p;
8727 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8731 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
8733 +#ifdef __LITTLE_ENDIAN
8736 + uint8_t *u_p = (uint8_t *)p;
8737 + return (u_p[1] | (u_p[0] << 8));
8741 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
8743 +#ifdef __BIG_ENDIAN
8746 + uint8_t *u_p = (uint8_t *)p;
8747 + return (u_p[1] | (u_p[0] << 8));
8751 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
8753 +#ifdef __LITTLE_ENDIAN
8756 + uint8_t *u_p = (uint8_t *)p;
8757 + return (u_p[1] | (u_p[0] << 8));
8761 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
8763 +#ifdef __BIG_ENDIAN
8766 + uint8_t *u_p = (uint8_t *)p;
8767 + return (u_p[1] | (u_p[0] << 8));
8774 +uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
8776 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8777 + bus_size_t ior = (bus_size_t)reg;
8779 + return bus_space_read_4(io->iot, io->ioh, ior);
8783 +uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
8785 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8786 + bus_size_t ior = (bus_size_t)reg;
8788 + return bus_space_read_8(io->iot, io->ioh, ior);
8792 +void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
8794 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8795 + bus_size_t ior = (bus_size_t)reg;
8797 + bus_space_write_4(io->iot, io->ioh, ior, value);
8801 +void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
8803 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8804 + bus_size_t ior = (bus_size_t)reg;
8806 + bus_space_write_8(io->iot, io->ioh, ior, value);
8810 +void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
8811 + uint32_t set_mask)
8813 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8814 + bus_size_t ior = (bus_size_t)reg;
8816 + bus_space_write_4(io->iot, io->ioh, ior,
8817 + (bus_space_read_4(io->iot, io->ioh, ior) &
8818 + ~clear_mask) | set_mask);
8822 +void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
8823 + uint64_t set_mask)
8825 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8826 + bus_size_t ior = (bus_size_t)reg;
8828 + bus_space_write_8(io->iot, io->ioh, ior,
8829 + (bus_space_read_8(io->iot, io->ioh, ior) &
8830 + ~clear_mask) | set_mask);
8837 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
8839 + struct simplelock *sl = DWC_ALLOC(sizeof(*sl));
8842 + DWC_ERROR("Cannot allocate memory for spinlock");
8846 + simple_lock_init(sl);
8847 + return (dwc_spinlock_t *)sl;
8850 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
8852 + struct simplelock *sl = (struct simplelock *)lock;
8857 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
8859 + simple_lock((struct simplelock *)lock);
8862 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
8864 + simple_unlock((struct simplelock *)lock);
8867 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
8869 + simple_lock((struct simplelock *)lock);
8870 + *flags = splbio();
8873 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
8876 + simple_unlock((struct simplelock *)lock);
8879 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
8881 + dwc_mutex_t *mutex = DWC_ALLOC(sizeof(struct lock));
8884 + DWC_ERROR("Cannot allocate memory for mutex");
8888 + lockinit((struct lock *)mutex, 0, "dw3mtx", 0, 0);
8892 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
8894 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
8900 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
8902 + lockmgr((struct lock *)mutex, LK_EXCLUSIVE, NULL);
8905 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
8909 + status = lockmgr((struct lock *)mutex, LK_EXCLUSIVE | LK_NOWAIT, NULL);
8910 + return status == 0;
8913 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
8915 + lockmgr((struct lock *)mutex, LK_RELEASE, NULL);
8921 +void DWC_UDELAY(uint32_t usecs)
8926 +void DWC_MDELAY(uint32_t msecs)
8930 + } while (--msecs);
8933 +void DWC_MSLEEP(uint32_t msecs)
8935 + struct timeval tv;
8937 + tv.tv_sec = msecs / 1000;
8938 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
8939 + tsleep(&tv, 0, "dw3slp", tvtohz(&tv));
8942 +uint32_t DWC_TIME(void)
8944 + struct timeval tv;
8946 + microuptime(&tv); // or getmicrouptime? (less precise, but faster)
8947 + return tv.tv_sec * 1000 + tv.tv_usec / 1000;
8956 + dwc_spinlock_t *lock;
8957 + dwc_timer_callback_t cb;
8961 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
8963 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
8966 + DWC_ERROR("Cannot allocate memory for timer");
8970 + callout_init(&t->t);
8972 + t->name = DWC_STRDUP(name);
8974 + DWC_ERROR("Cannot allocate memory for timer->name");
8978 + t->lock = DWC_SPINLOCK_ALLOC();
8980 + DWC_ERROR("Cannot allocate memory for timer->lock");
8990 + DWC_FREE(t->name);
8997 +void DWC_TIMER_FREE(dwc_timer_t *timer)
8999 + callout_stop(&timer->t);
9000 + DWC_SPINLOCK_FREE(timer->lock);
9001 + DWC_FREE(timer->name);
9005 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
9007 + struct timeval tv;
9009 + tv.tv_sec = time / 1000;
9010 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
9011 + callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
9014 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
9016 + callout_stop(&timer->t);
9023 + struct simplelock lock;
9027 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
9029 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
9032 + DWC_ERROR("Cannot allocate memory for waitqueue");
9036 + simple_lock_init(&wq->lock);
9042 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
9047 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
9052 + simple_lock(&wq->lock);
9055 + /* Skip the sleep if already aborted or triggered */
9056 + if (!wq->abort && !cond(data)) {
9058 + result = ltsleep(wq, PCATCH, "dw3wat", 0, &wq->lock); // infinite timeout
9062 + if (result == 0) { // awoken
9065 + result = -DWC_E_ABORT;
9071 + simple_unlock(&wq->lock);
9075 + simple_unlock(&wq->lock);
9077 + if (result == ERESTART) { // signaled - restart
9078 + result = -DWC_E_RESTART;
9079 + } else { // signaled - must be EINTR
9080 + result = -DWC_E_ABORT;
9087 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
9088 + void *data, int32_t msecs)
9090 + struct timeval tv, tv1, tv2;
9094 + tv.tv_sec = msecs / 1000;
9095 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
9097 + simple_lock(&wq->lock);
9100 + /* Skip the sleep if already aborted or triggered */
9101 + if (!wq->abort && !cond(data)) {
9103 + getmicrouptime(&tv1);
9104 + result = ltsleep(wq, PCATCH, "dw3wto", tvtohz(&tv), &wq->lock);
9105 + getmicrouptime(&tv2);
9109 + if (result == 0) { // awoken
9113 + simple_unlock(&wq->lock);
9114 + result = -DWC_E_ABORT;
9117 + simple_unlock(&wq->lock);
9119 + tv2.tv_usec -= tv1.tv_usec;
9120 + if (tv2.tv_usec < 0) {
9121 + tv2.tv_usec += 1000000;
9125 + tv2.tv_sec -= tv1.tv_sec;
9126 + result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
9127 + result = msecs - result;
9134 + simple_unlock(&wq->lock);
9136 + if (result == ERESTART) { // signaled - restart
9137 + result = -DWC_E_RESTART;
9139 + } else if (result == EINTR) { // signaled - interrupt
9140 + result = -DWC_E_ABORT;
9142 + } else { // timed out
9143 + result = -DWC_E_TIMEOUT;
9150 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
9155 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
9159 + simple_lock(&wq->lock);
9164 + simple_unlock(&wq->lock);
9170 +struct dwc_thread {
9171 + struct proc *proc;
9175 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
9178 + dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
9184 + thread->abort = 0;
9185 + retval = kthread_create1((void (*)(void *))func, data, &thread->proc,
9195 +int DWC_THREAD_STOP(dwc_thread_t *thread)
9199 + thread->abort = 1;
9200 + retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
9202 + if (retval == 0) {
9203 + /* DWC_THREAD_EXIT() will free the thread struct */
9207 + /* NOTE: We leak the thread struct if thread doesn't die */
9209 + if (retval == EWOULDBLOCK) {
9210 + return -DWC_E_TIMEOUT;
9213 + return -DWC_E_UNKNOWN;
9216 +dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
9218 + return thread->abort;
9221 +void DWC_THREAD_EXIT(dwc_thread_t *thread)
9223 + wakeup(&thread->abort);
9229 + - Runs in interrupt context (cannot sleep)
9230 + - Each tasklet runs on a single CPU
9231 + - Different tasklets can be running simultaneously on different CPUs
9232 + [ On NetBSD there is no corresponding mechanism, drivers don't have bottom-
9233 + halves. So we just call the callback directly from DWC_TASK_SCHEDULE() ]
9235 +struct dwc_tasklet {
9236 + dwc_tasklet_callback_t cb;
9240 +static void tasklet_callback(void *data)
9242 + dwc_tasklet_t *task = (dwc_tasklet_t *)data;
9244 + task->cb(task->data);
9247 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
9249 + dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
9253 + task->data = data;
9255 + DWC_ERROR("Cannot allocate memory for tasklet");
9261 +void DWC_TASK_FREE(dwc_tasklet_t *task)
9266 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
9268 + tasklet_callback(task);
9273 + - Runs in process context (can sleep)
9275 +typedef struct work_container {
9276 + dwc_work_callback_t cb;
9282 +} work_container_t;
9285 + struct workqueue *taskq;
9286 + dwc_spinlock_t *lock;
9287 + dwc_waitq_t *waitq;
9289 + struct work_container *container;
9292 +static void do_work(struct work *task, void *data)
9294 + dwc_workq_t *wq = (dwc_workq_t *)data;
9295 + work_container_t *container = wq->container;
9296 + dwc_irqflags_t flags;
9298 + if (container->hz) {
9299 + tsleep(container, 0, "dw3wrk", container->hz);
9302 + container->cb(container->data);
9303 + DWC_DEBUG("Work done: %s, container=%p", container->name, container);
9305 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9306 + if (container->name)
9307 + DWC_FREE(container->name);
9308 + DWC_FREE(container);
9310 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9311 + DWC_WAITQ_TRIGGER(wq->waitq);
9314 +static int work_done(void *data)
9316 + dwc_workq_t *workq = (dwc_workq_t *)data;
9318 + return workq->pending == 0;
9321 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
9323 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
9326 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
9329 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
9332 + DWC_ERROR("Cannot allocate memory for workqueue");
9336 + result = workqueue_create(&wq->taskq, name, do_work, wq, 0 /*PWAIT*/,
9339 + DWC_ERROR("Cannot create workqueue");
9345 + wq->lock = DWC_SPINLOCK_ALLOC();
9347 + DWC_ERROR("Cannot allocate memory for spinlock");
9351 + wq->waitq = DWC_WAITQ_ALLOC();
9353 + DWC_ERROR("Cannot allocate memory for waitqueue");
9360 + DWC_SPINLOCK_FREE(wq->lock);
9362 + workqueue_destroy(wq->taskq);
9369 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
9372 + dwc_irqflags_t flags;
9374 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9376 + if (wq->pending != 0) {
9377 + struct work_container *container = wq->container;
9379 + DWC_ERROR("Destroying work queue with pending work");
9381 + if (container && container->name) {
9382 + DWC_ERROR("Work %s still pending", container->name);
9386 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9388 + DWC_WAITQ_FREE(wq->waitq);
9389 + DWC_SPINLOCK_FREE(wq->lock);
9390 + workqueue_destroy(wq->taskq);
9394 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
9395 + char *format, ...)
9397 + dwc_irqflags_t flags;
9398 + work_container_t *container;
9399 + static char name[128];
9402 + va_start(args, format);
9403 + DWC_VSNPRINTF(name, 128, format, args);
9406 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9408 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9409 + DWC_WAITQ_TRIGGER(wq->waitq);
9411 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
9413 + DWC_ERROR("Cannot allocate memory for container");
9417 + container->name = DWC_STRDUP(name);
9418 + if (!container->name) {
9419 + DWC_ERROR("Cannot allocate memory for container->name");
9420 + DWC_FREE(container);
9424 + container->cb = cb;
9425 + container->data = data;
9426 + container->wq = wq;
9427 + container->hz = 0;
9428 + wq->container = container;
9430 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
9431 + workqueue_enqueue(wq->taskq, &container->task);
9434 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
9435 + void *data, uint32_t time, char *format, ...)
9437 + dwc_irqflags_t flags;
9438 + work_container_t *container;
9439 + static char name[128];
9440 + struct timeval tv;
9443 + va_start(args, format);
9444 + DWC_VSNPRINTF(name, 128, format, args);
9447 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9449 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9450 + DWC_WAITQ_TRIGGER(wq->waitq);
9452 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
9454 + DWC_ERROR("Cannot allocate memory for container");
9458 + container->name = DWC_STRDUP(name);
9459 + if (!container->name) {
9460 + DWC_ERROR("Cannot allocate memory for container->name");
9461 + DWC_FREE(container);
9465 + container->cb = cb;
9466 + container->data = data;
9467 + container->wq = wq;
9468 + tv.tv_sec = time / 1000;
9469 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
9470 + container->hz = tvtohz(&tv);
9471 + wq->container = container;
9473 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
9474 + workqueue_enqueue(wq->taskq, &container->task);
9477 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
9479 + return wq->pending;
9482 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.c
9484 +/* =========================================================================
9485 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $
9487 + * $Date: 2010/09/28 $
9488 + * $Change: 1596182 $
9490 + * Synopsys Portability Library Software and documentation
9491 + * (hereinafter, "Software") is an Unsupported proprietary work of
9492 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9493 + * between Synopsys and you.
9495 + * The Software IS NOT an item of Licensed Software or Licensed Product
9496 + * under any End User Software License Agreement or Agreement for
9497 + * Licensed Product with Synopsys or any supplement thereto. You are
9498 + * permitted to use and redistribute this Software in source and binary
9499 + * forms, with or without modification, provided that redistributions
9500 + * of source code must retain this notice. You may not view, use,
9501 + * disclose, copy or distribute this file or any information contained
9502 + * herein except pursuant to this license grant from Synopsys. If you
9503 + * do not agree with this notice, including the disclaimer below, then
9504 + * you are not authorized to use the Software.
9506 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9507 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9508 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9509 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9510 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9511 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9512 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9513 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9514 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9515 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9516 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9518 + * ========================================================================= */
9521 + * This file contains the WUSB cryptographic routines.
9524 +#ifdef DWC_CRYPTOLIB
9526 +#include "dwc_crypto.h"
9530 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
9533 + DWC_PRINTF("%s: ", name);
9534 + for (i=0; i<len; i++) {
9535 + DWC_PRINTF("%02x ", bytes[i]);
9540 +#define dump_bytes(x...)
9543 +/* Display a block */
9544 +void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
9546 +#ifdef DWC_DEBUG_CRYPTO
9547 + int i, blksize = 16;
9549 + DWC_DEBUG("%s", prefix);
9551 + if (suffix == NULL) {
9556 + for (i = 0; i < blksize; i++)
9557 + DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? " " : " ");
9558 + DWC_PRINT(suffix);
9563 + * Encrypts an array of bytes using the AES encryption engine.
9564 + * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
9567 + * @return 0 on success, negative error code on error.
9569 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
9572 + DWC_MEMSET(block_t, 0, 16);
9574 + return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
9578 + * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
9579 + * This function takes a data string and returns the encrypted CBC
9580 + * Counter-mode MIC.
9582 + * @param key The 128-bit symmetric key.
9583 + * @param nonce The CCM nonce.
9584 + * @param label The unique 14-byte ASCII text label.
9585 + * @param bytes The byte array to be encrypted.
9586 + * @param len Length of the byte array.
9587 + * @param result Byte array to receive the 8-byte encrypted MIC.
9589 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
9590 + char *label, u8 *bytes, int len, u8 *result)
9596 + u16 la = (u16)(len + 14);
9598 + /* Set the AES-128 key */
9599 + //dwc_aes_setkey(tfm, key, 16);
9601 + /* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
9602 + block_m[0] = 0x59;
9603 + for (idx = 0; idx < 13; idx++)
9604 + block_m[idx + 1] = nonce[idx];
9608 + /* Produce the CBC IV */
9609 + dwc_wusb_aes_encrypt(block_m, key, block_x);
9610 + show_block(block_m, "CBC IV in: ", "\n", 0);
9611 + show_block(block_x, "CBC IV out:", "\n", 0);
9613 + /* Fill block B1 from l(a) = Blen + 14, and A */
9614 + block_x[0] ^= (u8)(la >> 8);
9615 + block_x[1] ^= (u8)la;
9616 + for (idx = 0; idx < 14; idx++)
9617 + block_x[idx + 2] ^= label[idx];
9618 + show_block(block_x, "After xor: ", "b1\n", 16);
9620 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9621 + show_block(block_x, "After AES: ", "b1\n", 16);
9626 + /* Fill remaining blocks with B */
9627 + while (len-- > 0) {
9628 + block_x[idx] ^= *bytes++;
9629 + if (++idx >= 16) {
9631 + show_block(block_x, "After xor: ", "\n", blkNum);
9632 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9633 + show_block(block_x, "After AES: ", "\n", blkNum);
9638 + /* Handle partial last block */
9640 + show_block(block_x, "After xor: ", "\n", blkNum);
9641 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9642 + show_block(block_x, "After AES: ", "\n", blkNum);
9645 + /* Save the MIC tag */
9646 + DWC_MEMCPY(block_t, block_x, 8);
9647 + show_block(block_t, "MIC tag : ", NULL, 8);
9649 + /* Fill block A0 from flags = 0x01, N, and counter = 0 */
9650 + block_m[0] = 0x01;
9654 + /* Encrypt the counter */
9655 + dwc_wusb_aes_encrypt(block_m, key, block_x);
9656 + show_block(block_x, "CTR[MIC] : ", NULL, 8);
9658 + /* XOR with MIC tag */
9659 + for (idx = 0; idx < 8; idx++) {
9660 + block_t[idx] ^= block_x[idx];
9663 + /* Return result to caller */
9664 + DWC_MEMCPY(result, block_t, 8);
9665 + show_block(result, "CCM-MIC : ", NULL, 8);
9670 + * The PRF function described in section 6.5 of the WUSB spec. This function
9671 + * concatenates MIC values returned from dwc_cmf() to create a value of
9672 + * the requested length.
9674 + * @param prf_len Length of the PRF function in bits (64, 128, or 256).
9675 + * @param key, nonce, label, bytes, len Same as for dwc_cmf().
9676 + * @param result Byte array to receive the result.
9678 +void dwc_wusb_prf(int prf_len, u8 *key,
9679 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
9684 + for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
9685 + dwc_wusb_cmf(key, nonce, label, bytes, len, result);
9691 + * Fills in CCM Nonce per the WUSB spec.
9693 + * @param[in] haddr Host address.
9694 + * @param[in] daddr Device address.
9695 + * @param[in] tkid Session Key(PTK) identifier.
9696 + * @param[out] nonce Pointer to where the CCM Nonce output is to be written.
9698 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
9702 + DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
9704 + DWC_MEMSET(&nonce[0], 0, 16);
9706 + DWC_MEMCPY(&nonce[6], tkid, 3);
9707 + nonce[9] = daddr & 0xFF;
9708 + nonce[10] = (daddr >> 8) & 0xFF;
9709 + nonce[11] = haddr & 0xFF;
9710 + nonce[12] = (haddr >> 8) & 0xFF;
9712 + dump_bytes("CCM nonce", nonce, 16);
9716 + * Generates a 16-byte cryptographic-grade random number for the Host/Device
9719 +void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
9721 + uint8_t inonce[16];
9724 + /* Fill in the Nonce */
9725 + DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
9726 + inonce[9] = addr & 0xFF;
9727 + inonce[10] = (addr >> 8) & 0xFF;
9728 + inonce[11] = inonce[9];
9729 + inonce[12] = inonce[10];
9731 + /* Collect "randomness samples" */
9732 + DWC_RANDOM_BYTES((uint8_t *)temp, 16);
9734 + dwc_wusb_prf_128((uint8_t *)temp, nonce,
9735 + "Random Numbers", (uint8_t *)temp, sizeof(temp),
9740 + * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
9743 + * @param[in] ccm_nonce Pointer to CCM Nonce.
9744 + * @param[in] mk Master Key to derive the session from
9745 + * @param[in] hnonce Pointer to Host Nonce.
9746 + * @param[in] dnonce Pointer to Device Nonce.
9747 + * @param[out] kck Pointer to where the KCK output is to be written.
9748 + * @param[out] ptk Pointer to where the PTK output is to be written.
9750 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
9751 + uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
9753 + uint8_t idata[32];
9754 + uint8_t odata[32];
9756 + dump_bytes("ck", mk, 16);
9757 + dump_bytes("hnonce", hnonce, 16);
9758 + dump_bytes("dnonce", dnonce, 16);
9760 + /* The data is the HNonce and DNonce concatenated */
9761 + DWC_MEMCPY(&idata[0], hnonce, 16);
9762 + DWC_MEMCPY(&idata[16], dnonce, 16);
9764 + dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
9766 + /* Low 16 bytes of the result is the KCK, high 16 is the PTK */
9767 + DWC_MEMCPY(kck, &odata[0], 16);
9768 + DWC_MEMCPY(ptk, &odata[16], 16);
9770 + dump_bytes("kck", kck, 16);
9771 + dump_bytes("ptk", ptk, 16);
9775 + * Generates the Message Integrity Code over the Handshake data per the
9778 + * @param ccm_nonce Pointer to CCM Nonce.
9779 + * @param kck Pointer to Key Confirmation Key.
9780 + * @param data Pointer to Handshake data to be checked.
9781 + * @param mic Pointer to where the MIC output is to be written.
9783 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
9784 + uint8_t *data, uint8_t *mic)
9787 + dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
9788 + data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
9791 +#endif /* DWC_CRYPTOLIB */
9793 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.h
9795 +/* =========================================================================
9796 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.h $
9798 + * $Date: 2010/09/28 $
9799 + * $Change: 1596182 $
9801 + * Synopsys Portability Library Software and documentation
9802 + * (hereinafter, "Software") is an Unsupported proprietary work of
9803 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9804 + * between Synopsys and you.
9806 + * The Software IS NOT an item of Licensed Software or Licensed Product
9807 + * under any End User Software License Agreement or Agreement for
9808 + * Licensed Product with Synopsys or any supplement thereto. You are
9809 + * permitted to use and redistribute this Software in source and binary
9810 + * forms, with or without modification, provided that redistributions
9811 + * of source code must retain this notice. You may not view, use,
9812 + * disclose, copy or distribute this file or any information contained
9813 + * herein except pursuant to this license grant from Synopsys. If you
9814 + * do not agree with this notice, including the disclaimer below, then
9815 + * you are not authorized to use the Software.
9817 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9818 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9819 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9820 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9821 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9822 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9823 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9824 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9825 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9826 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9827 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9829 + * ========================================================================= */
9831 +#ifndef _DWC_CRYPTO_H_
9832 +#define _DWC_CRYPTO_H_
9840 + * This file contains declarations for the WUSB Cryptographic routines as
9841 + * defined in the WUSB spec. They are only to be used internally by the DWC UWB
9845 +#include "dwc_os.h"
9847 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
9849 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
9850 + char *label, u8 *bytes, int len, u8 *result);
9851 +void dwc_wusb_prf(int prf_len, u8 *key,
9852 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
9855 + * The PRF-64 function described in section 6.5 of the WUSB spec.
9857 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9859 +static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
9860 + char *label, u8 *bytes, int len, u8 *result)
9862 + dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
9866 + * The PRF-128 function described in section 6.5 of the WUSB spec.
9868 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9870 +static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
9871 + char *label, u8 *bytes, int len, u8 *result)
9873 + dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
9877 + * The PRF-256 function described in section 6.5 of the WUSB spec.
9879 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9881 +static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
9882 + char *label, u8 *bytes, int len, u8 *result)
9884 + dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
9888 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
9890 +void dwc_wusb_gen_nonce(uint16_t addr,
9893 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
9894 + uint8_t *hnonce, uint8_t *dnonce,
9895 + uint8_t *kck, uint8_t *ptk);
9898 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
9899 + *kck, uint8_t *data, uint8_t *mic);
9905 +#endif /* _DWC_CRYPTO_H_ */
9907 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.c
9909 +/* =========================================================================
9910 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
9912 + * $Date: 2010/09/28 $
9913 + * $Change: 1596182 $
9915 + * Synopsys Portability Library Software and documentation
9916 + * (hereinafter, "Software") is an Unsupported proprietary work of
9917 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9918 + * between Synopsys and you.
9920 + * The Software IS NOT an item of Licensed Software or Licensed Product
9921 + * under any End User Software License Agreement or Agreement for
9922 + * Licensed Product with Synopsys or any supplement thereto. You are
9923 + * permitted to use and redistribute this Software in source and binary
9924 + * forms, with or without modification, provided that redistributions
9925 + * of source code must retain this notice. You may not view, use,
9926 + * disclose, copy or distribute this file or any information contained
9927 + * herein except pursuant to this license grant from Synopsys. If you
9928 + * do not agree with this notice, including the disclaimer below, then
9929 + * you are not authorized to use the Software.
9931 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9932 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9933 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9934 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9935 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9936 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9937 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9938 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9939 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9940 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9941 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9943 + * ========================================================================= */
9944 +#ifdef DWC_CRYPTOLIB
9946 +#ifndef CONFIG_MACH_IPMATE
9948 +#include "dwc_dh.h"
9949 +#include "dwc_modpow.h"
9952 +/* This function prints out a buffer in the format described in the Association
9953 + * Model specification. */
9954 +static void dh_dump(char *str, void *_num, int len)
9956 + uint8_t *num = _num;
9958 + DWC_PRINTF("%s\n", str);
9959 + for (i = 0; i < len; i ++) {
9960 + DWC_PRINTF("%02x", num[i]);
9961 + if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
9962 + if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
9968 +#define dh_dump(_x...) do {; } while(0)
9971 +/* Constant g value */
9972 +static __u32 dh_g[] = {
9976 +/* Constant p value */
9977 +static __u32 dh_p[] = {
9978 + 0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
9979 + 0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
9980 + 0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
9981 + 0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
9982 + 0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
9983 + 0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
9984 + 0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
9985 + 0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
9986 + 0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
9987 + 0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
9988 + 0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
9989 + 0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
9992 +static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
9994 + uint8_t *in = _in;
9995 + uint8_t *out = _out;
9997 + for (i=0; i<len; i++) {
9998 + out[i] = in[len-1-i];
10002 +/* Computes the modular exponentiation (num^exp % mod). num, exp, and mod are
10003 + * big endian numbers of size len, in bytes. Each len value must be a multiple
10005 +int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
10006 + void *exp, uint32_t exp_len,
10007 + void *mod, uint32_t mod_len,
10010 + /* modpow() takes little endian numbers. AM uses big-endian. This
10011 + * function swaps bytes of numbers before passing onto modpow. */
10014 + uint32_t *result;
10016 + uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
10017 + uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
10018 + uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
10020 + dh_swap_bytes(num, &bignum_num[1], num_len);
10021 + bignum_num[0] = num_len / 4;
10023 + dh_swap_bytes(exp, &bignum_exp[1], exp_len);
10024 + bignum_exp[0] = exp_len / 4;
10026 + dh_swap_bytes(mod, &bignum_mod[1], mod_len);
10027 + bignum_mod[0] = mod_len / 4;
10029 + result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
10032 + goto dh_modpow_nomem;
10035 + dh_swap_bytes(&result[1], out, result[0] * 4);
10036 + dwc_free(mem_ctx, result);
10039 + dwc_free(mem_ctx, bignum_num);
10040 + dwc_free(mem_ctx, bignum_exp);
10041 + dwc_free(mem_ctx, bignum_mod);
10046 +int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
10051 +#ifndef DH_TEST_VECTORS
10052 + DWC_RANDOM_BYTES(exp, 32);
10055 + /* Compute the pkd */
10056 + if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
10058 + dh_p, 384, pk))) {
10063 + DWC_MEMCPY(&m3[0], pk, 384);
10064 + DWC_SHA256(m3, 385, hash);
10066 + dh_dump("PK", pk, 384);
10067 + dh_dump("SHA-256(M3)", hash, 32);
10071 +int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
10072 + uint8_t *exp, int is_host,
10073 + char *dd, uint8_t *ck, uint8_t *kdk)
10077 + uint8_t sha_result[32];
10078 + uint8_t dhkey[384];
10079 + uint8_t shared_secret[384];
10092 + if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
10094 + dh_p, 384, shared_secret))) {
10097 + dh_dump("Shared Secret", shared_secret, 384);
10099 + DWC_SHA256(shared_secret, 384, dhkey);
10100 + dh_dump("DHKEY", dhkey, 384);
10102 + DWC_MEMCPY(&mv[0], pkd, 384);
10103 + DWC_MEMCPY(&mv[384], pkh, 384);
10104 + DWC_MEMCPY(&mv[768], "displayed digest", 16);
10105 + dh_dump("MV", mv, 784);
10107 + DWC_SHA256(mv, 784, sha_result);
10108 + dh_dump("SHA-256(MV)", sha_result, 32);
10109 + dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
10111 + dh_swap_bytes(sha_result, &vd, 4);
10113 + DWC_PRINTF("Vd (decimal) = %d\n", vd);
10119 + DWC_SPRINTF(dd, "%02d", vd);
10123 + DWC_SPRINTF(dd, "%03d", vd);
10127 + DWC_SPRINTF(dd, "%04d", vd);
10131 + DWC_PRINTF("Display Digits: %s\n", dd);
10134 + message = "connection key";
10135 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
10136 + dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
10137 + DWC_MEMCPY(ck, sha_result, 16);
10139 + message = "key derivation key";
10140 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
10141 + dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
10142 + DWC_MEMCPY(kdk, sha_result, 32);
10148 +#ifdef DH_TEST_VECTORS
10150 +static __u8 dh_a[] = {
10151 + 0x44, 0x00, 0x51, 0xd6,
10152 + 0xf0, 0xb5, 0x5e, 0xa9,
10153 + 0x67, 0xab, 0x31, 0xc6,
10154 + 0x8a, 0x8b, 0x5e, 0x37,
10155 + 0xd9, 0x10, 0xda, 0xe0,
10156 + 0xe2, 0xd4, 0x59, 0xa4,
10157 + 0x86, 0x45, 0x9c, 0xaa,
10158 + 0xdf, 0x36, 0x75, 0x16,
10161 +static __u8 dh_b[] = {
10162 + 0x5d, 0xae, 0xc7, 0x86,
10163 + 0x79, 0x80, 0xa3, 0x24,
10164 + 0x8c, 0xe3, 0x57, 0x8f,
10165 + 0xc7, 0x5f, 0x1b, 0x0f,
10166 + 0x2d, 0xf8, 0x9d, 0x30,
10167 + 0x6f, 0xa4, 0x52, 0xcd,
10168 + 0xe0, 0x7a, 0x04, 0x8a,
10169 + 0xde, 0xd9, 0x26, 0x56,
10172 +void dwc_run_dh_test_vectors(void *mem_ctx)
10174 + uint8_t pkd[384];
10175 + uint8_t pkh[384];
10176 + uint8_t hashd[32];
10177 + uint8_t hashh[32];
10182 + DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
10184 + /* compute the PKd and SHA-256(PKd || Nd) */
10185 + DWC_PRINTF("Computing PKd\n");
10186 + dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
10188 + /* compute the PKd and SHA-256(PKh || Nd) */
10189 + DWC_PRINTF("Computing PKh\n");
10190 + dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
10192 + /* compute the dhkey */
10193 + dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
10195 +#endif /* DH_TEST_VECTORS */
10197 +#endif /* !CONFIG_MACH_IPMATE */
10199 +#endif /* DWC_CRYPTOLIB */
10201 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.h
10203 +/* =========================================================================
10204 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.h $
10205 + * $Revision: #4 $
10206 + * $Date: 2010/09/28 $
10207 + * $Change: 1596182 $
10209 + * Synopsys Portability Library Software and documentation
10210 + * (hereinafter, "Software") is an Unsupported proprietary work of
10211 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
10212 + * between Synopsys and you.
10214 + * The Software IS NOT an item of Licensed Software or Licensed Product
10215 + * under any End User Software License Agreement or Agreement for
10216 + * Licensed Product with Synopsys or any supplement thereto. You are
10217 + * permitted to use and redistribute this Software in source and binary
10218 + * forms, with or without modification, provided that redistributions
10219 + * of source code must retain this notice. You may not view, use,
10220 + * disclose, copy or distribute this file or any information contained
10221 + * herein except pursuant to this license grant from Synopsys. If you
10222 + * do not agree with this notice, including the disclaimer below, then
10223 + * you are not authorized to use the Software.
10225 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
10226 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10227 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
10228 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
10229 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
10230 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
10231 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
10232 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
10233 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10234 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
10235 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
10237 + * ========================================================================= */
10238 +#ifndef _DWC_DH_H_
10239 +#define _DWC_DH_H_
10241 +#ifdef __cplusplus
10245 +#include "dwc_os.h"
10249 + * This file defines the common functions on device and host for performing
10250 + * numeric association as defined in the WUSB spec. They are only to be
10251 + * used internally by the DWC UWB modules. */
10253 +extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
10254 +extern int dwc_dh_hmac_sha256(uint8_t *message, uint32_t messagelen,
10255 + uint8_t *key, uint32_t keylen,
10257 +extern int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
10258 + void *exp, uint32_t exp_len,
10259 + void *mod, uint32_t mod_len,
10262 +/** Computes PKD or PKH, and SHA-256(PKd || Nd)
10264 + * PK = g^exp mod p.
10267 + * Nd = Number of digits on the device.
10270 + * exp = A 32-byte buffer to be filled with a randomly generated number.
10271 + * used as either A or B.
10272 + * pk = A 384-byte buffer to be filled with the PKH or PKD.
10273 + * hash = A 32-byte buffer to be filled with SHA-256(PK || ND).
10275 +extern int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash);
10277 +/** Computes the DHKEY, and VD.
10279 + * If called from host, then it will comput DHKEY=PKD^exp % p.
10280 + * If called from device, then it will comput DHKEY=PKH^exp % p.
10283 + * pkd = The PKD value.
10284 + * pkh = The PKH value.
10285 + * exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk.
10286 + * is_host = Set to non zero if a WUSB host is calling this function.
10290 + * dd = A pointer to an buffer to be set to the displayed digits string to be shown
10291 + * to the user. This buffer should be at 5 bytes long to hold 4 digits plus a
10292 + * null termination character. This buffer can be used directly for display.
10293 + * ck = A 16-byte buffer to be filled with the CK.
10294 + * kdk = A 32-byte buffer to be filled with the KDK.
10296 +extern int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
10297 + uint8_t *exp, int is_host,
10298 + char *dd, uint8_t *ck, uint8_t *kdk);
10300 +#ifdef DH_TEST_VECTORS
10301 +extern void dwc_run_dh_test_vectors(void);
10304 +#ifdef __cplusplus
10308 +#endif /* _DWC_DH_H_ */
10310 +++ b/drivers/usb/host/dwc_common_port/dwc_list.h
10312 +/* $OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $ */
10313 +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
10316 + * Copyright (c) 1991, 1993
10317 + * The Regents of the University of California. All rights reserved.
10319 + * Redistribution and use in source and binary forms, with or without
10320 + * modification, are permitted provided that the following conditions
10322 + * 1. Redistributions of source code must retain the above copyright
10323 + * notice, this list of conditions and the following disclaimer.
10324 + * 2. Redistributions in binary form must reproduce the above copyright
10325 + * notice, this list of conditions and the following disclaimer in the
10326 + * documentation and/or other materials provided with the distribution.
10327 + * 3. Neither the name of the University nor the names of its contributors
10328 + * may be used to endorse or promote products derived from this software
10329 + * without specific prior written permission.
10331 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
10332 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10333 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10334 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
10335 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10336 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10337 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10338 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10339 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10340 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10343 + * @(#)queue.h 8.5 (Berkeley) 8/20/94
10346 +#ifndef _DWC_LIST_H_
10347 +#define _DWC_LIST_H_
10349 +#ifdef __cplusplus
10355 + * This file defines linked list operations. It is derived from BSD with
10356 + * only the MACRO names being prefixed with DWC_. This is because a few of
10357 + * these names conflict with those on Linux. For documentation on use, see the
10358 + * inline comments in the source code. The original license for this source
10359 + * code applies and is preserved in the dwc_list.h source file.
10363 + * This file defines five types of data structures: singly-linked lists,
10364 + * lists, simple queues, tail queues, and circular queues.
10367 + * A singly-linked list is headed by a single forward pointer. The elements
10368 + * are singly linked for minimum space and pointer manipulation overhead at
10369 + * the expense of O(n) removal for arbitrary elements. New elements can be
10370 + * added to the list after an existing element or at the head of the list.
10371 + * Elements being removed from the head of the list should use the explicit
10372 + * macro for this purpose for optimum efficiency. A singly-linked list may
10373 + * only be traversed in the forward direction. Singly-linked lists are ideal
10374 + * for applications with large datasets and few or no removals or for
10375 + * implementing a LIFO queue.
10377 + * A list is headed by a single forward pointer (or an array of forward
10378 + * pointers for a hash table header). The elements are doubly linked
10379 + * so that an arbitrary element can be removed without a need to
10380 + * traverse the list. New elements can be added to the list before
10381 + * or after an existing element or at the head of the list. A list
10382 + * may only be traversed in the forward direction.
10384 + * A simple queue is headed by a pair of pointers, one the head of the
10385 + * list and the other to the tail of the list. The elements are singly
10386 + * linked to save space, so elements can only be removed from the
10387 + * head of the list. New elements can be added to the list before or after
10388 + * an existing element, at the head of the list, or at the end of the
10389 + * list. A simple queue may only be traversed in the forward direction.
10391 + * A tail queue is headed by a pair of pointers, one to the head of the
10392 + * list and the other to the tail of the list. The elements are doubly
10393 + * linked so that an arbitrary element can be removed without a need to
10394 + * traverse the list. New elements can be added to the list before or
10395 + * after an existing element, at the head of the list, or at the end of
10396 + * the list. A tail queue may be traversed in either direction.
10398 + * A circle queue is headed by a pair of pointers, one to the head of the
10399 + * list and the other to the tail of the list. The elements are doubly
10400 + * linked so that an arbitrary element can be removed without a need to
10401 + * traverse the list. New elements can be added to the list before or after
10402 + * an existing element, at the head of the list, or at the end of the list.
10403 + * A circle queue may be traversed in either direction, but has a more
10404 + * complex end of list detection.
10406 + * For details on the use of these macros, see the queue(3) manual page.
10410 + * Double-linked List.
10413 +typedef struct dwc_list_link {
10414 + struct dwc_list_link *next;
10415 + struct dwc_list_link *prev;
10416 +} dwc_list_link_t;
10418 +#define DWC_LIST_INIT(link) do { \
10419 + (link)->next = (link); \
10420 + (link)->prev = (link); \
10423 +#define DWC_LIST_FIRST(link) ((link)->next)
10424 +#define DWC_LIST_LAST(link) ((link)->prev)
10425 +#define DWC_LIST_END(link) (link)
10426 +#define DWC_LIST_NEXT(link) ((link)->next)
10427 +#define DWC_LIST_PREV(link) ((link)->prev)
10428 +#define DWC_LIST_EMPTY(link) \
10429 + (DWC_LIST_FIRST(link) == DWC_LIST_END(link))
10430 +#define DWC_LIST_ENTRY(link, type, field) \
10431 + (type *)((uint8_t *)(link) - (size_t)(&((type *)0)->field))
10434 +#define DWC_LIST_INSERT_HEAD(list, link) do { \
10435 + (link)->next = (list)->next; \
10436 + (link)->prev = (list); \
10437 + (list)->next->prev = (link); \
10438 + (list)->next = (link); \
10441 +#define DWC_LIST_INSERT_TAIL(list, link) do { \
10442 + (link)->next = (list); \
10443 + (link)->prev = (list)->prev; \
10444 + (list)->prev->next = (link); \
10445 + (list)->prev = (link); \
10448 +#define DWC_LIST_INSERT_HEAD(list, link) do { \
10449 + dwc_list_link_t *__next__ = (list)->next; \
10450 + __next__->prev = (link); \
10451 + (link)->next = __next__; \
10452 + (link)->prev = (list); \
10453 + (list)->next = (link); \
10456 +#define DWC_LIST_INSERT_TAIL(list, link) do { \
10457 + dwc_list_link_t *__prev__ = (list)->prev; \
10458 + (list)->prev = (link); \
10459 + (link)->next = (list); \
10460 + (link)->prev = __prev__; \
10461 + __prev__->next = (link); \
10466 +static inline void __list_add(struct list_head *new,
10467 + struct list_head *prev,
10468 + struct list_head *next)
10470 + next->prev = new;
10471 + new->next = next;
10472 + new->prev = prev;
10473 + prev->next = new;
10476 +static inline void list_add(struct list_head *new, struct list_head *head)
10478 + __list_add(new, head, head->next);
10481 +static inline void list_add_tail(struct list_head *new, struct list_head *head)
10483 + __list_add(new, head->prev, head);
10486 +static inline void __list_del(struct list_head * prev, struct list_head * next)
10488 + next->prev = prev;
10489 + prev->next = next;
10492 +static inline void list_del(struct list_head *entry)
10494 + __list_del(entry->prev, entry->next);
10495 + entry->next = LIST_POISON1;
10496 + entry->prev = LIST_POISON2;
10500 +#define DWC_LIST_REMOVE(link) do { \
10501 + (link)->next->prev = (link)->prev; \
10502 + (link)->prev->next = (link)->next; \
10505 +#define DWC_LIST_REMOVE_INIT(link) do { \
10506 + DWC_LIST_REMOVE(link); \
10507 + DWC_LIST_INIT(link); \
10510 +#define DWC_LIST_MOVE_HEAD(list, link) do { \
10511 + DWC_LIST_REMOVE(link); \
10512 + DWC_LIST_INSERT_HEAD(list, link); \
10515 +#define DWC_LIST_MOVE_TAIL(list, link) do { \
10516 + DWC_LIST_REMOVE(link); \
10517 + DWC_LIST_INSERT_TAIL(list, link); \
10520 +#define DWC_LIST_FOREACH(var, list) \
10521 + for((var) = DWC_LIST_FIRST(list); \
10522 + (var) != DWC_LIST_END(list); \
10523 + (var) = DWC_LIST_NEXT(var))
10525 +#define DWC_LIST_FOREACH_SAFE(var, var2, list) \
10526 + for((var) = DWC_LIST_FIRST(list), (var2) = DWC_LIST_NEXT(var); \
10527 + (var) != DWC_LIST_END(list); \
10528 + (var) = (var2), (var2) = DWC_LIST_NEXT(var2))
10530 +#define DWC_LIST_FOREACH_REVERSE(var, list) \
10531 + for((var) = DWC_LIST_LAST(list); \
10532 + (var) != DWC_LIST_END(list); \
10533 + (var) = DWC_LIST_PREV(var))
10536 + * Singly-linked List definitions.
10538 +#define DWC_SLIST_HEAD(name, type) \
10540 + struct type *slh_first; /* first element */ \
10543 +#define DWC_SLIST_HEAD_INITIALIZER(head) \
10546 +#define DWC_SLIST_ENTRY(type) \
10548 + struct type *sle_next; /* next element */ \
10552 + * Singly-linked List access methods.
10554 +#define DWC_SLIST_FIRST(head) ((head)->slh_first)
10555 +#define DWC_SLIST_END(head) NULL
10556 +#define DWC_SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
10557 +#define DWC_SLIST_NEXT(elm, field) ((elm)->field.sle_next)
10559 +#define DWC_SLIST_FOREACH(var, head, field) \
10560 + for((var) = SLIST_FIRST(head); \
10561 + (var) != SLIST_END(head); \
10562 + (var) = SLIST_NEXT(var, field))
10564 +#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field) \
10565 + for((varp) = &SLIST_FIRST((head)); \
10566 + ((var) = *(varp)) != SLIST_END(head); \
10567 + (varp) = &SLIST_NEXT((var), field))
10570 + * Singly-linked List functions.
10572 +#define DWC_SLIST_INIT(head) { \
10573 + SLIST_FIRST(head) = SLIST_END(head); \
10576 +#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do { \
10577 + (elm)->field.sle_next = (slistelm)->field.sle_next; \
10578 + (slistelm)->field.sle_next = (elm); \
10581 +#define DWC_SLIST_INSERT_HEAD(head, elm, field) do { \
10582 + (elm)->field.sle_next = (head)->slh_first; \
10583 + (head)->slh_first = (elm); \
10586 +#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do { \
10587 + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
10590 +#define DWC_SLIST_REMOVE_HEAD(head, field) do { \
10591 + (head)->slh_first = (head)->slh_first->field.sle_next; \
10594 +#define DWC_SLIST_REMOVE(head, elm, type, field) do { \
10595 + if ((head)->slh_first == (elm)) { \
10596 + SLIST_REMOVE_HEAD((head), field); \
10599 + struct type *curelm = (head)->slh_first; \
10600 + while( curelm->field.sle_next != (elm) ) \
10601 + curelm = curelm->field.sle_next; \
10602 + curelm->field.sle_next = \
10603 + curelm->field.sle_next->field.sle_next; \
10608 + * Simple queue definitions.
10610 +#define DWC_SIMPLEQ_HEAD(name, type) \
10612 + struct type *sqh_first; /* first element */ \
10613 + struct type **sqh_last; /* addr of last next element */ \
10616 +#define DWC_SIMPLEQ_HEAD_INITIALIZER(head) \
10617 + { NULL, &(head).sqh_first }
10619 +#define DWC_SIMPLEQ_ENTRY(type) \
10621 + struct type *sqe_next; /* next element */ \
10625 + * Simple queue access methods.
10627 +#define DWC_SIMPLEQ_FIRST(head) ((head)->sqh_first)
10628 +#define DWC_SIMPLEQ_END(head) NULL
10629 +#define DWC_SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
10630 +#define DWC_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
10632 +#define DWC_SIMPLEQ_FOREACH(var, head, field) \
10633 + for((var) = SIMPLEQ_FIRST(head); \
10634 + (var) != SIMPLEQ_END(head); \
10635 + (var) = SIMPLEQ_NEXT(var, field))
10638 + * Simple queue functions.
10640 +#define DWC_SIMPLEQ_INIT(head) do { \
10641 + (head)->sqh_first = NULL; \
10642 + (head)->sqh_last = &(head)->sqh_first; \
10645 +#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
10646 + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
10647 + (head)->sqh_last = &(elm)->field.sqe_next; \
10648 + (head)->sqh_first = (elm); \
10651 +#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
10652 + (elm)->field.sqe_next = NULL; \
10653 + *(head)->sqh_last = (elm); \
10654 + (head)->sqh_last = &(elm)->field.sqe_next; \
10657 +#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
10658 + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
10659 + (head)->sqh_last = &(elm)->field.sqe_next; \
10660 + (listelm)->field.sqe_next = (elm); \
10663 +#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do { \
10664 + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
10665 + (head)->sqh_last = &(head)->sqh_first; \
10669 + * Tail queue definitions.
10671 +#define DWC_TAILQ_HEAD(name, type) \
10673 + struct type *tqh_first; /* first element */ \
10674 + struct type **tqh_last; /* addr of last next element */ \
10677 +#define DWC_TAILQ_HEAD_INITIALIZER(head) \
10678 + { NULL, &(head).tqh_first }
10680 +#define DWC_TAILQ_ENTRY(type) \
10682 + struct type *tqe_next; /* next element */ \
10683 + struct type **tqe_prev; /* address of previous next element */ \
10687 + * tail queue access methods
10689 +#define DWC_TAILQ_FIRST(head) ((head)->tqh_first)
10690 +#define DWC_TAILQ_END(head) NULL
10691 +#define DWC_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
10692 +#define DWC_TAILQ_LAST(head, headname) \
10693 + (*(((struct headname *)((head)->tqh_last))->tqh_last))
10695 +#define DWC_TAILQ_PREV(elm, headname, field) \
10696 + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
10697 +#define DWC_TAILQ_EMPTY(head) \
10698 + (TAILQ_FIRST(head) == TAILQ_END(head))
10700 +#define DWC_TAILQ_FOREACH(var, head, field) \
10701 + for((var) = TAILQ_FIRST(head); \
10702 + (var) != TAILQ_END(head); \
10703 + (var) = TAILQ_NEXT(var, field))
10705 +#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
10706 + for((var) = TAILQ_LAST(head, headname); \
10707 + (var) != TAILQ_END(head); \
10708 + (var) = TAILQ_PREV(var, headname, field))
10711 + * Tail queue functions.
10713 +#define DWC_TAILQ_INIT(head) do { \
10714 + (head)->tqh_first = NULL; \
10715 + (head)->tqh_last = &(head)->tqh_first; \
10718 +#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do { \
10719 + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
10720 + (head)->tqh_first->field.tqe_prev = \
10721 + &(elm)->field.tqe_next; \
10723 + (head)->tqh_last = &(elm)->field.tqe_next; \
10724 + (head)->tqh_first = (elm); \
10725 + (elm)->field.tqe_prev = &(head)->tqh_first; \
10728 +#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do { \
10729 + (elm)->field.tqe_next = NULL; \
10730 + (elm)->field.tqe_prev = (head)->tqh_last; \
10731 + *(head)->tqh_last = (elm); \
10732 + (head)->tqh_last = &(elm)->field.tqe_next; \
10735 +#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
10736 + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
10737 + (elm)->field.tqe_next->field.tqe_prev = \
10738 + &(elm)->field.tqe_next; \
10740 + (head)->tqh_last = &(elm)->field.tqe_next; \
10741 + (listelm)->field.tqe_next = (elm); \
10742 + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
10745 +#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
10746 + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
10747 + (elm)->field.tqe_next = (listelm); \
10748 + *(listelm)->field.tqe_prev = (elm); \
10749 + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
10752 +#define DWC_TAILQ_REMOVE(head, elm, field) do { \
10753 + if (((elm)->field.tqe_next) != NULL) \
10754 + (elm)->field.tqe_next->field.tqe_prev = \
10755 + (elm)->field.tqe_prev; \
10757 + (head)->tqh_last = (elm)->field.tqe_prev; \
10758 + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
10761 +#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do { \
10762 + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
10763 + (elm2)->field.tqe_next->field.tqe_prev = \
10764 + &(elm2)->field.tqe_next; \
10766 + (head)->tqh_last = &(elm2)->field.tqe_next; \
10767 + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
10768 + *(elm2)->field.tqe_prev = (elm2); \
10772 + * Circular queue definitions.
10774 +#define DWC_CIRCLEQ_HEAD(name, type) \
10776 + struct type *cqh_first; /* first element */ \
10777 + struct type *cqh_last; /* last element */ \
10780 +#define DWC_CIRCLEQ_HEAD_INITIALIZER(head) \
10781 + { DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
10783 +#define DWC_CIRCLEQ_ENTRY(type) \
10785 + struct type *cqe_next; /* next element */ \
10786 + struct type *cqe_prev; /* previous element */ \
10790 + * Circular queue access methods
10792 +#define DWC_CIRCLEQ_FIRST(head) ((head)->cqh_first)
10793 +#define DWC_CIRCLEQ_LAST(head) ((head)->cqh_last)
10794 +#define DWC_CIRCLEQ_END(head) ((void *)(head))
10795 +#define DWC_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
10796 +#define DWC_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
10797 +#define DWC_CIRCLEQ_EMPTY(head) \
10798 + (DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
10800 +#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
10802 +#define DWC_CIRCLEQ_FOREACH(var, head, field) \
10803 + for((var) = DWC_CIRCLEQ_FIRST(head); \
10804 + (var) != DWC_CIRCLEQ_END(head); \
10805 + (var) = DWC_CIRCLEQ_NEXT(var, field))
10807 +#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field) \
10808 + for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
10809 + (var) != DWC_CIRCLEQ_END(head); \
10810 + (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
10812 +#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field) \
10813 + for((var) = DWC_CIRCLEQ_LAST(head); \
10814 + (var) != DWC_CIRCLEQ_END(head); \
10815 + (var) = DWC_CIRCLEQ_PREV(var, field))
10818 + * Circular queue functions.
10820 +#define DWC_CIRCLEQ_INIT(head) do { \
10821 + (head)->cqh_first = DWC_CIRCLEQ_END(head); \
10822 + (head)->cqh_last = DWC_CIRCLEQ_END(head); \
10825 +#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do { \
10826 + (elm)->field.cqe_next = NULL; \
10827 + (elm)->field.cqe_prev = NULL; \
10830 +#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
10831 + (elm)->field.cqe_next = (listelm)->field.cqe_next; \
10832 + (elm)->field.cqe_prev = (listelm); \
10833 + if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
10834 + (head)->cqh_last = (elm); \
10836 + (listelm)->field.cqe_next->field.cqe_prev = (elm); \
10837 + (listelm)->field.cqe_next = (elm); \
10840 +#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
10841 + (elm)->field.cqe_next = (listelm); \
10842 + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
10843 + if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
10844 + (head)->cqh_first = (elm); \
10846 + (listelm)->field.cqe_prev->field.cqe_next = (elm); \
10847 + (listelm)->field.cqe_prev = (elm); \
10850 +#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
10851 + (elm)->field.cqe_next = (head)->cqh_first; \
10852 + (elm)->field.cqe_prev = DWC_CIRCLEQ_END(head); \
10853 + if ((head)->cqh_last == DWC_CIRCLEQ_END(head)) \
10854 + (head)->cqh_last = (elm); \
10856 + (head)->cqh_first->field.cqe_prev = (elm); \
10857 + (head)->cqh_first = (elm); \
10860 +#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
10861 + (elm)->field.cqe_next = DWC_CIRCLEQ_END(head); \
10862 + (elm)->field.cqe_prev = (head)->cqh_last; \
10863 + if ((head)->cqh_first == DWC_CIRCLEQ_END(head)) \
10864 + (head)->cqh_first = (elm); \
10866 + (head)->cqh_last->field.cqe_next = (elm); \
10867 + (head)->cqh_last = (elm); \
10870 +#define DWC_CIRCLEQ_REMOVE(head, elm, field) do { \
10871 + if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
10872 + (head)->cqh_last = (elm)->field.cqe_prev; \
10874 + (elm)->field.cqe_next->field.cqe_prev = \
10875 + (elm)->field.cqe_prev; \
10876 + if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
10877 + (head)->cqh_first = (elm)->field.cqe_next; \
10879 + (elm)->field.cqe_prev->field.cqe_next = \
10880 + (elm)->field.cqe_next; \
10883 +#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do { \
10884 + DWC_CIRCLEQ_REMOVE(head, elm, field); \
10885 + DWC_CIRCLEQ_INIT_ENTRY(elm, field); \
10888 +#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
10889 + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
10890 + DWC_CIRCLEQ_END(head)) \
10891 + (head).cqh_last = (elm2); \
10893 + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
10894 + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
10895 + DWC_CIRCLEQ_END(head)) \
10896 + (head).cqh_first = (elm2); \
10898 + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
10901 +#ifdef __cplusplus
10905 +#endif /* _DWC_LIST_H_ */
10907 +++ b/drivers/usb/host/dwc_common_port/dwc_mem.c
10909 +/* Memory Debugging */
10910 +#ifdef DWC_DEBUG_MEMORY
10912 +#include "dwc_os.h"
10913 +#include "dwc_list.h"
10915 +struct allocation {
10922 + DWC_CIRCLEQ_ENTRY(allocation) entry;
10925 +DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
10927 +struct allocation_manager {
10929 + struct allocation_queue allocations;
10940 +static struct allocation_manager *manager = NULL;
10942 +static int add_allocation(void *ctx, uint32_t size, char const *func, int line, void *addr,
10945 + struct allocation *a;
10947 + DWC_ASSERT(manager != NULL, "manager not allocated");
10949 + a = __DWC_ALLOC_ATOMIC(manager->mem_ctx, sizeof(*a));
10951 + return -DWC_E_NO_MEMORY;
10954 + a->func = __DWC_ALLOC_ATOMIC(manager->mem_ctx, DWC_STRLEN(func) + 1);
10956 + __DWC_FREE(manager->mem_ctx, a);
10957 + return -DWC_E_NO_MEMORY;
10960 + DWC_MEMCPY(a->func, func, DWC_STRLEN(func) + 1);
10966 + DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
10968 + /* Update stats */
10970 + manager->num_active++;
10971 + manager->total += size;
10972 + manager->cur += size;
10974 + if (manager->max < manager->cur) {
10975 + manager->max = manager->cur;
10981 +static struct allocation *find_allocation(void *ctx, void *addr)
10983 + struct allocation *a;
10985 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
10986 + if (a->ctx == ctx && a->addr == addr) {
10994 +static void free_allocation(void *ctx, void *addr, char const *func, int line)
10996 + struct allocation *a = find_allocation(ctx, addr);
11000 + "Free of address %p that was never allocated or already freed %s:%d",
11001 + addr, func, line);
11005 + DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
11007 + manager->num_active--;
11008 + manager->num_freed++;
11009 + manager->cur -= a->size;
11010 + __DWC_FREE(manager->mem_ctx, a->func);
11011 + __DWC_FREE(manager->mem_ctx, a);
11014 +int dwc_memory_debug_start(void *mem_ctx)
11016 + DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
11019 + return -DWC_E_BUSY;
11022 + manager = __DWC_ALLOC(mem_ctx, sizeof(*manager));
11024 + return -DWC_E_NO_MEMORY;
11027 + DWC_CIRCLEQ_INIT(&manager->allocations);
11028 + manager->mem_ctx = mem_ctx;
11029 + manager->num = 0;
11030 + manager->num_freed = 0;
11031 + manager->num_active = 0;
11032 + manager->total = 0;
11033 + manager->cur = 0;
11034 + manager->max = 0;
11039 +void dwc_memory_debug_stop(void)
11041 + struct allocation *a;
11043 + dwc_memory_debug_report();
11045 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
11046 + DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
11047 + free_allocation(a->ctx, a->addr, NULL, -1);
11050 + __DWC_FREE(manager->mem_ctx, manager);
11053 +void dwc_memory_debug_report(void)
11055 + struct allocation *a;
11057 + DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
11058 + DWC_PRINTF("Num Allocations = %d\n", manager->num);
11059 + DWC_PRINTF("Freed = %d\n", manager->num_freed);
11060 + DWC_PRINTF("Active = %d\n", manager->num_active);
11061 + DWC_PRINTF("Current Memory Used = %d\n", manager->cur);
11062 + DWC_PRINTF("Total Memory Used = %d\n", manager->total);
11063 + DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
11064 + DWC_PRINTF("Unfreed allocations:\n");
11066 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
11067 + DWC_PRINTF(" addr=%p, size=%d from %s:%d, DMA=%d\n",
11068 + a->addr, a->size, a->func, a->line, a->dma);
11072 +/* The replacement functions */
11073 +void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line)
11075 + void *addr = __DWC_ALLOC(mem_ctx, size);
11081 + if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
11082 + __DWC_FREE(mem_ctx, addr);
11089 +void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func,
11092 + void *addr = __DWC_ALLOC_ATOMIC(mem_ctx, size);
11098 + if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
11099 + __DWC_FREE(mem_ctx, addr);
11106 +void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line)
11108 + free_allocation(mem_ctx, addr, func, line);
11109 + __DWC_FREE(mem_ctx, addr);
11112 +void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
11113 + char const *func, int line)
11115 + void *addr = __DWC_DMA_ALLOC(dma_ctx, size, dma_addr);
11121 + if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
11122 + __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
11129 +void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size,
11130 + dwc_dma_t *dma_addr, char const *func, int line)
11132 + void *addr = __DWC_DMA_ALLOC_ATOMIC(dma_ctx, size, dma_addr);
11138 + if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
11139 + __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
11146 +void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
11147 + dwc_dma_t dma_addr, char const *func, int line)
11149 + free_allocation(dma_ctx, virt_addr, func, line);
11150 + __DWC_DMA_FREE(dma_ctx, size, virt_addr, dma_addr);
11153 +#endif /* DWC_DEBUG_MEMORY */
11155 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.c
11157 +/* Bignum routines adapted from PUTTY sources. PuTTY copyright notice follows.
11159 + * PuTTY is copyright 1997-2007 Simon Tatham.
11161 + * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
11162 + * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
11163 + * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
11164 + * Kuhn, and CORE SDI S.A.
11166 + * Permission is hereby granted, free of charge, to any person
11167 + * obtaining a copy of this software and associated documentation files
11168 + * (the "Software"), to deal in the Software without restriction,
11169 + * including without limitation the rights to use, copy, modify, merge,
11170 + * publish, distribute, sublicense, and/or sell copies of the Software,
11171 + * and to permit persons to whom the Software is furnished to do so,
11172 + * subject to the following conditions:
11174 + * The above copyright notice and this permission notice shall be
11175 + * included in all copies or substantial portions of the Software.
11177 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11178 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11179 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11180 + * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
11181 + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
11182 + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
11183 + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11186 +#ifdef DWC_CRYPTOLIB
11188 +#ifndef CONFIG_MACH_IPMATE
11190 +#include "dwc_modpow.h"
11192 +#define BIGNUM_INT_MASK 0xFFFFFFFFUL
11193 +#define BIGNUM_TOP_BIT 0x80000000UL
11194 +#define BIGNUM_INT_BITS 32
11197 +static void *snmalloc(void *mem_ctx, size_t n, size_t size)
11201 + if (size == 0) size = 1;
11202 + p = dwc_alloc(mem_ctx, size);
11206 +#define snewn(ctx, n, type) ((type *)snmalloc((ctx), (n), sizeof(type)))
11207 +#define sfree dwc_free
11211 + * * Do not call the DIVMOD_WORD macro with expressions such as array
11212 + * subscripts, as some implementations object to this (see below).
11213 + * * Note that none of the division methods below will cope if the
11214 + * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
11215 + * to avoid this case.
11216 + * If this condition occurs, in the case of the x86 DIV instruction,
11217 + * an overflow exception will occur, which (according to a correspondent)
11218 + * will manifest on Windows as something like
11219 + * 0xC0000095: Integer overflow
11220 + * The C variant won't give the right answer, either.
11223 +#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
11225 +#if defined __GNUC__ && defined __i386__
11226 +#define DIVMOD_WORD(q, r, hi, lo, w) \
11227 + __asm__("div %2" : \
11228 + "=d" (r), "=a" (q) : \
11229 + "r" (w), "d" (hi), "a" (lo))
11231 +#define DIVMOD_WORD(q, r, hi, lo, w) do { \
11232 + BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
11241 +#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
11243 +#define BIGNUM_INTERNAL
11245 +static Bignum newbn(void *mem_ctx, int length)
11247 + Bignum b = snewn(mem_ctx, length + 1, BignumInt);
11249 + //abort(); /* FIXME */
11250 + DWC_MEMSET(b, 0, (length + 1) * sizeof(*b));
11255 +void freebn(void *mem_ctx, Bignum b)
11258 + * Burn the evidence, just in case.
11260 + DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1));
11261 + sfree(mem_ctx, b);
11265 + * Compute c = a * b.
11266 + * Input is in the first len words of a and b.
11267 + * Result is returned in the first 2*len words of c.
11269 +static void internal_mul(BignumInt *a, BignumInt *b,
11270 + BignumInt *c, int len)
11275 + for (j = 0; j < 2 * len; j++)
11278 + for (i = len - 1; i >= 0; i--) {
11280 + for (j = len - 1; j >= 0; j--) {
11281 + t += MUL_WORD(a[i], (BignumDblInt) b[j]);
11282 + t += (BignumDblInt) c[i + j + 1];
11283 + c[i + j + 1] = (BignumInt) t;
11284 + t = t >> BIGNUM_INT_BITS;
11286 + c[i] = (BignumInt) t;
11290 +static void internal_add_shifted(BignumInt *number,
11291 + unsigned n, int shift)
11293 + int word = 1 + (shift / BIGNUM_INT_BITS);
11294 + int bshift = shift % BIGNUM_INT_BITS;
11295 + BignumDblInt addend;
11297 + addend = (BignumDblInt)n << bshift;
11300 + addend += number[word];
11301 + number[word] = (BignumInt) addend & BIGNUM_INT_MASK;
11302 + addend >>= BIGNUM_INT_BITS;
11308 + * Compute a = a % m.
11309 + * Input in first alen words of a and first mlen words of m.
11310 + * Output in first alen words of a
11311 + * (of which first alen-mlen words will be zero).
11312 + * The MSW of m MUST have its high bit set.
11313 + * Quotient is accumulated in the `quotient' array, which is a Bignum
11314 + * rather than the internal bigendian format. Quotient parts are shifted
11315 + * left by `qshift' before adding into quot.
11317 +static void internal_mod(BignumInt *a, int alen,
11318 + BignumInt *m, int mlen,
11319 + BignumInt *quot, int qshift)
11321 + BignumInt m0, m1;
11331 + for (i = 0; i <= alen - mlen; i++) {
11333 + unsigned int q, r, c, ai1;
11342 + if (i == alen - 1)
11347 + /* Find q = h:a[i] / m0 */
11352 + * To illustrate it, suppose a BignumInt is 8 bits, and
11353 + * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then
11354 + * our initial division will be 0xA123 / 0xA1, which
11355 + * will give a quotient of 0x100 and a divide overflow.
11356 + * However, the invariants in this division algorithm
11357 + * are not violated, since the full number A1:23:... is
11358 + * _less_ than the quotient prefix A1:B2:... and so the
11359 + * following correction loop would have sorted it out.
11361 + * In this situation we set q to be the largest
11362 + * quotient we _can_ stomach (0xFF, of course).
11364 + q = BIGNUM_INT_MASK;
11366 + /* Macro doesn't want an array subscript expression passed
11367 + * into it (see definition), so use a temporary. */
11368 + BignumInt tmplo = a[i];
11369 + DIVMOD_WORD(q, r, h, tmplo, m0);
11371 + /* Refine our estimate of q by looking at
11372 + h:a[i]:a[i+1] / m0:m1 */
11373 + t = MUL_WORD(m1, q);
11374 + if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
11377 + r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */
11378 + if (r >= (BignumDblInt) m0 &&
11379 + t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
11383 + /* Subtract q * m from a[i...] */
11385 + for (k = mlen - 1; k >= 0; k--) {
11386 + t = MUL_WORD(q, m[k]);
11388 + c = (unsigned)(t >> BIGNUM_INT_BITS);
11389 + if ((BignumInt) t > a[i + k])
11391 + a[i + k] -= (BignumInt) t;
11394 + /* Add back m in case of borrow */
11397 + for (k = mlen - 1; k >= 0; k--) {
11400 + a[i + k] = (BignumInt) t;
11401 + t = t >> BIGNUM_INT_BITS;
11406 + internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
11411 + * Compute p % mod.
11412 + * The most significant word of mod MUST be non-zero.
11413 + * We assume that the result array is the same size as the mod array.
11414 + * We optionally write out a quotient if `quotient' is non-NULL.
11415 + * We can avoid writing out the result if `result' is NULL.
11417 +void bigdivmod(void *mem_ctx, Bignum p, Bignum mod, Bignum result, Bignum quotient)
11419 + BignumInt *n, *m;
11421 + int plen, mlen, i, j;
11423 + /* Allocate m of size mlen, copy mod to m */
11424 + /* We use big endian internally */
11426 + m = snewn(mem_ctx, mlen, BignumInt);
11428 + //abort(); /* FIXME */
11429 + for (j = 0; j < mlen; j++)
11430 + m[j] = mod[mod[0] - j];
11432 + /* Shift m left to make msb bit set */
11433 + for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
11434 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
11437 + for (i = 0; i < mlen - 1; i++)
11438 + m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift));
11439 + m[mlen - 1] = m[mlen - 1] << mshift;
11443 + /* Ensure plen > mlen */
11444 + if (plen <= mlen)
11447 + /* Allocate n of size plen, copy p to n */
11448 + n = snewn(mem_ctx, plen, BignumInt);
11450 + //abort(); /* FIXME */
11451 + for (j = 0; j < plen; j++)
11453 + for (j = 1; j <= (int)p[0]; j++)
11454 + n[plen - j] = p[j];
11456 + /* Main computation */
11457 + internal_mod(n, plen, m, mlen, quotient, mshift);
11459 + /* Fixup result in case the modulus was shifted */
11461 + for (i = plen - mlen - 1; i < plen - 1; i++)
11462 + n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift));
11463 + n[plen - 1] = n[plen - 1] << mshift;
11464 + internal_mod(n, plen, m, mlen, quotient, 0);
11465 + for (i = plen - 1; i >= plen - mlen; i--)
11466 + n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift));
11469 + /* Copy result to buffer */
11471 + for (i = 1; i <= (int)result[0]; i++) {
11472 + int j = plen - i;
11473 + result[i] = j >= 0 ? n[j] : 0;
11477 + /* Free temporary arrays */
11478 + for (i = 0; i < mlen; i++)
11480 + sfree(mem_ctx, m);
11481 + for (i = 0; i < plen; i++)
11483 + sfree(mem_ctx, n);
11487 + * Simple remainder.
11489 +Bignum bigmod(void *mem_ctx, Bignum a, Bignum b)
11491 + Bignum r = newbn(mem_ctx, b[0]);
11492 + bigdivmod(mem_ctx, a, b, r, NULL);
11497 + * Compute (base ^ exp) % mod.
11499 +Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod)
11501 + BignumInt *a, *b, *n, *m;
11504 + Bignum base, result;
11507 + * The most significant word of mod needs to be non-zero. It
11508 + * should already be, but let's make sure.
11510 + //assert(mod[mod[0]] != 0);
11513 + * Make sure the base is smaller than the modulus, by reducing
11514 + * it modulo the modulus if not.
11516 + base = bigmod(mem_ctx, base_in, mod);
11518 + /* Allocate m of size mlen, copy mod to m */
11519 + /* We use big endian internally */
11521 + m = snewn(mem_ctx, mlen, BignumInt);
11523 + //abort(); /* FIXME */
11524 + for (j = 0; j < mlen; j++)
11525 + m[j] = mod[mod[0] - j];
11527 + /* Shift m left to make msb bit set */
11528 + for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
11529 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
11532 + for (i = 0; i < mlen - 1; i++)
11534 + (m[i] << mshift) | (m[i + 1] >>
11535 + (BIGNUM_INT_BITS - mshift));
11536 + m[mlen - 1] = m[mlen - 1] << mshift;
11539 + /* Allocate n of size mlen, copy base to n */
11540 + n = snewn(mem_ctx, mlen, BignumInt);
11542 + //abort(); /* FIXME */
11543 + i = mlen - base[0];
11544 + for (j = 0; j < i; j++)
11546 + for (j = 0; j < base[0]; j++)
11547 + n[i + j] = base[base[0] - j];
11549 + /* Allocate a and b of size 2*mlen. Set a = 1 */
11550 + a = snewn(mem_ctx, 2 * mlen, BignumInt);
11552 + //abort(); /* FIXME */
11553 + b = snewn(mem_ctx, 2 * mlen, BignumInt);
11555 + //abort(); /* FIXME */
11556 + for (i = 0; i < 2 * mlen; i++)
11558 + a[2 * mlen - 1] = 1;
11560 + /* Skip leading zero bits of exp. */
11562 + j = BIGNUM_INT_BITS - 1;
11563 + while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
11567 + j = BIGNUM_INT_BITS - 1;
11571 + /* Main computation */
11572 + while (i < exp[0]) {
11574 + internal_mul(a + mlen, a + mlen, b, mlen);
11575 + internal_mod(b, mlen * 2, m, mlen, NULL, 0);
11576 + if ((exp[exp[0] - i] & (1 << j)) != 0) {
11577 + internal_mul(b + mlen, n, a, mlen);
11578 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
11588 + j = BIGNUM_INT_BITS - 1;
11591 + /* Fixup result in case the modulus was shifted */
11593 + for (i = mlen - 1; i < 2 * mlen - 1; i++)
11595 + (a[i] << mshift) | (a[i + 1] >>
11596 + (BIGNUM_INT_BITS - mshift));
11597 + a[2 * mlen - 1] = a[2 * mlen - 1] << mshift;
11598 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
11599 + for (i = 2 * mlen - 1; i >= mlen; i--)
11601 + (a[i] >> mshift) | (a[i - 1] <<
11602 + (BIGNUM_INT_BITS - mshift));
11605 + /* Copy result to buffer */
11606 + result = newbn(mem_ctx, mod[0]);
11607 + for (i = 0; i < mlen; i++)
11608 + result[result[0] - i] = a[i + mlen];
11609 + while (result[0] > 1 && result[result[0]] == 0)
11612 + /* Free temporary arrays */
11613 + for (i = 0; i < 2 * mlen; i++)
11615 + sfree(mem_ctx, a);
11616 + for (i = 0; i < 2 * mlen; i++)
11618 + sfree(mem_ctx, b);
11619 + for (i = 0; i < mlen; i++)
11621 + sfree(mem_ctx, m);
11622 + for (i = 0; i < mlen; i++)
11624 + sfree(mem_ctx, n);
11626 + freebn(mem_ctx, base);
11634 +static __u32 dh_p[] = {
11734 +static __u32 dh_a[] = {
11746 +static __u32 dh_b[] = {
11758 +static __u32 dh_g[] = {
11767 + k = dwc_modpow(NULL, dh_g, dh_a, dh_p);
11770 + for (i=0; i<k[0]; i++) {
11771 + __u32 word32 = k[k[0] - i];
11772 + __u16 l = word32 & 0xffff;
11773 + __u16 m = (word32 & 0xffff0000) >> 16;
11774 + printf("%04x %04x ", m, l);
11775 + if (!((i + 1)%13)) printf("\n");
11779 + if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) {
11780 + printf("PASS\n\n");
11783 + printf("FAIL\n\n");
11788 +#endif /* UNITTEST */
11790 +#endif /* CONFIG_MACH_IPMATE */
11792 +#endif /*DWC_CRYPTOLIB */
11794 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.h
11798 + * See dwc_modpow.c for license and changes
11800 +#ifndef _DWC_MODPOW_H
11801 +#define _DWC_MODPOW_H
11803 +#ifdef __cplusplus
11807 +#include "dwc_os.h"
11811 + * This file defines the module exponentiation function which is only used
11812 + * internally by the DWC UWB modules for calculation of PKs during numeric
11813 + * association. The routine is taken from the PUTTY, an open source terminal
11814 + * emulator. The PUTTY License is preserved in the dwc_modpow.c file.
11818 +typedef uint32_t BignumInt;
11819 +typedef uint64_t BignumDblInt;
11820 +typedef BignumInt *Bignum;
11822 +/* Compute modular exponentiaion */
11823 +extern Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod);
11825 +#ifdef __cplusplus
11829 +#endif /* _LINUX_BIGNUM_H */
11831 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.c
11833 +#ifdef DWC_NOTIFYLIB
11835 +#include "dwc_notifier.h"
11836 +#include "dwc_list.h"
11838 +typedef struct dwc_observer {
11840 + dwc_notifier_callback_t callback;
11842 + char *notification;
11843 + DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
11846 +DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
11848 +typedef struct dwc_notifier {
11851 + struct observer_queue observers;
11852 + DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
11855 +DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
11857 +typedef struct manager {
11861 +// dwc_mutex_t *mutex;
11862 + struct notifier_queue notifiers;
11865 +static manager_t *manager = NULL;
11867 +static int create_manager(void *mem_ctx, void *wkq_ctx)
11869 + manager = dwc_alloc(mem_ctx, sizeof(manager_t));
11871 + return -DWC_E_NO_MEMORY;
11874 + DWC_CIRCLEQ_INIT(&manager->notifiers);
11876 + manager->wq = dwc_workq_alloc(wkq_ctx, "DWC Notification WorkQ");
11877 + if (!manager->wq) {
11878 + return -DWC_E_NO_MEMORY;
11884 +static void free_manager(void)
11886 + dwc_workq_free(manager->wq);
11888 + /* All notifiers must have unregistered themselves before this module
11889 + * can be removed. Hitting this assertion indicates a programmer
11891 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers),
11892 + "Notification manager being freed before all notifiers have been removed");
11893 + dwc_free(manager->mem_ctx, manager);
11897 +static void dump_manager(void)
11902 + DWC_ASSERT(manager, "Notification manager not found");
11904 + DWC_DEBUG("List of all notifiers and observers:\n");
11905 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
11906 + DWC_DEBUG("Notifier %p has observers:\n", n->object);
11907 + DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
11908 + DWC_DEBUG(" %p watching %s\n", o->observer, o->notification);
11913 +#define dump_manager(...)
11916 +static observer_t *alloc_observer(void *mem_ctx, void *observer, char *notification,
11917 + dwc_notifier_callback_t callback, void *data)
11919 + observer_t *new_observer = dwc_alloc(mem_ctx, sizeof(observer_t));
11921 + if (!new_observer) {
11925 + DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
11926 + new_observer->observer = observer;
11927 + new_observer->notification = notification;
11928 + new_observer->callback = callback;
11929 + new_observer->data = data;
11930 + return new_observer;
11933 +static void free_observer(void *mem_ctx, observer_t *observer)
11935 + dwc_free(mem_ctx, observer);
11938 +static notifier_t *alloc_notifier(void *mem_ctx, void *object)
11940 + notifier_t *notifier;
11946 + notifier = dwc_alloc(mem_ctx, sizeof(notifier_t));
11951 + DWC_CIRCLEQ_INIT(¬ifier->observers);
11952 + DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
11954 + notifier->mem_ctx = mem_ctx;
11955 + notifier->object = object;
11959 +static void free_notifier(notifier_t *notifier)
11961 + observer_t *observer;
11963 + DWC_CIRCLEQ_FOREACH(observer, ¬ifier->observers, list_entry) {
11964 + free_observer(notifier->mem_ctx, observer);
11967 + dwc_free(notifier->mem_ctx, notifier);
11970 +static notifier_t *find_notifier(void *object)
11972 + notifier_t *notifier;
11974 + DWC_ASSERT(manager, "Notification manager not found");
11980 + DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
11981 + if (notifier->object == object) {
11989 +int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx)
11991 + return create_manager(mem_ctx, wkq_ctx);
11994 +void dwc_free_notification_manager(void)
11999 +dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object)
12001 + notifier_t *notifier;
12003 + DWC_ASSERT(manager, "Notification manager not found");
12005 + notifier = find_notifier(object);
12007 + DWC_ERROR("Notifier %p is already registered\n", object);
12011 + notifier = alloc_notifier(mem_ctx, object);
12016 + DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
12018 + DWC_INFO("Notifier %p registered", object);
12024 +void dwc_unregister_notifier(dwc_notifier_t *notifier)
12026 + DWC_ASSERT(manager, "Notification manager not found");
12028 + if (!DWC_CIRCLEQ_EMPTY(¬ifier->observers)) {
12031 + DWC_ERROR("Notifier %p has active observers when removing\n", notifier->object);
12032 + DWC_CIRCLEQ_FOREACH(o, ¬ifier->observers, list_entry) {
12033 + DWC_DEBUGC(" %p watching %s\n", o->observer, o->notification);
12036 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(¬ifier->observers),
12037 + "Notifier %p has active observers when removing", notifier);
12040 + DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
12041 + free_notifier(notifier);
12043 + DWC_INFO("Notifier unregistered");
12047 +/* Add an observer to observe the notifier for a particular state, event, or notification. */
12048 +int dwc_add_observer(void *observer, void *object, char *notification,
12049 + dwc_notifier_callback_t callback, void *data)
12051 + notifier_t *notifier = find_notifier(object);
12052 + observer_t *new_observer;
12055 + DWC_ERROR("Notifier %p is not found when adding observer\n", object);
12056 + return -DWC_E_INVALID;
12059 + new_observer = alloc_observer(notifier->mem_ctx, observer, notification, callback, data);
12060 + if (!new_observer) {
12061 + return -DWC_E_NO_MEMORY;
12064 + DWC_CIRCLEQ_INSERT_TAIL(¬ifier->observers, new_observer, list_entry);
12066 + DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
12067 + observer, object, notification, callback, data);
12073 +int dwc_remove_observer(void *observer)
12077 + DWC_ASSERT(manager, "Notification manager not found");
12079 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
12083 + DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
12084 + if (o->observer == observer) {
12085 + DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
12086 + DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
12087 + o->observer, n->object, o->notification);
12088 + free_observer(n->mem_ctx, o);
12097 +typedef struct callback_data {
12099 + dwc_notifier_callback_t cb;
12103 + char *notification;
12104 + void *notification_data;
12107 +static void cb_task(void *data)
12109 + cb_data_t *cb = (cb_data_t *)data;
12111 + cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
12112 + dwc_free(cb->mem_ctx, cb);
12115 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
12119 + DWC_ASSERT(manager, "Notification manager not found");
12121 + DWC_CIRCLEQ_FOREACH(o, ¬ifier->observers, list_entry) {
12122 + int len = DWC_STRLEN(notification);
12124 + if (DWC_STRLEN(o->notification) != len) {
12128 + if (DWC_STRNCMP(o->notification, notification, len) == 0) {
12129 + cb_data_t *cb_data = dwc_alloc(notifier->mem_ctx, sizeof(cb_data_t));
12132 + DWC_ERROR("Failed to allocate callback data\n");
12136 + cb_data->mem_ctx = notifier->mem_ctx;
12137 + cb_data->cb = o->callback;
12138 + cb_data->observer = o->observer;
12139 + cb_data->data = o->data;
12140 + cb_data->object = notifier->object;
12141 + cb_data->notification = notification;
12142 + cb_data->notification_data = notification_data;
12143 + DWC_DEBUGC("Observer found %p for notification %s\n", o->observer, notification);
12144 + DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
12145 + "Notify callback from %p for Notification %s, to observer %p",
12146 + cb_data->object, notification, cb_data->observer);
12151 +#endif /* DWC_NOTIFYLIB */
12153 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.h
12156 +#ifndef __DWC_NOTIFIER_H__
12157 +#define __DWC_NOTIFIER_H__
12159 +#ifdef __cplusplus
12163 +#include "dwc_os.h"
12167 + * A simple implementation of the Observer pattern. Any "module" can
12168 + * register as an observer or notifier. The notion of "module" is abstract and
12169 + * can mean anything used to identify either an observer or notifier. Usually
12170 + * it will be a pointer to a data structure which contains some state, ie an
12173 + * Before any notifiers can be added, the global notification manager must be
12174 + * brought up with dwc_alloc_notification_manager().
12175 + * dwc_free_notification_manager() will bring it down and free all resources.
12176 + * These would typically be called upon module load and unload. The
12177 + * notification manager is a single global instance that handles all registered
12178 + * observable modules and observers so this should be done only once.
12180 + * A module can be observable by using Notifications to publicize some general
12181 + * information about it's state or operation. It does not care who listens, or
12182 + * even if anyone listens, or what they do with the information. The observable
12183 + * modules do not need to know any information about it's observers or their
12184 + * interface, or their state or data.
12186 + * Any module can register to emit Notifications. It should publish a list of
12187 + * notifications that it can emit and their behavior, such as when they will get
12188 + * triggered, and what information will be provided to the observer. Then it
12189 + * should register itself as an observable module. See dwc_register_notifier().
12191 + * Any module can observe any observable, registered module, provided it has a
12192 + * handle to the other module and knows what notifications to observe. See
12193 + * dwc_add_observer().
12195 + * A function of type dwc_notifier_callback_t is called whenever a notification
12196 + * is triggered with one or more observers observing it. This function is
12197 + * called in it's own process so it may sleep or block if needed. It is
12198 + * guaranteed to be called sometime after the notification has occurred and will
12199 + * be called once per each time the notification is triggered. It will NOT be
12200 + * called in the same process context used to trigger the notification.
12202 + * @section Limitiations
12204 + * Keep in mind that Notifications that can be triggered in rapid sucession may
12205 + * schedule too many processes too handle. Be aware of this limitation when
12206 + * designing to use notifications, and only add notifications for appropriate
12207 + * observable information.
12209 + * Also Notification callbacks are not synchronous. If you need to synchronize
12210 + * the behavior between module/observer you must use other means. And perhaps
12211 + * that will mean Notifications are not the proper solution.
12214 +struct dwc_notifier;
12215 +typedef struct dwc_notifier dwc_notifier_t;
12217 +/** The callback function must be of this type.
12219 + * @param object This is the object that is being observed.
12220 + * @param notification This is the notification that was triggered.
12221 + * @param observer This is the observer
12222 + * @param notification_data This is notification-specific data that the notifier
12223 + * has included in this notification. The value of this should be published in
12224 + * the documentation of the observable module with the notifications.
12225 + * @param user_data This is any custom data that the observer provided when
12226 + * adding itself as an observer to the notification. */
12227 +typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer,
12228 + void *notification_data, void *user_data);
12230 +/** Brings up the notification manager. */
12231 +extern int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx);
12232 +/** Brings down the notification manager. */
12233 +extern void dwc_free_notification_manager(void);
12235 +/** This function registers an observable module. A dwc_notifier_t object is
12236 + * returned to the observable module. This is an opaque object that is used by
12237 + * the observable module to trigger notifications. This object should only be
12238 + * accessible to functions that are authorized to trigger notifications for this
12239 + * module. Observers do not need this object. */
12240 +extern dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object);
12242 +/** This function unregisters an observable module. All observers have to be
12243 + * removed prior to unregistration. */
12244 +extern void dwc_unregister_notifier(dwc_notifier_t *notifier);
12246 +/** Add a module as an observer to the observable module. The observable module
12247 + * needs to have previously registered with the notification manager.
12249 + * @param observer The observer module
12250 + * @param object The module to observe
12251 + * @param notification The notification to observe
12252 + * @param callback The callback function to call
12253 + * @param user_data Any additional user data to pass into the callback function */
12254 +extern int dwc_add_observer(void *observer, void *object, char *notification,
12255 + dwc_notifier_callback_t callback, void *user_data);
12257 +/** Removes the specified observer from all notifications that it is currently
12259 +extern int dwc_remove_observer(void *observer);
12261 +/** This function triggers a Notification. It should be called by the
12262 + * observable module, or any module or library which the observable module
12263 + * allows to trigger notification on it's behalf. Such as the dwc_cc_t.
12265 + * dwc_notify is a non-blocking function. Callbacks are scheduled called in
12266 + * their own process context for each trigger. Callbacks can be blocking.
12267 + * dwc_notify can be called from interrupt context if needed.
12270 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data);
12272 +#ifdef __cplusplus
12276 +#endif /* __DWC_NOTIFIER_H__ */
12278 +++ b/drivers/usb/host/dwc_common_port/dwc_os.h
12280 +/* =========================================================================
12281 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_os.h $
12282 + * $Revision: #14 $
12283 + * $Date: 2010/11/04 $
12284 + * $Change: 1621695 $
12286 + * Synopsys Portability Library Software and documentation
12287 + * (hereinafter, "Software") is an Unsupported proprietary work of
12288 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
12289 + * between Synopsys and you.
12291 + * The Software IS NOT an item of Licensed Software or Licensed Product
12292 + * under any End User Software License Agreement or Agreement for
12293 + * Licensed Product with Synopsys or any supplement thereto. You are
12294 + * permitted to use and redistribute this Software in source and binary
12295 + * forms, with or without modification, provided that redistributions
12296 + * of source code must retain this notice. You may not view, use,
12297 + * disclose, copy or distribute this file or any information contained
12298 + * herein except pursuant to this license grant from Synopsys. If you
12299 + * do not agree with this notice, including the disclaimer below, then
12300 + * you are not authorized to use the Software.
12302 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
12303 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
12304 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12305 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
12306 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
12307 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
12308 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
12309 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
12310 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12311 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
12312 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
12314 + * ========================================================================= */
12315 +#ifndef _DWC_OS_H_
12316 +#define _DWC_OS_H_
12318 +#ifdef __cplusplus
12324 + * DWC portability library, low level os-wrapper functions
12328 +/* These basic types need to be defined by some OS header file or custom header
12329 + * file for your specific target architecture.
12331 + * uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
12333 + * Any custom or alternate header file must be added and enabled here.
12337 +# include <linux/types.h>
12338 +# ifdef CONFIG_DEBUG_MUTEXES
12339 +# include <linux/mutex.h>
12341 +# include <linux/spinlock.h>
12342 +# include <linux/errno.h>
12343 +# include <stdarg.h>
12346 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12347 +# include <os_dep.h>
12351 +/** @name Primitive Types and Values */
12353 +/** We define a boolean type for consistency. Can be either YES or NO */
12354 +typedef uint8_t dwc_bool_t;
12360 +/** @name Error Codes */
12361 +#define DWC_E_INVALID EINVAL
12362 +#define DWC_E_NO_MEMORY ENOMEM
12363 +#define DWC_E_NO_DEVICE ENODEV
12364 +#define DWC_E_NOT_SUPPORTED EOPNOTSUPP
12365 +#define DWC_E_TIMEOUT ETIMEDOUT
12366 +#define DWC_E_BUSY EBUSY
12367 +#define DWC_E_AGAIN EAGAIN
12368 +#define DWC_E_RESTART ERESTART
12369 +#define DWC_E_ABORT ECONNABORTED
12370 +#define DWC_E_SHUTDOWN ESHUTDOWN
12371 +#define DWC_E_NO_DATA ENODATA
12372 +#define DWC_E_DISCONNECT ECONNRESET
12373 +#define DWC_E_UNKNOWN EINVAL
12374 +#define DWC_E_NO_STREAM_RES ENOSR
12375 +#define DWC_E_COMMUNICATION ECOMM
12376 +#define DWC_E_OVERFLOW EOVERFLOW
12377 +#define DWC_E_PROTOCOL EPROTO
12378 +#define DWC_E_IN_PROGRESS EINPROGRESS
12379 +#define DWC_E_PIPE EPIPE
12380 +#define DWC_E_IO EIO
12381 +#define DWC_E_NO_SPACE ENOSPC
12385 +/** @name Error Codes */
12386 +#define DWC_E_INVALID 1001
12387 +#define DWC_E_NO_MEMORY 1002
12388 +#define DWC_E_NO_DEVICE 1003
12389 +#define DWC_E_NOT_SUPPORTED 1004
12390 +#define DWC_E_TIMEOUT 1005
12391 +#define DWC_E_BUSY 1006
12392 +#define DWC_E_AGAIN 1007
12393 +#define DWC_E_RESTART 1008
12394 +#define DWC_E_ABORT 1009
12395 +#define DWC_E_SHUTDOWN 1010
12396 +#define DWC_E_NO_DATA 1011
12397 +#define DWC_E_DISCONNECT 2000
12398 +#define DWC_E_UNKNOWN 3000
12399 +#define DWC_E_NO_STREAM_RES 4001
12400 +#define DWC_E_COMMUNICATION 4002
12401 +#define DWC_E_OVERFLOW 4003
12402 +#define DWC_E_PROTOCOL 4004
12403 +#define DWC_E_IN_PROGRESS 4005
12404 +#define DWC_E_PIPE 4006
12405 +#define DWC_E_IO 4007
12406 +#define DWC_E_NO_SPACE 4008
12411 +/** @name Tracing/Logging Functions
12413 + * These function provide the capability to add tracing, debugging, and error
12414 + * messages, as well exceptions as assertions. The WUDEV uses these
12415 + * extensively. These could be logged to the main console, the serial port, an
12416 + * internal buffer, etc. These functions could also be no-op if they are too
12417 + * expensive on your system. By default undefining the DEBUG macro already
12418 + * no-ops some of these functions. */
12420 +/** Returns non-zero if in interrupt context. */
12421 +extern dwc_bool_t DWC_IN_IRQ(void);
12422 +#define dwc_in_irq DWC_IN_IRQ
12424 +/** Returns "IRQ" if DWC_IN_IRQ is true. */
12425 +static inline char *dwc_irq(void) {
12426 + return DWC_IN_IRQ() ? "IRQ" : "";
12429 +/** Returns non-zero if in bottom-half context. */
12430 +extern dwc_bool_t DWC_IN_BH(void);
12431 +#define dwc_in_bh DWC_IN_BH
12433 +/** Returns "BH" if DWC_IN_BH is true. */
12434 +static inline char *dwc_bh(void) {
12435 + return DWC_IN_BH() ? "BH" : "";
12439 + * A vprintf() clone. Just call vprintf if you've got it.
12441 +extern void DWC_VPRINTF(char *format, va_list args);
12442 +#define dwc_vprintf DWC_VPRINTF
12445 + * A vsnprintf() clone. Just call vprintf if you've got it.
12447 +extern int DWC_VSNPRINTF(char *str, int size, char *format, va_list args);
12448 +#define dwc_vsnprintf DWC_VSNPRINTF
12451 + * printf() clone. Just call printf if you've go it.
12453 +extern void DWC_PRINTF(char *format, ...)
12454 +/* This provides compiler level static checking of the parameters if you're
12457 + __attribute__ ((format(printf, 1, 2)));
12461 +#define dwc_printf DWC_PRINTF
12464 + * sprintf() clone. Just call sprintf if you've got it.
12466 +extern int DWC_SPRINTF(char *string, char *format, ...)
12468 + __attribute__ ((format(printf, 2, 3)));
12472 +#define dwc_sprintf DWC_SPRINTF
12475 + * snprintf() clone. Just call snprintf if you've got it.
12477 +extern int DWC_SNPRINTF(char *string, int size, char *format, ...)
12479 + __attribute__ ((format(printf, 3, 4)));
12483 +#define dwc_snprintf DWC_SNPRINTF
12486 + * Prints a WARNING message. On systems that don't differentiate between
12487 + * warnings and regular log messages, just print it. Indicates that something
12488 + * may be wrong with the driver. Works like printf().
12490 + * Use the DWC_WARN macro to call this function.
12492 +extern void __DWC_WARN(char *format, ...)
12494 + __attribute__ ((format(printf, 1, 2)));
12500 + * Prints an error message. On systems that don't differentiate between errors
12501 + * and regular log messages, just print it. Indicates that something went wrong
12502 + * with the driver. Works like printf().
12504 + * Use the DWC_ERROR macro to call this function.
12506 +extern void __DWC_ERROR(char *format, ...)
12508 + __attribute__ ((format(printf, 1, 2)));
12514 + * Prints an exception error message and takes some user-defined action such as
12515 + * print out a backtrace or trigger a breakpoint. Indicates that something went
12516 + * abnormally wrong with the driver such as programmer error, or other
12517 + * exceptional condition. It should not be ignored so even on systems without
12518 + * printing capability, some action should be taken to notify the developer of
12519 + * it. Works like printf().
12521 +extern void DWC_EXCEPTION(char *format, ...)
12523 + __attribute__ ((format(printf, 1, 2)));
12527 +#define dwc_exception DWC_EXCEPTION
12529 +#ifndef DWC_OTG_DEBUG_LEV
12530 +#define DWC_OTG_DEBUG_LEV 0
12535 + * Prints out a debug message. Used for logging/trace messages.
12537 + * Use the DWC_DEBUG macro to call this function
12539 +extern void __DWC_DEBUG(char *format, ...)
12541 + __attribute__ ((format(printf, 1, 2)));
12546 +#define __DWC_DEBUG printk
12550 + * Prints out a Debug message.
12552 +#define DWC_DEBUG(_format, _args...) __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", \
12553 + __func__, dwc_irq(), ## _args)
12554 +#define dwc_debug DWC_DEBUG
12556 + * Prints out a Debug message if enabled at compile time.
12558 +#if DWC_OTG_DEBUG_LEV > 0
12559 +#define DWC_DEBUGC(_format, _args...) DWC_DEBUG(_format, ##_args )
12561 +#define DWC_DEBUGC(_format, _args...)
12563 +#define dwc_debugc DWC_DEBUGC
12565 + * Prints out an informative message.
12567 +#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", \
12568 + dwc_irq(), ## _args)
12569 +#define dwc_info DWC_INFO
12571 + * Prints out an informative message if enabled at compile time.
12573 +#if DWC_OTG_DEBUG_LEV > 1
12574 +#define DWC_INFOC(_format, _args...) DWC_INFO(_format, ##_args )
12576 +#define DWC_INFOC(_format, _args...)
12578 +#define dwc_infoc DWC_INFOC
12580 + * Prints out a warning message.
12582 +#define DWC_WARN(_format, _args...) __DWC_WARN("WARN:%s:%s:%d: " _format "\n", \
12583 + dwc_irq(), __func__, __LINE__, ## _args)
12584 +#define dwc_warn DWC_WARN
12586 + * Prints out an error message.
12588 +#define DWC_ERROR(_format, _args...) __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", \
12589 + dwc_irq(), __func__, __LINE__, ## _args)
12590 +#define dwc_error DWC_ERROR
12592 +#define DWC_PROTO_ERROR(_format, _args...) __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", \
12593 + dwc_irq(), __func__, __LINE__, ## _args)
12594 +#define dwc_proto_error DWC_PROTO_ERROR
12597 +/** Prints out a exception error message if the _expr expression fails. Disabled
12598 + * if DEBUG is not enabled. */
12599 +#define DWC_ASSERT(_expr, _format, _args...) do { \
12600 + if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), \
12601 + __FILE__, __LINE__, ## _args); } \
12604 +#define DWC_ASSERT(_x...)
12606 +#define dwc_assert DWC_ASSERT
12609 +/** @name Byte Ordering
12610 + * The following functions are for conversions between processor's byte ordering
12611 + * and specific ordering you want.
12614 +/** Converts 32 bit data in CPU byte ordering to little endian. */
12615 +extern uint32_t DWC_CPU_TO_LE32(uint32_t *p);
12616 +#define dwc_cpu_to_le32 DWC_CPU_TO_LE32
12618 +/** Converts 32 bit data in CPU byte orderint to big endian. */
12619 +extern uint32_t DWC_CPU_TO_BE32(uint32_t *p);
12620 +#define dwc_cpu_to_be32 DWC_CPU_TO_BE32
12622 +/** Converts 32 bit little endian data to CPU byte ordering. */
12623 +extern uint32_t DWC_LE32_TO_CPU(uint32_t *p);
12624 +#define dwc_le32_to_cpu DWC_LE32_TO_CPU
12626 +/** Converts 32 bit big endian data to CPU byte ordering. */
12627 +extern uint32_t DWC_BE32_TO_CPU(uint32_t *p);
12628 +#define dwc_be32_to_cpu DWC_BE32_TO_CPU
12630 +/** Converts 16 bit data in CPU byte ordering to little endian. */
12631 +extern uint16_t DWC_CPU_TO_LE16(uint16_t *p);
12632 +#define dwc_cpu_to_le16 DWC_CPU_TO_LE16
12634 +/** Converts 16 bit data in CPU byte orderint to big endian. */
12635 +extern uint16_t DWC_CPU_TO_BE16(uint16_t *p);
12636 +#define dwc_cpu_to_be16 DWC_CPU_TO_BE16
12638 +/** Converts 16 bit little endian data to CPU byte ordering. */
12639 +extern uint16_t DWC_LE16_TO_CPU(uint16_t *p);
12640 +#define dwc_le16_to_cpu DWC_LE16_TO_CPU
12642 +/** Converts 16 bit bi endian data to CPU byte ordering. */
12643 +extern uint16_t DWC_BE16_TO_CPU(uint16_t *p);
12644 +#define dwc_be16_to_cpu DWC_BE16_TO_CPU
12647 +/** @name Register Read/Write
12649 + * The following six functions should be implemented to read/write registers of
12650 + * 32-bit and 64-bit sizes. All modules use this to read/write register values.
12651 + * The reg value is a pointer to the register calculated from the void *base
12652 + * variable passed into the driver when it is started. */
12655 +/* Linux doesn't need any extra parameters for register read/write, so we
12656 + * just throw away the IO context parameter.
12658 +/** Reads the content of a 32-bit register. */
12659 +extern uint32_t DWC_READ_REG32(uint32_t volatile *reg);
12660 +#define dwc_read_reg32(_ctx_,_reg_) DWC_READ_REG32(_reg_)
12662 +/** Reads the content of a 64-bit register. */
12663 +extern uint64_t DWC_READ_REG64(uint64_t volatile *reg);
12664 +#define dwc_read_reg64(_ctx_,_reg_) DWC_READ_REG64(_reg_)
12666 +/** Writes to a 32-bit register. */
12667 +extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value);
12668 +#define dwc_write_reg32(_ctx_,_reg_,_val_) DWC_WRITE_REG32(_reg_, _val_)
12670 +/** Writes to a 64-bit register. */
12671 +extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value);
12672 +#define dwc_write_reg64(_ctx_,_reg_,_val_) DWC_WRITE_REG64(_reg_, _val_)
12675 + * Modify bit values in a register. Using the
12676 + * algorithm: (reg_contents & ~clear_mask) | set_mask.
12678 +extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
12679 +#define dwc_modify_reg32(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG32(_reg_,_cmsk_,_smsk_)
12680 +extern void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
12681 +#define dwc_modify_reg64(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG64(_reg_,_cmsk_,_smsk_)
12683 +#endif /* DWC_LINUX */
12685 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12686 +typedef struct dwc_ioctx {
12687 + struct device *dev;
12688 + bus_space_tag_t iot;
12689 + bus_space_handle_t ioh;
12692 +/** BSD needs two extra parameters for register read/write, so we pass
12693 + * them in using the IO context parameter.
12695 +/** Reads the content of a 32-bit register. */
12696 +extern uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg);
12697 +#define dwc_read_reg32 DWC_READ_REG32
12699 +/** Reads the content of a 64-bit register. */
12700 +extern uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg);
12701 +#define dwc_read_reg64 DWC_READ_REG64
12703 +/** Writes to a 32-bit register. */
12704 +extern void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value);
12705 +#define dwc_write_reg32 DWC_WRITE_REG32
12707 +/** Writes to a 64-bit register. */
12708 +extern void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value);
12709 +#define dwc_write_reg64 DWC_WRITE_REG64
12712 + * Modify bit values in a register. Using the
12713 + * algorithm: (reg_contents & ~clear_mask) | set_mask.
12715 +extern void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
12716 +#define dwc_modify_reg32 DWC_MODIFY_REG32
12717 +extern void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
12718 +#define dwc_modify_reg64 DWC_MODIFY_REG64
12720 +#endif /* DWC_FREEBSD || DWC_NETBSD */
12724 +/** @name Some convenience MACROS used internally. Define DWC_DEBUG_REGS to log the
12725 + * register writes. */
12729 +# ifdef DWC_DEBUG_REGS
12731 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12732 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
12733 + return DWC_READ_REG32(&container->regs->_reg[num]); \
12735 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
12736 + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
12737 + &(((uint32_t*)container->regs->_reg)[num]), data); \
12738 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
12741 +#define dwc_define_read_write_reg(_reg,_container_type) \
12742 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
12743 + return DWC_READ_REG32(&container->regs->_reg); \
12745 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
12746 + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
12747 + DWC_WRITE_REG32(&container->regs->_reg, data); \
12750 +# else /* DWC_DEBUG_REGS */
12752 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12753 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
12754 + return DWC_READ_REG32(&container->regs->_reg[num]); \
12756 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
12757 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
12760 +#define dwc_define_read_write_reg(_reg,_container_type) \
12761 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
12762 + return DWC_READ_REG32(&container->regs->_reg); \
12764 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
12765 + DWC_WRITE_REG32(&container->regs->_reg, data); \
12768 +# endif /* DWC_DEBUG_REGS */
12770 +#endif /* DWC_LINUX */
12772 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12774 +# ifdef DWC_DEBUG_REGS
12776 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12777 +static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
12778 + return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
12780 +static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
12781 + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
12782 + &(((uint32_t*)container->regs->_reg)[num]), data); \
12783 + DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
12786 +#define dwc_define_read_write_reg(_reg,_container_type) \
12787 +static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
12788 + return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
12790 +static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
12791 + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
12792 + DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
12795 +# else /* DWC_DEBUG_REGS */
12797 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12798 +static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
12799 + return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
12801 +static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
12802 + DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
12805 +#define dwc_define_read_write_reg(_reg,_container_type) \
12806 +static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
12807 + return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
12809 +static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
12810 + DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
12813 +# endif /* DWC_DEBUG_REGS */
12815 +#endif /* DWC_FREEBSD || DWC_NETBSD */
12820 +#ifdef DWC_CRYPTOLIB
12821 +/** @name Crypto Functions
12823 + * These are the low-level cryptographic functions used by the driver. */
12825 +/** Perform AES CBC */
12826 +extern int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out);
12827 +#define dwc_aes_cbc DWC_AES_CBC
12829 +/** Fill the provided buffer with random bytes. These should be cryptographic grade random numbers. */
12830 +extern void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length);
12831 +#define dwc_random_bytes DWC_RANDOM_BYTES
12833 +/** Perform the SHA-256 hash function */
12834 +extern int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out);
12835 +#define dwc_sha256 DWC_SHA256
12837 +/** Calculated the HMAC-SHA256 */
12838 +extern int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out);
12839 +#define dwc_hmac_sha256 DWC_HMAC_SHA256
12841 +#endif /* DWC_CRYPTOLIB */
12844 +/** @name Memory Allocation
12846 + * These function provide access to memory allocation. There are only 2 DMA
12847 + * functions and 3 Regular memory functions that need to be implemented. None
12848 + * of the memory debugging routines need to be implemented. The allocation
12849 + * routines all ZERO the contents of the memory.
12851 + * Defining DWC_DEBUG_MEMORY turns on memory debugging and statistic gathering.
12852 + * This checks for memory leaks, keeping track of alloc/free pairs. It also
12853 + * keeps track of how much memory the driver is using at any given time. */
12855 +#define DWC_PAGE_SIZE 4096
12856 +#define DWC_PAGE_OFFSET(addr) (((uint32_t)addr) & 0xfff)
12857 +#define DWC_PAGE_ALIGNED(addr) ((((uint32_t)addr) & 0xfff) == 0)
12859 +#define DWC_INVALID_DMA_ADDR 0x0
12862 +/** Type for a DMA address */
12863 +typedef dma_addr_t dwc_dma_t;
12866 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12867 +typedef bus_addr_t dwc_dma_t;
12870 +#ifdef DWC_FREEBSD
12871 +typedef struct dwc_dmactx {
12872 + struct device *dev;
12873 + bus_dma_tag_t dma_tag;
12874 + bus_dmamap_t dma_map;
12875 + bus_addr_t dma_paddr;
12881 +typedef struct dwc_dmactx {
12882 + struct device *dev;
12883 + bus_dma_tag_t dma_tag;
12884 + bus_dmamap_t dma_map;
12885 + bus_dma_segment_t segs[1];
12887 + bus_addr_t dma_paddr;
12892 +/* @todo these functions will be added in the future */
12895 + * Creates a DMA pool from which you can allocate DMA buffers. Buffers
12896 + * allocated from this pool will be guaranteed to meet the size, alignment, and
12897 + * boundary requirements specified.
12899 + * @param[in] size Specifies the size of the buffers that will be allocated from
12901 + * @param[in] align Specifies the byte alignment requirements of the buffers
12902 + * allocated from this pool. Must be a power of 2.
12903 + * @param[in] boundary Specifies the N-byte boundary that buffers allocated from
12904 + * this pool must not cross.
12906 + * @returns A pointer to an internal opaque structure which is not to be
12907 + * accessed outside of these library functions. Use this handle to specify
12908 + * which pools to allocate/free DMA buffers from and also to destroy the pool,
12909 + * when you are done with it.
12911 +extern dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t boundary);
12914 + * Destroy a DMA pool. All buffers allocated from that pool must be freed first.
12916 +extern void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool);
12919 + * Allocate a buffer from the specified DMA pool and zeros its contents.
12921 +extern void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr);
12924 + * Free a previously allocated buffer from the DMA pool.
12926 +extern void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr);
12929 +/** Allocates a DMA capable buffer and zeroes its contents. */
12930 +extern void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
12932 +/** Allocates a DMA capable buffer and zeroes its contents in atomic contest */
12933 +extern void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
12935 +/** Frees a previously allocated buffer. */
12936 +extern void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr);
12938 +/** Allocates a block of memory and zeroes its contents. */
12939 +extern void *__DWC_ALLOC(void *mem_ctx, uint32_t size);
12941 +/** Allocates a block of memory and zeroes its contents, in an atomic manner
12942 + * which can be used inside interrupt context. The size should be sufficiently
12943 + * small, a few KB at most, such that failures are not likely to occur. Can just call
12944 + * __DWC_ALLOC if it is atomic. */
12945 +extern void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size);
12947 +/** Frees a previously allocated buffer. */
12948 +extern void __DWC_FREE(void *mem_ctx, void *addr);
12950 +#ifndef DWC_DEBUG_MEMORY
12952 +#define DWC_ALLOC(_size_) __DWC_ALLOC(NULL, _size_)
12953 +#define DWC_ALLOC_ATOMIC(_size_) __DWC_ALLOC_ATOMIC(NULL, _size_)
12954 +#define DWC_FREE(_addr_) __DWC_FREE(NULL, _addr_)
12957 +#define DWC_DMA_ALLOC(_size_,_dma_) __DWC_DMA_ALLOC(NULL, _size_, _dma_)
12958 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) __DWC_DMA_ALLOC_ATOMIC(NULL, _size_,_dma_)
12959 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) __DWC_DMA_FREE(NULL, _size_, _virt_, _dma_)
12962 +# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12963 +#define DWC_DMA_ALLOC __DWC_DMA_ALLOC
12964 +#define DWC_DMA_FREE __DWC_DMA_FREE
12966 +extern void *dwc_dma_alloc_atomic_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line);
12968 +#else /* DWC_DEBUG_MEMORY */
12970 +extern void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line);
12971 +extern void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func, int line);
12972 +extern void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line);
12973 +extern void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
12974 + char const *func, int line);
12975 +extern void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
12976 + char const *func, int line);
12977 +extern void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
12978 + dwc_dma_t dma_addr, char const *func, int line);
12980 +extern int dwc_memory_debug_start(void *mem_ctx);
12981 +extern void dwc_memory_debug_stop(void);
12982 +extern void dwc_memory_debug_report(void);
12984 +#define DWC_ALLOC(_size_) dwc_alloc_debug(NULL, _size_, __func__, __LINE__)
12985 +#define DWC_ALLOC_ATOMIC(_size_) dwc_alloc_atomic_debug(NULL, _size_, \
12986 + __func__, __LINE__)
12987 +#define DWC_FREE(_addr_) dwc_free_debug(NULL, _addr_, __func__, __LINE__)
12990 +#define DWC_DMA_ALLOC(_size_,_dma_) dwc_dma_alloc_debug(NULL, _size_, \
12991 + _dma_, __func__, __LINE__)
12992 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) dwc_dma_alloc_atomic_debug(NULL, _size_, \
12993 + _dma_, __func__, __LINE__)
12994 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) dwc_dma_free_debug(NULL, _size_, \
12995 + _virt_, _dma_, __func__, __LINE__)
12998 +# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12999 +#define DWC_DMA_ALLOC(_ctx_,_size_,_dma_) dwc_dma_alloc_debug(_ctx_, _size_, \
13000 + _dma_, __func__, __LINE__)
13001 +#define DWC_DMA_FREE(_ctx_,_size_,_virt_,_dma_) dwc_dma_free_debug(_ctx_, _size_, \
13002 + _virt_, _dma_, __func__, __LINE__)
13005 +#endif /* DWC_DEBUG_MEMORY */
13007 +#define dwc_alloc(_ctx_,_size_) DWC_ALLOC(_size_)
13008 +#define dwc_alloc_atomic(_ctx_,_size_) DWC_ALLOC_ATOMIC(_size_)
13009 +#define dwc_free(_ctx_,_addr_) DWC_FREE(_addr_)
13012 +/* Linux doesn't need any extra parameters for DMA buffer allocation, so we
13013 + * just throw away the DMA context parameter.
13015 +#define dwc_dma_alloc(_ctx_,_size_,_dma_) DWC_DMA_ALLOC(_size_, _dma_)
13016 +#define dwc_dma_alloc_atomic(_ctx_,_size_,_dma_) DWC_DMA_ALLOC_ATOMIC(_size_, _dma_)
13017 +#define dwc_dma_free(_ctx_,_size_,_virt_,_dma_) DWC_DMA_FREE(_size_, _virt_, _dma_)
13020 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13021 +/** BSD needs several extra parameters for DMA buffer allocation, so we pass
13022 + * them in using the DMA context parameter.
13024 +#define dwc_dma_alloc DWC_DMA_ALLOC
13025 +#define dwc_dma_free DWC_DMA_FREE
13029 +/** @name Memory and String Processing */
13031 +/** memset() clone */
13032 +extern void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size);
13033 +#define dwc_memset DWC_MEMSET
13035 +/** memcpy() clone */
13036 +extern void *DWC_MEMCPY(void *dest, void const *src, uint32_t size);
13037 +#define dwc_memcpy DWC_MEMCPY
13039 +/** memmove() clone */
13040 +extern void *DWC_MEMMOVE(void *dest, void *src, uint32_t size);
13041 +#define dwc_memmove DWC_MEMMOVE
13043 +/** memcmp() clone */
13044 +extern int DWC_MEMCMP(void *m1, void *m2, uint32_t size);
13045 +#define dwc_memcmp DWC_MEMCMP
13047 +/** strcmp() clone */
13048 +extern int DWC_STRCMP(void *s1, void *s2);
13049 +#define dwc_strcmp DWC_STRCMP
13051 +/** strncmp() clone */
13052 +extern int DWC_STRNCMP(void *s1, void *s2, uint32_t size);
13053 +#define dwc_strncmp DWC_STRNCMP
13055 +/** strlen() clone, for NULL terminated ASCII strings */
13056 +extern int DWC_STRLEN(char const *str);
13057 +#define dwc_strlen DWC_STRLEN
13059 +/** strcpy() clone, for NULL terminated ASCII strings */
13060 +extern char *DWC_STRCPY(char *to, const char *from);
13061 +#define dwc_strcpy DWC_STRCPY
13063 +/** strdup() clone. If you wish to use memory allocation debugging, this
13064 + * implementation of strdup should use the DWC_* memory routines instead of
13065 + * calling a predefined strdup. Otherwise the memory allocated by this routine
13066 + * will not be seen by the debugging routines. */
13067 +extern char *DWC_STRDUP(char const *str);
13068 +#define dwc_strdup(_ctx_,_str_) DWC_STRDUP(_str_)
13070 +/** NOT an atoi() clone. Read the description carefully. Returns an integer
13071 + * converted from the string str in base 10 unless the string begins with a "0x"
13072 + * in which case it is base 16. String must be a NULL terminated sequence of
13073 + * ASCII characters and may optionally begin with whitespace, a + or -, and a
13074 + * "0x" prefix if base 16. The remaining characters must be valid digits for
13075 + * the number and end with a NULL character. If any invalid characters are
13076 + * encountered or it returns with a negative error code and the results of the
13077 + * conversion are undefined. On sucess it returns 0. Overflow conditions are
13078 + * undefined. An example implementation using atoi() can be referenced from the
13079 + * Linux implementation. */
13080 +extern int DWC_ATOI(const char *str, int32_t *value);
13081 +#define dwc_atoi DWC_ATOI
13083 +/** Same as above but for unsigned. */
13084 +extern int DWC_ATOUI(const char *str, uint32_t *value);
13085 +#define dwc_atoui DWC_ATOUI
13088 +/** This routine returns a UTF16LE unicode encoded string from a UTF8 string. */
13089 +extern int DWC_UTF8_TO_UTF16LE(uint8_t const *utf8string, uint16_t *utf16string, unsigned len);
13090 +#define dwc_utf8_to_utf16le DWC_UTF8_TO_UTF16LE
13094 +/** @name Wait queues
13096 + * Wait queues provide a means of synchronizing between threads or processes. A
13097 + * process can block on a waitq if some condition is not true, waiting for it to
13098 + * become true. When the waitq is triggered all waiting process will get
13099 + * unblocked and the condition will be check again. Waitqs should be triggered
13100 + * every time a condition can potentially change.*/
13103 +/** Type for a waitq */
13104 +typedef struct dwc_waitq dwc_waitq_t;
13106 +/** The type of waitq condition callback function. This is called every time
13107 + * condition is evaluated. */
13108 +typedef int (*dwc_waitq_condition_t)(void *data);
13110 +/** Allocate a waitq */
13111 +extern dwc_waitq_t *DWC_WAITQ_ALLOC(void);
13112 +#define dwc_waitq_alloc(_ctx_) DWC_WAITQ_ALLOC()
13114 +/** Free a waitq */
13115 +extern void DWC_WAITQ_FREE(dwc_waitq_t *wq);
13116 +#define dwc_waitq_free DWC_WAITQ_FREE
13118 +/** Check the condition and if it is false, block on the waitq. When unblocked, check the
13119 + * condition again. The function returns when the condition becomes true. The return value
13120 + * is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. */
13121 +extern int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data);
13122 +#define dwc_waitq_wait DWC_WAITQ_WAIT
13124 +/** Check the condition and if it is false, block on the waitq. When unblocked,
13125 + * check the condition again. The function returns when the condition become
13126 + * true or the timeout has passed. The return value is 0 on condition true or
13127 + * DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on
13129 +extern int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
13130 + void *data, int32_t msecs);
13131 +#define dwc_waitq_wait_timeout DWC_WAITQ_WAIT_TIMEOUT
13133 +/** Trigger a waitq, unblocking all processes. This should be called whenever a condition
13134 + * has potentially changed. */
13135 +extern void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq);
13136 +#define dwc_waitq_trigger DWC_WAITQ_TRIGGER
13138 +/** Unblock all processes waiting on the waitq with an ABORTED result. */
13139 +extern void DWC_WAITQ_ABORT(dwc_waitq_t *wq);
13140 +#define dwc_waitq_abort DWC_WAITQ_ABORT
13145 + * A thread must be explicitly stopped. It must check DWC_THREAD_SHOULD_STOP
13146 + * whenever it is woken up, and then return. The DWC_THREAD_STOP function
13147 + * returns the value from the thread.
13150 +struct dwc_thread;
13152 +/** Type for a thread */
13153 +typedef struct dwc_thread dwc_thread_t;
13155 +/** The thread function */
13156 +typedef int (*dwc_thread_function_t)(void *data);
13158 +/** Create a thread and start it running the thread_function. Returns a handle
13159 + * to the thread */
13160 +extern dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data);
13161 +#define dwc_thread_run(_ctx_,_func_,_name_,_data_) DWC_THREAD_RUN(_func_, _name_, _data_)
13163 +/** Stops a thread. Return the value returned by the thread. Or will return
13164 + * DWC_ABORT if the thread never started. */
13165 +extern int DWC_THREAD_STOP(dwc_thread_t *thread);
13166 +#define dwc_thread_stop DWC_THREAD_STOP
13168 +/** Signifies to the thread that it must stop. */
13170 +/* Linux doesn't need any parameters for kthread_should_stop() */
13171 +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(void);
13172 +#define dwc_thread_should_stop(_thrd_) DWC_THREAD_SHOULD_STOP()
13174 +/* No thread_exit function in Linux */
13175 +#define dwc_thread_exit(_thrd_)
13178 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13179 +/** BSD needs the thread pointer for kthread_suspend_check() */
13180 +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread);
13181 +#define dwc_thread_should_stop DWC_THREAD_SHOULD_STOP
13183 +/** The thread must call this to exit. */
13184 +extern void DWC_THREAD_EXIT(dwc_thread_t *thread);
13185 +#define dwc_thread_exit DWC_THREAD_EXIT
13189 +/** @name Work queues
13191 + * Workqs are used to queue a callback function to be called at some later time,
13192 + * in another thread. */
13195 +/** Type for a workq */
13196 +typedef struct dwc_workq dwc_workq_t;
13198 +/** The type of the callback function to be called. */
13199 +typedef void (*dwc_work_callback_t)(void *data);
13201 +/** Allocate a workq */
13202 +extern dwc_workq_t *DWC_WORKQ_ALLOC(char *name);
13203 +#define dwc_workq_alloc(_ctx_,_name_) DWC_WORKQ_ALLOC(_name_)
13205 +/** Free a workq. All work must be completed before being freed. */
13206 +extern void DWC_WORKQ_FREE(dwc_workq_t *workq);
13207 +#define dwc_workq_free DWC_WORKQ_FREE
13209 +/** Schedule a callback on the workq, passing in data. The function will be
13210 + * scheduled at some later time. */
13211 +extern void DWC_WORKQ_SCHEDULE(dwc_workq_t *workq, dwc_work_callback_t cb,
13212 + void *data, char *format, ...)
13214 + __attribute__ ((format(printf, 4, 5)));
13218 +#define dwc_workq_schedule DWC_WORKQ_SCHEDULE
13220 +/** Schedule a callback on the workq, that will be called until at least
13221 + * given number miliseconds have passed. */
13222 +extern void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *workq, dwc_work_callback_t cb,
13223 + void *data, uint32_t time, char *format, ...)
13225 + __attribute__ ((format(printf, 5, 6)));
13229 +#define dwc_workq_schedule_delayed DWC_WORKQ_SCHEDULE_DELAYED
13231 +/** The number of processes in the workq */
13232 +extern int DWC_WORKQ_PENDING(dwc_workq_t *workq);
13233 +#define dwc_workq_pending DWC_WORKQ_PENDING
13235 +/** Blocks until all the work in the workq is complete or timed out. Returns <
13236 + * 0 on timeout. */
13237 +extern int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout);
13238 +#define dwc_workq_wait_work_done DWC_WORKQ_WAIT_WORK_DONE
13241 +/** @name Tasklets
13244 +struct dwc_tasklet;
13246 +/** Type for a tasklet */
13247 +typedef struct dwc_tasklet dwc_tasklet_t;
13249 +/** The type of the callback function to be called */
13250 +typedef void (*dwc_tasklet_callback_t)(void *data);
13252 +/** Allocates a tasklet */
13253 +extern dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data);
13254 +#define dwc_task_alloc(_ctx_,_name_,_cb_,_data_) DWC_TASK_ALLOC(_name_, _cb_, _data_)
13256 +/** Frees a tasklet */
13257 +extern void DWC_TASK_FREE(dwc_tasklet_t *task);
13258 +#define dwc_task_free DWC_TASK_FREE
13260 +/** Schedules a tasklet to run */
13261 +extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
13262 +#define dwc_task_schedule DWC_TASK_SCHEDULE
13267 + * Callbacks must be small and atomic.
13271 +/** Type for a timer */
13272 +typedef struct dwc_timer dwc_timer_t;
13274 +/** The type of the callback function to be called */
13275 +typedef void (*dwc_timer_callback_t)(void *data);
13277 +/** Allocates a timer */
13278 +extern dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data);
13279 +#define dwc_timer_alloc(_ctx_,_name_,_cb_,_data_) DWC_TIMER_ALLOC(_name_,_cb_,_data_)
13281 +/** Frees a timer */
13282 +extern void DWC_TIMER_FREE(dwc_timer_t *timer);
13283 +#define dwc_timer_free DWC_TIMER_FREE
13285 +/** Schedules the timer to run at time ms from now. And will repeat at every
13286 + * repeat_interval msec therafter
13288 + * Modifies a timer that is still awaiting execution to a new expiration time.
13289 + * The mod_time is added to the old time. */
13290 +extern void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time);
13291 +#define dwc_timer_schedule DWC_TIMER_SCHEDULE
13293 +/** Disables the timer from execution. */
13294 +extern void DWC_TIMER_CANCEL(dwc_timer_t *timer);
13295 +#define dwc_timer_cancel DWC_TIMER_CANCEL
13298 +/** @name Spinlocks
13300 + * These locks are used when the work between the lock/unlock is atomic and
13301 + * short. Interrupts are also disabled during the lock/unlock and thus they are
13302 + * suitable to lock between interrupt/non-interrupt context. They also lock
13303 + * between processes if you have multiple CPUs or Preemption. If you don't have
13304 + * multiple CPUS or Preemption, then the you can simply implement the
13305 + * DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts. Because
13306 + * the work between the lock/unlock is atomic, the process context will never
13307 + * change, and so you never have to lock between processes. */
13309 +struct dwc_spinlock;
13311 +/** Type for a spinlock */
13312 +typedef struct dwc_spinlock dwc_spinlock_t;
13314 +/** Type for the 'flags' argument to spinlock funtions */
13315 +typedef unsigned long dwc_irqflags_t;
13317 +/** Returns an initialized lock variable. This function should allocate and
13318 + * initialize the OS-specific data structure used for locking. This data
13319 + * structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should
13320 + * be freed by the DWC_FREE_LOCK when it is no longer used.
13322 + * For Linux Spinlock Debugging make it macro because the debugging routines use
13323 + * the symbol name to determine recursive locking. Using a wrapper function
13324 + * makes it falsely think recursive locking occurs. */
13325 +#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK)
13326 +#define DWC_SPINLOCK_ALLOC_LINUX_DEBUG(lock) ({ \
13327 + lock = DWC_ALLOC(sizeof(spinlock_t)); \
13329 + spin_lock_init((spinlock_t *)lock); \
13333 +extern dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void);
13334 +#define dwc_spinlock_alloc(_ctx_) DWC_SPINLOCK_ALLOC()
13337 +/** Frees an initialized lock variable. */
13338 +extern void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock);
13339 +#define dwc_spinlock_free(_ctx_,_lock_) DWC_SPINLOCK_FREE(_lock_)
13341 +/** Disables interrupts and blocks until it acquires the lock.
13343 + * @param lock Pointer to the spinlock.
13344 + * @param flags Unsigned long for irq flags storage.
13346 +extern void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags);
13347 +#define dwc_spinlock_irqsave DWC_SPINLOCK_IRQSAVE
13349 +/** Re-enables the interrupt and releases the lock.
13351 + * @param lock Pointer to the spinlock.
13352 + * @param flags Unsigned long for irq flags storage. Must be the same as was
13353 + * passed into DWC_LOCK.
13355 +extern void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags);
13356 +#define dwc_spinunlock_irqrestore DWC_SPINUNLOCK_IRQRESTORE
13358 +/** Blocks until it acquires the lock.
13360 + * @param lock Pointer to the spinlock.
13362 +extern void DWC_SPINLOCK(dwc_spinlock_t *lock);
13363 +#define dwc_spinlock DWC_SPINLOCK
13365 +/** Releases the lock.
13367 + * @param lock Pointer to the spinlock.
13369 +extern void DWC_SPINUNLOCK(dwc_spinlock_t *lock);
13370 +#define dwc_spinunlock DWC_SPINUNLOCK
13375 + * Unlike spinlocks Mutexes lock only between processes and the work between the
13376 + * lock/unlock CAN block, therefore it CANNOT be called from interrupt context.
13381 +/** Type for a mutex */
13382 +typedef struct dwc_mutex dwc_mutex_t;
13384 +/* For Linux Mutex Debugging make it inline because the debugging routines use
13385 + * the symbol to determine recursive locking. This makes it falsely think
13386 + * recursive locking occurs. */
13387 +#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
13388 +#define DWC_MUTEX_ALLOC_LINUX_DEBUG(__mutexp) ({ \
13389 + __mutexp = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); \
13390 + mutex_init((struct mutex *)__mutexp); \
13394 +/** Allocate a mutex */
13395 +extern dwc_mutex_t *DWC_MUTEX_ALLOC(void);
13396 +#define dwc_mutex_alloc(_ctx_) DWC_MUTEX_ALLOC()
13398 +/* For memory leak debugging when using Linux Mutex Debugging */
13399 +#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
13400 +#define DWC_MUTEX_FREE(__mutexp) do { \
13401 + mutex_destroy((struct mutex *)__mutexp); \
13402 + DWC_FREE(__mutexp); \
13405 +/** Free a mutex */
13406 +extern void DWC_MUTEX_FREE(dwc_mutex_t *mutex);
13407 +#define dwc_mutex_free(_ctx_,_mutex_) DWC_MUTEX_FREE(_mutex_)
13410 +/** Lock a mutex */
13411 +extern void DWC_MUTEX_LOCK(dwc_mutex_t *mutex);
13412 +#define dwc_mutex_lock DWC_MUTEX_LOCK
13414 +/** Non-blocking lock returns 1 on successful lock. */
13415 +extern int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex);
13416 +#define dwc_mutex_trylock DWC_MUTEX_TRYLOCK
13418 +/** Unlock a mutex */
13419 +extern void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex);
13420 +#define dwc_mutex_unlock DWC_MUTEX_UNLOCK
13425 +/** Microsecond delay.
13427 + * @param usecs Microseconds to delay.
13429 +extern void DWC_UDELAY(uint32_t usecs);
13430 +#define dwc_udelay DWC_UDELAY
13432 +/** Millisecond delay.
13434 + * @param msecs Milliseconds to delay.
13436 +extern void DWC_MDELAY(uint32_t msecs);
13437 +#define dwc_mdelay DWC_MDELAY
13439 +/** Non-busy waiting.
13440 + * Sleeps for specified number of milliseconds.
13442 + * @param msecs Milliseconds to sleep.
13444 +extern void DWC_MSLEEP(uint32_t msecs);
13445 +#define dwc_msleep DWC_MSLEEP
13448 + * Returns number of milliseconds since boot.
13450 +extern uint32_t DWC_TIME(void);
13451 +#define dwc_time DWC_TIME
13456 +/* @mainpage DWC Portability and Common Library
13458 + * This is the documentation for the DWC Portability and Common Library.
13460 + * @section intro Introduction
13462 + * The DWC Portability library consists of wrapper calls and data structures to
13463 + * all low-level functions which are typically provided by the OS. The WUDEV
13464 + * driver uses only these functions. In order to port the WUDEV driver, only
13465 + * the functions in this library need to be re-implemented, with the same
13466 + * behavior as documented here.
13468 + * The Common library consists of higher level functions, which rely only on
13469 + * calling the functions from the DWC Portability library. These common
13470 + * routines are shared across modules. Some of the common libraries need to be
13471 + * used directly by the driver programmer when porting WUDEV. Such as the
13472 + * parameter and notification libraries.
13474 + * @section low Portability Library OS Wrapper Functions
13476 + * Any function starting with DWC and in all CAPS is a low-level OS-wrapper that
13477 + * needs to be implemented when porting, for example DWC_MUTEX_ALLOC(). All of
13478 + * these functions are included in the dwc_os.h file.
13480 + * There are many functions here covering a wide array of OS services. Please
13481 + * see dwc_os.h for details, and implementation notes for each function.
13483 + * @section common Common Library Functions
13485 + * Any function starting with dwc and in all lowercase is a common library
13486 + * routine. These functions have a portable implementation and do not need to
13487 + * be reimplemented when porting. The common routines can be used by any
13488 + * driver, and some must be used by the end user to control the drivers. For
13489 + * example, you must use the Parameter common library in order to set the
13490 + * parameters in the WUDEV module.
13492 + * The common libraries consist of the following:
13494 + * - Connection Contexts - Used internally and can be used by end-user. See dwc_cc.h
13495 + * - Parameters - Used internally and can be used by end-user. See dwc_params.h
13496 + * - Notifications - Used internally and can be used by end-user. See dwc_notifier.h
13497 + * - Lists - Used internally and can be used by end-user. See dwc_list.h
13498 + * - Memory Debugging - Used internally and can be used by end-user. See dwc_os.h
13499 + * - Modpow - Used internally only. See dwc_modpow.h
13500 + * - DH - Used internally only. See dwc_dh.h
13501 + * - Crypto - Used internally only. See dwc_crypto.h
13504 + * @section prereq Prerequistes For dwc_os.h
13505 + * @subsection types Data Types
13507 + * The dwc_os.h file assumes that several low-level data types are pre defined for the
13508 + * compilation environment. These data types are:
13510 + * - uint8_t - unsigned 8-bit data type
13511 + * - int8_t - signed 8-bit data type
13512 + * - uint16_t - unsigned 16-bit data type
13513 + * - int16_t - signed 16-bit data type
13514 + * - uint32_t - unsigned 32-bit data type
13515 + * - int32_t - signed 32-bit data type
13516 + * - uint64_t - unsigned 64-bit data type
13517 + * - int64_t - signed 64-bit data type
13519 + * Ensure that these are defined before using dwc_os.h. The easiest way to do
13520 + * that is to modify the top of the file to include the appropriate header.
13521 + * This is already done for the Linux environment. If the DWC_LINUX macro is
13522 + * defined, the correct header will be added. A standard header <stdint.h> is
13523 + * also used for environments where standard C headers are available.
13525 + * @subsection stdarg Variable Arguments
13527 + * Variable arguments are provided by a standard C header <stdarg.h>. it is
13528 + * available in Both the Linux and ANSI C enviornment. An equivalent must be
13529 + * provided in your enviornment in order to use dwc_os.h with the debug and
13530 + * tracing message functionality.
13532 + * @subsection thread Threading
13534 + * WUDEV Core must be run on an operating system that provides for multiple
13535 + * threads/processes. Threading can be implemented in many ways, even in
13536 + * embedded systems without an operating system. At the bare minimum, the
13537 + * system should be able to start any number of processes at any time to handle
13538 + * special work. It need not be a pre-emptive system. Process context can
13539 + * change upon a call to a blocking function. The hardware interrupt context
13540 + * that calls the module's ISR() function must be differentiable from process
13541 + * context, even if your processes are impemented via a hardware interrupt.
13542 + * Further locking mechanism between process must exist (or be implemented), and
13543 + * process context must have a way to disable interrupts for a period of time to
13544 + * lock them out. If all of this exists, the functions in dwc_os.h related to
13545 + * threading should be able to be implemented with the defined behavior.
13549 +#ifdef __cplusplus
13553 +#endif /* _DWC_OS_H_ */
13555 +++ b/drivers/usb/host/dwc_common_port/usb.h
13558 + * Copyright (c) 1998 The NetBSD Foundation, Inc.
13559 + * All rights reserved.
13561 + * This code is derived from software contributed to The NetBSD Foundation
13562 + * by Lennart Augustsson (lennart@augustsson.net) at
13563 + * Carlstedt Research & Technology.
13565 + * Redistribution and use in source and binary forms, with or without
13566 + * modification, are permitted provided that the following conditions
13568 + * 1. Redistributions of source code must retain the above copyright
13569 + * notice, this list of conditions and the following disclaimer.
13570 + * 2. Redistributions in binary form must reproduce the above copyright
13571 + * notice, this list of conditions and the following disclaimer in the
13572 + * documentation and/or other materials provided with the distribution.
13573 + * 3. All advertising materials mentioning features or use of this software
13574 + * must display the following acknowledgement:
13575 + * This product includes software developed by the NetBSD
13576 + * Foundation, Inc. and its contributors.
13577 + * 4. Neither the name of The NetBSD Foundation nor the names of its
13578 + * contributors may be used to endorse or promote products derived
13579 + * from this software without specific prior written permission.
13581 + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
13582 + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13583 + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
13584 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
13585 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
13586 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
13587 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
13588 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
13589 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
13590 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
13591 + * POSSIBILITY OF SUCH DAMAGE.
13594 +/* Modified by Synopsys, Inc, 12/12/2007 */
13600 +#ifdef __cplusplus
13605 + * The USB records contain some unaligned little-endian word
13606 + * components. The U[SG]ETW macros take care of both the alignment
13607 + * and endian problem and should always be used to access non-byte
13610 +typedef u_int8_t uByte;
13611 +typedef u_int8_t uWord[2];
13612 +typedef u_int8_t uDWord[4];
13614 +#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
13615 +#define UCONSTW(x) { (x) & 0xff, ((x) >> 8) & 0xff }
13616 +#define UCONSTDW(x) { (x) & 0xff, ((x) >> 8) & 0xff, \
13617 + ((x) >> 16) & 0xff, ((x) >> 24) & 0xff }
13620 +#define UGETW(w) ((w)[0] | ((w)[1] << 8))
13621 +#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
13622 +#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
13623 +#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
13624 + (w)[1] = (u_int8_t)((v) >> 8), \
13625 + (w)[2] = (u_int8_t)((v) >> 16), \
13626 + (w)[3] = (u_int8_t)((v) >> 24))
13629 + * On little-endian machines that can handle unanliged accesses
13630 + * (e.g. i386) these macros can be replaced by the following.
13632 +#define UGETW(w) (*(u_int16_t *)(w))
13633 +#define USETW(w,v) (*(u_int16_t *)(w) = (v))
13634 +#define UGETDW(w) (*(u_int32_t *)(w))
13635 +#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
13639 + * Macros for accessing UAS IU fields, which are big-endian
13641 +#define IUSETW2(w,h,l) ((w)[0] = (u_int8_t)(h), (w)[1] = (u_int8_t)(l))
13642 +#define IUCONSTW(x) { ((x) >> 8) & 0xff, (x) & 0xff }
13643 +#define IUCONSTDW(x) { ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
13644 + ((x) >> 8) & 0xff, (x) & 0xff }
13645 +#define IUGETW(w) (((w)[0] << 8) | (w)[1])
13646 +#define IUSETW(w,v) ((w)[0] = (u_int8_t)((v) >> 8), (w)[1] = (u_int8_t)(v))
13647 +#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
13648 +#define IUSETDW(w,v) ((w)[0] = (u_int8_t)((v) >> 24), \
13649 + (w)[1] = (u_int8_t)((v) >> 16), \
13650 + (w)[2] = (u_int8_t)((v) >> 8), \
13651 + (w)[3] = (u_int8_t)(v))
13653 +#define UPACKED __attribute__((__packed__))
13656 + uByte bmRequestType;
13661 +} UPACKED usb_device_request_t;
13663 +#define UT_GET_DIR(a) ((a) & 0x80)
13664 +#define UT_WRITE 0x00
13665 +#define UT_READ 0x80
13667 +#define UT_GET_TYPE(a) ((a) & 0x60)
13668 +#define UT_STANDARD 0x00
13669 +#define UT_CLASS 0x20
13670 +#define UT_VENDOR 0x40
13672 +#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
13673 +#define UT_DEVICE 0x00
13674 +#define UT_INTERFACE 0x01
13675 +#define UT_ENDPOINT 0x02
13676 +#define UT_OTHER 0x03
13678 +#define UT_READ_DEVICE (UT_READ | UT_STANDARD | UT_DEVICE)
13679 +#define UT_READ_INTERFACE (UT_READ | UT_STANDARD | UT_INTERFACE)
13680 +#define UT_READ_ENDPOINT (UT_READ | UT_STANDARD | UT_ENDPOINT)
13681 +#define UT_WRITE_DEVICE (UT_WRITE | UT_STANDARD | UT_DEVICE)
13682 +#define UT_WRITE_INTERFACE (UT_WRITE | UT_STANDARD | UT_INTERFACE)
13683 +#define UT_WRITE_ENDPOINT (UT_WRITE | UT_STANDARD | UT_ENDPOINT)
13684 +#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE)
13685 +#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE)
13686 +#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER)
13687 +#define UT_READ_CLASS_ENDPOINT (UT_READ | UT_CLASS | UT_ENDPOINT)
13688 +#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE)
13689 +#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
13690 +#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER)
13691 +#define UT_WRITE_CLASS_ENDPOINT (UT_WRITE | UT_CLASS | UT_ENDPOINT)
13692 +#define UT_READ_VENDOR_DEVICE (UT_READ | UT_VENDOR | UT_DEVICE)
13693 +#define UT_READ_VENDOR_INTERFACE (UT_READ | UT_VENDOR | UT_INTERFACE)
13694 +#define UT_READ_VENDOR_OTHER (UT_READ | UT_VENDOR | UT_OTHER)
13695 +#define UT_READ_VENDOR_ENDPOINT (UT_READ | UT_VENDOR | UT_ENDPOINT)
13696 +#define UT_WRITE_VENDOR_DEVICE (UT_WRITE | UT_VENDOR | UT_DEVICE)
13697 +#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
13698 +#define UT_WRITE_VENDOR_OTHER (UT_WRITE | UT_VENDOR | UT_OTHER)
13699 +#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
13702 +#define UR_GET_STATUS 0x00
13703 +#define USTAT_STANDARD_STATUS 0x00
13704 +#define WUSTAT_WUSB_FEATURE 0x01
13705 +#define WUSTAT_CHANNEL_INFO 0x02
13706 +#define WUSTAT_RECEIVED_DATA 0x03
13707 +#define WUSTAT_MAS_AVAILABILITY 0x04
13708 +#define WUSTAT_CURRENT_TRANSMIT_POWER 0x05
13709 +#define UR_CLEAR_FEATURE 0x01
13710 +#define UR_SET_FEATURE 0x03
13711 +#define UR_SET_AND_TEST_FEATURE 0x0c
13712 +#define UR_SET_ADDRESS 0x05
13713 +#define UR_GET_DESCRIPTOR 0x06
13714 +#define UDESC_DEVICE 0x01
13715 +#define UDESC_CONFIG 0x02
13716 +#define UDESC_STRING 0x03
13717 +#define UDESC_INTERFACE 0x04
13718 +#define UDESC_ENDPOINT 0x05
13719 +#define UDESC_SS_USB_COMPANION 0x30
13720 +#define UDESC_DEVICE_QUALIFIER 0x06
13721 +#define UDESC_OTHER_SPEED_CONFIGURATION 0x07
13722 +#define UDESC_INTERFACE_POWER 0x08
13723 +#define UDESC_OTG 0x09
13724 +#define WUDESC_SECURITY 0x0c
13725 +#define WUDESC_KEY 0x0d
13726 +#define WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
13727 +#define WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
13728 +#define WUD_KEY_TYPE_ASSOC 0x01
13729 +#define WUD_KEY_TYPE_GTK 0x02
13730 +#define WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
13731 +#define WUD_KEY_ORIGIN_HOST 0x00
13732 +#define WUD_KEY_ORIGIN_DEVICE 0x01
13733 +#define WUDESC_ENCRYPTION_TYPE 0x0e
13734 +#define WUDESC_BOS 0x0f
13735 +#define WUDESC_DEVICE_CAPABILITY 0x10
13736 +#define WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
13737 +#define UDESC_BOS 0x0f
13738 +#define UDESC_DEVICE_CAPABILITY 0x10
13739 +#define UDESC_CS_DEVICE 0x21 /* class specific */
13740 +#define UDESC_CS_CONFIG 0x22
13741 +#define UDESC_CS_STRING 0x23
13742 +#define UDESC_CS_INTERFACE 0x24
13743 +#define UDESC_CS_ENDPOINT 0x25
13744 +#define UDESC_HUB 0x29
13745 +#define UR_SET_DESCRIPTOR 0x07
13746 +#define UR_GET_CONFIG 0x08
13747 +#define UR_SET_CONFIG 0x09
13748 +#define UR_GET_INTERFACE 0x0a
13749 +#define UR_SET_INTERFACE 0x0b
13750 +#define UR_SYNCH_FRAME 0x0c
13751 +#define WUR_SET_ENCRYPTION 0x0d
13752 +#define WUR_GET_ENCRYPTION 0x0e
13753 +#define WUR_SET_HANDSHAKE 0x0f
13754 +#define WUR_GET_HANDSHAKE 0x10
13755 +#define WUR_SET_CONNECTION 0x11
13756 +#define WUR_SET_SECURITY_DATA 0x12
13757 +#define WUR_GET_SECURITY_DATA 0x13
13758 +#define WUR_SET_WUSB_DATA 0x14
13759 +#define WUDATA_DRPIE_INFO 0x01
13760 +#define WUDATA_TRANSMIT_DATA 0x02
13761 +#define WUDATA_TRANSMIT_PARAMS 0x03
13762 +#define WUDATA_RECEIVE_PARAMS 0x04
13763 +#define WUDATA_TRANSMIT_POWER 0x05
13764 +#define WUR_LOOPBACK_DATA_WRITE 0x15
13765 +#define WUR_LOOPBACK_DATA_READ 0x16
13766 +#define WUR_SET_INTERFACE_DS 0x17
13768 +/* Feature numbers */
13769 +#define UF_ENDPOINT_HALT 0
13770 +#define UF_DEVICE_REMOTE_WAKEUP 1
13771 +#define UF_TEST_MODE 2
13772 +#define UF_DEVICE_B_HNP_ENABLE 3
13773 +#define UF_DEVICE_A_HNP_SUPPORT 4
13774 +#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
13775 +#define WUF_WUSB 3
13776 +#define WUF_TX_DRPIE 0x0
13777 +#define WUF_DEV_XMIT_PACKET 0x1
13778 +#define WUF_COUNT_PACKETS 0x2
13779 +#define WUF_CAPTURE_PACKETS 0x3
13780 +#define UF_FUNCTION_SUSPEND 0
13781 +#define UF_U1_ENABLE 48
13782 +#define UF_U2_ENABLE 49
13783 +#define UF_LTM_ENABLE 50
13785 +/* Class requests from the USB 2.0 hub spec, table 11-15 */
13786 +#define UCR_CLEAR_HUB_FEATURE (0x2000 | UR_CLEAR_FEATURE)
13787 +#define UCR_CLEAR_PORT_FEATURE (0x2300 | UR_CLEAR_FEATURE)
13788 +#define UCR_GET_HUB_DESCRIPTOR (0xa000 | UR_GET_DESCRIPTOR)
13789 +#define UCR_GET_HUB_STATUS (0xa000 | UR_GET_STATUS)
13790 +#define UCR_GET_PORT_STATUS (0xa300 | UR_GET_STATUS)
13791 +#define UCR_SET_HUB_FEATURE (0x2000 | UR_SET_FEATURE)
13792 +#define UCR_SET_PORT_FEATURE (0x2300 | UR_SET_FEATURE)
13793 +#define UCR_SET_AND_TEST_PORT_FEATURE (0xa300 | UR_SET_AND_TEST_FEATURE)
13796 +#include <pshpack1.h>
13801 + uByte bDescriptorType;
13802 + uByte bDescriptorSubtype;
13803 +} UPACKED usb_descriptor_t;
13807 + uByte bDescriptorType;
13808 +} UPACKED usb_descriptor_header_t;
13812 + uByte bDescriptorType;
13814 +#define UD_USB_2_0 0x0200
13815 +#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
13816 + uByte bDeviceClass;
13817 + uByte bDeviceSubClass;
13818 + uByte bDeviceProtocol;
13819 + uByte bMaxPacketSize;
13820 + /* The fields below are not part of the initial descriptor. */
13824 + uByte iManufacturer;
13826 + uByte iSerialNumber;
13827 + uByte bNumConfigurations;
13828 +} UPACKED usb_device_descriptor_t;
13829 +#define USB_DEVICE_DESCRIPTOR_SIZE 18
13833 + uByte bDescriptorType;
13834 + uWord wTotalLength;
13835 + uByte bNumInterface;
13836 + uByte bConfigurationValue;
13837 + uByte iConfiguration;
13838 +#define UC_ATT_ONE (1 << 7) /* must be set */
13839 +#define UC_ATT_SELFPOWER (1 << 6) /* self powered */
13840 +#define UC_ATT_WAKEUP (1 << 5) /* can wakeup */
13841 +#define UC_ATT_BATTERY (1 << 4) /* battery powered */
13842 + uByte bmAttributes;
13843 +#define UC_BUS_POWERED 0x80
13844 +#define UC_SELF_POWERED 0x40
13845 +#define UC_REMOTE_WAKEUP 0x20
13846 + uByte bMaxPower; /* max current in 2 mA units */
13847 +#define UC_POWER_FACTOR 2
13848 +} UPACKED usb_config_descriptor_t;
13849 +#define USB_CONFIG_DESCRIPTOR_SIZE 9
13853 + uByte bDescriptorType;
13854 + uByte bInterfaceNumber;
13855 + uByte bAlternateSetting;
13856 + uByte bNumEndpoints;
13857 + uByte bInterfaceClass;
13858 + uByte bInterfaceSubClass;
13859 + uByte bInterfaceProtocol;
13860 + uByte iInterface;
13861 +} UPACKED usb_interface_descriptor_t;
13862 +#define USB_INTERFACE_DESCRIPTOR_SIZE 9
13866 + uByte bDescriptorType;
13867 + uByte bEndpointAddress;
13868 +#define UE_GET_DIR(a) ((a) & 0x80)
13869 +#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7))
13870 +#define UE_DIR_IN 0x80
13871 +#define UE_DIR_OUT 0x00
13872 +#define UE_ADDR 0x0f
13873 +#define UE_GET_ADDR(a) ((a) & UE_ADDR)
13874 + uByte bmAttributes;
13875 +#define UE_XFERTYPE 0x03
13876 +#define UE_CONTROL 0x00
13877 +#define UE_ISOCHRONOUS 0x01
13878 +#define UE_BULK 0x02
13879 +#define UE_INTERRUPT 0x03
13880 +#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE)
13881 +#define UE_ISO_TYPE 0x0c
13882 +#define UE_ISO_ASYNC 0x04
13883 +#define UE_ISO_ADAPT 0x08
13884 +#define UE_ISO_SYNC 0x0c
13885 +#define UE_GET_ISO_TYPE(a) ((a) & UE_ISO_TYPE)
13886 + uWord wMaxPacketSize;
13888 +} UPACKED usb_endpoint_descriptor_t;
13889 +#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
13891 +typedef struct ss_endpoint_companion_descriptor {
13893 + uByte bDescriptorType;
13895 +#define USSE_GET_MAX_STREAMS(a) ((a) & 0x1f)
13896 +#define USSE_SET_MAX_STREAMS(a, b) ((a) | ((b) & 0x1f))
13897 +#define USSE_GET_MAX_PACKET_NUM(a) ((a) & 0x03)
13898 +#define USSE_SET_MAX_PACKET_NUM(a, b) ((a) | ((b) & 0x03))
13899 + uByte bmAttributes;
13900 + uWord wBytesPerInterval;
13901 +} UPACKED ss_endpoint_companion_descriptor_t;
13902 +#define USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE 6
13906 + uByte bDescriptorType;
13907 + uWord bString[127];
13908 +} UPACKED usb_string_descriptor_t;
13909 +#define USB_MAX_STRING_LEN 128
13910 +#define USB_LANGUAGE_TABLE 0 /* # of the string language id table */
13912 +/* Hub specific request */
13913 +#define UR_GET_BUS_STATE 0x02
13914 +#define UR_CLEAR_TT_BUFFER 0x08
13915 +#define UR_RESET_TT 0x09
13916 +#define UR_GET_TT_STATE 0x0a
13917 +#define UR_STOP_TT 0x0b
13919 +/* Hub features */
13920 +#define UHF_C_HUB_LOCAL_POWER 0
13921 +#define UHF_C_HUB_OVER_CURRENT 1
13922 +#define UHF_PORT_CONNECTION 0
13923 +#define UHF_PORT_ENABLE 1
13924 +#define UHF_PORT_SUSPEND 2
13925 +#define UHF_PORT_OVER_CURRENT 3
13926 +#define UHF_PORT_RESET 4
13927 +#define UHF_PORT_L1 5
13928 +#define UHF_PORT_POWER 8
13929 +#define UHF_PORT_LOW_SPEED 9
13930 +#define UHF_PORT_HIGH_SPEED 10
13931 +#define UHF_C_PORT_CONNECTION 16
13932 +#define UHF_C_PORT_ENABLE 17
13933 +#define UHF_C_PORT_SUSPEND 18
13934 +#define UHF_C_PORT_OVER_CURRENT 19
13935 +#define UHF_C_PORT_RESET 20
13936 +#define UHF_C_PORT_L1 23
13937 +#define UHF_PORT_TEST 21
13938 +#define UHF_PORT_INDICATOR 22
13941 + uByte bDescLength;
13942 + uByte bDescriptorType;
13944 + uWord wHubCharacteristics;
13945 +#define UHD_PWR 0x0003
13946 +#define UHD_PWR_GANGED 0x0000
13947 +#define UHD_PWR_INDIVIDUAL 0x0001
13948 +#define UHD_PWR_NO_SWITCH 0x0002
13949 +#define UHD_COMPOUND 0x0004
13950 +#define UHD_OC 0x0018
13951 +#define UHD_OC_GLOBAL 0x0000
13952 +#define UHD_OC_INDIVIDUAL 0x0008
13953 +#define UHD_OC_NONE 0x0010
13954 +#define UHD_TT_THINK 0x0060
13955 +#define UHD_TT_THINK_8 0x0000
13956 +#define UHD_TT_THINK_16 0x0020
13957 +#define UHD_TT_THINK_24 0x0040
13958 +#define UHD_TT_THINK_32 0x0060
13959 +#define UHD_PORT_IND 0x0080
13960 + uByte bPwrOn2PwrGood; /* delay in 2 ms units */
13961 +#define UHD_PWRON_FACTOR 2
13962 + uByte bHubContrCurrent;
13963 + uByte DeviceRemovable[32]; /* max 255 ports */
13964 +#define UHD_NOT_REMOV(desc, i) \
13965 + (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
13966 + /* deprecated */ uByte PortPowerCtrlMask[1];
13967 +} UPACKED usb_hub_descriptor_t;
13968 +#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
13972 + uByte bDescriptorType;
13974 + uByte bDeviceClass;
13975 + uByte bDeviceSubClass;
13976 + uByte bDeviceProtocol;
13977 + uByte bMaxPacketSize0;
13978 + uByte bNumConfigurations;
13980 +} UPACKED usb_device_qualifier_t;
13981 +#define USB_DEVICE_QUALIFIER_SIZE 10
13985 + uByte bDescriptorType;
13986 + uByte bmAttributes;
13987 +#define UOTG_SRP 0x01
13988 +#define UOTG_HNP 0x02
13989 +} UPACKED usb_otg_descriptor_t;
13991 +/* OTG feature selectors */
13992 +#define UOTG_B_HNP_ENABLE 3
13993 +#define UOTG_A_HNP_SUPPORT 4
13994 +#define UOTG_A_ALT_HNP_SUPPORT 5
13998 +/* Device status flags */
13999 +#define UDS_SELF_POWERED 0x0001
14000 +#define UDS_REMOTE_WAKEUP 0x0002
14001 +/* Endpoint status flags */
14002 +#define UES_HALT 0x0001
14003 +} UPACKED usb_status_t;
14006 + uWord wHubStatus;
14007 +#define UHS_LOCAL_POWER 0x0001
14008 +#define UHS_OVER_CURRENT 0x0002
14009 + uWord wHubChange;
14010 +} UPACKED usb_hub_status_t;
14013 + uWord wPortStatus;
14014 +#define UPS_CURRENT_CONNECT_STATUS 0x0001
14015 +#define UPS_PORT_ENABLED 0x0002
14016 +#define UPS_SUSPEND 0x0004
14017 +#define UPS_OVERCURRENT_INDICATOR 0x0008
14018 +#define UPS_RESET 0x0010
14019 +#define UPS_PORT_POWER 0x0100
14020 +#define UPS_LOW_SPEED 0x0200
14021 +#define UPS_HIGH_SPEED 0x0400
14022 +#define UPS_PORT_TEST 0x0800
14023 +#define UPS_PORT_INDICATOR 0x1000
14024 + uWord wPortChange;
14025 +#define UPS_C_CONNECT_STATUS 0x0001
14026 +#define UPS_C_PORT_ENABLED 0x0002
14027 +#define UPS_C_SUSPEND 0x0004
14028 +#define UPS_C_OVERCURRENT_INDICATOR 0x0008
14029 +#define UPS_C_PORT_RESET 0x0010
14030 +} UPACKED usb_port_status_t;
14033 +#include <poppack.h>
14036 +/* Device class codes */
14037 +#define UDCLASS_IN_INTERFACE 0x00
14038 +#define UDCLASS_COMM 0x02
14039 +#define UDCLASS_HUB 0x09
14040 +#define UDSUBCLASS_HUB 0x00
14041 +#define UDPROTO_FSHUB 0x00
14042 +#define UDPROTO_HSHUBSTT 0x01
14043 +#define UDPROTO_HSHUBMTT 0x02
14044 +#define UDCLASS_DIAGNOSTIC 0xdc
14045 +#define UDCLASS_WIRELESS 0xe0
14046 +#define UDSUBCLASS_RF 0x01
14047 +#define UDPROTO_BLUETOOTH 0x01
14048 +#define UDCLASS_VENDOR 0xff
14050 +/* Interface class codes */
14051 +#define UICLASS_UNSPEC 0x00
14053 +#define UICLASS_AUDIO 0x01
14054 +#define UISUBCLASS_AUDIOCONTROL 1
14055 +#define UISUBCLASS_AUDIOSTREAM 2
14056 +#define UISUBCLASS_MIDISTREAM 3
14058 +#define UICLASS_CDC 0x02 /* communication */
14059 +#define UISUBCLASS_DIRECT_LINE_CONTROL_MODEL 1
14060 +#define UISUBCLASS_ABSTRACT_CONTROL_MODEL 2
14061 +#define UISUBCLASS_TELEPHONE_CONTROL_MODEL 3
14062 +#define UISUBCLASS_MULTICHANNEL_CONTROL_MODEL 4
14063 +#define UISUBCLASS_CAPI_CONTROLMODEL 5
14064 +#define UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
14065 +#define UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
14066 +#define UIPROTO_CDC_AT 1
14068 +#define UICLASS_HID 0x03
14069 +#define UISUBCLASS_BOOT 1
14070 +#define UIPROTO_BOOT_KEYBOARD 1
14072 +#define UICLASS_PHYSICAL 0x05
14074 +#define UICLASS_IMAGE 0x06
14076 +#define UICLASS_PRINTER 0x07
14077 +#define UISUBCLASS_PRINTER 1
14078 +#define UIPROTO_PRINTER_UNI 1
14079 +#define UIPROTO_PRINTER_BI 2
14080 +#define UIPROTO_PRINTER_1284 3
14082 +#define UICLASS_MASS 0x08
14083 +#define UISUBCLASS_RBC 1
14084 +#define UISUBCLASS_SFF8020I 2
14085 +#define UISUBCLASS_QIC157 3
14086 +#define UISUBCLASS_UFI 4
14087 +#define UISUBCLASS_SFF8070I 5
14088 +#define UISUBCLASS_SCSI 6
14089 +#define UIPROTO_MASS_CBI_I 0
14090 +#define UIPROTO_MASS_CBI 1
14091 +#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */
14092 +#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */
14094 +#define UICLASS_HUB 0x09
14095 +#define UISUBCLASS_HUB 0
14096 +#define UIPROTO_FSHUB 0
14097 +#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */
14098 +#define UIPROTO_HSHUBMTT 1
14100 +#define UICLASS_CDC_DATA 0x0a
14101 +#define UISUBCLASS_DATA 0
14102 +#define UIPROTO_DATA_ISDNBRI 0x30 /* Physical iface */
14103 +#define UIPROTO_DATA_HDLC 0x31 /* HDLC */
14104 +#define UIPROTO_DATA_TRANSPARENT 0x32 /* Transparent */
14105 +#define UIPROTO_DATA_Q921M 0x50 /* Management for Q921 */
14106 +#define UIPROTO_DATA_Q921 0x51 /* Data for Q921 */
14107 +#define UIPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */
14108 +#define UIPROTO_DATA_V42BIS 0x90 /* Data compression */
14109 +#define UIPROTO_DATA_Q931 0x91 /* Euro-ISDN */
14110 +#define UIPROTO_DATA_V120 0x92 /* V.24 rate adaption */
14111 +#define UIPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */
14112 +#define UIPROTO_DATA_HOST_BASED 0xfd /* Host based driver */
14113 +#define UIPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc.*/
14114 +#define UIPROTO_DATA_VENDOR 0xff /* Vendor specific */
14116 +#define UICLASS_SMARTCARD 0x0b
14118 +/*#define UICLASS_FIRM_UPD 0x0c*/
14120 +#define UICLASS_SECURITY 0x0d
14122 +#define UICLASS_DIAGNOSTIC 0xdc
14124 +#define UICLASS_WIRELESS 0xe0
14125 +#define UISUBCLASS_RF 0x01
14126 +#define UIPROTO_BLUETOOTH 0x01
14128 +#define UICLASS_APPL_SPEC 0xfe
14129 +#define UISUBCLASS_FIRMWARE_DOWNLOAD 1
14130 +#define UISUBCLASS_IRDA 2
14131 +#define UIPROTO_IRDA 0
14133 +#define UICLASS_VENDOR 0xff
14135 +#define USB_HUB_MAX_DEPTH 5
14138 + * Minimum time a device needs to be powered down to go through
14139 + * a power cycle. XXX Are these time in the spec?
14141 +#define USB_POWER_DOWN_TIME 200 /* ms */
14142 +#define USB_PORT_POWER_DOWN_TIME 100 /* ms */
14145 +/* These are the values from the spec. */
14146 +#define USB_PORT_RESET_DELAY 10 /* ms */
14147 +#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
14148 +#define USB_PORT_RESET_RECOVERY 10 /* ms */
14149 +#define USB_PORT_POWERUP_DELAY 100 /* ms */
14150 +#define USB_SET_ADDRESS_SETTLE 2 /* ms */
14151 +#define USB_RESUME_DELAY (20*5) /* ms */
14152 +#define USB_RESUME_WAIT 10 /* ms */
14153 +#define USB_RESUME_RECOVERY 10 /* ms */
14154 +#define USB_EXTRA_POWER_UP_TIME 0 /* ms */
14156 +/* Allow for marginal (i.e. non-conforming) devices. */
14157 +#define USB_PORT_RESET_DELAY 50 /* ms */
14158 +#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
14159 +#define USB_PORT_RESET_RECOVERY 250 /* ms */
14160 +#define USB_PORT_POWERUP_DELAY 300 /* ms */
14161 +#define USB_SET_ADDRESS_SETTLE 10 /* ms */
14162 +#define USB_RESUME_DELAY (50*5) /* ms */
14163 +#define USB_RESUME_WAIT 50 /* ms */
14164 +#define USB_RESUME_RECOVERY 50 /* ms */
14165 +#define USB_EXTRA_POWER_UP_TIME 20 /* ms */
14168 +#define USB_MIN_POWER 100 /* mA */
14169 +#define USB_MAX_POWER 500 /* mA */
14171 +#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/
14173 +#define USB_UNCONFIG_NO 0
14174 +#define USB_UNCONFIG_INDEX (-1)
14176 +/*** ioctl() related stuff ***/
14178 +struct usb_ctl_request {
14180 + usb_device_request_t ucr_request;
14183 +#define USBD_SHORT_XFER_OK 0x04 /* allow short reads */
14184 + int ucr_actlen; /* actual length transferred */
14187 +struct usb_alt_interface {
14188 + int uai_config_index;
14189 + int uai_interface_index;
14193 +#define USB_CURRENT_CONFIG_INDEX (-1)
14194 +#define USB_CURRENT_ALT_INDEX (-1)
14196 +struct usb_config_desc {
14197 + int ucd_config_index;
14198 + usb_config_descriptor_t ucd_desc;
14201 +struct usb_interface_desc {
14202 + int uid_config_index;
14203 + int uid_interface_index;
14204 + int uid_alt_index;
14205 + usb_interface_descriptor_t uid_desc;
14208 +struct usb_endpoint_desc {
14209 + int ued_config_index;
14210 + int ued_interface_index;
14211 + int ued_alt_index;
14212 + int ued_endpoint_index;
14213 + usb_endpoint_descriptor_t ued_desc;
14216 +struct usb_full_desc {
14217 + int ufd_config_index;
14219 + u_char *ufd_data;
14222 +struct usb_string_desc {
14223 + int usd_string_index;
14224 + int usd_language_id;
14225 + usb_string_descriptor_t usd_desc;
14228 +struct usb_ctl_report_desc {
14230 + u_char ucrd_data[1024]; /* filled data size will vary */
14233 +typedef struct { u_int32_t cookie; } usb_event_cookie_t;
14235 +#define USB_MAX_DEVNAMES 4
14236 +#define USB_MAX_DEVNAMELEN 16
14237 +struct usb_device_info {
14238 + u_int8_t udi_bus;
14239 + u_int8_t udi_addr; /* device address */
14240 + usb_event_cookie_t udi_cookie;
14241 + char udi_product[USB_MAX_STRING_LEN];
14242 + char udi_vendor[USB_MAX_STRING_LEN];
14243 + char udi_release[8];
14244 + u_int16_t udi_productNo;
14245 + u_int16_t udi_vendorNo;
14246 + u_int16_t udi_releaseNo;
14247 + u_int8_t udi_class;
14248 + u_int8_t udi_subclass;
14249 + u_int8_t udi_protocol;
14250 + u_int8_t udi_config;
14251 + u_int8_t udi_speed;
14252 +#define USB_SPEED_UNKNOWN 0
14253 +#define USB_SPEED_LOW 1
14254 +#define USB_SPEED_FULL 2
14255 +#define USB_SPEED_HIGH 3
14256 +#define USB_SPEED_VARIABLE 4
14257 +#define USB_SPEED_SUPER 5
14258 + int udi_power; /* power consumption in mA, 0 if selfpowered */
14260 + char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
14261 + u_int8_t udi_ports[16];/* hub only: addresses of devices on ports */
14262 +#define USB_PORT_ENABLED 0xff
14263 +#define USB_PORT_SUSPENDED 0xfe
14264 +#define USB_PORT_POWERED 0xfd
14265 +#define USB_PORT_DISABLED 0xfc
14268 +struct usb_ctl_report {
14270 + u_char ucr_data[1024]; /* filled data size will vary */
14273 +struct usb_device_stats {
14274 + u_long uds_requests[4]; /* indexed by transfer type UE_* */
14277 +#define WUSB_MIN_IE 0x80
14278 +#define WUSB_WCTA_IE 0x80
14279 +#define WUSB_WCONNECTACK_IE 0x81
14280 +#define WUSB_WHOSTINFO_IE 0x82
14281 +#define WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
14282 +#define WUHI_CA_RECONN 0x00
14283 +#define WUHI_CA_LIMITED 0x01
14284 +#define WUHI_CA_ALL 0x03
14285 +#define WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
14286 +#define WUSB_WCHCHANGEANNOUNCE_IE 0x83
14287 +#define WUSB_WDEV_DISCONNECT_IE 0x84
14288 +#define WUSB_WHOST_DISCONNECT_IE 0x85
14289 +#define WUSB_WRELEASE_CHANNEL_IE 0x86
14290 +#define WUSB_WWORK_IE 0x87
14291 +#define WUSB_WCHANNEL_STOP_IE 0x88
14292 +#define WUSB_WDEV_KEEPALIVE_IE 0x89
14293 +#define WUSB_WISOCH_DISCARD_IE 0x8A
14294 +#define WUSB_WRESETDEVICE_IE 0x8B
14295 +#define WUSB_WXMIT_PACKET_ADJUST_IE 0x8C
14296 +#define WUSB_MAX_IE 0x8C
14298 +/* Device Notification Types */
14300 +#define WUSB_DN_MIN 0x01
14301 +#define WUSB_DN_CONNECT 0x01
14302 +# define WUSB_DA_OLDCONN 0x00
14303 +# define WUSB_DA_NEWCONN 0x01
14304 +# define WUSB_DA_SELF_BEACON 0x02
14305 +# define WUSB_DA_DIR_BEACON 0x04
14306 +# define WUSB_DA_NO_BEACON 0x06
14307 +#define WUSB_DN_DISCONNECT 0x02
14308 +#define WUSB_DN_EPRDY 0x03
14309 +#define WUSB_DN_MASAVAILCHANGED 0x04
14310 +#define WUSB_DN_REMOTEWAKEUP 0x05
14311 +#define WUSB_DN_SLEEP 0x06
14312 +#define WUSB_DN_ALIVE 0x07
14313 +#define WUSB_DN_MAX 0x07
14316 +#include <pshpack1.h>
14319 +/* WUSB Handshake Data. Used during the SET/GET HANDSHAKE requests */
14320 +typedef struct wusb_hndshk_data {
14321 + uByte bMessageNumber;
14328 +} UPACKED wusb_hndshk_data_t;
14329 +#define WUSB_HANDSHAKE_LEN_FOR_MIC 38
14331 +/* WUSB Connection Context */
14332 +typedef struct wusb_conn_context {
14336 +} UPACKED wusb_conn_context_t;
14338 +/* WUSB Security Descriptor */
14339 +typedef struct wusb_security_desc {
14341 + uByte bDescriptorType;
14342 + uWord wTotalLength;
14343 + uByte bNumEncryptionTypes;
14344 +} UPACKED wusb_security_desc_t;
14346 +/* WUSB Encryption Type Descriptor */
14347 +typedef struct wusb_encrypt_type_desc {
14349 + uByte bDescriptorType;
14351 + uByte bEncryptionType;
14352 +#define WUETD_UNSECURE 0
14353 +#define WUETD_WIRED 1
14354 +#define WUETD_CCM_1 2
14355 +#define WUETD_RSA_1 3
14357 + uByte bEncryptionValue;
14358 + uByte bAuthKeyIndex;
14359 +} UPACKED wusb_encrypt_type_desc_t;
14361 +/* WUSB Key Descriptor */
14362 +typedef struct wusb_key_desc {
14364 + uByte bDescriptorType;
14367 + uByte KeyData[1]; /* variable length */
14368 +} UPACKED wusb_key_desc_t;
14370 +/* WUSB BOS Descriptor (Binary device Object Store) */
14371 +typedef struct wusb_bos_desc {
14373 + uByte bDescriptorType;
14374 + uWord wTotalLength;
14375 + uByte bNumDeviceCaps;
14376 +} UPACKED wusb_bos_desc_t;
14378 +#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02
14379 +typedef struct usb_dev_cap_20_ext_desc {
14381 + uByte bDescriptorType;
14382 + uByte bDevCapabilityType;
14383 +#define USB_20_EXT_LPM 0x02
14384 + uDWord bmAttributes;
14385 +} UPACKED usb_dev_cap_20_ext_desc_t;
14387 +#define USB_DEVICE_CAPABILITY_SS_USB 0x03
14388 +typedef struct usb_dev_cap_ss_usb {
14390 + uByte bDescriptorType;
14391 + uByte bDevCapabilityType;
14392 +#define USB_DC_SS_USB_LTM_CAPABLE 0x02
14393 + uByte bmAttributes;
14394 +#define USB_DC_SS_USB_SPEED_SUPPORT_LOW 0x01
14395 +#define USB_DC_SS_USB_SPEED_SUPPORT_FULL 0x02
14396 +#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH 0x04
14397 +#define USB_DC_SS_USB_SPEED_SUPPORT_SS 0x08
14398 + uWord wSpeedsSupported;
14399 + uByte bFunctionalitySupport;
14400 + uByte bU1DevExitLat;
14401 + uWord wU2DevExitLat;
14402 +} UPACKED usb_dev_cap_ss_usb_t;
14404 +#define USB_DEVICE_CAPABILITY_CONTAINER_ID 0x04
14405 +typedef struct usb_dev_cap_container_id {
14407 + uByte bDescriptorType;
14408 + uByte bDevCapabilityType;
14410 + uByte containerID[16];
14411 +} UPACKED usb_dev_cap_container_id_t;
14413 +/* Device Capability Type Codes */
14414 +#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
14416 +/* Device Capability Descriptor */
14417 +typedef struct wusb_dev_cap_desc {
14419 + uByte bDescriptorType;
14420 + uByte bDevCapabilityType;
14421 + uByte caps[1]; /* Variable length */
14422 +} UPACKED wusb_dev_cap_desc_t;
14424 +/* Device Capability Descriptor */
14425 +typedef struct wusb_dev_cap_uwb_desc {
14427 + uByte bDescriptorType;
14428 + uByte bDevCapabilityType;
14429 + uByte bmAttributes;
14430 + uWord wPHYRates; /* Bitmap */
14431 + uByte bmTFITXPowerInfo;
14432 + uByte bmFFITXPowerInfo;
14433 + uWord bmBandGroup;
14435 +} UPACKED wusb_dev_cap_uwb_desc_t;
14437 +/* Wireless USB Endpoint Companion Descriptor */
14438 +typedef struct wusb_endpoint_companion_desc {
14440 + uByte bDescriptorType;
14442 + uByte bMaxSequence;
14443 + uWord wMaxStreamDelay;
14444 + uWord wOverTheAirPacketSize;
14445 + uByte bOverTheAirInterval;
14446 + uByte bmCompAttributes;
14447 +} UPACKED wusb_endpoint_companion_desc_t;
14449 +/* Wireless USB Numeric Association M1 Data Structure */
14450 +typedef struct wusb_m1_data {
14453 + uByte deviceFriendlyNameLength;
14454 + uByte sha_256_m3[32];
14455 + uByte deviceFriendlyName[256];
14456 +} UPACKED wusb_m1_data_t;
14458 +typedef struct wusb_m2_data {
14461 + uByte hostFriendlyNameLength;
14463 + uByte hostFriendlyName[256];
14464 +} UPACKED wusb_m2_data_t;
14466 +typedef struct wusb_m3_data {
14469 +} UPACKED wusb_m3_data_t;
14471 +typedef struct wusb_m4_data {
14472 + uDWord _attributeTypeIdAndLength_1;
14473 + uWord associationTypeId;
14475 + uDWord _attributeTypeIdAndLength_2;
14476 + uWord associationSubTypeId;
14478 + uDWord _attributeTypeIdAndLength_3;
14481 + uDWord _attributeTypeIdAndLength_4;
14482 + uDWord associationStatus;
14484 + uDWord _attributeTypeIdAndLength_5;
14487 + uDWord _attributeTypeIdAndLength_6;
14490 + uDWord _attributeTypeIdAndLength_7;
14491 + uByte bandGroups[2];
14492 +} UPACKED wusb_m4_data_t;
14495 +#include <poppack.h>
14498 +#ifdef __cplusplus
14502 +#endif /* _USB_H_ */
14504 +++ b/drivers/usb/host/dwc_otg/Makefile
14507 +# Makefile for DWC_otg Highspeed USB controller driver
14510 +ifneq ($(KERNELRELEASE),)
14512 +# Use the BUS_INTERFACE variable to compile the software for either
14513 +# PCI(PCI_INTERFACE) or LM(LM_INTERFACE) bus.
14514 +ifeq ($(BUS_INTERFACE),)
14515 +# BUS_INTERFACE = -DPCI_INTERFACE
14516 +# BUS_INTERFACE = -DLM_INTERFACE
14517 + BUS_INTERFACE = -DPLATFORM_INTERFACE
14520 +#ccflags-y += -DDEBUG
14521 +#ccflags-y += -DDWC_OTG_DEBUGLEV=1 # reduce common debug msgs
14523 +# Use one of the following flags to compile the software in host-only or
14524 +# device-only mode.
14525 +#ccflags-y += -DDWC_HOST_ONLY
14526 +#ccflags-y += -DDWC_DEVICE_ONLY
14528 +ccflags-y += -Dlinux -DDWC_HS_ELECT_TST
14529 +#ccflags-y += -DDWC_EN_ISOC
14530 +ccflags-y += -I$(obj)/../dwc_common_port
14531 +#ccflags-y += -I$(PORTLIB)
14532 +ccflags-y += -DDWC_LINUX
14533 +ccflags-y += $(CFI)
14534 +ccflags-y += $(BUS_INTERFACE)
14535 +#ccflags-y += -DDWC_DEV_SRPCAP
14537 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o
14539 +dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o
14540 +dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
14541 +dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o
14542 +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
14543 +dwc_otg-objs += dwc_otg_adp.o
14545 +dwc_otg-objs += dwc_otg_cfi.o
14548 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
14549 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
14551 +ifneq ($(kernrel3),2.6.20)
14552 +ccflags-y += $(CPPFLAGS)
14557 +PWD := $(shell pwd)
14558 +PORTLIB := $(PWD)/../dwc_common_port
14562 +DOXYGEN := $(DOXYGEN)
14565 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
14568 + $(MAKE) -C$(KDIR) M=$(PORTLIB) modules_install
14569 + $(MAKE) -C$(KDIR) M=$(PWD) modules_install
14572 + $(MAKE) -C$(KDIR) M=$(PORTLIB) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
14573 + cp $(PORTLIB)/Module.symvers $(PWD)/
14575 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
14576 + $(DOXYGEN) doc/doxygen.cfg
14578 +tags: $(wildcard *.[hc])
14579 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
14583 + rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers
14587 +++ b/drivers/usb/host/dwc_otg/doc/doxygen.cfg
14589 +# Doxyfile 1.3.9.1
14591 +#---------------------------------------------------------------------------
14592 +# Project related configuration options
14593 +#---------------------------------------------------------------------------
14594 +PROJECT_NAME = "DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver"
14595 +PROJECT_NUMBER = v3.00a
14596 +OUTPUT_DIRECTORY = ./doc/
14597 +CREATE_SUBDIRS = NO
14598 +OUTPUT_LANGUAGE = English
14599 +BRIEF_MEMBER_DESC = YES
14600 +REPEAT_BRIEF = YES
14601 +ABBREVIATE_BRIEF = "The $name class" \
14602 + "The $name widget" \
14603 + "The $name file" \
14612 +ALWAYS_DETAILED_SEC = NO
14613 +INLINE_INHERITED_MEMB = NO
14614 +FULL_PATH_NAMES = NO
14616 +STRIP_FROM_INC_PATH =
14618 +JAVADOC_AUTOBRIEF = YES
14619 +MULTILINE_CPP_IS_BRIEF = NO
14620 +INHERIT_DOCS = YES
14621 +DISTRIBUTE_GROUP_DOC = NO
14624 +OPTIMIZE_OUTPUT_FOR_C = YES
14625 +OPTIMIZE_OUTPUT_JAVA = NO
14627 +#---------------------------------------------------------------------------
14628 +# Build related configuration options
14629 +#---------------------------------------------------------------------------
14631 +EXTRACT_PRIVATE = YES
14632 +EXTRACT_STATIC = YES
14633 +EXTRACT_LOCAL_CLASSES = YES
14634 +EXTRACT_LOCAL_METHODS = NO
14635 +HIDE_UNDOC_MEMBERS = NO
14636 +HIDE_UNDOC_CLASSES = NO
14637 +HIDE_FRIEND_COMPOUNDS = NO
14638 +HIDE_IN_BODY_DOCS = NO
14639 +INTERNAL_DOCS = NO
14640 +CASE_SENSE_NAMES = NO
14641 +HIDE_SCOPE_NAMES = NO
14642 +SHOW_INCLUDE_FILES = YES
14644 +SORT_MEMBER_DOCS = NO
14645 +SORT_BRIEF_DOCS = NO
14646 +SORT_BY_SCOPE_NAME = NO
14647 +GENERATE_TODOLIST = YES
14648 +GENERATE_TESTLIST = YES
14649 +GENERATE_BUGLIST = YES
14650 +GENERATE_DEPRECATEDLIST= YES
14651 +ENABLED_SECTIONS =
14652 +MAX_INITIALIZER_LINES = 30
14653 +SHOW_USED_FILES = YES
14654 +SHOW_DIRECTORIES = YES
14655 +#---------------------------------------------------------------------------
14656 +# configuration options related to warning and progress messages
14657 +#---------------------------------------------------------------------------
14660 +WARN_IF_UNDOCUMENTED = NO
14661 +WARN_IF_DOC_ERROR = YES
14662 +WARN_FORMAT = "$file:$line: $text"
14664 +#---------------------------------------------------------------------------
14665 +# configuration options related to the input files
14666 +#---------------------------------------------------------------------------
14668 +FILE_PATTERNS = *.c \
14673 +EXCLUDE = ./test/ \
14674 + ./dwc_otg/.AppleDouble/
14675 +EXCLUDE_SYMLINKS = YES
14676 +EXCLUDE_PATTERNS = *.mod.*
14678 +EXAMPLE_PATTERNS = *
14679 +EXAMPLE_RECURSIVE = NO
14683 +FILTER_SOURCE_FILES = NO
14684 +#---------------------------------------------------------------------------
14685 +# configuration options related to source browsing
14686 +#---------------------------------------------------------------------------
14687 +SOURCE_BROWSER = YES
14688 +INLINE_SOURCES = NO
14689 +STRIP_CODE_COMMENTS = YES
14690 +REFERENCED_BY_RELATION = NO
14691 +REFERENCES_RELATION = NO
14692 +VERBATIM_HEADERS = NO
14693 +#---------------------------------------------------------------------------
14694 +# configuration options related to the alphabetical class index
14695 +#---------------------------------------------------------------------------
14696 +ALPHABETICAL_INDEX = NO
14697 +COLS_IN_ALPHA_INDEX = 5
14699 +#---------------------------------------------------------------------------
14700 +# configuration options related to the HTML output
14701 +#---------------------------------------------------------------------------
14702 +GENERATE_HTML = YES
14703 +HTML_OUTPUT = html
14704 +HTML_FILE_EXTENSION = .html
14708 +HTML_ALIGN_MEMBERS = YES
14709 +GENERATE_HTMLHELP = NO
14715 +DISABLE_INDEX = NO
14716 +ENUM_VALUES_PER_LINE = 4
14717 +GENERATE_TREEVIEW = YES
14718 +TREEVIEW_WIDTH = 250
14719 +#---------------------------------------------------------------------------
14720 +# configuration options related to the LaTeX output
14721 +#---------------------------------------------------------------------------
14722 +GENERATE_LATEX = NO
14723 +LATEX_OUTPUT = latex
14724 +LATEX_CMD_NAME = latex
14725 +MAKEINDEX_CMD_NAME = makeindex
14726 +COMPACT_LATEX = NO
14727 +PAPER_TYPE = a4wide
14730 +PDF_HYPERLINKS = NO
14732 +LATEX_BATCHMODE = NO
14733 +LATEX_HIDE_INDICES = NO
14734 +#---------------------------------------------------------------------------
14735 +# configuration options related to the RTF output
14736 +#---------------------------------------------------------------------------
14740 +RTF_HYPERLINKS = NO
14741 +RTF_STYLESHEET_FILE =
14742 +RTF_EXTENSIONS_FILE =
14743 +#---------------------------------------------------------------------------
14744 +# configuration options related to the man page output
14745 +#---------------------------------------------------------------------------
14748 +MAN_EXTENSION = .3
14750 +#---------------------------------------------------------------------------
14751 +# configuration options related to the XML output
14752 +#---------------------------------------------------------------------------
14757 +XML_PROGRAMLISTING = YES
14758 +#---------------------------------------------------------------------------
14759 +# configuration options for the AutoGen Definitions output
14760 +#---------------------------------------------------------------------------
14761 +GENERATE_AUTOGEN_DEF = NO
14762 +#---------------------------------------------------------------------------
14763 +# configuration options related to the Perl module output
14764 +#---------------------------------------------------------------------------
14765 +GENERATE_PERLMOD = NO
14766 +PERLMOD_LATEX = NO
14767 +PERLMOD_PRETTY = YES
14768 +PERLMOD_MAKEVAR_PREFIX =
14769 +#---------------------------------------------------------------------------
14770 +# Configuration options related to the preprocessor
14771 +#---------------------------------------------------------------------------
14772 +ENABLE_PREPROCESSING = YES
14773 +MACRO_EXPANSION = YES
14774 +EXPAND_ONLY_PREDEF = YES
14775 +SEARCH_INCLUDES = YES
14777 +INCLUDE_FILE_PATTERNS =
14778 +PREDEFINED = DEVICE_ATTR DWC_EN_ISOC
14779 +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
14780 +SKIP_FUNCTION_MACROS = NO
14781 +#---------------------------------------------------------------------------
14782 +# Configuration::additions related to external references
14783 +#---------------------------------------------------------------------------
14785 +GENERATE_TAGFILE =
14787 +EXTERNAL_GROUPS = YES
14788 +PERL_PATH = /usr/bin/perl
14789 +#---------------------------------------------------------------------------
14790 +# Configuration options related to the dot tool
14791 +#---------------------------------------------------------------------------
14792 +CLASS_DIAGRAMS = YES
14793 +HIDE_UNDOC_RELATIONS = YES
14796 +COLLABORATION_GRAPH = YES
14798 +TEMPLATE_RELATIONS = NO
14799 +INCLUDE_GRAPH = YES
14800 +INCLUDED_BY_GRAPH = YES
14802 +GRAPHICAL_HIERARCHY = YES
14803 +DOT_IMAGE_FORMAT = png
14806 +MAX_DOT_GRAPH_DEPTH = 1000
14807 +GENERATE_LEGEND = YES
14809 +#---------------------------------------------------------------------------
14810 +# Configuration::additions related to the search engine
14811 +#---------------------------------------------------------------------------
14814 +++ b/drivers/usb/host/dwc_otg/dummy_audio.c
14817 + * zero.c -- Gadget Zero, for USB development
14819 + * Copyright (C) 2003-2004 David Brownell
14820 + * All rights reserved.
14822 + * Redistribution and use in source and binary forms, with or without
14823 + * modification, are permitted provided that the following conditions
14825 + * 1. Redistributions of source code must retain the above copyright
14826 + * notice, this list of conditions, and the following disclaimer,
14827 + * without modification.
14828 + * 2. Redistributions in binary form must reproduce the above copyright
14829 + * notice, this list of conditions and the following disclaimer in the
14830 + * documentation and/or other materials provided with the distribution.
14831 + * 3. The names of the above-listed copyright holders may not be used
14832 + * to endorse or promote products derived from this software without
14833 + * specific prior written permission.
14835 + * ALTERNATIVELY, this software may be distributed under the terms of the
14836 + * GNU General Public License ("GPL") as published by the Free Software
14837 + * Foundation, either version 2 of that License or (at your option) any
14840 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
14841 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14842 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14843 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
14844 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
14845 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
14846 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
14847 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
14848 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
14849 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
14850 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14855 + * Gadget Zero only needs two bulk endpoints, and is an example of how you
14856 + * can write a hardware-agnostic gadget driver running inside a USB device.
14858 + * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
14859 + * affect most of the driver.
14861 + * Use it with the Linux host/master side "usbtest" driver to get a basic
14862 + * functional test of your device-side usb stack, or with "usb-skeleton".
14864 + * It supports two similar configurations. One sinks whatever the usb host
14865 + * writes, and in return sources zeroes. The other loops whatever the host
14866 + * writes back, so the host can read it. Module options include:
14868 + * buflen=N default N=4096, buffer size used
14869 + * qlen=N default N=32, how many buffers in the loopback queue
14870 + * loopdefault default false, list loopback config first
14872 + * Many drivers will only have one configuration, letting them be much
14873 + * simpler if they also don't support high speed operation (like this
14877 +#include <linux/config.h>
14878 +#include <linux/module.h>
14879 +#include <linux/kernel.h>
14880 +#include <linux/delay.h>
14881 +#include <linux/ioport.h>
14882 +#include <linux/sched.h>
14883 +#include <linux/slab.h>
14884 +#include <linux/smp_lock.h>
14885 +#include <linux/errno.h>
14886 +#include <linux/init.h>
14887 +#include <linux/timer.h>
14888 +#include <linux/list.h>
14889 +#include <linux/interrupt.h>
14890 +#include <linux/uts.h>
14891 +#include <linux/version.h>
14892 +#include <linux/device.h>
14893 +#include <linux/moduleparam.h>
14894 +#include <linux/proc_fs.h>
14896 +#include <asm/byteorder.h>
14897 +#include <asm/io.h>
14898 +#include <asm/irq.h>
14899 +#include <asm/system.h>
14900 +#include <asm/unaligned.h>
14902 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
14903 +# include <linux/usb/ch9.h>
14905 +# include <linux/usb_ch9.h>
14908 +#include <linux/usb_gadget.h>
14911 +/*-------------------------------------------------------------------------*/
14912 +/*-------------------------------------------------------------------------*/
14915 +static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
14921 + /* this insists on correct encodings, though not minimal ones.
14922 + * BUT it currently rejects legit 4-byte UTF-8 code points,
14923 + * which need surrogate pairs. (Unicode 3.1 can use them.)
14925 + while (len != 0 && (c = (u8) *s++) != 0) {
14926 + if (unlikely(c & 0x80)) {
14927 + // 2-byte sequence:
14928 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
14929 + if ((c & 0xe0) == 0xc0) {
14930 + uchar = (c & 0x1f) << 6;
14933 + if ((c & 0xc0) != 0xc0)
14938 + // 3-byte sequence (most CJKV characters):
14939 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
14940 + } else if ((c & 0xf0) == 0xe0) {
14941 + uchar = (c & 0x0f) << 12;
14944 + if ((c & 0xc0) != 0xc0)
14950 + if ((c & 0xc0) != 0xc0)
14955 + /* no bogus surrogates */
14956 + if (0xd800 <= uchar && uchar <= 0xdfff)
14959 + // 4-byte sequence (surrogate pairs, currently rare):
14960 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
14961 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
14962 + // (uuuuu = wwww + 1)
14963 + // FIXME accept the surrogate code points (only)
14969 + put_unaligned (cpu_to_le16 (uchar), cp++);
14980 + * usb_gadget_get_string - fill out a string descriptor
14981 + * @table: of c strings encoded using UTF-8
14982 + * @id: string id, from low byte of wValue in get string descriptor
14983 + * @buf: at least 256 bytes
14985 + * Finds the UTF-8 string matching the ID, and converts it into a
14986 + * string descriptor in utf16-le.
14987 + * Returns length of descriptor (always even) or negative errno
14989 + * If your driver needs stings in multiple languages, you'll probably
14990 + * "switch (wIndex) { ... }" in your ep0 string descriptor logic,
14991 + * using this routine after choosing which set of UTF-8 strings to use.
14992 + * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
14993 + * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
14994 + * characters (which are also widely used in C strings).
14997 +usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
14999 + struct usb_string *s;
15002 + /* descriptor 0 has the language id */
15005 + buf [1] = USB_DT_STRING;
15006 + buf [2] = (u8) table->language;
15007 + buf [3] = (u8) (table->language >> 8);
15010 + for (s = table->strings; s && s->s; s++)
15014 + /* unrecognized: stall. */
15018 + /* string descriptors have length, tag, then UTF16-LE text */
15019 + len = min ((size_t) 126, strlen (s->s));
15020 + memset (buf + 2, 0, 2 * len); /* zero all the bytes */
15021 + len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
15024 + buf [0] = (len + 1) * 2;
15025 + buf [1] = USB_DT_STRING;
15030 +/*-------------------------------------------------------------------------*/
15031 +/*-------------------------------------------------------------------------*/
15035 + * usb_descriptor_fillbuf - fill buffer with descriptors
15036 + * @buf: Buffer to be filled
15037 + * @buflen: Size of buf
15038 + * @src: Array of descriptor pointers, terminated by null pointer.
15040 + * Copies descriptors into the buffer, returning the length or a
15041 + * negative error code if they can't all be copied. Useful when
15042 + * assembling descriptors for an associated set of interfaces used
15043 + * as part of configuring a composite device; or in other cases where
15044 + * sets of descriptors need to be marshaled.
15047 +usb_descriptor_fillbuf(void *buf, unsigned buflen,
15048 + const struct usb_descriptor_header **src)
15055 + /* fill buffer from src[] until null descriptor ptr */
15056 + for (; 0 != *src; src++) {
15057 + unsigned len = (*src)->bLength;
15059 + if (len > buflen)
15061 + memcpy(dest, *src, len);
15065 + return dest - (u8 *)buf;
15070 + * usb_gadget_config_buf - builts a complete configuration descriptor
15071 + * @config: Header for the descriptor, including characteristics such
15072 + * as power requirements and number of interfaces.
15073 + * @desc: Null-terminated vector of pointers to the descriptors (interface,
15074 + * endpoint, etc) defining all functions in this device configuration.
15075 + * @buf: Buffer for the resulting configuration descriptor.
15076 + * @length: Length of buffer. If this is not big enough to hold the
15077 + * entire configuration descriptor, an error code will be returned.
15079 + * This copies descriptors into the response buffer, building a descriptor
15080 + * for that configuration. It returns the buffer length or a negative
15081 + * status code. The config.wTotalLength field is set to match the length
15082 + * of the result, but other descriptor fields (including power usage and
15083 + * interface count) must be set by the caller.
15085 + * Gadget drivers could use this when constructing a config descriptor
15086 + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
15087 + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
15089 +int usb_gadget_config_buf(
15090 + const struct usb_config_descriptor *config,
15093 + const struct usb_descriptor_header **desc
15096 + struct usb_config_descriptor *cp = buf;
15099 + /* config descriptor first */
15100 + if (length < USB_DT_CONFIG_SIZE || !desc)
15104 + /* then interface/endpoint/class/vendor/... */
15105 + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
15106 + length - USB_DT_CONFIG_SIZE, desc);
15109 + len += USB_DT_CONFIG_SIZE;
15110 + if (len > 0xffff)
15113 + /* patch up the config descriptor */
15114 + cp->bLength = USB_DT_CONFIG_SIZE;
15115 + cp->bDescriptorType = USB_DT_CONFIG;
15116 + cp->wTotalLength = cpu_to_le16(len);
15117 + cp->bmAttributes |= USB_CONFIG_ATT_ONE;
15121 +/*-------------------------------------------------------------------------*/
15122 +/*-------------------------------------------------------------------------*/
15125 +#define RBUF_LEN (1024*1024)
15126 +static int rbuf_start;
15127 +static int rbuf_len;
15128 +static __u8 rbuf[RBUF_LEN];
15130 +/*-------------------------------------------------------------------------*/
15132 +#define DRIVER_VERSION "St Patrick's Day 2004"
15134 +static const char shortname [] = "zero";
15135 +static const char longname [] = "YAMAHA YST-MS35D USB Speaker ";
15137 +static const char source_sink [] = "source and sink data";
15138 +static const char loopback [] = "loop input to output";
15140 +/*-------------------------------------------------------------------------*/
15143 + * driver assumes self-powered hardware, and
15144 + * has no way for users to trigger remote wakeup.
15146 + * this version autoconfigures as much as possible,
15147 + * which is reasonable for most "bulk-only" drivers.
15149 +static const char *EP_IN_NAME; /* source */
15150 +static const char *EP_OUT_NAME; /* sink */
15152 +/*-------------------------------------------------------------------------*/
15154 +/* big enough to hold our biggest descriptor */
15155 +#define USB_BUFSIZ 512
15159 + struct usb_gadget *gadget;
15160 + struct usb_request *req; /* for control responses */
15162 + /* when configured, we have one of two configs:
15163 + * - source data (in to host) and sink it (out from host)
15164 + * - or loop it back (out from host back in to host)
15167 + struct usb_ep *in_ep, *out_ep;
15169 + /* autoresume timer */
15170 + struct timer_list resume;
15173 +#define xprintk(d,level,fmt,args...) \
15174 + dev_printk(level , &(d)->gadget->dev , fmt , ## args)
15177 +#define DBG(dev,fmt,args...) \
15178 + xprintk(dev , KERN_DEBUG , fmt , ## args)
15180 +#define DBG(dev,fmt,args...) \
15182 +#endif /* DEBUG */
15187 +#define VDBG(dev,fmt,args...) \
15189 +#endif /* VERBOSE */
15191 +#define ERROR(dev,fmt,args...) \
15192 + xprintk(dev , KERN_ERR , fmt , ## args)
15193 +#define WARN(dev,fmt,args...) \
15194 + xprintk(dev , KERN_WARNING , fmt , ## args)
15195 +#define INFO(dev,fmt,args...) \
15196 + xprintk(dev , KERN_INFO , fmt , ## args)
15198 +/*-------------------------------------------------------------------------*/
15200 +static unsigned buflen = 4096;
15201 +static unsigned qlen = 32;
15202 +static unsigned pattern = 0;
15204 +module_param (buflen, uint, S_IRUGO|S_IWUSR);
15205 +module_param (qlen, uint, S_IRUGO|S_IWUSR);
15206 +module_param (pattern, uint, S_IRUGO|S_IWUSR);
15209 + * if it's nonzero, autoresume says how many seconds to wait
15210 + * before trying to wake up the host after suspend.
15212 +static unsigned autoresume = 0;
15213 +module_param (autoresume, uint, 0);
15216 + * Normally the "loopback" configuration is second (index 1) so
15217 + * it's not the default. Here's where to change that order, to
15218 + * work better with hosts where config changes are problematic.
15219 + * Or controllers (like superh) that only support one config.
15221 +static int loopdefault = 0;
15223 +module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
15225 +/*-------------------------------------------------------------------------*/
15227 +/* Thanks to NetChip Technologies for donating this product ID.
15229 + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
15230 + * Instead: allocate your own, using normal USB-IF procedures.
15232 +#ifndef CONFIG_USB_ZERO_HNPTEST
15233 +#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
15234 +#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
15236 +#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
15237 +#define DRIVER_PRODUCT_NUM 0xbadd
15240 +/*-------------------------------------------------------------------------*/
15243 + * DESCRIPTORS ... most are static, but strings and (full)
15244 + * configuration descriptors are built on demand.
15248 +#define STRING_MANUFACTURER 25
15249 +#define STRING_PRODUCT 42
15250 +#define STRING_SERIAL 101
15252 +#define STRING_MANUFACTURER 1
15253 +#define STRING_PRODUCT 2
15254 +#define STRING_SERIAL 3
15256 +#define STRING_SOURCE_SINK 250
15257 +#define STRING_LOOPBACK 251
15260 + * This device advertises two configurations; these numbers work
15261 + * on a pxa250 as well as more flexible hardware.
15263 +#define CONFIG_SOURCE_SINK 3
15264 +#define CONFIG_LOOPBACK 2
15267 +static struct usb_device_descriptor
15269 + .bLength = sizeof device_desc,
15270 + .bDescriptorType = USB_DT_DEVICE,
15272 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
15273 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
15275 + .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
15276 + .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
15277 + .iManufacturer = STRING_MANUFACTURER,
15278 + .iProduct = STRING_PRODUCT,
15279 + .iSerialNumber = STRING_SERIAL,
15280 + .bNumConfigurations = 2,
15283 +static struct usb_device_descriptor
15285 + .bLength = sizeof device_desc,
15286 + .bDescriptorType = USB_DT_DEVICE,
15287 + .bcdUSB = __constant_cpu_to_le16 (0x0100),
15288 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
15289 + .bDeviceSubClass = 0,
15290 + .bDeviceProtocol = 0,
15291 + .bMaxPacketSize0 = 64,
15292 + .bcdDevice = __constant_cpu_to_le16 (0x0100),
15293 + .idVendor = __constant_cpu_to_le16 (0x0499),
15294 + .idProduct = __constant_cpu_to_le16 (0x3002),
15295 + .iManufacturer = STRING_MANUFACTURER,
15296 + .iProduct = STRING_PRODUCT,
15297 + .iSerialNumber = STRING_SERIAL,
15298 + .bNumConfigurations = 1,
15301 +static struct usb_config_descriptor
15303 + .bLength = sizeof z_config,
15304 + .bDescriptorType = USB_DT_CONFIG,
15306 + /* compute wTotalLength on the fly */
15307 + .bNumInterfaces = 2,
15308 + .bConfigurationValue = 1,
15309 + .iConfiguration = 0,
15310 + .bmAttributes = 0x40,
15311 + .bMaxPower = 0, /* self-powered */
15315 +static struct usb_otg_descriptor
15316 +otg_descriptor = {
15317 + .bLength = sizeof otg_descriptor,
15318 + .bDescriptorType = USB_DT_OTG,
15320 + .bmAttributes = USB_OTG_SRP,
15323 +/* one interface in each configuration */
15324 +#ifdef CONFIG_USB_GADGET_DUALSPEED
15327 + * usb 2.0 devices need to expose both high speed and full speed
15328 + * descriptors, unless they only run at full speed.
15330 + * that means alternate endpoint descriptors (bigger packets)
15331 + * and a "device qualifier" ... plus more construction options
15332 + * for the config descriptor.
15335 +static struct usb_qualifier_descriptor
15337 + .bLength = sizeof dev_qualifier,
15338 + .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
15340 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
15341 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
15343 + .bNumConfigurations = 2,
15347 +struct usb_cs_as_general_descriptor {
15349 + __u8 bDescriptorType;
15351 + __u8 bDescriptorSubType;
15352 + __u8 bTerminalLink;
15354 + __u16 wFormatTag;
15355 +} __attribute__ ((packed));
15357 +struct usb_cs_as_format_descriptor {
15359 + __u8 bDescriptorType;
15361 + __u8 bDescriptorSubType;
15362 + __u8 bFormatType;
15363 + __u8 bNrChannels;
15364 + __u8 bSubframeSize;
15365 + __u8 bBitResolution;
15366 + __u8 bSamfreqType;
15367 + __u8 tLowerSamFreq[3];
15368 + __u8 tUpperSamFreq[3];
15369 +} __attribute__ ((packed));
15371 +static const struct usb_interface_descriptor
15372 +z_audio_control_if_desc = {
15373 + .bLength = sizeof z_audio_control_if_desc,
15374 + .bDescriptorType = USB_DT_INTERFACE,
15375 + .bInterfaceNumber = 0,
15376 + .bAlternateSetting = 0,
15377 + .bNumEndpoints = 0,
15378 + .bInterfaceClass = USB_CLASS_AUDIO,
15379 + .bInterfaceSubClass = 0x1,
15380 + .bInterfaceProtocol = 0,
15384 +static const struct usb_interface_descriptor
15385 +z_audio_if_desc = {
15386 + .bLength = sizeof z_audio_if_desc,
15387 + .bDescriptorType = USB_DT_INTERFACE,
15388 + .bInterfaceNumber = 1,
15389 + .bAlternateSetting = 0,
15390 + .bNumEndpoints = 0,
15391 + .bInterfaceClass = USB_CLASS_AUDIO,
15392 + .bInterfaceSubClass = 0x2,
15393 + .bInterfaceProtocol = 0,
15397 +static const struct usb_interface_descriptor
15398 +z_audio_if_desc2 = {
15399 + .bLength = sizeof z_audio_if_desc,
15400 + .bDescriptorType = USB_DT_INTERFACE,
15401 + .bInterfaceNumber = 1,
15402 + .bAlternateSetting = 1,
15403 + .bNumEndpoints = 1,
15404 + .bInterfaceClass = USB_CLASS_AUDIO,
15405 + .bInterfaceSubClass = 0x2,
15406 + .bInterfaceProtocol = 0,
15410 +static const struct usb_cs_as_general_descriptor
15411 +z_audio_cs_as_if_desc = {
15413 + .bDescriptorType = 0x24,
15415 + .bDescriptorSubType = 0x01,
15416 + .bTerminalLink = 0x01,
15418 + .wFormatTag = __constant_cpu_to_le16 (0x0001)
15422 +static const struct usb_cs_as_format_descriptor
15423 +z_audio_cs_as_format_desc = {
15425 + .bDescriptorType = 0x24,
15427 + .bDescriptorSubType = 2,
15428 + .bFormatType = 1,
15429 + .bNrChannels = 1,
15430 + .bSubframeSize = 1,
15431 + .bBitResolution = 8,
15432 + .bSamfreqType = 0,
15433 + .tLowerSamFreq = {0x7e, 0x13, 0x00},
15434 + .tUpperSamFreq = {0xe2, 0xd6, 0x00},
15437 +static const struct usb_endpoint_descriptor
15440 + .bDescriptorType = 0x05,
15441 + .bEndpointAddress = 0x04,
15442 + .bmAttributes = 0x09,
15443 + .wMaxPacketSize = 0x0038,
15444 + .bInterval = 0x01,
15445 + .bRefresh = 0x00,
15446 + .bSynchAddress = 0x00,
15449 +static char z_iso_ep2[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15452 +static char z_ac_interface_header_desc[] =
15453 +{ 0x09, 0x24, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x01, 0x01 };
15456 +static char z_0[] = {0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
15457 + 0x03, 0x00, 0x00, 0x00};
15459 +static char z_1[] = {0x0d, 0x24, 0x06, 0x02, 0x01, 0x02, 0x15, 0x00,
15460 + 0x02, 0x00, 0x02, 0x00, 0x00};
15462 +static char z_2[] = {0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x02,
15465 +static char za_0[] = {0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00,
15468 +static char za_1[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15470 +static char za_2[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x01, 0x08, 0x00,
15471 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15473 +static char za_3[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
15476 +static char za_4[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15478 +static char za_5[] = {0x09, 0x04, 0x01, 0x03, 0x01, 0x01, 0x02, 0x00,
15481 +static char za_6[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15483 +static char za_7[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x00,
15484 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15486 +static char za_8[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
15489 +static char za_9[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15491 +static char za_10[] = {0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00,
15494 +static char za_11[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15496 +static char za_12[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00,
15497 + 0x73, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15499 +static char za_13[] = {0x09, 0x05, 0x04, 0x09, 0xe0, 0x00, 0x01, 0x00,
15502 +static char za_14[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15504 +static char za_15[] = {0x09, 0x04, 0x01, 0x05, 0x01, 0x01, 0x02, 0x00,
15507 +static char za_16[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15509 +static char za_17[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x03, 0x14, 0x00,
15510 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15512 +static char za_18[] = {0x09, 0x05, 0x04, 0x09, 0xa8, 0x00, 0x01, 0x00,
15515 +static char za_19[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15517 +static char za_20[] = {0x09, 0x04, 0x01, 0x06, 0x01, 0x01, 0x02, 0x00,
15520 +static char za_21[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15522 +static char za_22[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x03, 0x14, 0x00,
15523 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15525 +static char za_23[] = {0x09, 0x05, 0x04, 0x09, 0x50, 0x01, 0x01, 0x00,
15528 +static char za_24[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15532 +static const struct usb_descriptor_header *z_function [] = {
15533 + (struct usb_descriptor_header *) &z_audio_control_if_desc,
15534 + (struct usb_descriptor_header *) &z_ac_interface_header_desc,
15535 + (struct usb_descriptor_header *) &z_0,
15536 + (struct usb_descriptor_header *) &z_1,
15537 + (struct usb_descriptor_header *) &z_2,
15538 + (struct usb_descriptor_header *) &z_audio_if_desc,
15539 + (struct usb_descriptor_header *) &z_audio_if_desc2,
15540 + (struct usb_descriptor_header *) &z_audio_cs_as_if_desc,
15541 + (struct usb_descriptor_header *) &z_audio_cs_as_format_desc,
15542 + (struct usb_descriptor_header *) &z_iso_ep,
15543 + (struct usb_descriptor_header *) &z_iso_ep2,
15544 + (struct usb_descriptor_header *) &za_0,
15545 + (struct usb_descriptor_header *) &za_1,
15546 + (struct usb_descriptor_header *) &za_2,
15547 + (struct usb_descriptor_header *) &za_3,
15548 + (struct usb_descriptor_header *) &za_4,
15549 + (struct usb_descriptor_header *) &za_5,
15550 + (struct usb_descriptor_header *) &za_6,
15551 + (struct usb_descriptor_header *) &za_7,
15552 + (struct usb_descriptor_header *) &za_8,
15553 + (struct usb_descriptor_header *) &za_9,
15554 + (struct usb_descriptor_header *) &za_10,
15555 + (struct usb_descriptor_header *) &za_11,
15556 + (struct usb_descriptor_header *) &za_12,
15557 + (struct usb_descriptor_header *) &za_13,
15558 + (struct usb_descriptor_header *) &za_14,
15559 + (struct usb_descriptor_header *) &za_15,
15560 + (struct usb_descriptor_header *) &za_16,
15561 + (struct usb_descriptor_header *) &za_17,
15562 + (struct usb_descriptor_header *) &za_18,
15563 + (struct usb_descriptor_header *) &za_19,
15564 + (struct usb_descriptor_header *) &za_20,
15565 + (struct usb_descriptor_header *) &za_21,
15566 + (struct usb_descriptor_header *) &za_22,
15567 + (struct usb_descriptor_header *) &za_23,
15568 + (struct usb_descriptor_header *) &za_24,
15572 +/* maxpacket and other transfer characteristics vary by speed. */
15573 +#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
15577 +/* if there's no high speed support, maxpacket doesn't change. */
15578 +#define ep_desc(g,hs,fs) fs
15580 +#endif /* !CONFIG_USB_GADGET_DUALSPEED */
15582 +static char manufacturer [40];
15583 +//static char serial [40];
15584 +static char serial [] = "Ser 00 em";
15586 +/* static strings, in UTF-8 */
15587 +static struct usb_string strings [] = {
15588 + { STRING_MANUFACTURER, manufacturer, },
15589 + { STRING_PRODUCT, longname, },
15590 + { STRING_SERIAL, serial, },
15591 + { STRING_LOOPBACK, loopback, },
15592 + { STRING_SOURCE_SINK, source_sink, },
15593 + { } /* end of list */
15596 +static struct usb_gadget_strings stringtab = {
15597 + .language = 0x0409, /* en-us */
15598 + .strings = strings,
15602 + * config descriptors are also handcrafted. these must agree with code
15603 + * that sets configurations, and with code managing interfaces and their
15604 + * altsettings. other complexity may come from:
15606 + * - high speed support, including "other speed config" rules
15607 + * - multiple configurations
15608 + * - interfaces with alternate settings
15609 + * - embedded class or vendor-specific descriptors
15611 + * this handles high speed, and has a second config that could as easily
15612 + * have been an alternate interface setting (on most hardware).
15614 + * NOTE: to demonstrate (and test) more USB capabilities, this driver
15615 + * should include an altsetting to test interrupt transfers, including
15616 + * high bandwidth modes at high speed. (Maybe work like Intel's test
15620 +config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index)
15623 + const struct usb_descriptor_header **function;
15625 + function = z_function;
15626 + len = usb_gadget_config_buf (&z_config, buf, USB_BUFSIZ, function);
15629 + ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
15633 +/*-------------------------------------------------------------------------*/
15635 +static struct usb_request *
15636 +alloc_ep_req (struct usb_ep *ep, unsigned length)
15638 + struct usb_request *req;
15640 + req = usb_ep_alloc_request (ep, GFP_ATOMIC);
15642 + req->length = length;
15643 + req->buf = usb_ep_alloc_buffer (ep, length,
15644 + &req->dma, GFP_ATOMIC);
15646 + usb_ep_free_request (ep, req);
15653 +static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
15656 + usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
15657 + usb_ep_free_request (ep, req);
15660 +/*-------------------------------------------------------------------------*/
15662 +/* optionally require specific source/sink data patterns */
15666 + struct zero_dev *dev,
15667 + struct usb_ep *ep,
15668 + struct usb_request *req
15672 + u8 *buf = req->buf;
15674 + for (i = 0; i < req->actual; i++, buf++) {
15675 + switch (pattern) {
15676 + /* all-zeroes has no synchronization issues */
15681 + /* mod63 stays in sync with short-terminated transfers,
15682 + * or otherwise when host and gadget agree on how large
15683 + * each usb transfer request should be. resync is done
15684 + * with set_interface or set_config.
15687 + if (*buf == (u8)(i % 63))
15691 + ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
15692 + usb_ep_set_halt (ep);
15698 +/*-------------------------------------------------------------------------*/
15700 +static void zero_reset_config (struct zero_dev *dev)
15702 + if (dev->config == 0)
15705 + DBG (dev, "reset config\n");
15707 + /* just disable endpoints, forcing completion of pending i/o.
15708 + * all our completion handlers free their requests in this case.
15710 + if (dev->in_ep) {
15711 + usb_ep_disable (dev->in_ep);
15712 + dev->in_ep = NULL;
15714 + if (dev->out_ep) {
15715 + usb_ep_disable (dev->out_ep);
15716 + dev->out_ep = NULL;
15719 + del_timer (&dev->resume);
15722 +#define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
15725 +zero_isoc_complete (struct usb_ep *ep, struct usb_request *req)
15727 + struct zero_dev *dev = ep->driver_data;
15728 + int status = req->status;
15731 + switch (status) {
15733 + case 0: /* normal completion? */
15734 + //printk ("\nzero ---------------> isoc normal completion %d bytes\n", req->actual);
15735 + for (i=0, j=rbuf_start; i<req->actual; i++) {
15736 + //printk ("%02x ", ((__u8*)req->buf)[i]);
15737 + rbuf[j] = ((__u8*)req->buf)[i];
15739 + if (j >= RBUF_LEN) j=0;
15742 + //printk ("\n\n");
15744 + if (rbuf_len < RBUF_LEN) {
15745 + rbuf_len += req->actual;
15746 + if (rbuf_len > RBUF_LEN) {
15747 + rbuf_len = RBUF_LEN;
15753 + /* this endpoint is normally active while we're configured */
15754 + case -ECONNABORTED: /* hardware forced ep reset */
15755 + case -ECONNRESET: /* request dequeued */
15756 + case -ESHUTDOWN: /* disconnect from host */
15757 + VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
15758 + req->actual, req->length);
15759 + if (ep == dev->out_ep)
15760 + check_read_data (dev, ep, req);
15761 + free_ep_req (ep, req);
15764 + case -EOVERFLOW: /* buffer overrun on read means that
15765 + * we didn't provide a big enough
15770 + DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
15771 + status, req->actual, req->length);
15773 + case -EREMOTEIO: /* short read */
15777 + status = usb_ep_queue (ep, req, GFP_ATOMIC);
15779 + ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
15780 + ep->name, req->length, status);
15781 + usb_ep_set_halt (ep);
15782 + /* FIXME recover later ... somehow */
15786 +static struct usb_request *
15787 +zero_start_isoc_ep (struct usb_ep *ep, int gfp_flags)
15789 + struct usb_request *req;
15792 + req = alloc_ep_req (ep, 512);
15796 + req->complete = zero_isoc_complete;
15798 + status = usb_ep_queue (ep, req, gfp_flags);
15800 + struct zero_dev *dev = ep->driver_data;
15802 + ERROR (dev, "start %s --> %d\n", ep->name, status);
15803 + free_ep_req (ep, req);
15810 +/* change our operational config. this code must agree with the code
15811 + * that returns config descriptors, and altsetting code.
15813 + * it's also responsible for power management interactions. some
15814 + * configurations might not work with our current power sources.
15816 + * note that some device controller hardware will constrain what this
15817 + * code can do, perhaps by disallowing more than one configuration or
15818 + * by limiting configuration choices (like the pxa2xx).
15821 +zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
15824 + struct usb_gadget *gadget = dev->gadget;
15825 + const struct usb_endpoint_descriptor *d;
15826 + struct usb_ep *ep;
15828 + if (number == dev->config)
15831 + zero_reset_config (dev);
15833 + gadget_for_each_ep (ep, gadget) {
15835 + if (strcmp (ep->name, "ep4") == 0) {
15837 + d = (struct usb_endpoint_descripter *)&za_23; // isoc ep desc for audio i/f alt setting 6
15838 + result = usb_ep_enable (ep, d);
15840 + if (result == 0) {
15841 + ep->driver_data = dev;
15844 + if (zero_start_isoc_ep (ep, gfp_flags) != 0) {
15850 + usb_ep_disable (ep);
15857 + dev->config = number;
15861 +/*-------------------------------------------------------------------------*/
15863 +static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
15865 + if (req->status || req->actual != req->length)
15866 + DBG ((struct zero_dev *) ep->driver_data,
15867 + "setup complete --> %d, %d/%d\n",
15868 + req->status, req->actual, req->length);
15872 + * The setup() callback implements all the ep0 functionality that's
15873 + * not handled lower down, in hardware or the hardware driver (like
15874 + * device and endpoint feature flags, and their status). It's all
15875 + * housekeeping for the gadget function we're implementing. Most of
15876 + * the work is in config-specific setup.
15879 +zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
15881 + struct zero_dev *dev = get_gadget_data (gadget);
15882 + struct usb_request *req = dev->req;
15883 + int value = -EOPNOTSUPP;
15885 + /* usually this stores reply data in the pre-allocated ep0 buffer,
15886 + * but config change events will reconfigure hardware.
15889 + switch (ctrl->bRequest) {
15891 + case USB_REQ_GET_DESCRIPTOR:
15893 + switch (ctrl->wValue >> 8) {
15895 + case USB_DT_DEVICE:
15896 + value = min (ctrl->wLength, (u16) sizeof device_desc);
15897 + memcpy (req->buf, &device_desc, value);
15899 +#ifdef CONFIG_USB_GADGET_DUALSPEED
15900 + case USB_DT_DEVICE_QUALIFIER:
15901 + if (!gadget->is_dualspeed)
15903 + value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
15904 + memcpy (req->buf, &dev_qualifier, value);
15907 + case USB_DT_OTHER_SPEED_CONFIG:
15908 + if (!gadget->is_dualspeed)
15911 +#endif /* CONFIG_USB_GADGET_DUALSPEED */
15912 + case USB_DT_CONFIG:
15913 + value = config_buf (gadget, req->buf,
15914 + ctrl->wValue >> 8,
15915 + ctrl->wValue & 0xff);
15917 + value = min (ctrl->wLength, (u16) value);
15920 + case USB_DT_STRING:
15921 + /* wIndex == language code.
15922 + * this driver only handles one language, you can
15923 + * add string tables for other languages, using
15924 + * any UTF-8 characters
15926 + value = usb_gadget_get_string (&stringtab,
15927 + ctrl->wValue & 0xff, req->buf);
15928 + if (value >= 0) {
15929 + value = min (ctrl->wLength, (u16) value);
15935 + /* currently two configs, two speeds */
15936 + case USB_REQ_SET_CONFIGURATION:
15937 + if (ctrl->bRequestType != 0)
15940 + spin_lock (&dev->lock);
15941 + value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
15942 + spin_unlock (&dev->lock);
15944 + case USB_REQ_GET_CONFIGURATION:
15945 + if (ctrl->bRequestType != USB_DIR_IN)
15947 + *(u8 *)req->buf = dev->config;
15948 + value = min (ctrl->wLength, (u16) 1);
15951 + /* until we add altsetting support, or other interfaces,
15952 + * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
15953 + * and already killed pending endpoint I/O.
15955 + case USB_REQ_SET_INTERFACE:
15957 + if (ctrl->bRequestType != USB_RECIP_INTERFACE)
15959 + spin_lock (&dev->lock);
15960 + if (dev->config) {
15961 + u8 config = dev->config;
15963 + /* resets interface configuration, forgets about
15964 + * previous transaction state (queued bufs, etc)
15965 + * and re-inits endpoint state (toggle etc)
15966 + * no response queued, just zero status == success.
15967 + * if we had more than one interface we couldn't
15968 + * use this "reset the config" shortcut.
15970 + zero_reset_config (dev);
15971 + zero_set_config (dev, config, GFP_ATOMIC);
15974 + spin_unlock (&dev->lock);
15976 + case USB_REQ_GET_INTERFACE:
15977 + if ((ctrl->bRequestType == 0x21) && (ctrl->wIndex == 0x02)) {
15978 + value = ctrl->wLength;
15982 + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
15984 + if (!dev->config)
15986 + if (ctrl->wIndex != 0) {
15990 + *(u8 *)req->buf = 0;
15991 + value = min (ctrl->wLength, (u16) 1);
15996 + * These are the same vendor-specific requests supported by
15997 + * Intel's USB 2.0 compliance test devices. We exceed that
15998 + * device spec by allowing multiple-packet requests.
16000 + case 0x5b: /* control WRITE test -- fill the buffer */
16001 + if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
16003 + if (ctrl->wValue || ctrl->wIndex)
16005 + /* just read that many bytes into the buffer */
16006 + if (ctrl->wLength > USB_BUFSIZ)
16008 + value = ctrl->wLength;
16010 + case 0x5c: /* control READ test -- return the buffer */
16011 + if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
16013 + if (ctrl->wValue || ctrl->wIndex)
16015 + /* expect those bytes are still in the buffer; send back */
16016 + if (ctrl->wLength > USB_BUFSIZ
16017 + || ctrl->wLength != req->length)
16019 + value = ctrl->wLength;
16022 + case 0x01: // SET_CUR
16027 + value = ctrl->wLength;
16030 + switch (ctrl->wValue) {
16033 + ((u8*)req->buf)[0] = 0x00;
16034 + ((u8*)req->buf)[1] = 0xe3;
16038 + ((u8*)req->buf)[0] = 0x00;
16041 + //((u8*)req->buf)[0] = 0x81;
16042 + //((u8*)req->buf)[1] = 0x81;
16043 + value = ctrl->wLength;
16046 + switch (ctrl->wValue) {
16049 + ((u8*)req->buf)[0] = 0x00;
16050 + ((u8*)req->buf)[1] = 0xc3;
16054 + ((u8*)req->buf)[0] = 0x00;
16057 + //((u8*)req->buf)[0] = 0x82;
16058 + //((u8*)req->buf)[1] = 0x82;
16059 + value = ctrl->wLength;
16062 + switch (ctrl->wValue) {
16065 + ((u8*)req->buf)[0] = 0x00;
16066 + ((u8*)req->buf)[1] = 0x00;
16069 + ((u8*)req->buf)[0] = 0x60;
16072 + ((u8*)req->buf)[0] = 0x18;
16075 + //((u8*)req->buf)[0] = 0x83;
16076 + //((u8*)req->buf)[1] = 0x83;
16077 + value = ctrl->wLength;
16080 + switch (ctrl->wValue) {
16083 + ((u8*)req->buf)[0] = 0x00;
16084 + ((u8*)req->buf)[1] = 0x01;
16088 + ((u8*)req->buf)[0] = 0x08;
16091 + //((u8*)req->buf)[0] = 0x84;
16092 + //((u8*)req->buf)[1] = 0x84;
16093 + value = ctrl->wLength;
16096 + ((u8*)req->buf)[0] = 0x85;
16097 + ((u8*)req->buf)[1] = 0x85;
16098 + value = ctrl->wLength;
16104 + printk("unknown control req%02x.%02x v%04x i%04x l%d\n",
16105 + ctrl->bRequestType, ctrl->bRequest,
16106 + ctrl->wValue, ctrl->wIndex, ctrl->wLength);
16109 + /* respond with data transfer before status phase? */
16110 + if (value >= 0) {
16111 + req->length = value;
16112 + req->zero = value < ctrl->wLength
16113 + && (value % gadget->ep0->maxpacket) == 0;
16114 + value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
16116 + DBG (dev, "ep_queue < 0 --> %d\n", value);
16118 + zero_setup_complete (gadget->ep0, req);
16122 + /* device either stalls (value < 0) or reports success */
16127 +zero_disconnect (struct usb_gadget *gadget)
16129 + struct zero_dev *dev = get_gadget_data (gadget);
16130 + unsigned long flags;
16132 + spin_lock_irqsave (&dev->lock, flags);
16133 + zero_reset_config (dev);
16135 + /* a more significant application might have some non-usb
16136 + * activities to quiesce here, saving resources like power
16137 + * or pushing the notification up a network stack.
16139 + spin_unlock_irqrestore (&dev->lock, flags);
16141 + /* next we may get setup() calls to enumerate new connections;
16142 + * or an unbind() during shutdown (including removing module).
16147 +zero_autoresume (unsigned long _dev)
16149 + struct zero_dev *dev = (struct zero_dev *) _dev;
16152 + /* normally the host would be woken up for something
16153 + * more significant than just a timer firing...
16155 + if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
16156 + status = usb_gadget_wakeup (dev->gadget);
16157 + DBG (dev, "wakeup --> %d\n", status);
16161 +/*-------------------------------------------------------------------------*/
16164 +zero_unbind (struct usb_gadget *gadget)
16166 + struct zero_dev *dev = get_gadget_data (gadget);
16168 + DBG (dev, "unbind\n");
16170 + /* we've already been disconnected ... no i/o is active */
16172 + free_ep_req (gadget->ep0, dev->req);
16173 + del_timer_sync (&dev->resume);
16175 + set_gadget_data (gadget, NULL);
16179 +zero_bind (struct usb_gadget *gadget)
16181 + struct zero_dev *dev;
16182 + //struct usb_ep *ep;
16184 + printk("binding\n");
16186 + * DRIVER POLICY CHOICE: you may want to do this differently.
16187 + * One thing to avoid is reusing a bcdDevice revision code
16188 + * with different host-visible configurations or behavior
16189 + * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
16191 + //device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
16194 + /* ok, we made sense of the hardware ... */
16195 + dev = kmalloc (sizeof *dev, SLAB_KERNEL);
16198 + memset (dev, 0, sizeof *dev);
16199 + spin_lock_init (&dev->lock);
16200 + dev->gadget = gadget;
16201 + set_gadget_data (gadget, dev);
16203 + /* preallocate control response and buffer */
16204 + dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
16207 + dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
16208 + &dev->req->dma, GFP_KERNEL);
16209 + if (!dev->req->buf)
16212 + dev->req->complete = zero_setup_complete;
16214 + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
16216 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16217 + /* assume ep0 uses the same value for both speeds ... */
16218 + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
16220 + /* and that all endpoints are dual-speed */
16221 + //hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
16222 + //hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
16225 + usb_gadget_set_selfpowered (gadget);
16227 + init_timer (&dev->resume);
16228 + dev->resume.function = zero_autoresume;
16229 + dev->resume.data = (unsigned long) dev;
16231 + gadget->ep0->driver_data = dev;
16233 + INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
16234 + INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
16235 + EP_OUT_NAME, EP_IN_NAME);
16237 + snprintf (manufacturer, sizeof manufacturer,
16238 + UTS_SYSNAME " " UTS_RELEASE " with %s",
16244 + zero_unbind (gadget);
16248 +/*-------------------------------------------------------------------------*/
16251 +zero_suspend (struct usb_gadget *gadget)
16253 + struct zero_dev *dev = get_gadget_data (gadget);
16255 + if (gadget->speed == USB_SPEED_UNKNOWN)
16258 + if (autoresume) {
16259 + mod_timer (&dev->resume, jiffies + (HZ * autoresume));
16260 + DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
16262 + DBG (dev, "suspend\n");
16266 +zero_resume (struct usb_gadget *gadget)
16268 + struct zero_dev *dev = get_gadget_data (gadget);
16270 + DBG (dev, "resume\n");
16271 + del_timer (&dev->resume);
16275 +/*-------------------------------------------------------------------------*/
16277 +static struct usb_gadget_driver zero_driver = {
16278 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16279 + .speed = USB_SPEED_HIGH,
16281 + .speed = USB_SPEED_FULL,
16283 + .function = (char *) longname,
16284 + .bind = zero_bind,
16285 + .unbind = zero_unbind,
16287 + .setup = zero_setup,
16288 + .disconnect = zero_disconnect,
16290 + .suspend = zero_suspend,
16291 + .resume = zero_resume,
16294 + .name = (char *) shortname,
16295 + // .shutdown = ...
16296 + // .suspend = ...
16301 +MODULE_AUTHOR ("David Brownell");
16302 +MODULE_LICENSE ("Dual BSD/GPL");
16304 +static struct proc_dir_entry *pdir, *pfile;
16306 +static int isoc_read_data (char *page, char **start,
16307 + off_t off, int count,
16308 + int *eof, void *data)
16311 + static int c = 0;
16312 + static int done = 0;
16313 + static int s = 0;
16316 + printk ("\ncount: %d\n", count);
16317 + printk ("rbuf_start: %d\n", rbuf_start);
16318 + printk ("rbuf_len: %d\n", rbuf_len);
16319 + printk ("off: %d\n", off);
16320 + printk ("start: %p\n\n", *start);
16330 + if (rbuf_len == RBUF_LEN)
16335 + for (i=0; i<count && c<rbuf_len; i++, c++) {
16336 + page[i] = rbuf[(c+s) % RBUF_LEN];
16340 + if (c >= rbuf_len) {
16349 +static int __init init (void)
16354 + pdir = proc_mkdir("isoc_test", NULL);
16355 + if(pdir == NULL) {
16356 + retval = -ENOMEM;
16357 + printk("Error creating dir\n");
16360 + pdir->owner = THIS_MODULE;
16362 + pfile = create_proc_read_entry("isoc_data",
16366 + if (pfile == NULL) {
16367 + retval = -ENOMEM;
16368 + printk("Error creating file\n");
16371 + pfile->owner = THIS_MODULE;
16373 + return usb_gadget_register_driver (&zero_driver);
16376 + remove_proc_entry("isoc_data", NULL);
16380 +module_init (init);
16382 +static void __exit cleanup (void)
16385 + usb_gadget_unregister_driver (&zero_driver);
16387 + remove_proc_entry("isoc_data", pdir);
16388 + remove_proc_entry("isoc_test", NULL);
16390 +module_exit (cleanup);
16392 +++ b/drivers/usb/host/dwc_otg/dwc_cfi_common.h
16394 +/* ==========================================================================
16395 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
16396 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
16397 + * otherwise expressly agreed to in writing between Synopsys and you.
16399 + * The Software IS NOT an item of Licensed Software or Licensed Product under
16400 + * any End User Software License Agreement or Agreement for Licensed Product
16401 + * with Synopsys or any supplement thereto. You are permitted to use and
16402 + * redistribute this Software in source and binary forms, with or without
16403 + * modification, provided that redistributions of source code must retain this
16404 + * notice. You may not view, use, disclose, copy or distribute this file or
16405 + * any information contained herein except pursuant to this license grant from
16406 + * Synopsys. If you do not agree with this notice, including the disclaimer
16407 + * below, then you are not authorized to use the Software.
16409 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
16410 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16411 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16412 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
16413 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16414 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16415 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
16416 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16417 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16418 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
16420 + * ========================================================================== */
16422 +#if !defined(__DWC_CFI_COMMON_H__)
16423 +#define __DWC_CFI_COMMON_H__
16425 +//#include <linux/types.h>
16430 + * This file contains the CFI specific common constants, interfaces
16431 + * (functions and macros) and structures for Linux. No PCD specific
16432 + * data structure or definition is to be included in this file.
16436 +/** This is a request for all Core Features */
16437 +#define VEN_CORE_GET_FEATURES 0xB1
16439 +/** This is a request to get the value of a specific Core Feature */
16440 +#define VEN_CORE_GET_FEATURE 0xB2
16442 +/** This command allows the host to set the value of a specific Core Feature */
16443 +#define VEN_CORE_SET_FEATURE 0xB3
16445 +/** This command allows the host to set the default values of
16446 + * either all or any specific Core Feature
16448 +#define VEN_CORE_RESET_FEATURES 0xB4
16450 +/** This command forces the PCD to write the deferred values of a Core Features */
16451 +#define VEN_CORE_ACTIVATE_FEATURES 0xB5
16453 +/** This request reads a DWORD value from a register at the specified offset */
16454 +#define VEN_CORE_READ_REGISTER 0xB6
16456 +/** This request writes a DWORD value into a register at the specified offset */
16457 +#define VEN_CORE_WRITE_REGISTER 0xB7
16459 +/** This structure is the header of the Core Features dataset returned to
16462 +struct cfi_all_features_header {
16463 +/** The features header structure length is */
16464 +#define CFI_ALL_FEATURES_HDR_LEN 8
16466 + * The total length of the features dataset returned to the Host
16468 + uint16_t wTotalLen;
16471 + * CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H).
16472 + * This field identifies the version of the CFI Specification with which
16473 + * the device is compliant.
16475 + uint16_t wVersion;
16477 + /** The ID of the Core */
16478 + uint16_t wCoreID;
16479 +#define CFI_CORE_ID_UDC 1
16480 +#define CFI_CORE_ID_OTG 2
16481 +#define CFI_CORE_ID_WUDEV 3
16483 + /** Number of features returned by VEN_CORE_GET_FEATURES request */
16484 + uint16_t wNumFeatures;
16487 +typedef struct cfi_all_features_header cfi_all_features_header_t;
16489 +/** This structure is a header of the Core Feature descriptor dataset returned to
16490 + * the Host after the VEN_CORE_GET_FEATURES request
16492 +struct cfi_feature_desc_header {
16493 +#define CFI_FEATURE_DESC_HDR_LEN 8
16495 + /** The feature ID */
16496 + uint16_t wFeatureID;
16498 + /** Length of this feature descriptor in bytes - including the
16499 + * length of the feature name string
16501 + uint16_t wLength;
16503 + /** The data length of this feature in bytes */
16504 + uint16_t wDataLength;
16507 + * Attributes of this features
16508 + * D0: Access rights
16512 + uint8_t bmAttributes;
16513 +#define CFI_FEATURE_ATTR_RO 1
16514 +#define CFI_FEATURE_ATTR_RW 0
16516 + /** Length of the feature name in bytes */
16517 + uint8_t bNameLen;
16519 + /** The feature name buffer */
16523 +typedef struct cfi_feature_desc_header cfi_feature_desc_header_t;
16526 + * This structure describes a NULL terminated string referenced by its id field.
16527 + * It is very similar to usb_string structure but has the id field type set to 16-bit.
16529 +struct cfi_string {
16531 + const uint8_t *s;
16533 +typedef struct cfi_string cfi_string_t;
16537 +++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.c
16539 +/* ==========================================================================
16540 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.c $
16541 + * $Revision: #12 $
16542 + * $Date: 2011/10/26 $
16543 + * $Change: 1873028 $
16545 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
16546 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
16547 + * otherwise expressly agreed to in writing between Synopsys and you.
16549 + * The Software IS NOT an item of Licensed Software or Licensed Product under
16550 + * any End User Software License Agreement or Agreement for Licensed Product
16551 + * with Synopsys or any supplement thereto. You are permitted to use and
16552 + * redistribute this Software in source and binary forms, with or without
16553 + * modification, provided that redistributions of source code must retain this
16554 + * notice. You may not view, use, disclose, copy or distribute this file or
16555 + * any information contained herein except pursuant to this license grant from
16556 + * Synopsys. If you do not agree with this notice, including the disclaimer
16557 + * below, then you are not authorized to use the Software.
16559 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
16560 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16561 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16562 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
16563 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16564 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16565 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
16566 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16567 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16568 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
16570 + * ========================================================================== */
16572 +#include "dwc_os.h"
16573 +#include "dwc_otg_regs.h"
16574 +#include "dwc_otg_cil.h"
16575 +#include "dwc_otg_adp.h"
16579 + * This file contains the most of the Attach Detect Protocol implementation for
16580 + * the driver to support OTG Rev2.0.
16584 +void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value)
16586 + adpctl_data_t adpctl;
16588 + adpctl.d32 = value;
16589 + adpctl.b.ar = 0x2;
16591 + DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
16593 + while (adpctl.b.ar) {
16594 + adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
16600 + * Function is called to read ADP registers
16602 +uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if)
16604 + adpctl_data_t adpctl;
16607 + adpctl.b.ar = 0x1;
16609 + DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
16611 + while (adpctl.b.ar) {
16612 + adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
16615 + return adpctl.d32;
16619 + * Function is called to read ADPCTL register and filter Write-clear bits
16621 +uint32_t dwc_otg_adp_read_reg_filter(dwc_otg_core_if_t * core_if)
16623 + adpctl_data_t adpctl;
16625 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16626 + adpctl.b.adp_tmout_int = 0;
16627 + adpctl.b.adp_prb_int = 0;
16628 + adpctl.b.adp_tmout_int = 0;
16630 + return adpctl.d32;
16634 + * Function is called to write ADP registers
16636 +void dwc_otg_adp_modify_reg(dwc_otg_core_if_t * core_if, uint32_t clr,
16639 + dwc_otg_adp_write_reg(core_if,
16640 + (dwc_otg_adp_read_reg(core_if) & (~clr)) | set);
16643 +static void adp_sense_timeout(void *ptr)
16645 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
16646 + core_if->adp.sense_timer_started = 0;
16647 + DWC_PRINTF("ADP SENSE TIMEOUT\n");
16648 + if (core_if->adp_enable) {
16649 + dwc_otg_adp_sense_stop(core_if);
16650 + dwc_otg_adp_probe_start(core_if);
16655 + * This function is called when the ADP vbus timer expires. Timeout is 1.1s.
16657 +static void adp_vbuson_timeout(void *ptr)
16659 + gpwrdn_data_t gpwrdn;
16660 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
16661 + hprt0_data_t hprt0 = {.d32 = 0 };
16662 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
16663 + DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
16665 + core_if->adp.vbuson_timer_started = 0;
16666 + /* Turn off vbus */
16667 + hprt0.b.prtpwr = 1;
16668 + DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
16671 + /* Power off the core */
16672 + if (core_if->power_down == 2) {
16673 + /* Enable Wakeup Logic */
16674 +// gpwrdn.b.wkupactiv = 1;
16675 + gpwrdn.b.pmuactv = 0;
16676 + gpwrdn.b.pwrdnrstn = 1;
16677 + gpwrdn.b.pwrdnclmp = 1;
16678 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
16681 + /* Suspend the Phy Clock */
16682 + pcgcctl.b.stoppclk = 1;
16683 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
16685 + /* Switch on VDD */
16686 +// gpwrdn.b.wkupactiv = 1;
16687 + gpwrdn.b.pmuactv = 1;
16688 + gpwrdn.b.pwrdnrstn = 1;
16689 + gpwrdn.b.pwrdnclmp = 1;
16690 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
16693 + /* Enable Power Down Logic */
16694 + gpwrdn.b.pmuintsel = 1;
16695 + gpwrdn.b.pmuactv = 1;
16696 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16699 + /* Power off the core */
16700 + if (core_if->power_down == 2) {
16702 + gpwrdn.b.pwrdnswtch = 1;
16703 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
16707 + /* Unmask SRP detected interrupt from Power Down Logic */
16709 + gpwrdn.b.srp_det_msk = 1;
16710 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16712 + dwc_otg_adp_probe_start(core_if);
16713 + dwc_otg_dump_global_registers(core_if);
16714 + dwc_otg_dump_host_registers(core_if);
16720 + * Start the ADP Initial Probe timer to detect if Port Connected interrupt is
16721 + * not asserted within 1.1 seconds.
16723 + * @param core_if the pointer to core_if strucure.
16725 +void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
16727 + core_if->adp.vbuson_timer_started = 1;
16728 + if (core_if->adp.vbuson_timer)
16730 + DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
16731 + /* 1.1 secs + 60ms necessary for cil_hcd_start*/
16732 + DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
16734 + DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
16740 + * Masks all DWC OTG core interrupts
16743 +static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
16746 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
16748 + /* Mask Host Interrupts */
16750 + /* Clear and disable HCINTs */
16751 + for (i = 0; i < core_if->core_params->host_channels; i++) {
16752 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
16753 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);
16757 + /* Clear and disable HAINT */
16758 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
16759 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);
16761 + /* Mask Device Interrupts */
16762 + if (!core_if->multiproc_int_enable) {
16763 + /* Clear and disable IN Endpoint interrupts */
16764 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
16765 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
16766 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
16767 + diepint, 0xFFFFFFFF);
16770 + /* Clear and disable OUT Endpoint interrupts */
16771 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
16772 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
16773 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
16774 + doepint, 0xFFFFFFFF);
16777 + /* Clear and disable DAINT */
16778 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
16780 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
16782 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
16783 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
16784 + diepeachintmsk[i], 0);
16785 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
16786 + diepint, 0xFFFFFFFF);
16789 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
16790 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
16791 + doepeachintmsk[i], 0);
16792 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
16793 + doepint, 0xFFFFFFFF);
16796 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
16798 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
16803 + /* Disable interrupts */
16804 + ahbcfg.b.glblintrmsk = 1;
16805 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
16807 + /* Disable all interrupts. */
16808 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
16810 + /* Clear any pending interrupts */
16811 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
16813 + /* Clear any pending OTG Interrupts */
16814 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);
16818 + * Unmask Port Connection Detected interrupt
16821 +static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
16823 + gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };
16825 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
16830 + * Starts the ADP Probing
16832 + * @param core_if the pointer to core_if structure.
16834 +uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
16837 + adpctl_data_t adpctl = {.d32 = 0};
16838 + gpwrdn_data_t gpwrdn;
16840 + adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
16841 + .b.adp_sns_int = 1, b.adp_tmout_int};
16843 + dwc_otg_disable_global_interrupts(core_if);
16844 + DWC_PRINTF("ADP Probe Start\n");
16845 + core_if->adp.probe_enabled = 1;
16847 + adpctl.b.adpres = 1;
16848 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16850 + while (adpctl.b.adpres) {
16851 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16855 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
16857 + /* In Host mode unmask SRP detected interrupt */
16859 + gpwrdn.b.sts_chngint_msk = 1;
16860 + if (!gpwrdn.b.idsts) {
16861 + gpwrdn.b.srp_det_msk = 1;
16863 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16865 + adpctl.b.adp_tmout_int_msk = 1;
16866 + adpctl.b.adp_prb_int_msk = 1;
16867 + adpctl.b.prb_dschg = 1;
16868 + adpctl.b.prb_delta = 1;
16869 + adpctl.b.prb_per = 1;
16870 + adpctl.b.adpen = 1;
16871 + adpctl.b.enaprb = 1;
16873 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16874 + DWC_PRINTF("ADP Probe Finish\n");
16879 + * Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted
16880 + * within 3 seconds.
16882 + * @param core_if the pointer to core_if strucure.
16884 +void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
16886 + core_if->adp.sense_timer_started = 1;
16887 + DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3000 /* 3 secs */ );
16891 + * Starts the ADP Sense
16893 + * @param core_if the pointer to core_if strucure.
16895 +uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
16897 + adpctl_data_t adpctl;
16899 + DWC_PRINTF("ADP Sense Start\n");
16901 + /* Unmask ADP sense interrupt and mask all other from the core */
16902 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
16903 + adpctl.b.adp_sns_int_msk = 1;
16904 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16905 + dwc_otg_disable_global_interrupts(core_if); // vahrama
16907 + /* Set ADP reset bit*/
16908 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
16909 + adpctl.b.adpres = 1;
16910 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16912 + while (adpctl.b.adpres) {
16913 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16916 + adpctl.b.adpres = 0;
16917 + adpctl.b.adpen = 1;
16918 + adpctl.b.enasns = 1;
16919 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16921 + dwc_otg_adp_sense_timer_start(core_if);
16927 + * Stops the ADP Probing
16929 + * @param core_if the pointer to core_if strucure.
16931 +uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if)
16934 + adpctl_data_t adpctl;
16935 + DWC_PRINTF("Stop ADP probe\n");
16936 + core_if->adp.probe_enabled = 0;
16937 + core_if->adp.probe_counter = 0;
16938 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16940 + adpctl.b.adpen = 0;
16941 + adpctl.b.adp_prb_int = 1;
16942 + adpctl.b.adp_tmout_int = 1;
16943 + adpctl.b.adp_sns_int = 1;
16944 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16950 + * Stops the ADP Sensing
16952 + * @param core_if the pointer to core_if strucure.
16954 +uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if)
16956 + adpctl_data_t adpctl;
16958 + core_if->adp.sense_enabled = 0;
16960 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
16961 + adpctl.b.enasns = 0;
16962 + adpctl.b.adp_sns_int = 1;
16963 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16969 + * Called to turn on the VBUS after initial ADP probe in host mode.
16970 + * If port power was already enabled in cil_hcd_start function then
16971 + * only schedule a timer.
16973 + * @param core_if the pointer to core_if structure.
16975 +void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
16977 + hprt0_data_t hprt0 = {.d32 = 0 };
16978 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
16979 + DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);
16981 + if (hprt0.b.prtpwr == 0) {
16982 + hprt0.b.prtpwr = 1;
16983 + //DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
16986 + dwc_otg_adp_vbuson_timer_start(core_if);
16990 + * Called right after driver is loaded
16991 + * to perform initial actions for ADP
16993 + * @param core_if the pointer to core_if structure.
16994 + * @param is_host - flag for current mode of operation either from GINTSTS or GPWRDN
16996 +void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host)
16998 + gpwrdn_data_t gpwrdn;
17000 + DWC_PRINTF("ADP Initial Start\n");
17001 + core_if->adp.adp_started = 1;
17003 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
17004 + dwc_otg_disable_global_interrupts(core_if);
17006 + DWC_PRINTF("HOST MODE\n");
17007 + /* Enable Power Down Logic Interrupt*/
17009 + gpwrdn.b.pmuintsel = 1;
17010 + gpwrdn.b.pmuactv = 1;
17011 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
17012 + /* Initialize first ADP probe to obtain Ramp Time value */
17013 + core_if->adp.initial_probe = 1;
17014 + dwc_otg_adp_probe_start(core_if);
17016 + gotgctl_data_t gotgctl;
17017 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
17018 + DWC_PRINTF("DEVICE MODE\n");
17019 + if (gotgctl.b.bsesvld == 0) {
17020 + /* Enable Power Down Logic Interrupt*/
17022 + DWC_PRINTF("VBUS is not valid - start ADP probe\n");
17023 + gpwrdn.b.pmuintsel = 1;
17024 + gpwrdn.b.pmuactv = 1;
17025 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
17026 + core_if->adp.initial_probe = 1;
17027 + dwc_otg_adp_probe_start(core_if);
17029 + DWC_PRINTF("VBUS is valid - initialize core as a Device\n");
17030 + core_if->op_state = B_PERIPHERAL;
17031 + dwc_otg_core_init(core_if);
17032 + dwc_otg_enable_global_interrupts(core_if);
17033 + cil_pcd_start(core_if);
17034 + dwc_otg_dump_global_registers(core_if);
17035 + dwc_otg_dump_dev_registers(core_if);
17040 +void dwc_otg_adp_init(dwc_otg_core_if_t * core_if)
17042 + core_if->adp.adp_started = 0;
17043 + core_if->adp.initial_probe = 0;
17044 + core_if->adp.probe_timer_values[0] = -1;
17045 + core_if->adp.probe_timer_values[1] = -1;
17046 + core_if->adp.probe_enabled = 0;
17047 + core_if->adp.sense_enabled = 0;
17048 + core_if->adp.sense_timer_started = 0;
17049 + core_if->adp.vbuson_timer_started = 0;
17050 + core_if->adp.probe_counter = 0;
17051 + core_if->adp.gpwrdn = 0;
17052 + core_if->adp.attached = DWC_OTG_ADP_UNKOWN;
17053 + /* Initialize timers */
17054 + core_if->adp.sense_timer =
17055 + DWC_TIMER_ALLOC("ADP SENSE TIMER", adp_sense_timeout, core_if);
17056 + core_if->adp.vbuson_timer =
17057 + DWC_TIMER_ALLOC("ADP VBUS ON TIMER", adp_vbuson_timeout, core_if);
17058 + if (!core_if->adp.sense_timer || !core_if->adp.vbuson_timer)
17060 + DWC_ERROR("Could not allocate memory for ADP timers\n");
17064 +void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if)
17066 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
17067 + gpwrdn.b.pmuintsel = 1;
17068 + gpwrdn.b.pmuactv = 1;
17069 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17071 + if (core_if->adp.probe_enabled)
17072 + dwc_otg_adp_probe_stop(core_if);
17073 + if (core_if->adp.sense_enabled)
17074 + dwc_otg_adp_sense_stop(core_if);
17075 + if (core_if->adp.sense_timer_started)
17076 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
17077 + if (core_if->adp.vbuson_timer_started)
17078 + DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
17079 + DWC_TIMER_FREE(core_if->adp.sense_timer);
17080 + DWC_TIMER_FREE(core_if->adp.vbuson_timer);
17083 +/////////////////////////////////////////////////////////////////////
17084 +////////////// ADP Interrupt Handlers ///////////////////////////////
17085 +/////////////////////////////////////////////////////////////////////
17087 + * This function sets Ramp Timer values
17089 +static uint32_t set_timer_value(dwc_otg_core_if_t * core_if, uint32_t val)
17091 + if (core_if->adp.probe_timer_values[0] == -1) {
17092 + core_if->adp.probe_timer_values[0] = val;
17093 + core_if->adp.probe_timer_values[1] = -1;
17096 + core_if->adp.probe_timer_values[1] =
17097 + core_if->adp.probe_timer_values[0];
17098 + core_if->adp.probe_timer_values[0] = val;
17104 + * This function compares Ramp Timer values
17106 +static uint32_t compare_timer_values(dwc_otg_core_if_t * core_if)
17109 + if (core_if->adp.probe_timer_values[0]>=core_if->adp.probe_timer_values[1])
17110 + diff = core_if->adp.probe_timer_values[0]-core_if->adp.probe_timer_values[1];
17112 + diff = core_if->adp.probe_timer_values[1]-core_if->adp.probe_timer_values[0];
17121 + * This function handles ADP Probe Interrupts
17123 +static int32_t dwc_otg_adp_handle_prb_intr(dwc_otg_core_if_t * core_if,
17126 + adpctl_data_t adpctl = {.d32 = 0 };
17127 + gpwrdn_data_t gpwrdn, temp;
17128 + adpctl.d32 = val;
17130 + temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17131 + core_if->adp.probe_counter++;
17132 + core_if->adp.gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17133 + if (adpctl.b.rtim == 0 && !temp.b.idsts){
17134 + DWC_PRINTF("RTIM value is 0\n");
17137 + if (set_timer_value(core_if, adpctl.b.rtim) &&
17138 + core_if->adp.initial_probe) {
17139 + core_if->adp.initial_probe = 0;
17140 + dwc_otg_adp_probe_stop(core_if);
17142 + gpwrdn.b.pmuactv = 1;
17143 + gpwrdn.b.pmuintsel = 1;
17144 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17145 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
17147 + /* check which value is for device mode and which for Host mode */
17148 + if (!temp.b.idsts) { /* considered host mode value is 0 */
17150 + * Turn on VBUS after initial ADP probe.
17152 + core_if->op_state = A_HOST;
17153 + dwc_otg_enable_global_interrupts(core_if);
17154 + DWC_SPINUNLOCK(core_if->lock);
17155 + cil_hcd_start(core_if);
17156 + dwc_otg_adp_turnon_vbus(core_if);
17157 + DWC_SPINLOCK(core_if->lock);
17160 + * Initiate SRP after initial ADP probe.
17162 + dwc_otg_enable_global_interrupts(core_if);
17163 + dwc_otg_initiate_srp(core_if);
17165 + } else if (core_if->adp.probe_counter > 2){
17166 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17167 + if (compare_timer_values(core_if)) {
17168 + DWC_PRINTF("Difference in timer values !!! \n");
17169 +// core_if->adp.attached = DWC_OTG_ADP_ATTACHED;
17170 + dwc_otg_adp_probe_stop(core_if);
17172 + /* Power on the core */
17173 + if (core_if->power_down == 2) {
17174 + gpwrdn.b.pwrdnswtch = 1;
17175 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17176 + gpwrdn, 0, gpwrdn.d32);
17179 + /* check which value is for device mode and which for Host mode */
17180 + if (!temp.b.idsts) { /* considered host mode value is 0 */
17181 + /* Disable Interrupt from Power Down Logic */
17183 + gpwrdn.b.pmuintsel = 1;
17184 + gpwrdn.b.pmuactv = 1;
17185 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17186 + gpwrdn, gpwrdn.d32, 0);
17189 + * Initialize the Core for Host mode.
17191 + core_if->op_state = A_HOST;
17192 + dwc_otg_core_init(core_if);
17193 + dwc_otg_enable_global_interrupts(core_if);
17194 + cil_hcd_start(core_if);
17196 + gotgctl_data_t gotgctl;
17197 + /* Mask SRP detected interrupt from Power Down Logic */
17199 + gpwrdn.b.srp_det_msk = 1;
17200 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17201 + gpwrdn, gpwrdn.d32, 0);
17203 + /* Disable Power Down Logic */
17205 + gpwrdn.b.pmuintsel = 1;
17206 + gpwrdn.b.pmuactv = 1;
17207 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17208 + gpwrdn, gpwrdn.d32, 0);
17211 + * Initialize the Core for Device mode.
17213 + core_if->op_state = B_PERIPHERAL;
17214 + dwc_otg_core_init(core_if);
17215 + dwc_otg_enable_global_interrupts(core_if);
17216 + cil_pcd_start(core_if);
17218 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
17219 + if (!gotgctl.b.bsesvld) {
17220 + dwc_otg_initiate_srp(core_if);
17224 + if (core_if->power_down == 2) {
17225 + if (gpwrdn.b.bsessvld) {
17226 + /* Mask SRP detected interrupt from Power Down Logic */
17228 + gpwrdn.b.srp_det_msk = 1;
17229 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17231 + /* Disable Power Down Logic */
17233 + gpwrdn.b.pmuactv = 1;
17234 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17237 + * Initialize the Core for Device mode.
17239 + core_if->op_state = B_PERIPHERAL;
17240 + dwc_otg_core_init(core_if);
17241 + dwc_otg_enable_global_interrupts(core_if);
17242 + cil_pcd_start(core_if);
17247 + /* Clear interrupt */
17248 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17249 + adpctl.b.adp_prb_int = 1;
17250 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17256 + * This function hadles ADP Sense Interrupt
17258 +static int32_t dwc_otg_adp_handle_sns_intr(dwc_otg_core_if_t * core_if)
17260 + adpctl_data_t adpctl;
17261 + /* Stop ADP Sense timer */
17262 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
17264 + /* Restart ADP Sense timer */
17265 + dwc_otg_adp_sense_timer_start(core_if);
17267 + /* Clear interrupt */
17268 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17269 + adpctl.b.adp_sns_int = 1;
17270 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17276 + * This function handles ADP Probe Interrupts
17278 +static int32_t dwc_otg_adp_handle_prb_tmout_intr(dwc_otg_core_if_t * core_if,
17281 + adpctl_data_t adpctl = {.d32 = 0 };
17282 + adpctl.d32 = val;
17283 + set_timer_value(core_if, adpctl.b.rtim);
17285 + /* Clear interrupt */
17286 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17287 + adpctl.b.adp_tmout_int = 1;
17288 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17294 + * ADP Interrupt handler.
17297 +int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if)
17300 + adpctl_data_t adpctl = {.d32 = 0};
17302 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17303 + DWC_PRINTF("ADPCTL = %08x\n",adpctl.d32);
17305 + if (adpctl.b.adp_sns_int & adpctl.b.adp_sns_int_msk) {
17306 + DWC_PRINTF("ADP Sense interrupt\n");
17307 + retval |= dwc_otg_adp_handle_sns_intr(core_if);
17309 + if (adpctl.b.adp_tmout_int & adpctl.b.adp_tmout_int_msk) {
17310 + DWC_PRINTF("ADP timeout interrupt\n");
17311 + retval |= dwc_otg_adp_handle_prb_tmout_intr(core_if, adpctl.d32);
17313 + if (adpctl.b.adp_prb_int & adpctl.b.adp_prb_int_msk) {
17314 + DWC_PRINTF("ADP Probe interrupt\n");
17315 + adpctl.b.adp_prb_int = 1;
17316 + retval |= dwc_otg_adp_handle_prb_intr(core_if, adpctl.d32);
17319 +// dwc_otg_adp_modify_reg(core_if, adpctl.d32, 0);
17320 + //dwc_otg_adp_write_reg(core_if, adpctl.d32);
17321 + DWC_PRINTF("RETURN FROM ADP ISR\n");
17328 + * @param core_if Programming view of DWC_otg controller.
17330 +int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if)
17333 +#ifndef DWC_HOST_ONLY
17334 + hprt0_data_t hprt0;
17335 + gpwrdn_data_t gpwrdn;
17336 + DWC_DEBUGPL(DBG_ANY, "++ Power Down Logic Session Request Interrupt++\n");
17338 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17339 + /* check which value is for device mode and which for Host mode */
17340 + if (!gpwrdn.b.idsts) { /* considered host mode value is 0 */
17341 + DWC_PRINTF("SRP: Host mode\n");
17343 + if (core_if->adp_enable) {
17344 + dwc_otg_adp_probe_stop(core_if);
17346 + /* Power on the core */
17347 + if (core_if->power_down == 2) {
17348 + gpwrdn.b.pwrdnswtch = 1;
17349 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17350 + gpwrdn, 0, gpwrdn.d32);
17353 + core_if->op_state = A_HOST;
17354 + dwc_otg_core_init(core_if);
17355 + dwc_otg_enable_global_interrupts(core_if);
17356 + cil_hcd_start(core_if);
17359 + /* Turn on the port power bit. */
17360 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
17361 + hprt0.b.prtpwr = 1;
17362 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
17364 + /* Start the Connection timer. So a message can be displayed
17365 + * if connect does not occur within 10 seconds. */
17366 + cil_hcd_session_start(core_if);
17368 + DWC_PRINTF("SRP: Device mode %s\n", __FUNCTION__);
17369 + if (core_if->adp_enable) {
17370 + dwc_otg_adp_probe_stop(core_if);
17372 + /* Power on the core */
17373 + if (core_if->power_down == 2) {
17374 + gpwrdn.b.pwrdnswtch = 1;
17375 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17376 + gpwrdn, 0, gpwrdn.d32);
17380 + gpwrdn.b.pmuactv = 0;
17381 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
17384 + core_if->op_state = B_PERIPHERAL;
17385 + dwc_otg_core_init(core_if);
17386 + dwc_otg_enable_global_interrupts(core_if);
17387 + cil_pcd_start(core_if);
17394 +++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.h
17396 +/* ==========================================================================
17397 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.h $
17398 + * $Revision: #7 $
17399 + * $Date: 2011/10/24 $
17400 + * $Change: 1871159 $
17402 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
17403 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
17404 + * otherwise expressly agreed to in writing between Synopsys and you.
17406 + * The Software IS NOT an item of Licensed Software or Licensed Product under
17407 + * any End User Software License Agreement or Agreement for Licensed Product
17408 + * with Synopsys or any supplement thereto. You are permitted to use and
17409 + * redistribute this Software in source and binary forms, with or without
17410 + * modification, provided that redistributions of source code must retain this
17411 + * notice. You may not view, use, disclose, copy or distribute this file or
17412 + * any information contained herein except pursuant to this license grant from
17413 + * Synopsys. If you do not agree with this notice, including the disclaimer
17414 + * below, then you are not authorized to use the Software.
17416 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
17417 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17418 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17419 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
17420 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17421 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17422 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17423 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17424 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17425 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
17427 + * ========================================================================== */
17429 +#ifndef __DWC_OTG_ADP_H__
17430 +#define __DWC_OTG_ADP_H__
17435 + * This file contains the Attach Detect Protocol interfaces and defines
17436 + * (functions) and structures for Linux.
17440 +#define DWC_OTG_ADP_UNATTACHED 0
17441 +#define DWC_OTG_ADP_ATTACHED 1
17442 +#define DWC_OTG_ADP_UNKOWN 2
17444 +typedef struct dwc_otg_adp {
17445 + uint32_t adp_started;
17446 + uint32_t initial_probe;
17447 + int32_t probe_timer_values[2];
17448 + uint32_t probe_enabled;
17449 + uint32_t sense_enabled;
17450 + dwc_timer_t *sense_timer;
17451 + uint32_t sense_timer_started;
17452 + dwc_timer_t *vbuson_timer;
17453 + uint32_t vbuson_timer_started;
17454 + uint32_t attached;
17455 + uint32_t probe_counter;
17460 + * Attach Detect Protocol functions
17463 +extern void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value);
17464 +extern uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if);
17465 +extern uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if);
17466 +extern uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if);
17467 +extern uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if);
17468 +extern uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if);
17469 +extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
17470 +extern void dwc_otg_adp_init(dwc_otg_core_if_t * core_if);
17471 +extern void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if);
17472 +extern int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if);
17473 +extern int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if);
17475 +#endif //__DWC_OTG_ADP_H__
17477 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
17479 +/* ==========================================================================
17480 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $
17481 + * $Revision: #44 $
17482 + * $Date: 2010/11/29 $
17483 + * $Change: 1636033 $
17485 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
17486 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
17487 + * otherwise expressly agreed to in writing between Synopsys and you.
17489 + * The Software IS NOT an item of Licensed Software or Licensed Product under
17490 + * any End User Software License Agreement or Agreement for Licensed Product
17491 + * with Synopsys or any supplement thereto. You are permitted to use and
17492 + * redistribute this Software in source and binary forms, with or without
17493 + * modification, provided that redistributions of source code must retain this
17494 + * notice. You may not view, use, disclose, copy or distribute this file or
17495 + * any information contained herein except pursuant to this license grant from
17496 + * Synopsys. If you do not agree with this notice, including the disclaimer
17497 + * below, then you are not authorized to use the Software.
17499 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
17500 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17501 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17502 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
17503 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17504 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17505 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17506 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17507 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17508 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
17510 + * ========================================================================== */
17514 + * The diagnostic interface will provide access to the controller for
17515 + * bringing up the hardware and testing. The Linux driver attributes
17516 + * feature will be used to provide the Linux Diagnostic
17517 + * Interface. These attributes are accessed through sysfs.
17520 +/** @page "Linux Module Attributes"
17522 + * The Linux module attributes feature is used to provide the Linux
17523 + * Diagnostic Interface. These attributes are accessed through sysfs.
17524 + * The diagnostic interface will provide access to the controller for
17525 + * bringing up the hardware and testing.
17527 + The following table shows the attributes.
17530 + <td><b> Name</b></td>
17531 + <td><b> Description</b></td>
17532 + <td><b> Access</b></td>
17537 + <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
17542 + <td> hnpcapable </td>
17543 + <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
17544 + Read returns the current value.</td>
17545 + <td> Read/Write</td>
17549 + <td> srpcapable </td>
17550 + <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
17551 + Read returns the current value.</td>
17552 + <td> Read/Write</td>
17556 + <td> hsic_connect </td>
17557 + <td> Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register.
17558 + Read returns the current value.</td>
17559 + <td> Read/Write</td>
17563 + <td> inv_sel_hsic </td>
17564 + <td> Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register.
17565 + Read returns the current value.</td>
17566 + <td> Read/Write</td>
17571 + <td> Initiates the Host Negotiation Protocol. Read returns the status.</td>
17572 + <td> Read/Write</td>
17577 + <td> Initiates the Session Request Protocol. Read returns the status.</td>
17578 + <td> Read/Write</td>
17582 + <td> buspower </td>
17583 + <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
17584 + <td> Read/Write</td>
17588 + <td> bussuspend </td>
17589 + <td> Suspends the USB bus.</td>
17590 + <td> Read/Write</td>
17594 + <td> busconnected </td>
17595 + <td> Gets the connection status of the bus</td>
17600 + <td> gotgctl </td>
17601 + <td> Gets or sets the Core Control Status Register.</td>
17602 + <td> Read/Write</td>
17606 + <td> gusbcfg </td>
17607 + <td> Gets or sets the Core USB Configuration Register</td>
17608 + <td> Read/Write</td>
17612 + <td> grxfsiz </td>
17613 + <td> Gets or sets the Receive FIFO Size Register</td>
17614 + <td> Read/Write</td>
17618 + <td> gnptxfsiz </td>
17619 + <td> Gets or sets the non-periodic Transmit Size Register</td>
17620 + <td> Read/Write</td>
17624 + <td> gpvndctl </td>
17625 + <td> Gets or sets the PHY Vendor Control Register</td>
17626 + <td> Read/Write</td>
17631 + <td> Gets the value in the lower 16-bits of the General Purpose IO Register
17632 + or sets the upper 16 bits.</td>
17633 + <td> Read/Write</td>
17638 + <td> Gets or sets the value of the User ID Register</td>
17639 + <td> Read/Write</td>
17643 + <td> gsnpsid </td>
17644 + <td> Gets the value of the Synopsys ID Regester</td>
17649 + <td> devspeed </td>
17650 + <td> Gets or sets the device speed setting in the DCFG register</td>
17651 + <td> Read/Write</td>
17655 + <td> enumspeed </td>
17656 + <td> Gets the device enumeration Speed.</td>
17661 + <td> hptxfsiz </td>
17662 + <td> Gets the value of the Host Periodic Transmit FIFO</td>
17668 + <td> Gets or sets the value in the Host Port Control and Status Register</td>
17669 + <td> Read/Write</td>
17673 + <td> regoffset </td>
17674 + <td> Sets the register offset for the next Register Access</td>
17675 + <td> Read/Write</td>
17679 + <td> regvalue </td>
17680 + <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
17681 + <td> Read/Write</td>
17685 + <td> remote_wakeup </td>
17686 + <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
17687 + wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
17688 + Wakeup signalling bit in the Device Control Register is set for 1
17689 + milli-second.</td>
17690 + <td> Read/Write</td>
17694 + <td> rem_wakeup_pwrdn </td>
17695 + <td> On read, shows the status core - hibernated or not. On write, initiates
17696 + a remote wakeup of the device from Hibernation. </td>
17697 + <td> Read/Write</td>
17701 + <td> mode_ch_tim_en </td>
17702 + <td> This bit is used to enable or disable the host core to wait for 200 PHY
17703 + clock cycles at the end of Resume to change the opmode signal to the PHY to 00
17704 + after Suspend or LPM. </td>
17705 + <td> Read/Write</td>
17709 + <td> fr_interval </td>
17710 + <td> On read, shows the value of HFIR Frame Interval. On write, dynamically
17711 + reload HFIR register during runtime. The application can write a value to this
17712 + register only after the Port Enable bit of the Host Port Control and Status
17713 + register (HPRT.PrtEnaPort) has been set </td>
17714 + <td> Read/Write</td>
17718 + <td> disconnect_us </td>
17719 + <td> On read, shows the status of disconnect_device_us. On write, sets disconnect_us
17720 + which causes soft disconnect for 100us. Applicable only for device mode of operation.</td>
17721 + <td> Read/Write</td>
17725 + <td> regdump </td>
17726 + <td> Dumps the contents of core registers.</td>
17731 + <td> spramdump </td>
17732 + <td> Dumps the contents of core registers.</td>
17737 + <td> hcddump </td>
17738 + <td> Dumps the current HCD state.</td>
17743 + <td> hcd_frrem </td>
17744 + <td> Shows the average value of the Frame Remaining
17745 + field in the Host Frame Number/Frame Remaining register when an SOF interrupt
17746 + occurs. This can be used to determine the average interrupt latency. Also
17747 + shows the average Frame Remaining value for start_transfer and the "a" and
17748 + "b" sample points. The "a" and "b" sample points may be used during debugging
17749 + bto determine how long it takes to execute a section of the HCD code.</td>
17754 + <td> rd_reg_test </td>
17755 + <td> Displays the time required to read the GNPTXFSIZ register many times
17756 + (the output shows the number of times the register is read).
17761 + <td> wr_reg_test </td>
17762 + <td> Displays the time required to write the GNPTXFSIZ register many times
17763 + (the output shows the number of times the register is written).
17768 + <td> lpm_response </td>
17769 + <td> Gets or sets lpm_response mode. Applicable only in device mode.
17774 + <td> sleep_status </td>
17775 + <td> Shows sleep status of device.
17782 + To get the current mode:
17783 + cat /sys/devices/lm0/mode
17785 + To power down the USB:
17786 + echo 0 > /sys/devices/lm0/buspower
17789 +#include "dwc_otg_os_dep.h"
17790 +#include "dwc_os.h"
17791 +#include "dwc_otg_driver.h"
17792 +#include "dwc_otg_attr.h"
17793 +#include "dwc_otg_core_if.h"
17794 +#include "dwc_otg_pcd_if.h"
17795 +#include "dwc_otg_hcd_if.h"
17798 + * MACROs for defining sysfs attribute
17800 +#ifdef LM_INTERFACE
17802 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17803 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17805 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17806 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17808 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17809 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17811 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17812 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17813 + const char *buf, size_t count) \
17815 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17816 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17817 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17818 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17822 +#elif defined(PCI_INTERFACE)
17824 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17825 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17827 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17829 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17830 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17832 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17833 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17834 + const char *buf, size_t count) \
17836 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17837 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17838 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17842 +#elif defined(PLATFORM_INTERFACE)
17844 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17845 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17847 + struct platform_device *platform_dev = \
17848 + container_of(_dev, struct platform_device, dev); \
17849 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17851 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
17852 + __func__, _dev, platform_dev, otg_dev); \
17853 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17854 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17856 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17857 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17858 + const char *buf, size_t count) \
17860 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
17861 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17862 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17863 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17869 + * MACROs for defining sysfs attribute for 32-bit registers
17871 +#ifdef LM_INTERFACE
17872 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17873 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17875 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17876 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17878 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17879 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
17881 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17882 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17883 + const char *buf, size_t count) \
17885 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17886 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17887 + uint32_t val = simple_strtoul(buf, NULL, 16); \
17888 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
17891 +#elif defined(PCI_INTERFACE)
17892 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17893 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17895 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17897 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17898 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
17900 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17901 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17902 + const char *buf, size_t count) \
17904 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17905 + uint32_t val = simple_strtoul(buf, NULL, 16); \
17906 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
17910 +#elif defined(PLATFORM_INTERFACE)
17911 +#include "dwc_otg_dbg.h"
17912 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17913 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17915 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
17916 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17918 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
17919 + __func__, _dev, platform_dev, otg_dev); \
17920 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17921 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
17923 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17924 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17925 + const char *buf, size_t count) \
17927 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
17928 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17929 + uint32_t val = simple_strtoul(buf, NULL, 16); \
17930 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
17936 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \
17937 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17938 +DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17939 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
17941 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \
17942 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17943 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
17945 +#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
17946 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17947 +DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
17948 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
17950 +#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
17951 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
17952 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
17954 +/** @name Functions for Show/Store of Attributes */
17958 + * Helper function returning the otg_device structure of the given device
17960 +static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
17962 + dwc_otg_device_t *otg_dev;
17963 + DWC_OTG_GETDRVDEV(otg_dev, _dev);
17968 + * Show the register offset of the Register Access.
17970 +static ssize_t regoffset_show(struct device *_dev,
17971 + struct device_attribute *attr, char *buf)
17973 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17974 + return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
17975 + otg_dev->os_dep.reg_offset);
17979 + * Set the register offset for the next Register Access Read/Write
17981 +static ssize_t regoffset_store(struct device *_dev,
17982 + struct device_attribute *attr,
17983 + const char *buf, size_t count)
17985 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
17986 + uint32_t offset = simple_strtoul(buf, NULL, 16);
17987 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
17988 + if (offset < SZ_256K) {
17989 +#elif defined(PCI_INTERFACE)
17990 + if (offset < 0x00040000) {
17992 + otg_dev->os_dep.reg_offset = offset;
17994 + dev_err(_dev, "invalid offset\n");
18000 +DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
18003 + * Show the value of the register at the offset in the reg_offset
18006 +static ssize_t regvalue_show(struct device *_dev,
18007 + struct device_attribute *attr, char *buf)
18009 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18011 + volatile uint32_t *addr;
18013 + if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
18014 + /* Calculate the address */
18015 + addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
18016 + (uint8_t *) otg_dev->os_dep.base);
18017 + val = DWC_READ_REG32(addr);
18018 + return snprintf(buf,
18019 + sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
18020 + "Reg@0x%06x = 0x%08x\n", otg_dev->os_dep.reg_offset,
18023 + dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->os_dep.reg_offset);
18024 + return sprintf(buf, "invalid offset\n");
18029 + * Store the value in the register at the offset in the reg_offset
18033 +static ssize_t regvalue_store(struct device *_dev,
18034 + struct device_attribute *attr,
18035 + const char *buf, size_t count)
18037 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18038 + volatile uint32_t *addr;
18039 + uint32_t val = simple_strtoul(buf, NULL, 16);
18040 + //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
18041 + if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
18042 + /* Calculate the address */
18043 + addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
18044 + (uint8_t *) otg_dev->os_dep.base);
18045 + DWC_WRITE_REG32(addr, val);
18047 + dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
18048 + otg_dev->os_dep.reg_offset);
18053 +DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
18058 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
18059 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
18060 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "SRPCapable");
18061 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
18062 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");
18064 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
18065 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
18066 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");
18068 +DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
18069 +DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
18070 + &(otg_dev->core_if->core_global_regs->gusbcfg),
18072 +DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
18073 + &(otg_dev->core_if->core_global_regs->grxfsiz),
18075 +DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
18076 + &(otg_dev->core_if->core_global_regs->gnptxfsiz),
18078 +DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
18079 + &(otg_dev->core_if->core_global_regs->gpvndctl),
18081 +DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
18082 + &(otg_dev->core_if->core_global_regs->ggpio),
18084 +DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
18086 +DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
18087 + &(otg_dev->core_if->core_global_regs->gsnpsid),
18089 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
18090 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");
18092 +DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
18093 + &(otg_dev->core_if->core_global_regs->hptxfsiz),
18095 +DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
18098 + * @todo Add code to initiate the HNP.
18101 + * Show the HNP status bit
18103 +static ssize_t hnp_show(struct device *_dev,
18104 + struct device_attribute *attr, char *buf)
18106 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18107 + return sprintf(buf, "HstNegScs = 0x%x\n",
18108 + dwc_otg_get_hnpstatus(otg_dev->core_if));
18112 + * Set the HNP Request bit
18114 +static ssize_t hnp_store(struct device *_dev,
18115 + struct device_attribute *attr,
18116 + const char *buf, size_t count)
18118 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18119 + uint32_t in = simple_strtoul(buf, NULL, 16);
18120 + dwc_otg_set_hnpreq(otg_dev->core_if, in);
18124 +DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
18127 + * @todo Add code to initiate the SRP.
18130 + * Show the SRP status bit
18132 +static ssize_t srp_show(struct device *_dev,
18133 + struct device_attribute *attr, char *buf)
18135 +#ifndef DWC_HOST_ONLY
18136 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18137 + return sprintf(buf, "SesReqScs = 0x%x\n",
18138 + dwc_otg_get_srpstatus(otg_dev->core_if));
18140 + return sprintf(buf, "Host Only Mode!\n");
18145 + * Set the SRP Request bit
18147 +static ssize_t srp_store(struct device *_dev,
18148 + struct device_attribute *attr,
18149 + const char *buf, size_t count)
18151 +#ifndef DWC_HOST_ONLY
18152 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18153 + dwc_otg_pcd_initiate_srp(otg_dev->pcd);
18158 +DEVICE_ATTR(srp, 0644, srp_show, srp_store);
18161 + * @todo Need to do more for power on/off?
18164 + * Show the Bus Power status
18166 +static ssize_t buspower_show(struct device *_dev,
18167 + struct device_attribute *attr, char *buf)
18169 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18170 + return sprintf(buf, "Bus Power = 0x%x\n",
18171 + dwc_otg_get_prtpower(otg_dev->core_if));
18175 + * Set the Bus Power status
18177 +static ssize_t buspower_store(struct device *_dev,
18178 + struct device_attribute *attr,
18179 + const char *buf, size_t count)
18181 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18182 + uint32_t on = simple_strtoul(buf, NULL, 16);
18183 + dwc_otg_set_prtpower(otg_dev->core_if, on);
18187 +DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
18190 + * @todo Need to do more for suspend?
18193 + * Show the Bus Suspend status
18195 +static ssize_t bussuspend_show(struct device *_dev,
18196 + struct device_attribute *attr, char *buf)
18198 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18199 + return sprintf(buf, "Bus Suspend = 0x%x\n",
18200 + dwc_otg_get_prtsuspend(otg_dev->core_if));
18204 + * Set the Bus Suspend status
18206 +static ssize_t bussuspend_store(struct device *_dev,
18207 + struct device_attribute *attr,
18208 + const char *buf, size_t count)
18210 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18211 + uint32_t in = simple_strtoul(buf, NULL, 16);
18212 + dwc_otg_set_prtsuspend(otg_dev->core_if, in);
18216 +DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
18219 + * Show the Mode Change Ready Timer status
18221 +static ssize_t mode_ch_tim_en_show(struct device *_dev,
18222 + struct device_attribute *attr, char *buf)
18224 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18225 + return sprintf(buf, "Mode Change Ready Timer Enable = 0x%x\n",
18226 + dwc_otg_get_mode_ch_tim(otg_dev->core_if));
18230 + * Set the Mode Change Ready Timer status
18232 +static ssize_t mode_ch_tim_en_store(struct device *_dev,
18233 + struct device_attribute *attr,
18234 + const char *buf, size_t count)
18236 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18237 + uint32_t in = simple_strtoul(buf, NULL, 16);
18238 + dwc_otg_set_mode_ch_tim(otg_dev->core_if, in);
18242 +DEVICE_ATTR(mode_ch_tim_en, 0644, mode_ch_tim_en_show, mode_ch_tim_en_store);
18245 + * Show the value of HFIR Frame Interval bitfield
18247 +static ssize_t fr_interval_show(struct device *_dev,
18248 + struct device_attribute *attr, char *buf)
18250 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18251 + return sprintf(buf, "Frame Interval = 0x%x\n",
18252 + dwc_otg_get_fr_interval(otg_dev->core_if));
18256 + * Set the HFIR Frame Interval value
18258 +static ssize_t fr_interval_store(struct device *_dev,
18259 + struct device_attribute *attr,
18260 + const char *buf, size_t count)
18262 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18263 + uint32_t in = simple_strtoul(buf, NULL, 10);
18264 + dwc_otg_set_fr_interval(otg_dev->core_if, in);
18268 +DEVICE_ATTR(fr_interval, 0644, fr_interval_show, fr_interval_store);
18271 + * Show the status of Remote Wakeup.
18273 +static ssize_t remote_wakeup_show(struct device *_dev,
18274 + struct device_attribute *attr, char *buf)
18276 +#ifndef DWC_HOST_ONLY
18277 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18279 + return sprintf(buf,
18280 + "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
18281 + dwc_otg_get_remotewakesig(otg_dev->core_if),
18282 + dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
18283 + dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
18285 + return sprintf(buf, "Host Only Mode!\n");
18286 +#endif /* DWC_HOST_ONLY */
18290 + * Initiate a remote wakeup of the host. The Device control register
18291 + * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
18295 +static ssize_t remote_wakeup_store(struct device *_dev,
18296 + struct device_attribute *attr,
18297 + const char *buf, size_t count)
18299 +#ifndef DWC_HOST_ONLY
18300 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18301 + uint32_t val = simple_strtoul(buf, NULL, 16);
18304 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
18306 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
18308 +#endif /* DWC_HOST_ONLY */
18312 +DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
18313 + remote_wakeup_store);
18316 + * Show the whether core is hibernated or not.
18318 +static ssize_t rem_wakeup_pwrdn_show(struct device *_dev,
18319 + struct device_attribute *attr, char *buf)
18321 +#ifndef DWC_HOST_ONLY
18322 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18324 + if (dwc_otg_get_core_state(otg_dev->core_if)) {
18325 + DWC_PRINTF("Core is in hibernation\n");
18327 + DWC_PRINTF("Core is not in hibernation\n");
18329 +#endif /* DWC_HOST_ONLY */
18333 +extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
18334 + int rem_wakeup, int reset);
18337 + * Initiate a remote wakeup of the device to exit from hibernation.
18339 +static ssize_t rem_wakeup_pwrdn_store(struct device *_dev,
18340 + struct device_attribute *attr,
18341 + const char *buf, size_t count)
18343 +#ifndef DWC_HOST_ONLY
18344 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18345 + dwc_otg_device_hibernation_restore(otg_dev->core_if, 1, 0);
18350 +DEVICE_ATTR(rem_wakeup_pwrdn, S_IRUGO | S_IWUSR, rem_wakeup_pwrdn_show,
18351 + rem_wakeup_pwrdn_store);
18353 +static ssize_t disconnect_us(struct device *_dev,
18354 + struct device_attribute *attr,
18355 + const char *buf, size_t count)
18358 +#ifndef DWC_HOST_ONLY
18359 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18360 + uint32_t val = simple_strtoul(buf, NULL, 16);
18361 + DWC_PRINTF("The Passed value is %04x\n", val);
18363 + dwc_otg_pcd_disconnect_us(otg_dev->pcd, 50);
18365 +#endif /* DWC_HOST_ONLY */
18369 +DEVICE_ATTR(disconnect_us, S_IWUSR, 0, disconnect_us);
18372 + * Dump global registers and either host or device registers (depending on the
18373 + * current mode of the core).
18375 +static ssize_t regdump_show(struct device *_dev,
18376 + struct device_attribute *attr, char *buf)
18378 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18380 + dwc_otg_dump_global_registers(otg_dev->core_if);
18381 + if (dwc_otg_is_host_mode(otg_dev->core_if)) {
18382 + dwc_otg_dump_host_registers(otg_dev->core_if);
18384 + dwc_otg_dump_dev_registers(otg_dev->core_if);
18387 + return sprintf(buf, "Register Dump\n");
18390 +DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);
18393 + * Dump global registers and either host or device registers (depending on the
18394 + * current mode of the core).
18396 +static ssize_t spramdump_show(struct device *_dev,
18397 + struct device_attribute *attr, char *buf)
18399 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18401 + dwc_otg_dump_spram(otg_dev->core_if);
18403 + return sprintf(buf, "SPRAM Dump\n");
18406 +DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);
18409 + * Dump the current hcd state.
18411 +static ssize_t hcddump_show(struct device *_dev,
18412 + struct device_attribute *attr, char *buf)
18414 +#ifndef DWC_DEVICE_ONLY
18415 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18416 + dwc_otg_hcd_dump_state(otg_dev->hcd);
18417 +#endif /* DWC_DEVICE_ONLY */
18418 + return sprintf(buf, "HCD Dump\n");
18421 +DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);
18424 + * Dump the average frame remaining at SOF. This can be used to
18425 + * determine average interrupt latency. Frame remaining is also shown for
18426 + * start transfer and two additional sample points.
18428 +static ssize_t hcd_frrem_show(struct device *_dev,
18429 + struct device_attribute *attr, char *buf)
18431 +#ifndef DWC_DEVICE_ONLY
18432 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18434 + dwc_otg_hcd_dump_frrem(otg_dev->hcd);
18435 +#endif /* DWC_DEVICE_ONLY */
18436 + return sprintf(buf, "HCD Dump Frame Remaining\n");
18439 +DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);
18442 + * Displays the time required to read the GNPTXFSIZ register many times (the
18443 + * output shows the number of times the register is read).
18445 +#define RW_REG_COUNT 10000000
18446 +#define MSEC_PER_JIFFIE 1000/HZ
18447 +static ssize_t rd_reg_test_show(struct device *_dev,
18448 + struct device_attribute *attr, char *buf)
18450 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18453 + int start_jiffies;
18455 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
18456 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
18457 + start_jiffies = jiffies;
18458 + for (i = 0; i < RW_REG_COUNT; i++) {
18459 + dwc_otg_get_gnptxfsiz(otg_dev->core_if);
18461 + time = jiffies - start_jiffies;
18462 + return sprintf(buf,
18463 + "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
18464 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
18467 +DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);
18470 + * Displays the time required to write the GNPTXFSIZ register many times (the
18471 + * output shows the number of times the register is written).
18473 +static ssize_t wr_reg_test_show(struct device *_dev,
18474 + struct device_attribute *attr, char *buf)
18476 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18477 + uint32_t reg_val;
18480 + int start_jiffies;
18482 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
18483 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
18484 + reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
18485 + start_jiffies = jiffies;
18486 + for (i = 0; i < RW_REG_COUNT; i++) {
18487 + dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);
18489 + time = jiffies - start_jiffies;
18490 + return sprintf(buf,
18491 + "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
18492 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
18495 +DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);
18497 +#ifdef CONFIG_USB_DWC_OTG_LPM
18500 +* Show the lpm_response attribute.
18502 +static ssize_t lpmresp_show(struct device *_dev,
18503 + struct device_attribute *attr, char *buf)
18505 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18507 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
18508 + return sprintf(buf, "** LPM is DISABLED **\n");
18510 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
18511 + return sprintf(buf, "** Current mode is not device mode\n");
18513 + return sprintf(buf, "lpm_response = %d\n",
18514 + dwc_otg_get_lpmresponse(otg_dev->core_if));
18518 +* Store the lpm_response attribute.
18520 +static ssize_t lpmresp_store(struct device *_dev,
18521 + struct device_attribute *attr,
18522 + const char *buf, size_t count)
18524 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18525 + uint32_t val = simple_strtoul(buf, NULL, 16);
18527 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
18531 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
18535 + dwc_otg_set_lpmresponse(otg_dev->core_if, val);
18539 +DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);
18542 +* Show the sleep_status attribute.
18544 +static ssize_t sleepstatus_show(struct device *_dev,
18545 + struct device_attribute *attr, char *buf)
18547 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18548 + return sprintf(buf, "Sleep Status = %d\n",
18549 + dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
18553 + * Store the sleep_status attribure.
18555 +static ssize_t sleepstatus_store(struct device *_dev,
18556 + struct device_attribute *attr,
18557 + const char *buf, size_t count)
18559 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18560 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
18562 + if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
18563 + if (dwc_otg_is_host_mode(core_if)) {
18565 + DWC_PRINTF("Host initiated resume\n");
18566 + dwc_otg_set_prtresume(otg_dev->core_if, 1);
18573 +DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
18574 + sleepstatus_store);
18576 +#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */
18581 + * Create the device files
18583 +void dwc_otg_attr_create(
18584 +#ifdef LM_INTERFACE
18585 + struct lm_device *dev
18586 +#elif defined(PCI_INTERFACE)
18587 + struct pci_dev *dev
18588 +#elif defined(PLATFORM_INTERFACE)
18589 + struct platform_device *dev
18595 + error = device_create_file(&dev->dev, &dev_attr_regoffset);
18596 + error = device_create_file(&dev->dev, &dev_attr_regvalue);
18597 + error = device_create_file(&dev->dev, &dev_attr_mode);
18598 + error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
18599 + error = device_create_file(&dev->dev, &dev_attr_srpcapable);
18600 + error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
18601 + error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
18602 + error = device_create_file(&dev->dev, &dev_attr_hnp);
18603 + error = device_create_file(&dev->dev, &dev_attr_srp);
18604 + error = device_create_file(&dev->dev, &dev_attr_buspower);
18605 + error = device_create_file(&dev->dev, &dev_attr_bussuspend);
18606 + error = device_create_file(&dev->dev, &dev_attr_mode_ch_tim_en);
18607 + error = device_create_file(&dev->dev, &dev_attr_fr_interval);
18608 + error = device_create_file(&dev->dev, &dev_attr_busconnected);
18609 + error = device_create_file(&dev->dev, &dev_attr_gotgctl);
18610 + error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
18611 + error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
18612 + error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
18613 + error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
18614 + error = device_create_file(&dev->dev, &dev_attr_ggpio);
18615 + error = device_create_file(&dev->dev, &dev_attr_guid);
18616 + error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
18617 + error = device_create_file(&dev->dev, &dev_attr_devspeed);
18618 + error = device_create_file(&dev->dev, &dev_attr_enumspeed);
18619 + error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
18620 + error = device_create_file(&dev->dev, &dev_attr_hprt0);
18621 + error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
18622 + error = device_create_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
18623 + error = device_create_file(&dev->dev, &dev_attr_disconnect_us);
18624 + error = device_create_file(&dev->dev, &dev_attr_regdump);
18625 + error = device_create_file(&dev->dev, &dev_attr_spramdump);
18626 + error = device_create_file(&dev->dev, &dev_attr_hcddump);
18627 + error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
18628 + error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
18629 + error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
18630 +#ifdef CONFIG_USB_DWC_OTG_LPM
18631 + error = device_create_file(&dev->dev, &dev_attr_lpm_response);
18632 + error = device_create_file(&dev->dev, &dev_attr_sleep_status);
18637 + * Remove the device files
18639 +void dwc_otg_attr_remove(
18640 +#ifdef LM_INTERFACE
18641 + struct lm_device *dev
18642 +#elif defined(PCI_INTERFACE)
18643 + struct pci_dev *dev
18644 +#elif defined(PLATFORM_INTERFACE)
18645 + struct platform_device *dev
18649 + device_remove_file(&dev->dev, &dev_attr_regoffset);
18650 + device_remove_file(&dev->dev, &dev_attr_regvalue);
18651 + device_remove_file(&dev->dev, &dev_attr_mode);
18652 + device_remove_file(&dev->dev, &dev_attr_hnpcapable);
18653 + device_remove_file(&dev->dev, &dev_attr_srpcapable);
18654 + device_remove_file(&dev->dev, &dev_attr_hsic_connect);
18655 + device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
18656 + device_remove_file(&dev->dev, &dev_attr_hnp);
18657 + device_remove_file(&dev->dev, &dev_attr_srp);
18658 + device_remove_file(&dev->dev, &dev_attr_buspower);
18659 + device_remove_file(&dev->dev, &dev_attr_bussuspend);
18660 + device_remove_file(&dev->dev, &dev_attr_mode_ch_tim_en);
18661 + device_remove_file(&dev->dev, &dev_attr_fr_interval);
18662 + device_remove_file(&dev->dev, &dev_attr_busconnected);
18663 + device_remove_file(&dev->dev, &dev_attr_gotgctl);
18664 + device_remove_file(&dev->dev, &dev_attr_gusbcfg);
18665 + device_remove_file(&dev->dev, &dev_attr_grxfsiz);
18666 + device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
18667 + device_remove_file(&dev->dev, &dev_attr_gpvndctl);
18668 + device_remove_file(&dev->dev, &dev_attr_ggpio);
18669 + device_remove_file(&dev->dev, &dev_attr_guid);
18670 + device_remove_file(&dev->dev, &dev_attr_gsnpsid);
18671 + device_remove_file(&dev->dev, &dev_attr_devspeed);
18672 + device_remove_file(&dev->dev, &dev_attr_enumspeed);
18673 + device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
18674 + device_remove_file(&dev->dev, &dev_attr_hprt0);
18675 + device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
18676 + device_remove_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
18677 + device_remove_file(&dev->dev, &dev_attr_disconnect_us);
18678 + device_remove_file(&dev->dev, &dev_attr_regdump);
18679 + device_remove_file(&dev->dev, &dev_attr_spramdump);
18680 + device_remove_file(&dev->dev, &dev_attr_hcddump);
18681 + device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
18682 + device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
18683 + device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
18684 +#ifdef CONFIG_USB_DWC_OTG_LPM
18685 + device_remove_file(&dev->dev, &dev_attr_lpm_response);
18686 + device_remove_file(&dev->dev, &dev_attr_sleep_status);
18690 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
18692 +/* ==========================================================================
18693 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
18694 + * $Revision: #13 $
18695 + * $Date: 2010/06/21 $
18696 + * $Change: 1532021 $
18698 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
18699 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
18700 + * otherwise expressly agreed to in writing between Synopsys and you.
18702 + * The Software IS NOT an item of Licensed Software or Licensed Product under
18703 + * any End User Software License Agreement or Agreement for Licensed Product
18704 + * with Synopsys or any supplement thereto. You are permitted to use and
18705 + * redistribute this Software in source and binary forms, with or without
18706 + * modification, provided that redistributions of source code must retain this
18707 + * notice. You may not view, use, disclose, copy or distribute this file or
18708 + * any information contained herein except pursuant to this license grant from
18709 + * Synopsys. If you do not agree with this notice, including the disclaimer
18710 + * below, then you are not authorized to use the Software.
18712 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
18713 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18714 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18715 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
18716 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18717 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18718 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18719 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18720 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18721 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
18723 + * ========================================================================== */
18725 +#if !defined(__DWC_OTG_ATTR_H__)
18726 +#define __DWC_OTG_ATTR_H__
18729 + * This file contains the interface to the Linux device attributes.
18731 +extern struct device_attribute dev_attr_regoffset;
18732 +extern struct device_attribute dev_attr_regvalue;
18734 +extern struct device_attribute dev_attr_mode;
18735 +extern struct device_attribute dev_attr_hnpcapable;
18736 +extern struct device_attribute dev_attr_srpcapable;
18737 +extern struct device_attribute dev_attr_hnp;
18738 +extern struct device_attribute dev_attr_srp;
18739 +extern struct device_attribute dev_attr_buspower;
18740 +extern struct device_attribute dev_attr_bussuspend;
18741 +extern struct device_attribute dev_attr_mode_ch_tim_en;
18742 +extern struct device_attribute dev_attr_fr_interval;
18743 +extern struct device_attribute dev_attr_busconnected;
18744 +extern struct device_attribute dev_attr_gotgctl;
18745 +extern struct device_attribute dev_attr_gusbcfg;
18746 +extern struct device_attribute dev_attr_grxfsiz;
18747 +extern struct device_attribute dev_attr_gnptxfsiz;
18748 +extern struct device_attribute dev_attr_gpvndctl;
18749 +extern struct device_attribute dev_attr_ggpio;
18750 +extern struct device_attribute dev_attr_guid;
18751 +extern struct device_attribute dev_attr_gsnpsid;
18752 +extern struct device_attribute dev_attr_devspeed;
18753 +extern struct device_attribute dev_attr_enumspeed;
18754 +extern struct device_attribute dev_attr_hptxfsiz;
18755 +extern struct device_attribute dev_attr_hprt0;
18756 +#ifdef CONFIG_USB_DWC_OTG_LPM
18757 +extern struct device_attribute dev_attr_lpm_response;
18758 +extern struct device_attribute devi_attr_sleep_status;
18761 +void dwc_otg_attr_create(
18762 +#ifdef LM_INTERFACE
18763 + struct lm_device *dev
18764 +#elif defined(PCI_INTERFACE)
18765 + struct pci_dev *dev
18766 +#elif defined(PLATFORM_INTERFACE)
18767 + struct platform_device *dev
18771 +void dwc_otg_attr_remove(
18772 +#ifdef LM_INTERFACE
18773 + struct lm_device *dev
18774 +#elif defined(PCI_INTERFACE)
18775 + struct pci_dev *dev
18776 +#elif defined(PLATFORM_INTERFACE)
18777 + struct platform_device *dev
18782 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.c
18784 +/* ==========================================================================
18785 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
18786 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
18787 + * otherwise expressly agreed to in writing between Synopsys and you.
18789 + * The Software IS NOT an item of Licensed Software or Licensed Product under
18790 + * any End User Software License Agreement or Agreement for Licensed Product
18791 + * with Synopsys or any supplement thereto. You are permitted to use and
18792 + * redistribute this Software in source and binary forms, with or without
18793 + * modification, provided that redistributions of source code must retain this
18794 + * notice. You may not view, use, disclose, copy or distribute this file or
18795 + * any information contained herein except pursuant to this license grant from
18796 + * Synopsys. If you do not agree with this notice, including the disclaimer
18797 + * below, then you are not authorized to use the Software.
18799 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
18800 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18801 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18802 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
18803 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18804 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18805 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18806 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18807 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18808 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
18810 + * ========================================================================== */
18814 + * This file contains the most of the CFI(Core Feature Interface)
18815 + * implementation for the OTG.
18818 +#ifdef DWC_UTE_CFI
18820 +#include "dwc_otg_pcd.h"
18821 +#include "dwc_otg_cfi.h"
18823 +/** This definition should actually migrate to the Portability Library */
18824 +#define DWC_CONSTANT_CPU_TO_LE16(x) (x)
18826 +extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex);
18828 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen);
18829 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
18830 + struct dwc_otg_pcd *pcd,
18831 + struct cfi_usb_ctrlrequest *ctrl_req);
18832 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd);
18833 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18834 + struct cfi_usb_ctrlrequest *req);
18835 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18836 + struct cfi_usb_ctrlrequest *req);
18837 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18838 + struct cfi_usb_ctrlrequest *req);
18839 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
18840 + struct cfi_usb_ctrlrequest *req);
18841 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep);
18843 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if);
18844 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue);
18845 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue);
18847 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if);
18849 +/** This is the header of the all features descriptor */
18850 +static cfi_all_features_header_t all_props_desc_header = {
18851 + .wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100),
18852 + .wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG),
18853 + .wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9),
18856 +/** This is an array of statically allocated feature descriptors */
18857 +static cfi_feature_desc_header_t prop_descs[] = {
18859 + /* FT_ID_DMA_MODE */
18861 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE),
18862 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18863 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1),
18866 + /* FT_ID_DMA_BUFFER_SETUP */
18868 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP),
18869 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18870 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18873 + /* FT_ID_DMA_BUFF_ALIGN */
18875 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN),
18876 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18877 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18880 + /* FT_ID_DMA_CONCAT_SETUP */
18882 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP),
18883 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18884 + //.wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18887 + /* FT_ID_DMA_CIRCULAR */
18889 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR),
18890 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18891 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18894 + /* FT_ID_THRESHOLD_SETUP */
18896 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP),
18897 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18898 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
18901 + /* FT_ID_DFIFO_DEPTH */
18903 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH),
18904 + .bmAttributes = CFI_FEATURE_ATTR_RO,
18905 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18908 + /* FT_ID_TX_FIFO_DEPTH */
18910 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH),
18911 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18912 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18915 + /* FT_ID_RX_FIFO_DEPTH */
18917 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH),
18918 + .bmAttributes = CFI_FEATURE_ATTR_RW,
18919 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
18923 +/** The table of feature names */
18924 +cfi_string_t prop_name_table[] = {
18925 + {FT_ID_DMA_MODE, "dma_mode"},
18926 + {FT_ID_DMA_BUFFER_SETUP, "buffer_setup"},
18927 + {FT_ID_DMA_BUFF_ALIGN, "buffer_align"},
18928 + {FT_ID_DMA_CONCAT_SETUP, "concat_setup"},
18929 + {FT_ID_DMA_CIRCULAR, "buffer_circular"},
18930 + {FT_ID_THRESHOLD_SETUP, "threshold_setup"},
18931 + {FT_ID_DFIFO_DEPTH, "dfifo_depth"},
18932 + {FT_ID_TX_FIFO_DEPTH, "txfifo_depth"},
18933 + {FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"},
18937 +/************************************************************************/
18940 + * Returns the name of the feature by its ID
18941 + * or NULL if no featute ID matches.
18944 +const uint8_t *get_prop_name(uint16_t prop_id, int *len)
18946 + cfi_string_t *pstr;
18949 + for (pstr = prop_name_table; pstr && pstr->s; pstr++) {
18950 + if (pstr->id == prop_id) {
18951 + *len = DWC_STRLEN(pstr->s);
18959 + * This function handles all CFI specific control requests.
18961 + * Return a negative value to stall the DCE.
18963 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)
18966 + dwc_otg_pcd_ep_t *ep = NULL;
18967 + cfiobject_t *cfi = pcd->cfi;
18968 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
18969 + uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength);
18970 + uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue);
18971 + uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex);
18972 + uint32_t regaddr = 0;
18973 + uint32_t regval = 0;
18975 + /* Save this Control Request in the CFI object.
18976 + * The data field will be assigned in the data stage completion CB function.
18978 + cfi->ctrl_req = *ctrl;
18979 + cfi->ctrl_req.data = NULL;
18981 + cfi->need_gadget_att = 0;
18982 + cfi->need_status_in_complete = 0;
18984 + switch (ctrl->bRequest) {
18985 + case VEN_CORE_GET_FEATURES:
18986 + retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN);
18987 + if (retval >= 0) {
18988 + //dump_msg(cfi->buf_in.buf, retval);
18991 + retval = min((uint16_t) retval, wLen);
18992 + /* Transfer this buffer to the host through the EP0-IN EP */
18993 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
18994 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
18995 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
18996 + ep->dwc_ep.xfer_len = retval;
18997 + ep->dwc_ep.xfer_count = 0;
18998 + ep->dwc_ep.sent_zlp = 0;
18999 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19001 + pcd->ep0_pending = 1;
19002 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19007 + case VEN_CORE_GET_FEATURE:
19008 + CFI_INFO("VEN_CORE_GET_FEATURE\n");
19009 + retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN,
19011 + if (retval >= 0) {
19014 + retval = min((uint16_t) retval, wLen);
19015 + /* Transfer this buffer to the host through the EP0-IN EP */
19016 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
19017 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
19018 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
19019 + ep->dwc_ep.xfer_len = retval;
19020 + ep->dwc_ep.xfer_count = 0;
19021 + ep->dwc_ep.sent_zlp = 0;
19022 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19024 + pcd->ep0_pending = 1;
19025 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19027 + CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval);
19028 + dump_msg(cfi->buf_in.buf, retval);
19031 + case VEN_CORE_SET_FEATURE:
19032 + CFI_INFO("VEN_CORE_SET_FEATURE\n");
19033 + /* Set up an XFER to get the data stage of the control request,
19034 + * which is the new value of the feature to be modified.
19037 + ep->dwc_ep.is_in = 0;
19038 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
19039 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
19040 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
19041 + ep->dwc_ep.xfer_len = wLen;
19042 + ep->dwc_ep.xfer_count = 0;
19043 + ep->dwc_ep.sent_zlp = 0;
19044 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19046 + pcd->ep0_pending = 1;
19047 + /* Read the control write's data stage */
19048 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19052 + case VEN_CORE_RESET_FEATURES:
19053 + CFI_INFO("VEN_CORE_RESET_FEATURES\n");
19054 + cfi->need_gadget_att = 1;
19055 + cfi->need_status_in_complete = 1;
19056 + retval = cfi_preproc_reset(pcd, ctrl);
19057 + CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval);
19060 + case VEN_CORE_ACTIVATE_FEATURES:
19061 + CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n");
19064 + case VEN_CORE_READ_REGISTER:
19065 + CFI_INFO("VEN_CORE_READ_REGISTER\n");
19066 + /* wValue optionally contains the HI WORD of the register offset and
19067 + * wIndex contains the LOW WORD of the register offset
19069 + if (wValue == 0) {
19070 + /* @TODO - MAS - fix the access to the base field */
19072 + //regaddr = (uint32_t) pcd->otg_dev->os_dep.base;
19073 + //GET_CORE_IF(pcd)->co
19074 + regaddr |= wIndex;
19076 + regaddr = (wValue << 16) | wIndex;
19079 + /* Read a 32-bit value of the memory at the regaddr */
19080 + regval = DWC_READ_REG32((uint32_t *) regaddr);
19083 + dwc_memcpy(cfi->buf_in.buf, ®val, sizeof(uint32_t));
19084 + ep->dwc_ep.is_in = 1;
19085 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
19086 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
19087 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
19088 + ep->dwc_ep.xfer_len = wLen;
19089 + ep->dwc_ep.xfer_count = 0;
19090 + ep->dwc_ep.sent_zlp = 0;
19091 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19093 + pcd->ep0_pending = 1;
19094 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19095 + cfi->need_gadget_att = 0;
19099 + case VEN_CORE_WRITE_REGISTER:
19100 + CFI_INFO("VEN_CORE_WRITE_REGISTER\n");
19101 + /* Set up an XFER to get the data stage of the control request,
19102 + * which is the new value of the register to be modified.
19105 + ep->dwc_ep.is_in = 0;
19106 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
19107 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
19108 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
19109 + ep->dwc_ep.xfer_len = wLen;
19110 + ep->dwc_ep.xfer_count = 0;
19111 + ep->dwc_ep.sent_zlp = 0;
19112 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19114 + pcd->ep0_pending = 1;
19115 + /* Read the control write's data stage */
19116 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19121 + retval = -DWC_E_NOT_SUPPORTED;
19129 + * This function prepares the core features descriptors and copies its
19130 + * raw representation into the buffer <buf>.
19132 + * The buffer structure is as follows:
19133 + * all_features_header (8 bytes)
19134 + * features_#1 (8 bytes + feature name string length)
19135 + * features_#2 (8 bytes + feature name string length)
19137 + * features_#n - where n=the total count of feature descriptors
19139 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen)
19141 + cfi_feature_desc_header_t *prop_hdr = prop_descs;
19142 + cfi_feature_desc_header_t *prop;
19143 + cfi_all_features_header_t *all_props_hdr = &all_props_desc_header;
19144 + cfi_all_features_header_t *tmp;
19145 + uint8_t *tmpbuf = buf;
19146 + const uint8_t *pname = NULL;
19147 + int i, j, namelen = 0, totlen;
19149 + /* Prepare and copy the core features into the buffer */
19150 + CFI_INFO("%s:\n", __func__);
19152 + tmp = (cfi_all_features_header_t *) tmpbuf;
19153 + *tmp = *all_props_hdr;
19154 + tmpbuf += CFI_ALL_FEATURES_HDR_LEN;
19156 + j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t);
19157 + for (i = 0; i < j; i++, prop_hdr++) {
19158 + pname = get_prop_name(prop_hdr->wFeatureID, &namelen);
19159 + prop = (cfi_feature_desc_header_t *) tmpbuf;
19160 + *prop = *prop_hdr;
19162 + prop->bNameLen = namelen;
19164 + DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN +
19167 + tmpbuf += CFI_FEATURE_DESC_HDR_LEN;
19168 + dwc_memcpy(tmpbuf, pname, namelen);
19169 + tmpbuf += namelen;
19172 + totlen = tmpbuf - buf;
19174 + if (totlen > 0) {
19175 + tmp = (cfi_all_features_header_t *) buf;
19176 + tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen);
19183 + * This function releases all the dynamic memory in the CFI object.
19185 +static void cfi_release(cfiobject_t * cfiobj)
19188 + dwc_list_link_t *tmp;
19190 + CFI_INFO("%s\n", __func__);
19192 + if (cfiobj->buf_in.buf) {
19193 + DWC_DMA_FREE(CFI_IN_BUF_LEN, cfiobj->buf_in.buf,
19194 + cfiobj->buf_in.addr);
19195 + cfiobj->buf_in.buf = NULL;
19198 + if (cfiobj->buf_out.buf) {
19199 + DWC_DMA_FREE(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf,
19200 + cfiobj->buf_out.addr);
19201 + cfiobj->buf_out.buf = NULL;
19204 + /* Free the Buffer Setup values for each EP */
19205 + //list_for_each_entry(cfiep, &cfiobj->active_eps, lh) {
19206 + DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) {
19207 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19208 + cfi_free_ep_bs_dyn_data(cfiep);
19213 + * This function frees the dynamically allocated EP buffer setup data.
19215 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep)
19217 + if (cfiep->bm_sg) {
19218 + DWC_FREE(cfiep->bm_sg);
19219 + cfiep->bm_sg = NULL;
19222 + if (cfiep->bm_align) {
19223 + DWC_FREE(cfiep->bm_align);
19224 + cfiep->bm_align = NULL;
19227 + if (cfiep->bm_concat) {
19228 + if (NULL != cfiep->bm_concat->wTxBytes) {
19229 + DWC_FREE(cfiep->bm_concat->wTxBytes);
19230 + cfiep->bm_concat->wTxBytes = NULL;
19232 + DWC_FREE(cfiep->bm_concat);
19233 + cfiep->bm_concat = NULL;
19238 + * This function initializes the default values of the features
19239 + * for a specific endpoint and should be called only once when
19240 + * the EP is enabled first time.
19242 +static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep)
19246 + cfiep->bm_sg = DWC_ALLOC(sizeof(ddma_sg_buffer_setup_t));
19247 + if (NULL == cfiep->bm_sg) {
19248 + CFI_INFO("Failed to allocate memory for SG feature value\n");
19249 + return -DWC_E_NO_MEMORY;
19251 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19253 + /* For the Concatenation feature's default value we do not allocate
19254 + * memory for the wTxBytes field - it will be done in the set_feature_value
19255 + * request handler.
19257 + cfiep->bm_concat = DWC_ALLOC(sizeof(ddma_concat_buffer_setup_t));
19258 + if (NULL == cfiep->bm_concat) {
19260 + ("Failed to allocate memory for CONCATENATION feature value\n");
19261 + DWC_FREE(cfiep->bm_sg);
19262 + return -DWC_E_NO_MEMORY;
19264 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
19266 + cfiep->bm_align = DWC_ALLOC(sizeof(ddma_align_buffer_setup_t));
19267 + if (NULL == cfiep->bm_align) {
19269 + ("Failed to allocate memory for Alignment feature value\n");
19270 + DWC_FREE(cfiep->bm_sg);
19271 + DWC_FREE(cfiep->bm_concat);
19272 + return -DWC_E_NO_MEMORY;
19274 + dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t));
19280 + * The callback function that notifies the CFI on the activation of
19281 + * an endpoint in the PCD. The following steps are done in this function:
19283 + * Create a dynamically allocated cfi_ep_t object (a CFI wrapper to the PCD's
19284 + * active endpoint)
19285 + * Create MAX_DMA_DESCS_PER_EP count DMA Descriptors for the EP
19286 + * Set the Buffer Mode to standard
19287 + * Initialize the default values for all EP modes (SG, Circular, Concat, Align)
19288 + * Add the cfi_ep_t object to the list of active endpoints in the CFI object
19290 +static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
19291 + struct dwc_otg_pcd_ep *ep)
19294 + int retval = -DWC_E_NOT_SUPPORTED;
19296 + CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__,
19297 + "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress);
19298 + /* MAS - Check whether this endpoint already is in the list */
19299 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
19301 + if (NULL == cfiep) {
19302 + /* Allocate a cfi_ep_t object */
19303 + cfiep = DWC_ALLOC(sizeof(cfi_ep_t));
19304 + if (NULL == cfiep) {
19306 + ("Unable to allocate memory for <cfiep> in function %s\n",
19308 + return -DWC_E_NO_MEMORY;
19310 + dwc_memset(cfiep, 0, sizeof(cfi_ep_t));
19312 + /* Save the dwc_otg_pcd_ep pointer in the cfiep object */
19315 + /* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */
19316 + ep->dwc_ep.descs =
19317 + DWC_DMA_ALLOC(MAX_DMA_DESCS_PER_EP *
19318 + sizeof(dwc_otg_dma_desc_t),
19319 + &ep->dwc_ep.descs_dma_addr);
19321 + if (NULL == ep->dwc_ep.descs) {
19323 + return -DWC_E_NO_MEMORY;
19326 + DWC_LIST_INIT(&cfiep->lh);
19328 + /* Set the buffer mode to BM_STANDARD. It will be modified
19329 + * when building descriptors for a specific buffer mode */
19330 + ep->dwc_ep.buff_mode = BM_STANDARD;
19332 + /* Create and initialize the default values for this EP's Buffer modes */
19333 + if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0)
19336 + /* Add the cfi_ep_t object to the CFI object's list of active endpoints */
19337 + DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh);
19339 + } else { /* The sought EP already is in the list */
19340 + CFI_INFO("%s: The sought EP already is in the list\n",
19348 + * This function is called when the data stage of a 3-stage Control Write request
19352 +static int cfi_ctrl_write_complete(struct cfiobject *cfi,
19353 + struct dwc_otg_pcd *pcd)
19355 + uint32_t addr, reg_value;
19356 + uint16_t wIndex, wValue;
19357 + uint8_t bRequest;
19358 + uint8_t *buf = cfi->buf_out.buf;
19359 + //struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved;
19360 + struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req;
19361 + int retval = -DWC_E_NOT_SUPPORTED;
19363 + CFI_INFO("%s\n", __func__);
19365 + bRequest = ctrl_req->bRequest;
19366 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
19367 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
19370 + * Save the pointer to the data stage in the ctrl_req's <data> field.
19371 + * The request should be already saved in the command stage by now.
19373 + ctrl_req->data = cfi->buf_out.buf;
19374 + cfi->need_status_in_complete = 0;
19375 + cfi->need_gadget_att = 0;
19377 + switch (bRequest) {
19378 + case VEN_CORE_WRITE_REGISTER:
19379 + /* The buffer contains raw data of the new value for the register */
19380 + reg_value = *((uint32_t *) buf);
19381 + if (wValue == 0) {
19383 + //addr = (uint32_t) pcd->otg_dev->os_dep.base;
19386 + addr = (wValue << 16) | wIndex;
19389 + //writel(reg_value, addr);
19392 + cfi->need_status_in_complete = 1;
19395 + case VEN_CORE_SET_FEATURE:
19396 + /* The buffer contains raw data of the new value of the feature */
19397 + retval = cfi_set_feature_value(pcd);
19401 + cfi->need_status_in_complete = 1;
19412 + * This function builds the DMA descriptors for the SG buffer mode.
19414 +static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19415 + dwc_otg_pcd_request_t * req)
19417 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19418 + ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg;
19419 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19420 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
19421 + dma_addr_t buff_addr = req->dma;
19423 + uint32_t txsize, off;
19425 + txsize = sgval->wSize;
19426 + off = sgval->bOffset;
19428 +// CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n",
19429 +// __func__, cfiep->ep->ep.name, txsize, off);
19431 + for (i = 0; i < sgval->bCount; i++) {
19432 + desc->status.b.bs = BS_HOST_BUSY;
19433 + desc->buf = buff_addr;
19434 + desc->status.b.l = 0;
19435 + desc->status.b.ioc = 0;
19436 + desc->status.b.sp = 0;
19437 + desc->status.b.bytes = txsize;
19438 + desc->status.b.bs = BS_HOST_READY;
19440 + /* Set the next address of the buffer */
19441 + buff_addr += txsize + off;
19442 + desc_last = desc;
19446 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
19447 + desc_last->status.b.l = 1;
19448 + desc_last->status.b.ioc = 1;
19449 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
19450 + /* Save the last DMA descriptor pointer */
19451 + cfiep->dma_desc_last = desc_last;
19452 + cfiep->desc_count = sgval->bCount;
19456 + * This function builds the DMA descriptors for the Concatenation buffer mode.
19458 +static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19459 + dwc_otg_pcd_request_t * req)
19461 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19462 + ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat;
19463 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19464 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
19465 + dma_addr_t buff_addr = req->dma;
19467 + uint16_t *txsize;
19469 + txsize = concatval->wTxBytes;
19471 + for (i = 0; i < concatval->hdr.bDescCount; i++) {
19472 + desc->buf = buff_addr;
19473 + desc->status.b.bs = BS_HOST_BUSY;
19474 + desc->status.b.l = 0;
19475 + desc->status.b.ioc = 0;
19476 + desc->status.b.sp = 0;
19477 + desc->status.b.bytes = *txsize;
19478 + desc->status.b.bs = BS_HOST_READY;
19481 + /* Set the next address of the buffer */
19482 + buff_addr += UGETW(ep->desc->wMaxPacketSize);
19483 + desc_last = desc;
19487 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
19488 + desc_last->status.b.l = 1;
19489 + desc_last->status.b.ioc = 1;
19490 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
19491 + cfiep->dma_desc_last = desc_last;
19492 + cfiep->desc_count = concatval->hdr.bDescCount;
19496 + * This function builds the DMA descriptors for the Circular buffer mode
19498 +static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19499 + dwc_otg_pcd_request_t * req)
19501 + /* @todo: MAS - add implementation when this feature needs to be tested */
19505 + * This function builds the DMA descriptors for the Alignment buffer mode
19507 +static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19508 + dwc_otg_pcd_request_t * req)
19510 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19511 + ddma_align_buffer_setup_t *alignval = cfiep->bm_align;
19512 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19513 + dma_addr_t buff_addr = req->dma;
19515 + desc->status.b.bs = BS_HOST_BUSY;
19516 + desc->status.b.l = 1;
19517 + desc->status.b.ioc = 1;
19518 + desc->status.b.sp = ep->dwc_ep.sent_zlp;
19519 + desc->status.b.bytes = req->length;
19520 + /* Adjust the buffer alignment */
19521 + desc->buf = (buff_addr + alignval->bAlign);
19522 + desc->status.b.bs = BS_HOST_READY;
19523 + cfiep->dma_desc_last = desc;
19524 + cfiep->desc_count = 1;
19528 + * This function builds the DMA descriptors chain for different modes of the
19529 + * buffer setup of an endpoint.
19531 +static void cfi_build_descriptors(struct cfiobject *cfi,
19532 + struct dwc_otg_pcd *pcd,
19533 + struct dwc_otg_pcd_ep *ep,
19534 + dwc_otg_pcd_request_t * req)
19538 + /* Get the cfiep by the dwc_otg_pcd_ep */
19539 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
19540 + if (NULL == cfiep) {
19541 + CFI_INFO("%s: Unable to find a matching active endpoint\n",
19546 + cfiep->xfer_len = req->length;
19548 + /* Iterate through all the DMA descriptors */
19549 + switch (cfiep->ep->dwc_ep.buff_mode) {
19551 + cfi_build_sg_descs(cfi, cfiep, req);
19555 + cfi_build_concat_descs(cfi, cfiep, req);
19558 + case BM_CIRCULAR:
19559 + cfi_build_circ_descs(cfi, cfiep, req);
19563 + cfi_build_align_descs(cfi, cfiep, req);
19572 + * Allocate DMA buffer for different Buffer modes.
19574 +static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
19575 + struct dwc_otg_pcd_ep *ep, dma_addr_t * dma,
19576 + unsigned size, gfp_t flags)
19578 + return DWC_DMA_ALLOC(size, dma);
19582 + * This function initializes the CFI object.
19584 +int init_cfi(cfiobject_t * cfiobj)
19586 + CFI_INFO("%s\n", __func__);
19588 + /* Allocate a buffer for IN XFERs */
19589 + cfiobj->buf_in.buf =
19590 + DWC_DMA_ALLOC(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr);
19591 + if (NULL == cfiobj->buf_in.buf) {
19592 + CFI_INFO("Unable to allocate buffer for INs\n");
19593 + return -DWC_E_NO_MEMORY;
19596 + /* Allocate a buffer for OUT XFERs */
19597 + cfiobj->buf_out.buf =
19598 + DWC_DMA_ALLOC(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr);
19599 + if (NULL == cfiobj->buf_out.buf) {
19600 + CFI_INFO("Unable to allocate buffer for OUT\n");
19601 + return -DWC_E_NO_MEMORY;
19604 + /* Initialize the callback function pointers */
19605 + cfiobj->ops.release = cfi_release;
19606 + cfiobj->ops.ep_enable = cfi_ep_enable;
19607 + cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete;
19608 + cfiobj->ops.build_descriptors = cfi_build_descriptors;
19609 + cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf;
19611 + /* Initialize the list of active endpoints in the CFI object */
19612 + DWC_LIST_INIT(&cfiobj->active_eps);
19618 + * This function reads the required feature's current value into the buffer
19620 + * @retval: Returns negative as error, or the data length of the feature
19622 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
19623 + struct dwc_otg_pcd *pcd,
19624 + struct cfi_usb_ctrlrequest *ctrl_req)
19626 + int retval = -DWC_E_NOT_SUPPORTED;
19627 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
19628 + uint16_t dfifo, rxfifo, txfifo;
19630 + switch (ctrl_req->wIndex) {
19631 + /* Whether the DDMA is enabled or not */
19632 + case FT_ID_DMA_MODE:
19633 + *buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0;
19637 + case FT_ID_DMA_BUFFER_SETUP:
19638 + retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req);
19641 + case FT_ID_DMA_BUFF_ALIGN:
19642 + retval = cfi_ep_get_align_val(buf, pcd, ctrl_req);
19645 + case FT_ID_DMA_CONCAT_SETUP:
19646 + retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req);
19649 + case FT_ID_DMA_CIRCULAR:
19650 + CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n");
19653 + case FT_ID_THRESHOLD_SETUP:
19654 + CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n");
19657 + case FT_ID_DFIFO_DEPTH:
19658 + dfifo = get_dfifo_size(coreif);
19659 + *((uint16_t *) buf) = dfifo;
19660 + retval = sizeof(uint16_t);
19663 + case FT_ID_TX_FIFO_DEPTH:
19664 + retval = get_txfifo_size(pcd, ctrl_req->wValue);
19665 + if (retval >= 0) {
19667 + *((uint16_t *) buf) = txfifo;
19668 + retval = sizeof(uint16_t);
19672 + case FT_ID_RX_FIFO_DEPTH:
19673 + retval = get_rxfifo_size(coreif, ctrl_req->wValue);
19674 + if (retval >= 0) {
19676 + *((uint16_t *) buf) = rxfifo;
19677 + retval = sizeof(uint16_t);
19686 + * This function resets the SG for the specified EP to its default value
19688 +static int cfi_reset_sg_val(cfi_ep_t * cfiep)
19690 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19695 + * This function resets the Alignment for the specified EP to its default value
19697 +static int cfi_reset_align_val(cfi_ep_t * cfiep)
19699 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19704 + * This function resets the Concatenation for the specified EP to its default value
19705 + * This function will also set the value of the wTxBytes field to NULL after
19706 + * freeing the memory previously allocated for this field.
19708 +static int cfi_reset_concat_val(cfi_ep_t * cfiep)
19710 + /* First we need to free the wTxBytes field */
19711 + if (cfiep->bm_concat->wTxBytes) {
19712 + DWC_FREE(cfiep->bm_concat->wTxBytes);
19713 + cfiep->bm_concat->wTxBytes = NULL;
19716 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
19721 + * This function resets all the buffer setups of the specified endpoint
19723 +static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep)
19725 + cfi_reset_sg_val(cfiep);
19726 + cfi_reset_align_val(cfiep);
19727 + cfi_reset_concat_val(cfiep);
19731 +static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr,
19732 + uint8_t rx_rst, uint8_t tx_rst)
19734 + int retval = -DWC_E_INVALID;
19735 + uint16_t tx_siz[15];
19736 + uint16_t rx_siz = 0;
19737 + dwc_otg_pcd_ep_t *ep = NULL;
19738 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
19739 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
19742 + rx_siz = params->dev_rx_fifo_size;
19743 + params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz;
19747 + if (ep_addr == 0) {
19750 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
19752 + core_if->core_params->dev_tx_fifo_size[i];
19753 + core_if->core_params->dev_tx_fifo_size[i] =
19754 + core_if->init_txfsiz[i];
19758 + ep = get_ep_by_addr(pcd, ep_addr);
19760 + if (NULL == ep) {
19762 + ("%s: Unable to get the endpoint addr=0x%02x\n",
19763 + __func__, ep_addr);
19764 + return -DWC_E_INVALID;
19768 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num -
19770 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] =
19771 + GET_CORE_IF(pcd)->init_txfsiz[ep->
19772 + dwc_ep.tx_fifo_num -
19777 + if (resize_fifos(GET_CORE_IF(pcd))) {
19781 + ("%s: Error resetting the feature Reset All(FIFO size)\n",
19784 + params->dev_rx_fifo_size = rx_siz;
19788 + if (ep_addr == 0) {
19790 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps;
19793 + core_params->dev_tx_fifo_size[i] =
19797 + params->dev_tx_fifo_size[ep->
19798 + dwc_ep.tx_fifo_num -
19802 + retval = -DWC_E_INVALID;
19807 +static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr)
19811 + cfiobject_t *cfi = pcd->cfi;
19812 + dwc_list_link_t *tmp;
19814 + retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1);
19815 + if (retval < 0) {
19819 + /* If the EP address is known then reset the features for only that EP */
19821 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19822 + if (NULL == cfiep) {
19823 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19825 + return -DWC_E_INVALID;
19827 + retval = cfi_ep_reset_all_setup_vals(cfiep);
19828 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
19830 + /* Otherwise (wValue == 0), reset all features of all EP's */
19832 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19833 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19834 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19835 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19836 + retval = cfi_ep_reset_all_setup_vals(cfiep);
19837 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
19838 + if (retval < 0) {
19840 + ("%s: Error resetting the feature Reset All\n",
19849 +static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd,
19854 + cfiobject_t *cfi = pcd->cfi;
19855 + dwc_list_link_t *tmp;
19857 + /* If the EP address is known then reset the features for only that EP */
19859 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19860 + if (NULL == cfiep) {
19861 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19863 + return -DWC_E_INVALID;
19865 + retval = cfi_reset_sg_val(cfiep);
19867 + /* Otherwise (wValue == 0), reset all features of all EP's */
19869 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19870 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19871 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19872 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19873 + retval = cfi_reset_sg_val(cfiep);
19874 + if (retval < 0) {
19876 + ("%s: Error resetting the feature Buffer Setup\n",
19885 +static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr)
19889 + cfiobject_t *cfi = pcd->cfi;
19890 + dwc_list_link_t *tmp;
19892 + /* If the EP address is known then reset the features for only that EP */
19894 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19895 + if (NULL == cfiep) {
19896 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19898 + return -DWC_E_INVALID;
19900 + retval = cfi_reset_concat_val(cfiep);
19902 + /* Otherwise (wValue == 0), reset all features of all EP's */
19904 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19905 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19906 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19907 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19908 + retval = cfi_reset_concat_val(cfiep);
19909 + if (retval < 0) {
19911 + ("%s: Error resetting the feature Concatenation Value\n",
19920 +static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr)
19924 + cfiobject_t *cfi = pcd->cfi;
19925 + dwc_list_link_t *tmp;
19927 + /* If the EP address is known then reset the features for only that EP */
19929 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19930 + if (NULL == cfiep) {
19931 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19933 + return -DWC_E_INVALID;
19935 + retval = cfi_reset_align_val(cfiep);
19937 + /* Otherwise (wValue == 0), reset all features of all EP's */
19939 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19940 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19941 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19942 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19943 + retval = cfi_reset_align_val(cfiep);
19944 + if (retval < 0) {
19946 + ("%s: Error resetting the feature Aliignment Value\n",
19956 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
19957 + struct cfi_usb_ctrlrequest *req)
19961 + switch (req->wIndex) {
19963 + /* Reset all features */
19964 + retval = cfi_handle_reset_all(pcd, req->wValue & 0xff);
19967 + case FT_ID_DMA_BUFFER_SETUP:
19968 + /* Reset the SG buffer setup */
19970 + cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff);
19973 + case FT_ID_DMA_CONCAT_SETUP:
19974 + /* Reset the Concatenation buffer setup */
19975 + retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff);
19978 + case FT_ID_DMA_BUFF_ALIGN:
19979 + /* Reset the Alignment buffer setup */
19980 + retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff);
19983 + case FT_ID_TX_FIFO_DEPTH:
19985 + cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1);
19986 + pcd->cfi->need_gadget_att = 0;
19989 + case FT_ID_RX_FIFO_DEPTH:
19990 + retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0);
19991 + pcd->cfi->need_gadget_att = 0;
20000 + * This function sets a new value for the SG buffer setup.
20002 +static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20004 + uint8_t inaddr, outaddr;
20005 + cfi_ep_t *epin, *epout;
20006 + ddma_sg_buffer_setup_t *psgval;
20007 + uint32_t desccount, size;
20009 + CFI_INFO("%s\n", __func__);
20011 + psgval = (ddma_sg_buffer_setup_t *) buf;
20012 + desccount = (uint32_t) psgval->bCount;
20013 + size = (uint32_t) psgval->wSize;
20015 + /* Check the DMA descriptor count */
20016 + if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) {
20018 + ("%s: The count of DMA Descriptors should be between 1 and %d\n",
20019 + __func__, MAX_DMA_DESCS_PER_EP);
20020 + return -DWC_E_INVALID;
20023 + /* Check the DMA descriptor count */
20027 + CFI_INFO("%s: The transfer size should be at least 1 byte\n",
20030 + return -DWC_E_INVALID;
20034 + inaddr = psgval->bInEndpointAddress;
20035 + outaddr = psgval->bOutEndpointAddress;
20037 + epin = get_cfi_ep_by_addr(pcd->cfi, inaddr);
20038 + epout = get_cfi_ep_by_addr(pcd->cfi, outaddr);
20040 + if (NULL == epin || NULL == epout) {
20042 + ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n",
20043 + __func__, inaddr, outaddr);
20044 + return -DWC_E_INVALID;
20047 + epin->ep->dwc_ep.buff_mode = BM_SG;
20048 + dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
20050 + epout->ep->dwc_ep.buff_mode = BM_SG;
20051 + dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
20057 + * This function sets a new value for the buffer Alignment setup.
20059 +static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20063 + ddma_align_buffer_setup_t *palignval;
20065 + palignval = (ddma_align_buffer_setup_t *) buf;
20066 + addr = palignval->bEndpointAddress;
20068 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20070 + if (NULL == ep) {
20071 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20073 + return -DWC_E_INVALID;
20076 + ep->ep->dwc_ep.buff_mode = BM_ALIGN;
20077 + dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t));
20083 + * This function sets a new value for the Concatenation buffer setup.
20085 +static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20089 + struct _ddma_concat_buffer_setup_hdr *pConcatValHdr;
20091 + uint32_t desccount;
20095 + pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf;
20096 + desccount = (uint32_t) pConcatValHdr->bDescCount;
20097 + pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN);
20099 + /* Check the DMA descriptor count */
20100 + if (desccount > MAX_DMA_DESCS_PER_EP) {
20101 + CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n",
20102 + __func__, MAX_DMA_DESCS_PER_EP);
20103 + return -DWC_E_INVALID;
20106 + addr = pConcatValHdr->bEndpointAddress;
20107 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20108 + if (NULL == ep) {
20109 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20111 + return -DWC_E_INVALID;
20114 + mps = UGETW(ep->ep->desc->wMaxPacketSize);
20117 + for (i = 0; i < desccount; i++) {
20118 + CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]);
20120 + CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps);
20123 + /* Check the wTxSizes to be less than or equal to the mps */
20124 + for (i = 0; i < desccount; i++) {
20125 + if (pVals[i] > mps) {
20127 + ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n",
20128 + __func__, i, pVals[i]);
20129 + return -DWC_E_INVALID;
20133 + ep->ep->dwc_ep.buff_mode = BM_CONCAT;
20134 + dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN);
20136 + /* Free the previously allocated storage for the wTxBytes */
20137 + if (ep->bm_concat->wTxBytes) {
20138 + DWC_FREE(ep->bm_concat->wTxBytes);
20141 + /* Allocate a new storage for the wTxBytes field */
20142 + ep->bm_concat->wTxBytes =
20143 + DWC_ALLOC(sizeof(uint16_t) * pConcatValHdr->bDescCount);
20144 + if (NULL == ep->bm_concat->wTxBytes) {
20145 + CFI_INFO("%s: Unable to allocate memory\n", __func__);
20146 + return -DWC_E_NO_MEMORY;
20149 + /* Copy the new values into the wTxBytes filed */
20150 + dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN,
20151 + sizeof(uint16_t) * pConcatValHdr->bDescCount);
20157 + * This function calculates the total of all FIFO sizes
20159 + * @param core_if Programming view of DWC_otg controller
20161 + * @return The total of data FIFO sizes.
20164 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if)
20166 + dwc_otg_core_params_t *params = core_if->core_params;
20167 + uint16_t dfifo_total = 0;
20170 + /* The shared RxFIFO size */
20172 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
20174 + /* Add up each TxFIFO size to the total */
20175 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20176 + dfifo_total += params->dev_tx_fifo_size[i];
20179 + return dfifo_total;
20183 + * This function returns Rx FIFO size
20185 + * @param core_if Programming view of DWC_otg controller
20187 + * @return The total of data FIFO sizes.
20190 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue)
20192 + switch (wValue >> 8) {
20194 + return (core_if->pwron_rxfsiz <
20195 + 32768) ? core_if->pwron_rxfsiz : 32768;
20198 + return core_if->core_params->dev_rx_fifo_size;
20201 + return -DWC_E_INVALID;
20207 + * This function returns Tx FIFO size for IN EP
20209 + * @param core_if Programming view of DWC_otg controller
20211 + * @return The total of data FIFO sizes.
20214 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue)
20216 + dwc_otg_pcd_ep_t *ep;
20218 + ep = get_ep_by_addr(pcd, wValue & 0xff);
20220 + if (NULL == ep) {
20221 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20222 + __func__, wValue & 0xff);
20223 + return -DWC_E_INVALID;
20226 + if (!ep->dwc_ep.is_in) {
20228 + ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n",
20229 + __func__, wValue & 0xff);
20230 + return -DWC_E_INVALID;
20233 + switch (wValue >> 8) {
20235 + return (GET_CORE_IF(pcd)->pwron_txfsiz
20236 + [ep->dwc_ep.tx_fifo_num - 1] <
20237 + 768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->
20238 + dwc_ep.tx_fifo_num
20242 + return GET_CORE_IF(pcd)->core_params->
20243 + dev_tx_fifo_size[ep->dwc_ep.num - 1];
20246 + return -DWC_E_INVALID;
20252 + * This function checks if the submitted combination of
20253 + * device mode FIFO sizes is possible or not.
20255 + * @param core_if Programming view of DWC_otg controller
20257 + * @return 1 if possible, 0 otherwise.
20260 +static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if)
20262 + uint16_t dfifo_actual = 0;
20263 + dwc_otg_core_params_t *params = core_if->core_params;
20264 + uint16_t start_addr = 0;
20268 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
20270 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20271 + dfifo_actual += params->dev_tx_fifo_size[i];
20274 + if (dfifo_actual > core_if->total_fifo_size) {
20278 + if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16)
20281 + if (params->dev_nperio_tx_fifo_size > 32768
20282 + || params->dev_nperio_tx_fifo_size < 16)
20285 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20287 + if (params->dev_tx_fifo_size[i] > 768
20288 + || params->dev_tx_fifo_size[i] < 4)
20292 + if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz)
20294 + start_addr = params->dev_rx_fifo_size;
20296 + if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz)
20298 + start_addr += params->dev_nperio_tx_fifo_size;
20300 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20302 + if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i])
20304 + start_addr += params->dev_tx_fifo_size[i];
20311 + * This function resizes Device mode FIFOs
20313 + * @param core_if Programming view of DWC_otg controller
20315 + * @return 1 if successful, 0 otherwise
20318 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if)
20321 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
20322 + dwc_otg_core_params_t *params = core_if->core_params;
20323 + uint32_t rx_fifo_size;
20324 + fifosize_data_t nptxfifosize;
20325 + fifosize_data_t txfifosize[15];
20327 + uint32_t rx_fsz_bak;
20328 + uint32_t nptxfsz_bak;
20329 + uint32_t txfsz_bak[15];
20331 + uint16_t start_address;
20332 + uint8_t retval = 1;
20334 + if (!check_fifo_sizes(core_if)) {
20338 + /* Configure data FIFO sizes */
20339 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
20340 + rx_fsz_bak = DWC_READ_REG32(&global_regs->grxfsiz);
20341 + rx_fifo_size = params->dev_rx_fifo_size;
20342 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
20345 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
20346 + * Indexes of the FIFO size module parameters in the
20347 + * dev_tx_fifo_size array and the FIFO size registers in
20348 + * the dtxfsiz array run from 0 to 14.
20351 + /* Non-periodic Tx FIFO */
20352 + nptxfsz_bak = DWC_READ_REG32(&global_regs->gnptxfsiz);
20353 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
20354 + start_address = params->dev_rx_fifo_size;
20355 + nptxfifosize.b.startaddr = start_address;
20357 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
20359 + start_address += nptxfifosize.b.depth;
20361 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20362 + txfsz_bak[i] = DWC_READ_REG32(&global_regs->dtxfsiz[i]);
20364 + txfifosize[i].b.depth = params->dev_tx_fifo_size[i];
20365 + txfifosize[i].b.startaddr = start_address;
20366 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
20367 + txfifosize[i].d32);
20369 + start_address += txfifosize[i].b.depth;
20372 + /** Check if register values are set correctly */
20373 + if (rx_fifo_size != DWC_READ_REG32(&global_regs->grxfsiz)) {
20377 + if (nptxfifosize.d32 != DWC_READ_REG32(&global_regs->gnptxfsiz)) {
20381 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20382 + if (txfifosize[i].d32 !=
20383 + DWC_READ_REG32(&global_regs->dtxfsiz[i])) {
20388 + /** If register values are not set correctly, reset old values */
20389 + if (retval == 0) {
20390 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fsz_bak);
20392 + /* Non-periodic Tx FIFO */
20393 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfsz_bak);
20395 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20396 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
20404 + /* Flush the FIFOs */
20405 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
20406 + dwc_otg_flush_rx_fifo(core_if);
20412 + * This function sets a new value for the buffer Alignment setup.
20414 +static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
20419 + uint16_t ep_addr;
20420 + dwc_otg_pcd_ep_t *ep;
20421 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
20422 + tx_fifo_size_setup_t *ptxfifoval;
20424 + ptxfifoval = (tx_fifo_size_setup_t *) buf;
20425 + ep_addr = ptxfifoval->bEndpointAddress;
20426 + size = ptxfifoval->wDepth;
20428 + ep = get_ep_by_addr(pcd, ep_addr);
20431 + ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n",
20432 + __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num);
20434 + if (NULL == ep) {
20435 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20436 + __func__, ep_addr);
20437 + return -DWC_E_INVALID;
20440 + fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1];
20441 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size;
20443 + if (resize_fifos(GET_CORE_IF(pcd))) {
20447 + ("%s: Error setting the feature Tx FIFO Size for EP%d\n",
20448 + __func__, ep_addr);
20449 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz;
20450 + retval = -DWC_E_INVALID;
20457 + * This function sets a new value for the buffer Alignment setup.
20459 +static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
20464 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
20465 + rx_fifo_size_setup_t *prxfifoval;
20467 + prxfifoval = (rx_fifo_size_setup_t *) buf;
20468 + size = prxfifoval->wDepth;
20470 + fsiz = params->dev_rx_fifo_size;
20471 + params->dev_rx_fifo_size = size;
20473 + if (resize_fifos(GET_CORE_IF(pcd))) {
20476 + CFI_INFO("%s: Error setting the feature Rx FIFO Size\n",
20478 + params->dev_rx_fifo_size = fsiz;
20479 + retval = -DWC_E_INVALID;
20486 + * This function reads the SG of an EP's buffer setup into the buffer buf
20488 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20489 + struct cfi_usb_ctrlrequest *req)
20491 + int retval = -DWC_E_INVALID;
20495 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20496 + addr = req->wValue & 0xFF;
20497 + if (addr == 0) /* The address should be non-zero */
20500 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20501 + if (NULL == ep) {
20502 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20507 + dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN);
20508 + retval = BS_SG_VAL_DESC_LEN;
20513 + * This function reads the Concatenation value of an EP's buffer mode into
20516 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20517 + struct cfi_usb_ctrlrequest *req)
20519 + int retval = -DWC_E_INVALID;
20522 + uint8_t desc_count;
20524 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20525 + addr = req->wValue & 0xFF;
20526 + if (addr == 0) /* The address should be non-zero */
20529 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20530 + if (NULL == ep) {
20531 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20536 + /* Copy the header to the buffer */
20537 + dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN);
20538 + /* Advance the buffer pointer by the header size */
20539 + buf += BS_CONCAT_VAL_HDR_LEN;
20541 + desc_count = ep->bm_concat->hdr.bDescCount;
20542 + /* Copy alll the wTxBytes to the buffer */
20543 + dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count);
20545 + retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count;
20550 + * This function reads the buffer Alignment value of an EP's buffer mode into
20553 + * @return The total number of bytes copied to the buffer or negative error code.
20555 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20556 + struct cfi_usb_ctrlrequest *req)
20558 + int retval = -DWC_E_INVALID;
20562 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20563 + addr = req->wValue & 0xFF;
20564 + if (addr == 0) /* The address should be non-zero */
20567 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20568 + if (NULL == ep) {
20569 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20574 + dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN);
20575 + retval = BS_ALIGN_VAL_HDR_LEN;
20581 + * This function sets a new value for the specified feature
20583 + * @param pcd A pointer to the PCD object
20585 + * @return 0 if successful, negative error code otherwise to stall the DCE.
20587 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd)
20589 + int retval = -DWC_E_NOT_SUPPORTED;
20590 + uint16_t wIndex, wValue;
20591 + uint8_t bRequest;
20592 + struct dwc_otg_core_if *coreif;
20593 + cfiobject_t *cfi = pcd->cfi;
20594 + struct cfi_usb_ctrlrequest *ctrl_req;
20596 + ctrl_req = &cfi->ctrl_req;
20598 + buf = pcd->cfi->ctrl_req.data;
20600 + coreif = GET_CORE_IF(pcd);
20601 + bRequest = ctrl_req->bRequest;
20602 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
20603 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
20605 + /* See which feature is to be modified */
20606 + switch (wIndex) {
20607 + case FT_ID_DMA_BUFFER_SETUP:
20608 + /* Modify the feature */
20609 + if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0)
20612 + /* And send this request to the gadget */
20613 + cfi->need_gadget_att = 1;
20616 + case FT_ID_DMA_BUFF_ALIGN:
20617 + if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0)
20619 + cfi->need_gadget_att = 1;
20622 + case FT_ID_DMA_CONCAT_SETUP:
20623 + /* Modify the feature */
20624 + if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0)
20626 + cfi->need_gadget_att = 1;
20629 + case FT_ID_DMA_CIRCULAR:
20630 + CFI_INFO("FT_ID_DMA_CIRCULAR\n");
20633 + case FT_ID_THRESHOLD_SETUP:
20634 + CFI_INFO("FT_ID_THRESHOLD_SETUP\n");
20637 + case FT_ID_DFIFO_DEPTH:
20638 + CFI_INFO("FT_ID_DFIFO_DEPTH\n");
20641 + case FT_ID_TX_FIFO_DEPTH:
20642 + CFI_INFO("FT_ID_TX_FIFO_DEPTH\n");
20643 + if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0)
20645 + cfi->need_gadget_att = 0;
20648 + case FT_ID_RX_FIFO_DEPTH:
20649 + CFI_INFO("FT_ID_RX_FIFO_DEPTH\n");
20650 + if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0)
20652 + cfi->need_gadget_att = 0;
20659 +#endif //DWC_UTE_CFI
20661 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h
20663 +/* ==========================================================================
20664 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
20665 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
20666 + * otherwise expressly agreed to in writing between Synopsys and you.
20668 + * The Software IS NOT an item of Licensed Software or Licensed Product under
20669 + * any End User Software License Agreement or Agreement for Licensed Product
20670 + * with Synopsys or any supplement thereto. You are permitted to use and
20671 + * redistribute this Software in source and binary forms, with or without
20672 + * modification, provided that redistributions of source code must retain this
20673 + * notice. You may not view, use, disclose, copy or distribute this file or
20674 + * any information contained herein except pursuant to this license grant from
20675 + * Synopsys. If you do not agree with this notice, including the disclaimer
20676 + * below, then you are not authorized to use the Software.
20678 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
20679 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20680 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20681 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
20682 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20683 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20684 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20685 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20686 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20687 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
20689 + * ========================================================================== */
20691 +#if !defined(__DWC_OTG_CFI_H__)
20692 +#define __DWC_OTG_CFI_H__
20694 +#include "dwc_otg_pcd.h"
20695 +#include "dwc_cfi_common.h"
20699 + * This file contains the CFI related OTG PCD specific common constants,
20700 + * interfaces(functions and macros) and data structures.The CFI Protocol is an
20701 + * optional interface for internal testing purposes that a DUT may implement to
20702 + * support testing of configurable features.
20706 +struct dwc_otg_pcd;
20707 +struct dwc_otg_pcd_ep;
20709 +/** OTG CFI Features (properties) ID constants */
20710 +/** This is a request for all Core Features */
20711 +#define FT_ID_DMA_MODE 0x0001
20712 +#define FT_ID_DMA_BUFFER_SETUP 0x0002
20713 +#define FT_ID_DMA_BUFF_ALIGN 0x0003
20714 +#define FT_ID_DMA_CONCAT_SETUP 0x0004
20715 +#define FT_ID_DMA_CIRCULAR 0x0005
20716 +#define FT_ID_THRESHOLD_SETUP 0x0006
20717 +#define FT_ID_DFIFO_DEPTH 0x0007
20718 +#define FT_ID_TX_FIFO_DEPTH 0x0008
20719 +#define FT_ID_RX_FIFO_DEPTH 0x0009
20721 +/**********************************************************/
20722 +#define CFI_INFO_DEF
20724 +#ifdef CFI_INFO_DEF
20725 +#define CFI_INFO(fmt...) DWC_PRINTF("CFI: " fmt);
20727 +#define CFI_INFO(fmt...)
20730 +#define min(x,y) ({ \
20731 + x < y ? x : y; })
20733 +#define max(x,y) ({ \
20734 + x > y ? x : y; })
20737 + * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is
20738 + * also used for setting up a buffer for Circular DDMA.
20740 +struct _ddma_sg_buffer_setup {
20741 +#define BS_SG_VAL_DESC_LEN 6
20742 + /* The OUT EP address */
20743 + uint8_t bOutEndpointAddress;
20744 + /* The IN EP address */
20745 + uint8_t bInEndpointAddress;
20746 + /* Number of bytes to put between transfer segments (must be DWORD boundaries) */
20748 + /* The number of transfer segments (a DMA descriptors per each segment) */
20750 + /* Size (in byte) of each transfer segment */
20752 +} __attribute__ ((packed));
20753 +typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
20755 +/** Descriptor DMA Concatenation Buffer setup structure */
20756 +struct _ddma_concat_buffer_setup_hdr {
20757 +#define BS_CONCAT_VAL_HDR_LEN 4
20758 + /* The endpoint for which the buffer is to be set up */
20759 + uint8_t bEndpointAddress;
20760 + /* The count of descriptors to be used */
20761 + uint8_t bDescCount;
20762 + /* The total size of the transfer */
20764 +} __attribute__ ((packed));
20765 +typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
20767 +/** Descriptor DMA Concatenation Buffer setup structure */
20768 +struct _ddma_concat_buffer_setup {
20769 + /* The SG header */
20770 + ddma_concat_buffer_setup_hdr_t hdr;
20772 + /* The XFER sizes pointer (allocated dynamically) */
20773 + uint16_t *wTxBytes;
20774 +} __attribute__ ((packed));
20775 +typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
20777 +/** Descriptor DMA Alignment Buffer setup structure */
20778 +struct _ddma_align_buffer_setup {
20779 +#define BS_ALIGN_VAL_HDR_LEN 2
20780 + uint8_t bEndpointAddress;
20782 +} __attribute__ ((packed));
20783 +typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
20785 +/** Transmit FIFO Size setup structure */
20786 +struct _tx_fifo_size_setup {
20787 + uint8_t bEndpointAddress;
20789 +} __attribute__ ((packed));
20790 +typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
20792 +/** Transmit FIFO Size setup structure */
20793 +struct _rx_fifo_size_setup {
20795 +} __attribute__ ((packed));
20796 +typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
20799 + * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest
20800 + * This structure encapsulates the standard usb_ctrlrequest and adds a pointer
20801 + * to the data returned in the data stage of a 3-stage Control Write requests.
20803 +struct cfi_usb_ctrlrequest {
20804 + uint8_t bRequestType;
20805 + uint8_t bRequest;
20808 + uint16_t wLength;
20812 +/*---------------------------------------------------------------------------*/
20815 + * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures.
20816 + * This structure is used to store the buffer setup data for any
20817 + * enabled endpoint in the PCD.
20820 + /* Entry for the list container */
20821 + dwc_list_link_t lh;
20822 + /* Pointer to the active PCD endpoint structure */
20823 + struct dwc_otg_pcd_ep *ep;
20824 + /* The last descriptor in the chain of DMA descriptors of the endpoint */
20825 + struct dwc_otg_dma_desc *dma_desc_last;
20826 + /* The SG feature value */
20827 + ddma_sg_buffer_setup_t *bm_sg;
20828 + /* The Circular feature value */
20829 + ddma_sg_buffer_setup_t *bm_circ;
20830 + /* The Concatenation feature value */
20831 + ddma_concat_buffer_setup_t *bm_concat;
20832 + /* The Alignment feature value */
20833 + ddma_align_buffer_setup_t *bm_align;
20834 + /* XFER length */
20835 + uint32_t xfer_len;
20837 + * Count of DMA descriptors currently used.
20838 + * The total should not exceed the MAX_DMA_DESCS_PER_EP value
20839 + * defined in the dwc_otg_cil.h
20841 + uint32_t desc_count;
20843 +typedef struct cfi_ep cfi_ep_t;
20845 +typedef struct cfi_dma_buff {
20846 +#define CFI_IN_BUF_LEN 1024
20847 +#define CFI_OUT_BUF_LEN 1024
20855 + * This is the interface for the CFI operations.
20857 + * @param ep_enable Called when any endpoint is enabled and activated.
20858 + * @param release Called when the CFI object is released and it needs to correctly
20859 + * deallocate the dynamic memory
20860 + * @param ctrl_write_complete Called when the data stage of the request is complete
20862 +typedef struct cfi_ops {
20863 + int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
20864 + struct dwc_otg_pcd_ep * ep);
20865 + void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
20866 + struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
20867 + unsigned size, gfp_t flags);
20868 + void (*release) (struct cfiobject * cfi);
20869 + int (*ctrl_write_complete) (struct cfiobject * cfi,
20870 + struct dwc_otg_pcd * pcd);
20871 + void (*build_descriptors) (struct cfiobject * cfi,
20872 + struct dwc_otg_pcd * pcd,
20873 + struct dwc_otg_pcd_ep * ep,
20874 + dwc_otg_pcd_request_t * req);
20877 +struct cfiobject {
20879 + struct dwc_otg_pcd *pcd;
20880 + struct usb_gadget *gadget;
20882 + /* Buffers used to send/receive CFI-related request data */
20883 + cfi_dma_buff_t buf_in;
20884 + cfi_dma_buff_t buf_out;
20886 + /* CFI specific Control request wrapper */
20887 + struct cfi_usb_ctrlrequest ctrl_req;
20889 + /* The list of active EP's in the PCD of type cfi_ep_t */
20890 + dwc_list_link_t active_eps;
20892 + /* This flag shall control the propagation of a specific request
20893 + * to the gadget's processing routines.
20894 + * 0 - no gadget handling
20895 + * 1 - the gadget needs to know about this request (w/o completing a status
20896 + * phase - just return a 0 to the _setup callback)
20898 + uint8_t need_gadget_att;
20900 + /* Flag indicating whether the status IN phase needs to be
20901 + * completed by the PCD
20903 + uint8_t need_status_in_complete;
20905 +typedef struct cfiobject cfiobject_t;
20909 +#if defined(DUMP_MSG)
20910 +static inline void dump_msg(const u8 * buf, unsigned int length)
20912 + unsigned int start, num, i;
20913 + char line[52], *p;
20915 + if (length >= 512)
20919 + while (length > 0) {
20920 + num = min(length, 16u);
20922 + for (i = 0; i < num; ++i) {
20925 + DWC_SPRINTF(p, " %02x", buf[i]);
20929 + DWC_DEBUG("%6x: %s\n", start, line);
20936 +static inline void dump_msg(const u8 * buf, unsigned int length)
20942 + * This function returns a pointer to cfi_ep_t object with the addr address.
20944 +static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
20947 + struct cfi_ep *pcfiep;
20948 + dwc_list_link_t *tmp;
20950 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
20951 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
20953 + if (pcfiep->ep->desc->bEndpointAddress == addr) {
20962 + * This function returns a pointer to cfi_ep_t object that matches
20963 + * the dwc_otg_pcd_ep object.
20965 +static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
20966 + struct dwc_otg_pcd_ep *ep)
20968 + struct cfi_ep *pcfiep = NULL;
20969 + dwc_list_link_t *tmp;
20971 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
20972 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
20973 + if (pcfiep->ep == ep) {
20980 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
20982 +#endif /* (__DWC_OTG_CFI_H__) */
20984 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
20986 +/* ==========================================================================
20987 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $
20988 + * $Revision: #191 $
20989 + * $Date: 2012/08/10 $
20990 + * $Change: 2047372 $
20992 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
20993 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
20994 + * otherwise expressly agreed to in writing between Synopsys and you.
20996 + * The Software IS NOT an item of Licensed Software or Licensed Product under
20997 + * any End User Software License Agreement or Agreement for Licensed Product
20998 + * with Synopsys or any supplement thereto. You are permitted to use and
20999 + * redistribute this Software in source and binary forms, with or without
21000 + * modification, provided that redistributions of source code must retain this
21001 + * notice. You may not view, use, disclose, copy or distribute this file or
21002 + * any information contained herein except pursuant to this license grant from
21003 + * Synopsys. If you do not agree with this notice, including the disclaimer
21004 + * below, then you are not authorized to use the Software.
21006 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
21007 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21008 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21009 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
21010 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21011 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21012 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21013 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21014 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21015 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
21017 + * ========================================================================== */
21021 + * The Core Interface Layer provides basic services for accessing and
21022 + * managing the DWC_otg hardware. These services are used by both the
21023 + * Host Controller Driver and the Peripheral Controller Driver.
21025 + * The CIL manages the memory map for the core so that the HCD and PCD
21026 + * don't have to do this separately. It also handles basic tasks like
21027 + * reading/writing the registers and data FIFOs in the controller.
21028 + * Some of the data access functions provide encapsulation of several
21029 + * operations required to perform a task, such as writing multiple
21030 + * registers to start a transfer. Finally, the CIL performs basic
21031 + * services that are not specific to either the host or device modes
21032 + * of operation. These services include management of the OTG Host
21033 + * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
21034 + * Diagnostic API is also provided to allow testing of the controller
21037 + * The Core Interface Layer has the following requirements:
21038 + * - Provides basic controller operations.
21039 + * - Minimal use of OS services.
21040 + * - The OS services used will be abstracted by using inline functions
21045 +#include "dwc_os.h"
21046 +#include "dwc_otg_regs.h"
21047 +#include "dwc_otg_cil.h"
21049 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if);
21052 + * This function is called to initialize the DWC_otg CSR data
21053 + * structures. The register addresses in the device and host
21054 + * structures are initialized from the base address supplied by the
21055 + * caller. The calling function must make the OS calls to get the
21056 + * base address of the DWC_otg controller registers. The core_params
21057 + * argument holds the parameters that specify how the core should be
21060 + * @param reg_base_addr Base address of DWC_otg core registers
21063 +dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr)
21065 + dwc_otg_core_if_t *core_if = 0;
21066 + dwc_otg_dev_if_t *dev_if = 0;
21067 + dwc_otg_host_if_t *host_if = 0;
21068 + uint8_t *reg_base = (uint8_t *) reg_base_addr;
21071 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr);
21073 + core_if = DWC_ALLOC(sizeof(dwc_otg_core_if_t));
21075 + if (core_if == NULL) {
21076 + DWC_DEBUGPL(DBG_CIL,
21077 + "Allocation of dwc_otg_core_if_t failed\n");
21080 + core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base;
21083 + * Allocate the Device Mode structures.
21085 + dev_if = DWC_ALLOC(sizeof(dwc_otg_dev_if_t));
21087 + if (dev_if == NULL) {
21088 + DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
21089 + DWC_FREE(core_if);
21093 + dev_if->dev_global_regs =
21094 + (dwc_otg_device_global_regs_t *) (reg_base +
21095 + DWC_DEV_GLOBAL_REG_OFFSET);
21097 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21098 + dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
21099 + (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
21100 + (i * DWC_EP_REG_OFFSET));
21102 + dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
21103 + (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
21104 + (i * DWC_EP_REG_OFFSET));
21105 + DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
21106 + i, &dev_if->in_ep_regs[i]->diepctl);
21107 + DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
21108 + i, &dev_if->out_ep_regs[i]->doepctl);
21111 + dev_if->speed = 0; // unknown
21113 + core_if->dev_if = dev_if;
21116 + * Allocate the Host Mode structures.
21118 + host_if = DWC_ALLOC(sizeof(dwc_otg_host_if_t));
21120 + if (host_if == NULL) {
21121 + DWC_DEBUGPL(DBG_CIL,
21122 + "Allocation of dwc_otg_host_if_t failed\n");
21123 + DWC_FREE(dev_if);
21124 + DWC_FREE(core_if);
21128 + host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
21129 + (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
21132 + (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
21134 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21135 + host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
21136 + (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
21137 + (i * DWC_OTG_CHAN_REGS_OFFSET));
21138 + DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
21139 + i, &host_if->hc_regs[i]->hcchar);
21142 + host_if->num_host_channels = MAX_EPS_CHANNELS;
21143 + core_if->host_if = host_if;
21145 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21146 + core_if->data_fifo[i] =
21147 + (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
21148 + (i * DWC_OTG_DATA_FIFO_SIZE));
21149 + DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08lx\n",
21150 + i, (unsigned long)core_if->data_fifo[i]);
21153 + core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
21155 + /* Initiate lx_state to L3 disconnected state */
21156 + core_if->lx_state = DWC_OTG_L3;
21158 + * Store the contents of the hardware configuration registers here for
21159 + * easy access later.
21161 + core_if->hwcfg1.d32 =
21162 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg1);
21163 + core_if->hwcfg2.d32 =
21164 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
21165 + core_if->hwcfg3.d32 =
21166 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg3);
21167 + core_if->hwcfg4.d32 =
21168 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
21170 + /* Force host mode to get HPTXFSIZ exact power on value */
21172 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
21173 + gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21174 + gusbcfg.b.force_host_mode = 1;
21175 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
21177 + core_if->hptxfsiz.d32 =
21178 + DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
21179 + gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21180 + gusbcfg.b.force_host_mode = 0;
21181 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
21185 + DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
21186 + DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
21187 + DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
21188 + DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
21190 + core_if->hcfg.d32 =
21191 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
21192 + core_if->dcfg.d32 =
21193 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
21195 + DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32);
21196 + DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32);
21198 + DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
21199 + DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
21200 + DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
21201 + DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
21202 + core_if->hwcfg2.b.num_host_chan);
21203 + DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
21204 + core_if->hwcfg2.b.nonperio_tx_q_depth);
21205 + DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
21206 + core_if->hwcfg2.b.host_perio_tx_q_depth);
21207 + DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
21208 + core_if->hwcfg2.b.dev_token_q_depth);
21210 + DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
21211 + core_if->hwcfg3.b.dfifo_depth);
21212 + DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
21213 + core_if->hwcfg3.b.xfer_size_cntr_width);
21216 + * Set the SRP sucess bit for FS-I2c
21218 + core_if->srp_success = 0;
21219 + core_if->srp_timer_started = 0;
21222 + * Create new workqueue and init works
21224 + core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg");
21225 + if (core_if->wq_otg == 0) {
21226 + DWC_WARN("DWC_WORKQ_ALLOC failed\n");
21227 + DWC_FREE(host_if);
21228 + DWC_FREE(dev_if);
21229 + DWC_FREE(core_if);
21233 + core_if->snpsid = DWC_READ_REG32(&core_if->core_global_regs->gsnpsid);
21235 + DWC_PRINTF("Core Release: %x.%x%x%x\n",
21236 + (core_if->snpsid >> 12 & 0xF),
21237 + (core_if->snpsid >> 8 & 0xF),
21238 + (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF));
21240 + core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer",
21241 + w_wakeup_detected, core_if);
21242 + if (core_if->wkp_timer == 0) {
21243 + DWC_WARN("DWC_TIMER_ALLOC failed\n");
21244 + DWC_FREE(host_if);
21245 + DWC_FREE(dev_if);
21246 + DWC_WORKQ_FREE(core_if->wq_otg);
21247 + DWC_FREE(core_if);
21251 + if (dwc_otg_setup_params(core_if)) {
21252 + DWC_WARN("Error while setting core params\n");
21255 + core_if->hibernation_suspend = 0;
21257 + /** ADP initialization */
21258 + dwc_otg_adp_init(core_if);
21264 + * This function frees the structures allocated by dwc_otg_cil_init().
21266 + * @param core_if The core interface pointer returned from
21267 + * dwc_otg_cil_init().
21270 +void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if)
21272 + dctl_data_t dctl = {.d32 = 0 };
21273 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
21275 + /* Disable all interrupts */
21276 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 1, 0);
21277 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
21279 + dctl.b.sftdiscon = 1;
21280 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
21281 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0,
21285 + if (core_if->wq_otg) {
21286 + DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500);
21287 + DWC_WORKQ_FREE(core_if->wq_otg);
21289 + if (core_if->dev_if) {
21290 + DWC_FREE(core_if->dev_if);
21292 + if (core_if->host_if) {
21293 + DWC_FREE(core_if->host_if);
21296 + /** Remove ADP Stuff */
21297 + dwc_otg_adp_remove(core_if);
21298 + if (core_if->core_params) {
21299 + DWC_FREE(core_if->core_params);
21301 + if (core_if->wkp_timer) {
21302 + DWC_TIMER_FREE(core_if->wkp_timer);
21304 + if (core_if->srp_timer) {
21305 + DWC_TIMER_FREE(core_if->srp_timer);
21307 + DWC_FREE(core_if);
21311 + * This function enables the controller's Global Interrupt in the AHB Config
21314 + * @param core_if Programming view of DWC_otg controller.
21316 +void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if)
21318 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
21319 + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */
21320 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
21324 + * This function disables the controller's Global Interrupt in the AHB Config
21327 + * @param core_if Programming view of DWC_otg controller.
21329 +void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if)
21331 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
21332 + ahbcfg.b.glblintrmsk = 1; /* Disable interrupts */
21333 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
21337 + * This function initializes the commmon interrupts, used in both
21338 + * device and host modes.
21340 + * @param core_if Programming view of the DWC_otg controller
21343 +static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if)
21345 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
21346 + gintmsk_data_t intr_mask = {.d32 = 0 };
21348 + /* Clear any pending OTG Interrupts */
21349 + DWC_WRITE_REG32(&global_regs->gotgint, 0xFFFFFFFF);
21351 + /* Clear any pending interrupts */
21352 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
21355 + * Enable the interrupts in the GINTMSK.
21357 + intr_mask.b.modemismatch = 1;
21358 + intr_mask.b.otgintr = 1;
21360 + if (!core_if->dma_enable) {
21361 + intr_mask.b.rxstsqlvl = 1;
21364 + intr_mask.b.conidstschng = 1;
21365 + intr_mask.b.wkupintr = 1;
21366 + intr_mask.b.disconnect = 0;
21367 + intr_mask.b.usbsuspend = 1;
21368 + intr_mask.b.sessreqintr = 1;
21369 +#ifdef CONFIG_USB_DWC_OTG_LPM
21370 + if (core_if->core_params->lpm_enable) {
21371 + intr_mask.b.lpmtranrcvd = 1;
21374 + DWC_WRITE_REG32(&global_regs->gintmsk, intr_mask.d32);
21378 + * The restore operation is modified to support Synopsys Emulated Powerdown and
21379 + * Hibernation. This function is for exiting from Device mode hibernation by
21380 + * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
21381 + * @param core_if Programming view of DWC_otg controller.
21382 + * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
21383 + * @param reset - indicates whether resume is initiated by Reset.
21385 +int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
21386 + int rem_wakeup, int reset)
21388 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
21389 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
21390 + dctl_data_t dctl = {.d32 = 0 };
21392 + int timeout = 2000;
21394 + if (!core_if->hibernation_suspend) {
21395 + DWC_PRINTF("Already exited from Hibernation\n");
21399 + DWC_DEBUGPL(DBG_PCD, "%s called\n", __FUNCTION__);
21400 + /* Switch-on voltage to the core */
21401 + gpwrdn.b.pwrdnswtch = 1;
21402 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21407 + gpwrdn.b.pwrdnrstn = 1;
21408 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21411 + /* Assert Restore signal */
21413 + gpwrdn.b.restore = 1;
21414 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21417 + /* Disable power clamps */
21419 + gpwrdn.b.pwrdnclmp = 1;
21420 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21422 + if (rem_wakeup) {
21426 + /* Deassert Reset core */
21428 + gpwrdn.b.pwrdnrstn = 1;
21429 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21432 + /* Disable PMU interrupt */
21434 + gpwrdn.b.pmuintsel = 1;
21435 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21437 + /* Mask interrupts from gpwrdn */
21439 + gpwrdn.b.connect_det_msk = 1;
21440 + gpwrdn.b.srp_det_msk = 1;
21441 + gpwrdn.b.disconn_det_msk = 1;
21442 + gpwrdn.b.rst_det_msk = 1;
21443 + gpwrdn.b.lnstchng_msk = 1;
21444 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21446 + /* Indicates that we are going out from hibernation */
21447 + core_if->hibernation_suspend = 0;
21450 + * Set Restore Essential Regs bit in PCGCCTL register, restore_mode = 1
21451 + * indicates restore from remote_wakeup
21453 + restore_essential_regs(core_if, rem_wakeup, 0);
21456 + * Wait a little for seeing new value of variable hibernation_suspend if
21457 + * Restore done interrupt received before polling
21461 + if (core_if->hibernation_suspend == 0) {
21463 + * Wait For Restore_done Interrupt. This mechanism of polling the
21464 + * interrupt is introduced to avoid any possible race conditions
21467 + gintsts_data_t gintsts;
21469 + DWC_READ_REG32(&core_if->core_global_regs->gintsts);
21470 + if (gintsts.b.restoredone) {
21472 + gintsts.b.restoredone = 1;
21473 + DWC_WRITE_REG32(&core_if->core_global_regs->
21474 + gintsts, gintsts.d32);
21475 + DWC_PRINTF("Restore Done Interrupt seen\n");
21479 + } while (--timeout);
21481 + DWC_PRINTF("Restore Done interrupt wasn't generated here\n");
21484 + /* Clear all pending interupts */
21485 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21487 + /* De-assert Restore */
21489 + gpwrdn.b.restore = 1;
21490 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21493 + if (!rem_wakeup) {
21495 + pcgcctl.b.rstpdwnmodule = 1;
21496 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
21499 + /* Restore GUSBCFG and DCFG */
21500 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
21501 + core_if->gr_backup->gusbcfg_local);
21502 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
21503 + core_if->dr_backup->dcfg);
21505 + /* De-assert Wakeup Logic */
21507 + gpwrdn.b.pmuactv = 1;
21508 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21511 + if (!rem_wakeup) {
21512 + /* Set Device programming done bit */
21513 + dctl.b.pwronprgdone = 1;
21514 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
21516 + /* Start Remote Wakeup Signaling */
21517 + dctl.d32 = core_if->dr_backup->dctl;
21518 + dctl.b.rmtwkupsig = 1;
21519 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
21523 + /* Clear all pending interupts */
21524 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21526 + /* Restore global registers */
21527 + dwc_otg_restore_global_regs(core_if);
21528 + /* Restore device global registers */
21529 + dwc_otg_restore_dev_regs(core_if, rem_wakeup);
21531 + if (rem_wakeup) {
21534 + dctl.b.rmtwkupsig = 1;
21535 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
21538 + core_if->hibernation_suspend = 0;
21539 + /* The core will be in ON STATE */
21540 + core_if->lx_state = DWC_OTG_L0;
21541 + DWC_PRINTF("Hibernation recovery completes here\n");
21547 + * The restore operation is modified to support Synopsys Emulated Powerdown and
21548 + * Hibernation. This function is for exiting from Host mode hibernation by
21549 + * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
21550 + * @param core_if Programming view of DWC_otg controller.
21551 + * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
21552 + * @param reset - indicates whether resume is initiated by Reset.
21554 +int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
21555 + int rem_wakeup, int reset)
21557 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
21558 + hprt0_data_t hprt0 = {.d32 = 0 };
21560 + int timeout = 2000;
21562 + DWC_DEBUGPL(DBG_HCD, "%s called\n", __FUNCTION__);
21563 + /* Switch-on voltage to the core */
21564 + gpwrdn.b.pwrdnswtch = 1;
21565 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21570 + gpwrdn.b.pwrdnrstn = 1;
21571 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21574 + /* Assert Restore signal */
21576 + gpwrdn.b.restore = 1;
21577 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21580 + /* Disable power clamps */
21582 + gpwrdn.b.pwrdnclmp = 1;
21583 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21585 + if (!rem_wakeup) {
21589 + /* Deassert Reset core */
21591 + gpwrdn.b.pwrdnrstn = 1;
21592 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21595 + /* Disable PMU interrupt */
21597 + gpwrdn.b.pmuintsel = 1;
21598 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21601 + gpwrdn.b.connect_det_msk = 1;
21602 + gpwrdn.b.srp_det_msk = 1;
21603 + gpwrdn.b.disconn_det_msk = 1;
21604 + gpwrdn.b.rst_det_msk = 1;
21605 + gpwrdn.b.lnstchng_msk = 1;
21606 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21608 + /* Indicates that we are going out from hibernation */
21609 + core_if->hibernation_suspend = 0;
21611 + /* Set Restore Essential Regs bit in PCGCCTL register */
21612 + restore_essential_regs(core_if, rem_wakeup, 1);
21614 + /* Wait a little for seeing new value of variable hibernation_suspend if
21615 + * Restore done interrupt received before polling */
21618 + if (core_if->hibernation_suspend == 0) {
21619 + /* Wait For Restore_done Interrupt. This mechanism of polling the
21620 + * interrupt is introduced to avoid any possible race conditions
21623 + gintsts_data_t gintsts;
21624 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
21625 + if (gintsts.b.restoredone) {
21627 + gintsts.b.restoredone = 1;
21628 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
21629 + DWC_DEBUGPL(DBG_HCD,"Restore Done Interrupt seen\n");
21633 + } while (--timeout);
21635 + DWC_WARN("Restore Done interrupt wasn't generated\n");
21639 + /* Set the flag's value to 0 again after receiving restore done interrupt */
21640 + core_if->hibernation_suspend = 0;
21642 + /* This step is not described in functional spec but if not wait for this
21643 + * delay, mismatch interrupts occurred because just after restore core is
21644 + * in Device mode(gintsts.curmode == 0) */
21647 + /* Clear all pending interrupts */
21648 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21650 + /* De-assert Restore */
21652 + gpwrdn.b.restore = 1;
21653 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21656 + /* Restore GUSBCFG and HCFG */
21657 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
21658 + core_if->gr_backup->gusbcfg_local);
21659 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
21660 + core_if->hr_backup->hcfg_local);
21662 + /* De-assert Wakeup Logic */
21664 + gpwrdn.b.pmuactv = 1;
21665 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21668 + /* Start the Resume operation by programming HPRT0 */
21669 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21670 + hprt0.b.prtpwr = 1;
21671 + hprt0.b.prtena = 0;
21672 + hprt0.b.prtsusp = 0;
21673 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21675 + DWC_PRINTF("Resume Starts Now\n");
21676 + if (!reset) { // Indicates it is Resume Operation
21677 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21678 + hprt0.b.prtres = 1;
21679 + hprt0.b.prtpwr = 1;
21680 + hprt0.b.prtena = 0;
21681 + hprt0.b.prtsusp = 0;
21682 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21685 + hprt0.b.prtres = 0;
21686 + /* Wait for Resume time and then program HPRT again */
21688 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21690 + } else { // Indicates it is Reset Operation
21691 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21692 + hprt0.b.prtrst = 1;
21693 + hprt0.b.prtpwr = 1;
21694 + hprt0.b.prtena = 0;
21695 + hprt0.b.prtsusp = 0;
21696 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21697 + /* Wait for Reset time and then program HPRT again */
21699 + hprt0.b.prtrst = 0;
21700 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21702 + /* Clear all interrupt status */
21703 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
21704 + hprt0.b.prtconndet = 1;
21705 + hprt0.b.prtenchng = 1;
21706 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21708 + /* Clear all pending interupts */
21709 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21711 + /* Restore global registers */
21712 + dwc_otg_restore_global_regs(core_if);
21713 + /* Restore host global registers */
21714 + dwc_otg_restore_host_regs(core_if, reset);
21716 + /* The core will be in ON STATE */
21717 + core_if->lx_state = DWC_OTG_L0;
21718 + DWC_PRINTF("Hibernation recovery is complete here\n");
21722 +/** Saves some register values into system memory. */
21723 +int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if)
21725 + struct dwc_otg_global_regs_backup *gr;
21728 + gr = core_if->gr_backup;
21730 + gr = DWC_ALLOC(sizeof(*gr));
21732 + return -DWC_E_NO_MEMORY;
21734 + core_if->gr_backup = gr;
21737 + gr->gotgctl_local = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
21738 + gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
21739 + gr->gahbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
21740 + gr->gusbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21741 + gr->grxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
21742 + gr->gnptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
21743 + gr->hptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
21744 +#ifdef CONFIG_USB_DWC_OTG_LPM
21745 + gr->glpmcfg_local = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
21747 + gr->gi2cctl_local = DWC_READ_REG32(&core_if->core_global_regs->gi2cctl);
21748 + gr->pcgcctl_local = DWC_READ_REG32(core_if->pcgcctl);
21749 + gr->gdfifocfg_local =
21750 + DWC_READ_REG32(&core_if->core_global_regs->gdfifocfg);
21751 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21752 + gr->dtxfsiz_local[i] =
21753 + DWC_READ_REG32(&(core_if->core_global_regs->dtxfsiz[i]));
21756 + DWC_DEBUGPL(DBG_ANY, "===========Backing Global registers==========\n");
21757 + DWC_DEBUGPL(DBG_ANY, "Backed up gotgctl = %08x\n", gr->gotgctl_local);
21758 + DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
21759 + DWC_DEBUGPL(DBG_ANY, "Backed up gahbcfg = %08x\n", gr->gahbcfg_local);
21760 + DWC_DEBUGPL(DBG_ANY, "Backed up gusbcfg = %08x\n", gr->gusbcfg_local);
21761 + DWC_DEBUGPL(DBG_ANY, "Backed up grxfsiz = %08x\n", gr->grxfsiz_local);
21762 + DWC_DEBUGPL(DBG_ANY, "Backed up gnptxfsiz = %08x\n",
21763 + gr->gnptxfsiz_local);
21764 + DWC_DEBUGPL(DBG_ANY, "Backed up hptxfsiz = %08x\n",
21765 + gr->hptxfsiz_local);
21766 +#ifdef CONFIG_USB_DWC_OTG_LPM
21767 + DWC_DEBUGPL(DBG_ANY, "Backed up glpmcfg = %08x\n", gr->glpmcfg_local);
21769 + DWC_DEBUGPL(DBG_ANY, "Backed up gi2cctl = %08x\n", gr->gi2cctl_local);
21770 + DWC_DEBUGPL(DBG_ANY, "Backed up pcgcctl = %08x\n", gr->pcgcctl_local);
21771 + DWC_DEBUGPL(DBG_ANY,"Backed up gdfifocfg = %08x\n",gr->gdfifocfg_local);
21776 +/** Saves GINTMSK register before setting the msk bits. */
21777 +int dwc_otg_save_gintmsk_reg(dwc_otg_core_if_t * core_if)
21779 + struct dwc_otg_global_regs_backup *gr;
21781 + gr = core_if->gr_backup;
21783 + gr = DWC_ALLOC(sizeof(*gr));
21785 + return -DWC_E_NO_MEMORY;
21787 + core_if->gr_backup = gr;
21790 + gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
21792 + DWC_DEBUGPL(DBG_ANY,"=============Backing GINTMSK registers============\n");
21793 + DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
21798 +int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if)
21800 + struct dwc_otg_dev_regs_backup *dr;
21803 + dr = core_if->dr_backup;
21805 + dr = DWC_ALLOC(sizeof(*dr));
21807 + return -DWC_E_NO_MEMORY;
21809 + core_if->dr_backup = dr;
21812 + dr->dcfg = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
21813 + dr->dctl = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
21815 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
21817 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->diepmsk);
21819 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->doepmsk);
21821 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21823 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
21824 + dr->dieptsiz[i] =
21825 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz);
21827 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma);
21830 + DWC_DEBUGPL(DBG_ANY,
21831 + "=============Backing Host registers==============\n");
21832 + DWC_DEBUGPL(DBG_ANY, "Backed up dcfg = %08x\n", dr->dcfg);
21833 + DWC_DEBUGPL(DBG_ANY, "Backed up dctl = %08x\n", dr->dctl);
21834 + DWC_DEBUGPL(DBG_ANY, "Backed up daintmsk = %08x\n",
21836 + DWC_DEBUGPL(DBG_ANY, "Backed up diepmsk = %08x\n", dr->diepmsk);
21837 + DWC_DEBUGPL(DBG_ANY, "Backed up doepmsk = %08x\n", dr->doepmsk);
21838 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21839 + DWC_DEBUGPL(DBG_ANY, "Backed up diepctl[%d] = %08x\n", i,
21841 + DWC_DEBUGPL(DBG_ANY, "Backed up dieptsiz[%d] = %08x\n",
21842 + i, dr->dieptsiz[i]);
21843 + DWC_DEBUGPL(DBG_ANY, "Backed up diepdma[%d] = %08x\n", i,
21850 +int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if)
21852 + struct dwc_otg_host_regs_backup *hr;
21855 + hr = core_if->hr_backup;
21857 + hr = DWC_ALLOC(sizeof(*hr));
21859 + return -DWC_E_NO_MEMORY;
21861 + core_if->hr_backup = hr;
21865 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
21866 + hr->haintmsk_local =
21867 + DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
21868 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
21869 + hr->hcintmsk_local[i] =
21870 + DWC_READ_REG32(&core_if->host_if->hc_regs[i]->hcintmsk);
21872 + hr->hprt0_local = DWC_READ_REG32(core_if->host_if->hprt0);
21874 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
21876 + DWC_DEBUGPL(DBG_ANY,
21877 + "=============Backing Host registers===============\n");
21878 + DWC_DEBUGPL(DBG_ANY, "Backed up hcfg = %08x\n",
21880 + DWC_DEBUGPL(DBG_ANY, "Backed up haintmsk = %08x\n", hr->haintmsk_local);
21881 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
21882 + DWC_DEBUGPL(DBG_ANY, "Backed up hcintmsk[%02d]=%08x\n", i,
21883 + hr->hcintmsk_local[i]);
21885 + DWC_DEBUGPL(DBG_ANY, "Backed up hprt0 = %08x\n",
21886 + hr->hprt0_local);
21887 + DWC_DEBUGPL(DBG_ANY, "Backed up hfir = %08x\n",
21893 +int dwc_otg_restore_global_regs(dwc_otg_core_if_t *core_if)
21895 + struct dwc_otg_global_regs_backup *gr;
21898 + gr = core_if->gr_backup;
21900 + return -DWC_E_INVALID;
21903 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, gr->gotgctl_local);
21904 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gr->gintmsk_local);
21905 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gr->gusbcfg_local);
21906 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gr->gahbcfg_local);
21907 + DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, gr->grxfsiz_local);
21908 + DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz,
21909 + gr->gnptxfsiz_local);
21910 + DWC_WRITE_REG32(&core_if->core_global_regs->hptxfsiz,
21911 + gr->hptxfsiz_local);
21912 + DWC_WRITE_REG32(&core_if->core_global_regs->gdfifocfg,
21913 + gr->gdfifocfg_local);
21914 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21915 + DWC_WRITE_REG32(&core_if->core_global_regs->dtxfsiz[i],
21916 + gr->dtxfsiz_local[i]);
21919 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21920 + DWC_WRITE_REG32(core_if->host_if->hprt0, 0x0000100A);
21921 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg,
21922 + (gr->gahbcfg_local));
21926 +int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if, int rem_wakeup)
21928 + struct dwc_otg_dev_regs_backup *dr;
21931 + dr = core_if->dr_backup;
21934 + return -DWC_E_INVALID;
21937 + if (!rem_wakeup) {
21938 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
21942 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, dr->daintmsk);
21943 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, dr->diepmsk);
21944 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, dr->doepmsk);
21946 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21947 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz, dr->dieptsiz[i]);
21948 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma, dr->diepdma[i]);
21949 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl, dr->diepctl[i]);
21955 +int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset)
21957 + struct dwc_otg_host_regs_backup *hr;
21959 + hr = core_if->hr_backup;
21962 + return -DWC_E_INVALID;
21965 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hr->hcfg_local);
21968 + // DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hr->hfir_local);
21971 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk,
21972 + hr->haintmsk_local);
21973 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
21974 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk,
21975 + hr->hcintmsk_local[i]);
21981 +int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if)
21983 + struct dwc_otg_global_regs_backup *gr;
21985 + gr = core_if->gr_backup;
21987 + /* Restore values for LPM and I2C */
21988 +#ifdef CONFIG_USB_DWC_OTG_LPM
21989 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, gr->glpmcfg_local);
21991 + DWC_WRITE_REG32(&core_if->core_global_regs->gi2cctl, gr->gi2cctl_local);
21996 +int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode, int is_host)
21998 + struct dwc_otg_global_regs_backup *gr;
21999 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
22000 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
22001 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
22002 + gintmsk_data_t gintmsk = {.d32 = 0 };
22004 + /* Restore LPM and I2C registers */
22005 + restore_lpm_i2c_regs(core_if);
22007 + /* Set PCGCCTL to 0 */
22008 + DWC_WRITE_REG32(core_if->pcgcctl, 0x00000000);
22010 + gr = core_if->gr_backup;
22011 + /* Load restore values for [31:14] bits */
22012 + DWC_WRITE_REG32(core_if->pcgcctl,
22013 + ((gr->pcgcctl_local & 0xffffc000) | 0x00020000));
22015 + /* Umnask global Interrupt in GAHBCFG and restore it */
22016 + gahbcfg.d32 = gr->gahbcfg_local;
22017 + gahbcfg.b.glblintrmsk = 1;
22018 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
22020 + /* Clear all pending interupts */
22021 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
22023 + /* Unmask restore done interrupt */
22024 + gintmsk.b.restoredone = 1;
22025 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
22027 + /* Restore GUSBCFG and HCFG/DCFG */
22028 + gusbcfg.d32 = core_if->gr_backup->gusbcfg_local;
22029 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
22032 + hcfg_data_t hcfg = {.d32 = 0 };
22033 + hcfg.d32 = core_if->hr_backup->hcfg_local;
22034 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
22037 + /* Load restore values for [31:14] bits */
22038 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22039 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22042 + pcgcctl.b.restoremode = 1;
22043 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22046 + /* Load restore values for [31:14] bits and set EssRegRestored bit */
22047 + pcgcctl.d32 = gr->pcgcctl_local | 0xffffc000;
22048 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22049 + pcgcctl.b.ess_reg_restored = 1;
22051 + pcgcctl.b.restoremode = 1;
22052 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22054 + dcfg_data_t dcfg = {.d32 = 0 };
22055 + dcfg.d32 = core_if->dr_backup->dcfg;
22056 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
22058 + /* Load restore values for [31:14] bits */
22059 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22060 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22062 + pcgcctl.d32 |= 0x208;
22064 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22067 + /* Load restore values for [31:14] bits */
22068 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22069 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22070 + pcgcctl.b.ess_reg_restored = 1;
22072 + pcgcctl.d32 |= 0x208;
22073 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22080 + * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
22083 +static void init_fslspclksel(dwc_otg_core_if_t * core_if)
22086 + hcfg_data_t hcfg;
22088 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
22089 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22090 + (core_if->core_params->ulpi_fs_ls)) ||
22091 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22092 + /* Full speed PHY */
22093 + val = DWC_HCFG_48_MHZ;
22095 + /* High speed PHY running at full speed or high speed */
22096 + val = DWC_HCFG_30_60_MHZ;
22099 + DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
22100 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
22101 + hcfg.b.fslspclksel = val;
22102 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
22106 + * Initializes the DevSpd field of the DCFG register depending on the PHY type
22107 + * and the enumeration speed of the device.
22109 +static void init_devspd(dwc_otg_core_if_t * core_if)
22112 + dcfg_data_t dcfg;
22114 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
22115 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22116 + (core_if->core_params->ulpi_fs_ls)) ||
22117 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22118 + /* Full speed PHY */
22120 + } else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
22121 + /* High speed PHY running at full speed */
22124 + /* High speed PHY running at high speed */
22128 + DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
22130 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
22131 + dcfg.b.devspd = val;
22132 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
22136 + * This function calculates the number of IN EPS
22137 + * using GHWCFG1 and GHWCFG2 registers values
22139 + * @param core_if Programming view of the DWC_otg controller
22141 +static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if)
22143 + uint32_t num_in_eps = 0;
22144 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
22145 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3;
22146 + uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps;
22149 + for (i = 0; i < num_eps; ++i) {
22150 + if (!(hwcfg1 & 0x1))
22156 + if (core_if->hwcfg4.b.ded_fifo_en) {
22158 + (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
22161 + return num_in_eps;
22165 + * This function calculates the number of OUT EPS
22166 + * using GHWCFG1 and GHWCFG2 registers values
22168 + * @param core_if Programming view of the DWC_otg controller
22170 +static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if)
22172 + uint32_t num_out_eps = 0;
22173 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
22174 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2;
22177 + for (i = 0; i < num_eps; ++i) {
22178 + if (!(hwcfg1 & 0x1))
22183 + return num_out_eps;
22187 + * This function initializes the DWC_otg controller registers and
22188 + * prepares the core for device mode or host mode operation.
22190 + * @param core_if Programming view of the DWC_otg controller
22193 +void dwc_otg_core_init(dwc_otg_core_if_t * core_if)
22196 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22197 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
22198 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
22199 + gusbcfg_data_t usbcfg = {.d32 = 0 };
22200 + gi2cctl_data_t i2cctl = {.d32 = 0 };
22202 + DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p) regs at %p\n",
22203 + core_if, global_regs);
22205 + /* Common Initialization */
22206 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22208 + /* Program the ULPI External VBUS bit if needed */
22209 + usbcfg.b.ulpi_ext_vbus_drv =
22210 + (core_if->core_params->phy_ulpi_ext_vbus ==
22211 + DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
22213 + /* Set external TS Dline pulsing */
22214 + usbcfg.b.term_sel_dl_pulse =
22215 + (core_if->core_params->ts_dline == 1) ? 1 : 0;
22216 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22218 + /* Reset the Controller */
22219 + dwc_otg_core_reset(core_if);
22221 + core_if->adp_enable = core_if->core_params->adp_supp_enable;
22222 + core_if->power_down = core_if->core_params->power_down;
22223 + core_if->otg_sts = 0;
22225 + /* Initialize parameters from Hardware configuration registers. */
22226 + dev_if->num_in_eps = calc_num_in_eps(core_if);
22227 + dev_if->num_out_eps = calc_num_out_eps(core_if);
22229 + DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
22230 + core_if->hwcfg4.b.num_dev_perio_in_ep);
22232 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
22233 + dev_if->perio_tx_fifo_size[i] =
22234 + DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
22235 + DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
22236 + i, dev_if->perio_tx_fifo_size[i]);
22239 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
22240 + dev_if->tx_fifo_size[i] =
22241 + DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
22242 + DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
22243 + i, dev_if->tx_fifo_size[i]);
22246 + core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
22247 + core_if->rx_fifo_size = DWC_READ_REG32(&global_regs->grxfsiz);
22248 + core_if->nperio_tx_fifo_size =
22249 + DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16;
22251 + DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
22252 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
22253 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
22254 + core_if->nperio_tx_fifo_size);
22256 + /* This programming sequence needs to happen in FS mode before any other
22257 + * programming occurs */
22258 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
22259 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22260 + /* If FS mode with FS PHY */
22262 + /* core_init() is now called on every switch so only call the
22263 + * following for the first time through. */
22264 + if (!core_if->phy_init_done) {
22265 + core_if->phy_init_done = 1;
22266 + DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
22267 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22268 + usbcfg.b.physel = 1;
22269 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22271 + /* Reset after a PHY select */
22272 + dwc_otg_core_reset(core_if);
22275 + /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
22276 + * do this on HNP Dev/Host mode switches (done in dev_init and
22278 + if (dwc_otg_is_host_mode(core_if)) {
22279 + init_fslspclksel(core_if);
22281 + init_devspd(core_if);
22284 + if (core_if->core_params->i2c_enable) {
22285 + DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
22286 + /* Program GUSBCFG.OtgUtmifsSel to I2C */
22287 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22288 + usbcfg.b.otgutmifssel = 1;
22289 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22291 + /* Program GI2CCTL.I2CEn */
22292 + i2cctl.d32 = DWC_READ_REG32(&global_regs->gi2cctl);
22293 + i2cctl.b.i2cdevaddr = 1;
22294 + i2cctl.b.i2cen = 0;
22295 + DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
22296 + i2cctl.b.i2cen = 1;
22297 + DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
22300 + } /* endif speed == DWC_SPEED_PARAM_FULL */
22302 + /* High speed PHY. */
22303 + if (!core_if->phy_init_done) {
22304 + core_if->phy_init_done = 1;
22305 + /* HS PHY parameters. These parameters are preserved
22306 + * during soft reset so only program the first time. Do
22307 + * a soft reset immediately after setting phyif. */
22309 + if (core_if->core_params->phy_type == 2) {
22310 + /* ULPI interface */
22311 + usbcfg.b.ulpi_utmi_sel = 1;
22312 + usbcfg.b.phyif = 0;
22313 + usbcfg.b.ddrsel =
22314 + core_if->core_params->phy_ulpi_ddr;
22315 + } else if (core_if->core_params->phy_type == 1) {
22316 + /* UTMI+ interface */
22317 + usbcfg.b.ulpi_utmi_sel = 0;
22318 + if (core_if->core_params->phy_utmi_width == 16) {
22319 + usbcfg.b.phyif = 1;
22322 + usbcfg.b.phyif = 0;
22325 + DWC_ERROR("FS PHY TYPE\n");
22327 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22328 + /* Reset after setting the PHY parameters */
22329 + dwc_otg_core_reset(core_if);
22333 + if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
22334 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22335 + (core_if->core_params->ulpi_fs_ls)) {
22336 + DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
22337 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22338 + usbcfg.b.ulpi_fsls = 1;
22339 + usbcfg.b.ulpi_clk_sus_m = 1;
22340 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22342 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22343 + usbcfg.b.ulpi_fsls = 0;
22344 + usbcfg.b.ulpi_clk_sus_m = 0;
22345 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22348 + /* Program the GAHBCFG Register. */
22349 + switch (core_if->hwcfg2.b.architecture) {
22351 + case DWC_SLAVE_ONLY_ARCH:
22352 + DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
22353 + ahbcfg.b.nptxfemplvl_txfemplvl =
22354 + DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
22355 + ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
22356 + core_if->dma_enable = 0;
22357 + core_if->dma_desc_enable = 0;
22360 + case DWC_EXT_DMA_ARCH:
22361 + DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
22363 + uint8_t brst_sz = core_if->core_params->dma_burst_size;
22364 + ahbcfg.b.hburstlen = 0;
22365 + while (brst_sz > 1) {
22366 + ahbcfg.b.hburstlen++;
22370 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
22371 + core_if->dma_desc_enable =
22372 + (core_if->core_params->dma_desc_enable != 0);
22375 + case DWC_INT_DMA_ARCH:
22376 + DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
22377 + /* Old value was DWC_GAHBCFG_INT_DMA_BURST_INCR - done for
22378 + Host mode ISOC in issue fix - vahrama */
22379 + /* Broadcom had altered to (1<<3)|(0<<0) - WRESP=1, max 4 beats */
22380 + ahbcfg.b.hburstlen = (1<<3)|(0<<0);//DWC_GAHBCFG_INT_DMA_BURST_INCR4;
22381 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
22382 + core_if->dma_desc_enable =
22383 + (core_if->core_params->dma_desc_enable != 0);
22387 + if (core_if->dma_enable) {
22388 + if (core_if->dma_desc_enable) {
22389 + DWC_PRINTF("Using Descriptor DMA mode\n");
22391 + DWC_PRINTF("Using Buffer DMA mode\n");
22395 + DWC_PRINTF("Using Slave mode\n");
22396 + core_if->dma_desc_enable = 0;
22399 + if (core_if->core_params->ahb_single) {
22400 + ahbcfg.b.ahbsingle = 1;
22403 + ahbcfg.b.dmaenable = core_if->dma_enable;
22404 + DWC_WRITE_REG32(&global_regs->gahbcfg, ahbcfg.d32);
22406 + core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en;
22408 + core_if->pti_enh_enable = core_if->core_params->pti_enable != 0;
22409 + core_if->multiproc_int_enable = core_if->core_params->mpi_enable;
22410 + DWC_PRINTF("Periodic Transfer Interrupt Enhancement - %s\n",
22411 + ((core_if->pti_enh_enable) ? "enabled" : "disabled"));
22412 + DWC_PRINTF("Multiprocessor Interrupt Enhancement - %s\n",
22413 + ((core_if->multiproc_int_enable) ? "enabled" : "disabled"));
22416 + * Program the GUSBCFG register.
22418 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22420 + switch (core_if->hwcfg2.b.op_mode) {
22421 + case DWC_MODE_HNP_SRP_CAPABLE:
22422 + usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
22423 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
22424 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22425 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22428 + case DWC_MODE_SRP_ONLY_CAPABLE:
22429 + usbcfg.b.hnpcap = 0;
22430 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22431 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22434 + case DWC_MODE_NO_HNP_SRP_CAPABLE:
22435 + usbcfg.b.hnpcap = 0;
22436 + usbcfg.b.srpcap = 0;
22439 + case DWC_MODE_SRP_CAPABLE_DEVICE:
22440 + usbcfg.b.hnpcap = 0;
22441 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22442 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22445 + case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
22446 + usbcfg.b.hnpcap = 0;
22447 + usbcfg.b.srpcap = 0;
22450 + case DWC_MODE_SRP_CAPABLE_HOST:
22451 + usbcfg.b.hnpcap = 0;
22452 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22453 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22456 + case DWC_MODE_NO_SRP_CAPABLE_HOST:
22457 + usbcfg.b.hnpcap = 0;
22458 + usbcfg.b.srpcap = 0;
22462 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22464 +#ifdef CONFIG_USB_DWC_OTG_LPM
22465 + if (core_if->core_params->lpm_enable) {
22466 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
22468 + /* To enable LPM support set lpm_cap_en bit */
22469 + lpmcfg.b.lpm_cap_en = 1;
22471 + /* Make AppL1Res ACK */
22472 + lpmcfg.b.appl_resp = 1;
22474 + /* Retry 3 times */
22475 + lpmcfg.b.retry_count = 3;
22477 + DWC_MODIFY_REG32(&core_if->core_global_regs->glpmcfg,
22482 + if (core_if->core_params->ic_usb_cap) {
22483 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
22484 + gusbcfg.b.ic_usb_cap = 1;
22485 + DWC_MODIFY_REG32(&core_if->core_global_regs->gusbcfg,
22489 + gotgctl_data_t gotgctl = {.d32 = 0 };
22490 + gotgctl.b.otgver = core_if->core_params->otg_ver;
22491 + DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, 0,
22493 + /* Set OTG version supported */
22494 + core_if->otg_ver = core_if->core_params->otg_ver;
22495 + DWC_PRINTF("OTG VER PARAM: %d, OTG VER FLAG: %d\n",
22496 + core_if->core_params->otg_ver, core_if->otg_ver);
22500 + /* Enable common interrupts */
22501 + dwc_otg_enable_common_interrupts(core_if);
22503 + /* Do device or host intialization based on mode during PCD
22504 + * and HCD initialization */
22505 + if (dwc_otg_is_host_mode(core_if)) {
22506 + DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
22507 + core_if->op_state = A_HOST;
22509 + DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
22510 + core_if->op_state = B_PERIPHERAL;
22511 +#ifdef DWC_DEVICE_ONLY
22512 + dwc_otg_core_dev_init(core_if);
22518 + * This function enables the Device mode interrupts.
22520 + * @param core_if Programming view of DWC_otg controller
22522 +void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if)
22524 + gintmsk_data_t intr_mask = {.d32 = 0 };
22525 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22527 + DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
22529 + /* Disable all interrupts. */
22530 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
22532 + /* Clear any pending interrupts */
22533 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
22535 + /* Enable the common interrupts */
22536 + dwc_otg_enable_common_interrupts(core_if);
22538 + /* Enable interrupts */
22539 + intr_mask.b.usbreset = 1;
22540 + intr_mask.b.enumdone = 1;
22541 + /* Disable Disconnect interrupt in Device mode */
22542 + intr_mask.b.disconnect = 0;
22544 + if (!core_if->multiproc_int_enable) {
22545 + intr_mask.b.inepintr = 1;
22546 + intr_mask.b.outepintr = 1;
22549 + intr_mask.b.erlysuspend = 1;
22551 + if (core_if->en_multiple_tx_fifo == 0) {
22552 + intr_mask.b.epmismatch = 1;
22555 + //intr_mask.b.incomplisoout = 1;
22556 + intr_mask.b.incomplisoin = 1;
22558 +/* Enable the ignore frame number for ISOC xfers - MAS */
22559 +/* Disable to support high bandwith ISOC transfers - manukz */
22561 +#ifdef DWC_UTE_PER_IO
22562 + if (core_if->dma_enable) {
22563 + if (core_if->dma_desc_enable) {
22564 + dctl_data_t dctl1 = {.d32 = 0 };
22565 + dctl1.b.ifrmnum = 1;
22566 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
22567 + dctl, 0, dctl1.d32);
22568 + DWC_DEBUG("----Enabled Ignore frame number (0x%08x)",
22569 + DWC_READ_REG32(&core_if->dev_if->
22570 + dev_global_regs->dctl));
22575 +#ifdef DWC_EN_ISOC
22576 + if (core_if->dma_enable) {
22577 + if (core_if->dma_desc_enable == 0) {
22578 + if (core_if->pti_enh_enable) {
22579 + dctl_data_t dctl = {.d32 = 0 };
22580 + dctl.b.ifrmnum = 1;
22581 + DWC_MODIFY_REG32(&core_if->
22582 + dev_if->dev_global_regs->dctl,
22585 + intr_mask.b.incomplisoin = 1;
22586 + intr_mask.b.incomplisoout = 1;
22590 + intr_mask.b.incomplisoin = 1;
22591 + intr_mask.b.incomplisoout = 1;
22593 +#endif /* DWC_EN_ISOC */
22595 + /** @todo NGS: Should this be a module parameter? */
22596 +#ifdef USE_PERIODIC_EP
22597 + intr_mask.b.isooutdrop = 1;
22598 + intr_mask.b.eopframe = 1;
22599 + intr_mask.b.incomplisoin = 1;
22600 + intr_mask.b.incomplisoout = 1;
22603 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
22605 + DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
22606 + DWC_READ_REG32(&global_regs->gintmsk));
22610 + * This function initializes the DWC_otg controller registers for
22613 + * @param core_if Programming view of DWC_otg controller
22616 +void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if)
22619 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22620 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
22621 + dwc_otg_core_params_t *params = core_if->core_params;
22622 + dcfg_data_t dcfg = {.d32 = 0 };
22623 + depctl_data_t diepctl = {.d32 = 0 };
22624 + grstctl_t resetctl = {.d32 = 0 };
22625 + uint32_t rx_fifo_size;
22626 + fifosize_data_t nptxfifosize;
22627 + fifosize_data_t txfifosize;
22628 + dthrctl_data_t dthrctl;
22629 + fifosize_data_t ptxfifosize;
22630 + uint16_t rxfsiz, nptxfsiz;
22631 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
22632 + hwcfg3_data_t hwcfg3 = {.d32 = 0 };
22634 + /* Restart the Phy Clock */
22635 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
22637 + /* Device configuration register */
22638 + init_devspd(core_if);
22639 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
22640 + dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0;
22641 + dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
22642 + /* Enable Device OUT NAK in case of DDMA mode*/
22643 + if (core_if->core_params->dev_out_nak) {
22644 + dcfg.b.endevoutnak = 1;
22647 + if (core_if->core_params->cont_on_bna) {
22648 + dctl_data_t dctl = {.d32 = 0 };
22649 + dctl.b.encontonbna = 1;
22650 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
22654 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
22656 + /* Configure data FIFO sizes */
22657 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
22658 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
22659 + core_if->total_fifo_size);
22660 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
22661 + params->dev_rx_fifo_size);
22662 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
22663 + params->dev_nperio_tx_fifo_size);
22666 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
22667 + DWC_READ_REG32(&global_regs->grxfsiz));
22669 +#ifdef DWC_UTE_CFI
22670 + core_if->pwron_rxfsiz = DWC_READ_REG32(&global_regs->grxfsiz);
22671 + core_if->init_rxfsiz = params->dev_rx_fifo_size;
22673 + rx_fifo_size = params->dev_rx_fifo_size;
22674 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
22676 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
22677 + DWC_READ_REG32(&global_regs->grxfsiz));
22679 + /** Set Periodic Tx FIFO Mask all bits 0 */
22680 + core_if->p_tx_msk = 0;
22682 + /** Set Tx FIFO Mask all bits 0 */
22683 + core_if->tx_msk = 0;
22685 + if (core_if->en_multiple_tx_fifo == 0) {
22686 + /* Non-periodic Tx FIFO */
22687 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
22688 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22690 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
22691 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
22693 + DWC_WRITE_REG32(&global_regs->gnptxfsiz,
22694 + nptxfifosize.d32);
22696 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
22697 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22699 + /**@todo NGS: Fix Periodic FIFO Sizing! */
22701 + * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
22702 + * Indexes of the FIFO size module parameters in the
22703 + * dev_perio_tx_fifo_size array and the FIFO size registers in
22704 + * the dptxfsiz array run from 0 to 14.
22706 + /** @todo Finish debug of this */
22707 + ptxfifosize.b.startaddr =
22708 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
22709 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
22710 + ptxfifosize.b.depth =
22711 + params->dev_perio_tx_fifo_size[i];
22712 + DWC_DEBUGPL(DBG_CIL,
22713 + "initial dtxfsiz[%d]=%08x\n", i,
22714 + DWC_READ_REG32(&global_regs->dtxfsiz
22716 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
22717 + ptxfifosize.d32);
22718 + DWC_DEBUGPL(DBG_CIL, "new dtxfsiz[%d]=%08x\n",
22720 + DWC_READ_REG32(&global_regs->dtxfsiz
22722 + ptxfifosize.b.startaddr += ptxfifosize.b.depth;
22726 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
22727 + * Indexes of the FIFO size module parameters in the
22728 + * dev_tx_fifo_size array and the FIFO size registers in
22729 + * the dtxfsiz array run from 0 to 14.
22732 + /* Non-periodic Tx FIFO */
22733 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
22734 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22736 +#ifdef DWC_UTE_CFI
22737 + core_if->pwron_gnptxfsiz =
22738 + (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
22739 + core_if->init_gnptxfsiz =
22740 + params->dev_nperio_tx_fifo_size;
22742 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
22743 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
22745 + DWC_WRITE_REG32(&global_regs->gnptxfsiz,
22746 + nptxfifosize.d32);
22748 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
22749 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22751 + txfifosize.b.startaddr =
22752 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
22754 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
22756 + txfifosize.b.depth =
22757 + params->dev_tx_fifo_size[i];
22759 + DWC_DEBUGPL(DBG_CIL,
22760 + "initial dtxfsiz[%d]=%08x\n",
22762 + DWC_READ_REG32(&global_regs->dtxfsiz
22765 +#ifdef DWC_UTE_CFI
22766 + core_if->pwron_txfsiz[i] =
22768 + (&global_regs->dtxfsiz[i]) >> 16);
22769 + core_if->init_txfsiz[i] =
22770 + params->dev_tx_fifo_size[i];
22772 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
22775 + DWC_DEBUGPL(DBG_CIL,
22776 + "new dtxfsiz[%d]=%08x\n",
22778 + DWC_READ_REG32(&global_regs->dtxfsiz
22781 + txfifosize.b.startaddr += txfifosize.b.depth;
22783 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
22784 + /* Calculating DFIFOCFG for Device mode to include RxFIFO and NPTXFIFO */
22785 + gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
22786 + hwcfg3.d32 = DWC_READ_REG32(&global_regs->ghwcfg3);
22787 + gdfifocfg.b.gdfifocfg = (DWC_READ_REG32(&global_regs->ghwcfg3) >> 16);
22788 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
22789 + rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
22790 + nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
22791 + gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz;
22792 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
22796 + /* Flush the FIFOs */
22797 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
22798 + dwc_otg_flush_rx_fifo(core_if);
22800 + /* Flush the Learning Queue. */
22801 + resetctl.b.intknqflsh = 1;
22802 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
22804 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
22805 + core_if->start_predict = 0;
22806 + for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
22807 + core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
22809 + core_if->nextep_seq[0] = 0;
22810 + core_if->first_in_nextep_seq = 0;
22811 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
22812 + diepctl.b.nextep = 0;
22813 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
22815 + /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
22816 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
22817 + dcfg.b.epmscnt = 2;
22818 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
22820 + DWC_DEBUGPL(DBG_CILV,"%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
22821 + __func__, core_if->first_in_nextep_seq);
22822 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
22823 + DWC_DEBUGPL(DBG_CILV, "%2d ", core_if->nextep_seq[i]);
22825 + DWC_DEBUGPL(DBG_CILV,"\n");
22828 + /* Clear all pending Device Interrupts */
22829 + /** @todo - if the condition needed to be checked
22830 + * or in any case all pending interrutps should be cleared?
22832 + if (core_if->multiproc_int_enable) {
22833 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
22834 + DWC_WRITE_REG32(&dev_if->
22835 + dev_global_regs->diepeachintmsk[i], 0);
22839 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
22840 + DWC_WRITE_REG32(&dev_if->
22841 + dev_global_regs->doepeachintmsk[i], 0);
22844 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF);
22845 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk, 0);
22847 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, 0);
22848 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, 0);
22849 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
22850 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk, 0);
22853 + for (i = 0; i <= dev_if->num_in_eps; i++) {
22854 + depctl_data_t depctl;
22855 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
22856 + if (depctl.b.epena) {
22858 + depctl.b.epdis = 1;
22859 + depctl.b.snak = 1;
22864 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
22866 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
22867 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, 0);
22868 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
22871 + for (i = 0; i <= dev_if->num_out_eps; i++) {
22872 + depctl_data_t depctl;
22873 + depctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
22874 + if (depctl.b.epena) {
22875 + dctl_data_t dctl = {.d32 = 0 };
22876 + gintmsk_data_t gintsts = {.d32 = 0 };
22877 + doepint_data_t doepint = {.d32 = 0 };
22878 + dctl.b.sgoutnak = 1;
22879 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
22882 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
22883 + } while (!gintsts.b.goutnakeff);
22885 + gintsts.b.goutnakeff = 1;
22886 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
22889 + depctl.b.epdis = 1;
22890 + depctl.b.snak = 1;
22891 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepctl, depctl.d32);
22894 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
22895 + out_ep_regs[i]->doepint);
22896 + } while (!doepint.b.epdisabled);
22898 + doepint.b.epdisabled = 1;
22899 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepint, doepint.d32);
22902 + dctl.b.cgoutnak = 1;
22903 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
22908 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
22910 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
22911 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepdma, 0);
22912 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
22915 + if (core_if->en_multiple_tx_fifo && core_if->dma_enable) {
22916 + dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1;
22917 + dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1;
22918 + dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1;
22920 + dev_if->rx_thr_length = params->rx_thr_length;
22921 + dev_if->tx_thr_length = params->tx_thr_length;
22923 + dev_if->setup_desc_index = 0;
22926 + dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
22927 + dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
22928 + dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
22929 + dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
22930 + dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
22931 + dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio;
22933 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dtknqr3_dthrctl,
22936 + DWC_DEBUGPL(DBG_CIL,
22937 + "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
22938 + dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en,
22939 + dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len,
22940 + dthrctl.b.rx_thr_len);
22944 + dwc_otg_enable_device_interrupts(core_if);
22947 + diepmsk_data_t msk = {.d32 = 0 };
22948 + msk.b.txfifoundrn = 1;
22949 + if (core_if->multiproc_int_enable) {
22950 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->
22951 + diepeachintmsk[0], msk.d32, msk.d32);
22953 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk,
22954 + msk.d32, msk.d32);
22958 + if (core_if->multiproc_int_enable) {
22959 + /* Set NAK on Babble */
22960 + dctl_data_t dctl = {.d32 = 0 };
22961 + dctl.b.nakonbble = 1;
22962 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
22965 + if (core_if->snpsid >= OTG_CORE_REV_2_94a) {
22966 + dctl_data_t dctl = {.d32 = 0 };
22967 + dctl.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
22968 + dctl.b.sftdiscon = 0;
22969 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl, dctl.d32);
22974 + * This function enables the Host mode interrupts.
22976 + * @param core_if Programming view of DWC_otg controller
22978 +void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if)
22980 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22981 + gintmsk_data_t intr_mask = {.d32 = 0 };
22983 + DWC_DEBUGPL(DBG_CIL, "%s(%p)\n", __func__, core_if);
22985 + /* Disable all interrupts. */
22986 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
22988 + /* Clear any pending interrupts. */
22989 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
22991 + /* Enable the common interrupts */
22992 + dwc_otg_enable_common_interrupts(core_if);
22995 + * Enable host mode interrupts without disturbing common
22999 + intr_mask.b.disconnect = 1;
23000 + intr_mask.b.portintr = 1;
23001 + intr_mask.b.hcintr = 1;
23003 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
23007 + * This function disables the Host Mode interrupts.
23009 + * @param core_if Programming view of DWC_otg controller
23011 +void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if)
23013 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
23014 + gintmsk_data_t intr_mask = {.d32 = 0 };
23016 + DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
23019 + * Disable host mode interrupts without disturbing common
23022 + intr_mask.b.sofintr = 1;
23023 + intr_mask.b.portintr = 1;
23024 + intr_mask.b.hcintr = 1;
23025 + intr_mask.b.ptxfempty = 1;
23026 + intr_mask.b.nptxfempty = 1;
23028 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, 0);
23032 + * This function initializes the DWC_otg controller registers for
23035 + * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
23036 + * request queues. Host channels are reset to ensure that they are ready for
23037 + * performing transfers.
23039 + * @param core_if Programming view of DWC_otg controller
23042 +void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
23044 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
23045 + dwc_otg_host_if_t *host_if = core_if->host_if;
23046 + dwc_otg_core_params_t *params = core_if->core_params;
23047 + hprt0_data_t hprt0 = {.d32 = 0 };
23048 + fifosize_data_t nptxfifosize;
23049 + fifosize_data_t ptxfifosize;
23050 + uint16_t rxfsiz, nptxfsiz, hptxfsiz;
23051 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
23053 + hcchar_data_t hcchar;
23054 + hcfg_data_t hcfg;
23055 + hfir_data_t hfir;
23056 + dwc_otg_hc_regs_t *hc_regs;
23057 + int num_channels;
23058 + gotgctl_data_t gotgctl = {.d32 = 0 };
23060 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
23062 + /* Restart the Phy Clock */
23063 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
23065 + /* Initialize Host Configuration Register */
23066 + init_fslspclksel(core_if);
23067 + if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
23068 + hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
23069 + hcfg.b.fslssupp = 1;
23070 + DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
23074 + /* This bit allows dynamic reloading of the HFIR register
23075 + * during runtime. This bit needs to be programmed during
23076 + * initial configuration and its value must not be changed
23077 + * during runtime.*/
23078 + if (core_if->core_params->reload_ctl == 1) {
23079 + hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
23080 + hfir.b.hfirrldctrl = 1;
23081 + DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
23084 + if (core_if->core_params->dma_desc_enable) {
23085 + uint8_t op_mode = core_if->hwcfg2.b.op_mode;
23087 + (core_if->hwcfg4.b.desc_dma
23088 + && (core_if->snpsid >= OTG_CORE_REV_2_90a)
23089 + && ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
23090 + || (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
23092 + DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG)
23093 + || (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)
23095 + DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) {
23097 + DWC_ERROR("Host can't operate in Descriptor DMA mode.\n"
23098 + "Either core version is below 2.90a or "
23099 + "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n"
23100 + "To run the driver in Buffer DMA host mode set dma_desc_enable "
23101 + "module parameter to 0.\n");
23104 + hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
23105 + hcfg.b.descdma = 1;
23106 + DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
23109 + /* Configure data FIFO sizes */
23110 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
23111 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
23112 + core_if->total_fifo_size);
23113 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
23114 + params->host_rx_fifo_size);
23115 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
23116 + params->host_nperio_tx_fifo_size);
23117 + DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
23118 + params->host_perio_tx_fifo_size);
23121 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
23122 + DWC_READ_REG32(&global_regs->grxfsiz));
23123 + DWC_WRITE_REG32(&global_regs->grxfsiz,
23124 + params->host_rx_fifo_size);
23125 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
23126 + DWC_READ_REG32(&global_regs->grxfsiz));
23128 + /* Non-periodic Tx FIFO */
23129 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
23130 + DWC_READ_REG32(&global_regs->gnptxfsiz));
23131 + nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
23132 + nptxfifosize.b.startaddr = params->host_rx_fifo_size;
23133 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
23134 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
23135 + DWC_READ_REG32(&global_regs->gnptxfsiz));
23137 + /* Periodic Tx FIFO */
23138 + DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
23139 + DWC_READ_REG32(&global_regs->hptxfsiz));
23140 + ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
23141 + ptxfifosize.b.startaddr =
23142 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
23143 + DWC_WRITE_REG32(&global_regs->hptxfsiz, ptxfifosize.d32);
23144 + DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
23145 + DWC_READ_REG32(&global_regs->hptxfsiz));
23147 + if (core_if->en_multiple_tx_fifo
23148 + && core_if->snpsid <= OTG_CORE_REV_2_94a) {
23149 + /* Global DFIFOCFG calculation for Host mode - include RxFIFO, NPTXFIFO and HPTXFIFO */
23150 + gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
23151 + rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
23152 + nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
23153 + hptxfsiz = (DWC_READ_REG32(&global_regs->hptxfsiz) >> 16);
23154 + gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz + hptxfsiz;
23155 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
23159 + /* TODO - check this */
23160 + /* Clear Host Set HNP Enable in the OTG Control Register */
23161 + gotgctl.b.hstsethnpen = 1;
23162 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
23163 + /* Make sure the FIFOs are flushed. */
23164 + dwc_otg_flush_tx_fifo(core_if, 0x10 /* all TX FIFOs */ );
23165 + dwc_otg_flush_rx_fifo(core_if);
23167 + /* Clear Host Set HNP Enable in the OTG Control Register */
23168 + gotgctl.b.hstsethnpen = 1;
23169 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
23171 + if (!core_if->core_params->dma_desc_enable) {
23172 + /* Flush out any leftover queued requests. */
23173 + num_channels = core_if->core_params->host_channels;
23175 + for (i = 0; i < num_channels; i++) {
23176 + hc_regs = core_if->host_if->hc_regs[i];
23177 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23178 + hcchar.b.chen = 0;
23179 + hcchar.b.chdis = 1;
23180 + hcchar.b.epdir = 0;
23181 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23184 + /* Halt all channels to put them into a known state. */
23185 + for (i = 0; i < num_channels; i++) {
23187 + hc_regs = core_if->host_if->hc_regs[i];
23188 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23189 + hcchar.b.chen = 1;
23190 + hcchar.b.chdis = 1;
23191 + hcchar.b.epdir = 0;
23192 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23193 + DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d regs %p\n", __func__, i, hc_regs);
23195 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23196 + if (++count > 1000) {
23198 + ("%s: Unable to clear halt on channel %d (timeout HCCHAR 0x%X @%p)\n",
23199 + __func__, i, hcchar.d32, &hc_regs->hcchar);
23203 + } while (hcchar.b.chen);
23207 + /* Turn on the vbus power. */
23208 + DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state);
23209 + if (core_if->op_state == A_HOST) {
23210 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
23211 + DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
23212 + if (hprt0.b.prtpwr == 0) {
23213 + hprt0.b.prtpwr = 1;
23214 + DWC_WRITE_REG32(host_if->hprt0, hprt0.d32);
23218 + dwc_otg_enable_host_interrupts(core_if);
23222 + * Prepares a host channel for transferring packets to/from a specific
23223 + * endpoint. The HCCHARn register is set up with the characteristics specified
23224 + * in _hc. Host channel interrupts that may need to be serviced while this
23225 + * transfer is in progress are enabled.
23227 + * @param core_if Programming view of DWC_otg controller
23228 + * @param hc Information needed to initialize the host channel
23230 +void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23232 + uint32_t intr_enable;
23233 + hcintmsk_data_t hc_intr_mask;
23234 + gintmsk_data_t gintmsk = {.d32 = 0 };
23235 + hcchar_data_t hcchar;
23236 + hcsplt_data_t hcsplt;
23238 + uint8_t hc_num = hc->hc_num;
23239 + dwc_otg_host_if_t *host_if = core_if->host_if;
23240 + dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
23242 + /* Clear old interrupt conditions for this host channel. */
23243 + hc_intr_mask.d32 = 0xFFFFFFFF;
23244 + hc_intr_mask.b.reserved14_31 = 0;
23245 + DWC_WRITE_REG32(&hc_regs->hcint, hc_intr_mask.d32);
23247 + /* Enable channel interrupts required for this transfer. */
23248 + hc_intr_mask.d32 = 0;
23249 + hc_intr_mask.b.chhltd = 1;
23250 + if (core_if->dma_enable) {
23251 + /* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */
23252 + if (!core_if->dma_desc_enable)
23253 + hc_intr_mask.b.ahberr = 1;
23255 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23256 + hc_intr_mask.b.xfercompl = 1;
23259 + if (hc->error_state && !hc->do_split &&
23260 + hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
23261 + hc_intr_mask.b.ack = 1;
23262 + if (hc->ep_is_in) {
23263 + hc_intr_mask.b.datatglerr = 1;
23264 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
23265 + hc_intr_mask.b.nak = 1;
23270 + switch (hc->ep_type) {
23271 + case DWC_OTG_EP_TYPE_CONTROL:
23272 + case DWC_OTG_EP_TYPE_BULK:
23273 + hc_intr_mask.b.xfercompl = 1;
23274 + hc_intr_mask.b.stall = 1;
23275 + hc_intr_mask.b.xacterr = 1;
23276 + hc_intr_mask.b.datatglerr = 1;
23277 + if (hc->ep_is_in) {
23278 + hc_intr_mask.b.bblerr = 1;
23280 + hc_intr_mask.b.nak = 1;
23281 + hc_intr_mask.b.nyet = 1;
23282 + if (hc->do_ping) {
23283 + hc_intr_mask.b.ack = 1;
23287 + if (hc->do_split) {
23288 + hc_intr_mask.b.nak = 1;
23289 + if (hc->complete_split) {
23290 + hc_intr_mask.b.nyet = 1;
23292 + hc_intr_mask.b.ack = 1;
23296 + if (hc->error_state) {
23297 + hc_intr_mask.b.ack = 1;
23300 + case DWC_OTG_EP_TYPE_INTR:
23301 + hc_intr_mask.b.xfercompl = 1;
23302 + hc_intr_mask.b.nak = 1;
23303 + hc_intr_mask.b.stall = 1;
23304 + hc_intr_mask.b.xacterr = 1;
23305 + hc_intr_mask.b.datatglerr = 1;
23306 + hc_intr_mask.b.frmovrun = 1;
23308 + if (hc->ep_is_in) {
23309 + hc_intr_mask.b.bblerr = 1;
23311 + if (hc->error_state) {
23312 + hc_intr_mask.b.ack = 1;
23314 + if (hc->do_split) {
23315 + if (hc->complete_split) {
23316 + hc_intr_mask.b.nyet = 1;
23318 + hc_intr_mask.b.ack = 1;
23322 + case DWC_OTG_EP_TYPE_ISOC:
23323 + hc_intr_mask.b.xfercompl = 1;
23324 + hc_intr_mask.b.frmovrun = 1;
23325 + hc_intr_mask.b.ack = 1;
23327 + if (hc->ep_is_in) {
23328 + hc_intr_mask.b.xacterr = 1;
23329 + hc_intr_mask.b.bblerr = 1;
23334 + DWC_WRITE_REG32(&hc_regs->hcintmsk, hc_intr_mask.d32);
23336 + /* Enable the top level host channel interrupt. */
23337 + intr_enable = (1 << hc_num);
23338 + DWC_MODIFY_REG32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
23340 + /* Make sure host channel interrupts are enabled. */
23341 + gintmsk.b.hcintr = 1;
23342 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
23345 + * Program the HCCHARn register with the endpoint characteristics for
23346 + * the current transfer.
23349 + hcchar.b.devaddr = hc->dev_addr;
23350 + hcchar.b.epnum = hc->ep_num;
23351 + hcchar.b.epdir = hc->ep_is_in;
23352 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
23353 + hcchar.b.eptype = hc->ep_type;
23354 + hcchar.b.mps = hc->max_packet;
23356 + DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
23358 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d, Dev Addr %d, EP #%d\n",
23359 + __func__, hc->hc_num, hcchar.b.devaddr, hcchar.b.epnum);
23360 + DWC_DEBUGPL(DBG_HCDV, " Is In %d, Is Low Speed %d, EP Type %d, "
23361 + "Max Pkt %d, Multi Cnt %d\n",
23362 + hcchar.b.epdir, hcchar.b.lspddev, hcchar.b.eptype,
23363 + hcchar.b.mps, hcchar.b.multicnt);
23366 + * Program the HCSPLIT register for SPLITs
23369 + if (hc->do_split) {
23370 + DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
23372 + hc->complete_split ? "CSPLIT" : "SSPLIT");
23373 + hcsplt.b.compsplt = hc->complete_split;
23374 + hcsplt.b.xactpos = hc->xact_pos;
23375 + hcsplt.b.hubaddr = hc->hub_addr;
23376 + hcsplt.b.prtaddr = hc->port_addr;
23377 + DWC_DEBUGPL(DBG_HCDV, "\t comp split %d\n", hc->complete_split);
23378 + DWC_DEBUGPL(DBG_HCDV, "\t xact pos %d\n", hc->xact_pos);
23379 + DWC_DEBUGPL(DBG_HCDV, "\t hub addr %d\n", hc->hub_addr);
23380 + DWC_DEBUGPL(DBG_HCDV, "\t port addr %d\n", hc->port_addr);
23381 + DWC_DEBUGPL(DBG_HCDV, "\t is_in %d\n", hc->ep_is_in);
23382 + DWC_DEBUGPL(DBG_HCDV, "\t Max Pkt: %d\n", hcchar.b.mps);
23383 + DWC_DEBUGPL(DBG_HCDV, "\t xferlen: %d\n", hc->xfer_len);
23385 + DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
23390 + * Attempts to halt a host channel. This function should only be called in
23391 + * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
23392 + * normal circumstances in DMA mode, the controller halts the channel when the
23393 + * transfer is complete or a condition occurs that requires application
23396 + * In slave mode, checks for a free request queue entry, then sets the Channel
23397 + * Enable and Channel Disable bits of the Host Channel Characteristics
23398 + * register of the specified channel to intiate the halt. If there is no free
23399 + * request queue entry, sets only the Channel Disable bit of the HCCHARn
23400 + * register to flush requests for this channel. In the latter case, sets a
23401 + * flag to indicate that the host channel needs to be halted when a request
23402 + * queue slot is open.
23404 + * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
23405 + * HCCHARn register. The controller ensures there is space in the request
23406 + * queue before submitting the halt request.
23408 + * Some time may elapse before the core flushes any posted requests for this
23409 + * host channel and halts. The Channel Halted interrupt handler completes the
23410 + * deactivation of the host channel.
23412 + * @param core_if Controller register interface.
23413 + * @param hc Host channel to halt.
23414 + * @param halt_status Reason for halting the channel.
23416 +void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if,
23417 + dwc_hc_t * hc, dwc_otg_halt_status_e halt_status)
23419 + gnptxsts_data_t nptxsts;
23420 + hptxsts_data_t hptxsts;
23421 + hcchar_data_t hcchar;
23422 + dwc_otg_hc_regs_t *hc_regs;
23423 + dwc_otg_core_global_regs_t *global_regs;
23424 + dwc_otg_host_global_regs_t *host_global_regs;
23426 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23427 + global_regs = core_if->core_global_regs;
23428 + host_global_regs = core_if->host_if->host_global_regs;
23430 + DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS),
23431 + "halt_status = %d\n", halt_status);
23433 + if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
23434 + halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
23436 + * Disable all channel interrupts except Ch Halted. The QTD
23437 + * and QH state associated with this transfer has been cleared
23438 + * (in the case of URB_DEQUEUE), so the channel needs to be
23439 + * shut down carefully to prevent crashes.
23441 + hcintmsk_data_t hcintmsk;
23442 + hcintmsk.d32 = 0;
23443 + hcintmsk.b.chhltd = 1;
23444 + DWC_WRITE_REG32(&hc_regs->hcintmsk, hcintmsk.d32);
23447 + * Make sure no other interrupts besides halt are currently
23448 + * pending. Handling another interrupt could cause a crash due
23449 + * to the QTD and QH state.
23451 + DWC_WRITE_REG32(&hc_regs->hcint, ~hcintmsk.d32);
23454 + * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
23455 + * even if the channel was already halted for some other
23458 + hc->halt_status = halt_status;
23460 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23461 + if (hcchar.b.chen == 0) {
23463 + * The channel is either already halted or it hasn't
23464 + * started yet. In DMA mode, the transfer may halt if
23465 + * it finishes normally or a condition occurs that
23466 + * requires driver intervention. Don't want to halt
23467 + * the channel again. In either Slave or DMA mode,
23468 + * it's possible that the transfer has been assigned
23469 + * to a channel, but not started yet when an URB is
23470 + * dequeued. Don't want to halt a channel that hasn't
23476 + if (hc->halt_pending) {
23478 + * A halt has already been issued for this channel. This might
23479 + * happen when a transfer is aborted by a higher level in
23484 + ("*** %s: Channel %d, _hc->halt_pending already set ***\n",
23485 + __func__, hc->hc_num);
23491 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23493 + /* No need to set the bit in DDMA for disabling the channel */
23494 + //TODO check it everywhere channel is disabled
23495 + if (!core_if->core_params->dma_desc_enable)
23496 + hcchar.b.chen = 1;
23497 + hcchar.b.chdis = 1;
23499 + if (!core_if->dma_enable) {
23500 + /* Check for space in the request queue to issue the halt. */
23501 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
23502 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
23503 + nptxsts.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
23504 + if (nptxsts.b.nptxqspcavail == 0) {
23505 + hcchar.b.chen = 0;
23509 + DWC_READ_REG32(&host_global_regs->hptxsts);
23510 + if ((hptxsts.b.ptxqspcavail == 0)
23511 + || (core_if->queuing_high_bandwidth)) {
23512 + hcchar.b.chen = 0;
23516 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23518 + hc->halt_status = halt_status;
23520 + if (hcchar.b.chen) {
23521 + hc->halt_pending = 1;
23522 + hc->halt_on_queue = 0;
23524 + hc->halt_on_queue = 1;
23527 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23528 + DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32);
23529 + DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", hc->halt_pending);
23530 + DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", hc->halt_on_queue);
23531 + DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", hc->halt_status);
23537 + * Clears the transfer state for a host channel. This function is normally
23538 + * called after a transfer is done and the host channel is being released.
23540 + * @param core_if Programming view of DWC_otg controller.
23541 + * @param hc Identifies the host channel to clean up.
23543 +void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23545 + dwc_otg_hc_regs_t *hc_regs;
23547 + hc->xfer_started = 0;
23550 + * Clear channel interrupt enables and any unhandled channel interrupt
23553 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23554 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0);
23555 + DWC_WRITE_REG32(&hc_regs->hcint, 0xFFFFFFFF);
23557 + DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]);
23562 + * Sets the channel property that indicates in which frame a periodic transfer
23563 + * should occur. This is always set to the _next_ frame. This function has no
23564 + * effect on non-periodic transfers.
23566 + * @param core_if Programming view of DWC_otg controller.
23567 + * @param hc Identifies the host channel to set up and its properties.
23568 + * @param hcchar Current value of the HCCHAR register for the specified host
23571 +static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if,
23572 + dwc_hc_t * hc, hcchar_data_t * hcchar)
23574 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23575 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23576 + hfnum_data_t hfnum;
23578 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hfnum);
23580 + /* 1 if _next_ frame is odd, 0 if it's even */
23581 + hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
23583 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
23584 + && !hc->complete_split) {
23585 + switch (hfnum.b.frnum & 0x7) {
23587 + core_if->hfnum_7_samples++;
23588 + core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
23591 + core_if->hfnum_0_samples++;
23592 + core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
23595 + core_if->hfnum_other_samples++;
23596 + core_if->hfnum_other_frrem_accum +=
23606 +void hc_xfer_timeout(void *ptr)
23608 + hc_xfer_info_t *xfer_info = NULL;
23612 + xfer_info = (hc_xfer_info_t *) ptr;
23614 + if (!xfer_info->hc) {
23615 + DWC_ERROR("xfer_info->hc = %p\n", xfer_info->hc);
23619 + hc_num = xfer_info->hc->hc_num;
23620 + DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
23621 + DWC_WARN(" start_hcchar_val 0x%08x\n",
23622 + xfer_info->core_if->start_hcchar_val[hc_num]);
23626 +void ep_xfer_timeout(void *ptr)
23628 + ep_xfer_info_t *xfer_info = NULL;
23630 + dctl_data_t dctl = {.d32 = 0 };
23631 + gintsts_data_t gintsts = {.d32 = 0 };
23632 + gintmsk_data_t gintmsk = {.d32 = 0 };
23635 + xfer_info = (ep_xfer_info_t *) ptr;
23637 + if (!xfer_info->ep) {
23638 + DWC_ERROR("xfer_info->ep = %p\n", xfer_info->ep);
23642 + ep_num = xfer_info->ep->num;
23643 + DWC_WARN("%s: timeout on endpoit %d\n", __func__, ep_num);
23644 + /* Put the sate to 2 as it was time outed */
23645 + xfer_info->state = 2;
23648 + DWC_READ_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl);
23650 + DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintsts);
23652 + DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintmsk);
23654 + if (!gintmsk.b.goutnakeff) {
23656 + gintmsk.b.goutnakeff = 1;
23657 + DWC_WRITE_REG32(&xfer_info->core_if->core_global_regs->gintmsk,
23662 + if (!gintsts.b.goutnakeff) {
23663 + dctl.b.sgoutnak = 1;
23665 + DWC_WRITE_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl,
23670 +void set_pid_isoc(dwc_hc_t * hc)
23672 + /* Set up the initial PID for the transfer. */
23673 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
23674 + if (hc->ep_is_in) {
23675 + if (hc->multi_count == 1) {
23676 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23677 + } else if (hc->multi_count == 2) {
23678 + hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
23680 + hc->data_pid_start = DWC_OTG_HC_PID_DATA2;
23683 + if (hc->multi_count == 1) {
23684 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23686 + hc->data_pid_start = DWC_OTG_HC_PID_MDATA;
23690 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23695 + * This function does the setup for a data transfer for a host channel and
23696 + * starts the transfer. May be called in either Slave mode or DMA mode. In
23697 + * Slave mode, the caller must ensure that there is sufficient space in the
23698 + * request queue and Tx Data FIFO.
23700 + * For an OUT transfer in Slave mode, it loads a data packet into the
23701 + * appropriate FIFO. If necessary, additional data packets will be loaded in
23704 + * For an IN transfer in Slave mode, a data packet is requested. The data
23705 + * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
23706 + * additional data packets are requested in the Host ISR.
23708 + * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
23709 + * register along with a packet count of 1 and the channel is enabled. This
23710 + * causes a single PING transaction to occur. Other fields in HCTSIZ are
23711 + * simply set to 0 since no data transfer occurs in this case.
23713 + * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
23714 + * all the information required to perform the subsequent data transfer. In
23715 + * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
23716 + * controller performs the entire PING protocol, then starts the data
23719 + * @param core_if Programming view of DWC_otg controller.
23720 + * @param hc Information needed to initialize the host channel. The xfer_len
23721 + * value may be reduced to accommodate the max widths of the XferSize and
23722 + * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
23723 + * to reflect the final xfer_len value.
23725 +void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23727 + hcchar_data_t hcchar;
23728 + hctsiz_data_t hctsiz;
23729 + uint16_t num_packets;
23730 + uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
23731 + uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
23732 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23736 + if (hc->do_ping) {
23737 + if (!core_if->dma_enable) {
23738 + dwc_otg_hc_do_ping(core_if, hc);
23739 + hc->xfer_started = 1;
23742 + hctsiz.b.dopng = 1;
23746 + if (hc->do_split) {
23749 + if (hc->complete_split && !hc->ep_is_in) {
23750 + /* For CSPLIT OUT Transfer, set the size to 0 so the
23751 + * core doesn't expect any data written to the FIFO */
23752 + hc->xfer_len = 0;
23753 + } else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
23754 + hc->xfer_len = hc->max_packet;
23755 + } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
23756 + hc->xfer_len = 188;
23759 + hctsiz.b.xfersize = hc->xfer_len;
23762 + * Ensure that the transfer length and packet count will fit
23763 + * in the widths allocated for them in the HCTSIZn register.
23765 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23766 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23768 + * Make sure the transfer size is no larger than one
23769 + * (micro)frame's worth of data. (A check was done
23770 + * when the periodic transfer was accepted to ensure
23771 + * that a (micro)frame's worth of data can be
23772 + * programmed into a channel.)
23774 + uint32_t max_periodic_len =
23775 + hc->multi_count * hc->max_packet;
23776 + if (hc->xfer_len > max_periodic_len) {
23777 + hc->xfer_len = max_periodic_len;
23780 + } else if (hc->xfer_len > max_hc_xfer_size) {
23781 + /* Make sure that xfer_len is a multiple of max packet size. */
23782 + hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
23785 + if (hc->xfer_len > 0) {
23787 + (hc->xfer_len + hc->max_packet -
23788 + 1) / hc->max_packet;
23789 + if (num_packets > max_hc_pkt_count) {
23790 + num_packets = max_hc_pkt_count;
23791 + hc->xfer_len = num_packets * hc->max_packet;
23794 + /* Need 1 packet for transfer length of 0. */
23798 + if (hc->ep_is_in) {
23799 + /* Always program an integral # of max packets for IN transfers. */
23800 + hc->xfer_len = num_packets * hc->max_packet;
23803 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23804 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23806 + * Make sure that the multi_count field matches the
23807 + * actual transfer length.
23809 + hc->multi_count = num_packets;
23812 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23813 + set_pid_isoc(hc);
23815 + hctsiz.b.xfersize = hc->xfer_len;
23818 + hc->start_pkt_count = num_packets;
23819 + hctsiz.b.pktcnt = num_packets;
23820 + hctsiz.b.pid = hc->data_pid_start;
23821 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
23823 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23824 + DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize);
23825 + DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt);
23826 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
23828 + if (core_if->dma_enable) {
23829 + dwc_dma_t dma_addr;
23830 + if (hc->align_buff) {
23831 + dma_addr = hc->align_buff;
23833 + dma_addr = ((unsigned long)hc->xfer_buff & 0xffffffff);
23835 + DWC_WRITE_REG32(&hc_regs->hcdma, dma_addr);
23838 + /* Start the split */
23839 + if (hc->do_split) {
23840 + hcsplt_data_t hcsplt;
23841 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
23842 + hcsplt.b.spltena = 1;
23843 + DWC_WRITE_REG32(&hc_regs->hcsplt, hcsplt.d32);
23846 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23847 + hcchar.b.multicnt = hc->multi_count;
23848 + hc_set_even_odd_frame(core_if, hc, &hcchar);
23850 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
23851 + if (hcchar.b.chdis) {
23852 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
23853 + __func__, hc->hc_num, hcchar.d32);
23857 + /* Set host channel enable after all other setup is complete. */
23858 + hcchar.b.chen = 1;
23859 + hcchar.b.chdis = 0;
23860 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23862 + hc->xfer_started = 1;
23865 + if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
23866 + /* Load OUT packet into the appropriate Tx FIFO. */
23867 + dwc_otg_hc_write_packet(core_if, hc);
23870 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
23871 + DWC_DEBUGPL(DBG_HCDV, "transfer %d from core_if %p\n",
23872 + hc->hc_num, core_if);//GRAYG
23873 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
23874 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
23876 + /* Start a timer for this transfer. */
23877 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
23883 + * This function does the setup for a data transfer for a host channel
23884 + * and starts the transfer in Descriptor DMA mode.
23886 + * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
23887 + * Sets PID and NTD values. For periodic transfers
23888 + * initializes SCHED_INFO field with micro-frame bitmap.
23890 + * Initializes HCDMA register with descriptor list address and CTD value
23891 + * then starts the transfer via enabling the channel.
23893 + * @param core_if Programming view of DWC_otg controller.
23894 + * @param hc Information needed to initialize the host channel.
23896 +void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23898 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23899 + hcchar_data_t hcchar;
23900 + hctsiz_data_t hctsiz;
23901 + hcdma_data_t hcdma;
23906 + hctsiz.b_ddma.dopng = 1;
23908 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23909 + set_pid_isoc(hc);
23911 + /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
23912 + hctsiz.b_ddma.pid = hc->data_pid_start;
23913 + hctsiz.b_ddma.ntd = hc->ntd - 1; /* 0 - 1 descriptor, 1 - 2 descriptors, etc. */
23914 + hctsiz.b_ddma.schinfo = hc->schinfo; /* Non-zero only for high-speed interrupt endpoints */
23916 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23917 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
23918 + DWC_DEBUGPL(DBG_HCDV, " NTD: %d\n", hctsiz.b_ddma.ntd);
23920 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
23923 + hcdma.b.dma_addr = ((uint32_t) hc->desc_list_addr) >> 11;
23925 + /* Always start from first descriptor. */
23927 + DWC_WRITE_REG32(&hc_regs->hcdma, hcdma.d32);
23929 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23930 + hcchar.b.multicnt = hc->multi_count;
23933 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
23934 + if (hcchar.b.chdis) {
23935 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
23936 + __func__, hc->hc_num, hcchar.d32);
23940 + /* Set host channel enable after all other setup is complete. */
23941 + hcchar.b.chen = 1;
23942 + hcchar.b.chdis = 0;
23944 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23946 + hc->xfer_started = 1;
23950 + if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR)
23951 + && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) {
23952 + DWC_DEBUGPL(DBG_HCDV, "DMA transfer %d from core_if %p\n",
23953 + hc->hc_num, core_if);//GRAYG
23954 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
23955 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
23956 + /* Start a timer for this transfer. */
23957 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
23964 + * This function continues a data transfer that was started by previous call
23965 + * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
23966 + * sufficient space in the request queue and Tx Data FIFO. This function
23967 + * should only be called in Slave mode. In DMA mode, the controller acts
23968 + * autonomously to complete transfers programmed to a host channel.
23970 + * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
23971 + * if there is any data remaining to be queued. For an IN transfer, another
23972 + * data packet is always requested. For the SETUP phase of a control transfer,
23973 + * this function does nothing.
23975 + * @return 1 if a new request is queued, 0 if no more requests are required
23976 + * for this transfer.
23978 +int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23980 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23982 + if (hc->do_split) {
23983 + /* SPLITs always queue just once per channel */
23985 + } else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
23986 + /* SETUPs are queued only once since they can't be NAKed. */
23988 + } else if (hc->ep_is_in) {
23990 + * Always queue another request for other IN transfers. If
23991 + * back-to-back INs are issued and NAKs are received for both,
23992 + * the driver may still be processing the first NAK when the
23993 + * second NAK is received. When the interrupt handler clears
23994 + * the NAK interrupt for the first NAK, the second NAK will
23995 + * not be seen. So we can't depend on the NAK interrupt
23996 + * handler to requeue a NAKed request. Instead, IN requests
23997 + * are issued each time this function is called. When the
23998 + * transfer completes, the extra requests for the channel will
24001 + hcchar_data_t hcchar;
24002 + dwc_otg_hc_regs_t *hc_regs =
24003 + core_if->host_if->hc_regs[hc->hc_num];
24005 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24006 + hc_set_even_odd_frame(core_if, hc, &hcchar);
24007 + hcchar.b.chen = 1;
24008 + hcchar.b.chdis = 0;
24009 + DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n",
24011 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24015 + /* OUT transfers. */
24016 + if (hc->xfer_count < hc->xfer_len) {
24017 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
24018 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
24019 + hcchar_data_t hcchar;
24020 + dwc_otg_hc_regs_t *hc_regs;
24021 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
24022 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24023 + hc_set_even_odd_frame(core_if, hc, &hcchar);
24026 + /* Load OUT packet into the appropriate Tx FIFO. */
24027 + dwc_otg_hc_write_packet(core_if, hc);
24037 + * Starts a PING transfer. This function should only be called in Slave mode.
24038 + * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
24040 +void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24042 + hcchar_data_t hcchar;
24043 + hctsiz_data_t hctsiz;
24044 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
24046 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
24049 + hctsiz.b.dopng = 1;
24050 + hctsiz.b.pktcnt = 1;
24051 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
24053 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24054 + hcchar.b.chen = 1;
24055 + hcchar.b.chdis = 0;
24056 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24060 + * This function writes a packet into the Tx FIFO associated with the Host
24061 + * Channel. For a channel associated with a non-periodic EP, the non-periodic
24062 + * Tx FIFO is written. For a channel associated with a periodic EP, the
24063 + * periodic Tx FIFO is written. This function should only be called in Slave
24066 + * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
24067 + * then number of bytes written to the Tx FIFO.
24069 +void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24072 + uint32_t remaining_count;
24073 + uint32_t byte_count;
24074 + uint32_t dword_count;
24076 + uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
24077 + uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
24079 + remaining_count = hc->xfer_len - hc->xfer_count;
24080 + if (remaining_count > hc->max_packet) {
24081 + byte_count = hc->max_packet;
24083 + byte_count = remaining_count;
24086 + dword_count = (byte_count + 3) / 4;
24088 + if ((((unsigned long)data_buff) & 0x3) == 0) {
24089 + /* xfer_buff is DWORD aligned. */
24090 + for (i = 0; i < dword_count; i++, data_buff++) {
24091 + DWC_WRITE_REG32(data_fifo, *data_buff);
24094 + /* xfer_buff is not DWORD aligned. */
24095 + for (i = 0; i < dword_count; i++, data_buff++) {
24098 + (data_buff[0] | data_buff[1] << 8 | data_buff[2] <<
24099 + 16 | data_buff[3] << 24);
24100 + DWC_WRITE_REG32(data_fifo, data);
24104 + hc->xfer_count += byte_count;
24105 + hc->xfer_buff += byte_count;
24109 + * Gets the current USB frame number. This is the frame number from the last
24112 +uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if)
24114 + dsts_data_t dsts;
24115 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
24117 + /* read current frame/microframe number from DSTS register */
24118 + return dsts.b.soffn;
24122 + * Calculates and gets the frame Interval value of HFIR register according PHY
24123 + * type and speed.The application can modify a value of HFIR register only after
24124 + * the Port Enable bit of the Host Port Control and Status register
24125 + * (HPRT.PrtEnaPort) has been set.
24128 +uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if)
24130 + gusbcfg_data_t usbcfg;
24131 + hwcfg2_data_t hwcfg2;
24132 + hprt0_data_t hprt0;
24133 + int clock = 60; // default value
24134 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
24135 + hwcfg2.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
24136 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
24137 + if (!usbcfg.b.physel && usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
24139 + if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 3)
24141 + if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24142 + !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
24144 + if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24145 + !usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
24147 + if (usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24148 + !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
24150 + if (usbcfg.b.physel && !usbcfg.b.phyif && hwcfg2.b.fs_phy_type == 2)
24152 + if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 1)
24154 + if (hprt0.b.prtspd == 0)
24155 + /* High speed case */
24156 + return 125 * clock;
24159 + return 1000 * clock;
24163 + * This function reads a setup packet from the Rx FIFO into the destination
24164 + * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl)
24165 + * Interrupt routine when a SETUP packet has been received in Slave mode.
24167 + * @param core_if Programming view of DWC_otg controller.
24168 + * @param dest Destination buffer for packet data.
24170 +void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest)
24172 + device_grxsts_data_t status;
24173 + /* Get the 8 bytes of a setup transaction data */
24175 + /* Pop 2 DWORDS off the receive data FIFO into memory */
24176 + dest[0] = DWC_READ_REG32(core_if->data_fifo[0]);
24177 + dest[1] = DWC_READ_REG32(core_if->data_fifo[0]);
24178 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
24180 + DWC_READ_REG32(&core_if->core_global_regs->grxstsp);
24181 + DWC_DEBUGPL(DBG_ANY,
24182 + "EP:%d BCnt:%d " "pktsts:%x Frame:%d(0x%0x)\n",
24183 + status.b.epnum, status.b.bcnt, status.b.pktsts,
24184 + status.b.fn, status.b.fn);
24189 + * This function enables EP0 OUT to receive SETUP packets and configures EP0
24190 + * IN for transmitting packets. It is normally called when the
24191 + * "Enumeration Done" interrupt occurs.
24193 + * @param core_if Programming view of DWC_otg controller.
24194 + * @param ep The EP0 data.
24196 +void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24198 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24199 + dsts_data_t dsts;
24200 + depctl_data_t diepctl;
24201 + depctl_data_t doepctl;
24202 + dctl_data_t dctl = {.d32 = 0 };
24204 + ep->stp_rollover = 0;
24205 + /* Read the Device Status and Endpoint 0 Control registers */
24206 + dsts.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dsts);
24207 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
24208 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
24210 + /* Set the MPS of the IN EP based on the enumeration speed */
24211 + switch (dsts.b.enumspd) {
24212 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
24213 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
24214 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
24215 + diepctl.b.mps = DWC_DEP0CTL_MPS_64;
24217 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
24218 + diepctl.b.mps = DWC_DEP0CTL_MPS_8;
24222 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
24224 + /* Enable OUT EP for receive */
24225 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
24226 + doepctl.b.epena = 1;
24227 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
24230 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
24231 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
24232 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
24233 + DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
24235 + dctl.b.cgnpinnak = 1;
24237 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
24238 + DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
24239 + DWC_READ_REG32(&dev_if->dev_global_regs->dctl));
24244 + * This function activates an EP. The Device EP control register for
24245 + * the EP is configured as defined in the ep structure. Note: This
24246 + * function is not used for EP0.
24248 + * @param core_if Programming view of DWC_otg controller.
24249 + * @param ep The EP to activate.
24251 +void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24253 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24254 + depctl_data_t depctl;
24255 + volatile uint32_t *addr;
24256 + daint_data_t daintmsk = {.d32 = 0 };
24257 + dcfg_data_t dcfg;
24260 + DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
24261 + (ep->is_in ? "IN" : "OUT"));
24263 +#ifdef DWC_UTE_PER_IO
24264 + ep->xiso_frame_num = 0xFFFFFFFF;
24265 + ep->xiso_active_xfers = 0;
24266 + ep->xiso_queued_xfers = 0;
24268 + /* Read DEPCTLn register */
24269 + if (ep->is_in == 1) {
24270 + addr = &dev_if->in_ep_regs[ep->num]->diepctl;
24271 + daintmsk.ep.in = 1 << ep->num;
24273 + addr = &dev_if->out_ep_regs[ep->num]->doepctl;
24274 + daintmsk.ep.out = 1 << ep->num;
24277 + /* If the EP is already active don't change the EP Control
24279 + depctl.d32 = DWC_READ_REG32(addr);
24280 + if (!depctl.b.usbactep) {
24281 + depctl.b.mps = ep->maxpacket;
24282 + depctl.b.eptype = ep->type;
24283 + depctl.b.txfnum = ep->tx_fifo_num;
24285 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24286 + depctl.b.setd0pid = 1; // ???
24288 + depctl.b.setd0pid = 1;
24290 + depctl.b.usbactep = 1;
24292 + /* Update nextep_seq array and EPMSCNT in DCFG*/
24293 + if (!(depctl.b.eptype & 1) && (ep->is_in == 1)) { // NP IN EP
24294 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
24295 + if (core_if->nextep_seq[i] == core_if->first_in_nextep_seq)
24298 + core_if->nextep_seq[i] = ep->num;
24299 + core_if->nextep_seq[ep->num] = core_if->first_in_nextep_seq;
24300 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24301 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
24302 + dcfg.b.epmscnt++;
24303 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
24305 + DWC_DEBUGPL(DBG_PCDV,
24306 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
24307 + __func__, core_if->first_in_nextep_seq);
24308 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
24309 + DWC_DEBUGPL(DBG_PCDV, "%2d\n",
24310 + core_if->nextep_seq[i]);
24316 + DWC_WRITE_REG32(addr, depctl.d32);
24317 + DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", DWC_READ_REG32(addr));
24320 + /* Enable the Interrupt for this EP */
24321 + if (core_if->multiproc_int_enable) {
24322 + if (ep->is_in == 1) {
24323 + diepmsk_data_t diepmsk = {.d32 = 0 };
24324 + diepmsk.b.xfercompl = 1;
24325 + diepmsk.b.timeout = 1;
24326 + diepmsk.b.epdisabled = 1;
24327 + diepmsk.b.ahberr = 1;
24328 + diepmsk.b.intknepmis = 1;
24329 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
24330 + diepmsk.b.intknepmis = 0;
24331 + diepmsk.b.txfifoundrn = 1; //?????
24332 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24333 + diepmsk.b.nak = 1;
24339 + if (core_if->dma_desc_enable) {
24340 + diepmsk.b.bna = 1;
24344 + if (core_if->dma_enable) {
24345 + doepmsk.b.nak = 1;
24348 + DWC_WRITE_REG32(&dev_if->dev_global_regs->
24349 + diepeachintmsk[ep->num], diepmsk.d32);
24352 + doepmsk_data_t doepmsk = {.d32 = 0 };
24353 + doepmsk.b.xfercompl = 1;
24354 + doepmsk.b.ahberr = 1;
24355 + doepmsk.b.epdisabled = 1;
24356 + if (ep->type == DWC_OTG_EP_TYPE_ISOC)
24357 + doepmsk.b.outtknepdis = 1;
24361 + if (core_if->dma_desc_enable) {
24362 + doepmsk.b.bna = 1;
24366 + doepmsk.b.babble = 1;
24367 + doepmsk.b.nyet = 1;
24368 + doepmsk.b.nak = 1;
24370 + DWC_WRITE_REG32(&dev_if->dev_global_regs->
24371 + doepeachintmsk[ep->num], doepmsk.d32);
24373 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->deachintmsk,
24374 + 0, daintmsk.d32);
24376 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24378 + diepmsk_data_t diepmsk = {.d32 = 0 };
24379 + diepmsk.b.nak = 1;
24380 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32);
24382 + doepmsk_data_t doepmsk = {.d32 = 0 };
24383 + doepmsk.b.outtknepdis = 1;
24384 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->doepmsk, 0, doepmsk.d32);
24387 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->daintmsk,
24388 + 0, daintmsk.d32);
24391 + DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
24392 + DWC_READ_REG32(&dev_if->dev_global_regs->daintmsk));
24394 + ep->stall_clear_flag = 0;
24400 + * This function deactivates an EP. This is done by clearing the USB Active
24401 + * EP bit in the Device EP control register. Note: This function is not used
24402 + * for EP0. EP0 cannot be deactivated.
24404 + * @param core_if Programming view of DWC_otg controller.
24405 + * @param ep The EP to deactivate.
24407 +void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24409 + depctl_data_t depctl = {.d32 = 0 };
24410 + volatile uint32_t *addr;
24411 + daint_data_t daintmsk = {.d32 = 0 };
24412 + dcfg_data_t dcfg;
24415 +#ifdef DWC_UTE_PER_IO
24416 + ep->xiso_frame_num = 0xFFFFFFFF;
24417 + ep->xiso_active_xfers = 0;
24418 + ep->xiso_queued_xfers = 0;
24421 + /* Read DEPCTLn register */
24422 + if (ep->is_in == 1) {
24423 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
24424 + daintmsk.ep.in = 1 << ep->num;
24426 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
24427 + daintmsk.ep.out = 1 << ep->num;
24430 + depctl.d32 = DWC_READ_REG32(addr);
24432 + depctl.b.usbactep = 0;
24434 + /* Update nextep_seq array and EPMSCNT in DCFG*/
24435 + if (!(depctl.b.eptype & 1) && ep->is_in == 1) { // NP EP IN
24436 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
24437 + if (core_if->nextep_seq[i] == ep->num)
24440 + core_if->nextep_seq[i] = core_if->nextep_seq[ep->num];
24441 + if (core_if->first_in_nextep_seq == ep->num)
24442 + core_if->first_in_nextep_seq = i;
24443 + core_if->nextep_seq[ep->num] = 0xff;
24444 + depctl.b.nextep = 0;
24446 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
24447 + dcfg.b.epmscnt--;
24448 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
24451 + DWC_DEBUGPL(DBG_PCDV,
24452 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
24453 + __func__, core_if->first_in_nextep_seq);
24454 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
24455 + DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
24459 + if (ep->is_in == 1)
24460 + depctl.b.txfnum = 0;
24462 + if (core_if->dma_desc_enable)
24463 + depctl.b.epdis = 1;
24465 + DWC_WRITE_REG32(addr, depctl.d32);
24466 + depctl.d32 = DWC_READ_REG32(addr);
24467 + if (core_if->dma_enable && ep->type == DWC_OTG_EP_TYPE_ISOC
24468 + && depctl.b.epena) {
24469 + depctl_data_t depctl = {.d32 = 0};
24471 + diepint_data_t diepint = {.d32 = 0};
24473 + depctl.b.snak = 1;
24474 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24475 + diepctl, depctl.d32);
24479 + DWC_READ_REG32(&core_if->
24480 + dev_if->in_ep_regs[ep->num]->
24482 + } while (!diepint.b.inepnakeff);
24483 + diepint.b.inepnakeff = 1;
24484 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24485 + diepint, diepint.d32);
24487 + depctl.b.epdis = 1;
24488 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24489 + diepctl, depctl.d32);
24493 + DWC_READ_REG32(&core_if->
24494 + dev_if->in_ep_regs[ep->num]->
24496 + } while (!diepint.b.epdisabled);
24497 + diepint.b.epdisabled = 1;
24498 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24499 + diepint, diepint.d32);
24501 + dctl_data_t dctl = {.d32 = 0};
24502 + gintmsk_data_t gintsts = {.d32 = 0};
24503 + doepint_data_t doepint = {.d32 = 0};
24504 + dctl.b.sgoutnak = 1;
24505 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
24506 + dctl, 0, dctl.d32);
24509 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
24510 + } while (!gintsts.b.goutnakeff);
24512 + gintsts.b.goutnakeff = 1;
24513 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
24516 + depctl.b.epdis = 1;
24517 + depctl.b.snak = 1;
24518 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepctl, depctl.d32);
24522 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
24523 + out_ep_regs[ep->num]->doepint);
24524 + } while (!doepint.b.epdisabled);
24526 + doepint.b.epdisabled = 1;
24527 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepint, doepint.d32);
24530 + dctl.b.cgoutnak = 1;
24531 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
24535 + /* Disable the Interrupt for this EP */
24536 + if (core_if->multiproc_int_enable) {
24537 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
24538 + daintmsk.d32, 0);
24540 + if (ep->is_in == 1) {
24541 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
24542 + diepeachintmsk[ep->num], 0);
24544 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
24545 + doepeachintmsk[ep->num], 0);
24548 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->daintmsk,
24549 + daintmsk.d32, 0);
24555 + * This function initializes dma descriptor chain.
24557 + * @param core_if Programming view of DWC_otg controller.
24558 + * @param ep The EP to start the transfer on.
24560 +static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24562 + dwc_otg_dev_dma_desc_t *dma_desc;
24564 + uint32_t xfer_est;
24566 + unsigned maxxfer_local, total_len;
24568 + if (!ep->is_in && ep->type == DWC_OTG_EP_TYPE_INTR &&
24569 + (ep->maxpacket%4)) {
24570 + maxxfer_local = ep->maxpacket;
24571 + total_len = ep->xfer_len;
24573 + maxxfer_local = ep->maxxfer;
24574 + total_len = ep->total_len;
24577 + ep->desc_cnt = (total_len / maxxfer_local) +
24578 + ((total_len % maxxfer_local) ? 1 : 0);
24580 + if (!ep->desc_cnt)
24581 + ep->desc_cnt = 1;
24583 + if (ep->desc_cnt > MAX_DMA_DESC_CNT)
24584 + ep->desc_cnt = MAX_DMA_DESC_CNT;
24586 + dma_desc = ep->desc_addr;
24587 + if (maxxfer_local == ep->maxpacket) {
24588 + if ((total_len % maxxfer_local) &&
24589 + (total_len/maxxfer_local < MAX_DMA_DESC_CNT)) {
24590 + xfer_est = (ep->desc_cnt - 1) * maxxfer_local +
24591 + (total_len % maxxfer_local);
24593 + xfer_est = ep->desc_cnt * maxxfer_local;
24595 + xfer_est = total_len;
24597 + for (i = 0; i < ep->desc_cnt; ++i) {
24598 + /** DMA Descriptor Setup */
24599 + if (xfer_est > maxxfer_local) {
24600 + dma_desc->status.b.bs = BS_HOST_BUSY;
24601 + dma_desc->status.b.l = 0;
24602 + dma_desc->status.b.ioc = 0;
24603 + dma_desc->status.b.sp = 0;
24604 + dma_desc->status.b.bytes = maxxfer_local;
24605 + dma_desc->buf = ep->dma_addr + offset;
24606 + dma_desc->status.b.sts = 0;
24607 + dma_desc->status.b.bs = BS_HOST_READY;
24609 + xfer_est -= maxxfer_local;
24610 + offset += maxxfer_local;
24612 + dma_desc->status.b.bs = BS_HOST_BUSY;
24613 + dma_desc->status.b.l = 1;
24614 + dma_desc->status.b.ioc = 1;
24616 + dma_desc->status.b.sp =
24618 + ep->maxpacket) ? 1 : ((ep->
24619 + sent_zlp) ? 1 : 0);
24620 + dma_desc->status.b.bytes = xfer_est;
24622 + if (maxxfer_local == ep->maxpacket)
24623 + dma_desc->status.b.bytes = xfer_est;
24625 + dma_desc->status.b.bytes =
24626 + xfer_est + ((4 - (xfer_est & 0x3)) & 0x3);
24629 + dma_desc->buf = ep->dma_addr + offset;
24630 + dma_desc->status.b.sts = 0;
24631 + dma_desc->status.b.bs = BS_HOST_READY;
24637 + * This function is called when to write ISOC data into appropriate dedicated
24640 +static int32_t write_isoc_tx_fifo(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
24642 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24643 + dwc_otg_dev_in_ep_regs_t *ep_regs;
24644 + dtxfsts_data_t txstatus = {.d32 = 0 };
24645 + uint32_t len = 0;
24646 + int epnum = dwc_ep->num;
24649 + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
24651 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
24653 + len = dwc_ep->xfer_len - dwc_ep->xfer_count;
24655 + if (len > dwc_ep->maxpacket) {
24656 + len = dwc_ep->maxpacket;
24659 + dwords = (len + 3) / 4;
24661 + /* While there is space in the queue and space in the FIFO and
24662 + * More data to tranfer, Write packets to the Tx FIFO */
24663 + txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
24664 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
24666 + while (txstatus.b.txfspcavail > dwords &&
24667 + dwc_ep->xfer_count < dwc_ep->xfer_len && dwc_ep->xfer_len != 0) {
24668 + /* Write the FIFO */
24669 + dwc_otg_ep_write_packet(core_if, dwc_ep, 0);
24671 + len = dwc_ep->xfer_len - dwc_ep->xfer_count;
24672 + if (len > dwc_ep->maxpacket) {
24673 + len = dwc_ep->maxpacket;
24676 + dwords = (len + 3) / 4;
24678 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
24679 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
24683 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
24684 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
24689 + * This function does the setup for a data transfer for an EP and
24690 + * starts the transfer. For an IN transfer, the packets will be
24691 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
24692 + * the packets are unloaded from the Rx FIFO in the ISR. the ISR.
24694 + * @param core_if Programming view of DWC_otg controller.
24695 + * @param ep The EP to start the transfer on.
24698 +void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24700 + depctl_data_t depctl;
24701 + deptsiz_data_t deptsiz;
24702 + gintmsk_data_t intr_mask = {.d32 = 0 };
24704 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
24705 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
24706 + "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n",
24707 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
24708 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
24710 + /* IN endpoint */
24711 + if (ep->is_in == 1) {
24712 + dwc_otg_dev_in_ep_regs_t *in_regs =
24713 + core_if->dev_if->in_ep_regs[ep->num];
24715 + gnptxsts_data_t gtxstatus;
24718 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
24720 + if (core_if->en_multiple_tx_fifo == 0
24721 + && gtxstatus.b.nptxqspcavail == 0 && !core_if->dma_enable) {
24723 + DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32);
24728 + depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
24729 + deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
24731 + if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
24732 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
24733 + ep->maxxfer : (ep->total_len - ep->xfer_len);
24735 + ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len - ep->xfer_len)) ?
24736 + MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
24739 + /* Zero Length Packet? */
24740 + if ((ep->xfer_len - ep->xfer_count) == 0) {
24741 + deptsiz.b.xfersize = 0;
24742 + deptsiz.b.pktcnt = 1;
24744 + /* Program the transfer size and packet count
24745 + * as follows: xfersize = N * maxpacket +
24746 + * short_packet pktcnt = N + (short_packet
24749 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
24750 + deptsiz.b.pktcnt =
24751 + (ep->xfer_len - ep->xfer_count - 1 +
24752 + ep->maxpacket) / ep->maxpacket;
24753 + if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
24754 + deptsiz.b.pktcnt = MAX_PKT_CNT;
24755 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
24757 + if (ep->type == DWC_OTG_EP_TYPE_ISOC)
24758 + deptsiz.b.mc = deptsiz.b.pktcnt;
24761 + /* Write the DMA register */
24762 + if (core_if->dma_enable) {
24763 + if (core_if->dma_desc_enable == 0) {
24764 + if (ep->type != DWC_OTG_EP_TYPE_ISOC)
24765 + deptsiz.b.mc = 1;
24766 + DWC_WRITE_REG32(&in_regs->dieptsiz,
24768 + DWC_WRITE_REG32(&(in_regs->diepdma),
24769 + (uint32_t) ep->dma_addr);
24771 +#ifdef DWC_UTE_CFI
24772 + /* The descriptor chain should be already initialized by now */
24773 + if (ep->buff_mode != BM_STANDARD) {
24774 + DWC_WRITE_REG32(&in_regs->diepdma,
24775 + ep->descs_dma_addr);
24778 + init_dma_desc_chain(core_if, ep);
24779 + /** DIEPDMAn Register write */
24780 + DWC_WRITE_REG32(&in_regs->diepdma,
24781 + ep->dma_desc_addr);
24782 +#ifdef DWC_UTE_CFI
24787 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
24788 + if (ep->type != DWC_OTG_EP_TYPE_ISOC) {
24790 + * Enable the Non-Periodic Tx FIFO empty interrupt,
24791 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
24792 + * the data will be written into the fifo by the ISR.
24794 + if (core_if->en_multiple_tx_fifo == 0) {
24795 + intr_mask.b.nptxfempty = 1;
24797 + (&core_if->core_global_regs->gintmsk,
24798 + intr_mask.d32, intr_mask.d32);
24800 + /* Enable the Tx FIFO Empty Interrupt for this EP */
24801 + if (ep->xfer_len > 0) {
24802 + uint32_t fifoemptymsk = 0;
24803 + fifoemptymsk = 1 << ep->num;
24805 + (&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
24806 + 0, fifoemptymsk);
24811 + write_isoc_tx_fifo(core_if, ep);
24814 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
24815 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24817 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24818 + dsts_data_t dsts = {.d32 = 0};
24819 + if (ep->bInterval == 1) {
24821 + DWC_READ_REG32(&core_if->dev_if->
24822 + dev_global_regs->dsts);
24823 + ep->frame_num = dsts.b.soffn + ep->bInterval;
24824 + if (ep->frame_num > 0x3FFF) {
24825 + ep->frm_overrun = 1;
24826 + ep->frame_num &= 0x3FFF;
24828 + ep->frm_overrun = 0;
24829 + if (ep->frame_num & 0x1) {
24830 + depctl.b.setd1pid = 1;
24832 + depctl.b.setd0pid = 1;
24836 + /* EP enable, IN data in FIFO */
24837 + depctl.b.cnak = 1;
24838 + depctl.b.epena = 1;
24839 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
24842 + /* OUT endpoint */
24843 + dwc_otg_dev_out_ep_regs_t *out_regs =
24844 + core_if->dev_if->out_ep_regs[ep->num];
24846 + depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
24847 + deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
24849 + if (!core_if->dma_desc_enable) {
24850 + if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
24851 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
24852 + ep->maxxfer : (ep->total_len - ep->xfer_len);
24854 + ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len
24855 + - ep->xfer_len)) ? MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
24858 + /* Program the transfer size and packet count as follows:
24861 + * xfersize = N * maxpacket
24863 + if ((ep->xfer_len - ep->xfer_count) == 0) {
24864 + /* Zero Length Packet */
24865 + deptsiz.b.xfersize = ep->maxpacket;
24866 + deptsiz.b.pktcnt = 1;
24868 + deptsiz.b.pktcnt =
24869 + (ep->xfer_len - ep->xfer_count +
24870 + (ep->maxpacket - 1)) / ep->maxpacket;
24871 + if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
24872 + deptsiz.b.pktcnt = MAX_PKT_CNT;
24874 + if (!core_if->dma_desc_enable) {
24876 + deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count;
24878 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
24881 + DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
24882 + ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
24884 + if (core_if->dma_enable) {
24885 + if (!core_if->dma_desc_enable) {
24886 + DWC_WRITE_REG32(&out_regs->doeptsiz,
24889 + DWC_WRITE_REG32(&(out_regs->doepdma),
24890 + (uint32_t) ep->dma_addr);
24892 +#ifdef DWC_UTE_CFI
24893 + /* The descriptor chain should be already initialized by now */
24894 + if (ep->buff_mode != BM_STANDARD) {
24895 + DWC_WRITE_REG32(&out_regs->doepdma,
24896 + ep->descs_dma_addr);
24899 + /** This is used for interrupt out transfers*/
24900 + if (!ep->xfer_len)
24901 + ep->xfer_len = ep->total_len;
24902 + init_dma_desc_chain(core_if, ep);
24904 + if (core_if->core_params->dev_out_nak) {
24905 + if (ep->type == DWC_OTG_EP_TYPE_BULK) {
24906 + deptsiz.b.pktcnt = (ep->total_len +
24907 + (ep->maxpacket - 1)) / ep->maxpacket;
24908 + deptsiz.b.xfersize = ep->total_len;
24909 + /* Remember initial value of doeptsiz */
24910 + core_if->start_doeptsiz_val[ep->num] = deptsiz.d32;
24911 + DWC_WRITE_REG32(&out_regs->doeptsiz,
24915 + /** DOEPDMAn Register write */
24916 + DWC_WRITE_REG32(&out_regs->doepdma,
24917 + ep->dma_desc_addr);
24918 +#ifdef DWC_UTE_CFI
24923 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
24926 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24927 + dsts_data_t dsts = {.d32 = 0};
24928 + if (ep->bInterval == 1) {
24930 + DWC_READ_REG32(&core_if->dev_if->
24931 + dev_global_regs->dsts);
24932 + ep->frame_num = dsts.b.soffn + ep->bInterval;
24933 + if (ep->frame_num > 0x3FFF) {
24934 + ep->frm_overrun = 1;
24935 + ep->frame_num &= 0x3FFF;
24937 + ep->frm_overrun = 0;
24939 + if (ep->frame_num & 0x1) {
24940 + depctl.b.setd1pid = 1;
24942 + depctl.b.setd0pid = 1;
24948 + depctl.b.cnak = 1;
24949 + depctl.b.epena = 1;
24951 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
24953 + DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
24954 + DWC_READ_REG32(&out_regs->doepctl),
24955 + DWC_READ_REG32(&out_regs->doeptsiz));
24956 + DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
24957 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
24959 + DWC_READ_REG32(&core_if->core_global_regs->
24962 + /* Timer is scheduling only for out bulk transfers for
24963 + * "Device DDMA OUT NAK Enhancement" feature to inform user
24964 + * about received data payload in case of timeout
24966 + if (core_if->core_params->dev_out_nak) {
24967 + if (ep->type == DWC_OTG_EP_TYPE_BULK) {
24968 + core_if->ep_xfer_info[ep->num].core_if = core_if;
24969 + core_if->ep_xfer_info[ep->num].ep = ep;
24970 + core_if->ep_xfer_info[ep->num].state = 1;
24972 + /* Start a timer for this transfer. */
24973 + DWC_TIMER_SCHEDULE(core_if->ep_xfer_timer[ep->num], 10000);
24980 + * This function setup a zero length transfer in Buffer DMA and
24981 + * Slave modes for usb requests with zero field set
24983 + * @param core_if Programming view of DWC_otg controller.
24984 + * @param ep The EP to start the transfer on.
24987 +void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24990 + depctl_data_t depctl;
24991 + deptsiz_data_t deptsiz;
24992 + gintmsk_data_t intr_mask = {.d32 = 0 };
24994 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
24995 + DWC_PRINTF("zero length transfer is called\n");
24997 + /* IN endpoint */
24998 + if (ep->is_in == 1) {
24999 + dwc_otg_dev_in_ep_regs_t *in_regs =
25000 + core_if->dev_if->in_ep_regs[ep->num];
25002 + depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
25003 + deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
25005 + deptsiz.b.xfersize = 0;
25006 + deptsiz.b.pktcnt = 1;
25008 + /* Write the DMA register */
25009 + if (core_if->dma_enable) {
25010 + if (core_if->dma_desc_enable == 0) {
25011 + deptsiz.b.mc = 1;
25012 + DWC_WRITE_REG32(&in_regs->dieptsiz,
25014 + DWC_WRITE_REG32(&(in_regs->diepdma),
25015 + (uint32_t) ep->dma_addr);
25018 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25020 + * Enable the Non-Periodic Tx FIFO empty interrupt,
25021 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
25022 + * the data will be written into the fifo by the ISR.
25024 + if (core_if->en_multiple_tx_fifo == 0) {
25025 + intr_mask.b.nptxfempty = 1;
25026 + DWC_MODIFY_REG32(&core_if->
25027 + core_global_regs->gintmsk,
25028 + intr_mask.d32, intr_mask.d32);
25030 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25031 + if (ep->xfer_len > 0) {
25032 + uint32_t fifoemptymsk = 0;
25033 + fifoemptymsk = 1 << ep->num;
25034 + DWC_MODIFY_REG32(&core_if->
25035 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25036 + 0, fifoemptymsk);
25041 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25042 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25043 + /* EP enable, IN data in FIFO */
25044 + depctl.b.cnak = 1;
25045 + depctl.b.epena = 1;
25046 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25049 + /* OUT endpoint */
25050 + dwc_otg_dev_out_ep_regs_t *out_regs =
25051 + core_if->dev_if->out_ep_regs[ep->num];
25053 + depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
25054 + deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
25056 + /* Zero Length Packet */
25057 + deptsiz.b.xfersize = ep->maxpacket;
25058 + deptsiz.b.pktcnt = 1;
25060 + if (core_if->dma_enable) {
25061 + if (!core_if->dma_desc_enable) {
25062 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25065 + DWC_WRITE_REG32(&(out_regs->doepdma),
25066 + (uint32_t) ep->dma_addr);
25069 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25073 + depctl.b.cnak = 1;
25074 + depctl.b.epena = 1;
25076 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
25082 + * This function does the setup for a data transfer for EP0 and starts
25083 + * the transfer. For an IN transfer, the packets will be loaded into
25084 + * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
25085 + * unloaded from the Rx FIFO in the ISR.
25087 + * @param core_if Programming view of DWC_otg controller.
25088 + * @param ep The EP0 data.
25090 +void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25092 + depctl_data_t depctl;
25093 + deptsiz0_data_t deptsiz;
25094 + gintmsk_data_t intr_mask = {.d32 = 0 };
25095 + dwc_otg_dev_dma_desc_t *dma_desc;
25097 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
25098 + "xfer_buff=%p start_xfer_buff=%p \n",
25099 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
25100 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
25102 + ep->total_len = ep->xfer_len;
25104 + /* IN endpoint */
25105 + if (ep->is_in == 1) {
25106 + dwc_otg_dev_in_ep_regs_t *in_regs =
25107 + core_if->dev_if->in_ep_regs[0];
25109 + gnptxsts_data_t gtxstatus;
25111 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
25112 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25113 + if (depctl.b.epena)
25118 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
25120 + /* If dedicated FIFO every time flush fifo before enable ep*/
25121 + if (core_if->en_multiple_tx_fifo && core_if->snpsid >= OTG_CORE_REV_3_00a)
25122 + dwc_otg_flush_tx_fifo(core_if, ep->tx_fifo_num);
25124 + if (core_if->en_multiple_tx_fifo == 0
25125 + && gtxstatus.b.nptxqspcavail == 0
25126 + && !core_if->dma_enable) {
25128 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25129 + DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
25130 + DWC_READ_REG32(&in_regs->diepctl));
25131 + DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
25133 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
25134 + DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n",
25140 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25141 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25143 + /* Zero Length Packet? */
25144 + if (ep->xfer_len == 0) {
25145 + deptsiz.b.xfersize = 0;
25146 + deptsiz.b.pktcnt = 1;
25148 + /* Program the transfer size and packet count
25149 + * as follows: xfersize = N * maxpacket +
25150 + * short_packet pktcnt = N + (short_packet
25153 + if (ep->xfer_len > ep->maxpacket) {
25154 + ep->xfer_len = ep->maxpacket;
25155 + deptsiz.b.xfersize = ep->maxpacket;
25157 + deptsiz.b.xfersize = ep->xfer_len;
25159 + deptsiz.b.pktcnt = 1;
25162 + DWC_DEBUGPL(DBG_PCDV,
25163 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25164 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25167 + /* Write the DMA register */
25168 + if (core_if->dma_enable) {
25169 + if (core_if->dma_desc_enable == 0) {
25170 + DWC_WRITE_REG32(&in_regs->dieptsiz,
25173 + DWC_WRITE_REG32(&(in_regs->diepdma),
25174 + (uint32_t) ep->dma_addr);
25176 + dma_desc = core_if->dev_if->in_desc_addr;
25178 + /** DMA Descriptor Setup */
25179 + dma_desc->status.b.bs = BS_HOST_BUSY;
25180 + dma_desc->status.b.l = 1;
25181 + dma_desc->status.b.ioc = 1;
25182 + dma_desc->status.b.sp =
25183 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
25184 + dma_desc->status.b.bytes = ep->xfer_len;
25185 + dma_desc->buf = ep->dma_addr;
25186 + dma_desc->status.b.sts = 0;
25187 + dma_desc->status.b.bs = BS_HOST_READY;
25189 + /** DIEPDMA0 Register write */
25190 + DWC_WRITE_REG32(&in_regs->diepdma,
25192 + dev_if->dma_in_desc_addr);
25195 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25198 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25199 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25200 + /* EP enable, IN data in FIFO */
25201 + depctl.b.cnak = 1;
25202 + depctl.b.epena = 1;
25203 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25206 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
25207 + * data will be written into the fifo by the ISR.
25209 + if (!core_if->dma_enable) {
25210 + if (core_if->en_multiple_tx_fifo == 0) {
25211 + intr_mask.b.nptxfempty = 1;
25212 + DWC_MODIFY_REG32(&core_if->
25213 + core_global_regs->gintmsk,
25214 + intr_mask.d32, intr_mask.d32);
25216 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25217 + if (ep->xfer_len > 0) {
25218 + uint32_t fifoemptymsk = 0;
25219 + fifoemptymsk |= 1 << ep->num;
25220 + DWC_MODIFY_REG32(&core_if->
25221 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25222 + 0, fifoemptymsk);
25227 + /* OUT endpoint */
25228 + dwc_otg_dev_out_ep_regs_t *out_regs =
25229 + core_if->dev_if->out_ep_regs[0];
25231 + depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
25232 + deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
25234 + /* Program the transfer size and packet count as follows:
25235 + * xfersize = N * (maxpacket + 4 - (maxpacket % 4))
25237 + /* Zero Length Packet */
25238 + deptsiz.b.xfersize = ep->maxpacket;
25239 + deptsiz.b.pktcnt = 1;
25240 + if (core_if->snpsid >= OTG_CORE_REV_3_00a)
25241 + deptsiz.b.supcnt = 3;
25243 + DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n",
25244 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);
25246 + if (core_if->dma_enable) {
25247 + if (!core_if->dma_desc_enable) {
25248 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25251 + DWC_WRITE_REG32(&(out_regs->doepdma),
25252 + (uint32_t) ep->dma_addr);
25254 + dma_desc = core_if->dev_if->out_desc_addr;
25256 + /** DMA Descriptor Setup */
25257 + dma_desc->status.b.bs = BS_HOST_BUSY;
25258 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
25259 + dma_desc->status.b.mtrf = 0;
25260 + dma_desc->status.b.sr = 0;
25262 + dma_desc->status.b.l = 1;
25263 + dma_desc->status.b.ioc = 1;
25264 + dma_desc->status.b.bytes = ep->maxpacket;
25265 + dma_desc->buf = ep->dma_addr;
25266 + dma_desc->status.b.sts = 0;
25267 + dma_desc->status.b.bs = BS_HOST_READY;
25269 + /** DOEPDMA0 Register write */
25270 + DWC_WRITE_REG32(&out_regs->doepdma,
25271 + core_if->dev_if->
25272 + dma_out_desc_addr);
25275 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25279 + depctl.b.cnak = 1;
25280 + depctl.b.epena = 1;
25281 + DWC_WRITE_REG32(&(out_regs->doepctl), depctl.d32);
25286 + * This function continues control IN transfers started by
25287 + * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
25288 + * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
25289 + * bit for the packet count.
25291 + * @param core_if Programming view of DWC_otg controller.
25292 + * @param ep The EP0 data.
25294 +void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25296 + depctl_data_t depctl;
25297 + deptsiz0_data_t deptsiz;
25298 + gintmsk_data_t intr_mask = {.d32 = 0 };
25299 + dwc_otg_dev_dma_desc_t *dma_desc;
25301 + if (ep->is_in == 1) {
25302 + dwc_otg_dev_in_ep_regs_t *in_regs =
25303 + core_if->dev_if->in_ep_regs[0];
25304 + gnptxsts_data_t tx_status = {.d32 = 0 };
25307 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
25308 + /** @todo Should there be check for room in the Tx
25309 + * Status Queue. If not remove the code above this comment. */
25311 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25312 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25314 + /* Program the transfer size and packet count
25315 + * as follows: xfersize = N * maxpacket +
25316 + * short_packet pktcnt = N + (short_packet
25320 + if (core_if->dma_desc_enable == 0) {
25321 + deptsiz.b.xfersize =
25322 + (ep->total_len - ep->xfer_count) >
25323 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
25325 + deptsiz.b.pktcnt = 1;
25326 + if (core_if->dma_enable == 0) {
25327 + ep->xfer_len += deptsiz.b.xfersize;
25329 + ep->xfer_len = deptsiz.b.xfersize;
25331 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25334 + (ep->total_len - ep->xfer_count) >
25335 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
25338 + dma_desc = core_if->dev_if->in_desc_addr;
25340 + /** DMA Descriptor Setup */
25341 + dma_desc->status.b.bs = BS_HOST_BUSY;
25342 + dma_desc->status.b.l = 1;
25343 + dma_desc->status.b.ioc = 1;
25344 + dma_desc->status.b.sp =
25345 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
25346 + dma_desc->status.b.bytes = ep->xfer_len;
25347 + dma_desc->buf = ep->dma_addr;
25348 + dma_desc->status.b.sts = 0;
25349 + dma_desc->status.b.bs = BS_HOST_READY;
25351 + /** DIEPDMA0 Register write */
25352 + DWC_WRITE_REG32(&in_regs->diepdma,
25353 + core_if->dev_if->dma_in_desc_addr);
25356 + DWC_DEBUGPL(DBG_PCDV,
25357 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25358 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25361 + /* Write the DMA register */
25362 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
25363 + if (core_if->dma_desc_enable == 0)
25364 + DWC_WRITE_REG32(&(in_regs->diepdma),
25365 + (uint32_t) ep->dma_addr);
25367 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25368 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25369 + /* EP enable, IN data in FIFO */
25370 + depctl.b.cnak = 1;
25371 + depctl.b.epena = 1;
25372 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25375 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
25376 + * data will be written into the fifo by the ISR.
25378 + if (!core_if->dma_enable) {
25379 + if (core_if->en_multiple_tx_fifo == 0) {
25380 + /* First clear it from GINTSTS */
25381 + intr_mask.b.nptxfempty = 1;
25382 + DWC_MODIFY_REG32(&core_if->
25383 + core_global_regs->gintmsk,
25384 + intr_mask.d32, intr_mask.d32);
25387 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25388 + if (ep->xfer_len > 0) {
25389 + uint32_t fifoemptymsk = 0;
25390 + fifoemptymsk |= 1 << ep->num;
25391 + DWC_MODIFY_REG32(&core_if->
25392 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25393 + 0, fifoemptymsk);
25398 + dwc_otg_dev_out_ep_regs_t *out_regs =
25399 + core_if->dev_if->out_ep_regs[0];
25401 + depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
25402 + deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
25404 + /* Program the transfer size and packet count
25405 + * as follows: xfersize = N * maxpacket +
25406 + * short_packet pktcnt = N + (short_packet
25409 + deptsiz.b.xfersize = ep->maxpacket;
25410 + deptsiz.b.pktcnt = 1;
25412 + if (core_if->dma_desc_enable == 0) {
25413 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25415 + dma_desc = core_if->dev_if->out_desc_addr;
25417 + /** DMA Descriptor Setup */
25418 + dma_desc->status.b.bs = BS_HOST_BUSY;
25419 + dma_desc->status.b.l = 1;
25420 + dma_desc->status.b.ioc = 1;
25421 + dma_desc->status.b.bytes = ep->maxpacket;
25422 + dma_desc->buf = ep->dma_addr;
25423 + dma_desc->status.b.sts = 0;
25424 + dma_desc->status.b.bs = BS_HOST_READY;
25426 + /** DOEPDMA0 Register write */
25427 + DWC_WRITE_REG32(&out_regs->doepdma,
25428 + core_if->dev_if->dma_out_desc_addr);
25431 + DWC_DEBUGPL(DBG_PCDV,
25432 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25433 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25436 + /* Write the DMA register */
25437 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
25438 + if (core_if->dma_desc_enable == 0)
25439 + DWC_WRITE_REG32(&(out_regs->doepdma),
25440 + (uint32_t) ep->dma_addr);
25444 + /* EP enable, IN data in FIFO */
25445 + depctl.b.cnak = 1;
25446 + depctl.b.epena = 1;
25447 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
25453 +void dump_msg(const u8 * buf, unsigned int length)
25455 + unsigned int start, num, i;
25456 + char line[52], *p;
25458 + if (length >= 512)
25461 + while (length > 0) {
25462 + num = length < 16u ? length : 16u;
25464 + for (i = 0; i < num; ++i) {
25467 + DWC_SPRINTF(p, " %02x", buf[i]);
25471 + DWC_PRINTF("%6x: %s\n", start, line);
25478 +static inline void dump_msg(const u8 * buf, unsigned int length)
25484 + * This function writes a packet into the Tx FIFO associated with the
25485 + * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For
25486 + * periodic EPs the periodic Tx FIFO associated with the EP is written
25487 + * with all packets for the next micro-frame.
25489 + * @param core_if Programming view of DWC_otg controller.
25490 + * @param ep The EP to write packet for.
25491 + * @param dma Indicates if DMA is being used.
25493 +void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep,
25497 + * The buffer is padded to DWORD on a per packet basis in
25498 + * slave/dma mode if the MPS is not DWORD aligned. The last
25499 + * packet, if short, is also padded to a multiple of DWORD.
25501 + * ep->xfer_buff always starts DWORD aligned in memory and is a
25502 + * multiple of DWORD in length
25504 + * ep->xfer_len can be any number of bytes
25506 + * ep->xfer_count is a multiple of ep->maxpacket until the last
25509 + * FIFO access is DWORD */
25512 + uint32_t byte_count;
25513 + uint32_t dword_count;
25515 + uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
25517 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if,
25519 + if (ep->xfer_count >= ep->xfer_len) {
25520 + DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
25524 + /* Find the byte length of the packet either short packet or MPS */
25525 + if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) {
25526 + byte_count = ep->xfer_len - ep->xfer_count;
25528 + byte_count = ep->maxpacket;
25531 + /* Find the DWORD length, padded by extra bytes as neccessary if MPS
25532 + * is not a multiple of DWORD */
25533 + dword_count = (byte_count + 3) / 4;
25536 + dump_msg(ep->xfer_buff, byte_count);
25539 + /**@todo NGS Where are the Periodic Tx FIFO addresses
25540 + * intialized? What should this be? */
25542 + fifo = core_if->data_fifo[ep->num];
25544 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
25545 + fifo, data_buff, *data_buff, byte_count);
25548 + for (i = 0; i < dword_count; i++, data_buff++) {
25549 + DWC_WRITE_REG32(fifo, *data_buff);
25553 + ep->xfer_count += byte_count;
25554 + ep->xfer_buff += byte_count;
25555 + ep->dma_addr += byte_count;
25559 + * Set the EP STALL.
25561 + * @param core_if Programming view of DWC_otg controller.
25562 + * @param ep The EP to set the stall on.
25564 +void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25566 + depctl_data_t depctl;
25567 + volatile uint32_t *depctl_addr;
25569 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
25570 + (ep->is_in ? "IN" : "OUT"));
25572 + if (ep->is_in == 1) {
25573 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
25574 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25576 + /* set the disable and stall bits */
25577 + if (depctl.b.epena) {
25578 + depctl.b.epdis = 1;
25580 + depctl.b.stall = 1;
25581 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25583 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
25584 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25586 + /* set the stall bit */
25587 + depctl.b.stall = 1;
25588 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25591 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
25597 + * Clear the EP STALL.
25599 + * @param core_if Programming view of DWC_otg controller.
25600 + * @param ep The EP to clear stall from.
25602 +void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25604 + depctl_data_t depctl;
25605 + volatile uint32_t *depctl_addr;
25607 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
25608 + (ep->is_in ? "IN" : "OUT"));
25610 + if (ep->is_in == 1) {
25611 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
25613 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
25616 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25618 + /* clear the stall bits */
25619 + depctl.b.stall = 0;
25622 + * USB Spec 9.4.5: For endpoints using data toggle, regardless
25623 + * of whether an endpoint has the Halt feature set, a
25624 + * ClearFeature(ENDPOINT_HALT) request always results in the
25625 + * data toggle being reinitialized to DATA0.
25627 + if (ep->type == DWC_OTG_EP_TYPE_INTR ||
25628 + ep->type == DWC_OTG_EP_TYPE_BULK) {
25629 + depctl.b.setd0pid = 1; /* DATA0 */
25632 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25633 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
25638 + * This function reads a packet from the Rx FIFO into the destination
25639 + * buffer. To read SETUP data use dwc_otg_read_setup_packet.
25641 + * @param core_if Programming view of DWC_otg controller.
25642 + * @param dest Destination buffer for the packet.
25643 + * @param bytes Number of bytes to copy to the destination.
25645 +void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
25646 + uint8_t * dest, uint16_t bytes)
25649 + int word_count = (bytes + 3) / 4;
25651 + volatile uint32_t *fifo = core_if->data_fifo[0];
25652 + uint32_t *data_buff = (uint32_t *) dest;
25655 + * @todo Account for the case where _dest is not dword aligned. This
25656 + * requires reading data from the FIFO into a uint32_t temp buffer,
25657 + * then moving it into the data buffer.
25660 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
25661 + core_if, dest, bytes);
25663 + for (i = 0; i < word_count; i++, data_buff++) {
25664 + *data_buff = DWC_READ_REG32(fifo);
25671 + * This functions reads the device registers and prints them
25673 + * @param core_if Programming view of DWC_otg controller.
25675 +void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if)
25678 + volatile uint32_t *addr;
25680 + DWC_PRINTF("Device Global Registers\n");
25681 + addr = &core_if->dev_if->dev_global_regs->dcfg;
25682 + DWC_PRINTF("DCFG @0x%08lX : 0x%08X\n",
25683 + (unsigned long)addr, DWC_READ_REG32(addr));
25684 + addr = &core_if->dev_if->dev_global_regs->dctl;
25685 + DWC_PRINTF("DCTL @0x%08lX : 0x%08X\n",
25686 + (unsigned long)addr, DWC_READ_REG32(addr));
25687 + addr = &core_if->dev_if->dev_global_regs->dsts;
25688 + DWC_PRINTF("DSTS @0x%08lX : 0x%08X\n",
25689 + (unsigned long)addr, DWC_READ_REG32(addr));
25690 + addr = &core_if->dev_if->dev_global_regs->diepmsk;
25691 + DWC_PRINTF("DIEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25692 + DWC_READ_REG32(addr));
25693 + addr = &core_if->dev_if->dev_global_regs->doepmsk;
25694 + DWC_PRINTF("DOEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25695 + DWC_READ_REG32(addr));
25696 + addr = &core_if->dev_if->dev_global_regs->daint;
25697 + DWC_PRINTF("DAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
25698 + DWC_READ_REG32(addr));
25699 + addr = &core_if->dev_if->dev_global_regs->daintmsk;
25700 + DWC_PRINTF("DAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25701 + DWC_READ_REG32(addr));
25702 + addr = &core_if->dev_if->dev_global_regs->dtknqr1;
25703 + DWC_PRINTF("DTKNQR1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25704 + DWC_READ_REG32(addr));
25705 + if (core_if->hwcfg2.b.dev_token_q_depth > 6) {
25706 + addr = &core_if->dev_if->dev_global_regs->dtknqr2;
25707 + DWC_PRINTF("DTKNQR2 @0x%08lX : 0x%08X\n",
25708 + (unsigned long)addr, DWC_READ_REG32(addr));
25711 + addr = &core_if->dev_if->dev_global_regs->dvbusdis;
25712 + DWC_PRINTF("DVBUSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
25713 + DWC_READ_REG32(addr));
25715 + addr = &core_if->dev_if->dev_global_regs->dvbuspulse;
25716 + DWC_PRINTF("DVBUSPULSE @0x%08lX : 0x%08X\n",
25717 + (unsigned long)addr, DWC_READ_REG32(addr));
25719 + addr = &core_if->dev_if->dev_global_regs->dtknqr3_dthrctl;
25720 + DWC_PRINTF("DTKNQR3_DTHRCTL @0x%08lX : 0x%08X\n",
25721 + (unsigned long)addr, DWC_READ_REG32(addr));
25723 + if (core_if->hwcfg2.b.dev_token_q_depth > 22) {
25724 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
25725 + DWC_PRINTF("DTKNQR4 @0x%08lX : 0x%08X\n",
25726 + (unsigned long)addr, DWC_READ_REG32(addr));
25729 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
25730 + DWC_PRINTF("FIFOEMPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25731 + DWC_READ_REG32(addr));
25733 + if (core_if->hwcfg2.b.multi_proc_int) {
25735 + addr = &core_if->dev_if->dev_global_regs->deachint;
25736 + DWC_PRINTF("DEACHINT @0x%08lX : 0x%08X\n",
25737 + (unsigned long)addr, DWC_READ_REG32(addr));
25738 + addr = &core_if->dev_if->dev_global_regs->deachintmsk;
25739 + DWC_PRINTF("DEACHINTMSK @0x%08lX : 0x%08X\n",
25740 + (unsigned long)addr, DWC_READ_REG32(addr));
25742 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
25744 + &core_if->dev_if->
25745 + dev_global_regs->diepeachintmsk[i];
25746 + DWC_PRINTF("DIEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
25747 + i, (unsigned long)addr,
25748 + DWC_READ_REG32(addr));
25751 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
25753 + &core_if->dev_if->
25754 + dev_global_regs->doepeachintmsk[i];
25755 + DWC_PRINTF("DOEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
25756 + i, (unsigned long)addr,
25757 + DWC_READ_REG32(addr));
25761 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
25762 + DWC_PRINTF("Device IN EP %d Registers\n", i);
25763 + addr = &core_if->dev_if->in_ep_regs[i]->diepctl;
25764 + DWC_PRINTF("DIEPCTL @0x%08lX : 0x%08X\n",
25765 + (unsigned long)addr, DWC_READ_REG32(addr));
25766 + addr = &core_if->dev_if->in_ep_regs[i]->diepint;
25767 + DWC_PRINTF("DIEPINT @0x%08lX : 0x%08X\n",
25768 + (unsigned long)addr, DWC_READ_REG32(addr));
25769 + addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz;
25770 + DWC_PRINTF("DIETSIZ @0x%08lX : 0x%08X\n",
25771 + (unsigned long)addr, DWC_READ_REG32(addr));
25772 + addr = &core_if->dev_if->in_ep_regs[i]->diepdma;
25773 + DWC_PRINTF("DIEPDMA @0x%08lX : 0x%08X\n",
25774 + (unsigned long)addr, DWC_READ_REG32(addr));
25775 + addr = &core_if->dev_if->in_ep_regs[i]->dtxfsts;
25776 + DWC_PRINTF("DTXFSTS @0x%08lX : 0x%08X\n",
25777 + (unsigned long)addr, DWC_READ_REG32(addr));
25778 + addr = &core_if->dev_if->in_ep_regs[i]->diepdmab;
25779 + DWC_PRINTF("DIEPDMAB @0x%08lX : 0x%08X\n",
25780 + (unsigned long)addr, 0 /*DWC_READ_REG32(addr) */ );
25783 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
25784 + DWC_PRINTF("Device OUT EP %d Registers\n", i);
25785 + addr = &core_if->dev_if->out_ep_regs[i]->doepctl;
25786 + DWC_PRINTF("DOEPCTL @0x%08lX : 0x%08X\n",
25787 + (unsigned long)addr, DWC_READ_REG32(addr));
25788 + addr = &core_if->dev_if->out_ep_regs[i]->doepint;
25789 + DWC_PRINTF("DOEPINT @0x%08lX : 0x%08X\n",
25790 + (unsigned long)addr, DWC_READ_REG32(addr));
25791 + addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz;
25792 + DWC_PRINTF("DOETSIZ @0x%08lX : 0x%08X\n",
25793 + (unsigned long)addr, DWC_READ_REG32(addr));
25794 + addr = &core_if->dev_if->out_ep_regs[i]->doepdma;
25795 + DWC_PRINTF("DOEPDMA @0x%08lX : 0x%08X\n",
25796 + (unsigned long)addr, DWC_READ_REG32(addr));
25797 + if (core_if->dma_enable) { /* Don't access this register in SLAVE mode */
25798 + addr = &core_if->dev_if->out_ep_regs[i]->doepdmab;
25799 + DWC_PRINTF("DOEPDMAB @0x%08lX : 0x%08X\n",
25800 + (unsigned long)addr, DWC_READ_REG32(addr));
25807 + * This functions reads the SPRAM and prints its content
25809 + * @param core_if Programming view of DWC_otg controller.
25811 +void dwc_otg_dump_spram(dwc_otg_core_if_t * core_if)
25813 + volatile uint8_t *addr, *start_addr, *end_addr;
25815 + DWC_PRINTF("SPRAM Data:\n");
25816 + start_addr = (void *)core_if->core_global_regs;
25817 + DWC_PRINTF("Base Address: 0x%8lX\n", (unsigned long)start_addr);
25818 + start_addr += 0x00028000;
25819 + end_addr = (void *)core_if->core_global_regs;
25820 + end_addr += 0x000280e0;
25822 + for (addr = start_addr; addr < end_addr; addr += 16) {
25824 + ("0x%8lX:\t%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n",
25825 + (unsigned long)addr, addr[0], addr[1], addr[2], addr[3],
25826 + addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
25827 + addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]
25835 + * This function reads the host registers and prints them
25837 + * @param core_if Programming view of DWC_otg controller.
25839 +void dwc_otg_dump_host_registers(dwc_otg_core_if_t * core_if)
25842 + volatile uint32_t *addr;
25844 + DWC_PRINTF("Host Global Registers\n");
25845 + addr = &core_if->host_if->host_global_regs->hcfg;
25846 + DWC_PRINTF("HCFG @0x%08lX : 0x%08X\n",
25847 + (unsigned long)addr, DWC_READ_REG32(addr));
25848 + addr = &core_if->host_if->host_global_regs->hfir;
25849 + DWC_PRINTF("HFIR @0x%08lX : 0x%08X\n",
25850 + (unsigned long)addr, DWC_READ_REG32(addr));
25851 + addr = &core_if->host_if->host_global_regs->hfnum;
25852 + DWC_PRINTF("HFNUM @0x%08lX : 0x%08X\n", (unsigned long)addr,
25853 + DWC_READ_REG32(addr));
25854 + addr = &core_if->host_if->host_global_regs->hptxsts;
25855 + DWC_PRINTF("HPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
25856 + DWC_READ_REG32(addr));
25857 + addr = &core_if->host_if->host_global_regs->haint;
25858 + DWC_PRINTF("HAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
25859 + DWC_READ_REG32(addr));
25860 + addr = &core_if->host_if->host_global_regs->haintmsk;
25861 + DWC_PRINTF("HAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25862 + DWC_READ_REG32(addr));
25863 + if (core_if->dma_desc_enable) {
25864 + addr = &core_if->host_if->host_global_regs->hflbaddr;
25865 + DWC_PRINTF("HFLBADDR @0x%08lX : 0x%08X\n",
25866 + (unsigned long)addr, DWC_READ_REG32(addr));
25869 + addr = core_if->host_if->hprt0;
25870 + DWC_PRINTF("HPRT0 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25871 + DWC_READ_REG32(addr));
25873 + for (i = 0; i < core_if->core_params->host_channels; i++) {
25874 + DWC_PRINTF("Host Channel %d Specific Registers\n", i);
25875 + addr = &core_if->host_if->hc_regs[i]->hcchar;
25876 + DWC_PRINTF("HCCHAR @0x%08lX : 0x%08X\n",
25877 + (unsigned long)addr, DWC_READ_REG32(addr));
25878 + addr = &core_if->host_if->hc_regs[i]->hcsplt;
25879 + DWC_PRINTF("HCSPLT @0x%08lX : 0x%08X\n",
25880 + (unsigned long)addr, DWC_READ_REG32(addr));
25881 + addr = &core_if->host_if->hc_regs[i]->hcint;
25882 + DWC_PRINTF("HCINT @0x%08lX : 0x%08X\n",
25883 + (unsigned long)addr, DWC_READ_REG32(addr));
25884 + addr = &core_if->host_if->hc_regs[i]->hcintmsk;
25885 + DWC_PRINTF("HCINTMSK @0x%08lX : 0x%08X\n",
25886 + (unsigned long)addr, DWC_READ_REG32(addr));
25887 + addr = &core_if->host_if->hc_regs[i]->hctsiz;
25888 + DWC_PRINTF("HCTSIZ @0x%08lX : 0x%08X\n",
25889 + (unsigned long)addr, DWC_READ_REG32(addr));
25890 + addr = &core_if->host_if->hc_regs[i]->hcdma;
25891 + DWC_PRINTF("HCDMA @0x%08lX : 0x%08X\n",
25892 + (unsigned long)addr, DWC_READ_REG32(addr));
25893 + if (core_if->dma_desc_enable) {
25894 + addr = &core_if->host_if->hc_regs[i]->hcdmab;
25895 + DWC_PRINTF("HCDMAB @0x%08lX : 0x%08X\n",
25896 + (unsigned long)addr, DWC_READ_REG32(addr));
25904 + * This function reads the core global registers and prints them
25906 + * @param core_if Programming view of DWC_otg controller.
25908 +void dwc_otg_dump_global_registers(dwc_otg_core_if_t * core_if)
25911 + volatile uint32_t *addr;
25914 + DWC_PRINTF("Core Global Registers\n");
25915 + addr = &core_if->core_global_regs->gotgctl;
25916 + DWC_PRINTF("GOTGCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25917 + DWC_READ_REG32(addr));
25918 + addr = &core_if->core_global_regs->gotgint;
25919 + DWC_PRINTF("GOTGINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
25920 + DWC_READ_REG32(addr));
25921 + addr = &core_if->core_global_regs->gahbcfg;
25922 + DWC_PRINTF("GAHBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
25923 + DWC_READ_REG32(addr));
25924 + addr = &core_if->core_global_regs->gusbcfg;
25925 + DWC_PRINTF("GUSBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
25926 + DWC_READ_REG32(addr));
25927 + addr = &core_if->core_global_regs->grstctl;
25928 + DWC_PRINTF("GRSTCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25929 + DWC_READ_REG32(addr));
25930 + addr = &core_if->core_global_regs->gintsts;
25931 + DWC_PRINTF("GINTSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
25932 + DWC_READ_REG32(addr));
25933 + addr = &core_if->core_global_regs->gintmsk;
25934 + DWC_PRINTF("GINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25935 + DWC_READ_REG32(addr));
25936 + addr = &core_if->core_global_regs->grxstsr;
25937 + DWC_PRINTF("GRXSTSR @0x%08lX : 0x%08X\n", (unsigned long)addr,
25938 + DWC_READ_REG32(addr));
25939 + addr = &core_if->core_global_regs->grxfsiz;
25940 + DWC_PRINTF("GRXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
25941 + DWC_READ_REG32(addr));
25942 + addr = &core_if->core_global_regs->gnptxfsiz;
25943 + DWC_PRINTF("GNPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
25944 + DWC_READ_REG32(addr));
25945 + addr = &core_if->core_global_regs->gnptxsts;
25946 + DWC_PRINTF("GNPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
25947 + DWC_READ_REG32(addr));
25948 + addr = &core_if->core_global_regs->gi2cctl;
25949 + DWC_PRINTF("GI2CCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25950 + DWC_READ_REG32(addr));
25951 + addr = &core_if->core_global_regs->gpvndctl;
25952 + DWC_PRINTF("GPVNDCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25953 + DWC_READ_REG32(addr));
25954 + addr = &core_if->core_global_regs->ggpio;
25955 + DWC_PRINTF("GGPIO @0x%08lX : 0x%08X\n", (unsigned long)addr,
25956 + DWC_READ_REG32(addr));
25957 + addr = &core_if->core_global_regs->guid;
25958 + DWC_PRINTF("GUID @0x%08lX : 0x%08X\n",
25959 + (unsigned long)addr, DWC_READ_REG32(addr));
25960 + addr = &core_if->core_global_regs->gsnpsid;
25961 + DWC_PRINTF("GSNPSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
25962 + DWC_READ_REG32(addr));
25963 + addr = &core_if->core_global_regs->ghwcfg1;
25964 + DWC_PRINTF("GHWCFG1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25965 + DWC_READ_REG32(addr));
25966 + addr = &core_if->core_global_regs->ghwcfg2;
25967 + DWC_PRINTF("GHWCFG2 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25968 + DWC_READ_REG32(addr));
25969 + addr = &core_if->core_global_regs->ghwcfg3;
25970 + DWC_PRINTF("GHWCFG3 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25971 + DWC_READ_REG32(addr));
25972 + addr = &core_if->core_global_regs->ghwcfg4;
25973 + DWC_PRINTF("GHWCFG4 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25974 + DWC_READ_REG32(addr));
25975 + addr = &core_if->core_global_regs->glpmcfg;
25976 + DWC_PRINTF("GLPMCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
25977 + DWC_READ_REG32(addr));
25978 + addr = &core_if->core_global_regs->gpwrdn;
25979 + DWC_PRINTF("GPWRDN @0x%08lX : 0x%08X\n", (unsigned long)addr,
25980 + DWC_READ_REG32(addr));
25981 + addr = &core_if->core_global_regs->gdfifocfg;
25982 + DWC_PRINTF("GDFIFOCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
25983 + DWC_READ_REG32(addr));
25984 + addr = &core_if->core_global_regs->adpctl;
25985 + DWC_PRINTF("ADPCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
25986 + dwc_otg_adp_read_reg(core_if));
25987 + addr = &core_if->core_global_regs->hptxfsiz;
25988 + DWC_PRINTF("HPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
25989 + DWC_READ_REG32(addr));
25991 + if (core_if->en_multiple_tx_fifo == 0) {
25992 + ep_num = core_if->hwcfg4.b.num_dev_perio_in_ep;
25993 + txfsiz = "DPTXFSIZ";
25995 + ep_num = core_if->hwcfg4.b.num_in_eps;
25996 + txfsiz = "DIENPTXF";
25998 + for (i = 0; i < ep_num; i++) {
25999 + addr = &core_if->core_global_regs->dtxfsiz[i];
26000 + DWC_PRINTF("%s[%d] @0x%08lX : 0x%08X\n", txfsiz, i + 1,
26001 + (unsigned long)addr, DWC_READ_REG32(addr));
26003 + addr = core_if->pcgcctl;
26004 + DWC_PRINTF("PCGCCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26005 + DWC_READ_REG32(addr));
26009 + * Flush a Tx FIFO.
26011 + * @param core_if Programming view of DWC_otg controller.
26012 + * @param num Tx FIFO to flush.
26014 +void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * core_if, const int num)
26016 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26017 + volatile grstctl_t greset = {.d32 = 0 };
26020 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", num);
26022 + greset.b.txfflsh = 1;
26023 + greset.b.txfnum = num;
26024 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26027 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26028 + if (++count > 10000) {
26029 + DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
26030 + __func__, greset.d32,
26031 + DWC_READ_REG32(&global_regs->gnptxsts));
26035 + } while (greset.b.txfflsh == 1);
26037 + /* Wait for 3 PHY Clocks */
26044 + * @param core_if Programming view of DWC_otg controller.
26046 +void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * core_if)
26048 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26049 + volatile grstctl_t greset = {.d32 = 0 };
26052 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__);
26056 + greset.b.rxfflsh = 1;
26057 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26060 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26061 + if (++count > 10000) {
26062 + DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
26067 + } while (greset.b.rxfflsh == 1);
26069 + /* Wait for 3 PHY Clocks */
26074 + * Do core a soft reset of the core. Be careful with this because it
26075 + * resets all the internal state machines of the core.
26077 +void dwc_otg_core_reset(dwc_otg_core_if_t * core_if)
26079 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26080 + volatile grstctl_t greset = {.d32 = 0 };
26083 + DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
26084 + /* Wait for AHB master IDLE state. */
26087 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26088 + if (++count > 100000) {
26089 + DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
26094 + while (greset.b.ahbidle == 0);
26096 + /* Core Soft Reset */
26098 + greset.b.csftrst = 1;
26099 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26101 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26102 + if (++count > 10000) {
26103 + DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n",
26104 + __func__, greset.d32);
26109 + while (greset.b.csftrst == 1);
26111 + /* Wait for 3 PHY Clocks */
26115 +uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if)
26117 + return (dwc_otg_mode(_core_if) != DWC_HOST_MODE);
26120 +uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if)
26122 + return (dwc_otg_mode(_core_if) == DWC_HOST_MODE);
26126 + * Register HCD callbacks. The callbacks are used to start and stop
26127 + * the HCD for interrupt processing.
26129 + * @param core_if Programming view of DWC_otg controller.
26130 + * @param cb the HCD callback structure.
26131 + * @param p pointer to be passed to callback function (usb_hcd*).
26133 +void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * core_if,
26134 + dwc_otg_cil_callbacks_t * cb, void *p)
26136 + core_if->hcd_cb = cb;
26141 + * Register PCD callbacks. The callbacks are used to start and stop
26142 + * the PCD for interrupt processing.
26144 + * @param core_if Programming view of DWC_otg controller.
26145 + * @param cb the PCD callback structure.
26146 + * @param p pointer to be passed to callback function (pcd*).
26148 +void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * core_if,
26149 + dwc_otg_cil_callbacks_t * cb, void *p)
26151 + core_if->pcd_cb = cb;
26155 +#ifdef DWC_EN_ISOC
26158 + * This function writes isoc data per 1 (micro)frame into tx fifo
26160 + * @param core_if Programming view of DWC_otg controller.
26161 + * @param ep The EP to start the transfer on.
26164 +void write_isoc_frame_data(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
26166 + dwc_otg_dev_in_ep_regs_t *ep_regs;
26167 + dtxfsts_data_t txstatus = {.d32 = 0 };
26168 + uint32_t len = 0;
26171 + ep->xfer_len = ep->data_per_frame;
26172 + ep->xfer_count = 0;
26174 + ep_regs = core_if->dev_if->in_ep_regs[ep->num];
26176 + len = ep->xfer_len - ep->xfer_count;
26178 + if (len > ep->maxpacket) {
26179 + len = ep->maxpacket;
26182 + dwords = (len + 3) / 4;
26184 + /* While there is space in the queue and space in the FIFO and
26185 + * More data to tranfer, Write packets to the Tx FIFO */
26187 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dtxfsts);
26188 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", ep->num, txstatus.d32);
26190 + while (txstatus.b.txfspcavail > dwords &&
26191 + ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) {
26192 + /* Write the FIFO */
26193 + dwc_otg_ep_write_packet(core_if, ep, 0);
26195 + len = ep->xfer_len - ep->xfer_count;
26196 + if (len > ep->maxpacket) {
26197 + len = ep->maxpacket;
26200 + dwords = (len + 3) / 4;
26202 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
26204 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", ep->num,
26210 + * This function initializes a descriptor chain for Isochronous transfer
26212 + * @param core_if Programming view of DWC_otg controller.
26213 + * @param ep The EP to start the transfer on.
26216 +void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
26219 + deptsiz_data_t deptsiz = {.d32 = 0 };
26220 + depctl_data_t depctl = {.d32 = 0 };
26221 + dsts_data_t dsts = {.d32 = 0 };
26222 + volatile uint32_t *addr;
26225 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
26227 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
26230 + ep->xfer_len = ep->data_per_frame;
26231 + ep->xfer_count = 0;
26232 + ep->xfer_buff = ep->cur_pkt_addr;
26233 + ep->dma_addr = ep->cur_pkt_dma_addr;
26236 + /* Program the transfer size and packet count
26237 + * as follows: xfersize = N * maxpacket +
26238 + * short_packet pktcnt = N + (short_packet
26241 + deptsiz.b.xfersize = ep->xfer_len;
26242 + deptsiz.b.pktcnt =
26243 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
26244 + deptsiz.b.mc = deptsiz.b.pktcnt;
26245 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dieptsiz,
26248 + /* Write the DMA register */
26249 + if (core_if->dma_enable) {
26250 + DWC_WRITE_REG32(&
26251 + (core_if->dev_if->in_ep_regs[ep->num]->
26252 + diepdma), (uint32_t) ep->dma_addr);
26255 + deptsiz.b.pktcnt =
26256 + (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket;
26257 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
26259 + DWC_WRITE_REG32(&core_if->dev_if->
26260 + out_ep_regs[ep->num]->doeptsiz, deptsiz.d32);
26262 + if (core_if->dma_enable) {
26263 + DWC_WRITE_REG32(&
26264 + (core_if->dev_if->
26265 + out_ep_regs[ep->num]->doepdma),
26266 + (uint32_t) ep->dma_addr);
26270 + /** Enable endpoint, clear nak */
26273 + if (ep->bInterval == 1) {
26275 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
26276 + ep->next_frame = dsts.b.soffn + ep->bInterval;
26278 + if (ep->next_frame & 0x1) {
26279 + depctl.b.setd1pid = 1;
26281 + depctl.b.setd0pid = 1;
26284 + ep->next_frame += ep->bInterval;
26286 + if (ep->next_frame & 0x1) {
26287 + depctl.b.setd1pid = 1;
26289 + depctl.b.setd0pid = 1;
26292 + depctl.b.epena = 1;
26293 + depctl.b.cnak = 1;
26295 + DWC_MODIFY_REG32(addr, 0, depctl.d32);
26296 + depctl.d32 = DWC_READ_REG32(addr);
26298 + if (ep->is_in && core_if->dma_enable == 0) {
26299 + write_isoc_frame_data(core_if, ep);
26303 +#endif /* DWC_EN_ISOC */
26305 +static void dwc_otg_set_uninitialized(int32_t * p, int size)
26308 + for (i = 0; i < size; i++) {
26313 +static int dwc_otg_param_initialized(int32_t val)
26315 + return val != -1;
26318 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if)
26321 + core_if->core_params = DWC_ALLOC(sizeof(*core_if->core_params));
26322 + if (!core_if->core_params) {
26323 + return -DWC_E_NO_MEMORY;
26325 + dwc_otg_set_uninitialized((int32_t *) core_if->core_params,
26326 + sizeof(*core_if->core_params) /
26327 + sizeof(int32_t));
26328 + DWC_PRINTF("Setting default values for core params\n");
26329 + dwc_otg_set_param_otg_cap(core_if, dwc_param_otg_cap_default);
26330 + dwc_otg_set_param_dma_enable(core_if, dwc_param_dma_enable_default);
26331 + dwc_otg_set_param_dma_desc_enable(core_if,
26332 + dwc_param_dma_desc_enable_default);
26333 + dwc_otg_set_param_opt(core_if, dwc_param_opt_default);
26334 + dwc_otg_set_param_dma_burst_size(core_if,
26335 + dwc_param_dma_burst_size_default);
26336 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
26337 + dwc_param_host_support_fs_ls_low_power_default);
26338 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
26339 + dwc_param_enable_dynamic_fifo_default);
26340 + dwc_otg_set_param_data_fifo_size(core_if,
26341 + dwc_param_data_fifo_size_default);
26342 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
26343 + dwc_param_dev_rx_fifo_size_default);
26344 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
26345 + dwc_param_dev_nperio_tx_fifo_size_default);
26346 + dwc_otg_set_param_host_rx_fifo_size(core_if,
26347 + dwc_param_host_rx_fifo_size_default);
26348 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
26349 + dwc_param_host_nperio_tx_fifo_size_default);
26350 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
26351 + dwc_param_host_perio_tx_fifo_size_default);
26352 + dwc_otg_set_param_max_transfer_size(core_if,
26353 + dwc_param_max_transfer_size_default);
26354 + dwc_otg_set_param_max_packet_count(core_if,
26355 + dwc_param_max_packet_count_default);
26356 + dwc_otg_set_param_host_channels(core_if,
26357 + dwc_param_host_channels_default);
26358 + dwc_otg_set_param_dev_endpoints(core_if,
26359 + dwc_param_dev_endpoints_default);
26360 + dwc_otg_set_param_phy_type(core_if, dwc_param_phy_type_default);
26361 + dwc_otg_set_param_speed(core_if, dwc_param_speed_default);
26362 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
26363 + dwc_param_host_ls_low_power_phy_clk_default);
26364 + dwc_otg_set_param_phy_ulpi_ddr(core_if, dwc_param_phy_ulpi_ddr_default);
26365 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
26366 + dwc_param_phy_ulpi_ext_vbus_default);
26367 + dwc_otg_set_param_phy_utmi_width(core_if,
26368 + dwc_param_phy_utmi_width_default);
26369 + dwc_otg_set_param_ts_dline(core_if, dwc_param_ts_dline_default);
26370 + dwc_otg_set_param_i2c_enable(core_if, dwc_param_i2c_enable_default);
26371 + dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_param_ulpi_fs_ls_default);
26372 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
26373 + dwc_param_en_multiple_tx_fifo_default);
26374 + for (i = 0; i < 15; i++) {
26375 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
26376 + dwc_param_dev_perio_tx_fifo_size_default,
26380 + for (i = 0; i < 15; i++) {
26381 + dwc_otg_set_param_dev_tx_fifo_size(core_if,
26382 + dwc_param_dev_tx_fifo_size_default,
26385 + dwc_otg_set_param_thr_ctl(core_if, dwc_param_thr_ctl_default);
26386 + dwc_otg_set_param_mpi_enable(core_if, dwc_param_mpi_enable_default);
26387 + dwc_otg_set_param_pti_enable(core_if, dwc_param_pti_enable_default);
26388 + dwc_otg_set_param_lpm_enable(core_if, dwc_param_lpm_enable_default);
26389 + dwc_otg_set_param_ic_usb_cap(core_if, dwc_param_ic_usb_cap_default);
26390 + dwc_otg_set_param_tx_thr_length(core_if,
26391 + dwc_param_tx_thr_length_default);
26392 + dwc_otg_set_param_rx_thr_length(core_if,
26393 + dwc_param_rx_thr_length_default);
26394 + dwc_otg_set_param_ahb_thr_ratio(core_if,
26395 + dwc_param_ahb_thr_ratio_default);
26396 + dwc_otg_set_param_power_down(core_if, dwc_param_power_down_default);
26397 + dwc_otg_set_param_reload_ctl(core_if, dwc_param_reload_ctl_default);
26398 + dwc_otg_set_param_dev_out_nak(core_if, dwc_param_dev_out_nak_default);
26399 + dwc_otg_set_param_cont_on_bna(core_if, dwc_param_cont_on_bna_default);
26400 + dwc_otg_set_param_ahb_single(core_if, dwc_param_ahb_single_default);
26401 + dwc_otg_set_param_otg_ver(core_if, dwc_param_otg_ver_default);
26402 + dwc_otg_set_param_adp_enable(core_if, dwc_param_adp_enable_default);
26403 + DWC_PRINTF("Finished setting default values for core params\n");
26408 +uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if)
26410 + return core_if->dma_enable;
26413 +/* Checks if the parameter is outside of its valid range of values */
26414 +#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \
26415 + (((_param_) < (_low_)) || \
26416 + ((_param_) > (_high_)))
26418 +/* Parameter access functions */
26419 +int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val)
26423 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
26424 + DWC_WARN("Wrong value for otg_cap parameter\n");
26425 + DWC_WARN("otg_cap parameter must be 0,1 or 2\n");
26426 + retval = -DWC_E_INVALID;
26432 + case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
26433 + if (core_if->hwcfg2.b.op_mode !=
26434 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26437 + case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
26438 + if ((core_if->hwcfg2.b.op_mode !=
26439 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26440 + && (core_if->hwcfg2.b.op_mode !=
26441 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
26442 + && (core_if->hwcfg2.b.op_mode !=
26443 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
26444 + && (core_if->hwcfg2.b.op_mode !=
26445 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) {
26449 + case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
26450 + /* always valid */
26454 + if (dwc_otg_param_initialized(core_if->core_params->otg_cap)) {
26456 + ("%d invalid for otg_cap paremter. Check HW configuration.\n",
26460 + (((core_if->hwcfg2.b.op_mode ==
26461 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26462 + || (core_if->hwcfg2.b.op_mode ==
26463 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
26464 + || (core_if->hwcfg2.b.op_mode ==
26465 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
26466 + || (core_if->hwcfg2.b.op_mode ==
26467 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ?
26468 + DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE :
26469 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
26470 + retval = -DWC_E_INVALID;
26473 + core_if->core_params->otg_cap = val;
26478 +int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if)
26480 + return core_if->core_params->otg_cap;
26483 +int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val)
26485 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26486 + DWC_WARN("Wrong value for opt parameter\n");
26487 + return -DWC_E_INVALID;
26489 + core_if->core_params->opt = val;
26493 +int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if)
26495 + return core_if->core_params->opt;
26498 +int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, int32_t val)
26501 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26502 + DWC_WARN("Wrong value for dma enable\n");
26503 + return -DWC_E_INVALID;
26506 + if ((val == 1) && (core_if->hwcfg2.b.architecture == 0)) {
26507 + if (dwc_otg_param_initialized(core_if->core_params->dma_enable)) {
26509 + ("%d invalid for dma_enable paremter. Check HW configuration.\n",
26513 + retval = -DWC_E_INVALID;
26516 + core_if->core_params->dma_enable = val;
26518 + dwc_otg_set_param_dma_desc_enable(core_if, 0);
26523 +int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if)
26525 + return core_if->core_params->dma_enable;
26528 +int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, int32_t val)
26531 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26532 + DWC_WARN("Wrong value for dma_enable\n");
26533 + DWC_WARN("dma_desc_enable must be 0 or 1\n");
26534 + return -DWC_E_INVALID;
26538 + && ((dwc_otg_get_param_dma_enable(core_if) == 0)
26539 + || (core_if->hwcfg4.b.desc_dma == 0))) {
26540 + if (dwc_otg_param_initialized
26541 + (core_if->core_params->dma_desc_enable)) {
26543 + ("%d invalid for dma_desc_enable paremter. Check HW configuration.\n",
26547 + retval = -DWC_E_INVALID;
26549 + core_if->core_params->dma_desc_enable = val;
26553 +int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if)
26555 + return core_if->core_params->dma_desc_enable;
26558 +int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * core_if,
26561 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26562 + DWC_WARN("Wrong value for host_support_fs_low_power\n");
26563 + DWC_WARN("host_support_fs_low_power must be 0 or 1\n");
26564 + return -DWC_E_INVALID;
26566 + core_if->core_params->host_support_fs_ls_low_power = val;
26570 +int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
26573 + return core_if->core_params->host_support_fs_ls_low_power;
26576 +int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
26580 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26581 + DWC_WARN("Wrong value for enable_dynamic_fifo\n");
26582 + DWC_WARN("enable_dynamic_fifo must be 0 or 1\n");
26583 + return -DWC_E_INVALID;
26586 + if ((val == 1) && (core_if->hwcfg2.b.dynamic_fifo == 0)) {
26587 + if (dwc_otg_param_initialized
26588 + (core_if->core_params->enable_dynamic_fifo)) {
26590 + ("%d invalid for enable_dynamic_fifo paremter. Check HW configuration.\n",
26594 + retval = -DWC_E_INVALID;
26596 + core_if->core_params->enable_dynamic_fifo = val;
26600 +int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if)
26602 + return core_if->core_params->enable_dynamic_fifo;
26605 +int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
26608 + if (DWC_OTG_PARAM_TEST(val, 32, 32768)) {
26609 + DWC_WARN("Wrong value for data_fifo_size\n");
26610 + DWC_WARN("data_fifo_size must be 32-32768\n");
26611 + return -DWC_E_INVALID;
26614 + if (val > core_if->hwcfg3.b.dfifo_depth) {
26615 + if (dwc_otg_param_initialized
26616 + (core_if->core_params->data_fifo_size)) {
26618 + ("%d invalid for data_fifo_size parameter. Check HW configuration.\n",
26621 + val = core_if->hwcfg3.b.dfifo_depth;
26622 + retval = -DWC_E_INVALID;
26625 + core_if->core_params->data_fifo_size = val;
26629 +int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if)
26631 + return core_if->core_params->data_fifo_size;
26634 +int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
26637 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26638 + DWC_WARN("Wrong value for dev_rx_fifo_size\n");
26639 + DWC_WARN("dev_rx_fifo_size must be 16-32768\n");
26640 + return -DWC_E_INVALID;
26643 + if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
26644 + if (dwc_otg_param_initialized(core_if->core_params->dev_rx_fifo_size)) {
26645 + DWC_WARN("%d invalid for dev_rx_fifo_size parameter\n", val);
26647 + val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
26648 + retval = -DWC_E_INVALID;
26651 + core_if->core_params->dev_rx_fifo_size = val;
26655 +int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if)
26657 + return core_if->core_params->dev_rx_fifo_size;
26660 +int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26665 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26666 + DWC_WARN("Wrong value for dev_nperio_tx_fifo\n");
26667 + DWC_WARN("dev_nperio_tx_fifo must be 16-32768\n");
26668 + return -DWC_E_INVALID;
26671 + if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
26672 + if (dwc_otg_param_initialized
26673 + (core_if->core_params->dev_nperio_tx_fifo_size)) {
26675 + ("%d invalid for dev_nperio_tx_fifo_size. Check HW configuration.\n",
26679 + (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
26681 + retval = -DWC_E_INVALID;
26684 + core_if->core_params->dev_nperio_tx_fifo_size = val;
26688 +int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26690 + return core_if->core_params->dev_nperio_tx_fifo_size;
26693 +int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
26698 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26699 + DWC_WARN("Wrong value for host_rx_fifo_size\n");
26700 + DWC_WARN("host_rx_fifo_size must be 16-32768\n");
26701 + return -DWC_E_INVALID;
26704 + if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
26705 + if (dwc_otg_param_initialized
26706 + (core_if->core_params->host_rx_fifo_size)) {
26708 + ("%d invalid for host_rx_fifo_size. Check HW configuration.\n",
26711 + val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
26712 + retval = -DWC_E_INVALID;
26715 + core_if->core_params->host_rx_fifo_size = val;
26720 +int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if)
26722 + return core_if->core_params->host_rx_fifo_size;
26725 +int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26730 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26731 + DWC_WARN("Wrong value for host_nperio_tx_fifo_size\n");
26732 + DWC_WARN("host_nperio_tx_fifo_size must be 16-32768\n");
26733 + return -DWC_E_INVALID;
26736 + if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
26737 + if (dwc_otg_param_initialized
26738 + (core_if->core_params->host_nperio_tx_fifo_size)) {
26740 + ("%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
26744 + (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
26746 + retval = -DWC_E_INVALID;
26749 + core_if->core_params->host_nperio_tx_fifo_size = val;
26753 +int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26755 + return core_if->core_params->host_nperio_tx_fifo_size;
26758 +int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26762 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26763 + DWC_WARN("Wrong value for host_perio_tx_fifo_size\n");
26764 + DWC_WARN("host_perio_tx_fifo_size must be 16-32768\n");
26765 + return -DWC_E_INVALID;
26768 + if (val > ((core_if->hptxfsiz.d32) >> 16)) {
26769 + if (dwc_otg_param_initialized
26770 + (core_if->core_params->host_perio_tx_fifo_size)) {
26772 + ("%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
26775 + val = (core_if->hptxfsiz.d32) >> 16;
26776 + retval = -DWC_E_INVALID;
26779 + core_if->core_params->host_perio_tx_fifo_size = val;
26783 +int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26785 + return core_if->core_params->host_perio_tx_fifo_size;
26788 +int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
26793 + if (DWC_OTG_PARAM_TEST(val, 2047, 524288)) {
26794 + DWC_WARN("Wrong value for max_transfer_size\n");
26795 + DWC_WARN("max_transfer_size must be 2047-524288\n");
26796 + return -DWC_E_INVALID;
26799 + if (val >= (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))) {
26800 + if (dwc_otg_param_initialized
26801 + (core_if->core_params->max_transfer_size)) {
26803 + ("%d invalid for max_transfer_size. Check HW configuration.\n",
26807 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 11)) -
26809 + retval = -DWC_E_INVALID;
26812 + core_if->core_params->max_transfer_size = val;
26816 +int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if)
26818 + return core_if->core_params->max_transfer_size;
26821 +int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, int32_t val)
26825 + if (DWC_OTG_PARAM_TEST(val, 15, 511)) {
26826 + DWC_WARN("Wrong value for max_packet_count\n");
26827 + DWC_WARN("max_packet_count must be 15-511\n");
26828 + return -DWC_E_INVALID;
26831 + if (val > (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))) {
26832 + if (dwc_otg_param_initialized
26833 + (core_if->core_params->max_packet_count)) {
26835 + ("%d invalid for max_packet_count. Check HW configuration.\n",
26839 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1);
26840 + retval = -DWC_E_INVALID;
26843 + core_if->core_params->max_packet_count = val;
26847 +int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if)
26849 + return core_if->core_params->max_packet_count;
26852 +int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, int32_t val)
26856 + if (DWC_OTG_PARAM_TEST(val, 1, 16)) {
26857 + DWC_WARN("Wrong value for host_channels\n");
26858 + DWC_WARN("host_channels must be 1-16\n");
26859 + return -DWC_E_INVALID;
26862 + if (val > (core_if->hwcfg2.b.num_host_chan + 1)) {
26863 + if (dwc_otg_param_initialized
26864 + (core_if->core_params->host_channels)) {
26866 + ("%d invalid for host_channels. Check HW configurations.\n",
26869 + val = (core_if->hwcfg2.b.num_host_chan + 1);
26870 + retval = -DWC_E_INVALID;
26873 + core_if->core_params->host_channels = val;
26877 +int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if)
26879 + return core_if->core_params->host_channels;
26882 +int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, int32_t val)
26886 + if (DWC_OTG_PARAM_TEST(val, 1, 15)) {
26887 + DWC_WARN("Wrong value for dev_endpoints\n");
26888 + DWC_WARN("dev_endpoints must be 1-15\n");
26889 + return -DWC_E_INVALID;
26892 + if (val > (core_if->hwcfg2.b.num_dev_ep)) {
26893 + if (dwc_otg_param_initialized
26894 + (core_if->core_params->dev_endpoints)) {
26896 + ("%d invalid for dev_endpoints. Check HW configurations.\n",
26899 + val = core_if->hwcfg2.b.num_dev_ep;
26900 + retval = -DWC_E_INVALID;
26903 + core_if->core_params->dev_endpoints = val;
26907 +int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if)
26909 + return core_if->core_params->dev_endpoints;
26912 +int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val)
26917 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
26918 + DWC_WARN("Wrong value for phy_type\n");
26919 + DWC_WARN("phy_type must be 0,1 or 2\n");
26920 + return -DWC_E_INVALID;
26922 +#ifndef NO_FS_PHY_HW_CHECKS
26923 + if ((val == DWC_PHY_TYPE_PARAM_UTMI) &&
26924 + ((core_if->hwcfg2.b.hs_phy_type == 1) ||
26925 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
26927 + } else if ((val == DWC_PHY_TYPE_PARAM_ULPI) &&
26928 + ((core_if->hwcfg2.b.hs_phy_type == 2) ||
26929 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
26931 + } else if ((val == DWC_PHY_TYPE_PARAM_FS) &&
26932 + (core_if->hwcfg2.b.fs_phy_type == 1)) {
26936 + if (dwc_otg_param_initialized(core_if->core_params->phy_type)) {
26938 + ("%d invalid for phy_type. Check HW configurations.\n",
26941 + if (core_if->hwcfg2.b.hs_phy_type) {
26942 + if ((core_if->hwcfg2.b.hs_phy_type == 3) ||
26943 + (core_if->hwcfg2.b.hs_phy_type == 1)) {
26944 + val = DWC_PHY_TYPE_PARAM_UTMI;
26946 + val = DWC_PHY_TYPE_PARAM_ULPI;
26949 + retval = -DWC_E_INVALID;
26952 + core_if->core_params->phy_type = val;
26956 +int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if)
26958 + return core_if->core_params->phy_type;
26961 +int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val)
26964 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26965 + DWC_WARN("Wrong value for speed parameter\n");
26966 + DWC_WARN("max_speed parameter must be 0 or 1\n");
26967 + return -DWC_E_INVALID;
26970 + && dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS) {
26971 + if (dwc_otg_param_initialized(core_if->core_params->speed)) {
26973 + ("%d invalid for speed paremter. Check HW configuration.\n",
26977 + (dwc_otg_get_param_phy_type(core_if) ==
26978 + DWC_PHY_TYPE_PARAM_FS ? 1 : 0);
26979 + retval = -DWC_E_INVALID;
26981 + core_if->core_params->speed = val;
26985 +int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if)
26987 + return core_if->core_params->speed;
26990 +int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if,
26995 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26997 + ("Wrong value for host_ls_low_power_phy_clk parameter\n");
26998 + DWC_WARN("host_ls_low_power_phy_clk must be 0 or 1\n");
26999 + return -DWC_E_INVALID;
27002 + if ((val == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)
27003 + && (dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS)) {
27004 + if (dwc_otg_param_initialized
27005 + (core_if->core_params->host_ls_low_power_phy_clk)) {
27007 + ("%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
27011 + (dwc_otg_get_param_phy_type(core_if) ==
27012 + DWC_PHY_TYPE_PARAM_FS) ?
27013 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ :
27014 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
27015 + retval = -DWC_E_INVALID;
27018 + core_if->core_params->host_ls_low_power_phy_clk = val;
27022 +int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if)
27024 + return core_if->core_params->host_ls_low_power_phy_clk;
27027 +int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, int32_t val)
27029 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27030 + DWC_WARN("Wrong value for phy_ulpi_ddr\n");
27031 + DWC_WARN("phy_upli_ddr must be 0 or 1\n");
27032 + return -DWC_E_INVALID;
27035 + core_if->core_params->phy_ulpi_ddr = val;
27039 +int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if)
27041 + return core_if->core_params->phy_ulpi_ddr;
27044 +int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
27047 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27048 + DWC_WARN("Wrong valaue for phy_ulpi_ext_vbus\n");
27049 + DWC_WARN("phy_ulpi_ext_vbus must be 0 or 1\n");
27050 + return -DWC_E_INVALID;
27053 + core_if->core_params->phy_ulpi_ext_vbus = val;
27057 +int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if)
27059 + return core_if->core_params->phy_ulpi_ext_vbus;
27062 +int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, int32_t val)
27064 + if (DWC_OTG_PARAM_TEST(val, 8, 8) && DWC_OTG_PARAM_TEST(val, 16, 16)) {
27065 + DWC_WARN("Wrong valaue for phy_utmi_width\n");
27066 + DWC_WARN("phy_utmi_width must be 8 or 16\n");
27067 + return -DWC_E_INVALID;
27070 + core_if->core_params->phy_utmi_width = val;
27074 +int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if)
27076 + return core_if->core_params->phy_utmi_width;
27079 +int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, int32_t val)
27081 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27082 + DWC_WARN("Wrong valaue for ulpi_fs_ls\n");
27083 + DWC_WARN("ulpi_fs_ls must be 0 or 1\n");
27084 + return -DWC_E_INVALID;
27087 + core_if->core_params->ulpi_fs_ls = val;
27091 +int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if)
27093 + return core_if->core_params->ulpi_fs_ls;
27096 +int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val)
27098 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27099 + DWC_WARN("Wrong valaue for ts_dline\n");
27100 + DWC_WARN("ts_dline must be 0 or 1\n");
27101 + return -DWC_E_INVALID;
27104 + core_if->core_params->ts_dline = val;
27108 +int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if)
27110 + return core_if->core_params->ts_dline;
27113 +int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, int32_t val)
27116 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27117 + DWC_WARN("Wrong valaue for i2c_enable\n");
27118 + DWC_WARN("i2c_enable must be 0 or 1\n");
27119 + return -DWC_E_INVALID;
27121 +#ifndef NO_FS_PHY_HW_CHECK
27122 + if (val == 1 && core_if->hwcfg3.b.i2c == 0) {
27123 + if (dwc_otg_param_initialized(core_if->core_params->i2c_enable)) {
27125 + ("%d invalid for i2c_enable. Check HW configuration.\n",
27129 + retval = -DWC_E_INVALID;
27133 + core_if->core_params->i2c_enable = val;
27137 +int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if)
27139 + return core_if->core_params->i2c_enable;
27142 +int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
27143 + int32_t val, int fifo_num)
27147 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
27148 + DWC_WARN("Wrong value for dev_perio_tx_fifo_size\n");
27149 + DWC_WARN("dev_perio_tx_fifo_size must be 4-768\n");
27150 + return -DWC_E_INVALID;
27154 + (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
27155 + if (dwc_otg_param_initialized
27156 + (core_if->core_params->dev_perio_tx_fifo_size[fifo_num])) {
27158 + ("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n",
27161 + val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
27162 + retval = -DWC_E_INVALID;
27165 + core_if->core_params->dev_perio_tx_fifo_size[fifo_num] = val;
27169 +int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
27172 + return core_if->core_params->dev_perio_tx_fifo_size[fifo_num];
27175 +int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
27179 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27180 + DWC_WARN("Wrong valaue for en_multiple_tx_fifo,\n");
27181 + DWC_WARN("en_multiple_tx_fifo must be 0 or 1\n");
27182 + return -DWC_E_INVALID;
27185 + if (val == 1 && core_if->hwcfg4.b.ded_fifo_en == 0) {
27186 + if (dwc_otg_param_initialized
27187 + (core_if->core_params->en_multiple_tx_fifo)) {
27189 + ("%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
27193 + retval = -DWC_E_INVALID;
27196 + core_if->core_params->en_multiple_tx_fifo = val;
27200 +int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if)
27202 + return core_if->core_params->en_multiple_tx_fifo;
27205 +int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val,
27210 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
27211 + DWC_WARN("Wrong value for dev_tx_fifo_size\n");
27212 + DWC_WARN("dev_tx_fifo_size must be 4-768\n");
27213 + return -DWC_E_INVALID;
27217 + (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
27218 + if (dwc_otg_param_initialized
27219 + (core_if->core_params->dev_tx_fifo_size[fifo_num])) {
27221 + ("`%d' invalid for parameter `dev_tx_fifo_size_%d'. Check HW configuration.\n",
27224 + val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
27225 + retval = -DWC_E_INVALID;
27228 + core_if->core_params->dev_tx_fifo_size[fifo_num] = val;
27232 +int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
27235 + return core_if->core_params->dev_tx_fifo_size[fifo_num];
27238 +int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val)
27242 + if (DWC_OTG_PARAM_TEST(val, 0, 7)) {
27243 + DWC_WARN("Wrong value for thr_ctl\n");
27244 + DWC_WARN("thr_ctl must be 0-7\n");
27245 + return -DWC_E_INVALID;
27248 + if ((val != 0) &&
27249 + (!dwc_otg_get_param_dma_enable(core_if) ||
27250 + !core_if->hwcfg4.b.ded_fifo_en)) {
27251 + if (dwc_otg_param_initialized(core_if->core_params->thr_ctl)) {
27253 + ("%d invalid for parameter thr_ctl. Check HW configuration.\n",
27257 + retval = -DWC_E_INVALID;
27260 + core_if->core_params->thr_ctl = val;
27264 +int32_t dwc_otg_get_param_thr_ctl(dwc_otg_core_if_t * core_if)
27266 + return core_if->core_params->thr_ctl;
27269 +int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, int32_t val)
27273 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27274 + DWC_WARN("Wrong value for lpm_enable\n");
27275 + DWC_WARN("lpm_enable must be 0 or 1\n");
27276 + return -DWC_E_INVALID;
27279 + if (val && !core_if->hwcfg3.b.otg_lpm_en) {
27280 + if (dwc_otg_param_initialized(core_if->core_params->lpm_enable)) {
27282 + ("%d invalid for parameter lpm_enable. Check HW configuration.\n",
27286 + retval = -DWC_E_INVALID;
27289 + core_if->core_params->lpm_enable = val;
27293 +int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if)
27295 + return core_if->core_params->lpm_enable;
27298 +int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
27300 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
27301 + DWC_WARN("Wrong valaue for tx_thr_length\n");
27302 + DWC_WARN("tx_thr_length must be 8 - 128\n");
27303 + return -DWC_E_INVALID;
27306 + core_if->core_params->tx_thr_length = val;
27310 +int32_t dwc_otg_get_param_tx_thr_length(dwc_otg_core_if_t * core_if)
27312 + return core_if->core_params->tx_thr_length;
27315 +int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
27317 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
27318 + DWC_WARN("Wrong valaue for rx_thr_length\n");
27319 + DWC_WARN("rx_thr_length must be 8 - 128\n");
27320 + return -DWC_E_INVALID;
27323 + core_if->core_params->rx_thr_length = val;
27327 +int32_t dwc_otg_get_param_rx_thr_length(dwc_otg_core_if_t * core_if)
27329 + return core_if->core_params->rx_thr_length;
27332 +int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, int32_t val)
27334 + if (DWC_OTG_PARAM_TEST(val, 1, 1) &&
27335 + DWC_OTG_PARAM_TEST(val, 4, 4) &&
27336 + DWC_OTG_PARAM_TEST(val, 8, 8) &&
27337 + DWC_OTG_PARAM_TEST(val, 16, 16) &&
27338 + DWC_OTG_PARAM_TEST(val, 32, 32) &&
27339 + DWC_OTG_PARAM_TEST(val, 64, 64) &&
27340 + DWC_OTG_PARAM_TEST(val, 128, 128) &&
27341 + DWC_OTG_PARAM_TEST(val, 256, 256)) {
27342 + DWC_WARN("`%d' invalid for parameter `dma_burst_size'\n", val);
27343 + return -DWC_E_INVALID;
27345 + core_if->core_params->dma_burst_size = val;
27349 +int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if)
27351 + return core_if->core_params->dma_burst_size;
27354 +int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, int32_t val)
27357 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27358 + DWC_WARN("`%d' invalid for parameter `pti_enable'\n", val);
27359 + return -DWC_E_INVALID;
27361 + if (val && (core_if->snpsid < OTG_CORE_REV_2_72a)) {
27362 + if (dwc_otg_param_initialized(core_if->core_params->pti_enable)) {
27364 + ("%d invalid for parameter pti_enable. Check HW configuration.\n",
27367 + retval = -DWC_E_INVALID;
27370 + core_if->core_params->pti_enable = val;
27374 +int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if)
27376 + return core_if->core_params->pti_enable;
27379 +int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, int32_t val)
27382 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27383 + DWC_WARN("`%d' invalid for parameter `mpi_enable'\n", val);
27384 + return -DWC_E_INVALID;
27386 + if (val && (core_if->hwcfg2.b.multi_proc_int == 0)) {
27387 + if (dwc_otg_param_initialized(core_if->core_params->mpi_enable)) {
27389 + ("%d invalid for parameter mpi_enable. Check HW configuration.\n",
27392 + retval = -DWC_E_INVALID;
27395 + core_if->core_params->mpi_enable = val;
27399 +int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if)
27401 + return core_if->core_params->mpi_enable;
27404 +int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if, int32_t val)
27407 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27408 + DWC_WARN("`%d' invalid for parameter `adp_enable'\n", val);
27409 + return -DWC_E_INVALID;
27411 + if (val && (core_if->hwcfg3.b.adp_supp == 0)) {
27412 + if (dwc_otg_param_initialized
27413 + (core_if->core_params->adp_supp_enable)) {
27415 + ("%d invalid for parameter adp_enable. Check HW configuration.\n",
27418 + retval = -DWC_E_INVALID;
27421 + core_if->core_params->adp_supp_enable = val;
27422 + /*Set OTG version 2.0 in case of enabling ADP*/
27424 + dwc_otg_set_param_otg_ver(core_if, 1);
27429 +int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if)
27431 + return core_if->core_params->adp_supp_enable;
27434 +int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if, int32_t val)
27437 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27438 + DWC_WARN("`%d' invalid for parameter `ic_usb_cap'\n", val);
27439 + DWC_WARN("ic_usb_cap must be 0 or 1\n");
27440 + return -DWC_E_INVALID;
27443 + if (val && (core_if->hwcfg2.b.otg_enable_ic_usb == 0)) {
27444 + if (dwc_otg_param_initialized(core_if->core_params->ic_usb_cap)) {
27446 + ("%d invalid for parameter ic_usb_cap. Check HW configuration.\n",
27449 + retval = -DWC_E_INVALID;
27452 + core_if->core_params->ic_usb_cap = val;
27456 +int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if)
27458 + return core_if->core_params->ic_usb_cap;
27461 +int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val)
27466 + if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
27467 + DWC_WARN("`%d' invalid for parameter `ahb_thr_ratio'\n", val);
27468 + DWC_WARN("ahb_thr_ratio must be 0 - 3\n");
27469 + return -DWC_E_INVALID;
27473 + && (core_if->snpsid < OTG_CORE_REV_2_81a
27474 + || !dwc_otg_get_param_thr_ctl(core_if))) {
27477 + && ((dwc_otg_get_param_tx_thr_length(core_if) / (1 << val)) <
27481 + if (valid == 0) {
27482 + if (dwc_otg_param_initialized
27483 + (core_if->core_params->ahb_thr_ratio)) {
27485 + ("%d invalid for parameter ahb_thr_ratio. Check HW configuration.\n",
27488 + retval = -DWC_E_INVALID;
27492 + core_if->core_params->ahb_thr_ratio = val;
27496 +int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if)
27498 + return core_if->core_params->ahb_thr_ratio;
27501 +int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if, int32_t val)
27505 + hwcfg4_data_t hwcfg4 = {.d32 = 0 };
27506 + hwcfg4.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
27508 + if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
27509 + DWC_WARN("`%d' invalid for parameter `power_down'\n", val);
27510 + DWC_WARN("power_down must be 0 - 2\n");
27511 + return -DWC_E_INVALID;
27514 + if ((val == 2) && (core_if->snpsid < OTG_CORE_REV_2_91a)) {
27518 + && ((core_if->snpsid < OTG_CORE_REV_3_00a)
27519 + || (hwcfg4.b.xhiber == 0))) {
27522 + if (valid == 0) {
27523 + if (dwc_otg_param_initialized(core_if->core_params->power_down)) {
27525 + ("%d invalid for parameter power_down. Check HW configuration.\n",
27528 + retval = -DWC_E_INVALID;
27531 + core_if->core_params->power_down = val;
27535 +int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if)
27537 + return core_if->core_params->power_down;
27540 +int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if, int32_t val)
27545 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27546 + DWC_WARN("`%d' invalid for parameter `reload_ctl'\n", val);
27547 + DWC_WARN("reload_ctl must be 0 or 1\n");
27548 + return -DWC_E_INVALID;
27551 + if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_92a)) {
27554 + if (valid == 0) {
27555 + if (dwc_otg_param_initialized(core_if->core_params->reload_ctl)) {
27556 + DWC_ERROR("%d invalid for parameter reload_ctl."
27557 + "Check HW configuration.\n", val);
27559 + retval = -DWC_E_INVALID;
27562 + core_if->core_params->reload_ctl = val;
27566 +int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if)
27568 + return core_if->core_params->reload_ctl;
27571 +int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if, int32_t val)
27576 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27577 + DWC_WARN("`%d' invalid for parameter `dev_out_nak'\n", val);
27578 + DWC_WARN("dev_out_nak must be 0 or 1\n");
27579 + return -DWC_E_INVALID;
27582 + if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_93a) ||
27583 + !(core_if->core_params->dma_desc_enable))) {
27586 + if (valid == 0) {
27587 + if (dwc_otg_param_initialized(core_if->core_params->dev_out_nak)) {
27588 + DWC_ERROR("%d invalid for parameter dev_out_nak."
27589 + "Check HW configuration.\n", val);
27591 + retval = -DWC_E_INVALID;
27594 + core_if->core_params->dev_out_nak = val;
27598 +int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if)
27600 + return core_if->core_params->dev_out_nak;
27603 +int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if, int32_t val)
27608 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27609 + DWC_WARN("`%d' invalid for parameter `cont_on_bna'\n", val);
27610 + DWC_WARN("cont_on_bna must be 0 or 1\n");
27611 + return -DWC_E_INVALID;
27614 + if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_94a) ||
27615 + !(core_if->core_params->dma_desc_enable))) {
27618 + if (valid == 0) {
27619 + if (dwc_otg_param_initialized(core_if->core_params->cont_on_bna)) {
27620 + DWC_ERROR("%d invalid for parameter cont_on_bna."
27621 + "Check HW configuration.\n", val);
27623 + retval = -DWC_E_INVALID;
27626 + core_if->core_params->cont_on_bna = val;
27630 +int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if)
27632 + return core_if->core_params->cont_on_bna;
27635 +int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if, int32_t val)
27640 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27641 + DWC_WARN("`%d' invalid for parameter `ahb_single'\n", val);
27642 + DWC_WARN("ahb_single must be 0 or 1\n");
27643 + return -DWC_E_INVALID;
27646 + if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
27649 + if (valid == 0) {
27650 + if (dwc_otg_param_initialized(core_if->core_params->ahb_single)) {
27651 + DWC_ERROR("%d invalid for parameter ahb_single."
27652 + "Check HW configuration.\n", val);
27654 + retval = -DWC_E_INVALID;
27657 + core_if->core_params->ahb_single = val;
27661 +int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if)
27663 + return core_if->core_params->ahb_single;
27666 +int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val)
27670 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27671 + DWC_WARN("`%d' invalid for parameter `otg_ver'\n", val);
27673 + ("otg_ver must be 0(for OTG 1.3 support) or 1(for OTG 2.0 support)\n");
27674 + return -DWC_E_INVALID;
27677 + core_if->core_params->otg_ver = val;
27681 +int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if)
27683 + return core_if->core_params->otg_ver;
27686 +uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if)
27688 + gotgctl_data_t otgctl;
27689 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27690 + return otgctl.b.hstnegscs;
27693 +uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if)
27695 + gotgctl_data_t otgctl;
27696 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27697 + return otgctl.b.sesreqscs;
27700 +void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val)
27702 + if(core_if->otg_ver == 0) {
27703 + gotgctl_data_t otgctl;
27704 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27705 + otgctl.b.hnpreq = val;
27706 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, otgctl.d32);
27708 + core_if->otg_sts = val;
27712 +uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if)
27714 + return core_if->snpsid;
27717 +uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if)
27719 + gintsts_data_t gintsts;
27720 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
27721 + return gintsts.b.curmode;
27724 +uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if)
27726 + gusbcfg_data_t usbcfg;
27727 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27728 + return usbcfg.b.hnpcap;
27731 +void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
27733 + gusbcfg_data_t usbcfg;
27734 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27735 + usbcfg.b.hnpcap = val;
27736 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
27739 +uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if)
27741 + gusbcfg_data_t usbcfg;
27742 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27743 + return usbcfg.b.srpcap;
27746 +void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
27748 + gusbcfg_data_t usbcfg;
27749 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27750 + usbcfg.b.srpcap = val;
27751 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
27754 +uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if)
27756 + dcfg_data_t dcfg;
27757 + /* originally: dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg); */
27759 + dcfg.d32 = -1; //GRAYG
27760 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)\n", __func__, core_if);
27761 + if (NULL == core_if)
27762 + DWC_ERROR("reg request with NULL core_if\n");
27763 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)\n", __func__,
27764 + core_if, core_if->dev_if);
27765 + if (NULL == core_if->dev_if)
27766 + DWC_ERROR("reg request with NULL dev_if\n");
27767 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)->"
27768 + "dev_global_regs(%p)\n", __func__,
27769 + core_if, core_if->dev_if,
27770 + core_if->dev_if->dev_global_regs);
27771 + if (NULL == core_if->dev_if->dev_global_regs)
27772 + DWC_ERROR("reg request with NULL dev_global_regs\n");
27774 + DWC_DEBUGPL(DBG_CILV, "%s - &core_if(%p)->dev_if(%p)->"
27775 + "dev_global_regs(%p)->dcfg = %p\n", __func__,
27776 + core_if, core_if->dev_if,
27777 + core_if->dev_if->dev_global_regs,
27778 + &core_if->dev_if->dev_global_regs->dcfg);
27779 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
27781 + return dcfg.b.devspd;
27784 +void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val)
27786 + dcfg_data_t dcfg;
27787 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
27788 + dcfg.b.devspd = val;
27789 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
27792 +uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if)
27794 + hprt0_data_t hprt0;
27795 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27796 + return hprt0.b.prtconnsts;
27799 +uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if)
27801 + dsts_data_t dsts;
27802 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
27803 + return dsts.b.enumspd;
27806 +uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if)
27808 + hprt0_data_t hprt0;
27809 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27810 + return hprt0.b.prtpwr;
27814 +uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if)
27816 + return core_if->hibernation_suspend;
27819 +void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val)
27821 + hprt0_data_t hprt0;
27822 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27823 + hprt0.b.prtpwr = val;
27824 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27827 +uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if)
27829 + hprt0_data_t hprt0;
27830 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27831 + return hprt0.b.prtsusp;
27835 +void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val)
27837 + hprt0_data_t hprt0;
27838 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27839 + hprt0.b.prtsusp = val;
27840 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27843 +uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if)
27845 + hfir_data_t hfir;
27846 + hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
27847 + return hfir.b.frint;
27851 +void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val)
27853 + hfir_data_t hfir;
27854 + uint32_t fram_int;
27855 + fram_int = calc_frame_interval(core_if);
27856 + hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
27857 + if (!core_if->core_params->reload_ctl) {
27858 + DWC_WARN("\nCannot reload HFIR register.HFIR.HFIRRldCtrl bit is"
27859 + "not set to 1.\nShould load driver with reload_ctl=1"
27860 + " module parameter\n");
27863 + switch (fram_int) {
27865 + if ((val < 3350) || (val > 4150)) {
27866 + DWC_WARN("HFIR interval for HS core and 30 MHz"
27867 + "clock freq should be from 3350 to 4150\n");
27872 + if ((val < 26820) || (val > 33180)) {
27873 + DWC_WARN("HFIR interval for FS/LS core and 30 MHz"
27874 + "clock freq should be from 26820 to 33180\n");
27879 + if ((val < 5360) || (val > 6640)) {
27880 + DWC_WARN("HFIR interval for HS core and 48 MHz"
27881 + "clock freq should be from 5360 to 6640\n");
27886 + if ((val < 42912) || (val > 53088)) {
27887 + DWC_WARN("HFIR interval for FS/LS core and 48 MHz"
27888 + "clock freq should be from 42912 to 53088\n");
27893 + if ((val < 6700) || (val > 8300)) {
27894 + DWC_WARN("HFIR interval for HS core and 60 MHz"
27895 + "clock freq should be from 6700 to 8300\n");
27900 + if ((val < 53640) || (val > 65536)) {
27901 + DWC_WARN("HFIR interval for FS/LS core and 60 MHz"
27902 + "clock freq should be from 53640 to 65536\n");
27907 + DWC_WARN("Unknown frame interval\n");
27912 + hfir.b.frint = val;
27913 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hfir.d32);
27916 +uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if)
27918 + hcfg_data_t hcfg;
27919 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
27920 + return hcfg.b.modechtimen;
27924 +void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val)
27926 + hcfg_data_t hcfg;
27927 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
27928 + hcfg.b.modechtimen = val;
27929 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
27932 +void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val)
27934 + hprt0_data_t hprt0;
27935 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27936 + hprt0.b.prtres = val;
27937 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27940 +uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if)
27942 + dctl_data_t dctl;
27943 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
27944 + return dctl.b.rmtwkupsig;
27947 +uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if)
27949 + glpmcfg_data_t lpmcfg;
27950 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27953 + ((core_if->lx_state == DWC_OTG_L1) ^ lpmcfg.b.prt_sleep_sts),
27954 + "lx_state = %d, lmpcfg.prt_sleep_sts = %d\n",
27955 + core_if->lx_state, lpmcfg.b.prt_sleep_sts);
27957 + return lpmcfg.b.prt_sleep_sts;
27960 +uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if)
27962 + glpmcfg_data_t lpmcfg;
27963 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27964 + return lpmcfg.b.rem_wkup_en;
27967 +uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if)
27969 + glpmcfg_data_t lpmcfg;
27970 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27971 + return lpmcfg.b.appl_resp;
27974 +void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val)
27976 + glpmcfg_data_t lpmcfg;
27977 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27978 + lpmcfg.b.appl_resp = val;
27979 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
27982 +uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if)
27984 + glpmcfg_data_t lpmcfg;
27985 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27986 + return lpmcfg.b.hsic_connect;
27989 +void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val)
27991 + glpmcfg_data_t lpmcfg;
27992 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
27993 + lpmcfg.b.hsic_connect = val;
27994 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
27997 +uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if)
27999 + glpmcfg_data_t lpmcfg;
28000 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28001 + return lpmcfg.b.inv_sel_hsic;
28005 +void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val)
28007 + glpmcfg_data_t lpmcfg;
28008 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28009 + lpmcfg.b.inv_sel_hsic = val;
28010 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
28013 +uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if)
28015 + return DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
28018 +void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val)
28020 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, val);
28023 +uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if)
28025 + return DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
28028 +void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val)
28030 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, val);
28033 +uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if)
28035 + return DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
28038 +void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
28040 + DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, val);
28043 +uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if)
28045 + return DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
28048 +void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
28050 + DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz, val);
28053 +uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if)
28055 + return DWC_READ_REG32(&core_if->core_global_regs->gpvndctl);
28058 +void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val)
28060 + DWC_WRITE_REG32(&core_if->core_global_regs->gpvndctl, val);
28063 +uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if)
28065 + return DWC_READ_REG32(&core_if->core_global_regs->ggpio);
28068 +void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val)
28070 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, val);
28073 +uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if)
28075 + return DWC_READ_REG32(core_if->host_if->hprt0);
28079 +void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val)
28081 + DWC_WRITE_REG32(core_if->host_if->hprt0, val);
28084 +uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if)
28086 + return DWC_READ_REG32(&core_if->core_global_regs->guid);
28089 +void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val)
28091 + DWC_WRITE_REG32(&core_if->core_global_regs->guid, val);
28094 +uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if)
28096 + return DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
28099 +uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if)
28101 + return ((core_if->otg_ver == 1) ? (uint16_t)0x0200 : (uint16_t)0x0103);
28105 + * Start the SRP timer to detect when the SRP does not complete within
28108 + * @param core_if the pointer to core_if strucure.
28110 +void dwc_otg_pcd_start_srp_timer(dwc_otg_core_if_t * core_if)
28112 + core_if->srp_timer_started = 1;
28113 + DWC_TIMER_SCHEDULE(core_if->srp_timer, 6000 /* 6 secs */ );
28116 +void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if)
28118 + uint32_t *addr = (uint32_t *) & (core_if->core_global_regs->gotgctl);
28119 + gotgctl_data_t mem;
28120 + gotgctl_data_t val;
28122 + val.d32 = DWC_READ_REG32(addr);
28123 + if (val.b.sesreq) {
28124 + DWC_ERROR("Session Request Already active!\n");
28128 + DWC_INFO("Session Request Initated\n"); //NOTICE
28129 + mem.d32 = DWC_READ_REG32(addr);
28130 + mem.b.sesreq = 1;
28131 + DWC_WRITE_REG32(addr, mem.d32);
28133 + /* Start the SRP timer */
28134 + dwc_otg_pcd_start_srp_timer(core_if);
28138 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.h
28140 +/* ==========================================================================
28141 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.h $
28142 + * $Revision: #123 $
28143 + * $Date: 2012/08/10 $
28144 + * $Change: 2047372 $
28146 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
28147 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
28148 + * otherwise expressly agreed to in writing between Synopsys and you.
28150 + * The Software IS NOT an item of Licensed Software or Licensed Product under
28151 + * any End User Software License Agreement or Agreement for Licensed Product
28152 + * with Synopsys or any supplement thereto. You are permitted to use and
28153 + * redistribute this Software in source and binary forms, with or without
28154 + * modification, provided that redistributions of source code must retain this
28155 + * notice. You may not view, use, disclose, copy or distribute this file or
28156 + * any information contained herein except pursuant to this license grant from
28157 + * Synopsys. If you do not agree with this notice, including the disclaimer
28158 + * below, then you are not authorized to use the Software.
28160 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
28161 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28162 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28163 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
28164 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28165 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28166 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28167 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28168 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28169 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28171 + * ========================================================================== */
28173 +#if !defined(__DWC_CIL_H__)
28174 +#define __DWC_CIL_H__
28176 +#include "dwc_list.h"
28177 +#include "dwc_otg_dbg.h"
28178 +#include "dwc_otg_regs.h"
28180 +#include "dwc_otg_core_if.h"
28181 +#include "dwc_otg_adp.h"
28185 + * This file contains the interface to the Core Interface Layer.
28188 +#ifdef DWC_UTE_CFI
28190 +#define MAX_DMA_DESCS_PER_EP 256
28193 + * Enumeration for the data buffer mode
28195 +typedef enum _data_buffer_mode {
28196 + BM_STANDARD = 0, /* data buffer is in normal mode */
28197 + BM_SG = 1, /* data buffer uses the scatter/gather mode */
28198 + BM_CONCAT = 2, /* data buffer uses the concatenation mode */
28199 + BM_CIRCULAR = 3, /* data buffer uses the circular DMA mode */
28200 + BM_ALIGN = 4 /* data buffer is in buffer alignment mode */
28201 +} data_buffer_mode_e;
28202 +#endif //DWC_UTE_CFI
28204 +/** Macros defined for DWC OTG HW Release version */
28206 +#define OTG_CORE_REV_2_60a 0x4F54260A
28207 +#define OTG_CORE_REV_2_71a 0x4F54271A
28208 +#define OTG_CORE_REV_2_72a 0x4F54272A
28209 +#define OTG_CORE_REV_2_80a 0x4F54280A
28210 +#define OTG_CORE_REV_2_81a 0x4F54281A
28211 +#define OTG_CORE_REV_2_90a 0x4F54290A
28212 +#define OTG_CORE_REV_2_91a 0x4F54291A
28213 +#define OTG_CORE_REV_2_92a 0x4F54292A
28214 +#define OTG_CORE_REV_2_93a 0x4F54293A
28215 +#define OTG_CORE_REV_2_94a 0x4F54294A
28216 +#define OTG_CORE_REV_3_00a 0x4F54300A
28219 + * Information for each ISOC packet.
28221 +typedef struct iso_pkt_info {
28228 + * The <code>dwc_ep</code> structure represents the state of a single
28229 + * endpoint when acting in device mode. It contains the data items
28230 + * needed for an endpoint to be activated and transfer packets.
28232 +typedef struct dwc_ep {
28233 + /** EP number used for register address lookup */
28235 + /** EP direction 0 = OUT */
28236 + unsigned is_in:1;
28237 + /** EP active. */
28238 + unsigned active:1;
28241 + * Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic
28242 + * Tx FIFO. If dedicated Tx FIFOs are enabled Tx FIFO # FOR IN EPs*/
28243 + unsigned tx_fifo_num:4;
28244 + /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */
28246 +#define DWC_OTG_EP_TYPE_CONTROL 0
28247 +#define DWC_OTG_EP_TYPE_ISOC 1
28248 +#define DWC_OTG_EP_TYPE_BULK 2
28249 +#define DWC_OTG_EP_TYPE_INTR 3
28251 + /** DATA start PID for INTR and BULK EP */
28252 + unsigned data_pid_start:1;
28253 + /** Frame (even/odd) for ISOC EP */
28254 + unsigned even_odd_frame:1;
28255 + /** Max Packet bytes */
28256 + unsigned maxpacket:11;
28258 + /** Max Transfer size */
28259 + uint32_t maxxfer;
28261 + /** @name Transfer state */
28265 + * Pointer to the beginning of the transfer buffer -- do not modify
28266 + * during transfer.
28269 + dwc_dma_t dma_addr;
28271 + dwc_dma_t dma_desc_addr;
28272 + dwc_otg_dev_dma_desc_t *desc_addr;
28274 + uint8_t *start_xfer_buff;
28275 + /** pointer to the transfer buffer */
28276 + uint8_t *xfer_buff;
28277 + /** Number of bytes to transfer */
28278 + unsigned xfer_len:19;
28279 + /** Number of bytes transferred. */
28280 + unsigned xfer_count:19;
28282 + unsigned sent_zlp:1;
28283 + /** Total len for control transfer */
28284 + unsigned total_len:19;
28286 + /** stall clear flag */
28287 + unsigned stall_clear_flag:1;
28289 + /** SETUP pkt cnt rollover flag for EP0 out*/
28290 + unsigned stp_rollover;
28292 +#ifdef DWC_UTE_CFI
28293 + /* The buffer mode */
28294 + data_buffer_mode_e buff_mode;
28296 + /* The chain of DMA descriptors.
28297 + * MAX_DMA_DESCS_PER_EP will be allocated for each active EP.
28299 + dwc_otg_dma_desc_t *descs;
28301 + /* The DMA address of the descriptors chain start */
28302 + dma_addr_t descs_dma_addr;
28303 + /** This variable stores the length of the last enqueued request */
28304 + uint32_t cfi_req_len;
28305 +#endif //DWC_UTE_CFI
28307 +/** Max DMA Descriptor count for any EP */
28308 +#define MAX_DMA_DESC_CNT 256
28309 + /** Allocated DMA Desc count */
28310 + uint32_t desc_cnt;
28313 + uint32_t bInterval;
28314 + /** Next frame num to setup next ISOC transfer */
28315 + uint32_t frame_num;
28316 + /** Indicates SOF number overrun in DSTS */
28317 + uint8_t frm_overrun;
28319 +#ifdef DWC_UTE_PER_IO
28320 + /** Next frame num for which will be setup DMA Desc */
28321 + uint32_t xiso_frame_num;
28323 + uint32_t xiso_bInterval;
28324 + /** Count of currently active transfers - shall be either 0 or 1 */
28325 + int xiso_active_xfers;
28326 + int xiso_queued_xfers;
28328 +#ifdef DWC_EN_ISOC
28330 + * Variables specific for ISOC EPs
28333 + /** DMA addresses of ISOC buffers */
28334 + dwc_dma_t dma_addr0;
28335 + dwc_dma_t dma_addr1;
28337 + dwc_dma_t iso_dma_desc_addr;
28338 + dwc_otg_dev_dma_desc_t *iso_desc_addr;
28340 + /** pointer to the transfer buffers */
28341 + uint8_t *xfer_buff0;
28342 + uint8_t *xfer_buff1;
28344 + /** number of ISOC Buffer is processing */
28345 + uint32_t proc_buf_num;
28346 + /** Interval of ISOC Buffer processing */
28347 + uint32_t buf_proc_intrvl;
28348 + /** Data size for regular frame */
28349 + uint32_t data_per_frame;
28351 + /* todo - pattern data support is to be implemented in the future */
28352 + /** Data size for pattern frame */
28353 + uint32_t data_pattern_frame;
28354 + /** Frame number of pattern data */
28355 + uint32_t sync_frame;
28358 + uint32_t bInterval;
28359 + /** ISO Packet number per frame */
28360 + uint32_t pkt_per_frm;
28361 + /** Next frame num for which will be setup DMA Desc */
28362 + uint32_t next_frame;
28363 + /** Number of packets per buffer processing */
28364 + uint32_t pkt_cnt;
28365 + /** Info for all isoc packets */
28366 + iso_pkt_info_t *pkt_info;
28367 + /** current pkt number */
28368 + uint32_t cur_pkt;
28369 + /** current pkt number */
28370 + uint8_t *cur_pkt_addr;
28371 + /** current pkt number */
28372 + uint32_t cur_pkt_dma_addr;
28373 +#endif /* DWC_EN_ISOC */
28379 + * Reasons for halting a host channel.
28381 +typedef enum dwc_otg_halt_status {
28382 + DWC_OTG_HC_XFER_NO_HALT_STATUS,
28383 + DWC_OTG_HC_XFER_COMPLETE,
28384 + DWC_OTG_HC_XFER_URB_COMPLETE,
28385 + DWC_OTG_HC_XFER_ACK,
28386 + DWC_OTG_HC_XFER_NAK,
28387 + DWC_OTG_HC_XFER_NYET,
28388 + DWC_OTG_HC_XFER_STALL,
28389 + DWC_OTG_HC_XFER_XACT_ERR,
28390 + DWC_OTG_HC_XFER_FRAME_OVERRUN,
28391 + DWC_OTG_HC_XFER_BABBLE_ERR,
28392 + DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
28393 + DWC_OTG_HC_XFER_AHB_ERR,
28394 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
28395 + DWC_OTG_HC_XFER_URB_DEQUEUE
28396 +} dwc_otg_halt_status_e;
28399 + * Host channel descriptor. This structure represents the state of a single
28400 + * host channel when acting in host mode. It contains the data items needed to
28401 + * transfer packets to an endpoint via a host channel.
28403 +typedef struct dwc_hc {
28404 + /** Host channel number used for register address lookup */
28407 + /** Device to access */
28408 + unsigned dev_addr:7;
28410 + /** EP to access */
28411 + unsigned ep_num:4;
28413 + /** EP direction. 0: OUT, 1: IN */
28414 + unsigned ep_is_in:1;
28418 + * One of the following values:
28419 + * - DWC_OTG_EP_SPEED_LOW
28420 + * - DWC_OTG_EP_SPEED_FULL
28421 + * - DWC_OTG_EP_SPEED_HIGH
28423 + unsigned speed:2;
28424 +#define DWC_OTG_EP_SPEED_LOW 0
28425 +#define DWC_OTG_EP_SPEED_FULL 1
28426 +#define DWC_OTG_EP_SPEED_HIGH 2
28430 + * One of the following values:
28431 + * - DWC_OTG_EP_TYPE_CONTROL: 0
28432 + * - DWC_OTG_EP_TYPE_ISOC: 1
28433 + * - DWC_OTG_EP_TYPE_BULK: 2
28434 + * - DWC_OTG_EP_TYPE_INTR: 3
28436 + unsigned ep_type:2;
28438 + /** Max packet size in bytes */
28439 + unsigned max_packet:11;
28442 + * PID for initial transaction.
28446 + * 3: MDATA (non-Control EP),
28447 + * SETUP (Control EP)
28449 + unsigned data_pid_start:2;
28450 +#define DWC_OTG_HC_PID_DATA0 0
28451 +#define DWC_OTG_HC_PID_DATA2 1
28452 +#define DWC_OTG_HC_PID_DATA1 2
28453 +#define DWC_OTG_HC_PID_MDATA 3
28454 +#define DWC_OTG_HC_PID_SETUP 3
28456 + /** Number of periodic transactions per (micro)frame */
28457 + unsigned multi_count:2;
28459 + /** @name Transfer State */
28462 + /** Pointer to the current transfer buffer position. */
28463 + uint8_t *xfer_buff;
28465 + * In Buffer DMA mode this buffer will be used
28466 + * if xfer_buff is not DWORD aligned.
28468 + dwc_dma_t align_buff;
28469 + /** Total number of bytes to transfer. */
28470 + uint32_t xfer_len;
28471 + /** Number of bytes transferred so far. */
28472 + uint32_t xfer_count;
28473 + /** Packet count at start of transfer.*/
28474 + uint16_t start_pkt_count;
28477 + * Flag to indicate whether the transfer has been started. Set to 1 if
28478 + * it has been started, 0 otherwise.
28480 + uint8_t xfer_started;
28483 + * Set to 1 to indicate that a PING request should be issued on this
28484 + * channel. If 0, process normally.
28489 + * Set to 1 to indicate that the error count for this transaction is
28490 + * non-zero. Set to 0 if the error count is 0.
28492 + uint8_t error_state;
28495 + * Set to 1 to indicate that this channel should be halted the next
28496 + * time a request is queued for the channel. This is necessary in
28497 + * slave mode if no request queue space is available when an attempt
28498 + * is made to halt the channel.
28500 + uint8_t halt_on_queue;
28503 + * Set to 1 if the host channel has been halted, but the core is not
28504 + * finished flushing queued requests. Otherwise 0.
28506 + uint8_t halt_pending;
28509 + * Reason for halting the host channel.
28511 + dwc_otg_halt_status_e halt_status;
28514 + * Split settings for the host channel
28516 + uint8_t do_split; /**< Enable split for the channel */
28517 + uint8_t complete_split; /**< Enable complete split */
28518 + uint8_t hub_addr; /**< Address of high speed hub */
28520 + uint8_t port_addr; /**< Port of the low/full speed device */
28521 + /** Split transaction position
28522 + * One of the following values:
28523 + * - DWC_HCSPLIT_XACTPOS_MID
28524 + * - DWC_HCSPLIT_XACTPOS_BEGIN
28525 + * - DWC_HCSPLIT_XACTPOS_END
28526 + * - DWC_HCSPLIT_XACTPOS_ALL */
28527 + uint8_t xact_pos;
28529 + /** Set when the host channel does a short read. */
28530 + uint8_t short_read;
28533 + * Number of requests issued for this channel since it was assigned to
28534 + * the current transfer (not counting PINGs).
28536 + uint8_t requests;
28539 + * Queue Head for the transfer being processed by this channel.
28541 + struct dwc_otg_qh *qh;
28545 + /** Entry in list of host channels. */
28546 + DWC_CIRCLEQ_ENTRY(dwc_hc) hc_list_entry;
28548 + /** @name Descriptor DMA support */
28551 + /** Number of Transfer Descriptors */
28554 + /** Descriptor List DMA address */
28555 + dwc_dma_t desc_list_addr;
28557 + /** Scheduling micro-frame bitmap. */
28564 + * The following parameters may be specified when starting the module. These
28565 + * parameters define how the DWC_otg controller should be configured.
28567 +typedef struct dwc_otg_core_params {
28571 + * Specifies the OTG capabilities. The driver will automatically
28572 + * detect the value for this parameter if none is specified.
28573 + * 0 - HNP and SRP capable (default)
28574 + * 1 - SRP Only capable
28575 + * 2 - No HNP/SRP capable
28580 + * Specifies whether to use slave or DMA mode for accessing the data
28581 + * FIFOs. The driver will automatically detect the value for this
28582 + * parameter if none is specified.
28584 + * 1 - DMA (default, if available)
28586 + int32_t dma_enable;
28589 + * When DMA mode is enabled specifies whether to use address DMA or DMA
28590 + * Descriptor mode for accessing the data FIFOs in device mode. The driver
28591 + * will automatically detect the value for this if none is specified.
28592 + * 0 - address DMA
28593 + * 1 - DMA Descriptor(default, if available)
28595 + int32_t dma_desc_enable;
28596 + /** The DMA Burst size (applicable only for External DMA
28597 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
28599 + int32_t dma_burst_size; /* Translate this to GAHBCFG values */
28602 + * Specifies the maximum speed of operation in host and device mode.
28603 + * The actual speed depends on the speed of the attached device and
28604 + * the value of phy_type. The actual speed depends on the speed of the
28605 + * attached device.
28606 + * 0 - High Speed (default)
28610 + /** Specifies whether low power mode is supported when attached
28611 + * to a Full Speed or Low Speed device in host mode.
28612 + * 0 - Don't support low power mode (default)
28613 + * 1 - Support low power mode
28615 + int32_t host_support_fs_ls_low_power;
28617 + /** Specifies the PHY clock rate in low power mode when connected to a
28618 + * Low Speed device in host mode. This parameter is applicable only if
28619 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
28620 + * then defaults to 6 MHZ otherwise 48 MHZ.
28625 + int32_t host_ls_low_power_phy_clk;
28628 + * 0 - Use cC FIFO size parameters
28629 + * 1 - Allow dynamic FIFO sizing (default)
28631 + int32_t enable_dynamic_fifo;
28633 + /** Total number of 4-byte words in the data FIFO memory. This
28634 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
28636 + * 32 to 32768 (default 8192)
28637 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
28639 + int32_t data_fifo_size;
28641 + /** Number of 4-byte words in the Rx FIFO in device mode when dynamic
28642 + * FIFO sizing is enabled.
28643 + * 16 to 32768 (default 1064)
28645 + int32_t dev_rx_fifo_size;
28647 + /** Number of 4-byte words in the non-periodic Tx FIFO in device mode
28648 + * when dynamic FIFO sizing is enabled.
28649 + * 16 to 32768 (default 1024)
28651 + int32_t dev_nperio_tx_fifo_size;
28653 + /** Number of 4-byte words in each of the periodic Tx FIFOs in device
28654 + * mode when dynamic FIFO sizing is enabled.
28655 + * 4 to 768 (default 256)
28657 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
28659 + /** Number of 4-byte words in the Rx FIFO in host mode when dynamic
28660 + * FIFO sizing is enabled.
28661 + * 16 to 32768 (default 1024)
28663 + int32_t host_rx_fifo_size;
28665 + /** Number of 4-byte words in the non-periodic Tx FIFO in host mode
28666 + * when Dynamic FIFO sizing is enabled in the core.
28667 + * 16 to 32768 (default 1024)
28669 + int32_t host_nperio_tx_fifo_size;
28671 + /** Number of 4-byte words in the host periodic Tx FIFO when dynamic
28672 + * FIFO sizing is enabled.
28673 + * 16 to 32768 (default 1024)
28675 + int32_t host_perio_tx_fifo_size;
28677 + /** The maximum transfer size supported in bytes.
28678 + * 2047 to 65,535 (default 65,535)
28680 + int32_t max_transfer_size;
28682 + /** The maximum number of packets in a transfer.
28683 + * 15 to 511 (default 511)
28685 + int32_t max_packet_count;
28687 + /** The number of host channel registers to use.
28688 + * 1 to 16 (default 12)
28689 + * Note: The FPGA configuration supports a maximum of 12 host channels.
28691 + int32_t host_channels;
28693 + /** The number of endpoints in addition to EP0 available for device
28694 + * mode operations.
28695 + * 1 to 15 (default 6 IN and OUT)
28696 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
28697 + * endpoints in addition to EP0.
28699 + int32_t dev_endpoints;
28702 + * Specifies the type of PHY interface to use. By default, the driver
28703 + * will automatically detect the phy_type.
28705 + * 0 - Full Speed PHY
28706 + * 1 - UTMI+ (default)
28709 + int32_t phy_type;
28712 + * Specifies the UTMI+ Data Width. This parameter is
28713 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
28714 + * PHY_TYPE, this parameter indicates the data width between
28715 + * the MAC and the ULPI Wrapper.) Also, this parameter is
28716 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
28717 + * to "8 and 16 bits", meaning that the core has been
28718 + * configured to work at either data path width.
28720 + * 8 or 16 bits (default 16)
28722 + int32_t phy_utmi_width;
28725 + * Specifies whether the ULPI operates at double or single
28726 + * data rate. This parameter is only applicable if PHY_TYPE is
28729 + * 0 - single data rate ULPI interface with 8 bit wide data
28731 + * 1 - double data rate ULPI interface with 4 bit wide data
28734 + int32_t phy_ulpi_ddr;
28737 + * Specifies whether to use the internal or external supply to
28738 + * drive the vbus with a ULPI phy.
28740 + int32_t phy_ulpi_ext_vbus;
28743 + * Specifies whether to use the I2Cinterface for full speed PHY. This
28744 + * parameter is only applicable if PHY_TYPE is FS.
28745 + * 0 - No (default)
28748 + int32_t i2c_enable;
28750 + int32_t ulpi_fs_ls;
28752 + int32_t ts_dline;
28755 + * Specifies whether dedicated transmit FIFOs are
28756 + * enabled for non periodic IN endpoints in device mode
28760 + int32_t en_multiple_tx_fifo;
28762 + /** Number of 4-byte words in each of the Tx FIFOs in device
28763 + * mode when dynamic FIFO sizing is enabled.
28764 + * 4 to 768 (default 256)
28766 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
28768 + /** Thresholding enable flag-
28769 + * bit 0 - enable non-ISO Tx thresholding
28770 + * bit 1 - enable ISO Tx thresholding
28771 + * bit 2 - enable Rx thresholding
28773 + uint32_t thr_ctl;
28775 + /** Thresholding length for Tx
28776 + * FIFOs in 32 bit DWORDs
28778 + uint32_t tx_thr_length;
28780 + /** Thresholding length for Rx
28781 + * FIFOs in 32 bit DWORDs
28783 + uint32_t rx_thr_length;
28786 + * Specifies whether LPM (Link Power Management) support is enabled
28788 + int32_t lpm_enable;
28790 + /** Per Transfer Interrupt
28791 + * mode enable flag
28795 + int32_t pti_enable;
28797 + /** Multi Processor Interrupt
28798 + * mode enable flag
28802 + int32_t mpi_enable;
28804 + /** IS_USB Capability
28808 + int32_t ic_usb_cap;
28810 + /** AHB Threshold Ratio
28811 + * 2'b00 AHB Threshold = MAC Threshold
28812 + * 2'b01 AHB Threshold = 1/2 MAC Threshold
28813 + * 2'b10 AHB Threshold = 1/4 MAC Threshold
28814 + * 2'b11 AHB Threshold = 1/8 MAC Threshold
28816 + int32_t ahb_thr_ratio;
28822 + int32_t adp_supp_enable;
28824 + /** HFIR Reload Control
28825 + * 0 - The HFIR cannot be reloaded dynamically.
28826 + * 1 - Allow dynamic reloading of the HFIR register during runtime.
28828 + int32_t reload_ctl;
28830 + /** DCFG: Enable device Out NAK
28831 + * 0 - The core does not set NAK after Bulk Out transfer complete.
28832 + * 1 - The core sets NAK after Bulk OUT transfer complete.
28834 + int32_t dev_out_nak;
28836 + /** DCFG: Enable Continue on BNA
28837 + * After receiving BNA interrupt the core disables the endpoint,when the
28838 + * endpoint is re-enabled by the application the core starts processing
28839 + * 0 - from the DOEPDMA descriptor
28840 + * 1 - from the descriptor which received the BNA.
28842 + int32_t cont_on_bna;
28844 + /** GAHBCFG: AHB Single Support
28845 + * This bit when programmed supports SINGLE transfers for remainder
28846 + * data in a transfer for DMA mode of operation.
28847 + * 0 - in this case the remainder data will be sent using INCR burst size.
28848 + * 1 - in this case the remainder data will be sent using SINGLE burst size.
28850 + int32_t ahb_single;
28852 + /** Core Power down mode
28853 + * 0 - No Power Down is enabled
28855 + * 2 - Complete Power Down (Hibernation)
28857 + int32_t power_down;
28859 + /** OTG revision supported
28860 + * 0 - OTG 1.3 revision
28861 + * 1 - OTG 2.0 revision
28865 +} dwc_otg_core_params_t;
28868 +struct dwc_otg_core_if;
28869 +typedef struct hc_xfer_info {
28870 + struct dwc_otg_core_if *core_if;
28875 +typedef struct ep_xfer_info {
28876 + struct dwc_otg_core_if *core_if;
28883 +typedef enum dwc_otg_lx_state {
28886 + /** LPM sleep state*/
28888 + /** USB suspend state*/
28892 +} dwc_otg_lx_state_e;
28894 +struct dwc_otg_global_regs_backup {
28895 + uint32_t gotgctl_local;
28896 + uint32_t gintmsk_local;
28897 + uint32_t gahbcfg_local;
28898 + uint32_t gusbcfg_local;
28899 + uint32_t grxfsiz_local;
28900 + uint32_t gnptxfsiz_local;
28901 +#ifdef CONFIG_USB_DWC_OTG_LPM
28902 + uint32_t glpmcfg_local;
28904 + uint32_t gi2cctl_local;
28905 + uint32_t hptxfsiz_local;
28906 + uint32_t pcgcctl_local;
28907 + uint32_t gdfifocfg_local;
28908 + uint32_t dtxfsiz_local[MAX_EPS_CHANNELS];
28909 + uint32_t gpwrdn_local;
28910 + uint32_t xhib_pcgcctl;
28911 + uint32_t xhib_gpwrdn;
28914 +struct dwc_otg_host_regs_backup {
28915 + uint32_t hcfg_local;
28916 + uint32_t haintmsk_local;
28917 + uint32_t hcintmsk_local[MAX_EPS_CHANNELS];
28918 + uint32_t hprt0_local;
28919 + uint32_t hfir_local;
28922 +struct dwc_otg_dev_regs_backup {
28925 + uint32_t daintmsk;
28926 + uint32_t diepmsk;
28927 + uint32_t doepmsk;
28928 + uint32_t diepctl[MAX_EPS_CHANNELS];
28929 + uint32_t dieptsiz[MAX_EPS_CHANNELS];
28930 + uint32_t diepdma[MAX_EPS_CHANNELS];
28933 + * The <code>dwc_otg_core_if</code> structure contains information needed to manage
28934 + * the DWC_otg controller acting in either host or device mode. It
28935 + * represents the programming view of the controller as a whole.
28937 +struct dwc_otg_core_if {
28938 + /** Parameters that define how the core should be configured.*/
28939 + dwc_otg_core_params_t *core_params;
28941 + /** Core Global registers starting at offset 000h. */
28942 + dwc_otg_core_global_regs_t *core_global_regs;
28944 + /** Device-specific information */
28945 + dwc_otg_dev_if_t *dev_if;
28946 + /** Host-specific information */
28947 + dwc_otg_host_if_t *host_if;
28949 + /** Value from SNPSID register */
28953 + * Set to 1 if the core PHY interface bits in USBCFG have been
28956 + uint8_t phy_init_done;
28959 + * SRP Success flag, set by srp success interrupt in FS I2C mode
28961 + uint8_t srp_success;
28962 + uint8_t srp_timer_started;
28963 + /** Timer for SRP. If it expires before SRP is successful
28964 + * clear the SRP. */
28965 + dwc_timer_t *srp_timer;
28967 +#ifdef DWC_DEV_SRPCAP
28968 + /* This timer is needed to power on the hibernated host core if SRP is not
28969 + * initiated on connected SRP capable device for limited period of time
28971 + uint8_t pwron_timer_started;
28972 + dwc_timer_t *pwron_timer;
28974 + /* Common configuration information */
28975 + /** Power and Clock Gating Control Register */
28976 + volatile uint32_t *pcgcctl;
28977 +#define DWC_OTG_PCGCCTL_OFFSET 0xE00
28979 + /** Push/pop addresses for endpoints or host channels.*/
28980 + uint32_t *data_fifo[MAX_EPS_CHANNELS];
28981 +#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
28982 +#define DWC_OTG_DATA_FIFO_SIZE 0x1000
28984 + /** Total RAM for FIFOs (Bytes) */
28985 + uint16_t total_fifo_size;
28986 + /** Size of Rx FIFO (Bytes) */
28987 + uint16_t rx_fifo_size;
28988 + /** Size of Non-periodic Tx FIFO (Bytes) */
28989 + uint16_t nperio_tx_fifo_size;
28991 + /** 1 if DMA is enabled, 0 otherwise. */
28992 + uint8_t dma_enable;
28994 + /** 1 if DMA descriptor is enabled, 0 otherwise. */
28995 + uint8_t dma_desc_enable;
28997 + /** 1 if PTI Enhancement mode is enabled, 0 otherwise. */
28998 + uint8_t pti_enh_enable;
29000 + /** 1 if MPI Enhancement mode is enabled, 0 otherwise. */
29001 + uint8_t multiproc_int_enable;
29003 + /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */
29004 + uint8_t en_multiple_tx_fifo;
29006 + /** Set to 1 if multiple packets of a high-bandwidth transfer is in
29007 + * process of being queued */
29008 + uint8_t queuing_high_bandwidth;
29010 + /** Hardware Configuration -- stored here for convenience.*/
29011 + hwcfg1_data_t hwcfg1;
29012 + hwcfg2_data_t hwcfg2;
29013 + hwcfg3_data_t hwcfg3;
29014 + hwcfg4_data_t hwcfg4;
29015 + fifosize_data_t hptxfsiz;
29017 + /** Host and Device Configuration -- stored here for convenience.*/
29018 + hcfg_data_t hcfg;
29019 + dcfg_data_t dcfg;
29021 + /** The operational State, during transations
29022 + * (a_host>>a_peripherial and b_device=>b_host) this may not
29023 + * match the core but allows the software to determine
29026 + uint8_t op_state;
29029 + * Set to 1 if the HCD needs to be restarted on a session request
29030 + * interrupt. This is required if no connector ID status change has
29031 + * occurred since the HCD was last disconnected.
29033 + uint8_t restart_hcd_on_session_req;
29035 + /** HCD callbacks */
29036 + /** A-Device is a_host */
29037 +#define A_HOST (1)
29038 + /** A-Device is a_suspend */
29039 +#define A_SUSPEND (2)
29040 + /** A-Device is a_peripherial */
29041 +#define A_PERIPHERAL (3)
29042 + /** B-Device is operating as a Peripheral. */
29043 +#define B_PERIPHERAL (4)
29044 + /** B-Device is operating as a Host. */
29045 +#define B_HOST (5)
29047 + /** HCD callbacks */
29048 + struct dwc_otg_cil_callbacks *hcd_cb;
29049 + /** PCD callbacks */
29050 + struct dwc_otg_cil_callbacks *pcd_cb;
29052 + /** Device mode Periodic Tx FIFO Mask */
29053 + uint32_t p_tx_msk;
29054 + /** Device mode Periodic Tx FIFO Mask */
29057 + /** Workqueue object used for handling several interrupts */
29058 + dwc_workq_t *wq_otg;
29060 + /** Timer object used for handling "Wakeup Detected" Interrupt */
29061 + dwc_timer_t *wkp_timer;
29062 + /** This arrays used for debug purposes for DEV OUT NAK enhancement */
29063 + uint32_t start_doeptsiz_val[MAX_EPS_CHANNELS];
29064 + ep_xfer_info_t ep_xfer_info[MAX_EPS_CHANNELS];
29065 + dwc_timer_t *ep_xfer_timer[MAX_EPS_CHANNELS];
29067 + uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
29069 + hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS];
29070 + dwc_timer_t *hc_xfer_timer[MAX_EPS_CHANNELS];
29072 + uint32_t hfnum_7_samples;
29073 + uint64_t hfnum_7_frrem_accum;
29074 + uint32_t hfnum_0_samples;
29075 + uint64_t hfnum_0_frrem_accum;
29076 + uint32_t hfnum_other_samples;
29077 + uint64_t hfnum_other_frrem_accum;
29080 +#ifdef DWC_UTE_CFI
29081 + uint16_t pwron_rxfsiz;
29082 + uint16_t pwron_gnptxfsiz;
29083 + uint16_t pwron_txfsiz[15];
29085 + uint16_t init_rxfsiz;
29086 + uint16_t init_gnptxfsiz;
29087 + uint16_t init_txfsiz[15];
29090 + /** Lx state of device */
29091 + dwc_otg_lx_state_e lx_state;
29093 + /** Saved Core Global registers */
29094 + struct dwc_otg_global_regs_backup *gr_backup;
29095 + /** Saved Host registers */
29096 + struct dwc_otg_host_regs_backup *hr_backup;
29097 + /** Saved Device registers */
29098 + struct dwc_otg_dev_regs_backup *dr_backup;
29100 + /** Power Down Enable */
29101 + uint32_t power_down;
29103 + /** ADP support Enable */
29104 + uint32_t adp_enable;
29106 + /** ADP structure object */
29107 + dwc_otg_adp_t adp;
29109 + /** hibernation/suspend flag */
29110 + int hibernation_suspend;
29112 + /** Device mode extended hibernation flag */
29115 + /** OTG revision supported */
29116 + uint32_t otg_ver;
29118 + /** OTG status flag used for HNP polling */
29121 + /** Pointer to either hcd->lock or pcd->lock */
29122 + dwc_spinlock_t *lock;
29124 + /** Start predict NextEP based on Learning Queue if equal 1,
29125 + * also used as counter of disabled NP IN EP's */
29126 + uint8_t start_predict;
29128 + /** NextEp sequence, including EP0: nextep_seq[] = EP if non-periodic and
29129 + * active, 0xff otherwise */
29130 + uint8_t nextep_seq[MAX_EPS_CHANNELS];
29132 + /** Index of fisrt EP in nextep_seq array which should be re-enabled **/
29133 + uint8_t first_in_nextep_seq;
29135 + /** Frame number while entering to ISR - needed for ISOCs **/
29136 + uint32_t frame_num;
29142 + * This function is called when transfer is timed out.
29144 +extern void hc_xfer_timeout(void *ptr);
29148 + * This function is called when transfer is timed out on endpoint.
29150 +extern void ep_xfer_timeout(void *ptr);
29153 + * The following functions are functions for works
29154 + * using during handling some interrupts
29156 +extern void w_conn_id_status_change(void *p);
29158 +extern void w_wakeup_detected(void *p);
29160 +/** Saves global register values into system memory. */
29161 +extern int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if);
29162 +/** Saves device register values into system memory. */
29163 +extern int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if);
29164 +/** Saves host register values into system memory. */
29165 +extern int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if);
29166 +/** Restore global register values. */
29167 +extern int dwc_otg_restore_global_regs(dwc_otg_core_if_t * core_if);
29168 +/** Restore host register values. */
29169 +extern int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset);
29170 +/** Restore device register values. */
29171 +extern int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if,
29173 +extern int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if);
29174 +extern int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode,
29177 +extern int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
29178 + int restore_mode, int reset);
29179 +extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
29180 + int rem_wakeup, int reset);
29183 + * The following functions support initialization of the CIL driver component
29184 + * and the DWC_otg controller.
29186 +extern void dwc_otg_core_host_init(dwc_otg_core_if_t * _core_if);
29187 +extern void dwc_otg_core_dev_init(dwc_otg_core_if_t * _core_if);
29189 +/** @name Device CIL Functions
29190 + * The following functions support managing the DWC_otg controller in device
29194 +extern void dwc_otg_wakeup(dwc_otg_core_if_t * _core_if);
29195 +extern void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if,
29196 + uint32_t * _dest);
29197 +extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if);
29198 +extern void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29199 +extern void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29200 +extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29201 +extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if,
29203 +extern void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * _core_if,
29205 +extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * _core_if,
29207 +extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * _core_if,
29209 +extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t * _core_if,
29210 + dwc_ep_t * _ep, int _dma);
29211 +extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29212 +extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * _core_if,
29214 +extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * _core_if);
29216 +#ifdef DWC_EN_ISOC
29217 +extern void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
29219 +extern void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
29221 +#endif /* DWC_EN_ISOC */
29224 +/** @name Host CIL Functions
29225 + * The following functions support managing the DWC_otg controller in host
29229 +extern void dwc_otg_hc_init(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29230 +extern void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if,
29231 + dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status);
29232 +extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29233 +extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if,
29235 +extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if,
29237 +extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29238 +extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if,
29240 +extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * _core_if);
29241 +extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * _core_if);
29243 +extern void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if,
29246 +extern uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if);
29248 +/* Macro used to clear one channel interrupt */
29249 +#define clear_hc_int(_hc_regs_, _intr_) \
29251 + hcint_data_t hcint_clear = {.d32 = 0}; \
29252 + hcint_clear.b._intr_ = 1; \
29253 + DWC_WRITE_REG32(&(_hc_regs_)->hcint, hcint_clear.d32); \
29257 + * Macro used to disable one channel interrupt. Channel interrupts are
29258 + * disabled when the channel is halted or released by the interrupt handler.
29259 + * There is no need to handle further interrupts of that type until the
29260 + * channel is re-assigned. In fact, subsequent handling may cause crashes
29261 + * because the channel structures are cleaned up when the channel is released.
29263 +#define disable_hc_int(_hc_regs_, _intr_) \
29265 + hcintmsk_data_t hcintmsk = {.d32 = 0}; \
29266 + hcintmsk.b._intr_ = 1; \
29267 + DWC_MODIFY_REG32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \
29271 + * This function Reads HPRT0 in preparation to modify. It keeps the
29272 + * WC bits 0 so that if they are read as 1, they won't clear when you
29275 +static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t * _core_if)
29277 + hprt0_data_t hprt0;
29278 + hprt0.d32 = DWC_READ_REG32(_core_if->host_if->hprt0);
29279 + hprt0.b.prtena = 0;
29280 + hprt0.b.prtconndet = 0;
29281 + hprt0.b.prtenchng = 0;
29282 + hprt0.b.prtovrcurrchng = 0;
29283 + return hprt0.d32;
29288 +/** @name Common CIL Functions
29289 + * The following functions support managing the DWC_otg controller in either
29290 + * device or host mode.
29294 +extern void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
29295 + uint8_t * dest, uint16_t bytes);
29297 +extern void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * _core_if, const int _num);
29298 +extern void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * _core_if);
29299 +extern void dwc_otg_core_reset(dwc_otg_core_if_t * _core_if);
29302 + * This function returns the Core Interrupt register.
29304 +static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t * core_if)
29306 + return (DWC_READ_REG32(&core_if->core_global_regs->gintsts) &
29307 + DWC_READ_REG32(&core_if->core_global_regs->gintmsk));
29311 + * This function returns the OTG Interrupt register.
29313 +static inline uint32_t dwc_otg_read_otg_intr(dwc_otg_core_if_t * core_if)
29315 + return (DWC_READ_REG32(&core_if->core_global_regs->gotgint));
29319 + * This function reads the Device All Endpoints Interrupt register and
29320 + * returns the IN endpoint interrupt bits.
29322 +static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *
29328 + if (core_if->multiproc_int_enable) {
29329 + v = DWC_READ_REG32(&core_if->dev_if->
29330 + dev_global_regs->deachint) &
29331 + DWC_READ_REG32(&core_if->
29332 + dev_if->dev_global_regs->deachintmsk);
29334 + v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
29335 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
29337 + return (v & 0xffff);
29341 + * This function reads the Device All Endpoints Interrupt register and
29342 + * returns the OUT endpoint interrupt bits.
29344 +static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *
29349 + if (core_if->multiproc_int_enable) {
29350 + v = DWC_READ_REG32(&core_if->dev_if->
29351 + dev_global_regs->deachint) &
29352 + DWC_READ_REG32(&core_if->
29353 + dev_if->dev_global_regs->deachintmsk);
29355 + v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
29356 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
29359 + return ((v & 0xffff0000) >> 16);
29363 + * This function returns the Device IN EP Interrupt register
29365 +static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t * core_if,
29368 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
29369 + uint32_t v, msk, emp;
29371 + if (core_if->multiproc_int_enable) {
29373 + DWC_READ_REG32(&dev_if->
29374 + dev_global_regs->diepeachintmsk[ep->num]);
29376 + DWC_READ_REG32(&dev_if->
29377 + dev_global_regs->dtknqr4_fifoemptymsk);
29378 + msk |= ((emp >> ep->num) & 0x1) << 7;
29379 + v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
29381 + msk = DWC_READ_REG32(&dev_if->dev_global_regs->diepmsk);
29383 + DWC_READ_REG32(&dev_if->
29384 + dev_global_regs->dtknqr4_fifoemptymsk);
29385 + msk |= ((emp >> ep->num) & 0x1) << 7;
29386 + v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
29393 + * This function returns the Device OUT EP Interrupt register
29395 +static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *
29396 + _core_if, dwc_ep_t * _ep)
29398 + dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
29400 + doepmsk_data_t msk = {.d32 = 0 };
29402 + if (_core_if->multiproc_int_enable) {
29404 + DWC_READ_REG32(&dev_if->
29405 + dev_global_regs->doepeachintmsk[_ep->num]);
29406 + if (_core_if->pti_enh_enable) {
29407 + msk.b.pktdrpsts = 1;
29409 + v = DWC_READ_REG32(&dev_if->
29410 + out_ep_regs[_ep->num]->doepint) & msk.d32;
29412 + msk.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->doepmsk);
29413 + if (_core_if->pti_enh_enable) {
29414 + msk.b.pktdrpsts = 1;
29416 + v = DWC_READ_REG32(&dev_if->
29417 + out_ep_regs[_ep->num]->doepint) & msk.d32;
29423 + * This function returns the Host All Channel Interrupt register
29425 +static inline uint32_t dwc_otg_read_host_all_channels_intr(dwc_otg_core_if_t *
29428 + return (DWC_READ_REG32(&_core_if->host_if->host_global_regs->haint));
29431 +static inline uint32_t dwc_otg_read_host_channel_intr(dwc_otg_core_if_t *
29432 + _core_if, dwc_hc_t * _hc)
29434 + return (DWC_READ_REG32
29435 + (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint));
29439 + * This function returns the mode of the operation, host or device.
29441 + * @return 0 - Device Mode, 1 - Host Mode
29443 +static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t * _core_if)
29445 + return (DWC_READ_REG32(&_core_if->core_global_regs->gintsts) & 0x1);
29451 + * DWC_otg CIL callback structure. This structure allows the HCD and
29452 + * PCD to register functions used for starting and stopping the PCD
29453 + * and HCD for role change on for a DRD.
29455 +typedef struct dwc_otg_cil_callbacks {
29456 + /** Start function for role change */
29457 + int (*start) (void *_p);
29458 + /** Stop Function for role change */
29459 + int (*stop) (void *_p);
29460 + /** Disconnect Function for role change */
29461 + int (*disconnect) (void *_p);
29462 + /** Resume/Remote wakeup Function */
29463 + int (*resume_wakeup) (void *_p);
29464 + /** Suspend function */
29465 + int (*suspend) (void *_p);
29466 + /** Session Start (SRP) */
29467 + int (*session_start) (void *_p);
29468 +#ifdef CONFIG_USB_DWC_OTG_LPM
29469 + /** Sleep (switch to L0 state) */
29470 + int (*sleep) (void *_p);
29472 + /** Pointer passed to start() and stop() */
29474 +} dwc_otg_cil_callbacks_t;
29476 +extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if,
29477 + dwc_otg_cil_callbacks_t * _cb,
29479 +extern void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * _core_if,
29480 + dwc_otg_cil_callbacks_t * _cb,
29483 +void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if);
29485 +//////////////////////////////////////////////////////////////////////
29486 +/** Start the HCD. Helper function for using the HCD callbacks.
29488 + * @param core_if Programming view of DWC_otg controller.
29490 +static inline void cil_hcd_start(dwc_otg_core_if_t * core_if)
29492 + if (core_if->hcd_cb && core_if->hcd_cb->start) {
29493 + core_if->hcd_cb->start(core_if->hcd_cb->p);
29497 +/** Stop the HCD. Helper function for using the HCD callbacks.
29499 + * @param core_if Programming view of DWC_otg controller.
29501 +static inline void cil_hcd_stop(dwc_otg_core_if_t * core_if)
29503 + if (core_if->hcd_cb && core_if->hcd_cb->stop) {
29504 + core_if->hcd_cb->stop(core_if->hcd_cb->p);
29508 +/** Disconnect the HCD. Helper function for using the HCD callbacks.
29510 + * @param core_if Programming view of DWC_otg controller.
29512 +static inline void cil_hcd_disconnect(dwc_otg_core_if_t * core_if)
29514 + if (core_if->hcd_cb && core_if->hcd_cb->disconnect) {
29515 + core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
29519 +/** Inform the HCD the a New Session has begun. Helper function for
29520 + * using the HCD callbacks.
29522 + * @param core_if Programming view of DWC_otg controller.
29524 +static inline void cil_hcd_session_start(dwc_otg_core_if_t * core_if)
29526 + if (core_if->hcd_cb && core_if->hcd_cb->session_start) {
29527 + core_if->hcd_cb->session_start(core_if->hcd_cb->p);
29531 +#ifdef CONFIG_USB_DWC_OTG_LPM
29533 + * Inform the HCD about LPM sleep.
29534 + * Helper function for using the HCD callbacks.
29536 + * @param core_if Programming view of DWC_otg controller.
29538 +static inline void cil_hcd_sleep(dwc_otg_core_if_t * core_if)
29540 + if (core_if->hcd_cb && core_if->hcd_cb->sleep) {
29541 + core_if->hcd_cb->sleep(core_if->hcd_cb->p);
29546 +/** Resume the HCD. Helper function for using the HCD callbacks.
29548 + * @param core_if Programming view of DWC_otg controller.
29550 +static inline void cil_hcd_resume(dwc_otg_core_if_t * core_if)
29552 + if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) {
29553 + core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p);
29557 +/** Start the PCD. Helper function for using the PCD callbacks.
29559 + * @param core_if Programming view of DWC_otg controller.
29561 +static inline void cil_pcd_start(dwc_otg_core_if_t * core_if)
29563 + if (core_if->pcd_cb && core_if->pcd_cb->start) {
29564 + core_if->pcd_cb->start(core_if->pcd_cb->p);
29568 +/** Stop the PCD. Helper function for using the PCD callbacks.
29570 + * @param core_if Programming view of DWC_otg controller.
29572 +static inline void cil_pcd_stop(dwc_otg_core_if_t * core_if)
29574 + if (core_if->pcd_cb && core_if->pcd_cb->stop) {
29575 + core_if->pcd_cb->stop(core_if->pcd_cb->p);
29579 +/** Suspend the PCD. Helper function for using the PCD callbacks.
29581 + * @param core_if Programming view of DWC_otg controller.
29583 +static inline void cil_pcd_suspend(dwc_otg_core_if_t * core_if)
29585 + if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
29586 + core_if->pcd_cb->suspend(core_if->pcd_cb->p);
29590 +/** Resume the PCD. Helper function for using the PCD callbacks.
29592 + * @param core_if Programming view of DWC_otg controller.
29594 +static inline void cil_pcd_resume(dwc_otg_core_if_t * core_if)
29596 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
29597 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
29601 +//////////////////////////////////////////////////////////////////////
29605 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
29607 +/* ==========================================================================
29608 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
29609 + * $Revision: #32 $
29610 + * $Date: 2012/08/10 $
29611 + * $Change: 2047372 $
29613 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
29614 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
29615 + * otherwise expressly agreed to in writing between Synopsys and you.
29617 + * The Software IS NOT an item of Licensed Software or Licensed Product under
29618 + * any End User Software License Agreement or Agreement for Licensed Product
29619 + * with Synopsys or any supplement thereto. You are permitted to use and
29620 + * redistribute this Software in source and binary forms, with or without
29621 + * modification, provided that redistributions of source code must retain this
29622 + * notice. You may not view, use, disclose, copy or distribute this file or
29623 + * any information contained herein except pursuant to this license grant from
29624 + * Synopsys. If you do not agree with this notice, including the disclaimer
29625 + * below, then you are not authorized to use the Software.
29627 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
29628 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29629 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29630 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
29631 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29632 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29633 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29634 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29635 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29636 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29638 + * ========================================================================== */
29642 + * The Core Interface Layer provides basic services for accessing and
29643 + * managing the DWC_otg hardware. These services are used by both the
29644 + * Host Controller Driver and the Peripheral Controller Driver.
29646 + * This file contains the Common Interrupt handlers.
29648 +#include "dwc_os.h"
29649 +#include "dwc_otg_regs.h"
29650 +#include "dwc_otg_cil.h"
29651 +#include "dwc_otg_driver.h"
29652 +#include "dwc_otg_pcd.h"
29653 +#include "dwc_otg_hcd.h"
29656 +inline const char *op_state_str(dwc_otg_core_if_t * core_if)
29658 + return (core_if->op_state == A_HOST ? "a_host" :
29659 + (core_if->op_state == A_SUSPEND ? "a_suspend" :
29660 + (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
29661 + (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
29662 + (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
29666 +/** This function will log a debug message
29668 + * @param core_if Programming view of DWC_otg controller.
29670 +int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if)
29672 + gintsts_data_t gintsts;
29673 + DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
29674 + dwc_otg_mode(core_if) ? "Host" : "Device");
29676 + /* Clear interrupt */
29678 + gintsts.b.modemismatch = 1;
29679 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
29684 + * This function handles the OTG Interrupts. It reads the OTG
29685 + * Interrupt Register (GOTGINT) to determine what interrupt has
29688 + * @param core_if Programming view of DWC_otg controller.
29690 +int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if)
29692 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
29693 + gotgint_data_t gotgint;
29694 + gotgctl_data_t gotgctl;
29695 + gintmsk_data_t gintmsk;
29696 + gpwrdn_data_t gpwrdn;
29698 + gotgint.d32 = DWC_READ_REG32(&global_regs->gotgint);
29699 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29700 + DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
29701 + op_state_str(core_if));
29703 + if (gotgint.b.sesenddet) {
29704 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29705 + "Session End Detected++ (%s)\n",
29706 + op_state_str(core_if));
29707 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29709 + if (core_if->op_state == B_HOST) {
29710 + cil_pcd_start(core_if);
29711 + core_if->op_state = B_PERIPHERAL;
29713 + /* If not B_HOST and Device HNP still set. HNP
29714 + * Did not succeed!*/
29715 + if (gotgctl.b.devhnpen) {
29716 + DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
29717 + __DWC_ERROR("Device Not Connected/Responding!\n");
29720 + /* If Session End Detected the B-Cable has
29721 + * been disconnected. */
29722 + /* Reset PCD and Gadget driver to a
29723 + * clean state. */
29724 + core_if->lx_state = DWC_OTG_L0;
29725 + DWC_SPINUNLOCK(core_if->lock);
29726 + cil_pcd_stop(core_if);
29727 + DWC_SPINLOCK(core_if->lock);
29729 + if (core_if->adp_enable) {
29730 + if (core_if->power_down == 2) {
29732 + gpwrdn.b.pwrdnswtch = 1;
29733 + DWC_MODIFY_REG32(&core_if->
29734 + core_global_regs->
29735 + gpwrdn, gpwrdn.d32, 0);
29739 + gpwrdn.b.pmuintsel = 1;
29740 + gpwrdn.b.pmuactv = 1;
29741 + DWC_MODIFY_REG32(&core_if->core_global_regs->
29742 + gpwrdn, 0, gpwrdn.d32);
29744 + dwc_otg_adp_sense_start(core_if);
29749 + gotgctl.b.devhnpen = 1;
29750 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
29752 + if (gotgint.b.sesreqsucstschng) {
29753 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29754 + "Session Reqeust Success Status Change++\n");
29755 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29756 + if (gotgctl.b.sesreqscs) {
29758 + if ((core_if->core_params->phy_type ==
29759 + DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) {
29760 + core_if->srp_success = 1;
29762 + DWC_SPINUNLOCK(core_if->lock);
29763 + cil_pcd_resume(core_if);
29764 + DWC_SPINLOCK(core_if->lock);
29765 + /* Clear Session Request */
29767 + gotgctl.b.sesreq = 1;
29768 + DWC_MODIFY_REG32(&global_regs->gotgctl,
29773 + if (gotgint.b.hstnegsucstschng) {
29774 + /* Print statements during the HNP interrupt handling
29775 + * can cause it to fail.*/
29776 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29777 + /* WA for 3.00a- HW is not setting cur_mode, even sometimes
29778 + * this does not help*/
29779 + if (core_if->snpsid >= OTG_CORE_REV_3_00a)
29781 + if (gotgctl.b.hstnegscs) {
29782 + if (dwc_otg_is_host_mode(core_if)) {
29783 + core_if->op_state = B_HOST;
29785 + * Need to disable SOF interrupt immediately.
29786 + * When switching from device to host, the PCD
29787 + * interrupt handler won't handle the
29788 + * interrupt if host mode is already set. The
29789 + * HCD interrupt handler won't get called if
29790 + * the HCD state is HALT. This means that the
29791 + * interrupt does not get handled and Linux
29792 + * complains loudly.
29795 + gintmsk.b.sofintr = 1;
29796 + DWC_MODIFY_REG32(&global_regs->gintmsk,
29798 + /* Call callback function with spin lock released */
29799 + DWC_SPINUNLOCK(core_if->lock);
29800 + cil_pcd_stop(core_if);
29802 + * Initialize the Core for Host mode.
29804 + cil_hcd_start(core_if);
29805 + DWC_SPINLOCK(core_if->lock);
29806 + core_if->op_state = B_HOST;
29810 + gotgctl.b.hnpreq = 1;
29811 + gotgctl.b.devhnpen = 1;
29812 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
29813 + DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
29814 + __DWC_ERROR("Device Not Connected/Responding\n");
29817 + if (gotgint.b.hstnegdet) {
29818 + /* The disconnect interrupt is set at the same time as
29819 + * Host Negotiation Detected. During the mode
29820 + * switch all interrupts are cleared so the disconnect
29821 + * interrupt handler will not get executed.
29823 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29824 + "Host Negotiation Detected++ (%s)\n",
29825 + (dwc_otg_is_host_mode(core_if) ? "Host" :
29827 + if (dwc_otg_is_device_mode(core_if)) {
29828 + DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
29829 + core_if->op_state);
29830 + DWC_SPINUNLOCK(core_if->lock);
29831 + cil_hcd_disconnect(core_if);
29832 + cil_pcd_start(core_if);
29833 + DWC_SPINLOCK(core_if->lock);
29834 + core_if->op_state = A_PERIPHERAL;
29837 + * Need to disable SOF interrupt immediately. When
29838 + * switching from device to host, the PCD interrupt
29839 + * handler won't handle the interrupt if host mode is
29840 + * already set. The HCD interrupt handler won't get
29841 + * called if the HCD state is HALT. This means that
29842 + * the interrupt does not get handled and Linux
29843 + * complains loudly.
29846 + gintmsk.b.sofintr = 1;
29847 + DWC_MODIFY_REG32(&global_regs->gintmsk, gintmsk.d32, 0);
29848 + DWC_SPINUNLOCK(core_if->lock);
29849 + cil_pcd_stop(core_if);
29850 + cil_hcd_start(core_if);
29851 + DWC_SPINLOCK(core_if->lock);
29852 + core_if->op_state = A_HOST;
29855 + if (gotgint.b.adevtoutchng) {
29856 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29857 + "A-Device Timeout Change++\n");
29859 + if (gotgint.b.debdone) {
29860 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
29863 + /* Clear GOTGINT */
29864 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, gotgint.d32);
29869 +void w_conn_id_status_change(void *p)
29871 + dwc_otg_core_if_t *core_if = p;
29872 + uint32_t count = 0;
29873 + gotgctl_data_t gotgctl = {.d32 = 0 };
29875 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
29876 + DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
29877 + DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
29879 + /* B-Device connector (Device Mode) */
29880 + if (gotgctl.b.conidsts) {
29881 + /* Wait for switch to device mode. */
29882 + while (!dwc_otg_is_device_mode(core_if)) {
29883 + DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
29884 + (dwc_otg_is_host_mode(core_if) ? "Host" :
29887 + if (++count > 10000)
29890 + DWC_ASSERT(++count < 10000,
29891 + "Connection id status change timed out");
29892 + core_if->op_state = B_PERIPHERAL;
29893 + dwc_otg_core_init(core_if);
29894 + dwc_otg_enable_global_interrupts(core_if);
29895 + cil_pcd_start(core_if);
29897 + /* A-Device connector (Host Mode) */
29898 + while (!dwc_otg_is_host_mode(core_if)) {
29899 + DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
29900 + (dwc_otg_is_host_mode(core_if) ? "Host" :
29903 + if (++count > 10000)
29906 + DWC_ASSERT(++count < 10000,
29907 + "Connection id status change timed out");
29908 + core_if->op_state = A_HOST;
29910 + * Initialize the Core for Host mode.
29912 + dwc_otg_core_init(core_if);
29913 + dwc_otg_enable_global_interrupts(core_if);
29914 + cil_hcd_start(core_if);
29919 + * This function handles the Connector ID Status Change Interrupt. It
29920 + * reads the OTG Interrupt Register (GOTCTL) to determine whether this
29921 + * is a Device to Host Mode transition or a Host Mode to Device
29924 + * This only occurs when the cable is connected/removed from the PHY
29927 + * @param core_if Programming view of DWC_otg controller.
29929 +int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
29933 + * Need to disable SOF interrupt immediately. If switching from device
29934 + * to host, the PCD interrupt handler won't handle the interrupt if
29935 + * host mode is already set. The HCD interrupt handler won't get
29936 + * called if the HCD state is HALT. This means that the interrupt does
29937 + * not get handled and Linux complains loudly.
29939 + gintmsk_data_t gintmsk = {.d32 = 0 };
29940 + gintsts_data_t gintsts = {.d32 = 0 };
29942 + gintmsk.b.sofintr = 1;
29943 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
29945 + DWC_DEBUGPL(DBG_CIL,
29946 + " ++Connector ID Status Change Interrupt++ (%s)\n",
29947 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
29949 + DWC_SPINUNLOCK(core_if->lock);
29952 + * Need to schedule a work, as there are possible DELAY function calls
29953 + * Release lock before scheduling workq as it holds spinlock during scheduling
29956 + DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
29957 + core_if, "connection id status change");
29958 + DWC_SPINLOCK(core_if->lock);
29960 + /* Set flag and clear interrupt */
29961 + gintsts.b.conidstschng = 1;
29962 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
29968 + * This interrupt indicates that a device is initiating the Session
29969 + * Request Protocol to request the host to turn on bus power so a new
29970 + * session can begin. The handler responds by turning on bus power. If
29971 + * the DWC_otg controller is in low power mode, the handler brings the
29972 + * controller out of low power mode before turning on bus power.
29974 + * @param core_if Programming view of DWC_otg controller.
29976 +int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
29978 + gintsts_data_t gintsts;
29980 +#ifndef DWC_HOST_ONLY
29981 + DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
29983 + if (dwc_otg_is_device_mode(core_if)) {
29984 + DWC_PRINTF("SRP: Device mode\n");
29986 + hprt0_data_t hprt0;
29987 + DWC_PRINTF("SRP: Host mode\n");
29989 + /* Turn on the port power bit. */
29990 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
29991 + hprt0.b.prtpwr = 1;
29992 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
29994 + /* Start the Connection timer. So a message can be displayed
29995 + * if connect does not occur within 10 seconds. */
29996 + cil_hcd_session_start(core_if);
30000 + /* Clear interrupt */
30002 + gintsts.b.sessreqintr = 1;
30003 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30008 +void w_wakeup_detected(void *p)
30010 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
30012 + * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
30013 + * so that OPT tests pass with all PHYs).
30015 + hprt0_data_t hprt0 = {.d32 = 0 };
30017 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30018 + /* Restart the Phy Clock */
30019 + pcgcctl.b.stoppclk = 1;
30020 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
30023 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
30024 + DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
30025 +// dwc_mdelay(70);
30026 + hprt0.b.prtres = 0; /* Resume */
30027 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
30028 + DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
30029 + DWC_READ_REG32(core_if->host_if->hprt0));
30031 + cil_hcd_resume(core_if);
30033 + /** Change to L0 state*/
30034 + core_if->lx_state = DWC_OTG_L0;
30038 + * This interrupt indicates that the DWC_otg controller has detected a
30039 + * resume or remote wakeup sequence. If the DWC_otg controller is in
30040 + * low power mode, the handler must brings the controller out of low
30041 + * power mode. The controller automatically begins resume
30042 + * signaling. The handler schedules a time to stop resume signaling.
30044 +int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
30046 + gintsts_data_t gintsts;
30048 + DWC_DEBUGPL(DBG_ANY,
30049 + "++Resume and Remote Wakeup Detected Interrupt++\n");
30051 + DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
30053 + if (dwc_otg_is_device_mode(core_if)) {
30054 + dctl_data_t dctl = {.d32 = 0 };
30055 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
30056 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
30058 + if (core_if->lx_state == DWC_OTG_L2) {
30059 +#ifdef PARTIAL_POWER_DOWN
30060 + if (core_if->hwcfg4.b.power_optimiz) {
30061 + pcgcctl_data_t power = {.d32 = 0 };
30063 + power.d32 = DWC_READ_REG32(core_if->pcgcctl);
30064 + DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
30067 + power.b.stoppclk = 0;
30068 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30070 + power.b.pwrclmp = 0;
30071 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30073 + power.b.rstpdwnmodule = 0;
30074 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30077 + /* Clear the Remote Wakeup Signaling */
30078 + dctl.b.rmtwkupsig = 1;
30079 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
30080 + dctl, dctl.d32, 0);
30082 + DWC_SPINUNLOCK(core_if->lock);
30083 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
30084 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
30086 + DWC_SPINLOCK(core_if->lock);
30088 + glpmcfg_data_t lpmcfg;
30090 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
30091 + lpmcfg.b.hird_thres &= (~(1 << 4));
30092 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
30095 + /** Change to L0 state*/
30096 + core_if->lx_state = DWC_OTG_L0;
30098 + if (core_if->lx_state != DWC_OTG_L1) {
30099 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30101 + /* Restart the Phy Clock */
30102 + pcgcctl.b.stoppclk = 1;
30103 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
30104 + DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
30106 + /** Change to L0 state*/
30107 + core_if->lx_state = DWC_OTG_L0;
30111 + /* Clear interrupt */
30113 + gintsts.b.wkupintr = 1;
30114 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30120 + * This interrupt indicates that the Wakeup Logic has detected a
30121 + * Device disconnect.
30123 +static int32_t dwc_otg_handle_pwrdn_disconnect_intr(dwc_otg_core_if_t *core_if)
30125 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
30126 + gpwrdn_data_t gpwrdn_temp = { .d32 = 0 };
30127 + gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30129 + DWC_PRINTF("%s called\n", __FUNCTION__);
30131 + if (!core_if->hibernation_suspend) {
30132 + DWC_PRINTF("Already exited from Hibernation\n");
30136 + /* Switch on the voltage to the core */
30137 + gpwrdn.b.pwrdnswtch = 1;
30138 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30141 + /* Reset the core */
30143 + gpwrdn.b.pwrdnrstn = 1;
30144 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30147 + /* Disable power clamps*/
30149 + gpwrdn.b.pwrdnclmp = 1;
30150 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30152 + /* Remove reset the core signal */
30154 + gpwrdn.b.pwrdnrstn = 1;
30155 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30158 + /* Disable PMU interrupt */
30160 + gpwrdn.b.pmuintsel = 1;
30161 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30163 + core_if->hibernation_suspend = 0;
30165 + /* Disable PMU */
30167 + gpwrdn.b.pmuactv = 1;
30168 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30171 + if (gpwrdn_temp.b.idsts) {
30172 + core_if->op_state = B_PERIPHERAL;
30173 + dwc_otg_core_init(core_if);
30174 + dwc_otg_enable_global_interrupts(core_if);
30175 + cil_pcd_start(core_if);
30177 + core_if->op_state = A_HOST;
30178 + dwc_otg_core_init(core_if);
30179 + dwc_otg_enable_global_interrupts(core_if);
30180 + cil_hcd_start(core_if);
30187 + * This interrupt indicates that the Wakeup Logic has detected a
30188 + * remote wakeup sequence.
30190 +static int32_t dwc_otg_handle_pwrdn_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
30192 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30193 + DWC_DEBUGPL(DBG_ANY,
30194 + "++Powerdown Remote Wakeup Detected Interrupt++\n");
30196 + if (!core_if->hibernation_suspend) {
30197 + DWC_PRINTF("Already exited from Hibernation\n");
30201 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30202 + if (gpwrdn.b.idsts) { // Device Mode
30203 + if ((core_if->power_down == 2)
30204 + && (core_if->hibernation_suspend == 1)) {
30205 + dwc_otg_device_hibernation_restore(core_if, 0, 0);
30208 + if ((core_if->power_down == 2)
30209 + && (core_if->hibernation_suspend == 1)) {
30210 + dwc_otg_host_hibernation_restore(core_if, 1, 0);
30216 +static int32_t dwc_otg_handle_pwrdn_idsts_change(dwc_otg_device_t *otg_dev)
30218 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30219 + gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
30220 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30222 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30223 + gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30224 + if (core_if->power_down == 2) {
30225 + if (!core_if->hibernation_suspend) {
30226 + DWC_PRINTF("Already exited from Hibernation\n");
30229 + DWC_DEBUGPL(DBG_ANY, "Exit from hibernation on ID sts change\n");
30230 + /* Switch on the voltage to the core */
30231 + gpwrdn.b.pwrdnswtch = 1;
30232 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30235 + /* Reset the core */
30237 + gpwrdn.b.pwrdnrstn = 1;
30238 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30241 + /* Disable power clamps */
30243 + gpwrdn.b.pwrdnclmp = 1;
30244 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30246 + /* Remove reset the core signal */
30248 + gpwrdn.b.pwrdnrstn = 1;
30249 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30252 + /* Disable PMU interrupt */
30254 + gpwrdn.b.pmuintsel = 1;
30255 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30257 + /*Indicates that we are exiting from hibernation */
30258 + core_if->hibernation_suspend = 0;
30260 + /* Disable PMU */
30262 + gpwrdn.b.pmuactv = 1;
30263 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30266 + gpwrdn.d32 = core_if->gr_backup->gpwrdn_local;
30267 + if (gpwrdn.b.dis_vbus == 1) {
30269 + gpwrdn.b.dis_vbus = 1;
30270 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30273 + if (gpwrdn_temp.b.idsts) {
30274 + core_if->op_state = B_PERIPHERAL;
30275 + dwc_otg_core_init(core_if);
30276 + dwc_otg_enable_global_interrupts(core_if);
30277 + cil_pcd_start(core_if);
30279 + core_if->op_state = A_HOST;
30280 + dwc_otg_core_init(core_if);
30281 + dwc_otg_enable_global_interrupts(core_if);
30282 + cil_hcd_start(core_if);
30286 + if (core_if->adp_enable) {
30287 + uint8_t is_host = 0;
30288 + DWC_SPINUNLOCK(core_if->lock);
30289 + /* Change the core_if's lock to hcd/pcd lock depend on mode? */
30290 +#ifndef DWC_HOST_ONLY
30291 + if (gpwrdn_temp.b.idsts)
30292 + core_if->lock = otg_dev->pcd->lock;
30294 +#ifndef DWC_DEVICE_ONLY
30295 + if (!gpwrdn_temp.b.idsts) {
30296 + core_if->lock = otg_dev->hcd->lock;
30300 + DWC_PRINTF("RESTART ADP\n");
30301 + if (core_if->adp.probe_enabled)
30302 + dwc_otg_adp_probe_stop(core_if);
30303 + if (core_if->adp.sense_enabled)
30304 + dwc_otg_adp_sense_stop(core_if);
30305 + if (core_if->adp.sense_timer_started)
30306 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
30307 + if (core_if->adp.vbuson_timer_started)
30308 + DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
30309 + core_if->adp.probe_timer_values[0] = -1;
30310 + core_if->adp.probe_timer_values[1] = -1;
30311 + core_if->adp.sense_timer_started = 0;
30312 + core_if->adp.vbuson_timer_started = 0;
30313 + core_if->adp.probe_counter = 0;
30314 + core_if->adp.gpwrdn = 0;
30316 + /* Disable PMU and restart ADP */
30317 + gpwrdn_temp.d32 = 0;
30318 + gpwrdn_temp.b.pmuactv = 1;
30319 + gpwrdn_temp.b.pmuintsel = 1;
30320 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30321 + DWC_PRINTF("Check point 1\n");
30323 + dwc_otg_adp_start(core_if, is_host);
30324 + DWC_SPINLOCK(core_if->lock);
30331 +static int32_t dwc_otg_handle_pwrdn_session_change(dwc_otg_core_if_t * core_if)
30333 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30334 + int32_t otg_cap_param = core_if->core_params->otg_cap;
30335 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30337 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30338 + if (core_if->power_down == 2) {
30339 + if (!core_if->hibernation_suspend) {
30340 + DWC_PRINTF("Already exited from Hibernation\n");
30344 + if ((otg_cap_param != DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
30345 + otg_cap_param != DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) &&
30346 + gpwrdn.b.bsessvld == 0) {
30347 + /* Save gpwrdn register for further usage if stschng interrupt */
30348 + core_if->gr_backup->gpwrdn_local =
30349 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30350 + /*Exit from ISR and wait for stschng interrupt with bsessvld = 1 */
30354 + /* Switch on the voltage to the core */
30356 + gpwrdn.b.pwrdnswtch = 1;
30357 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30360 + /* Reset the core */
30362 + gpwrdn.b.pwrdnrstn = 1;
30363 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30366 + /* Disable power clamps */
30368 + gpwrdn.b.pwrdnclmp = 1;
30369 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30371 + /* Remove reset the core signal */
30373 + gpwrdn.b.pwrdnrstn = 1;
30374 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30377 + /* Disable PMU interrupt */
30379 + gpwrdn.b.pmuintsel = 1;
30380 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30383 + /*Indicates that we are exiting from hibernation */
30384 + core_if->hibernation_suspend = 0;
30386 + /* Disable PMU */
30388 + gpwrdn.b.pmuactv = 1;
30389 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30392 + core_if->op_state = B_PERIPHERAL;
30393 + dwc_otg_core_init(core_if);
30394 + dwc_otg_enable_global_interrupts(core_if);
30395 + cil_pcd_start(core_if);
30397 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
30398 + otg_cap_param == DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) {
30400 + * Initiate SRP after initial ADP probe.
30402 + dwc_otg_initiate_srp(core_if);
30409 + * This interrupt indicates that the Wakeup Logic has detected a
30410 + * status change either on IDDIG or BSessVld.
30412 +static uint32_t dwc_otg_handle_pwrdn_stschng_intr(dwc_otg_device_t *otg_dev)
30415 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30416 + gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
30417 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30419 + DWC_PRINTF("%s called\n", __FUNCTION__);
30421 + if (core_if->power_down == 2) {
30422 + if (core_if->hibernation_suspend <= 0) {
30423 + DWC_PRINTF("Already exited from Hibernation\n");
30426 + gpwrdn_temp.d32 = core_if->gr_backup->gpwrdn_local;
30429 + gpwrdn_temp.d32 = core_if->adp.gpwrdn;
30432 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30434 + if (gpwrdn.b.idsts ^ gpwrdn_temp.b.idsts) {
30435 + retval = dwc_otg_handle_pwrdn_idsts_change(otg_dev);
30436 + } else if (gpwrdn.b.bsessvld ^ gpwrdn_temp.b.bsessvld) {
30437 + retval = dwc_otg_handle_pwrdn_session_change(core_if);
30444 + * This interrupt indicates that the Wakeup Logic has detected a
30447 +static int32_t dwc_otg_handle_pwrdn_srp_intr(dwc_otg_core_if_t * core_if)
30449 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30451 + DWC_PRINTF("%s called\n", __FUNCTION__);
30453 + if (!core_if->hibernation_suspend) {
30454 + DWC_PRINTF("Already exited from Hibernation\n");
30457 +#ifdef DWC_DEV_SRPCAP
30458 + if (core_if->pwron_timer_started) {
30459 + core_if->pwron_timer_started = 0;
30460 + DWC_TIMER_CANCEL(core_if->pwron_timer);
30464 + /* Switch on the voltage to the core */
30465 + gpwrdn.b.pwrdnswtch = 1;
30466 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30469 + /* Reset the core */
30471 + gpwrdn.b.pwrdnrstn = 1;
30472 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30475 + /* Disable power clamps */
30477 + gpwrdn.b.pwrdnclmp = 1;
30478 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30480 + /* Remove reset the core signal */
30482 + gpwrdn.b.pwrdnrstn = 1;
30483 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30486 + /* Disable PMU interrupt */
30488 + gpwrdn.b.pmuintsel = 1;
30489 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30491 + /* Indicates that we are exiting from hibernation */
30492 + core_if->hibernation_suspend = 0;
30494 + /* Disable PMU */
30496 + gpwrdn.b.pmuactv = 1;
30497 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30500 + /* Programm Disable VBUS to 0 */
30502 + gpwrdn.b.dis_vbus = 1;
30503 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30505 + /*Initialize the core as Host */
30506 + core_if->op_state = A_HOST;
30507 + dwc_otg_core_init(core_if);
30508 + dwc_otg_enable_global_interrupts(core_if);
30509 + cil_hcd_start(core_if);
30514 +/** This interrupt indicates that restore command after Hibernation
30515 + * was completed by the core. */
30516 +int32_t dwc_otg_handle_restore_done_intr(dwc_otg_core_if_t * core_if)
30518 + pcgcctl_data_t pcgcctl;
30519 + DWC_DEBUGPL(DBG_ANY, "++Restore Done Interrupt++\n");
30521 + //TODO De-assert restore signal. 8.a
30522 + pcgcctl.d32 = DWC_READ_REG32(core_if->pcgcctl);
30523 + if (pcgcctl.b.restoremode == 1) {
30524 + gintmsk_data_t gintmsk = {.d32 = 0 };
30526 + * If restore mode is Remote Wakeup,
30527 + * unmask Remote Wakeup interrupt.
30529 + gintmsk.b.wkupintr = 1;
30530 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
30538 + * This interrupt indicates that a device has been disconnected from
30541 +int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if)
30543 + gintsts_data_t gintsts;
30545 + DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
30546 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
30547 + op_state_str(core_if));
30549 +/** @todo Consolidate this if statement. */
30550 +#ifndef DWC_HOST_ONLY
30551 + if (core_if->op_state == B_HOST) {
30552 + /* If in device mode Disconnect and stop the HCD, then
30553 + * start the PCD. */
30554 + DWC_SPINUNLOCK(core_if->lock);
30555 + cil_hcd_disconnect(core_if);
30556 + cil_pcd_start(core_if);
30557 + DWC_SPINLOCK(core_if->lock);
30558 + core_if->op_state = B_PERIPHERAL;
30559 + } else if (dwc_otg_is_device_mode(core_if)) {
30560 + gotgctl_data_t gotgctl = {.d32 = 0 };
30562 + DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
30563 + if (gotgctl.b.hstsethnpen == 1) {
30564 + /* Do nothing, if HNP in process the OTG
30565 + * interrupt "Host Negotiation Detected"
30566 + * interrupt will do the mode switch.
30568 + } else if (gotgctl.b.devhnpen == 0) {
30569 + /* If in device mode Disconnect and stop the HCD, then
30570 + * start the PCD. */
30571 + DWC_SPINUNLOCK(core_if->lock);
30572 + cil_hcd_disconnect(core_if);
30573 + cil_pcd_start(core_if);
30574 + DWC_SPINLOCK(core_if->lock);
30575 + core_if->op_state = B_PERIPHERAL;
30577 + DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
30580 + if (core_if->op_state == A_HOST) {
30581 + /* A-Cable still connected but device disconnected. */
30582 + cil_hcd_disconnect(core_if);
30583 + if (core_if->adp_enable) {
30584 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
30585 + cil_hcd_stop(core_if);
30586 + /* Enable Power Down Logic */
30587 + gpwrdn.b.pmuintsel = 1;
30588 + gpwrdn.b.pmuactv = 1;
30589 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30590 + gpwrdn, 0, gpwrdn.d32);
30591 + dwc_otg_adp_probe_start(core_if);
30593 + /* Power off the core */
30594 + if (core_if->power_down == 2) {
30596 + gpwrdn.b.pwrdnswtch = 1;
30598 + (&core_if->core_global_regs->gpwrdn,
30605 + /* Change to L3(OFF) state */
30606 + core_if->lx_state = DWC_OTG_L3;
30609 + gintsts.b.disconnect = 1;
30610 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30615 + * This interrupt indicates that SUSPEND state has been detected on
30618 + * For HNP the USB Suspend interrupt signals the change from
30619 + * "a_peripheral" to "a_host".
30621 + * When power management is enabled the core will be put in low power
30624 +int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if)
30626 + dsts_data_t dsts;
30627 + gintsts_data_t gintsts;
30628 + dcfg_data_t dcfg;
30630 + DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
30632 + if (dwc_otg_is_device_mode(core_if)) {
30633 + /* Check the Device status register to determine if the Suspend
30634 + * state is active. */
30636 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
30637 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
30638 + DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
30639 + "HWCFG4.power Optimize=%d\n",
30640 + dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
30642 +#ifdef PARTIAL_POWER_DOWN
30643 +/** @todo Add a module parameter for power management. */
30645 + if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
30646 + pcgcctl_data_t power = {.d32 = 0 };
30647 + DWC_DEBUGPL(DBG_CIL, "suspend\n");
30649 + power.b.pwrclmp = 1;
30650 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30652 + power.b.rstpdwnmodule = 1;
30653 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
30655 + power.b.stoppclk = 1;
30656 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
30659 + DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
30662 + /* PCD callback for suspend. Release the lock inside of callback function */
30663 + cil_pcd_suspend(core_if);
30664 + if (core_if->power_down == 2)
30666 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
30667 + DWC_DEBUGPL(DBG_ANY,"lx_state = %08x\n",core_if->lx_state);
30668 + DWC_DEBUGPL(DBG_ANY," device address = %08d\n",dcfg.b.devaddr);
30670 + if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
30671 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30672 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30673 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
30675 + /* Change to L2(suspend) state */
30676 + core_if->lx_state = DWC_OTG_L2;
30678 + /* Clear interrupt in gintsts */
30680 + gintsts.b.usbsuspend = 1;
30681 + DWC_WRITE_REG32(&core_if->core_global_regs->
30682 + gintsts, gintsts.d32);
30683 + DWC_PRINTF("Start of hibernation completed\n");
30684 + dwc_otg_save_global_regs(core_if);
30685 + dwc_otg_save_dev_regs(core_if);
30688 + DWC_READ_REG32(&core_if->core_global_regs->
30690 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
30691 + /* ULPI interface */
30692 + /* Suspend the Phy Clock */
30694 + pcgcctl.b.stoppclk = 1;
30695 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
30698 + gpwrdn.b.pmuactv = 1;
30699 + DWC_MODIFY_REG32(&core_if->
30700 + core_global_regs->
30701 + gpwrdn, 0, gpwrdn.d32);
30703 + /* UTMI+ Interface */
30704 + gpwrdn.b.pmuactv = 1;
30705 + DWC_MODIFY_REG32(&core_if->
30706 + core_global_regs->
30707 + gpwrdn, 0, gpwrdn.d32);
30709 + pcgcctl.b.stoppclk = 1;
30710 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
30715 + /* Set flag to indicate that we are in hibernation */
30716 + core_if->hibernation_suspend = 1;
30717 + /* Enable interrupts from wake up logic */
30719 + gpwrdn.b.pmuintsel = 1;
30720 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30721 + gpwrdn, 0, gpwrdn.d32);
30724 + /* Unmask device mode interrupts in GPWRDN */
30726 + gpwrdn.b.rst_det_msk = 1;
30727 + gpwrdn.b.lnstchng_msk = 1;
30728 + gpwrdn.b.sts_chngint_msk = 1;
30729 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30730 + gpwrdn, 0, gpwrdn.d32);
30733 + /* Enable Power Down Clamp */
30735 + gpwrdn.b.pwrdnclmp = 1;
30736 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30737 + gpwrdn, 0, gpwrdn.d32);
30740 + /* Switch off VDD */
30742 + gpwrdn.b.pwrdnswtch = 1;
30743 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30744 + gpwrdn, 0, gpwrdn.d32);
30746 + /* Save gpwrdn register for further usage if stschng interrupt */
30747 + core_if->gr_backup->gpwrdn_local =
30748 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30749 + DWC_PRINTF("Hibernation completed\n");
30753 + } else if (core_if->power_down == 3) {
30754 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30755 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
30756 + DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",core_if->lx_state);
30757 + DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",dcfg.b.devaddr);
30759 + if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
30760 + DWC_DEBUGPL(DBG_ANY, "Start entering to extended hibernation\n");
30761 + core_if->xhib = 1;
30763 + /* Clear interrupt in gintsts */
30765 + gintsts.b.usbsuspend = 1;
30766 + DWC_WRITE_REG32(&core_if->core_global_regs->
30767 + gintsts, gintsts.d32);
30769 + dwc_otg_save_global_regs(core_if);
30770 + dwc_otg_save_dev_regs(core_if);
30772 + /* Wait for 10 PHY clocks */
30775 + /* Program GPIO register while entering to xHib */
30776 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x1);
30778 + pcgcctl.b.enbl_extnd_hiber = 1;
30779 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30780 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30783 + pcgcctl.b.extnd_hiber_pwrclmp = 1;
30784 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30787 + pcgcctl.b.extnd_hiber_switch = 1;
30788 + core_if->gr_backup->xhib_gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30789 + core_if->gr_backup->xhib_pcgcctl = DWC_READ_REG32(core_if->pcgcctl) | pcgcctl.d32;
30790 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30792 + DWC_DEBUGPL(DBG_ANY, "Finished entering to extended hibernation\n");
30798 + if (core_if->op_state == A_PERIPHERAL) {
30799 + DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
30800 + /* Clear the a_peripheral flag, back to a_host. */
30801 + DWC_SPINUNLOCK(core_if->lock);
30802 + cil_pcd_stop(core_if);
30803 + cil_hcd_start(core_if);
30804 + DWC_SPINLOCK(core_if->lock);
30805 + core_if->op_state = A_HOST;
30809 + /* Change to L2(suspend) state */
30810 + core_if->lx_state = DWC_OTG_L2;
30812 + /* Clear interrupt */
30814 + gintsts.b.usbsuspend = 1;
30815 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30820 +static int32_t dwc_otg_handle_xhib_exit_intr(dwc_otg_core_if_t * core_if)
30822 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30823 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30824 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
30828 + /* Program GPIO register while entering to xHib */
30829 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x0);
30831 + pcgcctl.d32 = core_if->gr_backup->xhib_pcgcctl;
30832 + pcgcctl.b.extnd_hiber_pwrclmp = 0;
30833 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30836 + gpwrdn.d32 = core_if->gr_backup->xhib_gpwrdn;
30837 + gpwrdn.b.restore = 1;
30838 + DWC_WRITE_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32);
30841 + restore_lpm_i2c_regs(core_if);
30843 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
30844 + pcgcctl.b.max_xcvrselect = 1;
30845 + pcgcctl.b.ess_reg_restored = 0;
30846 + pcgcctl.b.extnd_hiber_switch = 0;
30847 + pcgcctl.b.extnd_hiber_pwrclmp = 0;
30848 + pcgcctl.b.enbl_extnd_hiber = 1;
30849 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30851 + gahbcfg.d32 = core_if->gr_backup->gahbcfg_local;
30852 + gahbcfg.b.glblintrmsk = 1;
30853 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
30855 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
30856 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0x1 << 16);
30858 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
30859 + core_if->gr_backup->gusbcfg_local);
30860 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
30861 + core_if->dr_backup->dcfg);
30864 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
30865 + pcgcctl.b.max_xcvrselect = 1;
30866 + pcgcctl.d32 |= 0x608;
30867 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30871 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
30872 + pcgcctl.b.max_xcvrselect = 1;
30873 + pcgcctl.b.ess_reg_restored = 1;
30874 + pcgcctl.b.enbl_extnd_hiber = 1;
30875 + pcgcctl.b.rstpdwnmodule = 1;
30876 + pcgcctl.b.restoremode = 1;
30877 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30879 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30884 +#ifdef CONFIG_USB_DWC_OTG_LPM
30886 + * This function hadles LPM transaction received interrupt.
30888 +static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
30890 + glpmcfg_data_t lpmcfg;
30891 + gintsts_data_t gintsts;
30893 + if (!core_if->core_params->lpm_enable) {
30894 + DWC_PRINTF("Unexpected LPM interrupt\n");
30897 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
30898 + DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
30900 + if (dwc_otg_is_host_mode(core_if)) {
30901 + cil_hcd_sleep(core_if);
30903 + lpmcfg.b.hird_thres |= (1 << 4);
30904 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
30908 + /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
30910 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
30911 + if (lpmcfg.b.prt_sleep_sts) {
30912 + /* Save the current state */
30913 + core_if->lx_state = DWC_OTG_L1;
30916 + /* Clear interrupt */
30918 + gintsts.b.lpmtranrcvd = 1;
30919 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30922 +#endif /* CONFIG_USB_DWC_OTG_LPM */
30925 + * This function returns the Core Interrupt register.
30927 +static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
30929 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
30930 + gintsts_data_t gintsts;
30931 + gintmsk_data_t gintmsk;
30932 + gintmsk_data_t gintmsk_common = {.d32 = 0 };
30933 + gintmsk_common.b.wkupintr = 1;
30934 + gintmsk_common.b.sessreqintr = 1;
30935 + gintmsk_common.b.conidstschng = 1;
30936 + gintmsk_common.b.otgintr = 1;
30937 + gintmsk_common.b.modemismatch = 1;
30938 + gintmsk_common.b.disconnect = 1;
30939 + gintmsk_common.b.usbsuspend = 1;
30940 +#ifdef CONFIG_USB_DWC_OTG_LPM
30941 + gintmsk_common.b.lpmtranrcvd = 1;
30943 + gintmsk_common.b.restoredone = 1;
30944 + /** @todo: The port interrupt occurs while in device
30945 + * mode. Added code to CIL to clear the interrupt for now!
30947 + gintmsk_common.b.portintr = 1;
30949 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
30950 + gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
30951 + gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
30954 + /* if any common interrupts set */
30955 + if (gintsts.d32 & gintmsk_common.d32) {
30956 + DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
30957 + gintsts.d32, gintmsk.d32);
30960 + if (gahbcfg.b.glblintrmsk)
30961 + return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
30967 +/* MACRO for clearing interupt bits in GPWRDN register */
30968 +#define CLEAR_GPWRDN_INTR(__core_if,__intr) \
30970 + gpwrdn_data_t gpwrdn = {.d32=0}; \
30971 + gpwrdn.b.__intr = 1; \
30972 + DWC_MODIFY_REG32(&__core_if->core_global_regs->gpwrdn, \
30973 + 0, gpwrdn.d32); \
30977 + * Common interrupt handler.
30979 + * The common interrupts are those that occur in both Host and Device mode.
30980 + * This handler handles the following interrupts:
30981 + * - Mode Mismatch Interrupt
30982 + * - Disconnect Interrupt
30983 + * - OTG Interrupt
30984 + * - Connector ID Status Change Interrupt
30985 + * - Session Request Interrupt.
30986 + * - Resume / Remote Wakeup Detected Interrupt.
30987 + * - LPM Transaction Received Interrupt
30988 + * - ADP Transaction Received Interrupt
30991 +int32_t dwc_otg_handle_common_intr(void *dev)
30994 + gintsts_data_t gintsts;
30995 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30996 + dwc_otg_device_t *otg_dev = dev;
30997 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30998 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30999 + if (dwc_otg_is_device_mode(core_if))
31000 + core_if->frame_num = dwc_otg_get_frame_number(core_if);
31002 + if (core_if->lock)
31003 + DWC_SPINLOCK(core_if->lock);
31005 + if (core_if->power_down == 3 && core_if->xhib == 1) {
31006 + DWC_DEBUGPL(DBG_ANY, "Exiting from xHIB state\n");
31007 + retval |= dwc_otg_handle_xhib_exit_intr(core_if);
31008 + core_if->xhib = 2;
31009 + if (core_if->lock)
31010 + DWC_SPINUNLOCK(core_if->lock);
31015 + if (core_if->hibernation_suspend <= 0) {
31016 + gintsts.d32 = dwc_otg_read_common_intr(core_if);
31018 + if (gintsts.b.modemismatch) {
31019 + retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
31021 + if (gintsts.b.otgintr) {
31022 + retval |= dwc_otg_handle_otg_intr(core_if);
31024 + if (gintsts.b.conidstschng) {
31026 + dwc_otg_handle_conn_id_status_change_intr(core_if);
31028 + if (gintsts.b.disconnect) {
31029 + retval |= dwc_otg_handle_disconnect_intr(core_if);
31031 + if (gintsts.b.sessreqintr) {
31032 + retval |= dwc_otg_handle_session_req_intr(core_if);
31034 + if (gintsts.b.wkupintr) {
31035 + retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
31037 + if (gintsts.b.usbsuspend) {
31038 + retval |= dwc_otg_handle_usb_suspend_intr(core_if);
31040 +#ifdef CONFIG_USB_DWC_OTG_LPM
31041 + if (gintsts.b.lpmtranrcvd) {
31042 + retval |= dwc_otg_handle_lpm_intr(core_if);
31045 + if (gintsts.b.restoredone) {
31047 + if (core_if->power_down == 2)
31048 + core_if->hibernation_suspend = -1;
31049 + else if (core_if->power_down == 3 && core_if->xhib == 2) {
31050 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
31051 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
31052 + dctl_data_t dctl = {.d32 = 0 };
31054 + DWC_WRITE_REG32(&core_if->core_global_regs->
31055 + gintsts, 0xFFFFFFFF);
31057 + DWC_DEBUGPL(DBG_ANY,
31058 + "RESTORE DONE generated\n");
31060 + gpwrdn.b.restore = 1;
31061 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
31064 + pcgcctl.b.rstpdwnmodule = 1;
31065 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
31067 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, core_if->gr_backup->gusbcfg_local);
31068 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, core_if->dr_backup->dcfg);
31069 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, core_if->dr_backup->dctl);
31072 + dctl.b.pwronprgdone = 1;
31073 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
31076 + dwc_otg_restore_global_regs(core_if);
31077 + dwc_otg_restore_dev_regs(core_if, 0);
31080 + dctl.b.pwronprgdone = 1;
31081 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
31085 + pcgcctl.b.enbl_extnd_hiber = 1;
31086 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
31088 + /* The core will be in ON STATE */
31089 + core_if->lx_state = DWC_OTG_L0;
31090 + core_if->xhib = 0;
31092 + DWC_SPINUNLOCK(core_if->lock);
31093 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
31094 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
31096 + DWC_SPINLOCK(core_if->lock);
31100 + gintsts.b.restoredone = 1;
31101 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
31102 + DWC_PRINTF(" --Restore done interrupt received-- \n");
31105 + if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
31106 + /* The port interrupt occurs while in device mode with HPRT0
31107 + * Port Enable/Disable.
31110 + gintsts.b.portintr = 1;
31111 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
31116 + DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
31118 + if (gpwrdn.b.disconn_det && gpwrdn.b.disconn_det_msk) {
31119 + CLEAR_GPWRDN_INTR(core_if, disconn_det);
31120 + if (gpwrdn.b.linestate == 0) {
31121 + dwc_otg_handle_pwrdn_disconnect_intr(core_if);
31123 + DWC_PRINTF("Disconnect detected while linestate is not 0\n");
31128 + if (gpwrdn.b.lnstschng && gpwrdn.b.lnstchng_msk) {
31129 + CLEAR_GPWRDN_INTR(core_if, lnstschng);
31130 + /* remote wakeup from hibernation */
31131 + if (gpwrdn.b.linestate == 2 || gpwrdn.b.linestate == 1) {
31132 + dwc_otg_handle_pwrdn_wakeup_detected_intr(core_if);
31134 + DWC_PRINTF("gpwrdn.linestate = %d\n", gpwrdn.b.linestate);
31138 + if (gpwrdn.b.rst_det && gpwrdn.b.rst_det_msk) {
31139 + CLEAR_GPWRDN_INTR(core_if, rst_det);
31140 + if (gpwrdn.b.linestate == 0) {
31141 + DWC_PRINTF("Reset detected\n");
31142 + retval |= dwc_otg_device_hibernation_restore(core_if, 0, 1);
31145 + if (gpwrdn.b.srp_det && gpwrdn.b.srp_det_msk) {
31146 + CLEAR_GPWRDN_INTR(core_if, srp_det);
31147 + dwc_otg_handle_pwrdn_srp_intr(core_if);
31151 + /* Handle ADP interrupt here */
31152 + if (gpwrdn.b.adp_int) {
31153 + DWC_PRINTF("ADP interrupt\n");
31154 + CLEAR_GPWRDN_INTR(core_if, adp_int);
31155 + dwc_otg_adp_handle_intr(core_if);
31158 + if (gpwrdn.b.sts_chngint && gpwrdn.b.sts_chngint_msk) {
31159 + DWC_PRINTF("STS CHNG interrupt asserted\n");
31160 + CLEAR_GPWRDN_INTR(core_if, sts_chngint);
31161 + dwc_otg_handle_pwrdn_stschng_intr(otg_dev);
31165 + if (core_if->lock)
31166 + DWC_SPINUNLOCK(core_if->lock);
31171 +++ b/drivers/usb/host/dwc_otg/dwc_otg_core_if.h
31173 +/* ==========================================================================
31174 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $
31175 + * $Revision: #13 $
31176 + * $Date: 2012/08/10 $
31177 + * $Change: 2047372 $
31179 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
31180 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
31181 + * otherwise expressly agreed to in writing between Synopsys and you.
31183 + * The Software IS NOT an item of Licensed Software or Licensed Product under
31184 + * any End User Software License Agreement or Agreement for Licensed Product
31185 + * with Synopsys or any supplement thereto. You are permitted to use and
31186 + * redistribute this Software in source and binary forms, with or without
31187 + * modification, provided that redistributions of source code must retain this
31188 + * notice. You may not view, use, disclose, copy or distribute this file or
31189 + * any information contained herein except pursuant to this license grant from
31190 + * Synopsys. If you do not agree with this notice, including the disclaimer
31191 + * below, then you are not authorized to use the Software.
31193 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
31194 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31195 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31196 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
31197 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31198 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31199 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31200 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31201 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31202 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31204 + * ========================================================================== */
31205 +#if !defined(__DWC_CORE_IF_H__)
31206 +#define __DWC_CORE_IF_H__
31208 +#include "dwc_os.h"
31211 + * This file defines DWC_OTG Core API
31214 +struct dwc_otg_core_if;
31215 +typedef struct dwc_otg_core_if dwc_otg_core_if_t;
31217 +/** Maximum number of Periodic FIFOs */
31218 +#define MAX_PERIO_FIFOS 15
31219 +/** Maximum number of Periodic FIFOs */
31220 +#define MAX_TX_FIFOS 15
31222 +/** Maximum number of Endpoints/HostChannels */
31223 +#define MAX_EPS_CHANNELS 16
31225 +extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr);
31226 +extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if);
31227 +extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if);
31229 +extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if);
31230 +extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if);
31232 +extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if);
31233 +extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if);
31235 +extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if);
31237 +/** This function should be called on every hardware interrupt. */
31238 +extern int32_t dwc_otg_handle_common_intr(void *otg_dev);
31240 +/** @name OTG Core Parameters */
31244 + * Specifies the OTG capabilities. The driver will automatically
31245 + * detect the value for this parameter if none is specified.
31246 + * 0 - HNP and SRP capable (default)
31247 + * 1 - SRP Only capable
31248 + * 2 - No HNP/SRP capable
31250 +extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val);
31251 +extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if);
31252 +#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
31253 +#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
31254 +#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
31255 +#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
31257 +extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val);
31258 +extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if);
31259 +#define dwc_param_opt_default 1
31262 + * Specifies whether to use slave or DMA mode for accessing the data
31263 + * FIFOs. The driver will automatically detect the value for this
31264 + * parameter if none is specified.
31266 + * 1 - DMA (default, if available)
31268 +extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if,
31270 +extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if);
31271 +#define dwc_param_dma_enable_default 1
31274 + * When DMA mode is enabled specifies whether to use
31275 + * address DMA or DMA Descritor mode for accessing the data
31276 + * FIFOs in device mode. The driver will automatically detect
31277 + * the value for this parameter if none is specified.
31278 + * 0 - address DMA
31279 + * 1 - DMA Descriptor(default, if available)
31281 +extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if,
31283 +extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if);
31284 +//#define dwc_param_dma_desc_enable_default 1
31285 +#define dwc_param_dma_desc_enable_default 0 // Broadcom BCM2708
31287 +/** The DMA Burst size (applicable only for External DMA
31288 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
31290 +extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if,
31292 +extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if);
31293 +#define dwc_param_dma_burst_size_default 32
31296 + * Specifies the maximum speed of operation in host and device mode.
31297 + * The actual speed depends on the speed of the attached device and
31298 + * the value of phy_type. The actual speed depends on the speed of the
31299 + * attached device.
31300 + * 0 - High Speed (default)
31303 +extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val);
31304 +extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if);
31305 +#define dwc_param_speed_default 0
31306 +#define DWC_SPEED_PARAM_HIGH 0
31307 +#define DWC_SPEED_PARAM_FULL 1
31309 +/** Specifies whether low power mode is supported when attached
31310 + * to a Full Speed or Low Speed device in host mode.
31311 + * 0 - Don't support low power mode (default)
31312 + * 1 - Support low power mode
31314 +extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
31315 + core_if, int32_t val);
31316 +extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t
31318 +#define dwc_param_host_support_fs_ls_low_power_default 0
31320 +/** Specifies the PHY clock rate in low power mode when connected to a
31321 + * Low Speed device in host mode. This parameter is applicable only if
31322 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
31323 + * then defaults to 6 MHZ otherwise 48 MHZ.
31328 +extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
31329 + core_if, int32_t val);
31330 +extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
31332 +#define dwc_param_host_ls_low_power_phy_clk_default 0
31333 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
31334 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
31337 + * 0 - Use cC FIFO size parameters
31338 + * 1 - Allow dynamic FIFO sizing (default)
31340 +extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
31342 +extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t *
31344 +#define dwc_param_enable_dynamic_fifo_default 1
31346 +/** Total number of 4-byte words in the data FIFO memory. This
31347 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
31349 + * 32 to 32768 (default 8192)
31350 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
31352 +extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if,
31354 +extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if);
31355 +//#define dwc_param_data_fifo_size_default 8192
31356 +#define dwc_param_data_fifo_size_default 0xFF0 // Broadcom BCM2708
31358 +/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
31359 + * FIFO sizing is enabled.
31360 + * 16 to 32768 (default 1064)
31362 +extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if,
31364 +extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if);
31365 +#define dwc_param_dev_rx_fifo_size_default 1064
31367 +/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
31368 + * when dynamic FIFO sizing is enabled.
31369 + * 16 to 32768 (default 1024)
31371 +extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
31372 + core_if, int32_t val);
31373 +extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
31375 +#define dwc_param_dev_nperio_tx_fifo_size_default 1024
31377 +/** Number of 4-byte words in each of the periodic Tx FIFOs in device
31378 + * mode when dynamic FIFO sizing is enabled.
31379 + * 4 to 768 (default 256)
31381 +extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
31382 + int32_t val, int fifo_num);
31383 +extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t *
31384 + core_if, int fifo_num);
31385 +#define dwc_param_dev_perio_tx_fifo_size_default 256
31387 +/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
31388 + * FIFO sizing is enabled.
31389 + * 16 to 32768 (default 1024)
31391 +extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
31393 +extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if);
31394 +//#define dwc_param_host_rx_fifo_size_default 1024
31395 +#define dwc_param_host_rx_fifo_size_default 774 // Broadcom BCM2708
31397 +/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
31398 + * when Dynamic FIFO sizing is enabled in the core.
31399 + * 16 to 32768 (default 1024)
31401 +extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
31402 + core_if, int32_t val);
31403 +extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
31405 +//#define dwc_param_host_nperio_tx_fifo_size_default 1024
31406 +#define dwc_param_host_nperio_tx_fifo_size_default 0x100 // Broadcom BCM2708
31408 +/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
31409 + * FIFO sizing is enabled.
31410 + * 16 to 32768 (default 1024)
31412 +extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
31413 + core_if, int32_t val);
31414 +extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
31416 +//#define dwc_param_host_perio_tx_fifo_size_default 1024
31417 +#define dwc_param_host_perio_tx_fifo_size_default 0x200 // Broadcom BCM2708
31419 +/** The maximum transfer size supported in bytes.
31420 + * 2047 to 65,535 (default 65,535)
31422 +extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
31424 +extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if);
31425 +#define dwc_param_max_transfer_size_default 65535
31427 +/** The maximum number of packets in a transfer.
31428 + * 15 to 511 (default 511)
31430 +extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if,
31432 +extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if);
31433 +#define dwc_param_max_packet_count_default 511
31435 +/** The number of host channel registers to use.
31436 + * 1 to 16 (default 12)
31437 + * Note: The FPGA configuration supports a maximum of 12 host channels.
31439 +extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if,
31441 +extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if);
31442 +//#define dwc_param_host_channels_default 12
31443 +#define dwc_param_host_channels_default 8 // Broadcom BCM2708
31445 +/** The number of endpoints in addition to EP0 available for device
31446 + * mode operations.
31447 + * 1 to 15 (default 6 IN and OUT)
31448 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
31449 + * endpoints in addition to EP0.
31451 +extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if,
31453 +extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if);
31454 +#define dwc_param_dev_endpoints_default 6
31457 + * Specifies the type of PHY interface to use. By default, the driver
31458 + * will automatically detect the phy_type.
31460 + * 0 - Full Speed PHY
31461 + * 1 - UTMI+ (default)
31464 +extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val);
31465 +extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if);
31466 +#define DWC_PHY_TYPE_PARAM_FS 0
31467 +#define DWC_PHY_TYPE_PARAM_UTMI 1
31468 +#define DWC_PHY_TYPE_PARAM_ULPI 2
31469 +#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
31472 + * Specifies the UTMI+ Data Width. This parameter is
31473 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
31474 + * PHY_TYPE, this parameter indicates the data width between
31475 + * the MAC and the ULPI Wrapper.) Also, this parameter is
31476 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
31477 + * to "8 and 16 bits", meaning that the core has been
31478 + * configured to work at either data path width.
31480 + * 8 or 16 bits (default 16)
31482 +extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if,
31484 +extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if);
31485 +//#define dwc_param_phy_utmi_width_default 16
31486 +#define dwc_param_phy_utmi_width_default 8 // Broadcom BCM2708
31489 + * Specifies whether the ULPI operates at double or single
31490 + * data rate. This parameter is only applicable if PHY_TYPE is
31493 + * 0 - single data rate ULPI interface with 8 bit wide data
31495 + * 1 - double data rate ULPI interface with 4 bit wide data
31498 +extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if,
31500 +extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if);
31501 +#define dwc_param_phy_ulpi_ddr_default 0
31504 + * Specifies whether to use the internal or external supply to
31505 + * drive the vbus with a ULPI phy.
31507 +extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
31509 +extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if);
31510 +#define DWC_PHY_ULPI_INTERNAL_VBUS 0
31511 +#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
31512 +#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
31515 + * Specifies whether to use the I2Cinterface for full speed PHY. This
31516 + * parameter is only applicable if PHY_TYPE is FS.
31517 + * 0 - No (default)
31520 +extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if,
31522 +extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if);
31523 +#define dwc_param_i2c_enable_default 0
31525 +extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if,
31527 +extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if);
31528 +#define dwc_param_ulpi_fs_ls_default 0
31530 +extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val);
31531 +extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if);
31532 +#define dwc_param_ts_dline_default 0
31535 + * Specifies whether dedicated transmit FIFOs are
31536 + * enabled for non periodic IN endpoints in device mode
31540 +extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
31542 +extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t *
31544 +#define dwc_param_en_multiple_tx_fifo_default 1
31546 +/** Number of 4-byte words in each of the Tx FIFOs in device
31547 + * mode when dynamic FIFO sizing is enabled.
31548 + * 4 to 768 (default 256)
31550 +extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
31551 + int fifo_num, int32_t val);
31552 +extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
31554 +#define dwc_param_dev_tx_fifo_size_default 768
31556 +/** Thresholding enable flag-
31557 + * bit 0 - enable non-ISO Tx thresholding
31558 + * bit 1 - enable ISO Tx thresholding
31559 + * bit 2 - enable Rx thresholding
31561 +extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val);
31562 +extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num);
31563 +#define dwc_param_thr_ctl_default 0
31565 +/** Thresholding length for Tx
31566 + * FIFOs in 32 bit DWORDs
31568 +extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if,
31570 +extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if);
31571 +#define dwc_param_tx_thr_length_default 64
31573 +/** Thresholding length for Rx
31574 + * FIFOs in 32 bit DWORDs
31576 +extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if,
31578 +extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if);
31579 +#define dwc_param_rx_thr_length_default 64
31582 + * Specifies whether LPM (Link Power Management) support is enabled
31584 +extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if,
31586 +extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if);
31587 +#define dwc_param_lpm_enable_default 1
31590 + * Specifies whether PTI enhancement is enabled
31592 +extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if,
31594 +extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if);
31595 +#define dwc_param_pti_enable_default 0
31598 + * Specifies whether MPI enhancement is enabled
31600 +extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if,
31602 +extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if);
31603 +#define dwc_param_mpi_enable_default 0
31606 + * Specifies whether ADP capability is enabled
31608 +extern int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if,
31610 +extern int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if);
31611 +#define dwc_param_adp_enable_default 0
31614 + * Specifies whether IC_USB capability is enabled
31617 +extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
31619 +extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if);
31620 +#define dwc_param_ic_usb_cap_default 0
31622 +extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if,
31624 +extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if);
31625 +#define dwc_param_ahb_thr_ratio_default 0
31627 +extern int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if,
31629 +extern int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if);
31630 +#define dwc_param_power_down_default 0
31632 +extern int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if,
31634 +extern int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if);
31635 +#define dwc_param_reload_ctl_default 0
31637 +extern int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if,
31639 +extern int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if);
31640 +#define dwc_param_dev_out_nak_default 0
31642 +extern int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if,
31644 +extern int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if);
31645 +#define dwc_param_cont_on_bna_default 0
31647 +extern int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if,
31649 +extern int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if);
31650 +#define dwc_param_ahb_single_default 0
31652 +extern int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val);
31653 +extern int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if);
31654 +#define dwc_param_otg_ver_default 0
31658 +/** @name Access to registers and bit-fields */
31661 + * Dump core registers and SPRAM
31663 +extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if);
31664 +extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if);
31665 +extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if);
31666 +extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if);
31669 + * Get host negotiation status.
31671 +extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if);
31676 +extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if);
31679 + * Set hnpreq bit in the GOTGCTL register.
31681 +extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val);
31684 + * Get Content of SNPSID register.
31686 +extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if);
31689 + * Get current mode.
31690 + * Returns 0 if in device mode, and 1 if in host mode.
31692 +extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if);
31695 + * Get value of hnpcapable field in the GUSBCFG register
31697 +extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if);
31699 + * Set value of hnpcapable field in the GUSBCFG register
31701 +extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
31704 + * Get value of srpcapable field in the GUSBCFG register
31706 +extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if);
31708 + * Set value of srpcapable field in the GUSBCFG register
31710 +extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
31713 + * Get value of devspeed field in the DCFG register
31715 +extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if);
31717 + * Set value of devspeed field in the DCFG register
31719 +extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val);
31722 + * Get the value of busconnected field from the HPRT0 register
31724 +extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if);
31727 + * Gets the device enumeration Speed.
31729 +extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if);
31732 + * Get value of prtpwr field from the HPRT0 register
31734 +extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if);
31737 + * Get value of flag indicating core state - hibernated or not
31739 +extern uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if);
31742 + * Set value of prtpwr field from the HPRT0 register
31744 +extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val);
31747 + * Get value of prtsusp field from the HPRT0 regsiter
31749 +extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if);
31751 + * Set value of prtpwr field from the HPRT0 register
31753 +extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val);
31756 + * Get value of ModeChTimEn field from the HCFG regsiter
31758 +extern uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if);
31760 + * Set value of ModeChTimEn field from the HCFG regsiter
31762 +extern void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val);
31765 + * Get value of Fram Interval field from the HFIR regsiter
31767 +extern uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if);
31769 + * Set value of Frame Interval field from the HFIR regsiter
31771 +extern void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val);
31774 + * Set value of prtres field from the HPRT0 register
31777 +extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val);
31780 + * Get value of rmtwkupsig bit in DCTL register
31782 +extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if);
31785 + * Get value of prt_sleep_sts field from the GLPMCFG register
31787 +extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if);
31790 + * Get value of rem_wkup_en field from the GLPMCFG register
31792 +extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if);
31795 + * Get value of appl_resp field from the GLPMCFG register
31797 +extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if);
31799 + * Set value of appl_resp field from the GLPMCFG register
31801 +extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val);
31804 + * Get value of hsic_connect field from the GLPMCFG register
31806 +extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if);
31808 + * Set value of hsic_connect field from the GLPMCFG register
31810 +extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val);
31813 + * Get value of inv_sel_hsic field from the GLPMCFG register.
31815 +extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if);
31817 + * Set value of inv_sel_hsic field from the GLPMFG register.
31819 +extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val);
31822 + * Some functions for accessing registers
31826 + * GOTGCTL register
31828 +extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if);
31829 +extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val);
31832 + * GUSBCFG register
31834 +extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if);
31835 +extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val);
31838 + * GRXFSIZ register
31840 +extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if);
31841 +extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
31844 + * GNPTXFSIZ register
31846 +extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if);
31847 +extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
31849 +extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if);
31850 +extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val);
31855 +extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if);
31856 +extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val);
31861 +extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if);
31862 +extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val);
31867 +extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if);
31868 +extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val);
31873 +extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if);
31877 +#endif /* __DWC_CORE_IF_H__ */
31879 +++ b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h
31881 +/* ==========================================================================
31883 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
31884 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
31885 + * otherwise expressly agreed to in writing between Synopsys and you.
31887 + * The Software IS NOT an item of Licensed Software or Licensed Product under
31888 + * any End User Software License Agreement or Agreement for Licensed Product
31889 + * with Synopsys or any supplement thereto. You are permitted to use and
31890 + * redistribute this Software in source and binary forms, with or without
31891 + * modification, provided that redistributions of source code must retain this
31892 + * notice. You may not view, use, disclose, copy or distribute this file or
31893 + * any information contained herein except pursuant to this license grant from
31894 + * Synopsys. If you do not agree with this notice, including the disclaimer
31895 + * below, then you are not authorized to use the Software.
31897 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
31898 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31899 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31900 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
31901 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31902 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31903 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31904 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31905 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31906 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31908 + * ========================================================================== */
31910 +#ifndef __DWC_OTG_DBG_H__
31911 +#define __DWC_OTG_DBG_H__
31914 + * This file defines debug levels.
31915 + * Debugging support vanishes in non-debug builds.
31919 + * The Debug Level bit-mask variable.
31921 +extern uint32_t g_dbg_lvl;
31923 + * Set the Debug Level variable.
31925 +static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new)
31927 + uint32_t old = g_dbg_lvl;
31932 +/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
31933 +#define DBG_CIL (0x2)
31934 +/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
31936 +#define DBG_CILV (0x20)
31937 +/** When debug level has the DBG_PCD bit set, display PCD (Device) debug
31939 +#define DBG_PCD (0x4)
31940 +/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
31942 +#define DBG_PCDV (0x40)
31943 +/** When debug level has the DBG_HCD bit set, display Host debug messages */
31944 +#define DBG_HCD (0x8)
31945 +/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
31947 +#define DBG_HCDV (0x80)
31948 +/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
31950 +#define DBG_HCD_URB (0x800)
31951 +/** When debug level has the DBG_HCDI bit set, display host interrupt
31953 +#define DBG_HCDI (0x1000)
31955 +/** When debug level has any bit set, display debug messages */
31956 +#define DBG_ANY (0xFF)
31958 +/** All debug messages off */
31961 +/** Prefix string for DWC_DEBUG print macros. */
31962 +#define USB_DWC "DWC_otg: "
31965 + * Print a debug message when the Global debug level variable contains
31966 + * the bit defined in <code>lvl</code>.
31968 + * @param[in] lvl - Debug level, use one of the DBG_ constants above.
31969 + * @param[in] x - like printf
31973 + * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
31976 + * results in:<br>
31978 + * usb-DWC_otg: dwc_otg_cil_init(ca867000)
31983 +# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0)
31984 +# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x )
31986 +# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
31990 +# define DWC_DEBUGPL(lvl, x...) do{}while(0)
31991 +# define DWC_DEBUGP(x...)
31993 +# define CHK_DEBUG_LEVEL(level) (0)
31998 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
32000 +/* ==========================================================================
32001 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $
32002 + * $Revision: #92 $
32003 + * $Date: 2012/08/10 $
32004 + * $Change: 2047372 $
32006 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
32007 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
32008 + * otherwise expressly agreed to in writing between Synopsys and you.
32010 + * The Software IS NOT an item of Licensed Software or Licensed Product under
32011 + * any End User Software License Agreement or Agreement for Licensed Product
32012 + * with Synopsys or any supplement thereto. You are permitted to use and
32013 + * redistribute this Software in source and binary forms, with or without
32014 + * modification, provided that redistributions of source code must retain this
32015 + * notice. You may not view, use, disclose, copy or distribute this file or
32016 + * any information contained herein except pursuant to this license grant from
32017 + * Synopsys. If you do not agree with this notice, including the disclaimer
32018 + * below, then you are not authorized to use the Software.
32020 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
32021 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32022 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32023 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
32024 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32025 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32026 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32027 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32028 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32029 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32031 + * ========================================================================== */
32034 + * The dwc_otg_driver module provides the initialization and cleanup entry
32035 + * points for the DWC_otg driver. This module will be dynamically installed
32036 + * after Linux is booted using the insmod command. When the module is
32037 + * installed, the dwc_otg_driver_init function is called. When the module is
32038 + * removed (using rmmod), the dwc_otg_driver_cleanup function is called.
32040 + * This module also defines a data structure for the dwc_otg_driver, which is
32041 + * used in conjunction with the standard ARM lm_device structure. These
32042 + * structures allow the OTG driver to comply with the standard Linux driver
32043 + * model in which devices and drivers are registered with a bus driver. This
32044 + * has the benefit that Linux can expose attributes of the driver and device
32045 + * in its special sysfs file system. Users can then read or write files in
32046 + * this file system to perform diagnostics on the driver components or the
32050 +#include "dwc_otg_os_dep.h"
32051 +#include "dwc_os.h"
32052 +#include "dwc_otg_dbg.h"
32053 +#include "dwc_otg_driver.h"
32054 +#include "dwc_otg_attr.h"
32055 +#include "dwc_otg_core_if.h"
32056 +#include "dwc_otg_pcd_if.h"
32057 +#include "dwc_otg_hcd_if.h"
32059 +#define DWC_DRIVER_VERSION "3.00a 10-AUG-2012"
32060 +#define DWC_DRIVER_DESC "HS OTG USB Controller driver"
32062 +bool microframe_schedule=true;
32064 +static const char dwc_driver_name[] = "dwc_otg";
32066 +extern int pcd_init(
32067 +#ifdef LM_INTERFACE
32068 + struct lm_device *_dev
32069 +#elif defined(PCI_INTERFACE)
32070 + struct pci_dev *_dev
32071 +#elif defined(PLATFORM_INTERFACE)
32072 + struct platform_device *dev
32075 +extern int hcd_init(
32076 +#ifdef LM_INTERFACE
32077 + struct lm_device *_dev
32078 +#elif defined(PCI_INTERFACE)
32079 + struct pci_dev *_dev
32080 +#elif defined(PLATFORM_INTERFACE)
32081 + struct platform_device *dev
32085 +extern int pcd_remove(
32086 +#ifdef LM_INTERFACE
32087 + struct lm_device *_dev
32088 +#elif defined(PCI_INTERFACE)
32089 + struct pci_dev *_dev
32090 +#elif defined(PLATFORM_INTERFACE)
32091 + struct platform_device *_dev
32095 +extern void hcd_remove(
32096 +#ifdef LM_INTERFACE
32097 + struct lm_device *_dev
32098 +#elif defined(PCI_INTERFACE)
32099 + struct pci_dev *_dev
32100 +#elif defined(PLATFORM_INTERFACE)
32101 + struct platform_device *_dev
32105 +extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
32107 +/*-------------------------------------------------------------------------*/
32108 +/* Encapsulate the module parameter settings */
32110 +struct dwc_otg_driver_module_params {
32113 + int32_t dma_enable;
32114 + int32_t dma_desc_enable;
32115 + int32_t dma_burst_size;
32117 + int32_t host_support_fs_ls_low_power;
32118 + int32_t host_ls_low_power_phy_clk;
32119 + int32_t enable_dynamic_fifo;
32120 + int32_t data_fifo_size;
32121 + int32_t dev_rx_fifo_size;
32122 + int32_t dev_nperio_tx_fifo_size;
32123 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
32124 + int32_t host_rx_fifo_size;
32125 + int32_t host_nperio_tx_fifo_size;
32126 + int32_t host_perio_tx_fifo_size;
32127 + int32_t max_transfer_size;
32128 + int32_t max_packet_count;
32129 + int32_t host_channels;
32130 + int32_t dev_endpoints;
32131 + int32_t phy_type;
32132 + int32_t phy_utmi_width;
32133 + int32_t phy_ulpi_ddr;
32134 + int32_t phy_ulpi_ext_vbus;
32135 + int32_t i2c_enable;
32136 + int32_t ulpi_fs_ls;
32137 + int32_t ts_dline;
32138 + int32_t en_multiple_tx_fifo;
32139 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
32140 + uint32_t thr_ctl;
32141 + uint32_t tx_thr_length;
32142 + uint32_t rx_thr_length;
32143 + int32_t pti_enable;
32144 + int32_t mpi_enable;
32145 + int32_t lpm_enable;
32146 + int32_t ic_usb_cap;
32147 + int32_t ahb_thr_ratio;
32148 + int32_t power_down;
32149 + int32_t reload_ctl;
32150 + int32_t dev_out_nak;
32151 + int32_t cont_on_bna;
32152 + int32_t ahb_single;
32154 + int32_t adp_enable;
32157 +static struct dwc_otg_driver_module_params dwc_otg_module_params = {
32160 + .dma_enable = -1,
32161 + .dma_desc_enable = -1,
32162 + .dma_burst_size = -1,
32164 + .host_support_fs_ls_low_power = -1,
32165 + .host_ls_low_power_phy_clk = -1,
32166 + .enable_dynamic_fifo = -1,
32167 + .data_fifo_size = -1,
32168 + .dev_rx_fifo_size = -1,
32169 + .dev_nperio_tx_fifo_size = -1,
32170 + .dev_perio_tx_fifo_size = {
32171 + /* dev_perio_tx_fifo_size_1 */
32189 + .host_rx_fifo_size = -1,
32190 + .host_nperio_tx_fifo_size = -1,
32191 + .host_perio_tx_fifo_size = -1,
32192 + .max_transfer_size = -1,
32193 + .max_packet_count = -1,
32194 + .host_channels = -1,
32195 + .dev_endpoints = -1,
32197 + .phy_utmi_width = -1,
32198 + .phy_ulpi_ddr = -1,
32199 + .phy_ulpi_ext_vbus = -1,
32200 + .i2c_enable = -1,
32201 + .ulpi_fs_ls = -1,
32203 + .en_multiple_tx_fifo = -1,
32204 + .dev_tx_fifo_size = {
32205 + /* dev_tx_fifo_size */
32224 + .tx_thr_length = -1,
32225 + .rx_thr_length = -1,
32226 + .pti_enable = -1,
32227 + .mpi_enable = -1,
32229 + .ic_usb_cap = -1,
32230 + .ahb_thr_ratio = -1,
32231 + .power_down = -1,
32232 + .reload_ctl = -1,
32233 + .dev_out_nak = -1,
32234 + .cont_on_bna = -1,
32235 + .ahb_single = -1,
32237 + .adp_enable = -1,
32241 + * This function shows the Driver Version.
32243 +static ssize_t version_show(struct device_driver *dev, char *buf)
32245 + return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n",
32246 + DWC_DRIVER_VERSION);
32249 +static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
32252 + * Global Debug Level Mask.
32254 +uint32_t g_dbg_lvl = 0; /* OFF */
32257 + * This function shows the driver Debug Level.
32259 +static ssize_t dbg_level_show(struct device_driver *drv, char *buf)
32261 + return sprintf(buf, "0x%0x\n", g_dbg_lvl);
32265 + * This function stores the driver Debug Level.
32267 +static ssize_t dbg_level_store(struct device_driver *drv, const char *buf,
32270 + g_dbg_lvl = simple_strtoul(buf, NULL, 16);
32274 +static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show,
32275 + dbg_level_store);
32278 + * This function is called during module intialization
32279 + * to pass module parameters to the DWC_OTG CORE.
32281 +static int set_parameters(dwc_otg_core_if_t * core_if)
32286 + if (dwc_otg_module_params.otg_cap != -1) {
32288 + dwc_otg_set_param_otg_cap(core_if,
32289 + dwc_otg_module_params.otg_cap);
32291 + if (dwc_otg_module_params.dma_enable != -1) {
32293 + dwc_otg_set_param_dma_enable(core_if,
32294 + dwc_otg_module_params.
32297 + if (dwc_otg_module_params.dma_desc_enable != -1) {
32299 + dwc_otg_set_param_dma_desc_enable(core_if,
32300 + dwc_otg_module_params.
32301 + dma_desc_enable);
32303 + if (dwc_otg_module_params.opt != -1) {
32305 + dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt);
32307 + if (dwc_otg_module_params.dma_burst_size != -1) {
32309 + dwc_otg_set_param_dma_burst_size(core_if,
32310 + dwc_otg_module_params.
32313 + if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) {
32315 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
32316 + dwc_otg_module_params.
32317 + host_support_fs_ls_low_power);
32319 + if (dwc_otg_module_params.enable_dynamic_fifo != -1) {
32321 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
32322 + dwc_otg_module_params.
32323 + enable_dynamic_fifo);
32325 + if (dwc_otg_module_params.data_fifo_size != -1) {
32327 + dwc_otg_set_param_data_fifo_size(core_if,
32328 + dwc_otg_module_params.
32331 + if (dwc_otg_module_params.dev_rx_fifo_size != -1) {
32333 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
32334 + dwc_otg_module_params.
32335 + dev_rx_fifo_size);
32337 + if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) {
32339 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
32340 + dwc_otg_module_params.
32341 + dev_nperio_tx_fifo_size);
32343 + if (dwc_otg_module_params.host_rx_fifo_size != -1) {
32345 + dwc_otg_set_param_host_rx_fifo_size(core_if,
32346 + dwc_otg_module_params.host_rx_fifo_size);
32348 + if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) {
32350 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
32351 + dwc_otg_module_params.
32352 + host_nperio_tx_fifo_size);
32354 + if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) {
32356 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
32357 + dwc_otg_module_params.
32358 + host_perio_tx_fifo_size);
32360 + if (dwc_otg_module_params.max_transfer_size != -1) {
32362 + dwc_otg_set_param_max_transfer_size(core_if,
32363 + dwc_otg_module_params.
32364 + max_transfer_size);
32366 + if (dwc_otg_module_params.max_packet_count != -1) {
32368 + dwc_otg_set_param_max_packet_count(core_if,
32369 + dwc_otg_module_params.
32370 + max_packet_count);
32372 + if (dwc_otg_module_params.host_channels != -1) {
32374 + dwc_otg_set_param_host_channels(core_if,
32375 + dwc_otg_module_params.
32378 + if (dwc_otg_module_params.dev_endpoints != -1) {
32380 + dwc_otg_set_param_dev_endpoints(core_if,
32381 + dwc_otg_module_params.
32384 + if (dwc_otg_module_params.phy_type != -1) {
32386 + dwc_otg_set_param_phy_type(core_if,
32387 + dwc_otg_module_params.phy_type);
32389 + if (dwc_otg_module_params.speed != -1) {
32391 + dwc_otg_set_param_speed(core_if,
32392 + dwc_otg_module_params.speed);
32394 + if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) {
32396 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
32397 + dwc_otg_module_params.
32398 + host_ls_low_power_phy_clk);
32400 + if (dwc_otg_module_params.phy_ulpi_ddr != -1) {
32402 + dwc_otg_set_param_phy_ulpi_ddr(core_if,
32403 + dwc_otg_module_params.
32406 + if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) {
32408 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
32409 + dwc_otg_module_params.
32410 + phy_ulpi_ext_vbus);
32412 + if (dwc_otg_module_params.phy_utmi_width != -1) {
32414 + dwc_otg_set_param_phy_utmi_width(core_if,
32415 + dwc_otg_module_params.
32418 + if (dwc_otg_module_params.ulpi_fs_ls != -1) {
32420 + dwc_otg_set_param_ulpi_fs_ls(core_if,
32421 + dwc_otg_module_params.ulpi_fs_ls);
32423 + if (dwc_otg_module_params.ts_dline != -1) {
32425 + dwc_otg_set_param_ts_dline(core_if,
32426 + dwc_otg_module_params.ts_dline);
32428 + if (dwc_otg_module_params.i2c_enable != -1) {
32430 + dwc_otg_set_param_i2c_enable(core_if,
32431 + dwc_otg_module_params.
32434 + if (dwc_otg_module_params.en_multiple_tx_fifo != -1) {
32436 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
32437 + dwc_otg_module_params.
32438 + en_multiple_tx_fifo);
32440 + for (i = 0; i < 15; i++) {
32441 + if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) {
32443 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
32444 + dwc_otg_module_params.
32445 + dev_perio_tx_fifo_size
32450 + for (i = 0; i < 15; i++) {
32451 + if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) {
32452 + retval += dwc_otg_set_param_dev_tx_fifo_size(core_if,
32453 + dwc_otg_module_params.
32458 + if (dwc_otg_module_params.thr_ctl != -1) {
32460 + dwc_otg_set_param_thr_ctl(core_if,
32461 + dwc_otg_module_params.thr_ctl);
32463 + if (dwc_otg_module_params.mpi_enable != -1) {
32465 + dwc_otg_set_param_mpi_enable(core_if,
32466 + dwc_otg_module_params.
32469 + if (dwc_otg_module_params.pti_enable != -1) {
32471 + dwc_otg_set_param_pti_enable(core_if,
32472 + dwc_otg_module_params.
32475 + if (dwc_otg_module_params.lpm_enable != -1) {
32477 + dwc_otg_set_param_lpm_enable(core_if,
32478 + dwc_otg_module_params.
32481 + if (dwc_otg_module_params.ic_usb_cap != -1) {
32483 + dwc_otg_set_param_ic_usb_cap(core_if,
32484 + dwc_otg_module_params.
32487 + if (dwc_otg_module_params.tx_thr_length != -1) {
32489 + dwc_otg_set_param_tx_thr_length(core_if,
32490 + dwc_otg_module_params.tx_thr_length);
32492 + if (dwc_otg_module_params.rx_thr_length != -1) {
32494 + dwc_otg_set_param_rx_thr_length(core_if,
32495 + dwc_otg_module_params.
32498 + if (dwc_otg_module_params.ahb_thr_ratio != -1) {
32500 + dwc_otg_set_param_ahb_thr_ratio(core_if,
32501 + dwc_otg_module_params.ahb_thr_ratio);
32503 + if (dwc_otg_module_params.power_down != -1) {
32505 + dwc_otg_set_param_power_down(core_if,
32506 + dwc_otg_module_params.power_down);
32508 + if (dwc_otg_module_params.reload_ctl != -1) {
32510 + dwc_otg_set_param_reload_ctl(core_if,
32511 + dwc_otg_module_params.reload_ctl);
32514 + if (dwc_otg_module_params.dev_out_nak != -1) {
32516 + dwc_otg_set_param_dev_out_nak(core_if,
32517 + dwc_otg_module_params.dev_out_nak);
32520 + if (dwc_otg_module_params.cont_on_bna != -1) {
32522 + dwc_otg_set_param_cont_on_bna(core_if,
32523 + dwc_otg_module_params.cont_on_bna);
32526 + if (dwc_otg_module_params.ahb_single != -1) {
32528 + dwc_otg_set_param_ahb_single(core_if,
32529 + dwc_otg_module_params.ahb_single);
32532 + if (dwc_otg_module_params.otg_ver != -1) {
32534 + dwc_otg_set_param_otg_ver(core_if,
32535 + dwc_otg_module_params.otg_ver);
32537 + if (dwc_otg_module_params.adp_enable != -1) {
32539 + dwc_otg_set_param_adp_enable(core_if,
32540 + dwc_otg_module_params.
32547 + * This function is the top level interrupt handler for the Common
32548 + * (Device and host modes) interrupts.
32550 +static irqreturn_t dwc_otg_common_irq(int irq, void *dev)
32552 + int32_t retval = IRQ_NONE;
32554 + retval = dwc_otg_handle_common_intr(dev);
32555 + if (retval != 0) {
32556 + S3C2410X_CLEAR_EINTPEND();
32558 + return IRQ_RETVAL(retval);
32562 + * This function is called when a lm_device is unregistered with the
32563 + * dwc_otg_driver. This happens, for example, when the rmmod command is
32564 + * executed. The device may or may not be electrically present. If it is
32565 + * present, the driver stops device processing. Any resources used on behalf
32566 + * of this device are freed.
32570 +#ifdef LM_INTERFACE
32571 +#define REM_RETVAL(n)
32572 +static void dwc_otg_driver_remove( struct lm_device *_dev )
32573 +{ dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
32574 +#elif defined(PCI_INTERFACE)
32575 +#define REM_RETVAL(n)
32576 +static void dwc_otg_driver_remove( struct pci_dev *_dev )
32577 +{ dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
32578 +#elif defined(PLATFORM_INTERFACE)
32579 +#define REM_RETVAL(n) n
32580 +static int dwc_otg_driver_remove( struct platform_device *_dev )
32581 +{ dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
32584 + DWC_DEBUGPL(DBG_ANY, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
32587 + /* Memory allocation for the dwc_otg_device failed. */
32588 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
32589 + return REM_RETVAL(-ENOMEM);
32591 +#ifndef DWC_DEVICE_ONLY
32592 + if (otg_dev->hcd) {
32593 + hcd_remove(_dev);
32595 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
32596 + return REM_RETVAL(-EINVAL);
32600 +#ifndef DWC_HOST_ONLY
32601 + if (otg_dev->pcd) {
32602 + pcd_remove(_dev);
32604 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->pcd NULL!\n", __func__);
32605 + return REM_RETVAL(-EINVAL);
32611 + if (otg_dev->common_irq_installed) {
32612 +#ifdef PLATFORM_INTERFACE
32613 + free_irq(platform_get_irq(_dev, 0), otg_dev);
32615 + free_irq(_dev->irq, otg_dev);
32618 + DWC_DEBUGPL(DBG_ANY, "%s: There is no installed irq!\n", __func__);
32619 + return REM_RETVAL(-ENXIO);
32622 + if (otg_dev->core_if) {
32623 + dwc_otg_cil_remove(otg_dev->core_if);
32625 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->core_if NULL!\n", __func__);
32626 + return REM_RETVAL(-ENXIO);
32630 + * Remove the device attributes
32632 + dwc_otg_attr_remove(_dev);
32635 + * Return the memory.
32637 + if (otg_dev->os_dep.base) {
32638 + iounmap(otg_dev->os_dep.base);
32640 + DWC_FREE(otg_dev);
32643 + * Clear the drvdata pointer.
32645 +#ifdef LM_INTERFACE
32646 + lm_set_drvdata(_dev, 0);
32647 +#elif defined(PCI_INTERFACE)
32648 + release_mem_region(otg_dev->os_dep.rsrc_start,
32649 + otg_dev->os_dep.rsrc_len);
32650 + pci_set_drvdata(_dev, 0);
32651 +#elif defined(PLATFORM_INTERFACE)
32652 + platform_set_drvdata(_dev, 0);
32654 + return REM_RETVAL(0);
32658 + * This function is called when an lm_device is bound to a
32659 + * dwc_otg_driver. It creates the driver components required to
32660 + * control the device (CIL, HCD, and PCD) and it initializes the
32661 + * device. The driver components are stored in a dwc_otg_device
32662 + * structure. A reference to the dwc_otg_device is saved in the
32663 + * lm_device. This allows the driver to access the dwc_otg_device
32664 + * structure on subsequent calls to driver methods for this device.
32666 + * @param _dev Bus device
32668 +static int dwc_otg_driver_probe(
32669 +#ifdef LM_INTERFACE
32670 + struct lm_device *_dev
32671 +#elif defined(PCI_INTERFACE)
32672 + struct pci_dev *_dev,
32673 + const struct pci_device_id *id
32674 +#elif defined(PLATFORM_INTERFACE)
32675 + struct platform_device *_dev
32680 + dwc_otg_device_t *dwc_otg_device;
32683 + dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev);
32684 +#ifdef LM_INTERFACE
32685 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource.start);
32686 +#elif defined(PCI_INTERFACE)
32688 + DWC_ERROR("Invalid pci_device_id %p", id);
32692 + if (!_dev || (pci_enable_device(_dev) < 0)) {
32693 + DWC_ERROR("Invalid pci_device %p", _dev);
32696 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(_dev,0));
32697 + /* other stuff needed as well? */
32699 +#elif defined(PLATFORM_INTERFACE)
32700 + dev_dbg(&_dev->dev, "start=0x%08x (len 0x%x)\n",
32701 + (unsigned)_dev->resource->start,
32702 + (unsigned)(_dev->resource->end - _dev->resource->start));
32705 + dwc_otg_device = DWC_ALLOC(sizeof(dwc_otg_device_t));
32707 + if (!dwc_otg_device) {
32708 + dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n");
32712 + memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
32713 + dwc_otg_device->os_dep.reg_offset = 0xFFFFFFFF;
32716 + * Map the DWC_otg Core memory into virtual address space.
32718 +#ifdef LM_INTERFACE
32719 + dwc_otg_device->os_dep.base = ioremap(_dev->resource.start, SZ_256K);
32721 + if (!dwc_otg_device->os_dep.base) {
32722 + dev_err(&_dev->dev, "ioremap() failed\n");
32723 + DWC_FREE(dwc_otg_device);
32726 + dev_dbg(&_dev->dev, "base=0x%08x\n",
32727 + (unsigned)dwc_otg_device->os_dep.base);
32728 +#elif defined(PCI_INTERFACE)
32729 + _dev->current_state = PCI_D0;
32730 + _dev->dev.power.power_state = PMSG_ON;
32732 + if (!_dev->irq) {
32733 + DWC_ERROR("Found HC with no IRQ. Check BIOS/PCI %s setup!",
32735 + iounmap(dwc_otg_device->os_dep.base);
32736 + DWC_FREE(dwc_otg_device);
32740 + dwc_otg_device->os_dep.rsrc_start = pci_resource_start(_dev, 0);
32741 + dwc_otg_device->os_dep.rsrc_len = pci_resource_len(_dev, 0);
32742 + DWC_DEBUGPL(DBG_ANY, "PCI resource: start=%08x, len=%08x\n",
32743 + (unsigned)dwc_otg_device->os_dep.rsrc_start,
32744 + (unsigned)dwc_otg_device->os_dep.rsrc_len);
32745 + if (!request_mem_region
32746 + (dwc_otg_device->os_dep.rsrc_start, dwc_otg_device->os_dep.rsrc_len,
32748 + dev_dbg(&_dev->dev, "error requesting memory\n");
32749 + iounmap(dwc_otg_device->os_dep.base);
32750 + DWC_FREE(dwc_otg_device);
32754 + dwc_otg_device->os_dep.base =
32755 + ioremap_nocache(dwc_otg_device->os_dep.rsrc_start,
32756 + dwc_otg_device->os_dep.rsrc_len);
32757 + if (dwc_otg_device->os_dep.base == NULL) {
32758 + dev_dbg(&_dev->dev, "error mapping memory\n");
32759 + release_mem_region(dwc_otg_device->os_dep.rsrc_start,
32760 + dwc_otg_device->os_dep.rsrc_len);
32761 + iounmap(dwc_otg_device->os_dep.base);
32762 + DWC_FREE(dwc_otg_device);
32765 + dev_dbg(&_dev->dev, "base=0x%p (before adjust) \n",
32766 + dwc_otg_device->os_dep.base);
32767 + dwc_otg_device->os_dep.base = (char *)dwc_otg_device->os_dep.base;
32768 + dev_dbg(&_dev->dev, "base=0x%p (after adjust) \n",
32769 + dwc_otg_device->os_dep.base);
32770 + dev_dbg(&_dev->dev, "%s: mapped PA 0x%x to VA 0x%p\n", __func__,
32771 + (unsigned)dwc_otg_device->os_dep.rsrc_start,
32772 + dwc_otg_device->os_dep.base);
32774 + pci_set_master(_dev);
32775 + pci_set_drvdata(_dev, dwc_otg_device);
32776 +#elif defined(PLATFORM_INTERFACE)
32777 + DWC_DEBUGPL(DBG_ANY,"Platform resource: start=%08x, len=%08x\n",
32778 + _dev->resource->start,
32779 + _dev->resource->end - _dev->resource->start + 1);
32781 + if (!request_mem_region(_dev->resource->start,
32782 + _dev->resource->end - _dev->resource->start + 1,
32784 + dev_dbg(&_dev->dev, "error reserving mapped memory\n");
32785 + retval = -EFAULT;
32789 + dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource->start,
32790 + _dev->resource->end -
32791 + _dev->resource->start+1);
32794 + struct map_desc desc = {
32795 + .virtual = IO_ADDRESS((unsigned)_dev->resource->start),
32796 + .pfn = __phys_to_pfn((unsigned)_dev->resource->start),
32797 + .length = SZ_128K,
32798 + .type = MT_DEVICE
32800 + iotable_init(&desc, 1);
32801 + dwc_otg_device->os_dep.base = (void *)desc.virtual;
32804 + if (!dwc_otg_device->os_dep.base) {
32805 + dev_err(&_dev->dev, "ioremap() failed\n");
32806 + retval = -ENOMEM;
32809 + dev_dbg(&_dev->dev, "base=0x%08x\n",
32810 + (unsigned)dwc_otg_device->os_dep.base);
32814 + * Initialize driver data to point to the global DWC_otg
32815 + * Device structure.
32817 +#ifdef LM_INTERFACE
32818 + lm_set_drvdata(_dev, dwc_otg_device);
32819 +#elif defined(PLATFORM_INTERFACE)
32820 + platform_set_drvdata(_dev, dwc_otg_device);
32822 + dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device);
32824 + dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->os_dep.base);
32825 + DWC_DEBUGPL(DBG_HCDV, "probe of device %p given core_if %p\n",
32826 + dwc_otg_device, dwc_otg_device->core_if);//GRAYG
32828 + if (!dwc_otg_device->core_if) {
32829 + dev_err(&_dev->dev, "CIL initialization failed!\n");
32830 + retval = -ENOMEM;
32834 + dev_dbg(&_dev->dev, "Calling get_gsnpsid\n");
32836 + * Attempt to ensure this device is really a DWC_otg Controller.
32837 + * Read and verify the SNPSID register contents. The value should be
32838 + * 0x45F42XXX or 0x45F42XXX, which corresponds to either "OT2" or "OTG3",
32839 + * as in "OTG version 2.XX" or "OTG version 3.XX".
32842 + if (((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F542000) &&
32843 + ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F543000)) {
32844 + dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n",
32845 + dwc_otg_get_gsnpsid(dwc_otg_device->core_if));
32846 + retval = -EINVAL;
32851 + * Validate parameter values.
32853 + dev_dbg(&_dev->dev, "Calling set_parameters\n");
32854 + if (set_parameters(dwc_otg_device->core_if)) {
32855 + retval = -EINVAL;
32860 + * Create Device Attributes in sysfs
32862 + dev_dbg(&_dev->dev, "Calling attr_create\n");
32863 + dwc_otg_attr_create(_dev);
32866 + * Disable the global interrupt until all the interrupt
32867 + * handlers are installed.
32869 + dev_dbg(&_dev->dev, "Calling disable_global_interrupts\n");
32870 + dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
32873 + * Install the interrupt handler for the common interrupts before
32874 + * enabling common interrupts in core_init below.
32877 +#if defined(PLATFORM_INTERFACE)
32878 + devirq = platform_get_irq(_dev, 0);
32880 + devirq = _dev->irq;
32882 + DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n",
32884 + dev_dbg(&_dev->dev, "Calling request_irq(%d)\n", devirq);
32885 + retval = request_irq(devirq, dwc_otg_common_irq,
32887 + "dwc_otg", dwc_otg_device);
32889 + DWC_ERROR("request of irq%d failed\n", devirq);
32893 + dwc_otg_device->common_irq_installed = 1;
32896 +#ifndef IRQF_TRIGGER_LOW
32897 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
32898 + dev_dbg(&_dev->dev, "Calling set_irq_type\n");
32899 + set_irq_type(devirq,
32900 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
32903 + IRQ_TYPE_LEVEL_LOW
32907 +#endif /*IRQF_TRIGGER_LOW*/
32910 + * Initialize the DWC_otg core.
32912 + dev_dbg(&_dev->dev, "Calling dwc_otg_core_init\n");
32913 + dwc_otg_core_init(dwc_otg_device->core_if);
32915 +#ifndef DWC_HOST_ONLY
32917 + * Initialize the PCD
32919 + dev_dbg(&_dev->dev, "Calling pcd_init\n");
32920 + retval = pcd_init(_dev);
32921 + if (retval != 0) {
32922 + DWC_ERROR("pcd_init failed\n");
32923 + dwc_otg_device->pcd = NULL;
32927 +#ifndef DWC_DEVICE_ONLY
32929 + * Initialize the HCD
32931 + dev_dbg(&_dev->dev, "Calling hcd_init\n");
32932 + retval = hcd_init(_dev);
32933 + if (retval != 0) {
32934 + DWC_ERROR("hcd_init failed\n");
32935 + dwc_otg_device->hcd = NULL;
32939 + /* Recover from drvdata having been overwritten by hcd_init() */
32940 +#ifdef LM_INTERFACE
32941 + lm_set_drvdata(_dev, dwc_otg_device);
32942 +#elif defined(PLATFORM_INTERFACE)
32943 + platform_set_drvdata(_dev, dwc_otg_device);
32944 +#elif defined(PCI_INTERFACE)
32945 + pci_set_drvdata(_dev, dwc_otg_device);
32946 + dwc_otg_device->os_dep.pcidev = _dev;
32950 + * Enable the global interrupt after all the interrupt
32951 + * handlers are installed if there is no ADP support else
32952 + * perform initial actions required for Internal ADP logic.
32954 + if (!dwc_otg_get_param_adp_enable(dwc_otg_device->core_if)) {
32955 + dev_dbg(&_dev->dev, "Calling enable_global_interrupts\n");
32956 + dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);
32957 + dev_dbg(&_dev->dev, "Done\n");
32959 + dwc_otg_adp_start(dwc_otg_device->core_if,
32960 + dwc_otg_is_host_mode(dwc_otg_device->core_if));
32965 + dwc_otg_driver_remove(_dev);
32970 + * This structure defines the methods to be called by a bus driver
32971 + * during the lifecycle of a device on that bus. Both drivers and
32972 + * devices are registered with a bus driver. The bus driver matches
32973 + * devices to drivers based on information in the device and driver
32976 + * The probe function is called when the bus driver matches a device
32977 + * to this driver. The remove function is called when a device is
32978 + * unregistered with the bus driver.
32980 +#ifdef LM_INTERFACE
32981 +static struct lm_driver dwc_otg_driver = {
32982 + .drv = {.name = (char *)dwc_driver_name,},
32983 + .probe = dwc_otg_driver_probe,
32984 + .remove = dwc_otg_driver_remove,
32985 + // 'suspend' and 'resume' absent
32987 +#elif defined(PCI_INTERFACE)
32988 +static const struct pci_device_id pci_ids[] = { {
32989 + PCI_DEVICE(0x16c3, 0xabcd),
32991 + (unsigned long)0xdeadbeef,
32992 + }, { /* end: all zeroes */ }
32995 +MODULE_DEVICE_TABLE(pci, pci_ids);
32997 +/* pci driver glue; this is a "new style" PCI driver module */
32998 +static struct pci_driver dwc_otg_driver = {
32999 + .name = "dwc_otg",
33000 + .id_table = pci_ids,
33002 + .probe = dwc_otg_driver_probe,
33003 + .remove = dwc_otg_driver_remove,
33006 + .name = (char *)dwc_driver_name,
33009 +#elif defined(PLATFORM_INTERFACE)
33010 +static struct platform_device_id platform_ids[] = {
33012 + .name = "bcm2708_usb",
33013 + .driver_data = (kernel_ulong_t) 0xdeadbeef,
33015 + { /* end: all zeroes */ }
33017 +MODULE_DEVICE_TABLE(platform, platform_ids);
33019 +static struct platform_driver dwc_otg_driver = {
33021 + .name = (char *)dwc_driver_name,
33023 + .id_table = platform_ids,
33025 + .probe = dwc_otg_driver_probe,
33026 + .remove = dwc_otg_driver_remove,
33027 + // no 'shutdown', 'suspend', 'resume', 'suspend_late' or 'resume_early'
33032 + * This function is called when the dwc_otg_driver is installed with the
33033 + * insmod command. It registers the dwc_otg_driver structure with the
33034 + * appropriate bus driver. This will cause the dwc_otg_driver_probe function
33035 + * to be called. In addition, the bus driver will automatically expose
33036 + * attributes defined for the device and driver in the special sysfs file
33041 +static int __init dwc_otg_driver_init(void)
33045 + struct device_driver *drv;
33046 + printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name,
33047 + DWC_DRIVER_VERSION,
33048 +#ifdef LM_INTERFACE
33050 + retval = lm_driver_register(&dwc_otg_driver);
33051 + drv = &dwc_otg_driver.drv;
33052 +#elif defined(PCI_INTERFACE)
33054 + retval = pci_register_driver(&dwc_otg_driver);
33055 + drv = &dwc_otg_driver.driver;
33056 +#elif defined(PLATFORM_INTERFACE)
33058 + retval = platform_driver_register(&dwc_otg_driver);
33059 + drv = &dwc_otg_driver.driver;
33061 + if (retval < 0) {
33062 + printk(KERN_ERR "%s retval=%d\n", __func__, retval);
33066 + error = driver_create_file(drv, &driver_attr_version);
33068 + error = driver_create_file(drv, &driver_attr_debuglevel);
33073 +module_init(dwc_otg_driver_init);
33076 + * This function is called when the driver is removed from the kernel
33077 + * with the rmmod command. The driver unregisters itself with its bus
33081 +static void __exit dwc_otg_driver_cleanup(void)
33083 + printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n");
33085 +#ifdef LM_INTERFACE
33086 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
33087 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_version);
33088 + lm_driver_unregister(&dwc_otg_driver);
33089 +#elif defined(PCI_INTERFACE)
33090 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
33091 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
33092 + pci_unregister_driver(&dwc_otg_driver);
33093 +#elif defined(PLATFORM_INTERFACE)
33094 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
33095 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
33096 + platform_driver_unregister(&dwc_otg_driver);
33099 + printk(KERN_INFO "%s module removed\n", dwc_driver_name);
33102 +module_exit(dwc_otg_driver_cleanup);
33104 +MODULE_DESCRIPTION(DWC_DRIVER_DESC);
33105 +MODULE_AUTHOR("Synopsys Inc.");
33106 +MODULE_LICENSE("GPL");
33108 +module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444);
33109 +MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None");
33110 +module_param_named(opt, dwc_otg_module_params.opt, int, 0444);
33111 +MODULE_PARM_DESC(opt, "OPT Mode");
33112 +module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444);
33113 +MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled");
33115 +module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int,
33117 +MODULE_PARM_DESC(dma_desc_enable,
33118 + "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled");
33120 +module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int,
33122 +MODULE_PARM_DESC(dma_burst_size,
33123 + "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256");
33124 +module_param_named(speed, dwc_otg_module_params.speed, int, 0444);
33125 +MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed");
33126 +module_param_named(host_support_fs_ls_low_power,
33127 + dwc_otg_module_params.host_support_fs_ls_low_power, int,
33129 +MODULE_PARM_DESC(host_support_fs_ls_low_power,
33130 + "Support Low Power w/FS or LS 0=Support 1=Don't Support");
33131 +module_param_named(host_ls_low_power_phy_clk,
33132 + dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444);
33133 +MODULE_PARM_DESC(host_ls_low_power_phy_clk,
33134 + "Low Speed Low Power Clock 0=48Mhz 1=6Mhz");
33135 +module_param_named(enable_dynamic_fifo,
33136 + dwc_otg_module_params.enable_dynamic_fifo, int, 0444);
33137 +MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing");
33138 +module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int,
33140 +MODULE_PARM_DESC(data_fifo_size,
33141 + "Total number of words in the data FIFO memory 32-32768");
33142 +module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size,
33144 +MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
33145 +module_param_named(dev_nperio_tx_fifo_size,
33146 + dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444);
33147 +MODULE_PARM_DESC(dev_nperio_tx_fifo_size,
33148 + "Number of words in the non-periodic Tx FIFO 16-32768");
33149 +module_param_named(dev_perio_tx_fifo_size_1,
33150 + dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444);
33151 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_1,
33152 + "Number of words in the periodic Tx FIFO 4-768");
33153 +module_param_named(dev_perio_tx_fifo_size_2,
33154 + dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444);
33155 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_2,
33156 + "Number of words in the periodic Tx FIFO 4-768");
33157 +module_param_named(dev_perio_tx_fifo_size_3,
33158 + dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444);
33159 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_3,
33160 + "Number of words in the periodic Tx FIFO 4-768");
33161 +module_param_named(dev_perio_tx_fifo_size_4,
33162 + dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444);
33163 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_4,
33164 + "Number of words in the periodic Tx FIFO 4-768");
33165 +module_param_named(dev_perio_tx_fifo_size_5,
33166 + dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444);
33167 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_5,
33168 + "Number of words in the periodic Tx FIFO 4-768");
33169 +module_param_named(dev_perio_tx_fifo_size_6,
33170 + dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444);
33171 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_6,
33172 + "Number of words in the periodic Tx FIFO 4-768");
33173 +module_param_named(dev_perio_tx_fifo_size_7,
33174 + dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444);
33175 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_7,
33176 + "Number of words in the periodic Tx FIFO 4-768");
33177 +module_param_named(dev_perio_tx_fifo_size_8,
33178 + dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444);
33179 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_8,
33180 + "Number of words in the periodic Tx FIFO 4-768");
33181 +module_param_named(dev_perio_tx_fifo_size_9,
33182 + dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444);
33183 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_9,
33184 + "Number of words in the periodic Tx FIFO 4-768");
33185 +module_param_named(dev_perio_tx_fifo_size_10,
33186 + dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444);
33187 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_10,
33188 + "Number of words in the periodic Tx FIFO 4-768");
33189 +module_param_named(dev_perio_tx_fifo_size_11,
33190 + dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444);
33191 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_11,
33192 + "Number of words in the periodic Tx FIFO 4-768");
33193 +module_param_named(dev_perio_tx_fifo_size_12,
33194 + dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444);
33195 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_12,
33196 + "Number of words in the periodic Tx FIFO 4-768");
33197 +module_param_named(dev_perio_tx_fifo_size_13,
33198 + dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444);
33199 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_13,
33200 + "Number of words in the periodic Tx FIFO 4-768");
33201 +module_param_named(dev_perio_tx_fifo_size_14,
33202 + dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444);
33203 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_14,
33204 + "Number of words in the periodic Tx FIFO 4-768");
33205 +module_param_named(dev_perio_tx_fifo_size_15,
33206 + dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444);
33207 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_15,
33208 + "Number of words in the periodic Tx FIFO 4-768");
33209 +module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size,
33211 +MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
33212 +module_param_named(host_nperio_tx_fifo_size,
33213 + dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444);
33214 +MODULE_PARM_DESC(host_nperio_tx_fifo_size,
33215 + "Number of words in the non-periodic Tx FIFO 16-32768");
33216 +module_param_named(host_perio_tx_fifo_size,
33217 + dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444);
33218 +MODULE_PARM_DESC(host_perio_tx_fifo_size,
33219 + "Number of words in the host periodic Tx FIFO 16-32768");
33220 +module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size,
33222 +/** @todo Set the max to 512K, modify checks */
33223 +MODULE_PARM_DESC(max_transfer_size,
33224 + "The maximum transfer size supported in bytes 2047-65535");
33225 +module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count,
33227 +MODULE_PARM_DESC(max_packet_count,
33228 + "The maximum number of packets in a transfer 15-511");
33229 +module_param_named(host_channels, dwc_otg_module_params.host_channels, int,
33231 +MODULE_PARM_DESC(host_channels,
33232 + "The number of host channel registers to use 1-16");
33233 +module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int,
33235 +MODULE_PARM_DESC(dev_endpoints,
33236 + "The number of endpoints in addition to EP0 available for device mode 1-15");
33237 +module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444);
33238 +MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI");
33239 +module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int,
33241 +MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits");
33242 +module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444);
33243 +MODULE_PARM_DESC(phy_ulpi_ddr,
33244 + "ULPI at double or single data rate 0=Single 1=Double");
33245 +module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus,
33247 +MODULE_PARM_DESC(phy_ulpi_ext_vbus,
33248 + "ULPI PHY using internal or external vbus 0=Internal");
33249 +module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444);
33250 +MODULE_PARM_DESC(i2c_enable, "FS PHY Interface");
33251 +module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444);
33252 +MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only");
33253 +module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444);
33254 +MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs");
33255 +module_param_named(debug, g_dbg_lvl, int, 0444);
33256 +MODULE_PARM_DESC(debug, "");
33258 +module_param_named(en_multiple_tx_fifo,
33259 + dwc_otg_module_params.en_multiple_tx_fifo, int, 0444);
33260 +MODULE_PARM_DESC(en_multiple_tx_fifo,
33261 + "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled");
33262 +module_param_named(dev_tx_fifo_size_1,
33263 + dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444);
33264 +MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768");
33265 +module_param_named(dev_tx_fifo_size_2,
33266 + dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444);
33267 +MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768");
33268 +module_param_named(dev_tx_fifo_size_3,
33269 + dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444);
33270 +MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768");
33271 +module_param_named(dev_tx_fifo_size_4,
33272 + dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444);
33273 +MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768");
33274 +module_param_named(dev_tx_fifo_size_5,
33275 + dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444);
33276 +MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768");
33277 +module_param_named(dev_tx_fifo_size_6,
33278 + dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444);
33279 +MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768");
33280 +module_param_named(dev_tx_fifo_size_7,
33281 + dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444);
33282 +MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768");
33283 +module_param_named(dev_tx_fifo_size_8,
33284 + dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444);
33285 +MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768");
33286 +module_param_named(dev_tx_fifo_size_9,
33287 + dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444);
33288 +MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768");
33289 +module_param_named(dev_tx_fifo_size_10,
33290 + dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444);
33291 +MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768");
33292 +module_param_named(dev_tx_fifo_size_11,
33293 + dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444);
33294 +MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768");
33295 +module_param_named(dev_tx_fifo_size_12,
33296 + dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444);
33297 +MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768");
33298 +module_param_named(dev_tx_fifo_size_13,
33299 + dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444);
33300 +MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768");
33301 +module_param_named(dev_tx_fifo_size_14,
33302 + dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444);
33303 +MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768");
33304 +module_param_named(dev_tx_fifo_size_15,
33305 + dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444);
33306 +MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768");
33308 +module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444);
33309 +MODULE_PARM_DESC(thr_ctl,
33310 + "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled");
33311 +module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int,
33313 +MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs");
33314 +module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int,
33316 +MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs");
33318 +module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444);
33319 +module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444);
33320 +module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444);
33321 +MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled");
33322 +module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444);
33323 +MODULE_PARM_DESC(ic_usb_cap,
33324 + "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled");
33325 +module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int,
33327 +MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio");
33328 +module_param_named(power_down, dwc_otg_module_params.power_down, int, 0444);
33329 +MODULE_PARM_DESC(power_down, "Power Down Mode");
33330 +module_param_named(reload_ctl, dwc_otg_module_params.reload_ctl, int, 0444);
33331 +MODULE_PARM_DESC(reload_ctl, "HFIR Reload Control");
33332 +module_param_named(dev_out_nak, dwc_otg_module_params.dev_out_nak, int, 0444);
33333 +MODULE_PARM_DESC(dev_out_nak, "Enable Device OUT NAK");
33334 +module_param_named(cont_on_bna, dwc_otg_module_params.cont_on_bna, int, 0444);
33335 +MODULE_PARM_DESC(cont_on_bna, "Enable Enable Continue on BNA");
33336 +module_param_named(ahb_single, dwc_otg_module_params.ahb_single, int, 0444);
33337 +MODULE_PARM_DESC(ahb_single, "Enable AHB Single Support");
33338 +module_param_named(adp_enable, dwc_otg_module_params.adp_enable, int, 0444);
33339 +MODULE_PARM_DESC(adp_enable, "ADP Enable 0=ADP Disabled 1=ADP Enabled");
33340 +module_param_named(otg_ver, dwc_otg_module_params.otg_ver, int, 0444);
33341 +MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0");
33342 +module_param(microframe_schedule, bool, 0444);
33343 +MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");
33345 +/** @page "Module Parameters"
33347 + * The following parameters may be specified when starting the module.
33348 + * These parameters define how the DWC_otg controller should be
33349 + * configured. Parameter values are passed to the CIL initialization
33350 + * function dwc_otg_cil_init
33352 + * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code>
33356 + <tr><td>Parameter Name</td><td>Meaning</td></tr>
33360 + <td>Specifies the OTG capabilities. The driver will automatically detect the
33361 + value for this parameter if none is specified.
33362 + - 0: HNP and SRP capable (default, if available)
33363 + - 1: SRP Only capable
33364 + - 2: No HNP/SRP capable
33368 + <td>dma_enable</td>
33369 + <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs.
33370 + The driver will automatically detect the value for this parameter if none is
33373 + - 1: DMA (default, if available)
33377 + <td>dma_burst_size</td>
33378 + <td>The DMA Burst size (applicable only for External DMA Mode).
33379 + - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32)
33384 + <td>Specifies the maximum speed of operation in host and device mode. The
33385 + actual speed depends on the speed of the attached device and the value of
33387 + - 0: High Speed (default)
33392 + <td>host_support_fs_ls_low_power</td>
33393 + <td>Specifies whether low power mode is supported when attached to a Full
33394 + Speed or Low Speed device in host mode.
33395 + - 0: Don't support low power mode (default)
33396 + - 1: Support low power mode
33400 + <td>host_ls_low_power_phy_clk</td>
33401 + <td>Specifies the PHY clock rate in low power mode when connected to a Low
33402 + Speed device in host mode. This parameter is applicable only if
33403 + HOST_SUPPORT_FS_LS_LOW_POWER is enabled.
33404 + - 0: 48 MHz (default)
33409 + <td>enable_dynamic_fifo</td>
33410 + <td> Specifies whether FIFOs may be resized by the driver software.
33411 + - 0: Use cC FIFO size parameters
33412 + - 1: Allow dynamic FIFO sizing (default)
33416 + <td>data_fifo_size</td>
33417 + <td>Total number of 4-byte words in the data FIFO memory. This memory
33418 + includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs.
33419 + - Values: 32 to 32768 (default 8192)
33421 + Note: The total FIFO memory depth in the FPGA configuration is 8192.
33425 + <td>dev_rx_fifo_size</td>
33426 + <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic
33427 + FIFO sizing is enabled.
33428 + - Values: 16 to 32768 (default 1064)
33432 + <td>dev_nperio_tx_fifo_size</td>
33433 + <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when
33434 + dynamic FIFO sizing is enabled.
33435 + - Values: 16 to 32768 (default 1024)
33439 + <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td>
33440 + <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode
33441 + when dynamic FIFO sizing is enabled.
33442 + - Values: 4 to 768 (default 256)
33446 + <td>host_rx_fifo_size</td>
33447 + <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO
33448 + sizing is enabled.
33449 + - Values: 16 to 32768 (default 1024)
33453 + <td>host_nperio_tx_fifo_size</td>
33454 + <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when
33455 + dynamic FIFO sizing is enabled in the core.
33456 + - Values: 16 to 32768 (default 1024)
33460 + <td>host_perio_tx_fifo_size</td>
33461 + <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO
33462 + sizing is enabled.
33463 + - Values: 16 to 32768 (default 1024)
33467 + <td>max_transfer_size</td>
33468 + <td>The maximum transfer size supported in bytes.
33469 + - Values: 2047 to 65,535 (default 65,535)
33473 + <td>max_packet_count</td>
33474 + <td>The maximum number of packets in a transfer.
33475 + - Values: 15 to 511 (default 511)
33479 + <td>host_channels</td>
33480 + <td>The number of host channel registers to use.
33481 + - Values: 1 to 16 (default 12)
33483 + Note: The FPGA configuration supports a maximum of 12 host channels.
33487 + <td>dev_endpoints</td>
33488 + <td>The number of endpoints in addition to EP0 available for device mode
33490 + - Values: 1 to 15 (default 6 IN and OUT)
33492 + Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in
33497 + <td>phy_type</td>
33498 + <td>Specifies the type of PHY interface to use. By default, the driver will
33499 + automatically detect the phy_type.
33501 + - 1: UTMI+ (default, if available)
33506 + <td>phy_utmi_width</td>
33507 + <td>Specifies the UTMI+ Data Width. This parameter is applicable for a
33508 + phy_type of UTMI+. Also, this parameter is applicable only if the
33509 + OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the
33510 + core has been configured to work at either data path width.
33511 + - Values: 8 or 16 bits (default 16)
33515 + <td>phy_ulpi_ddr</td>
33516 + <td>Specifies whether the ULPI operates at double or single data rate. This
33517 + parameter is only applicable if phy_type is ULPI.
33518 + - 0: single data rate ULPI interface with 8 bit wide data bus (default)
33519 + - 1: double data rate ULPI interface with 4 bit wide data bus
33523 + <td>i2c_enable</td>
33524 + <td>Specifies whether to use the I2C interface for full speed PHY. This
33525 + parameter is only applicable if PHY_TYPE is FS.
33526 + - 0: Disabled (default)
33531 + <td>ulpi_fs_ls</td>
33532 + <td>Specifies whether to use ULPI FS/LS mode only.
33533 + - 0: Disabled (default)
33538 + <td>ts_dline</td>
33539 + <td>Specifies whether term select D-Line pulsing for all PHYs is enabled.
33540 + - 0: Disabled (default)
33545 + <td>en_multiple_tx_fifo</td>
33546 + <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs.
33547 + The driver will automatically detect the value for this parameter if none is
33550 + - 1: Enabled (default, if available)
33554 + <td>dev_tx_fifo_size_n (n = 1 to 15)</td>
33555 + <td>Number of 4-byte words in each of the Tx FIFOs in device mode
33556 + when dynamic FIFO sizing is enabled.
33557 + - Values: 4 to 768 (default 256)
33561 + <td>tx_thr_length</td>
33562 + <td>Transmit Threshold length in 32 bit double words
33563 + - Values: 8 to 128 (default 64)
33567 + <td>rx_thr_length</td>
33568 + <td>Receive Threshold length in 32 bit double words
33569 + - Values: 8 to 128 (default 64)
33574 + <td>Specifies whether to enable Thresholding for Device mode. Bits 0, 1, 2 of
33575 + this parmater specifies if thresholding is enabled for non-Iso Tx, Iso Tx and
33576 + Rx transfers accordingly.
33577 + The driver will automatically detect the value for this parameter if none is
33579 + - Values: 0 to 7 (default 0)
33580 + Bit values indicate:
33581 + - 0: Thresholding disabled
33582 + - 1: Thresholding enabled
33586 + <td>dma_desc_enable</td>
33587 + <td>Specifies whether to enable Descriptor DMA mode.
33588 + The driver will automatically detect the value for this parameter if none is
33590 + - 0: Descriptor DMA disabled
33591 + - 1: Descriptor DMA (default, if available)
33595 + <td>mpi_enable</td>
33596 + <td>Specifies whether to enable MPI enhancement mode.
33597 + The driver will automatically detect the value for this parameter if none is
33599 + - 0: MPI disabled (default)
33604 + <td>pti_enable</td>
33605 + <td>Specifies whether to enable PTI enhancement support.
33606 + The driver will automatically detect the value for this parameter if none is
33608 + - 0: PTI disabled (default)
33613 + <td>lpm_enable</td>
33614 + <td>Specifies whether to enable LPM support.
33615 + The driver will automatically detect the value for this parameter if none is
33617 + - 0: LPM disabled
33618 + - 1: LPM enable (default, if available)
33622 + <td>ic_usb_cap</td>
33623 + <td>Specifies whether to enable IC_USB capability.
33624 + The driver will automatically detect the value for this parameter if none is
33626 + - 0: IC_USB disabled (default, if available)
33627 + - 1: IC_USB enable
33631 + <td>ahb_thr_ratio</td>
33632 + <td>Specifies AHB Threshold ratio.
33633 + - Values: 0 to 3 (default 0)
33637 + <td>power_down</td>
33638 + <td>Specifies Power Down(Hibernation) Mode.
33639 + The driver will automatically detect the value for this parameter if none is
33641 + - 0: Power Down disabled (default)
33642 + - 2: Power Down enabled
33646 + <td>reload_ctl</td>
33647 + <td>Specifies whether dynamic reloading of the HFIR register is allowed during
33648 + run time. The driver will automatically detect the value for this parameter if
33649 + none is specified. In case the HFIR value is reloaded when HFIR.RldCtrl == 1'b0
33650 + the core might misbehave.
33651 + - 0: Reload Control disabled (default)
33652 + - 1: Reload Control enabled
33656 + <td>dev_out_nak</td>
33657 + <td>Specifies whether Device OUT NAK enhancement enabled or no.
33658 + The driver will automatically detect the value for this parameter if
33659 + none is specified. This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
33660 + - 0: The core does not set NAK after Bulk OUT transfer complete (default)
33661 + - 1: The core sets NAK after Bulk OUT transfer complete
33665 + <td>cont_on_bna</td>
33666 + <td>Specifies whether Enable Continue on BNA enabled or no.
33667 + After receiving BNA interrupt the core disables the endpoint,when the
33668 + endpoint is re-enabled by the application the
33669 + - 0: Core starts processing from the DOEPDMA descriptor (default)
33670 + - 1: Core starts processing from the descriptor which received the BNA.
33671 + This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
33675 + <td>ahb_single</td>
33676 + <td>This bit when programmed supports SINGLE transfers for remainder data
33677 + in a transfer for DMA mode of operation.
33678 + - 0: The remainder data will be sent using INCR burst size (default)
33679 + - 1: The remainder data will be sent using SINGLE burst size.
33683 + <td>adp_enable</td>
33684 + <td>Specifies whether ADP feature is enabled.
33685 + The driver will automatically detect the value for this parameter if none is
33687 + - 0: ADP feature disabled (default)
33688 + - 1: ADP feature enabled
33693 + <td>Specifies whether OTG is performing as USB OTG Revision 2.0 or Revision 1.3
33695 + - 0: OTG 2.0 support disabled (default)
33696 + - 1: OTG 2.0 support enabled
33701 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.h
33703 +/* ==========================================================================
33704 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $
33705 + * $Revision: #19 $
33706 + * $Date: 2010/11/15 $
33707 + * $Change: 1627671 $
33709 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
33710 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
33711 + * otherwise expressly agreed to in writing between Synopsys and you.
33713 + * The Software IS NOT an item of Licensed Software or Licensed Product under
33714 + * any End User Software License Agreement or Agreement for Licensed Product
33715 + * with Synopsys or any supplement thereto. You are permitted to use and
33716 + * redistribute this Software in source and binary forms, with or without
33717 + * modification, provided that redistributions of source code must retain this
33718 + * notice. You may not view, use, disclose, copy or distribute this file or
33719 + * any information contained herein except pursuant to this license grant from
33720 + * Synopsys. If you do not agree with this notice, including the disclaimer
33721 + * below, then you are not authorized to use the Software.
33723 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
33724 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33725 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33726 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
33727 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33728 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33729 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33730 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33731 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33732 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33734 + * ========================================================================== */
33736 +#ifndef __DWC_OTG_DRIVER_H__
33737 +#define __DWC_OTG_DRIVER_H__
33740 + * This file contains the interface to the Linux driver.
33742 +#include "dwc_otg_os_dep.h"
33743 +#include "dwc_otg_core_if.h"
33745 +/* Type declarations */
33746 +struct dwc_otg_pcd;
33747 +struct dwc_otg_hcd;
33750 + * This structure is a wrapper that encapsulates the driver components used to
33751 + * manage a single DWC_otg controller.
33753 +typedef struct dwc_otg_device {
33754 + /** Structure containing OS-dependent stuff. KEEP THIS STRUCT AT THE
33755 + * VERY BEGINNING OF THE DEVICE STRUCT. OSes such as FreeBSD and NetBSD
33756 + * require this. */
33757 + struct os_dependent os_dep;
33759 + /** Pointer to the core interface structure. */
33760 + dwc_otg_core_if_t *core_if;
33762 + /** Pointer to the PCD structure. */
33763 + struct dwc_otg_pcd *pcd;
33765 + /** Pointer to the HCD structure. */
33766 + struct dwc_otg_hcd *hcd;
33768 + /** Flag to indicate whether the common IRQ handler is installed. */
33769 + uint8_t common_irq_installed;
33771 +} dwc_otg_device_t;
33773 +/*We must clear S3C24XX_EINTPEND external interrupt register
33774 + * because after clearing in this register trigerred IRQ from
33775 + * H/W core in kernel interrupt can be occured again before OTG
33776 + * handlers clear all IRQ sources of Core registers because of
33777 + * timing latencies and Low Level IRQ Type.
33779 +#ifdef CONFIG_MACH_IPMATE
33780 +#define S3C2410X_CLEAR_EINTPEND() \
33782 + __raw_writel(1UL << 11,S3C24XX_EINTPEND); \
33785 +#define S3C2410X_CLEAR_EINTPEND() do { } while (0)
33790 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
33793 +/* ==========================================================================
33794 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
33795 + * $Revision: #104 $
33796 + * $Date: 2011/10/24 $
33797 + * $Change: 1871159 $
33799 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
33800 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
33801 + * otherwise expressly agreed to in writing between Synopsys and you.
33803 + * The Software IS NOT an item of Licensed Software or Licensed Product under
33804 + * any End User Software License Agreement or Agreement for Licensed Product
33805 + * with Synopsys or any supplement thereto. You are permitted to use and
33806 + * redistribute this Software in source and binary forms, with or without
33807 + * modification, provided that redistributions of source code must retain this
33808 + * notice. You may not view, use, disclose, copy or distribute this file or
33809 + * any information contained herein except pursuant to this license grant from
33810 + * Synopsys. If you do not agree with this notice, including the disclaimer
33811 + * below, then you are not authorized to use the Software.
33813 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
33814 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33815 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33816 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
33817 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33818 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33819 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33820 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33821 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33822 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33824 + * ========================================================================== */
33825 +#ifndef DWC_DEVICE_ONLY
33828 + * This file implements HCD Core. All code in this file is portable and doesn't
33829 + * use any OS specific functions.
33830 + * Interface provided by HCD Core is defined in <code><hcd_if.h></code>
33834 +#include "dwc_otg_hcd.h"
33835 +#include "dwc_otg_regs.h"
33837 +extern bool microframe_schedule;
33839 +//#define DEBUG_HOST_CHANNELS
33840 +#ifdef DEBUG_HOST_CHANNELS
33841 +static int last_sel_trans_num_per_scheduled = 0;
33842 +static int last_sel_trans_num_nonper_scheduled = 0;
33843 +static int last_sel_trans_num_avail_hc_at_start = 0;
33844 +static int last_sel_trans_num_avail_hc_at_end = 0;
33845 +#endif /* DEBUG_HOST_CHANNELS */
33847 +dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
33849 + return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
33853 + * Connection timeout function. An OTG host is required to display a
33854 + * message if the device does not connect within 10 seconds.
33856 +void dwc_otg_hcd_connect_timeout(void *ptr)
33858 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
33859 + DWC_PRINTF("Connect Timeout\n");
33860 + __DWC_ERROR("Device Not Connected/Responding\n");
33863 +#if defined(DEBUG)
33864 +static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
33866 + if (qh->channel != NULL) {
33867 + dwc_hc_t *hc = qh->channel;
33868 + dwc_list_link_t *item;
33869 + dwc_otg_qh_t *qh_item;
33870 + int num_channels = hcd->core_if->core_params->host_channels;
33873 + dwc_otg_hc_regs_t *hc_regs;
33874 + hcchar_data_t hcchar;
33875 + hcsplt_data_t hcsplt;
33876 + hctsiz_data_t hctsiz;
33879 + hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
33880 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
33881 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
33882 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
33883 + hcdma = DWC_READ_REG32(&hc_regs->hcdma);
33885 + DWC_PRINTF(" Assigned to channel %p:\n", hc);
33886 + DWC_PRINTF(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
33888 + DWC_PRINTF(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
33890 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
33891 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
33892 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
33893 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
33894 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
33895 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
33896 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
33897 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
33898 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
33899 + DWC_PRINTF(" qh: %p\n", hc->qh);
33900 + DWC_PRINTF(" NP inactive sched:\n");
33901 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
33903 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
33904 + DWC_PRINTF(" %p\n", qh_item);
33906 + DWC_PRINTF(" NP active sched:\n");
33907 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
33909 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
33910 + DWC_PRINTF(" %p\n", qh_item);
33912 + DWC_PRINTF(" Channels: \n");
33913 + for (i = 0; i < num_channels; i++) {
33914 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
33915 + DWC_PRINTF(" %2d: %p\n", i, hc);
33920 +#define dump_channel_info(hcd, qh)
33921 +#endif /* DEBUG */
33924 + * Work queue function for starting the HCD when A-Cable is connected.
33925 + * The hcd_start() must be called in a process context.
33927 +static void hcd_start_func(void *_vp)
33929 + dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
33931 + DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
33933 + hcd->fops->start(hcd);
33937 +static void del_xfer_timers(dwc_otg_hcd_t * hcd)
33941 + int num_channels = hcd->core_if->core_params->host_channels;
33942 + for (i = 0; i < num_channels; i++) {
33943 + DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
33948 +static void del_timers(dwc_otg_hcd_t * hcd)
33950 + del_xfer_timers(hcd);
33951 + DWC_TIMER_CANCEL(hcd->conn_timer);
33955 + * Processes all the URBs in a single list of QHs. Completes them with
33956 + * -ETIMEDOUT and frees the QTD.
33958 +static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
33960 + dwc_list_link_t *qh_item;
33961 + dwc_otg_qh_t *qh;
33962 + dwc_otg_qtd_t *qtd, *qtd_tmp;
33964 + DWC_LIST_FOREACH(qh_item, qh_list) {
33965 + qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
33966 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
33967 + &qh->qtd_list, qtd_list_entry) {
33968 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
33969 + if (qtd->urb != NULL) {
33970 + hcd->fops->complete(hcd, qtd->urb->priv,
33971 + qtd->urb, -DWC_E_TIMEOUT);
33972 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
33980 + * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
33981 + * and periodic schedules. The QTD associated with each URB is removed from
33982 + * the schedule and freed. This function may be called when a disconnect is
33983 + * detected or when the HCD is being stopped.
33985 +static void kill_all_urbs(dwc_otg_hcd_t * hcd)
33987 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
33988 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
33989 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
33990 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
33991 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
33992 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
33996 + * Start the connection timer. An OTG host is required to display a
33997 + * message if the device does not connect within 10 seconds. The
33998 + * timer is deleted if a port connect interrupt occurs before the
34001 +static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
34003 + DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
34007 + * HCD Callback function for disconnect of the HCD.
34009 + * @param p void pointer to the <code>struct usb_hcd</code>
34011 +static int32_t dwc_otg_hcd_session_start_cb(void *p)
34013 + dwc_otg_hcd_t *dwc_otg_hcd;
34014 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
34016 + dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
34021 + * HCD Callback function for starting the HCD when A-Cable is
34024 + * @param p void pointer to the <code>struct usb_hcd</code>
34026 +static int32_t dwc_otg_hcd_start_cb(void *p)
34028 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34029 + dwc_otg_core_if_t *core_if;
34030 + hprt0_data_t hprt0;
34032 + core_if = dwc_otg_hcd->core_if;
34034 + if (core_if->op_state == B_HOST) {
34036 + * Reset the port. During a HNP mode switch the reset
34037 + * needs to occur within 1ms and have a duration of at
34040 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
34041 + hprt0.b.prtrst = 1;
34042 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34044 + DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
34045 + hcd_start_func, dwc_otg_hcd, 50,
34052 + * HCD Callback function for disconnect of the HCD.
34054 + * @param p void pointer to the <code>struct usb_hcd</code>
34056 +static int32_t dwc_otg_hcd_disconnect_cb(void *p)
34058 + gintsts_data_t intr;
34059 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34062 + * Set status flags for the hub driver.
34064 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
34065 + dwc_otg_hcd->flags.b.port_connect_status = 0;
34068 + * Shutdown any transfers in process by clearing the Tx FIFO Empty
34069 + * interrupt mask and status bits and disabling subsequent host
34070 + * channel interrupts.
34073 + intr.b.nptxfempty = 1;
34074 + intr.b.ptxfempty = 1;
34075 + intr.b.hcintr = 1;
34076 + DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
34078 + DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
34081 + del_timers(dwc_otg_hcd);
34084 + * Turn off the vbus power only if the core has transitioned to device
34085 + * mode. If still in host mode, need to keep power on to detect a
34088 + if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
34089 + if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
34090 + hprt0_data_t hprt0 = {.d32 = 0 };
34091 + DWC_PRINTF("Disconnect: PortPower off\n");
34092 + hprt0.b.prtpwr = 0;
34093 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0,
34097 + dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
34100 + /* Respond with an error status to all URBs in the schedule. */
34101 + kill_all_urbs(dwc_otg_hcd);
34103 + if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
34104 + /* Clean up any host channels that were in use. */
34105 + int num_channels;
34107 + dwc_hc_t *channel;
34108 + dwc_otg_hc_regs_t *hc_regs;
34109 + hcchar_data_t hcchar;
34111 + num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
34113 + if (!dwc_otg_hcd->core_if->dma_enable) {
34114 + /* Flush out any channel requests in slave mode. */
34115 + for (i = 0; i < num_channels; i++) {
34116 + channel = dwc_otg_hcd->hc_ptr_array[i];
34117 + if (DWC_CIRCLEQ_EMPTY_ENTRY
34118 + (channel, hc_list_entry)) {
34120 + dwc_otg_hcd->core_if->
34121 + host_if->hc_regs[i];
34123 + DWC_READ_REG32(&hc_regs->hcchar);
34124 + if (hcchar.b.chen) {
34125 + hcchar.b.chen = 0;
34126 + hcchar.b.chdis = 1;
34127 + hcchar.b.epdir = 0;
34129 + (&hc_regs->hcchar,
34136 + for (i = 0; i < num_channels; i++) {
34137 + channel = dwc_otg_hcd->hc_ptr_array[i];
34138 + if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
34140 + dwc_otg_hcd->core_if->host_if->hc_regs[i];
34141 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
34142 + if (hcchar.b.chen) {
34143 + /* Halt the channel. */
34144 + hcchar.b.chdis = 1;
34145 + DWC_WRITE_REG32(&hc_regs->hcchar,
34149 + dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
34151 + DWC_CIRCLEQ_INSERT_TAIL
34152 + (&dwc_otg_hcd->free_hc_list, channel,
34155 + * Added for Descriptor DMA to prevent channel double cleanup
34156 + * in release_channel_ddma(). Which called from ep_disable
34157 + * when device disconnect.
34159 + channel->qh = NULL;
34164 + if (dwc_otg_hcd->fops->disconnect) {
34165 + dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
34172 + * HCD Callback function for stopping the HCD.
34174 + * @param p void pointer to the <code>struct usb_hcd</code>
34176 +static int32_t dwc_otg_hcd_stop_cb(void *p)
34178 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34180 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
34181 + dwc_otg_hcd_stop(dwc_otg_hcd);
34185 +#ifdef CONFIG_USB_DWC_OTG_LPM
34187 + * HCD Callback function for sleep of HCD.
34189 + * @param p void pointer to the <code>struct usb_hcd</code>
34191 +static int dwc_otg_hcd_sleep_cb(void *p)
34193 + dwc_otg_hcd_t *hcd = p;
34195 + dwc_otg_hcd_free_hc_from_lpm(hcd);
34202 + * HCD Callback function for Remote Wakeup.
34204 + * @param p void pointer to the <code>struct usb_hcd</code>
34206 +static int dwc_otg_hcd_rem_wakeup_cb(void *p)
34208 + dwc_otg_hcd_t *hcd = p;
34210 + if (hcd->core_if->lx_state == DWC_OTG_L2) {
34211 + hcd->flags.b.port_suspend_change = 1;
34213 +#ifdef CONFIG_USB_DWC_OTG_LPM
34215 + hcd->flags.b.port_l1_change = 1;
34222 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
34225 +void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
34227 + hprt0_data_t hprt0 = {.d32 = 0 };
34229 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
34232 + * The root hub should be disconnected before this function is called.
34233 + * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
34234 + * and the QH lists (via ..._hcd_endpoint_disable).
34237 + /* Turn off all host-specific interrupts. */
34238 + dwc_otg_disable_host_interrupts(hcd->core_if);
34240 + /* Turn off the vbus power */
34241 + DWC_PRINTF("PortPower off\n");
34242 + hprt0.b.prtpwr = 0;
34243 + DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
34247 +int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
34248 + dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
34249 + int atomic_alloc)
34251 + dwc_irqflags_t flags;
34253 + dwc_otg_qtd_t *qtd;
34254 + gintmsk_data_t intr_mask = {.d32 = 0 };
34256 +#ifdef DEBUG /* integrity checks (Broadcom) */
34257 + if (NULL == hcd->core_if) {
34258 + DWC_ERROR("**** DWC OTG HCD URB Enqueue - HCD has NULL core_if\n");
34259 + /* No longer connected. */
34260 + return -DWC_E_INVALID;
34263 + if (!hcd->flags.b.port_connect_status) {
34264 + /* No longer connected. */
34265 + DWC_ERROR("Not connected\n");
34266 + return -DWC_E_NO_DEVICE;
34269 + qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
34270 + if (qtd == NULL) {
34271 + DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
34272 + return -DWC_E_NO_MEMORY;
34274 +#ifdef DEBUG /* integrity checks (Broadcom) */
34275 + if (qtd->urb == NULL) {
34276 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD with no URBs\n");
34277 + return -DWC_E_NO_MEMORY;
34279 + if (qtd->urb->priv == NULL) {
34280 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD URB with no URB handle\n");
34281 + return -DWC_E_NO_MEMORY;
34285 + dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
34286 + // creates a new queue in ep_handle if it doesn't exist already
34287 + if (retval < 0) {
34288 + DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
34289 + "Error status %d\n", retval);
34290 + dwc_otg_hcd_qtd_free(qtd);
34292 + qtd->qh = *ep_handle;
34294 + intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
34295 + if (!intr_mask.b.sofintr && retval == 0) {
34296 + dwc_otg_transaction_type_e tr_type;
34297 + if ((qtd->qh->ep_type == UE_BULK)
34298 + && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
34299 + /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
34302 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34303 + tr_type = dwc_otg_hcd_select_transactions(hcd);
34304 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
34305 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
34307 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34313 +int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
34314 + dwc_otg_hcd_urb_t * dwc_otg_urb)
34316 + dwc_otg_qh_t *qh;
34317 + dwc_otg_qtd_t *urb_qtd;
34319 +#ifdef DEBUG /* integrity checks (Broadcom) */
34321 + if (hcd == NULL) {
34322 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL HCD\n");
34323 + return -DWC_E_INVALID;
34325 + if (dwc_otg_urb == NULL) {
34326 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL URB\n");
34327 + return -DWC_E_INVALID;
34329 + if (dwc_otg_urb->qtd == NULL) {
34330 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with NULL QTD\n");
34331 + return -DWC_E_INVALID;
34333 + urb_qtd = dwc_otg_urb->qtd;
34334 + if (urb_qtd->qh == NULL) {
34335 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
34336 + return -DWC_E_INVALID;
34339 + urb_qtd = dwc_otg_urb->qtd;
34341 + qh = urb_qtd->qh;
34342 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
34343 + if (urb_qtd->in_process) {
34344 + dump_channel_info(hcd, qh);
34347 +#ifdef DEBUG /* integrity checks (Broadcom) */
34348 + if (hcd->core_if == NULL) {
34349 + DWC_ERROR("**** DWC OTG HCD URB Dequeue HCD has NULL core_if\n");
34350 + return -DWC_E_INVALID;
34353 + if (urb_qtd->in_process && qh->channel) {
34354 + /* The QTD is in process (it has been assigned to a channel). */
34355 + if (hcd->flags.b.port_connect_status) {
34357 + * If still connected (i.e. in host mode), halt the
34358 + * channel so it can be used for other transfers. If
34359 + * no longer connected, the host registers can't be
34360 + * written to halt the channel since the core is in
34363 + dwc_otg_hc_halt(hcd->core_if, qh->channel,
34364 + DWC_OTG_HC_XFER_URB_DEQUEUE);
34369 + * Free the QTD and clean up the associated QH. Leave the QH in the
34370 + * schedule if it has any remaining QTDs.
34373 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue - "
34374 + "delete %sQueue handler\n",
34375 + hcd->core_if->dma_desc_enable?"DMA ":"");
34376 + if (!hcd->core_if->dma_desc_enable) {
34377 + uint8_t b = urb_qtd->in_process;
34378 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
34380 + dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
34381 + qh->channel = NULL;
34382 + } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
34383 + dwc_otg_hcd_qh_remove(hcd, qh);
34386 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
34391 +int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
34394 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
34396 + dwc_irqflags_t flags;
34399 + retval = -DWC_E_INVALID;
34404 + retval = -DWC_E_INVALID;
34408 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34410 + while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
34411 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34414 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34417 + dwc_otg_hcd_qh_remove(hcd, qh);
34419 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34421 + * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
34422 + * and qh_free to prevent stack dump on DWC_DMA_FREE() with
34423 + * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
34424 + * and dwc_otg_hcd_frame_list_alloc().
34426 + dwc_otg_hcd_qh_free(hcd, qh);
34432 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
34433 +int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle)
34436 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
34438 + return -DWC_E_INVALID;
34440 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
34446 + * HCD Callback structure for handling mode switching.
34448 +static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
34449 + .start = dwc_otg_hcd_start_cb,
34450 + .stop = dwc_otg_hcd_stop_cb,
34451 + .disconnect = dwc_otg_hcd_disconnect_cb,
34452 + .session_start = dwc_otg_hcd_session_start_cb,
34453 + .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
34454 +#ifdef CONFIG_USB_DWC_OTG_LPM
34455 + .sleep = dwc_otg_hcd_sleep_cb,
34461 + * Reset tasklet function
34463 +static void reset_tasklet_func(void *data)
34465 + dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
34466 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
34467 + hprt0_data_t hprt0;
34469 + DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
34471 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
34472 + hprt0.b.prtrst = 1;
34473 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34476 + hprt0.b.prtrst = 0;
34477 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34478 + dwc_otg_hcd->flags.b.port_reset_change = 1;
34481 +static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
34483 + dwc_list_link_t *item;
34484 + dwc_otg_qh_t *qh;
34485 + dwc_irqflags_t flags;
34487 + if (!qh_list->next) {
34488 + /* The list hasn't been initialized yet. */
34492 + * Hold spinlock here. Not needed in that case if bellow
34493 + * function is being called from ISR
34495 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34496 + /* Ensure there are no QTDs or URBs left. */
34497 + kill_urbs_in_qh_list(hcd, qh_list);
34498 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34500 + DWC_LIST_FOREACH(item, qh_list) {
34501 + qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
34502 + dwc_otg_hcd_qh_remove_and_free(hcd, qh);
34507 + * Exit from Hibernation if Host did not detect SRP from connected SRP capable
34508 + * Device during SRP time by host power up.
34510 +void dwc_otg_hcd_power_up(void *ptr)
34512 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
34513 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
34515 + DWC_PRINTF("%s called\n", __FUNCTION__);
34517 + if (!core_if->hibernation_suspend) {
34518 + DWC_PRINTF("Already exited from Hibernation\n");
34522 + /* Switch on the voltage to the core */
34523 + gpwrdn.b.pwrdnswtch = 1;
34524 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34527 + /* Reset the core */
34529 + gpwrdn.b.pwrdnrstn = 1;
34530 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34533 + /* Disable power clamps */
34535 + gpwrdn.b.pwrdnclmp = 1;
34536 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34538 + /* Remove reset the core signal */
34540 + gpwrdn.b.pwrdnrstn = 1;
34541 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
34544 + /* Disable PMU interrupt */
34546 + gpwrdn.b.pmuintsel = 1;
34547 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34549 + core_if->hibernation_suspend = 0;
34551 + /* Disable PMU */
34553 + gpwrdn.b.pmuactv = 1;
34554 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34557 + /* Enable VBUS */
34559 + gpwrdn.b.dis_vbus = 1;
34560 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34562 + core_if->op_state = A_HOST;
34563 + dwc_otg_core_init(core_if);
34564 + dwc_otg_enable_global_interrupts(core_if);
34565 + cil_hcd_start(core_if);
34569 + * Frees secondary storage associated with the dwc_otg_hcd structure contained
34570 + * in the struct usb_hcd field.
34572 +static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
34576 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
34578 + del_timers(dwc_otg_hcd);
34580 + /* Free memory for QH/QTD lists */
34581 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
34582 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
34583 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
34584 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
34585 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
34586 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
34588 + /* Free memory for the host channels. */
34589 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
34590 + dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
34593 + if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
34594 + DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
34597 + if (hc != NULL) {
34598 + DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
34604 + if (dwc_otg_hcd->core_if->dma_enable) {
34605 + if (dwc_otg_hcd->status_buf_dma) {
34606 + DWC_DMA_FREE(DWC_OTG_HCD_STATUS_BUF_SIZE,
34607 + dwc_otg_hcd->status_buf,
34608 + dwc_otg_hcd->status_buf_dma);
34610 + } else if (dwc_otg_hcd->status_buf != NULL) {
34611 + DWC_FREE(dwc_otg_hcd->status_buf);
34613 + DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
34614 + /* Set core_if's lock pointer to NULL */
34615 + dwc_otg_hcd->core_if->lock = NULL;
34617 + DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
34618 + DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
34620 +#ifdef DWC_DEV_SRPCAP
34621 + if (dwc_otg_hcd->core_if->power_down == 2 &&
34622 + dwc_otg_hcd->core_if->pwron_timer) {
34623 + DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer);
34626 + DWC_FREE(dwc_otg_hcd);
34629 +int init_hcd_usecs(dwc_otg_hcd_t *_hcd);
34631 +int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
34634 + int num_channels;
34636 + dwc_hc_t *channel;
34638 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK))
34639 + DWC_SPINLOCK_ALLOC_LINUX_DEBUG(hcd->lock);
34640 + DWC_SPINLOCK_ALLOC_LINUX_DEBUG(hcd->channel_lock);
34642 + hcd->lock = DWC_SPINLOCK_ALLOC();
34643 + hcd->channel_lock = DWC_SPINLOCK_ALLOC();
34645 + DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n",
34647 + if (!hcd->lock) {
34648 + DWC_ERROR("Could not allocate lock for pcd");
34650 + retval = -DWC_E_NO_MEMORY;
34653 + hcd->core_if = core_if;
34655 + /* Register the HCD CIL Callbacks */
34656 + dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
34657 + &hcd_cil_callbacks, hcd);
34659 + /* Initialize the non-periodic schedule. */
34660 + DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
34661 + DWC_LIST_INIT(&hcd->non_periodic_sched_active);
34663 + /* Initialize the periodic schedule. */
34664 + DWC_LIST_INIT(&hcd->periodic_sched_inactive);
34665 + DWC_LIST_INIT(&hcd->periodic_sched_ready);
34666 + DWC_LIST_INIT(&hcd->periodic_sched_assigned);
34667 + DWC_LIST_INIT(&hcd->periodic_sched_queued);
34670 + * Create a host channel descriptor for each host channel implemented
34671 + * in the controller. Initialize the channel descriptor array.
34673 + DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
34674 + num_channels = hcd->core_if->core_params->host_channels;
34675 + DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
34676 + for (i = 0; i < num_channels; i++) {
34677 + channel = DWC_ALLOC(sizeof(dwc_hc_t));
34678 + if (channel == NULL) {
34679 + retval = -DWC_E_NO_MEMORY;
34680 + DWC_ERROR("%s: host channel allocation failed\n",
34682 + dwc_otg_hcd_free(hcd);
34685 + channel->hc_num = i;
34686 + hcd->hc_ptr_array[i] = channel;
34688 + hcd->core_if->hc_xfer_timer[i] =
34689 + DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
34690 + &hcd->core_if->hc_xfer_info[i]);
34692 + DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
34696 + /* Initialize the Connection timeout timer. */
34697 + hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
34698 + dwc_otg_hcd_connect_timeout, 0);
34700 + printk(KERN_DEBUG "dwc_otg: Microframe scheduler %s\n", microframe_schedule ? "enabled":"disabled");
34701 + if (microframe_schedule)
34702 + init_hcd_usecs(hcd);
34704 + /* Initialize reset tasklet. */
34705 + hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
34706 +#ifdef DWC_DEV_SRPCAP
34707 + if (hcd->core_if->power_down == 2) {
34708 + /* Initialize Power on timer for Host power up in case hibernation */
34709 + hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER",
34710 + dwc_otg_hcd_power_up, core_if);
34715 + * Allocate space for storing data on status transactions. Normally no
34716 + * data is sent, but this space acts as a bit bucket. This must be
34717 + * done after usb_add_hcd since that function allocates the DMA buffer
34720 + if (hcd->core_if->dma_enable) {
34721 + hcd->status_buf =
34722 + DWC_DMA_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE,
34723 + &hcd->status_buf_dma);
34725 + hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE);
34727 + if (!hcd->status_buf) {
34728 + retval = -DWC_E_NO_MEMORY;
34729 + DWC_ERROR("%s: status_buf allocation failed\n", __func__);
34730 + dwc_otg_hcd_free(hcd);
34734 + hcd->otg_port = 1;
34735 + hcd->frame_list = NULL;
34736 + hcd->frame_list_dma = 0;
34737 + hcd->periodic_qh_count = 0;
34742 +void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
34744 + /* Turn off all host-specific interrupts. */
34745 + dwc_otg_disable_host_interrupts(hcd->core_if);
34747 + dwc_otg_hcd_free(hcd);
34751 + * Initializes dynamic portions of the DWC_otg HCD state.
34753 +static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
34755 + int num_channels;
34757 + dwc_hc_t *channel;
34758 + dwc_hc_t *channel_tmp;
34760 + hcd->flags.d32 = 0;
34762 + hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
34763 + if (!microframe_schedule) {
34764 + hcd->non_periodic_channels = 0;
34765 + hcd->periodic_channels = 0;
34767 + hcd->available_host_channels = hcd->core_if->core_params->host_channels;
34770 + * Put all channels in the free channel list and clean up channel
34773 + DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
34774 + &hcd->free_hc_list, hc_list_entry) {
34775 + DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
34778 + num_channels = hcd->core_if->core_params->host_channels;
34779 + for (i = 0; i < num_channels; i++) {
34780 + channel = hcd->hc_ptr_array[i];
34781 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
34783 + dwc_otg_hc_cleanup(hcd->core_if, channel);
34786 + /* Initialize the DWC core for host mode operation. */
34787 + dwc_otg_core_host_init(hcd->core_if);
34789 + /* Set core_if's lock pointer to the hcd->lock */
34790 + hcd->core_if->lock = hcd->lock;
34794 + * Assigns transactions from a QTD to a free host channel and initializes the
34795 + * host channel to perform the transactions. The host channel is removed from
34798 + * @param hcd The HCD state structure.
34799 + * @param qh Transactions from the first QTD for this QH are selected and
34800 + * assigned to a free host channel.
34802 +static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
34805 + dwc_otg_qtd_t *qtd;
34806 + dwc_otg_hcd_urb_t *urb;
34807 + void* ptr = NULL;
34809 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
34813 + DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p) - urb %x, actual_length %d\n", __func__, hcd, qh, (unsigned int)urb, urb->actual_length);
34815 + if (((urb->actual_length < 0) || (urb->actual_length > urb->length)) && !dwc_otg_hcd_is_pipe_in(&urb->pipe_info))
34816 + urb->actual_length = urb->length;
34819 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
34821 + /* Remove the host channel from the free list. */
34822 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
34824 + qh->channel = hc;
34826 + qtd->in_process = 1;
34829 + * Use usb_pipedevice to determine device address. This address is
34830 + * 0 before the SET_ADDRESS command and the correct address afterward.
34832 + hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
34833 + hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
34834 + hc->speed = qh->dev_speed;
34835 + hc->max_packet = dwc_max_packet(qh->maxp);
34837 + hc->xfer_started = 0;
34838 + hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
34839 + hc->error_state = (qtd->error_count > 0);
34840 + hc->halt_on_queue = 0;
34841 + hc->halt_pending = 0;
34842 + hc->requests = 0;
34845 + * The following values may be modified in the transfer type section
34846 + * below. The xfer_len value may be reduced when the transfer is
34847 + * started to accommodate the max widths of the XferSize and PktCnt
34848 + * fields in the HCTSIZn register.
34851 + hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
34852 + if (hc->ep_is_in) {
34855 + hc->do_ping = qh->ping_state;
34858 + hc->data_pid_start = qh->data_toggle;
34859 + hc->multi_count = 1;
34861 + if (hcd->core_if->dma_enable) {
34862 + hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
34864 + /* For non-dword aligned case */
34865 + if (((unsigned long)hc->xfer_buff & 0x3)
34866 + && !hcd->core_if->dma_desc_enable) {
34867 + ptr = (uint8_t *) urb->buf + urb->actual_length;
34870 + hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
34872 + hc->xfer_len = urb->length - urb->actual_length;
34873 + hc->xfer_count = 0;
34876 + * Set the split attributes
34878 + hc->do_split = 0;
34879 + if (qh->do_split) {
34880 + uint32_t hub_addr, port_addr;
34881 + hc->do_split = 1;
34882 + hc->xact_pos = qtd->isoc_split_pos;
34883 + hc->complete_split = qtd->complete_split;
34884 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
34885 + hc->hub_addr = (uint8_t) hub_addr;
34886 + hc->port_addr = (uint8_t) port_addr;
34889 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
34891 + hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
34892 + switch (qtd->control_phase) {
34893 + case DWC_OTG_CONTROL_SETUP:
34894 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n");
34896 + hc->ep_is_in = 0;
34897 + hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
34898 + if (hcd->core_if->dma_enable) {
34899 + hc->xfer_buff = (uint8_t *) urb->setup_dma;
34901 + hc->xfer_buff = (uint8_t *) urb->setup_packet;
34903 + hc->xfer_len = 8;
34906 + case DWC_OTG_CONTROL_DATA:
34907 + DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
34908 + hc->data_pid_start = qtd->data_toggle;
34910 + case DWC_OTG_CONTROL_STATUS:
34912 + * Direction is opposite of data direction or IN if no
34915 + DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n");
34916 + if (urb->length == 0) {
34917 + hc->ep_is_in = 1;
34920 + dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
34922 + if (hc->ep_is_in) {
34926 + hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
34928 + hc->xfer_len = 0;
34929 + if (hcd->core_if->dma_enable) {
34930 + hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
34932 + hc->xfer_buff = (uint8_t *) hcd->status_buf;
34939 + hc->ep_type = DWC_OTG_EP_TYPE_BULK;
34941 + case UE_INTERRUPT:
34942 + hc->ep_type = DWC_OTG_EP_TYPE_INTR;
34944 + case UE_ISOCHRONOUS:
34946 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
34948 + hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
34950 + if (hcd->core_if->dma_desc_enable)
34953 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
34955 + frame_desc->status = 0;
34957 + if (hcd->core_if->dma_enable) {
34958 + hc->xfer_buff = (uint8_t *) urb->dma;
34960 + hc->xfer_buff = (uint8_t *) urb->buf;
34963 + frame_desc->offset + qtd->isoc_split_offset;
34965 + frame_desc->length - qtd->isoc_split_offset;
34967 + /* For non-dword aligned buffers */
34968 + if (((unsigned long)hc->xfer_buff & 0x3)
34969 + && hcd->core_if->dma_enable) {
34971 + (uint8_t *) urb->buf + frame_desc->offset +
34972 + qtd->isoc_split_offset;
34976 + if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
34977 + if (hc->xfer_len <= 188) {
34978 + hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
34981 + DWC_HCSPLIT_XACTPOS_BEGIN;
34987 + /* non DWORD-aligned buffer case */
34989 + uint32_t buf_size;
34990 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
34991 + buf_size = hcd->core_if->core_params->max_transfer_size;
34995 + if (!qh->dw_align_buf) {
34996 + qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(buf_size,
34997 + &qh->dw_align_buf_dma);
34998 + if (!qh->dw_align_buf) {
35000 + ("%s: Failed to allocate memory to handle "
35001 + "non-dword aligned buffer case\n",
35006 + if (!hc->ep_is_in) {
35007 + dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
35009 + hc->align_buff = qh->dw_align_buf_dma;
35011 + hc->align_buff = 0;
35014 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
35015 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
35017 + * This value may be modified when the transfer is started to
35018 + * reflect the actual transfer length.
35020 + hc->multi_count = dwc_hb_mult(qh->maxp);
35023 + if (hcd->core_if->dma_desc_enable)
35024 + hc->desc_list_addr = qh->desc_list_dma;
35026 + dwc_otg_hc_init(hcd->core_if, hc);
35031 + * This function selects transactions from the HCD transfer schedule and
35032 + * assigns them to available host channels. It is called from HCD interrupt
35033 + * handler functions.
35035 + * @param hcd The HCD state structure.
35037 + * @return The types of new transactions that were assigned to host channels.
35039 +dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
35041 + dwc_list_link_t *qh_ptr;
35042 + dwc_otg_qh_t *qh;
35043 + int num_channels;
35044 + dwc_irqflags_t flags;
35045 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
35046 + dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
35049 + DWC_DEBUGPL(DBG_HCD, " Select Transactions\n");
35052 +#ifdef DEBUG_HOST_CHANNELS
35053 + last_sel_trans_num_per_scheduled = 0;
35054 + last_sel_trans_num_nonper_scheduled = 0;
35055 + last_sel_trans_num_avail_hc_at_start = hcd->available_host_channels;
35056 +#endif /* DEBUG_HOST_CHANNELS */
35058 + /* Process entries in the periodic ready list. */
35059 + qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
35061 + while (qh_ptr != &hcd->periodic_sched_ready &&
35062 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
35063 + if (microframe_schedule) {
35064 + // Make sure we leave one channel for non periodic transactions.
35065 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35066 + if (hcd->available_host_channels <= 1) {
35067 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35070 + hcd->available_host_channels--;
35071 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35072 +#ifdef DEBUG_HOST_CHANNELS
35073 + last_sel_trans_num_per_scheduled++;
35074 +#endif /* DEBUG_HOST_CHANNELS */
35076 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35077 + assign_and_init_hc(hcd, qh);
35080 + * Move the QH from the periodic ready schedule to the
35081 + * periodic assigned schedule.
35083 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
35084 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35085 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
35086 + &qh->qh_list_entry);
35087 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35089 + ret_val = DWC_OTG_TRANSACTION_PERIODIC;
35093 + * Process entries in the inactive portion of the non-periodic
35094 + * schedule. Some free host channels may not be used if they are
35095 + * reserved for periodic transfers.
35097 + qh_ptr = hcd->non_periodic_sched_inactive.next;
35098 + num_channels = hcd->core_if->core_params->host_channels;
35099 + while (qh_ptr != &hcd->non_periodic_sched_inactive &&
35100 + (microframe_schedule || hcd->non_periodic_channels <
35101 + num_channels - hcd->periodic_channels) &&
35102 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
35104 + if (microframe_schedule) {
35105 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35106 + if (hcd->available_host_channels < 1) {
35107 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35110 + hcd->available_host_channels--;
35111 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35112 +#ifdef DEBUG_HOST_CHANNELS
35113 + last_sel_trans_num_nonper_scheduled++;
35114 +#endif /* DEBUG_HOST_CHANNELS */
35116 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35118 + assign_and_init_hc(hcd, qh);
35121 + * Move the QH from the non-periodic inactive schedule to the
35122 + * non-periodic active schedule.
35124 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
35125 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35126 + DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
35127 + &qh->qh_list_entry);
35128 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35130 + if (ret_val == DWC_OTG_TRANSACTION_NONE) {
35131 + ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
35133 + ret_val = DWC_OTG_TRANSACTION_ALL;
35136 + if (!microframe_schedule)
35137 + hcd->non_periodic_channels++;
35140 +#ifdef DEBUG_HOST_CHANNELS
35141 + last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels;
35142 +#endif /* DEBUG_HOST_CHANNELS */
35144 + DWC_SPINLOCK_FREE(channel_lock);
35149 + * Attempts to queue a single transaction request for a host channel
35150 + * associated with either a periodic or non-periodic transfer. This function
35151 + * assumes that there is space available in the appropriate request queue. For
35152 + * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
35153 + * is available in the appropriate Tx FIFO.
35155 + * @param hcd The HCD state structure.
35156 + * @param hc Host channel descriptor associated with either a periodic or
35157 + * non-periodic transfer.
35158 + * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx
35159 + * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
35162 + * @return 1 if a request is queued and more requests may be needed to
35163 + * complete the transfer, 0 if no more requests are required for this
35164 + * transfer, -1 if there is insufficient space in the Tx FIFO.
35166 +static int queue_transaction(dwc_otg_hcd_t * hcd,
35167 + dwc_hc_t * hc, uint16_t fifo_dwords_avail)
35171 + if (hcd->core_if->dma_enable) {
35172 + if (hcd->core_if->dma_desc_enable) {
35173 + if (!hc->xfer_started
35174 + || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
35175 + dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
35176 + hc->qh->ping_state = 0;
35178 + } else if (!hc->xfer_started) {
35179 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35180 + hc->qh->ping_state = 0;
35183 + } else if (hc->halt_pending) {
35184 + /* Don't queue a request if the channel has been halted. */
35186 + } else if (hc->halt_on_queue) {
35187 + dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
35189 + } else if (hc->do_ping) {
35190 + if (!hc->xfer_started) {
35191 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35194 + } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
35195 + if ((fifo_dwords_avail * 4) >= hc->max_packet) {
35196 + if (!hc->xfer_started) {
35197 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35201 + dwc_otg_hc_continue_transfer(hcd->core_if,
35208 + if (!hc->xfer_started) {
35209 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35212 + retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
35220 + * Processes periodic channels for the next frame and queues transactions for
35221 + * these channels to the DWC_otg controller. After queueing transactions, the
35222 + * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
35223 + * to queue as Periodic Tx FIFO or request queue space becomes available.
35224 + * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
35226 +static void process_periodic_channels(dwc_otg_hcd_t * hcd)
35228 + hptxsts_data_t tx_status;
35229 + dwc_list_link_t *qh_ptr;
35230 + dwc_otg_qh_t *qh;
35232 + int no_queue_space = 0;
35233 + int no_fifo_space = 0;
35235 + dwc_otg_host_global_regs_t *host_regs;
35236 + host_regs = hcd->core_if->host_if->host_global_regs;
35238 + DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
35240 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35241 + DWC_DEBUGPL(DBG_HCDV,
35242 + " P Tx Req Queue Space Avail (before queue): %d\n",
35243 + tx_status.b.ptxqspcavail);
35244 + DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n",
35245 + tx_status.b.ptxfspcavail);
35248 + qh_ptr = hcd->periodic_sched_assigned.next;
35249 + while (qh_ptr != &hcd->periodic_sched_assigned) {
35250 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35251 + if (tx_status.b.ptxqspcavail == 0) {
35252 + no_queue_space = 1;
35256 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35259 + * Set a flag if we're queuing high-bandwidth in slave mode.
35260 + * The flag prevents any halts to get into the request queue in
35261 + * the middle of multiple high-bandwidth packets getting queued.
35263 + if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
35264 + hcd->core_if->queuing_high_bandwidth = 1;
35267 + queue_transaction(hcd, qh->channel,
35268 + tx_status.b.ptxfspcavail);
35269 + if (status < 0) {
35270 + no_fifo_space = 1;
35275 + * In Slave mode, stay on the current transfer until there is
35276 + * nothing more to do or the high-bandwidth request count is
35277 + * reached. In DMA mode, only need to queue one request. The
35278 + * controller automatically handles multiple packets for
35279 + * high-bandwidth transfers.
35281 + if (hcd->core_if->dma_enable || status == 0 ||
35282 + qh->channel->requests == qh->channel->multi_count) {
35283 + qh_ptr = qh_ptr->next;
35285 + * Move the QH from the periodic assigned schedule to
35286 + * the periodic queued schedule.
35288 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
35289 + &qh->qh_list_entry);
35291 + /* done queuing high bandwidth */
35292 + hcd->core_if->queuing_high_bandwidth = 0;
35296 + if (!hcd->core_if->dma_enable) {
35297 + dwc_otg_core_global_regs_t *global_regs;
35298 + gintmsk_data_t intr_mask = {.d32 = 0 };
35300 + global_regs = hcd->core_if->core_global_regs;
35301 + intr_mask.b.ptxfempty = 1;
35303 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35304 + DWC_DEBUGPL(DBG_HCDV,
35305 + " P Tx Req Queue Space Avail (after queue): %d\n",
35306 + tx_status.b.ptxqspcavail);
35307 + DWC_DEBUGPL(DBG_HCDV,
35308 + " P Tx FIFO Space Avail (after queue): %d\n",
35309 + tx_status.b.ptxfspcavail);
35311 + if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
35312 + no_queue_space || no_fifo_space) {
35314 + * May need to queue more transactions as the request
35315 + * queue or Tx FIFO empties. Enable the periodic Tx
35316 + * FIFO empty interrupt. (Always use the half-empty
35317 + * level to ensure that new requests are loaded as
35318 + * soon as possible.)
35320 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
35324 + * Disable the Tx FIFO empty interrupt since there are
35325 + * no more transactions that need to be queued right
35326 + * now. This function is called from interrupt
35327 + * handlers to queue more transactions as transfer
35330 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
35337 + * Processes active non-periodic channels and queues transactions for these
35338 + * channels to the DWC_otg controller. After queueing transactions, the NP Tx
35339 + * FIFO Empty interrupt is enabled if there are more transactions to queue as
35340 + * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
35341 + * FIFO Empty interrupt is disabled.
35343 +static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
35345 + gnptxsts_data_t tx_status;
35346 + dwc_list_link_t *orig_qh_ptr;
35347 + dwc_otg_qh_t *qh;
35349 + int no_queue_space = 0;
35350 + int no_fifo_space = 0;
35351 + int more_to_do = 0;
35353 + dwc_otg_core_global_regs_t *global_regs =
35354 + hcd->core_if->core_global_regs;
35356 + DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
35358 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35359 + DWC_DEBUGPL(DBG_HCDV,
35360 + " NP Tx Req Queue Space Avail (before queue): %d\n",
35361 + tx_status.b.nptxqspcavail);
35362 + DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n",
35363 + tx_status.b.nptxfspcavail);
35366 + * Keep track of the starting point. Skip over the start-of-list
35369 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
35370 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
35372 + orig_qh_ptr = hcd->non_periodic_qh_ptr;
35375 + * Process once through the active list or until no more space is
35376 + * available in the request queue or the Tx FIFO.
35379 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35380 + if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
35381 + no_queue_space = 1;
35385 + qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
35388 + queue_transaction(hcd, qh->channel,
35389 + tx_status.b.nptxfspcavail);
35391 + if (status > 0) {
35393 + } else if (status < 0) {
35394 + no_fifo_space = 1;
35398 + /* Advance to next QH, skipping start-of-list entry. */
35399 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
35400 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
35401 + hcd->non_periodic_qh_ptr =
35402 + hcd->non_periodic_qh_ptr->next;
35405 + } while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
35407 + if (!hcd->core_if->dma_enable) {
35408 + gintmsk_data_t intr_mask = {.d32 = 0 };
35409 + intr_mask.b.nptxfempty = 1;
35412 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35413 + DWC_DEBUGPL(DBG_HCDV,
35414 + " NP Tx Req Queue Space Avail (after queue): %d\n",
35415 + tx_status.b.nptxqspcavail);
35416 + DWC_DEBUGPL(DBG_HCDV,
35417 + " NP Tx FIFO Space Avail (after queue): %d\n",
35418 + tx_status.b.nptxfspcavail);
35420 + if (more_to_do || no_queue_space || no_fifo_space) {
35422 + * May need to queue more transactions as the request
35423 + * queue or Tx FIFO empties. Enable the non-periodic
35424 + * Tx FIFO empty interrupt. (Always use the half-empty
35425 + * level to ensure that new requests are loaded as
35426 + * soon as possible.)
35428 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
35432 + * Disable the Tx FIFO empty interrupt since there are
35433 + * no more transactions that need to be queued right
35434 + * now. This function is called from interrupt
35435 + * handlers to queue more transactions as transfer
35438 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
35445 + * This function processes the currently active host channels and queues
35446 + * transactions for these channels to the DWC_otg controller. It is called
35447 + * from HCD interrupt handler functions.
35449 + * @param hcd The HCD state structure.
35450 + * @param tr_type The type(s) of transactions to queue (non-periodic,
35451 + * periodic, or both).
35453 +void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
35454 + dwc_otg_transaction_type_e tr_type)
35457 + DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
35459 + /* Process host channels associated with periodic transfers. */
35460 + if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
35461 + tr_type == DWC_OTG_TRANSACTION_ALL) &&
35462 + !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
35464 + process_periodic_channels(hcd);
35467 + /* Process host channels associated with non-periodic transfers. */
35468 + if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
35469 + tr_type == DWC_OTG_TRANSACTION_ALL) {
35470 + if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
35471 + process_non_periodic_channels(hcd);
35474 + * Ensure NP Tx FIFO empty interrupt is disabled when
35475 + * there are no non-periodic transfers to process.
35477 + gintmsk_data_t gintmsk = {.d32 = 0 };
35478 + gintmsk.b.nptxfempty = 1;
35479 + DWC_MODIFY_REG32(&hcd->core_if->
35480 + core_global_regs->gintmsk, gintmsk.d32,
35486 +#ifdef DWC_HS_ELECT_TST
35488 + * Quick and dirty hack to implement the HS Electrical Test
35489 + * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
35491 + * This code was copied from our userspace app "hset". It sends a
35492 + * Get Device Descriptor control sequence in two parts, first the
35493 + * Setup packet by itself, followed some time later by the In and
35494 + * Ack packets. Rather than trying to figure out how to add this
35495 + * functionality to the normal driver code, we just hijack the
35496 + * hardware, using these two function to drive the hardware
35500 +static dwc_otg_core_global_regs_t *global_regs;
35501 +static dwc_otg_host_global_regs_t *hc_global_regs;
35502 +static dwc_otg_hc_regs_t *hc_regs;
35503 +static uint32_t *data_fifo;
35505 +static void do_setup(void)
35507 + gintsts_data_t gintsts;
35508 + hctsiz_data_t hctsiz;
35509 + hcchar_data_t hcchar;
35510 + haint_data_t haint;
35511 + hcint_data_t hcint;
35513 + /* Enable HAINTs */
35514 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
35516 + /* Enable HCINTs */
35517 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
35519 + /* Read GINTSTS */
35520 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35523 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35526 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35528 + /* Read HCCHAR */
35529 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35531 + /* Clear HCINT */
35532 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35534 + /* Clear HAINT */
35535 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35537 + /* Clear GINTSTS */
35538 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35540 + /* Read GINTSTS */
35541 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35544 + * Send Setup packet (Get Device Descriptor)
35547 + /* Make sure channel is disabled */
35548 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35549 + if (hcchar.b.chen) {
35550 + hcchar.b.chdis = 1;
35551 +// hcchar.b.chen = 1;
35552 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35554 + dwc_mdelay(1000);
35556 + /* Read GINTSTS */
35557 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35560 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35563 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35565 + /* Read HCCHAR */
35566 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35568 + /* Clear HCINT */
35569 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35571 + /* Clear HAINT */
35572 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35574 + /* Clear GINTSTS */
35575 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35577 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35582 + hctsiz.b.xfersize = 8;
35583 + hctsiz.b.pktcnt = 1;
35584 + hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
35585 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35588 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35589 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35590 + hcchar.b.epdir = 0;
35591 + hcchar.b.epnum = 0;
35592 + hcchar.b.mps = 8;
35593 + hcchar.b.chen = 1;
35594 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35596 + /* Fill FIFO with Setup data for Get Device Descriptor */
35597 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
35598 + DWC_WRITE_REG32(data_fifo++, 0x01000680);
35599 + DWC_WRITE_REG32(data_fifo++, 0x00080000);
35601 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35603 + /* Wait for host channel interrupt */
35605 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35606 + } while (gintsts.b.hcintr == 0);
35608 + /* Disable HCINTs */
35609 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
35611 + /* Disable HAINTs */
35612 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
35615 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35618 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35620 + /* Read HCCHAR */
35621 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35623 + /* Clear HCINT */
35624 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35626 + /* Clear HAINT */
35627 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35629 + /* Clear GINTSTS */
35630 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35632 + /* Read GINTSTS */
35633 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35636 +static void do_in_ack(void)
35638 + gintsts_data_t gintsts;
35639 + hctsiz_data_t hctsiz;
35640 + hcchar_data_t hcchar;
35641 + haint_data_t haint;
35642 + hcint_data_t hcint;
35643 + host_grxsts_data_t grxsts;
35645 + /* Enable HAINTs */
35646 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
35648 + /* Enable HCINTs */
35649 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
35651 + /* Read GINTSTS */
35652 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35655 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35658 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35660 + /* Read HCCHAR */
35661 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35663 + /* Clear HCINT */
35664 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35666 + /* Clear HAINT */
35667 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35669 + /* Clear GINTSTS */
35670 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35672 + /* Read GINTSTS */
35673 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35676 + * Receive Control In packet
35679 + /* Make sure channel is disabled */
35680 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35681 + if (hcchar.b.chen) {
35682 + hcchar.b.chdis = 1;
35683 + hcchar.b.chen = 1;
35684 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35686 + dwc_mdelay(1000);
35688 + /* Read GINTSTS */
35689 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35692 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35695 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35697 + /* Read HCCHAR */
35698 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35700 + /* Clear HCINT */
35701 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35703 + /* Clear HAINT */
35704 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35706 + /* Clear GINTSTS */
35707 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35709 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35714 + hctsiz.b.xfersize = 8;
35715 + hctsiz.b.pktcnt = 1;
35716 + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
35717 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35720 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35721 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35722 + hcchar.b.epdir = 1;
35723 + hcchar.b.epnum = 0;
35724 + hcchar.b.mps = 8;
35725 + hcchar.b.chen = 1;
35726 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35728 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35730 + /* Wait for receive status queue interrupt */
35732 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35733 + } while (gintsts.b.rxstsqlvl == 0);
35736 + grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
35738 + /* Clear RXSTSQLVL in GINTSTS */
35740 + gintsts.b.rxstsqlvl = 1;
35741 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35743 + switch (grxsts.b.pktsts) {
35744 + case DWC_GRXSTS_PKTSTS_IN:
35745 + /* Read the data into the host buffer */
35746 + if (grxsts.b.bcnt > 0) {
35748 + int word_count = (grxsts.b.bcnt + 3) / 4;
35750 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
35752 + for (i = 0; i < word_count; i++) {
35753 + (void)DWC_READ_REG32(data_fifo++);
35762 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35764 + /* Wait for receive status queue interrupt */
35766 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35767 + } while (gintsts.b.rxstsqlvl == 0);
35770 + grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
35772 + /* Clear RXSTSQLVL in GINTSTS */
35774 + gintsts.b.rxstsqlvl = 1;
35775 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35777 + switch (grxsts.b.pktsts) {
35778 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
35785 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35787 + /* Wait for host channel interrupt */
35789 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35790 + } while (gintsts.b.hcintr == 0);
35793 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35796 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35798 + /* Read HCCHAR */
35799 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35801 + /* Clear HCINT */
35802 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35804 + /* Clear HAINT */
35805 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35807 + /* Clear GINTSTS */
35808 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35810 + /* Read GINTSTS */
35811 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35813 +// usleep(100000);
35818 + * Send handshake packet
35822 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35825 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35827 + /* Read HCCHAR */
35828 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35830 + /* Clear HCINT */
35831 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35833 + /* Clear HAINT */
35834 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35836 + /* Clear GINTSTS */
35837 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35839 + /* Read GINTSTS */
35840 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35842 + /* Make sure channel is disabled */
35843 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35844 + if (hcchar.b.chen) {
35845 + hcchar.b.chdis = 1;
35846 + hcchar.b.chen = 1;
35847 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35849 + dwc_mdelay(1000);
35851 + /* Read GINTSTS */
35852 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35855 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35858 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35860 + /* Read HCCHAR */
35861 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35863 + /* Clear HCINT */
35864 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35866 + /* Clear HAINT */
35867 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35869 + /* Clear GINTSTS */
35870 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35872 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35877 + hctsiz.b.xfersize = 0;
35878 + hctsiz.b.pktcnt = 1;
35879 + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
35880 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35883 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35884 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35885 + hcchar.b.epdir = 0;
35886 + hcchar.b.epnum = 0;
35887 + hcchar.b.mps = 8;
35888 + hcchar.b.chen = 1;
35889 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35891 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35893 + /* Wait for host channel interrupt */
35895 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35896 + } while (gintsts.b.hcintr == 0);
35898 + /* Disable HCINTs */
35899 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
35901 + /* Disable HAINTs */
35902 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
35905 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35908 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35910 + /* Read HCCHAR */
35911 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35913 + /* Clear HCINT */
35914 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35916 + /* Clear HAINT */
35917 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35919 + /* Clear GINTSTS */
35920 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35922 + /* Read GINTSTS */
35923 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35927 +/** Handles hub class-specific requests. */
35928 +int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
35929 + uint16_t typeReq,
35931 + uint16_t wIndex, uint8_t * buf, uint16_t wLength)
35935 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
35936 + usb_hub_descriptor_t *hub_desc;
35937 + hprt0_data_t hprt0 = {.d32 = 0 };
35939 + uint32_t port_status;
35941 + switch (typeReq) {
35942 + case UCR_CLEAR_HUB_FEATURE:
35943 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35944 + "ClearHubFeature 0x%x\n", wValue);
35945 + switch (wValue) {
35946 + case UHF_C_HUB_LOCAL_POWER:
35947 + case UHF_C_HUB_OVER_CURRENT:
35948 + /* Nothing required here */
35951 + retval = -DWC_E_INVALID;
35952 + DWC_ERROR("DWC OTG HCD - "
35953 + "ClearHubFeature request %xh unknown\n",
35957 + case UCR_CLEAR_PORT_FEATURE:
35958 +#ifdef CONFIG_USB_DWC_OTG_LPM
35959 + if (wValue != UHF_PORT_L1)
35961 + if (!wIndex || wIndex > 1)
35964 + switch (wValue) {
35965 + case UHF_PORT_ENABLE:
35966 + DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
35967 + "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
35968 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
35969 + hprt0.b.prtena = 1;
35970 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
35972 + case UHF_PORT_SUSPEND:
35973 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
35974 + "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
35976 + if (core_if->power_down == 2) {
35977 + dwc_otg_host_hibernation_restore(core_if, 0, 0);
35979 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
35982 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
35983 + hprt0.b.prtres = 1;
35984 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
35985 + hprt0.b.prtsusp = 0;
35986 + /* Clear Resume bit */
35988 + hprt0.b.prtres = 0;
35989 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
35992 +#ifdef CONFIG_USB_DWC_OTG_LPM
35993 + case UHF_PORT_L1:
35995 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
35996 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
35999 + DWC_READ_REG32(&core_if->
36000 + core_global_regs->glpmcfg);
36001 + lpmcfg.b.en_utmi_sleep = 0;
36002 + lpmcfg.b.hird_thres &= (~(1 << 4));
36003 + lpmcfg.b.prt_sleep_sts = 1;
36004 + DWC_WRITE_REG32(&core_if->
36005 + core_global_regs->glpmcfg,
36008 + /* Clear Enbl_L1Gating bit. */
36009 + pcgcctl.b.enbl_sleep_gating = 1;
36010 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
36015 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36016 + hprt0.b.prtres = 1;
36017 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36019 + /* This bit will be cleared in wakeup interrupt handle */
36023 + case UHF_PORT_POWER:
36024 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36025 + "ClearPortFeature USB_PORT_FEAT_POWER\n");
36026 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36027 + hprt0.b.prtpwr = 0;
36028 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36030 + case UHF_PORT_INDICATOR:
36031 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36032 + "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
36033 + /* Port inidicator not supported */
36035 + case UHF_C_PORT_CONNECTION:
36036 + /* Clears drivers internal connect status change
36038 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36039 + "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
36040 + dwc_otg_hcd->flags.b.port_connect_status_change = 0;
36042 + case UHF_C_PORT_RESET:
36043 + /* Clears the driver's internal Port Reset Change
36045 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36046 + "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
36047 + dwc_otg_hcd->flags.b.port_reset_change = 0;
36049 + case UHF_C_PORT_ENABLE:
36050 + /* Clears the driver's internal Port
36051 + * Enable/Disable Change flag */
36052 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36053 + "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
36054 + dwc_otg_hcd->flags.b.port_enable_change = 0;
36056 + case UHF_C_PORT_SUSPEND:
36057 + /* Clears the driver's internal Port Suspend
36058 + * Change flag, which is set when resume signaling on
36059 + * the host port is complete */
36060 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36061 + "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
36062 + dwc_otg_hcd->flags.b.port_suspend_change = 0;
36064 +#ifdef CONFIG_USB_DWC_OTG_LPM
36065 + case UHF_C_PORT_L1:
36066 + dwc_otg_hcd->flags.b.port_l1_change = 0;
36069 + case UHF_C_PORT_OVER_CURRENT:
36070 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36071 + "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
36072 + dwc_otg_hcd->flags.b.port_over_current_change = 0;
36075 + retval = -DWC_E_INVALID;
36076 + DWC_ERROR("DWC OTG HCD - "
36077 + "ClearPortFeature request %xh "
36078 + "unknown or unsupported\n", wValue);
36081 + case UCR_GET_HUB_DESCRIPTOR:
36082 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36083 + "GetHubDescriptor\n");
36084 + hub_desc = (usb_hub_descriptor_t *) buf;
36085 + hub_desc->bDescLength = 9;
36086 + hub_desc->bDescriptorType = 0x29;
36087 + hub_desc->bNbrPorts = 1;
36088 + USETW(hub_desc->wHubCharacteristics, 0x08);
36089 + hub_desc->bPwrOn2PwrGood = 1;
36090 + hub_desc->bHubContrCurrent = 0;
36091 + hub_desc->DeviceRemovable[0] = 0;
36092 + hub_desc->DeviceRemovable[1] = 0xff;
36094 + case UCR_GET_HUB_STATUS:
36095 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36096 + "GetHubStatus\n");
36097 + DWC_MEMSET(buf, 0, 4);
36099 + case UCR_GET_PORT_STATUS:
36100 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36101 + "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n",
36102 + wIndex, dwc_otg_hcd->flags.d32);
36103 + if (!wIndex || wIndex > 1)
36108 + if (dwc_otg_hcd->flags.b.port_connect_status_change)
36109 + port_status |= (1 << UHF_C_PORT_CONNECTION);
36111 + if (dwc_otg_hcd->flags.b.port_enable_change)
36112 + port_status |= (1 << UHF_C_PORT_ENABLE);
36114 + if (dwc_otg_hcd->flags.b.port_suspend_change)
36115 + port_status |= (1 << UHF_C_PORT_SUSPEND);
36117 + if (dwc_otg_hcd->flags.b.port_l1_change)
36118 + port_status |= (1 << UHF_C_PORT_L1);
36120 + if (dwc_otg_hcd->flags.b.port_reset_change) {
36121 + port_status |= (1 << UHF_C_PORT_RESET);
36124 + if (dwc_otg_hcd->flags.b.port_over_current_change) {
36125 + DWC_WARN("Overcurrent change detected\n");
36126 + port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
36129 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
36131 + * The port is disconnected, which means the core is
36132 + * either in device mode or it soon will be. Just
36133 + * return 0's for the remainder of the port status
36134 + * since the port register can't be read if the core
36135 + * is in device mode.
36137 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
36141 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
36142 + DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32);
36144 + if (hprt0.b.prtconnsts)
36145 + port_status |= (1 << UHF_PORT_CONNECTION);
36147 + if (hprt0.b.prtena)
36148 + port_status |= (1 << UHF_PORT_ENABLE);
36150 + if (hprt0.b.prtsusp)
36151 + port_status |= (1 << UHF_PORT_SUSPEND);
36153 + if (hprt0.b.prtovrcurract)
36154 + port_status |= (1 << UHF_PORT_OVER_CURRENT);
36156 + if (hprt0.b.prtrst)
36157 + port_status |= (1 << UHF_PORT_RESET);
36159 + if (hprt0.b.prtpwr)
36160 + port_status |= (1 << UHF_PORT_POWER);
36162 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
36163 + port_status |= (1 << UHF_PORT_HIGH_SPEED);
36164 + else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
36165 + port_status |= (1 << UHF_PORT_LOW_SPEED);
36167 + if (hprt0.b.prttstctl)
36168 + port_status |= (1 << UHF_PORT_TEST);
36169 + if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
36170 + port_status |= (1 << UHF_PORT_L1);
36173 + For Synopsys HW emulation of Power down wkup_control asserts the
36174 + hreset_n and prst_n on suspned. This causes the HPRT0 to be zero.
36175 + We intentionally tell the software that port is in L2Suspend state.
36178 + if ((core_if->power_down == 2)
36179 + && (core_if->hibernation_suspend == 1)) {
36180 + port_status |= (1 << UHF_PORT_SUSPEND);
36182 + /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
36184 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
36187 + case UCR_SET_HUB_FEATURE:
36188 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36189 + "SetHubFeature\n");
36190 + /* No HUB features supported */
36192 + case UCR_SET_PORT_FEATURE:
36193 + if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
36196 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
36198 + * The port is disconnected, which means the core is
36199 + * either in device mode or it soon will be. Just
36200 + * return without doing anything since the port
36201 + * register can't be written if the core is in device
36207 + switch (wValue) {
36208 + case UHF_PORT_SUSPEND:
36209 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36210 + "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
36211 + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) {
36214 + if (core_if->power_down == 2) {
36215 + int timeout = 300;
36216 + dwc_irqflags_t flags;
36217 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36218 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
36219 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
36220 +#ifdef DWC_DEV_SRPCAP
36221 + int32_t otg_cap_param = core_if->core_params->otg_cap;
36223 + DWC_PRINTF("Preparing for complete power-off\n");
36225 + /* Save registers before hibernation */
36226 + dwc_otg_save_global_regs(core_if);
36227 + dwc_otg_save_host_regs(core_if);
36229 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36230 + hprt0.b.prtsusp = 1;
36231 + hprt0.b.prtena = 0;
36232 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36233 + /* Spin hprt0.b.prtsusp to became 1 */
36235 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36236 + if (hprt0.b.prtsusp) {
36240 + } while (--timeout);
36242 + DWC_WARN("Suspend wasn't genereted\n");
36247 + * We need to disable interrupts to prevent servicing of any IRQ
36248 + * during going to hibernation
36250 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
36251 + core_if->lx_state = DWC_OTG_L2;
36252 +#ifdef DWC_DEV_SRPCAP
36253 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36254 + hprt0.b.prtpwr = 0;
36255 + hprt0.b.prtena = 0;
36256 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36260 + DWC_READ_REG32(&core_if->core_global_regs->
36262 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
36263 + /* ULPI interface */
36264 + /* Suspend the Phy Clock */
36266 + pcgcctl.b.stoppclk = 1;
36267 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
36270 + gpwrdn.b.pmuactv = 1;
36271 + DWC_MODIFY_REG32(&core_if->
36272 + core_global_regs->
36273 + gpwrdn, 0, gpwrdn.d32);
36275 + /* UTMI+ Interface */
36276 + gpwrdn.b.pmuactv = 1;
36277 + DWC_MODIFY_REG32(&core_if->
36278 + core_global_regs->
36279 + gpwrdn, 0, gpwrdn.d32);
36281 + pcgcctl.b.stoppclk = 1;
36282 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
36285 +#ifdef DWC_DEV_SRPCAP
36287 + gpwrdn.b.dis_vbus = 1;
36288 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36289 + gpwrdn, 0, gpwrdn.d32);
36292 + gpwrdn.b.pmuintsel = 1;
36293 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36294 + gpwrdn, 0, gpwrdn.d32);
36298 +#ifdef DWC_DEV_SRPCAP
36299 + gpwrdn.b.srp_det_msk = 1;
36301 + gpwrdn.b.disconn_det_msk = 1;
36302 + gpwrdn.b.lnstchng_msk = 1;
36303 + gpwrdn.b.sts_chngint_msk = 1;
36304 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36305 + gpwrdn, 0, gpwrdn.d32);
36308 + /* Enable Power Down Clamp and all interrupts in GPWRDN */
36310 + gpwrdn.b.pwrdnclmp = 1;
36311 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36312 + gpwrdn, 0, gpwrdn.d32);
36315 + /* Switch off VDD */
36317 + gpwrdn.b.pwrdnswtch = 1;
36318 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36319 + gpwrdn, 0, gpwrdn.d32);
36321 +#ifdef DWC_DEV_SRPCAP
36322 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
36324 + core_if->pwron_timer_started = 1;
36325 + DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ );
36328 + /* Save gpwrdn register for further usage if stschng interrupt */
36329 + core_if->gr_backup->gpwrdn_local =
36330 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
36332 + /* Set flag to indicate that we are in hibernation */
36333 + core_if->hibernation_suspend = 1;
36334 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags);
36336 + DWC_PRINTF("Host hibernation completed\n");
36337 + // Exit from case statement
36341 + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
36342 + dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
36343 + gotgctl_data_t gotgctl = {.d32 = 0 };
36344 + gotgctl.b.hstsethnpen = 1;
36345 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36346 + gotgctl, 0, gotgctl.d32);
36347 + core_if->op_state = A_SUSPEND;
36349 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36350 + hprt0.b.prtsusp = 1;
36351 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36353 + dwc_irqflags_t flags;
36354 + /* Update lx_state */
36355 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
36356 + core_if->lx_state = DWC_OTG_L2;
36357 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
36359 + /* Suspend the Phy Clock */
36361 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36362 + pcgcctl.b.stoppclk = 1;
36363 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
36368 + /* For HNP the bus must be suspended for at least 200ms. */
36369 + if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
36370 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36371 + pcgcctl.b.stoppclk = 1;
36372 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
36376 + /** @todo - check how sw can wait for 1 sec to check asesvld??? */
36377 +#if 0 //vahrama !!!!!!!!!!!!!!!!!!
36378 + if (core_if->adp_enable) {
36379 + gotgctl_data_t gotgctl = {.d32 = 0 };
36380 + gpwrdn_data_t gpwrdn;
36382 + while (gotgctl.b.asesvld == 1) {
36384 + DWC_READ_REG32(&core_if->
36385 + core_global_regs->
36390 + /* Enable Power Down Logic */
36392 + gpwrdn.b.pmuactv = 1;
36393 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36394 + gpwrdn, 0, gpwrdn.d32);
36396 + /* Unmask SRP detected interrupt from Power Down Logic */
36398 + gpwrdn.b.srp_det_msk = 1;
36399 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36400 + gpwrdn, 0, gpwrdn.d32);
36402 + dwc_otg_adp_probe_start(core_if);
36406 + case UHF_PORT_POWER:
36407 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36408 + "SetPortFeature - USB_PORT_FEAT_POWER\n");
36409 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36410 + hprt0.b.prtpwr = 1;
36411 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36413 + case UHF_PORT_RESET:
36414 + if ((core_if->power_down == 2)
36415 + && (core_if->hibernation_suspend == 1)) {
36416 + /* If we are going to exit from Hibernated
36417 + * state via USB RESET.
36419 + dwc_otg_host_hibernation_restore(core_if, 0, 1);
36421 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36423 + DWC_DEBUGPL(DBG_HCD,
36424 + "DWC OTG HCD HUB CONTROL - "
36425 + "SetPortFeature - USB_PORT_FEAT_RESET\n");
36427 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36428 + pcgcctl.b.enbl_sleep_gating = 1;
36429 + pcgcctl.b.stoppclk = 1;
36430 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
36431 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
36433 +#ifdef CONFIG_USB_DWC_OTG_LPM
36435 + glpmcfg_data_t lpmcfg;
36437 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36438 + if (lpmcfg.b.prt_sleep_sts) {
36439 + lpmcfg.b.en_utmi_sleep = 0;
36440 + lpmcfg.b.hird_thres &= (~(1 << 4));
36442 + (&core_if->core_global_regs->glpmcfg,
36448 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36449 + /* Clear suspend bit if resetting from suspended state. */
36450 + hprt0.b.prtsusp = 0;
36451 + /* When B-Host the Port reset bit is set in
36452 + * the Start HCD Callback function, so that
36453 + * the reset is started within 1ms of the HNP
36454 + * success interrupt. */
36455 + if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
36456 + hprt0.b.prtpwr = 1;
36457 + hprt0.b.prtrst = 1;
36458 + DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32);
36459 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36462 + /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
36464 + hprt0.b.prtrst = 0;
36465 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36466 + core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */
36469 +#ifdef DWC_HS_ELECT_TST
36470 + case UHF_PORT_TEST:
36473 + gintmsk_data_t gintmsk;
36475 + t = (wIndex >> 8); /* MSB wIndex USB */
36476 + DWC_DEBUGPL(DBG_HCD,
36477 + "DWC OTG HCD HUB CONTROL - "
36478 + "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
36480 + DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
36482 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36483 + hprt0.b.prttstctl = t;
36484 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36487 + /* Setup global vars with reg addresses (quick and
36488 + * dirty hack, should be cleaned up)
36490 + global_regs = core_if->core_global_regs;
36492 + core_if->host_if->host_global_regs;
36494 + (dwc_otg_hc_regs_t *) ((char *)
36498 + (uint32_t *) ((char *)global_regs +
36501 + if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */
36502 + /* Save current interrupt mask */
36505 + (&global_regs->gintmsk);
36507 + /* Disable all interrupts while we muck with
36508 + * the hardware directly
36510 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36512 + /* 15 second delay per the test spec */
36513 + dwc_mdelay(15000);
36515 + /* Drive suspend on the root port */
36517 + dwc_otg_read_hprt0(core_if);
36518 + hprt0.b.prtsusp = 1;
36519 + hprt0.b.prtres = 0;
36520 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36522 + /* 15 second delay per the test spec */
36523 + dwc_mdelay(15000);
36525 + /* Drive resume on the root port */
36527 + dwc_otg_read_hprt0(core_if);
36528 + hprt0.b.prtsusp = 0;
36529 + hprt0.b.prtres = 1;
36530 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36533 + /* Clear the resume bit */
36534 + hprt0.b.prtres = 0;
36535 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36537 + /* Restore interrupts */
36538 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36539 + } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
36540 + /* Save current interrupt mask */
36543 + (&global_regs->gintmsk);
36545 + /* Disable all interrupts while we muck with
36546 + * the hardware directly
36548 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36550 + /* 15 second delay per the test spec */
36551 + dwc_mdelay(15000);
36553 + /* Send the Setup packet */
36556 + /* 15 second delay so nothing else happens for awhile */
36557 + dwc_mdelay(15000);
36559 + /* Restore interrupts */
36560 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36561 + } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
36562 + /* Save current interrupt mask */
36565 + (&global_regs->gintmsk);
36567 + /* Disable all interrupts while we muck with
36568 + * the hardware directly
36570 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36572 + /* Send the Setup packet */
36575 + /* 15 second delay so nothing else happens for awhile */
36576 + dwc_mdelay(15000);
36578 + /* Send the In and Ack packets */
36581 + /* 15 second delay so nothing else happens for awhile */
36582 + dwc_mdelay(15000);
36584 + /* Restore interrupts */
36585 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36590 +#endif /* DWC_HS_ELECT_TST */
36592 + case UHF_PORT_INDICATOR:
36593 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36594 + "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
36595 + /* Not supported */
36598 + retval = -DWC_E_INVALID;
36599 + DWC_ERROR("DWC OTG HCD - "
36600 + "SetPortFeature request %xh "
36601 + "unknown or unsupported\n", wValue);
36605 +#ifdef CONFIG_USB_DWC_OTG_LPM
36606 + case UCR_SET_AND_TEST_PORT_FEATURE:
36607 + if (wValue != UHF_PORT_L1) {
36611 + int portnum, hird, devaddr, remwake;
36612 + glpmcfg_data_t lpmcfg;
36613 + uint32_t time_usecs;
36614 + gintsts_data_t gintsts;
36615 + gintmsk_data_t gintmsk;
36617 + if (!dwc_otg_get_param_lpm_enable(core_if)) {
36620 + if (wValue != UHF_PORT_L1 || wLength != 1) {
36623 + /* Check if the port currently is in SLEEP state */
36625 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36626 + if (lpmcfg.b.prt_sleep_sts) {
36627 + DWC_INFO("Port is already in sleep mode\n");
36628 + buf[0] = 0; /* Return success */
36632 + portnum = wIndex & 0xf;
36633 + hird = (wIndex >> 4) & 0xf;
36634 + devaddr = (wIndex >> 8) & 0x7f;
36635 + remwake = (wIndex >> 15);
36637 + if (portnum != 1) {
36638 + retval = -DWC_E_INVALID;
36640 + ("Wrong port number(%d) in SetandTestPortFeature request\n",
36646 + ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
36647 + portnum, hird, devaddr, remwake);
36648 + /* Disable LPM interrupt */
36650 + gintmsk.b.lpmtranrcvd = 1;
36651 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
36654 + if (dwc_otg_hcd_send_lpm
36655 + (dwc_otg_hcd, devaddr, hird, remwake)) {
36656 + retval = -DWC_E_INVALID;
36660 + time_usecs = 10 * (lpmcfg.b.retry_count + 1);
36661 + /* We will consider timeout if time_usecs microseconds pass,
36662 + * and we don't receive LPM transaction status.
36663 + * After receiving non-error responce(ACK/NYET/STALL) from device,
36664 + * core will set lpmtranrcvd bit.
36668 + DWC_READ_REG32(&core_if->core_global_regs->gintsts);
36669 + if (gintsts.b.lpmtranrcvd) {
36673 + } while (--time_usecs);
36674 + /* lpm_int bit will be cleared in LPM interrupt handler */
36676 + /* Now fill status
36681 + if (!gintsts.b.lpmtranrcvd) {
36682 + buf[0] = 0x3; /* Completion code is Timeout */
36683 + dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
36686 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36687 + if (lpmcfg.b.lpm_resp == 0x3) {
36688 + /* ACK responce from the device */
36689 + buf[0] = 0x00; /* Success */
36690 + } else if (lpmcfg.b.lpm_resp == 0x2) {
36691 + /* NYET responce from the device */
36694 + /* Otherwise responce with Timeout */
36698 + DWC_PRINTF("Device responce to LPM trans is %x\n",
36699 + lpmcfg.b.lpm_resp);
36700 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0,
36705 +#endif /* CONFIG_USB_DWC_OTG_LPM */
36708 + retval = -DWC_E_INVALID;
36709 + DWC_WARN("DWC OTG HCD - "
36710 + "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
36711 + typeReq, wIndex, wValue);
36718 +#ifdef CONFIG_USB_DWC_OTG_LPM
36719 +/** Returns index of host channel to perform LPM transaction. */
36720 +int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
36722 + dwc_otg_core_if_t *core_if = hcd->core_if;
36724 + hcchar_data_t hcchar;
36725 + gintmsk_data_t gintmsk = {.d32 = 0 };
36727 + if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
36728 + DWC_PRINTF("No free channel to select for LPM transaction\n");
36732 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
36734 + /* Mask host channel interrupts. */
36735 + gintmsk.b.hcintr = 1;
36736 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
36738 + /* Fill fields that core needs for LPM transaction */
36739 + hcchar.b.devaddr = devaddr;
36740 + hcchar.b.epnum = 0;
36741 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
36742 + hcchar.b.mps = 64;
36743 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
36744 + hcchar.b.epdir = 0; /* OUT */
36745 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
36748 + /* Remove the host channel from the free list. */
36749 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
36751 + DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
36753 + return hc->hc_num;
36756 +/** Release hc after performing LPM transaction */
36757 +void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
36760 + glpmcfg_data_t lpmcfg;
36763 + lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
36764 + hc_num = lpmcfg.b.lpm_chan_index;
36766 + hc = hcd->hc_ptr_array[hc_num];
36768 + DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
36769 + /* Return host channel to free list */
36770 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
36773 +int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
36774 + uint8_t bRemoteWake)
36776 + glpmcfg_data_t lpmcfg;
36777 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36780 + channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
36781 + if (channel < 0) {
36785 + pcgcctl.b.enbl_sleep_gating = 1;
36786 + DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
36788 + /* Read LPM config register */
36789 + lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
36791 + /* Program LPM transaction fields */
36792 + lpmcfg.b.rem_wkup_en = bRemoteWake;
36793 + lpmcfg.b.hird = hird;
36794 + lpmcfg.b.hird_thres = 0x1c;
36795 + lpmcfg.b.lpm_chan_index = channel;
36796 + lpmcfg.b.en_utmi_sleep = 1;
36797 + /* Program LPM config register */
36798 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
36800 + /* Send LPM transaction */
36801 + lpmcfg.b.send_lpm = 1;
36802 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
36807 +#endif /* CONFIG_USB_DWC_OTG_LPM */
36809 +int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
36814 + return -DWC_E_INVALID;
36817 + retval = (hcd->flags.b.port_connect_status_change ||
36818 + hcd->flags.b.port_reset_change ||
36819 + hcd->flags.b.port_enable_change ||
36820 + hcd->flags.b.port_suspend_change ||
36821 + hcd->flags.b.port_over_current_change);
36824 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
36825 + " Root port status changed\n");
36826 + DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n",
36827 + hcd->flags.b.port_connect_status_change);
36828 + DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n",
36829 + hcd->flags.b.port_reset_change);
36830 + DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n",
36831 + hcd->flags.b.port_enable_change);
36832 + DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n",
36833 + hcd->flags.b.port_suspend_change);
36834 + DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n",
36835 + hcd->flags.b.port_over_current_change);
36841 +int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
36843 + hfnum_data_t hfnum;
36845 + DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
36849 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
36852 + return hfnum.b.frnum;
36855 +int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
36856 + struct dwc_otg_hcd_function_ops *fops)
36860 + hcd->fops = fops;
36861 + if (!dwc_otg_is_device_mode(hcd->core_if) &&
36862 + (!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) {
36863 + dwc_otg_hcd_reinit(hcd);
36865 + retval = -DWC_E_NO_DEVICE;
36871 +void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
36873 + return hcd->priv;
36876 +void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
36878 + hcd->priv = priv_data;
36881 +uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
36883 + return hcd->otg_port;
36886 +uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
36888 + uint32_t is_b_host;
36889 + if (hcd->core_if->op_state == B_HOST) {
36895 + return is_b_host;
36898 +dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
36899 + int iso_desc_count, int atomic_alloc)
36901 + dwc_otg_hcd_urb_t *dwc_otg_urb;
36905 + sizeof(*dwc_otg_urb) +
36906 + iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
36907 + if (atomic_alloc)
36908 + dwc_otg_urb = DWC_ALLOC_ATOMIC(size);
36910 + dwc_otg_urb = DWC_ALLOC(size);
36912 + if (NULL != dwc_otg_urb)
36913 + dwc_otg_urb->packet_count = iso_desc_count;
36915 + dwc_otg_urb->packet_count = 0;
36917 + DWC_ERROR("**** DWC OTG HCD URB alloc - "
36918 + "%salloc of %db failed\n",
36919 + atomic_alloc?"atomic ":"", size);
36923 + return dwc_otg_urb;
36926 +void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
36927 + uint8_t dev_addr, uint8_t ep_num,
36928 + uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
36930 + dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
36931 + ep_type, ep_dir, mps);
36934 + ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
36935 + dev_addr, ep_num, ep_dir, ep_type, mps);
36939 +void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
36940 + void *urb_handle, void *buf, dwc_dma_t dma,
36941 + uint32_t buflen, void *setup_packet,
36942 + dwc_dma_t setup_dma, uint32_t flags,
36943 + uint16_t interval)
36945 + dwc_otg_urb->priv = urb_handle;
36946 + dwc_otg_urb->buf = buf;
36947 + dwc_otg_urb->dma = dma;
36948 + dwc_otg_urb->length = buflen;
36949 + dwc_otg_urb->setup_packet = setup_packet;
36950 + dwc_otg_urb->setup_dma = setup_dma;
36951 + dwc_otg_urb->flags = flags;
36952 + dwc_otg_urb->interval = interval;
36953 + dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
36956 +uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
36958 + return dwc_otg_urb->status;
36961 +uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
36963 + return dwc_otg_urb->actual_length;
36966 +uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
36968 + return dwc_otg_urb->error_count;
36971 +void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
36972 + int desc_num, uint32_t offset,
36975 + dwc_otg_urb->iso_descs[desc_num].offset = offset;
36976 + dwc_otg_urb->iso_descs[desc_num].length = length;
36979 +uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
36982 + return dwc_otg_urb->iso_descs[desc_num].status;
36985 +uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
36986 + dwc_otg_urb, int desc_num)
36988 + return dwc_otg_urb->iso_descs[desc_num].actual_length;
36991 +int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
36993 + int allocated = 0;
36994 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
36997 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
37001 + return allocated;
37004 +int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
37006 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
37008 + DWC_ASSERT(qh, "qh is not allocated\n");
37010 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
37017 +uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
37019 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
37020 + DWC_ASSERT(qh, "qh is not allocated\n");
37021 + return qh->usecs;
37024 +void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
37027 + int num_channels;
37029 + gnptxsts_data_t np_tx_status;
37030 + hptxsts_data_t p_tx_status;
37032 + num_channels = hcd->core_if->core_params->host_channels;
37033 + DWC_PRINTF("\n");
37035 + ("************************************************************\n");
37036 + DWC_PRINTF("HCD State:\n");
37037 + DWC_PRINTF(" Num channels: %d\n", num_channels);
37038 + for (i = 0; i < num_channels; i++) {
37039 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
37040 + DWC_PRINTF(" Channel %d:\n", i);
37041 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
37042 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
37043 + DWC_PRINTF(" speed: %d\n", hc->speed);
37044 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
37045 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
37046 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
37047 + DWC_PRINTF(" multi_count: %d\n", hc->multi_count);
37048 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
37049 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
37050 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
37051 + DWC_PRINTF(" xfer_count: %d\n", hc->xfer_count);
37052 + DWC_PRINTF(" halt_on_queue: %d\n", hc->halt_on_queue);
37053 + DWC_PRINTF(" halt_pending: %d\n", hc->halt_pending);
37054 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
37055 + DWC_PRINTF(" do_split: %d\n", hc->do_split);
37056 + DWC_PRINTF(" complete_split: %d\n", hc->complete_split);
37057 + DWC_PRINTF(" hub_addr: %d\n", hc->hub_addr);
37058 + DWC_PRINTF(" port_addr: %d\n", hc->port_addr);
37059 + DWC_PRINTF(" xact_pos: %d\n", hc->xact_pos);
37060 + DWC_PRINTF(" requests: %d\n", hc->requests);
37061 + DWC_PRINTF(" qh: %p\n", hc->qh);
37062 + if (hc->xfer_started) {
37063 + hfnum_data_t hfnum;
37064 + hcchar_data_t hcchar;
37065 + hctsiz_data_t hctsiz;
37066 + hcint_data_t hcint;
37067 + hcintmsk_data_t hcintmsk;
37069 + DWC_READ_REG32(&hcd->core_if->
37070 + host_if->host_global_regs->hfnum);
37072 + DWC_READ_REG32(&hcd->core_if->host_if->
37073 + hc_regs[i]->hcchar);
37075 + DWC_READ_REG32(&hcd->core_if->host_if->
37076 + hc_regs[i]->hctsiz);
37078 + DWC_READ_REG32(&hcd->core_if->host_if->
37079 + hc_regs[i]->hcint);
37081 + DWC_READ_REG32(&hcd->core_if->host_if->
37082 + hc_regs[i]->hcintmsk);
37083 + DWC_PRINTF(" hfnum: 0x%08x\n", hfnum.d32);
37084 + DWC_PRINTF(" hcchar: 0x%08x\n", hcchar.d32);
37085 + DWC_PRINTF(" hctsiz: 0x%08x\n", hctsiz.d32);
37086 + DWC_PRINTF(" hcint: 0x%08x\n", hcint.d32);
37087 + DWC_PRINTF(" hcintmsk: 0x%08x\n", hcintmsk.d32);
37089 + if (hc->xfer_started && hc->qh) {
37090 + dwc_otg_qtd_t *qtd;
37091 + dwc_otg_hcd_urb_t *urb;
37093 + DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
37094 + if (!qtd->in_process)
37098 + DWC_PRINTF(" URB Info:\n");
37099 + DWC_PRINTF(" qtd: %p, urb: %p\n", qtd, urb);
37101 + DWC_PRINTF(" Dev: %d, EP: %d %s\n",
37102 + dwc_otg_hcd_get_dev_addr(&urb->
37104 + dwc_otg_hcd_get_ep_num(&urb->
37106 + dwc_otg_hcd_is_pipe_in(&urb->
37109 + DWC_PRINTF(" Max packet size: %d\n",
37110 + dwc_otg_hcd_get_mps(&urb->
37112 + DWC_PRINTF(" transfer_buffer: %p\n",
37114 + DWC_PRINTF(" transfer_dma: %p\n",
37115 + (void *)urb->dma);
37116 + DWC_PRINTF(" transfer_buffer_length: %d\n",
37118 + DWC_PRINTF(" actual_length: %d\n",
37119 + urb->actual_length);
37124 + DWC_PRINTF(" non_periodic_channels: %d\n", hcd->non_periodic_channels);
37125 + DWC_PRINTF(" periodic_channels: %d\n", hcd->periodic_channels);
37126 + DWC_PRINTF(" periodic_usecs: %d\n", hcd->periodic_usecs);
37127 + np_tx_status.d32 =
37128 + DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts);
37129 + DWC_PRINTF(" NP Tx Req Queue Space Avail: %d\n",
37130 + np_tx_status.b.nptxqspcavail);
37131 + DWC_PRINTF(" NP Tx FIFO Space Avail: %d\n",
37132 + np_tx_status.b.nptxfspcavail);
37133 + p_tx_status.d32 =
37134 + DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts);
37135 + DWC_PRINTF(" P Tx Req Queue Space Avail: %d\n",
37136 + p_tx_status.b.ptxqspcavail);
37137 + DWC_PRINTF(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
37138 + dwc_otg_hcd_dump_frrem(hcd);
37139 + dwc_otg_dump_global_registers(hcd->core_if);
37140 + dwc_otg_dump_host_registers(hcd->core_if);
37142 + ("************************************************************\n");
37143 + DWC_PRINTF("\n");
37148 +void dwc_print_setup_data(uint8_t * setup)
37151 + if (CHK_DEBUG_LEVEL(DBG_HCD)) {
37152 + DWC_PRINTF("Setup Data = MSB ");
37153 + for (i = 7; i >= 0; i--)
37154 + DWC_PRINTF("%02x ", setup[i]);
37155 + DWC_PRINTF("\n");
37156 + DWC_PRINTF(" bmRequestType Tranfer = %s\n",
37157 + (setup[0] & 0x80) ? "Device-to-Host" :
37158 + "Host-to-Device");
37159 + DWC_PRINTF(" bmRequestType Type = ");
37160 + switch ((setup[0] & 0x60) >> 5) {
37162 + DWC_PRINTF("Standard\n");
37165 + DWC_PRINTF("Class\n");
37168 + DWC_PRINTF("Vendor\n");
37171 + DWC_PRINTF("Reserved\n");
37174 + DWC_PRINTF(" bmRequestType Recipient = ");
37175 + switch (setup[0] & 0x1f) {
37177 + DWC_PRINTF("Device\n");
37180 + DWC_PRINTF("Interface\n");
37183 + DWC_PRINTF("Endpoint\n");
37186 + DWC_PRINTF("Other\n");
37189 + DWC_PRINTF("Reserved\n");
37192 + DWC_PRINTF(" bRequest = 0x%0x\n", setup[1]);
37193 + DWC_PRINTF(" wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
37194 + DWC_PRINTF(" wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
37195 + DWC_PRINTF(" wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
37200 +void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
37203 + DWC_PRINTF("Frame remaining at SOF:\n");
37204 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37205 + hcd->frrem_samples, hcd->frrem_accum,
37206 + (hcd->frrem_samples > 0) ?
37207 + hcd->frrem_accum / hcd->frrem_samples : 0);
37209 + DWC_PRINTF("\n");
37210 + DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
37211 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37212 + hcd->core_if->hfnum_7_samples,
37213 + hcd->core_if->hfnum_7_frrem_accum,
37214 + (hcd->core_if->hfnum_7_samples >
37215 + 0) ? hcd->core_if->hfnum_7_frrem_accum /
37216 + hcd->core_if->hfnum_7_samples : 0);
37217 + DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
37218 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37219 + hcd->core_if->hfnum_0_samples,
37220 + hcd->core_if->hfnum_0_frrem_accum,
37221 + (hcd->core_if->hfnum_0_samples >
37222 + 0) ? hcd->core_if->hfnum_0_frrem_accum /
37223 + hcd->core_if->hfnum_0_samples : 0);
37224 + DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
37225 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37226 + hcd->core_if->hfnum_other_samples,
37227 + hcd->core_if->hfnum_other_frrem_accum,
37228 + (hcd->core_if->hfnum_other_samples >
37229 + 0) ? hcd->core_if->hfnum_other_frrem_accum /
37230 + hcd->core_if->hfnum_other_samples : 0);
37232 + DWC_PRINTF("\n");
37233 + DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
37234 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37235 + hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
37236 + (hcd->hfnum_7_samples_a > 0) ?
37237 + hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
37238 + DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
37239 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37240 + hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
37241 + (hcd->hfnum_0_samples_a > 0) ?
37242 + hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
37243 + DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
37244 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37245 + hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
37246 + (hcd->hfnum_other_samples_a > 0) ?
37247 + hcd->hfnum_other_frrem_accum_a /
37248 + hcd->hfnum_other_samples_a : 0);
37250 + DWC_PRINTF("\n");
37251 + DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
37252 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37253 + hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
37254 + (hcd->hfnum_7_samples_b > 0) ?
37255 + hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
37256 + DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
37257 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37258 + hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
37259 + (hcd->hfnum_0_samples_b > 0) ?
37260 + hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
37261 + DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
37262 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37263 + hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
37264 + (hcd->hfnum_other_samples_b > 0) ?
37265 + hcd->hfnum_other_frrem_accum_b /
37266 + hcd->hfnum_other_samples_b : 0);
37270 +#endif /* DWC_DEVICE_ONLY */
37272 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
37274 +/* ==========================================================================
37275 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $
37276 + * $Revision: #58 $
37277 + * $Date: 2011/09/15 $
37278 + * $Change: 1846647 $
37280 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
37281 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
37282 + * otherwise expressly agreed to in writing between Synopsys and you.
37284 + * The Software IS NOT an item of Licensed Software or Licensed Product under
37285 + * any End User Software License Agreement or Agreement for Licensed Product
37286 + * with Synopsys or any supplement thereto. You are permitted to use and
37287 + * redistribute this Software in source and binary forms, with or without
37288 + * modification, provided that redistributions of source code must retain this
37289 + * notice. You may not view, use, disclose, copy or distribute this file or
37290 + * any information contained herein except pursuant to this license grant from
37291 + * Synopsys. If you do not agree with this notice, including the disclaimer
37292 + * below, then you are not authorized to use the Software.
37294 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
37295 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37296 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37297 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
37298 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37299 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37300 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37301 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37302 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37303 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
37305 + * ========================================================================== */
37306 +#ifndef DWC_DEVICE_ONLY
37307 +#ifndef __DWC_HCD_H__
37308 +#define __DWC_HCD_H__
37310 +#include "dwc_otg_os_dep.h"
37312 +#include "dwc_otg_hcd_if.h"
37313 +#include "dwc_otg_core_if.h"
37314 +#include "dwc_list.h"
37315 +#include "dwc_otg_cil.h"
37320 + * This file contains the structures, constants, and interfaces for
37321 + * the Host Contoller Driver (HCD).
37323 + * The Host Controller Driver (HCD) is responsible for translating requests
37324 + * from the USB Driver into the appropriate actions on the DWC_otg controller.
37325 + * It isolates the USBD from the specifics of the controller by providing an
37326 + * API to the USBD.
37329 +struct dwc_otg_hcd_pipe_info {
37330 + uint8_t dev_addr;
37332 + uint8_t pipe_type;
37333 + uint8_t pipe_dir;
37337 +struct dwc_otg_hcd_iso_packet_desc {
37340 + uint32_t actual_length;
37344 +struct dwc_otg_qtd;
37346 +struct dwc_otg_hcd_urb {
37348 + struct dwc_otg_qtd *qtd;
37351 + void *setup_packet;
37352 + dwc_dma_t setup_dma;
37354 + uint32_t actual_length;
37356 + uint32_t error_count;
37357 + uint32_t packet_count;
37359 + uint16_t interval;
37360 + struct dwc_otg_hcd_pipe_info pipe_info;
37361 + struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
37364 +static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
37366 + return pipe->ep_num;
37369 +static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info
37372 + return pipe->pipe_type;
37375 +static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe)
37377 + return pipe->mps;
37380 +static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info
37383 + return pipe->dev_addr;
37386 +static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info
37389 + return (pipe->pipe_type == UE_ISOCHRONOUS);
37392 +static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info
37395 + return (pipe->pipe_type == UE_INTERRUPT);
37398 +static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info
37401 + return (pipe->pipe_type == UE_BULK);
37404 +static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info
37407 + return (pipe->pipe_type == UE_CONTROL);
37410 +static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe)
37412 + return (pipe->pipe_dir == UE_DIR_IN);
37415 +static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info
37418 + return (!dwc_otg_hcd_is_pipe_in(pipe));
37421 +static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe,
37422 + uint8_t devaddr, uint8_t ep_num,
37423 + uint8_t pipe_type, uint8_t pipe_dir,
37426 + pipe->dev_addr = devaddr;
37427 + pipe->ep_num = ep_num;
37428 + pipe->pipe_type = pipe_type;
37429 + pipe->pipe_dir = pipe_dir;
37434 + * Phases for control transfers.
37436 +typedef enum dwc_otg_control_phase {
37437 + DWC_OTG_CONTROL_SETUP,
37438 + DWC_OTG_CONTROL_DATA,
37439 + DWC_OTG_CONTROL_STATUS
37440 +} dwc_otg_control_phase_e;
37442 +/** Transaction types. */
37443 +typedef enum dwc_otg_transaction_type {
37444 + DWC_OTG_TRANSACTION_NONE,
37445 + DWC_OTG_TRANSACTION_PERIODIC,
37446 + DWC_OTG_TRANSACTION_NON_PERIODIC,
37447 + DWC_OTG_TRANSACTION_ALL
37448 +} dwc_otg_transaction_type_e;
37450 +struct dwc_otg_qh;
37453 + * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
37454 + * interrupt, or isochronous transfer. A single QTD is created for each URB
37455 + * (of one of these types) submitted to the HCD. The transfer associated with
37456 + * a QTD may require one or multiple transactions.
37458 + * A QTD is linked to a Queue Head, which is entered in either the
37459 + * non-periodic or periodic schedule for execution. When a QTD is chosen for
37460 + * execution, some or all of its transactions may be executed. After
37461 + * execution, the state of the QTD is updated. The QTD may be retired if all
37462 + * its transactions are complete or if an error occurred. Otherwise, it
37463 + * remains in the schedule so more transactions can be executed later.
37465 +typedef struct dwc_otg_qtd {
37467 + * Determines the PID of the next data packet for the data phase of
37468 + * control transfers. Ignored for other transfer types.<br>
37469 + * One of the following values:
37470 + * - DWC_OTG_HC_PID_DATA0
37471 + * - DWC_OTG_HC_PID_DATA1
37473 + uint8_t data_toggle;
37475 + /** Current phase for control transfers (Setup, Data, or Status). */
37476 + dwc_otg_control_phase_e control_phase;
37478 + /** Keep track of the current split type
37479 + * for FS/LS endpoints on a HS Hub */
37480 + uint8_t complete_split;
37482 + /** How many bytes transferred during SSPLIT OUT */
37483 + uint32_t ssplit_out_xfer_count;
37486 + * Holds the number of bus errors that have occurred for a transaction
37487 + * within this transfer.
37489 + uint8_t error_count;
37492 + * Index of the next frame descriptor for an isochronous transfer. A
37493 + * frame descriptor describes the buffer position and length of the
37494 + * data to be transferred in the next scheduled (micro)frame of an
37495 + * isochronous transfer. It also holds status for that transaction.
37496 + * The frame index starts at 0.
37498 + uint16_t isoc_frame_index;
37500 + /** Position of the ISOC split on full/low speed */
37501 + uint8_t isoc_split_pos;
37503 + /** Position of the ISOC split in the buffer for the current frame */
37504 + uint16_t isoc_split_offset;
37506 + /** URB for this transfer */
37507 + struct dwc_otg_hcd_urb *urb;
37509 + struct dwc_otg_qh *qh;
37511 + /** This list of QTDs */
37512 + DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry;
37514 + /** Indicates if this QTD is currently processed by HW. */
37515 + uint8_t in_process;
37517 + /** Number of DMA descriptors for this QTD */
37521 + * Last activated frame(packet) index.
37522 + * Used in Descriptor DMA mode only.
37524 + uint16_t isoc_frame_index_last;
37528 +DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd);
37531 + * A Queue Head (QH) holds the static characteristics of an endpoint and
37532 + * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
37533 + * be entered in either the non-periodic or periodic schedule.
37535 +typedef struct dwc_otg_qh {
37538 + * One of the following values:
37542 + * - UE_ISOCHRONOUS
37545 + uint8_t ep_is_in;
37547 + /** wMaxPacketSize Field of Endpoint Descriptor. */
37552 + * One of the following values:
37553 + * - DWC_OTG_EP_SPEED_LOW
37554 + * - DWC_OTG_EP_SPEED_FULL
37555 + * - DWC_OTG_EP_SPEED_HIGH
37557 + uint8_t dev_speed;
37560 + * Determines the PID of the next data packet for non-control
37561 + * transfers. Ignored for control transfers.<br>
37562 + * One of the following values:
37563 + * - DWC_OTG_HC_PID_DATA0
37564 + * - DWC_OTG_HC_PID_DATA1
37566 + uint8_t data_toggle;
37568 + /** Ping state if 1. */
37569 + uint8_t ping_state;
37572 + * List of QTDs for this QH.
37574 + struct dwc_otg_qtd_list qtd_list;
37576 + /** Host channel currently processing transfers for this QH. */
37577 + struct dwc_hc *channel;
37579 + /** Full/low speed endpoint on high-speed hub requires split. */
37580 + uint8_t do_split;
37582 + /** @name Periodic schedule information */
37585 + /** Bandwidth in microseconds per (micro)frame. */
37588 + /** Interval between transfers in (micro)frames. */
37589 + uint16_t interval;
37592 + * (micro)frame to initialize a periodic transfer. The transfer
37593 + * executes in the following (micro)frame.
37595 + uint16_t sched_frame;
37597 + /** (micro)frame at which last start split was initialized. */
37598 + uint16_t start_split_frame;
37603 + * Used instead of original buffer if
37604 + * it(physical address) is not dword-aligned.
37606 + uint8_t *dw_align_buf;
37607 + dwc_dma_t dw_align_buf_dma;
37609 + /** Entry for QH in either the periodic or non-periodic schedule. */
37610 + dwc_list_link_t qh_list_entry;
37612 + /** @name Descriptor DMA support */
37615 + /** Descriptor List. */
37616 + dwc_otg_host_dma_desc_t *desc_list;
37618 + /** Descriptor List physical address. */
37619 + dwc_dma_t desc_list_dma;
37622 + * Xfer Bytes array.
37623 + * Each element corresponds to a descriptor and indicates
37624 + * original XferSize size value for the descriptor.
37626 + uint32_t *n_bytes;
37628 + /** Actual number of transfer descriptors in a list. */
37631 + /** First activated isochronous transfer descriptor index. */
37632 + uint8_t td_first;
37633 + /** Last activated isochronous transfer descriptor index. */
37640 + uint16_t frame_usecs[8];
37643 +DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
37646 + * This structure holds the state of the HCD, including the non-periodic and
37647 + * periodic schedules.
37649 +struct dwc_otg_hcd {
37650 + /** The DWC otg device pointer */
37651 + struct dwc_otg_device *otg_dev;
37652 + /** DWC OTG Core Interface Layer */
37653 + dwc_otg_core_if_t *core_if;
37655 + /** Function HCD driver callbacks */
37656 + struct dwc_otg_hcd_function_ops *fops;
37658 + /** Internal DWC HCD Flags */
37659 + volatile union dwc_otg_hcd_internal_flags {
37662 + unsigned port_connect_status_change:1;
37663 + unsigned port_connect_status:1;
37664 + unsigned port_reset_change:1;
37665 + unsigned port_enable_change:1;
37666 + unsigned port_suspend_change:1;
37667 + unsigned port_over_current_change:1;
37668 + unsigned port_l1_change:1;
37669 + unsigned reserved:26;
37674 + * Inactive items in the non-periodic schedule. This is a list of
37675 + * Queue Heads. Transfers associated with these Queue Heads are not
37676 + * currently assigned to a host channel.
37678 + dwc_list_link_t non_periodic_sched_inactive;
37681 + * Active items in the non-periodic schedule. This is a list of
37682 + * Queue Heads. Transfers associated with these Queue Heads are
37683 + * currently assigned to a host channel.
37685 + dwc_list_link_t non_periodic_sched_active;
37688 + * Pointer to the next Queue Head to process in the active
37689 + * non-periodic schedule.
37691 + dwc_list_link_t *non_periodic_qh_ptr;
37694 + * Inactive items in the periodic schedule. This is a list of QHs for
37695 + * periodic transfers that are _not_ scheduled for the next frame.
37696 + * Each QH in the list has an interval counter that determines when it
37697 + * needs to be scheduled for execution. This scheduling mechanism
37698 + * allows only a simple calculation for periodic bandwidth used (i.e.
37699 + * must assume that all periodic transfers may need to execute in the
37700 + * same frame). However, it greatly simplifies scheduling and should
37701 + * be sufficient for the vast majority of OTG hosts, which need to
37702 + * connect to a small number of peripherals at one time.
37704 + * Items move from this list to periodic_sched_ready when the QH
37705 + * interval counter is 0 at SOF.
37707 + dwc_list_link_t periodic_sched_inactive;
37710 + * List of periodic QHs that are ready for execution in the next
37711 + * frame, but have not yet been assigned to host channels.
37713 + * Items move from this list to periodic_sched_assigned as host
37714 + * channels become available during the current frame.
37716 + dwc_list_link_t periodic_sched_ready;
37719 + * List of periodic QHs to be executed in the next frame that are
37720 + * assigned to host channels.
37722 + * Items move from this list to periodic_sched_queued as the
37723 + * transactions for the QH are queued to the DWC_otg controller.
37725 + dwc_list_link_t periodic_sched_assigned;
37728 + * List of periodic QHs that have been queued for execution.
37730 + * Items move from this list to either periodic_sched_inactive or
37731 + * periodic_sched_ready when the channel associated with the transfer
37732 + * is released. If the interval for the QH is 1, the item moves to
37733 + * periodic_sched_ready because it must be rescheduled for the next
37734 + * frame. Otherwise, the item moves to periodic_sched_inactive.
37736 + dwc_list_link_t periodic_sched_queued;
37739 + * Total bandwidth claimed so far for periodic transfers. This value
37740 + * is in microseconds per (micro)frame. The assumption is that all
37741 + * periodic transfers may occur in the same (micro)frame.
37743 + uint16_t periodic_usecs;
37746 + * Total bandwidth claimed so far for all periodic transfers
37748 + * This will include a mixture of HS and FS transfers.
37749 + * Units are microseconds per (micro)frame.
37750 + * We have a budget per frame and have to schedule
37751 + * transactions accordingly.
37752 + * Watch out for the fact that things are actually scheduled for the
37755 + uint16_t frame_usecs[8];
37759 + * Frame number read from the core at SOF. The value ranges from 0 to
37760 + * DWC_HFNUM_MAX_FRNUM.
37762 + uint16_t frame_number;
37765 + * Count of periodic QHs, if using several eps. For SOF enable/disable.
37767 + uint16_t periodic_qh_count;
37770 + * Free host channels in the controller. This is a list of
37771 + * dwc_hc_t items.
37773 + struct hc_list free_hc_list;
37775 + * Number of host channels assigned to periodic transfers. Currently
37776 + * assuming that there is a dedicated host channel for each periodic
37777 + * transaction and at least one host channel available for
37778 + * non-periodic transactions.
37780 + int periodic_channels; /* microframe_schedule==0 */
37783 + * Number of host channels assigned to non-periodic transfers.
37785 + int non_periodic_channels; /* microframe_schedule==0 */
37788 + * Number of host channels assigned to non-periodic transfers.
37790 + int available_host_channels;
37793 + * Array of pointers to the host channel descriptors. Allows accessing
37794 + * a host channel descriptor given the host channel number. This is
37795 + * useful in interrupt handlers.
37797 + struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
37800 + * Buffer to use for any data received during the status phase of a
37801 + * control transfer. Normally no data is transferred during the status
37802 + * phase. This buffer is used as a bit bucket.
37804 + uint8_t *status_buf;
37807 + * DMA address for status_buf.
37809 + dma_addr_t status_buf_dma;
37810 +#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
37813 + * Connection timer. An OTG host must display a message if the device
37814 + * does not connect. Started when the VBus power is turned on via
37815 + * sysfs attribute "buspower".
37817 + dwc_timer_t *conn_timer;
37819 + /* Tasket to do a reset */
37820 + dwc_tasklet_t *reset_tasklet;
37823 + dwc_spinlock_t *lock;
37826 + * Private data that could be used by OS wrapper.
37830 + uint8_t otg_port;
37832 + /** Frame List */
37833 + uint32_t *frame_list;
37835 + /** Frame List DMA address */
37836 + dma_addr_t frame_list_dma;
37839 + uint32_t frrem_samples;
37840 + uint64_t frrem_accum;
37842 + uint32_t hfnum_7_samples_a;
37843 + uint64_t hfnum_7_frrem_accum_a;
37844 + uint32_t hfnum_0_samples_a;
37845 + uint64_t hfnum_0_frrem_accum_a;
37846 + uint32_t hfnum_other_samples_a;
37847 + uint64_t hfnum_other_frrem_accum_a;
37849 + uint32_t hfnum_7_samples_b;
37850 + uint64_t hfnum_7_frrem_accum_b;
37851 + uint32_t hfnum_0_samples_b;
37852 + uint64_t hfnum_0_frrem_accum_b;
37853 + uint32_t hfnum_other_samples_b;
37854 + uint64_t hfnum_other_frrem_accum_b;
37858 +/** @name Transaction Execution Functions */
37860 +extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
37862 +extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
37863 + dwc_otg_transaction_type_e tr_type);
37867 +/** @name Interrupt Handler Functions */
37869 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37870 +extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37871 +extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t *
37873 +extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t *
37875 +extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t *
37877 +extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *
37879 +extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37880 +extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t *
37882 +extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37883 +extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37884 +extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd,
37886 +extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd);
37887 +extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t *
37891 +/** @name Schedule Queue Functions */
37894 +/* Implemented in dwc_otg_hcd_queue.c */
37895 +extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
37896 + dwc_otg_hcd_urb_t * urb, int atomic_alloc);
37897 +extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
37898 +extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
37899 +extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
37900 +extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
37901 + int sched_csplit);
37903 +/** Remove and free a QH */
37904 +static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd,
37905 + dwc_otg_qh_t * qh)
37907 + dwc_irqflags_t flags;
37908 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
37909 + dwc_otg_hcd_qh_remove(hcd, qh);
37910 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
37911 + dwc_otg_hcd_qh_free(hcd, qh);
37914 +/** Allocates memory for a QH structure.
37915 + * @return Returns the memory allocate or NULL on error. */
37916 +static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(int atomic_alloc)
37918 + if (atomic_alloc)
37919 + return (dwc_otg_qh_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qh_t));
37921 + return (dwc_otg_qh_t *) DWC_ALLOC(sizeof(dwc_otg_qh_t));
37924 +extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb,
37925 + int atomic_alloc);
37926 +extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb);
37927 +extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd,
37928 + dwc_otg_qh_t ** qh, int atomic_alloc);
37930 +/** Allocates memory for a QTD structure.
37931 + * @return Returns the memory allocate or NULL on error. */
37932 +static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(int atomic_alloc)
37934 + if (atomic_alloc)
37935 + return (dwc_otg_qtd_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qtd_t));
37937 + return (dwc_otg_qtd_t *) DWC_ALLOC(sizeof(dwc_otg_qtd_t));
37940 +/** Frees the memory for a QTD structure. QTD should already be removed from
37942 + * @param qtd QTD to free.*/
37943 +static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd)
37948 +/** Removes a QTD from list.
37949 + * @param hcd HCD instance.
37950 + * @param qtd QTD to remove from list.
37951 + * @param qh QTD belongs to.
37953 +static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd,
37954 + dwc_otg_qtd_t * qtd,
37955 + dwc_otg_qh_t * qh)
37957 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
37960 +/** Remove and free a QTD
37961 + * Need to disable IRQ and hold hcd lock while calling this function out of
37962 + * interrupt servicing chain */
37963 +static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd,
37964 + dwc_otg_qtd_t * qtd,
37965 + dwc_otg_qh_t * qh)
37967 + dwc_otg_hcd_qtd_remove(hcd, qtd, qh);
37968 + dwc_otg_hcd_qtd_free(qtd);
37973 +/** @name Descriptor DMA Supporting Functions */
37976 +extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
37977 +extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
37979 + dwc_otg_hc_regs_t * hc_regs,
37980 + dwc_otg_halt_status_e halt_status);
37982 +extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
37983 +extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
37987 +/** @name Internal Functions */
37989 +dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb);
37992 +#ifdef CONFIG_USB_DWC_OTG_LPM
37993 +extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd,
37994 + uint8_t devaddr);
37995 +extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd);
37998 +/** Gets the QH that contains the list_head */
37999 +#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
38001 +/** Gets the QTD that contains the list_head */
38002 +#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
38004 +/** Check if QH is non-periodic */
38005 +#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \
38006 + (_qh_ptr_->ep_type == UE_CONTROL))
38008 +/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
38009 +#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
38011 +/** Packet size for any kind of endpoint descriptor */
38012 +#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
38015 + * Returns true if _frame1 is less than or equal to _frame2. The comparison is
38016 + * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
38017 + * frame number when the max frame number is reached.
38019 +static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
38021 + return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
38022 + (DWC_HFNUM_MAX_FRNUM >> 1);
38026 + * Returns true if _frame1 is greater than _frame2. The comparison is done
38027 + * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
38028 + * number when the max frame number is reached.
38030 +static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
38032 + return (frame1 != frame2) &&
38033 + (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
38034 + (DWC_HFNUM_MAX_FRNUM >> 1));
38038 + * Increments _frame by the amount specified by _inc. The addition is done
38039 + * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
38041 +static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
38043 + return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
38046 +static inline uint16_t dwc_full_frame_num(uint16_t frame)
38048 + return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
38051 +static inline uint16_t dwc_micro_frame_num(uint16_t frame)
38053 + return frame & 0x7;
38056 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
38057 + dwc_otg_hc_regs_t * hc_regs,
38058 + dwc_otg_qtd_t * qtd);
38062 + * Macro to sample the remaining PHY clocks left in the current frame. This
38063 + * may be used during debugging to determine the average time it takes to
38064 + * execute sections of code. There are two possible sample points, "a" and
38065 + * "b", so the _letter argument must be one of these values.
38067 + * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
38068 + * example, "cat /sys/devices/lm0/hcd_frrem".
38070 +#define dwc_sample_frrem(_hcd, _qh, _letter) \
38072 + hfnum_data_t hfnum; \
38073 + dwc_otg_qtd_t *qtd; \
38074 + qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
38075 + if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
38076 + hfnum.d32 = DWC_READ_REG32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
38077 + switch (hfnum.b.frnum & 0x7) { \
38079 + _hcd->hfnum_7_samples_##_letter++; \
38080 + _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
38083 + _hcd->hfnum_0_samples_##_letter++; \
38084 + _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
38087 + _hcd->hfnum_other_samples_##_letter++; \
38088 + _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
38094 +#define dwc_sample_frrem(_hcd, _qh, _letter)
38097 +#endif /* DWC_DEVICE_ONLY */
38099 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
38101 +/*==========================================================================
38102 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
38103 + * $Revision: #10 $
38104 + * $Date: 2011/10/20 $
38105 + * $Change: 1869464 $
38107 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
38108 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
38109 + * otherwise expressly agreed to in writing between Synopsys and you.
38111 + * The Software IS NOT an item of Licensed Software or Licensed Product under
38112 + * any End User Software License Agreement or Agreement for Licensed Product
38113 + * with Synopsys or any supplement thereto. You are permitted to use and
38114 + * redistribute this Software in source and binary forms, with or without
38115 + * modification, provided that redistributions of source code must retain this
38116 + * notice. You may not view, use, disclose, copy or distribute this file or
38117 + * any information contained herein except pursuant to this license grant from
38118 + * Synopsys. If you do not agree with this notice, including the disclaimer
38119 + * below, then you are not authorized to use the Software.
38121 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
38122 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38123 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38124 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
38125 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38126 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
38127 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38128 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38129 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38130 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38132 + * ========================================================================== */
38133 +#ifndef DWC_DEVICE_ONLY
38136 + * This file contains Descriptor DMA support implementation for host mode.
38139 +#include "dwc_otg_hcd.h"
38140 +#include "dwc_otg_regs.h"
38142 +extern bool microframe_schedule;
38144 +static inline uint8_t frame_list_idx(uint16_t frame)
38146 + return (frame & (MAX_FRLIST_EN_NUM - 1));
38149 +static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
38151 + return (idx + inc) &
38153 + DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
38154 + MAX_DMA_DESC_NUM_GENERIC) - 1);
38157 +static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
38159 + return (idx - inc) &
38161 + DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
38162 + MAX_DMA_DESC_NUM_GENERIC) - 1);
38165 +static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
38167 + return (((qh->ep_type == UE_ISOCHRONOUS)
38168 + && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH))
38169 + ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC);
38171 +static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
38173 + return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)
38174 + ? ((qh->interval + 8 - 1) / 8)
38178 +static int desc_list_alloc(dwc_otg_qh_t * qh)
38182 + qh->desc_list = (dwc_otg_host_dma_desc_t *)
38183 + DWC_DMA_ALLOC(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
38184 + &qh->desc_list_dma);
38186 + if (!qh->desc_list) {
38187 + retval = -DWC_E_NO_MEMORY;
38188 + DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
38192 + dwc_memset(qh->desc_list, 0x00,
38193 + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
38196 + (uint32_t *) DWC_ALLOC(sizeof(uint32_t) * max_desc_num(qh));
38198 + if (!qh->n_bytes) {
38199 + retval = -DWC_E_NO_MEMORY;
38201 + ("%s: Failed to allocate array for descriptors' size actual values\n",
38209 +static void desc_list_free(dwc_otg_qh_t * qh)
38211 + if (qh->desc_list) {
38212 + DWC_DMA_FREE(max_desc_num(qh), qh->desc_list,
38213 + qh->desc_list_dma);
38214 + qh->desc_list = NULL;
38217 + if (qh->n_bytes) {
38218 + DWC_FREE(qh->n_bytes);
38219 + qh->n_bytes = NULL;
38223 +static int frame_list_alloc(dwc_otg_hcd_t * hcd)
38226 + if (hcd->frame_list)
38229 + hcd->frame_list = DWC_DMA_ALLOC(4 * MAX_FRLIST_EN_NUM,
38230 + &hcd->frame_list_dma);
38231 + if (!hcd->frame_list) {
38232 + retval = -DWC_E_NO_MEMORY;
38233 + DWC_ERROR("%s: Frame List allocation failed\n", __func__);
38236 + dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
38241 +static void frame_list_free(dwc_otg_hcd_t * hcd)
38243 + if (!hcd->frame_list)
38246 + DWC_DMA_FREE(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
38247 + hcd->frame_list = NULL;
38250 +static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
38253 + hcfg_data_t hcfg;
38255 + hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
38257 + if (hcfg.b.perschedena) {
38258 + /* already enabled */
38262 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hflbaddr,
38263 + hcd->frame_list_dma);
38265 + switch (fr_list_en) {
38267 + hcfg.b.frlisten = 3;
38270 + hcfg.b.frlisten = 2;
38273 + hcfg.b.frlisten = 1;
38276 + hcfg.b.frlisten = 0;
38282 + hcfg.b.perschedena = 1;
38284 + DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
38285 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
38289 +static void per_sched_disable(dwc_otg_hcd_t * hcd)
38291 + hcfg_data_t hcfg;
38293 + hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
38295 + if (!hcfg.b.perschedena) {
38296 + /* already disabled */
38299 + hcfg.b.perschedena = 0;
38301 + DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
38302 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
38306 + * Activates/Deactivates FrameList entries for the channel
38307 + * based on endpoint servicing period.
38309 +void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
38311 + uint16_t i, j, inc;
38312 + dwc_hc_t *hc = NULL;
38314 + if (!qh->channel) {
38315 + DWC_ERROR("qh->channel = %p", qh->channel);
38320 + DWC_ERROR("------hcd = %p", hcd);
38324 + if (!hcd->frame_list) {
38325 + DWC_ERROR("-------hcd->frame_list = %p", hcd->frame_list);
38329 + hc = qh->channel;
38330 + inc = frame_incr_val(qh);
38331 + if (qh->ep_type == UE_ISOCHRONOUS)
38332 + i = frame_list_idx(qh->sched_frame);
38339 + hcd->frame_list[j] |= (1 << hc->hc_num);
38341 + hcd->frame_list[j] &= ~(1 << hc->hc_num);
38342 + j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
38348 + if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
38350 + /* TODO - check this */
38351 + inc = (8 + qh->interval - 1) / qh->interval;
38352 + for (i = 0; i < inc; i++) {
38353 + hc->schinfo |= j;
38354 + j = j << qh->interval;
38357 + hc->schinfo = 0xff;
38362 +void dump_frame_list(dwc_otg_hcd_t * hcd)
38365 + DWC_PRINTF("--FRAME LIST (hex) --\n");
38366 + for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
38367 + DWC_PRINTF("%x\t", hcd->frame_list[i]);
38368 + if (!(i % 8) && i)
38369 + DWC_PRINTF("\n");
38371 + DWC_PRINTF("\n----\n");
38376 +static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38378 + dwc_irqflags_t flags;
38379 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
38381 + dwc_hc_t *hc = qh->channel;
38382 + if (dwc_qh_is_non_per(qh)) {
38383 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
38384 + if (!microframe_schedule)
38385 + hcd->non_periodic_channels--;
38387 + hcd->available_host_channels++;
38388 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
38390 + update_frame_list(hcd, qh, 0);
38393 + * The condition is added to prevent double cleanup try in case of device
38394 + * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
38397 + dwc_otg_hc_cleanup(hcd->core_if, hc);
38398 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
38402 + qh->channel = NULL;
38405 + if (qh->desc_list) {
38406 + dwc_memset(qh->desc_list, 0x00,
38407 + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
38409 + DWC_SPINLOCK_FREE(channel_lock);
38413 + * Initializes a QH structure's Descriptor DMA related members.
38414 + * Allocates memory for descriptor list.
38415 + * On first periodic QH, allocates memory for FrameList
38416 + * and enables periodic scheduling.
38418 + * @param hcd The HCD state structure for the DWC OTG controller.
38419 + * @param qh The QH to init.
38421 + * @return 0 if successful, negative error code otherwise.
38423 +int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38427 + if (qh->do_split) {
38428 + DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
38432 + retval = desc_list_alloc(qh);
38434 + if ((retval == 0)
38435 + && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
38436 + if (!hcd->frame_list) {
38437 + retval = frame_list_alloc(hcd);
38438 + /* Enable periodic schedule on first periodic QH */
38440 + per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
38450 + * Frees descriptor list memory associated with the QH.
38451 + * If QH is periodic and the last, frees FrameList memory
38452 + * and disables periodic scheduling.
38454 + * @param hcd The HCD state structure for the DWC OTG controller.
38455 + * @param qh The QH to init.
38457 +void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38459 + desc_list_free(qh);
38462 + * Channel still assigned due to some reasons.
38463 + * Seen on Isoc URB dequeue. Channel halted but no subsequent
38464 + * ChHalted interrupt to release the channel. Afterwards
38465 + * when it comes here from endpoint disable routine
38466 + * channel remains assigned.
38469 + release_channel_ddma(hcd, qh);
38471 + if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
38472 + && (microframe_schedule || !hcd->periodic_channels) && hcd->frame_list) {
38474 + per_sched_disable(hcd);
38475 + frame_list_free(hcd);
38479 +static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
38481 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
38483 + * Descriptor set(8 descriptors) index
38484 + * which is 8-aligned.
38486 + return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
38488 + return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
38493 + * Determine starting frame for Isochronous transfer.
38494 + * Few frames skipped to prevent race condition with HC.
38496 +static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
38497 + uint8_t * skip_frames)
38499 + uint16_t frame = 0;
38500 + hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
38502 + /* sched_frame is always frame number(not uFrame) both in FS and HS !! */
38505 + * skip_frames is used to limit activated descriptors number
38506 + * to avoid the situation when HC services the last activated
38507 + * descriptor firstly.
38508 + * Example for FS:
38509 + * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
38510 + * corresponding to curr_frame+1, the descriptor corresponding to frame 2
38511 + * will be fetched. If the number of descriptors is max=64 (or greather) the
38512 + * list will be fully programmed with Active descriptors and it is possible
38513 + * case(rare) that the latest descriptor(considering rollback) corresponding
38514 + * to frame 2 will be serviced first. HS case is more probable because, in fact,
38515 + * up to 11 uframes(16 in the code) may be skipped.
38517 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
38519 + * Consider uframe counter also, to start xfer asap.
38520 + * If half of the frame elapsed skip 2 frames otherwise
38522 + * Starting descriptor index must be 8-aligned, so
38523 + * if the current frame is near to complete the next one
38524 + * is skipped as well.
38527 + if (dwc_micro_frame_num(hcd->frame_number) >= 5) {
38528 + *skip_frames = 2 * 8;
38529 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
38531 + *skip_frames = 1 * 8;
38532 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
38535 + frame = dwc_full_frame_num(frame);
38538 + * Two frames are skipped for FS - the current and the next.
38539 + * But for descriptor programming, 1 frame(descriptor) is enough,
38540 + * see example above.
38542 + *skip_frames = 1;
38543 + frame = dwc_frame_num_inc(hcd->frame_number, 2);
38550 + * Calculate initial descriptor index for isochronous transfer
38551 + * based on scheduled frame.
38553 +static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38555 + uint16_t frame = 0, fr_idx, fr_idx_tmp;
38556 + uint8_t skip_frames = 0;
38558 + * With current ISOC processing algorithm the channel is being
38559 + * released when no more QTDs in the list(qh->ntd == 0).
38560 + * Thus this function is called only when qh->ntd == 0 and qh->channel == 0.
38562 + * So qh->channel != NULL branch is not used and just not removed from the
38563 + * source file. It is required for another possible approach which is,
38564 + * do not disable and release the channel when ISOC session completed,
38565 + * just move QH to inactive schedule until new QTD arrives.
38566 + * On new QTD, the QH moved back to 'ready' schedule,
38567 + * starting frame and therefore starting desc_index are recalculated.
38568 + * In this case channel is released only on ep_disable.
38571 + /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
38572 + if (qh->channel) {
38573 + frame = calc_starting_frame(hcd, qh, &skip_frames);
38575 + * Calculate initial descriptor index based on FrameList current bitmap
38576 + * and servicing period.
38578 + fr_idx_tmp = frame_list_idx(frame);
38580 + (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) -
38582 + % frame_incr_val(qh);
38583 + fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
38585 + qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);
38586 + fr_idx = frame_list_idx(qh->sched_frame);
38589 + qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx);
38591 + return skip_frames;
38594 +#define ISOC_URB_GIVEBACK_ASAP
38596 +#define MAX_ISOC_XFER_SIZE_FS 1023
38597 +#define MAX_ISOC_XFER_SIZE_HS 3072
38598 +#define DESCNUM_THRESHOLD 4
38600 +static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
38601 + uint8_t skip_frames)
38603 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
38604 + dwc_otg_qtd_t *qtd;
38605 + dwc_otg_host_dma_desc_t *dma_desc;
38606 + uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
38608 + idx = qh->td_last;
38609 + inc = qh->interval;
38612 + ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
38613 + if (skip_frames && !qh->channel)
38614 + ntd_max = ntd_max - skip_frames / qh->interval;
38617 + (qh->dev_speed ==
38618 + DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS :
38619 + MAX_ISOC_XFER_SIZE_FS;
38621 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
38622 + while ((qh->ntd < ntd_max)
38623 + && (qtd->isoc_frame_index_last <
38624 + qtd->urb->packet_count)) {
38626 + dma_desc = &qh->desc_list[idx];
38627 + dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
38629 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
38631 + if (frame_desc->length > max_xfer_size)
38632 + qh->n_bytes[idx] = max_xfer_size;
38634 + qh->n_bytes[idx] = frame_desc->length;
38635 + dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
38636 + dma_desc->status.b_isoc.a = 1;
38637 + dma_desc->status.b_isoc.sts = 0;
38639 + dma_desc->buf = qtd->urb->dma + frame_desc->offset;
38643 + qtd->isoc_frame_index_last++;
38645 +#ifdef ISOC_URB_GIVEBACK_ASAP
38647 + * Set IOC for each descriptor corresponding to the
38648 + * last frame of the URB.
38650 + if (qtd->isoc_frame_index_last ==
38651 + qtd->urb->packet_count)
38652 + dma_desc->status.b_isoc.ioc = 1;
38655 + idx = desclist_idx_inc(idx, inc, qh->dev_speed);
38659 + qtd->in_process = 1;
38662 + qh->td_last = idx;
38664 +#ifdef ISOC_URB_GIVEBACK_ASAP
38665 + /* Set IOC for the last descriptor if descriptor list is full */
38666 + if (qh->ntd == ntd_max) {
38667 + idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
38668 + qh->desc_list[idx].status.b_isoc.ioc = 1;
38672 + * Set IOC bit only for one descriptor.
38673 + * Always try to be ahead of HW processing,
38674 + * i.e. on IOC generation driver activates next descriptors but
38675 + * core continues to process descriptors followed the one with IOC set.
38678 + if (n_desc > DESCNUM_THRESHOLD) {
38680 + * Move IOC "up". Required even if there is only one QTD
38681 + * in the list, cause QTDs migth continue to be queued,
38682 + * but during the activation it was only one queued.
38683 + * Actually more than one QTD might be in the list if this function called
38684 + * from XferCompletion - QTDs was queued during HW processing of the previous
38685 + * descriptor chunk.
38687 + idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
38690 + * Set the IOC for the latest descriptor
38691 + * if either number of descriptor is not greather than threshold
38692 + * or no more new descriptors activated.
38694 + idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
38697 + qh->desc_list[idx].status.b_isoc.ioc = 1;
38701 +static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38705 + dwc_otg_host_dma_desc_t *dma_desc;
38706 + dwc_otg_qtd_t *qtd;
38707 + int num_packets, len, n_desc = 0;
38709 + hc = qh->channel;
38712 + * Start with hc->xfer_buff initialized in
38713 + * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
38714 + * this pointer re-assigned to the buffer of the currently processed QTD.
38715 + * For non-SG request there is always one QTD active.
38718 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
38721 + /* SG request - more than 1 QTDs */
38722 + hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
38723 + hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
38729 + dma_desc = &qh->desc_list[n_desc];
38730 + len = hc->xfer_len;
38732 + if (len > MAX_DMA_DESC_SIZE)
38733 + len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
38735 + if (hc->ep_is_in) {
38737 + num_packets = (len + hc->max_packet - 1) / hc->max_packet;
38739 + /* Need 1 packet for transfer length of 0. */
38742 + /* Always program an integral # of max packets for IN transfers. */
38743 + len = num_packets * hc->max_packet;
38746 + dma_desc->status.b.n_bytes = len;
38748 + qh->n_bytes[n_desc] = len;
38750 + if ((qh->ep_type == UE_CONTROL)
38751 + && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
38752 + dma_desc->status.b.sup = 1; /* Setup Packet */
38754 + dma_desc->status.b.a = 1; /* Active descriptor */
38755 + dma_desc->status.b.sts = 0;
38758 + ((unsigned long)hc->xfer_buff & 0xffffffff);
38761 + * Last descriptor(or single) of IN transfer
38762 + * with actual size less than MaxPacket.
38764 + if (len > hc->xfer_len) {
38765 + hc->xfer_len = 0;
38767 + hc->xfer_buff += len;
38768 + hc->xfer_len -= len;
38774 + while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
38777 + qtd->in_process = 1;
38779 + if (qh->ep_type == UE_CONTROL)
38782 + if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
38787 + /* Request Transfer Complete interrupt for the last descriptor */
38788 + qh->desc_list[n_desc - 1].status.b.ioc = 1;
38789 + /* End of List indicator */
38790 + qh->desc_list[n_desc - 1].status.b.eol = 1;
38792 + hc->ntd = n_desc;
38797 + * For Control and Bulk endpoints initializes descriptor list
38798 + * and starts the transfer.
38800 + * For Interrupt and Isochronous endpoints initializes descriptor list
38801 + * then updates FrameList, marking appropriate entries as active.
38802 + * In case of Isochronous, the starting descriptor index is calculated based
38803 + * on the scheduled frame, but only on the first transfer descriptor within a session.
38804 + * Then starts the transfer via enabling the channel.
38805 + * For Isochronous endpoint the channel is not halted on XferComplete
38806 + * interrupt so remains assigned to the endpoint(QH) until session is done.
38808 + * @param hcd The HCD state structure for the DWC OTG controller.
38809 + * @param qh The QH to init.
38811 + * @return 0 if successful, negative error code otherwise.
38813 +void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38815 + /* Channel is already assigned */
38816 + dwc_hc_t *hc = qh->channel;
38817 + uint8_t skip_frames = 0;
38819 + switch (hc->ep_type) {
38820 + case DWC_OTG_EP_TYPE_CONTROL:
38821 + case DWC_OTG_EP_TYPE_BULK:
38822 + init_non_isoc_dma_desc(hcd, qh);
38824 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
38826 + case DWC_OTG_EP_TYPE_INTR:
38827 + init_non_isoc_dma_desc(hcd, qh);
38829 + update_frame_list(hcd, qh, 1);
38831 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
38833 + case DWC_OTG_EP_TYPE_ISOC:
38836 + skip_frames = recalc_initial_desc_idx(hcd, qh);
38838 + init_isoc_dma_desc(hcd, qh, skip_frames);
38840 + if (!hc->xfer_started) {
38842 + update_frame_list(hcd, qh, 1);
38845 + * Always set to max, instead of actual size.
38846 + * Otherwise ntd will be changed with
38847 + * channel being enabled. Not recommended.
38850 + hc->ntd = max_desc_num(qh);
38851 + /* Enable channel only once for ISOC */
38852 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
38862 +static void complete_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
38864 + dwc_otg_hc_regs_t * hc_regs,
38865 + dwc_otg_halt_status_e halt_status)
38867 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
38868 + dwc_otg_qtd_t *qtd, *qtd_tmp;
38869 + dwc_otg_qh_t *qh;
38870 + dwc_otg_host_dma_desc_t *dma_desc;
38871 + uint16_t idx, remain;
38872 + uint8_t urb_compl;
38875 + idx = qh->td_first;
38877 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
38878 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
38879 + qtd->in_process = 0;
38881 + } else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) ||
38882 + (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
38884 + * Channel is halted in these error cases.
38885 + * Considered as serious issues.
38886 + * Complete all URBs marking all frames as failed,
38887 + * irrespective whether some of the descriptors(frames) succeeded or no.
38888 + * Pass error code to completion routine as well, to
38889 + * update urb->status, some of class drivers might use it to stop
38890 + * queing transfer requests.
38892 + int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR)
38894 + : (-DWC_E_OVERFLOW);
38896 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
38897 + for (idx = 0; idx < qtd->urb->packet_count; idx++) {
38898 + frame_desc = &qtd->urb->iso_descs[idx];
38899 + frame_desc->status = err;
38901 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
38902 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
38907 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
38909 + if (!qtd->in_process)
38916 + dma_desc = &qh->desc_list[idx];
38918 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
38919 + remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
38921 + if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
38923 + * XactError or, unable to complete all the transactions
38924 + * in the scheduled micro-frame/frame,
38925 + * both indicated by DMA_DESC_STS_PKTERR.
38927 + qtd->urb->error_count++;
38928 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
38929 + frame_desc->status = -DWC_E_PROTOCOL;
38933 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
38934 + frame_desc->status = 0;
38937 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
38939 + * urb->status is not used for isoc transfers here.
38940 + * The individual frame_desc status are used instead.
38943 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
38944 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
38947 + * This check is necessary because urb_dequeue can be called
38948 + * from urb complete callback(sound driver example).
38949 + * All pending URBs are dequeued there, so no need for
38950 + * further processing.
38952 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
38962 + /* Stop if IOC requested descriptor reached */
38963 + if (dma_desc->status.b_isoc.ioc) {
38964 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
38968 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
38973 + while (idx != qh->td_first);
38976 + qh->td_first = idx;
38979 +uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
38981 + dwc_otg_qtd_t * qtd,
38982 + dwc_otg_host_dma_desc_t * dma_desc,
38983 + dwc_otg_halt_status_e halt_status,
38984 + uint32_t n_bytes, uint8_t * xfer_done)
38987 + uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
38988 + dwc_otg_hcd_urb_t *urb = qtd->urb;
38990 + if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
38991 + urb->status = -DWC_E_IO;
38994 + if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
38995 + switch (halt_status) {
38996 + case DWC_OTG_HC_XFER_STALL:
38997 + urb->status = -DWC_E_PIPE;
38999 + case DWC_OTG_HC_XFER_BABBLE_ERR:
39000 + urb->status = -DWC_E_OVERFLOW;
39002 + case DWC_OTG_HC_XFER_XACT_ERR:
39003 + urb->status = -DWC_E_PROTOCOL;
39006 + DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
39013 + if (dma_desc->status.b.a == 1) {
39014 + DWC_DEBUGPL(DBG_HCDV,
39015 + "Active descriptor encountered on channel %d\n",
39020 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
39021 + if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
39022 + urb->actual_length += n_bytes - remain;
39023 + if (remain || urb->actual_length == urb->length) {
39025 + * For Control Data stage do not set urb->status=0 to prevent
39026 + * URB callback. Set it when Status phase done. See below.
39031 + } else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
39035 + /* No handling for SETUP stage */
39037 + /* BULK and INTR */
39038 + urb->actual_length += n_bytes - remain;
39039 + if (remain || urb->actual_length == urb->length) {
39048 +static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
39050 + dwc_otg_hc_regs_t * hc_regs,
39051 + dwc_otg_halt_status_e halt_status)
39053 + dwc_otg_hcd_urb_t *urb = NULL;
39054 + dwc_otg_qtd_t *qtd, *qtd_tmp;
39055 + dwc_otg_qh_t *qh;
39056 + dwc_otg_host_dma_desc_t *dma_desc;
39057 + uint32_t n_bytes, n_desc, i;
39058 + uint8_t failed = 0, xfer_done;
39064 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
39065 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
39066 + qtd->in_process = 0;
39071 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
39078 + for (i = 0; i < qtd->n_desc; i++) {
39079 + dma_desc = &qh->desc_list[n_desc];
39081 + n_bytes = qh->n_bytes[n_desc];
39084 + update_non_isoc_urb_state_ddma(hcd, hc, qtd,
39086 + halt_status, n_bytes,
39091 + && (urb->status != -DWC_E_IN_PROGRESS))) {
39093 + hcd->fops->complete(hcd, urb->priv, urb,
39095 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
39099 + } else if (qh->ep_type == UE_CONTROL) {
39100 + if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
39101 + if (urb->length > 0) {
39102 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
39104 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
39106 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n");
39107 + } else if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
39109 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
39110 + DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n");
39111 + } else if (i + 1 == qtd->n_desc) {
39113 + * Last descriptor for Control data stage which is
39114 + * not completed yet.
39116 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
39128 + if (qh->ep_type != UE_CONTROL) {
39130 + * Resetting the data toggle for bulk
39131 + * and interrupt endpoints in case of stall. See handle_hc_stall_intr()
39133 + if (halt_status == DWC_OTG_HC_XFER_STALL)
39134 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
39136 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
39139 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
39140 + hcint_data_t hcint;
39141 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
39142 + if (hcint.b.nyet) {
39144 + * Got a NYET on the last transaction of the transfer. It
39145 + * means that the endpoint should be in the PING state at the
39146 + * beginning of the next transfer.
39148 + qh->ping_state = 1;
39149 + clear_hc_int(hc_regs, nyet);
39157 + * This function is called from interrupt handlers.
39158 + * Scans the descriptor list, updates URB's status and
39159 + * calls completion routine for the URB if it's done.
39160 + * Releases the channel to be used by other transfers.
39161 + * In case of Isochronous endpoint the channel is not halted until
39162 + * the end of the session, i.e. QTD list is empty.
39163 + * If periodic channel released the FrameList is updated accordingly.
39165 + * Calls transaction selection routines to activate pending transfers.
39167 + * @param hcd The HCD state structure for the DWC OTG controller.
39168 + * @param hc Host channel, the transfer is completed on.
39169 + * @param hc_regs Host channel registers.
39170 + * @param halt_status Reason the channel is being halted,
39171 + * or just XferComplete for isochronous transfer
39173 +void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
39175 + dwc_otg_hc_regs_t * hc_regs,
39176 + dwc_otg_halt_status_e halt_status)
39178 + uint8_t continue_isoc_xfer = 0;
39179 + dwc_otg_transaction_type_e tr_type;
39180 + dwc_otg_qh_t *qh = hc->qh;
39182 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
39184 + complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
39186 + /* Release the channel if halted or session completed */
39187 + if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
39188 + DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
39190 + /* Halt the channel if session completed */
39191 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
39192 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
39195 + release_channel_ddma(hcd, qh);
39196 + dwc_otg_hcd_qh_remove(hcd, qh);
39198 + /* Keep in assigned schedule to continue transfer */
39199 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
39200 + &qh->qh_list_entry);
39201 + continue_isoc_xfer = 1;
39204 + /** @todo Consider the case when period exceeds FrameList size.
39205 + * Frame Rollover interrupt should be used.
39208 + /* Scan descriptor list to complete the URB(s), then release the channel */
39209 + complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
39211 + release_channel_ddma(hcd, qh);
39212 + dwc_otg_hcd_qh_remove(hcd, qh);
39214 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
39215 + /* Add back to inactive non-periodic schedule on normal completion */
39216 + dwc_otg_hcd_qh_add(hcd, qh);
39220 + tr_type = dwc_otg_hcd_select_transactions(hcd);
39221 + if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
39222 + if (continue_isoc_xfer) {
39223 + if (tr_type == DWC_OTG_TRANSACTION_NONE) {
39224 + tr_type = DWC_OTG_TRANSACTION_PERIODIC;
39225 + } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
39226 + tr_type = DWC_OTG_TRANSACTION_ALL;
39229 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
39233 +#endif /* DWC_DEVICE_ONLY */
39235 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
39237 +/* ==========================================================================
39238 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $
39239 + * $Revision: #12 $
39240 + * $Date: 2011/10/26 $
39241 + * $Change: 1873028 $
39243 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
39244 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
39245 + * otherwise expressly agreed to in writing between Synopsys and you.
39247 + * The Software IS NOT an item of Licensed Software or Licensed Product under
39248 + * any End User Software License Agreement or Agreement for Licensed Product
39249 + * with Synopsys or any supplement thereto. You are permitted to use and
39250 + * redistribute this Software in source and binary forms, with or without
39251 + * modification, provided that redistributions of source code must retain this
39252 + * notice. You may not view, use, disclose, copy or distribute this file or
39253 + * any information contained herein except pursuant to this license grant from
39254 + * Synopsys. If you do not agree with this notice, including the disclaimer
39255 + * below, then you are not authorized to use the Software.
39257 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
39258 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39259 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39260 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
39261 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39262 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39263 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39264 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39265 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39266 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39268 + * ========================================================================== */
39269 +#ifndef DWC_DEVICE_ONLY
39270 +#ifndef __DWC_HCD_IF_H__
39271 +#define __DWC_HCD_IF_H__
39273 +#include "dwc_otg_core_if.h"
39276 + * This file defines DWC_OTG HCD Core API.
39279 +struct dwc_otg_hcd;
39280 +typedef struct dwc_otg_hcd dwc_otg_hcd_t;
39282 +struct dwc_otg_hcd_urb;
39283 +typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t;
39285 +/** @name HCD Function Driver Callbacks */
39288 +/** This function is called whenever core switches to host mode. */
39289 +typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd);
39291 +/** This function is called when device has been disconnected */
39292 +typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd);
39294 +/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */
39295 +typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
39296 + void *urb_handle,
39297 + uint32_t * hub_addr,
39298 + uint32_t * port_addr);
39299 +/** Via this function HCD core gets device speed */
39300 +typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
39301 + void *urb_handle);
39303 +/** This function is called when urb is completed */
39304 +typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd,
39305 + void *urb_handle,
39306 + dwc_otg_hcd_urb_t * dwc_otg_urb,
39309 +/** Via this function HCD core gets b_hnp_enable parameter */
39310 +typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd);
39312 +struct dwc_otg_hcd_function_ops {
39313 + dwc_otg_hcd_start_cb_t start;
39314 + dwc_otg_hcd_disconnect_cb_t disconnect;
39315 + dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
39316 + dwc_otg_hcd_speed_from_urb_cb_t speed;
39317 + dwc_otg_hcd_complete_urb_cb_t complete;
39318 + dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
39322 +/** @name HCD Core API */
39324 +/** This function allocates dwc_otg_hcd structure and returns pointer on it. */
39325 +extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void);
39327 +/** This function should be called to initiate HCD Core.
39329 + * @param hcd The HCD
39330 + * @param core_if The DWC_OTG Core
39332 + * Returns -DWC_E_NO_MEMORY if no enough memory.
39333 + * Returns 0 on success
39335 +extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if);
39339 + * @param hcd The HCD
39341 +extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
39343 +/** This function should be called on every hardware interrupt.
39345 + * @param dwc_otg_hcd The HCD
39347 + * Returns non zero if interrupt is handled
39348 + * Return 0 if interrupt is not handled
39350 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
39353 + * Returns private data set by
39354 + * dwc_otg_hcd_set_priv_data function.
39356 + * @param hcd The HCD
39358 +extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd);
39361 + * Set private data.
39363 + * @param hcd The HCD
39364 + * @param priv_data pointer to be stored in private data
39366 +extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data);
39369 + * This function initializes the HCD Core.
39371 + * @param hcd The HCD
39372 + * @param fops The Function Driver Operations data structure containing pointers to all callbacks.
39374 + * Returns -DWC_E_NO_DEVICE if Core is currently is in device mode.
39375 + * Returns 0 on success
39377 +extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
39378 + struct dwc_otg_hcd_function_ops *fops);
39381 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
39384 + * @param hcd The HCD
39386 +extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd);
39389 + * Handles hub class-specific requests.
39391 + * @param dwc_otg_hcd The HCD
39392 + * @param typeReq Request Type
39393 + * @param wValue wValue from control request
39394 + * @param wIndex wIndex from control request
39395 + * @param buf data buffer
39396 + * @param wLength data buffer length
39398 + * Returns -DWC_E_INVALID if invalid argument is passed
39399 + * Returns 0 on success
39401 +extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
39402 + uint16_t typeReq, uint16_t wValue,
39403 + uint16_t wIndex, uint8_t * buf,
39404 + uint16_t wLength);
39407 + * Returns otg port number.
39409 + * @param hcd The HCD
39411 +extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd);
39414 + * Returns OTG version - either 1.3 or 2.0.
39416 + * @param core_if The core_if structure pointer
39418 +extern uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if);
39421 + * Returns 1 if currently core is acting as B host, and 0 otherwise.
39423 + * @param hcd The HCD
39425 +extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd);
39428 + * Returns current frame number.
39430 + * @param hcd The HCD
39432 +extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd);
39435 + * Dumps hcd state.
39437 + * @param hcd The HCD
39439 +extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd);
39442 + * Dump the average frame remaining at SOF. This can be used to
39443 + * determine average interrupt latency. Frame remaining is also shown for
39444 + * start transfer and two additional sample points.
39445 + * Currently this function is not implemented.
39447 + * @param hcd The HCD
39449 +extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd);
39452 + * Sends LPM transaction to the local device.
39454 + * @param hcd The HCD
39455 + * @param devaddr Device Address
39456 + * @param hird Host initiated resume duration
39457 + * @param bRemoteWake Value of bRemoteWake field in LPM transaction
39459 + * Returns negative value if sending LPM transaction was not succeeded.
39460 + * Returns 0 on success.
39462 +extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr,
39463 + uint8_t hird, uint8_t bRemoteWake);
39465 +/* URB interface */
39468 + * Allocates memory for dwc_otg_hcd_urb structure.
39469 + * Allocated memory should be freed by call of DWC_FREE.
39471 + * @param hcd The HCD
39472 + * @param iso_desc_count Count of ISOC descriptors
39473 + * @param atomic_alloc Specefies whether to perform atomic allocation.
39475 +extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
39476 + int iso_desc_count,
39477 + int atomic_alloc);
39480 + * Set pipe information in URB.
39482 + * @param hcd_urb DWC_OTG URB
39483 + * @param devaddr Device Address
39484 + * @param ep_num Endpoint Number
39485 + * @param ep_type Endpoint Type
39486 + * @param ep_dir Endpoint Direction
39487 + * @param mps Max Packet Size
39489 +extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb,
39490 + uint8_t devaddr, uint8_t ep_num,
39491 + uint8_t ep_type, uint8_t ep_dir,
39494 +/* Transfer flags */
39495 +#define URB_GIVEBACK_ASAP 0x1
39496 +#define URB_SEND_ZERO_PACKET 0x2
39499 + * Sets dwc_otg_hcd_urb parameters.
39501 + * @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
39502 + * @param urb_handle Unique handle for request, this will be passed back
39503 + * to function driver in completion callback.
39504 + * @param buf The buffer for the data
39505 + * @param dma The DMA buffer for the data
39506 + * @param buflen Transfer length
39507 + * @param sp Buffer for setup data
39508 + * @param sp_dma DMA address of setup data buffer
39509 + * @param flags Transfer flags
39510 + * @param interval Polling interval for interrupt or isochronous transfers.
39512 +extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb,
39513 + void *urb_handle, void *buf,
39514 + dwc_dma_t dma, uint32_t buflen, void *sp,
39515 + dwc_dma_t sp_dma, uint32_t flags,
39516 + uint16_t interval);
39518 +/** Gets status from dwc_otg_hcd_urb
39520 + * @param dwc_otg_urb DWC_OTG URB
39522 +extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb);
39524 +/** Gets actual length from dwc_otg_hcd_urb
39526 + * @param dwc_otg_urb DWC_OTG URB
39528 +extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t *
39531 +/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs
39533 + * @param dwc_otg_urb DWC_OTG URB
39535 +extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t *
39538 +/** Set ISOC descriptor offset and length
39540 + * @param dwc_otg_urb DWC_OTG URB
39541 + * @param desc_num ISOC descriptor number
39542 + * @param offset Offset from beginig of buffer.
39543 + * @param length Transaction length
39545 +extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
39546 + int desc_num, uint32_t offset,
39547 + uint32_t length);
39549 +/** Get status of ISOC descriptor, specified by desc_num
39551 + * @param dwc_otg_urb DWC_OTG URB
39552 + * @param desc_num ISOC descriptor number
39554 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t *
39555 + dwc_otg_urb, int desc_num);
39557 +/** Get actual length of ISOC descriptor, specified by desc_num
39559 + * @param dwc_otg_urb DWC_OTG URB
39560 + * @param desc_num ISOC descriptor number
39562 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
39566 +/** Queue URB. After transfer is completes, the complete callback will be called with the URB status
39568 + * @param dwc_otg_hcd The HCD
39569 + * @param dwc_otg_urb DWC_OTG URB
39570 + * @param ep_handle Out parameter for returning endpoint handle
39571 + * @param atomic_alloc Flag to do atomic allocation if needed
39573 + * Returns -DWC_E_NO_DEVICE if no device is connected.
39574 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
39575 + * Returns 0 on success.
39577 +extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd,
39578 + dwc_otg_hcd_urb_t * dwc_otg_urb,
39579 + void **ep_handle, int atomic_alloc);
39581 +/** De-queue the specified URB
39583 + * @param dwc_otg_hcd The HCD
39584 + * @param dwc_otg_urb DWC_OTG URB
39586 +extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd,
39587 + dwc_otg_hcd_urb_t * dwc_otg_urb);
39589 +/** Frees resources in the DWC_otg controller related to a given endpoint.
39590 + * Any URBs for the endpoint must already be dequeued.
39592 + * @param hcd The HCD
39593 + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
39594 + * @param retry Number of retries if there are queued transfers.
39596 + * Returns -DWC_E_INVALID if invalid arguments are passed.
39597 + * Returns 0 on success
39599 +extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
39602 +/* Resets the data toggle in qh structure. This function can be called from
39603 + * usb_clear_halt routine.
39605 + * @param hcd The HCD
39606 + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
39608 + * Returns -DWC_E_INVALID if invalid arguments are passed.
39609 + * Returns 0 on success
39611 +extern int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle);
39613 +/** Returns 1 if status of specified port is changed and 0 otherwise.
39615 + * @param hcd The HCD
39616 + * @param port Port number
39618 +extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port);
39620 +/** Call this function to check if bandwidth was allocated for specified endpoint.
39621 + * Only for ISOC and INTERRUPT endpoints.
39623 + * @param hcd The HCD
39624 + * @param ep_handle Endpoint handle
39626 +extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd,
39627 + void *ep_handle);
39629 +/** Call this function to check if bandwidth was freed for specified endpoint.
39631 + * @param hcd The HCD
39632 + * @param ep_handle Endpoint handle
39634 +extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle);
39636 +/** Returns bandwidth allocated for specified endpoint in microseconds.
39637 + * Only for ISOC and INTERRUPT endpoints.
39639 + * @param hcd The HCD
39640 + * @param ep_handle Endpoint handle
39642 +extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd,
39643 + void *ep_handle);
39647 +#endif /* __DWC_HCD_IF_H__ */
39648 +#endif /* DWC_DEVICE_ONLY */
39650 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
39652 +/* ==========================================================================
39653 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $
39654 + * $Revision: #89 $
39655 + * $Date: 2011/10/20 $
39656 + * $Change: 1869487 $
39658 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
39659 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
39660 + * otherwise expressly agreed to in writing between Synopsys and you.
39662 + * The Software IS NOT an item of Licensed Software or Licensed Product under
39663 + * any End User Software License Agreement or Agreement for Licensed Product
39664 + * with Synopsys or any supplement thereto. You are permitted to use and
39665 + * redistribute this Software in source and binary forms, with or without
39666 + * modification, provided that redistributions of source code must retain this
39667 + * notice. You may not view, use, disclose, copy or distribute this file or
39668 + * any information contained herein except pursuant to this license grant from
39669 + * Synopsys. If you do not agree with this notice, including the disclaimer
39670 + * below, then you are not authorized to use the Software.
39672 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
39673 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39674 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39675 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
39676 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39677 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39678 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39679 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39680 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39681 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39683 + * ========================================================================== */
39684 +#ifndef DWC_DEVICE_ONLY
39686 +#include "dwc_otg_hcd.h"
39687 +#include "dwc_otg_regs.h"
39689 +extern bool microframe_schedule;
39692 + * This file contains the implementation of the HCD Interrupt handlers.
39695 +/** This function handles interrupts for the HCD. */
39696 +int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39700 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
39701 + gintsts_data_t gintsts;
39703 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
39705 + //GRAYG: debugging
39706 + if (NULL == global_regs) {
39707 + DWC_DEBUGPL(DBG_HCD, "**** NULL regs: dwc_otg_hcd=%p "
39709 + dwc_otg_hcd, global_regs);
39714 + /* Exit from ISR if core is hibernated */
39715 + if (core_if->hibernation_suspend == 1) {
39718 + DWC_SPINLOCK(dwc_otg_hcd->lock);
39719 + /* Check if HOST Mode */
39720 + if (dwc_otg_is_host_mode(core_if)) {
39721 + gintsts.d32 = dwc_otg_read_core_intr(core_if);
39722 + if (!gintsts.d32) {
39723 + DWC_SPINUNLOCK(dwc_otg_hcd->lock);
39727 + /* Don't print debug message in the interrupt handler on SOF */
39729 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39731 + DWC_DEBUGPL(DBG_HCDI, "\n");
39736 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39738 + DWC_DEBUGPL(DBG_HCDI,
39739 + "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n",
39740 + gintsts.d32, core_if);
39743 + if (gintsts.b.sofintr) {
39744 + retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
39746 + if (gintsts.b.rxstsqlvl) {
39748 + dwc_otg_hcd_handle_rx_status_q_level_intr
39751 + if (gintsts.b.nptxfempty) {
39753 + dwc_otg_hcd_handle_np_tx_fifo_empty_intr
39756 + if (gintsts.b.i2cintr) {
39757 + /** @todo Implement i2cintr handler. */
39759 + if (gintsts.b.portintr) {
39760 + retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
39762 + if (gintsts.b.hcintr) {
39763 + retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
39765 + if (gintsts.b.ptxfempty) {
39767 + dwc_otg_hcd_handle_perio_tx_fifo_empty_intr
39772 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39775 + DWC_DEBUGPL(DBG_HCDI,
39776 + "DWC OTG HCD Finished Servicing Interrupts\n");
39777 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
39778 + DWC_READ_REG32(&global_regs->gintsts));
39779 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
39780 + DWC_READ_REG32(&global_regs->gintmsk));
39786 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39788 + DWC_DEBUGPL(DBG_HCDI, "\n");
39792 + DWC_SPINUNLOCK(dwc_otg_hcd->lock);
39796 +#ifdef DWC_TRACK_MISSED_SOFS
39797 +#warning Compiling code to track missed SOFs
39798 +#define FRAME_NUM_ARRAY_SIZE 1000
39800 + * This function is for debug only.
39802 +static inline void track_missed_sofs(uint16_t curr_frame_number)
39804 + static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
39805 + static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
39806 + static int frame_num_idx = 0;
39807 + static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
39808 + static int dumped_frame_num_array = 0;
39810 + if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
39811 + if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
39812 + curr_frame_number) {
39813 + frame_num_array[frame_num_idx] = curr_frame_number;
39814 + last_frame_num_array[frame_num_idx++] = last_frame_num;
39816 + } else if (!dumped_frame_num_array) {
39818 + DWC_PRINTF("Frame Last Frame\n");
39819 + DWC_PRINTF("----- ----------\n");
39820 + for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
39821 + DWC_PRINTF("0x%04x 0x%04x\n",
39822 + frame_num_array[i], last_frame_num_array[i]);
39824 + dumped_frame_num_array = 1;
39826 + last_frame_num = curr_frame_number;
39831 + * Handles the start-of-frame interrupt in host mode. Non-periodic
39832 + * transactions may be queued to the DWC_otg controller for the current
39833 + * (micro)frame. Periodic transactions may be queued to the controller for the
39834 + * next (micro)frame.
39836 +int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd)
39838 + hfnum_data_t hfnum;
39839 + dwc_list_link_t *qh_entry;
39840 + dwc_otg_qh_t *qh;
39841 + dwc_otg_transaction_type_e tr_type;
39842 + gintsts_data_t gintsts = {.d32 = 0 };
39845 + DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
39848 + DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
39850 + hcd->frame_number = hfnum.b.frnum;
39853 + hcd->frrem_accum += hfnum.b.frrem;
39854 + hcd->frrem_samples++;
39857 +#ifdef DWC_TRACK_MISSED_SOFS
39858 + track_missed_sofs(hcd->frame_number);
39860 + /* Determine whether any periodic QHs should be executed. */
39861 + qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive);
39862 + while (qh_entry != &hcd->periodic_sched_inactive) {
39863 + qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry);
39864 + qh_entry = qh_entry->next;
39865 + if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
39867 + * Move QH to the ready list to be executed next
39870 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
39871 + &qh->qh_list_entry);
39874 + tr_type = dwc_otg_hcd_select_transactions(hcd);
39875 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
39876 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
39879 + /* Clear interrupt */
39880 + gintsts.b.sofintr = 1;
39881 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
39886 +/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at
39887 + * least one packet in the Rx FIFO. The packets are moved from the FIFO to
39888 + * memory if the DWC_otg controller is operating in Slave mode. */
39889 +int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39891 + host_grxsts_data_t grxsts;
39892 + dwc_hc_t *hc = NULL;
39894 + DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
39897 + DWC_READ_REG32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp);
39899 + hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
39901 + DWC_ERROR("Unable to get corresponding channel\n");
39905 + /* Packet Status */
39906 + DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum);
39907 + DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt);
39908 + DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid,
39909 + hc->data_pid_start);
39910 + DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts);
39912 + switch (grxsts.b.pktsts) {
39913 + case DWC_GRXSTS_PKTSTS_IN:
39914 + /* Read the data into the host buffer. */
39915 + if (grxsts.b.bcnt > 0) {
39916 + dwc_otg_read_packet(dwc_otg_hcd->core_if,
39917 + hc->xfer_buff, grxsts.b.bcnt);
39919 + /* Update the HC fields for the next packet received. */
39920 + hc->xfer_count += grxsts.b.bcnt;
39921 + hc->xfer_buff += grxsts.b.bcnt;
39924 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
39925 + case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
39926 + case DWC_GRXSTS_PKTSTS_CH_HALTED:
39927 + /* Handled in interrupt, just ignore data */
39930 + DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n",
39931 + grxsts.b.pktsts);
39938 +/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
39939 + * data packets may be written to the FIFO for OUT transfers. More requests
39940 + * may be written to the non-periodic request queue for IN transfers. This
39941 + * interrupt is enabled only in Slave mode. */
39942 +int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39944 + DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
39945 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
39946 + DWC_OTG_TRANSACTION_NON_PERIODIC);
39950 +/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data
39951 + * packets may be written to the FIFO for OUT transfers. More requests may be
39952 + * written to the periodic request queue for IN transfers. This interrupt is
39953 + * enabled only in Slave mode. */
39954 +int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39956 + DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
39957 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
39958 + DWC_OTG_TRANSACTION_PERIODIC);
39962 +/** There are multiple conditions that can cause a port interrupt. This function
39963 + * determines which interrupt conditions have occurred and handles them
39964 + * appropriately. */
39965 +int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39968 + hprt0_data_t hprt0;
39969 + hprt0_data_t hprt0_modify;
39971 + hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
39972 + hprt0_modify.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
39974 + /* Clear appropriate bits in HPRT0 to clear the interrupt bit in
39977 + hprt0_modify.b.prtena = 0;
39978 + hprt0_modify.b.prtconndet = 0;
39979 + hprt0_modify.b.prtenchng = 0;
39980 + hprt0_modify.b.prtovrcurrchng = 0;
39982 + /* Port Connect Detected
39983 + * Set flag and clear if detected */
39984 + if (dwc_otg_hcd->core_if->hibernation_suspend == 1) {
39985 + // Dont modify port status if we are in hibernation state
39986 + hprt0_modify.b.prtconndet = 1;
39987 + hprt0_modify.b.prtenchng = 1;
39988 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
39989 + hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
39993 + if (hprt0.b.prtconndet) {
39994 + /** @todo - check if steps performed in 'else' block should be perfromed regardles adp */
39995 + if (dwc_otg_hcd->core_if->adp_enable &&
39996 + dwc_otg_hcd->core_if->adp.vbuson_timer_started == 1) {
39997 + DWC_PRINTF("PORT CONNECT DETECTED ----------------\n");
39998 + DWC_TIMER_CANCEL(dwc_otg_hcd->core_if->adp.vbuson_timer);
39999 + dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
40000 + /* TODO - check if this is required, as
40001 + * host initialization was already performed
40002 + * after initial ADP probing
40004 + /*dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
40005 + dwc_otg_core_init(dwc_otg_hcd->core_if);
40006 + dwc_otg_enable_global_interrupts(dwc_otg_hcd->core_if);
40007 + cil_hcd_start(dwc_otg_hcd->core_if);*/
40010 + DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
40011 + "Port Connect Detected--\n", hprt0.d32);
40012 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
40013 + dwc_otg_hcd->flags.b.port_connect_status = 1;
40014 + hprt0_modify.b.prtconndet = 1;
40016 + /* B-Device has connected, Delete the connection timer. */
40017 + DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer);
40019 + /* The Hub driver asserts a reset when it sees port connect
40020 + * status change flag */
40024 + /* Port Enable Changed
40025 + * Clear if detected - Set internal flag if disabled */
40026 + if (hprt0.b.prtenchng) {
40027 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
40028 + "Port Enable Changed--\n", hprt0.d32);
40029 + hprt0_modify.b.prtenchng = 1;
40030 + if (hprt0.b.prtena == 1) {
40031 + hfir_data_t hfir;
40032 + int do_reset = 0;
40033 + dwc_otg_core_params_t *params =
40034 + dwc_otg_hcd->core_if->core_params;
40035 + dwc_otg_core_global_regs_t *global_regs =
40036 + dwc_otg_hcd->core_if->core_global_regs;
40037 + dwc_otg_host_if_t *host_if =
40038 + dwc_otg_hcd->core_if->host_if;
40040 + /* Every time when port enables calculate
40041 + * HFIR.FrInterval
40043 + hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
40044 + hfir.b.frint = calc_frame_interval(dwc_otg_hcd->core_if);
40045 + DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
40047 + /* Check if we need to adjust the PHY clock speed for
40048 + * low power and adjust it */
40049 + if (params->host_support_fs_ls_low_power) {
40050 + gusbcfg_data_t usbcfg;
40053 + DWC_READ_REG32(&global_regs->gusbcfg);
40055 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED
40056 + || hprt0.b.prtspd ==
40057 + DWC_HPRT0_PRTSPD_FULL_SPEED) {
40061 + hcfg_data_t hcfg;
40062 + if (usbcfg.b.phylpwrclksel == 0) {
40063 + /* Set PHY low power clock select for FS/LS devices */
40064 + usbcfg.b.phylpwrclksel = 1;
40066 + (&global_regs->gusbcfg,
40073 + (&host_if->host_global_regs->hcfg);
40075 + if (hprt0.b.prtspd ==
40076 + DWC_HPRT0_PRTSPD_LOW_SPEED
40077 + && params->host_ls_low_power_phy_clk
40079 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)
40082 + DWC_DEBUGPL(DBG_CIL,
40083 + "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
40084 + if (hcfg.b.fslspclksel !=
40085 + DWC_HCFG_6_MHZ) {
40086 + hcfg.b.fslspclksel =
40089 + (&host_if->host_global_regs->hcfg,
40095 + DWC_DEBUGPL(DBG_CIL,
40096 + "FS_PHY programming HCFG to 48 MHz ()\n");
40097 + if (hcfg.b.fslspclksel !=
40098 + DWC_HCFG_48_MHZ) {
40099 + hcfg.b.fslspclksel =
40102 + (&host_if->host_global_regs->hcfg,
40111 + if (usbcfg.b.phylpwrclksel == 1) {
40112 + usbcfg.b.phylpwrclksel = 0;
40114 + (&global_regs->gusbcfg,
40121 + DWC_TASK_SCHEDULE(dwc_otg_hcd->reset_tasklet);
40126 + /* Port has been enabled set the reset change flag */
40127 + dwc_otg_hcd->flags.b.port_reset_change = 1;
40130 + dwc_otg_hcd->flags.b.port_enable_change = 1;
40135 + /** Overcurrent Change Interrupt */
40136 + if (hprt0.b.prtovrcurrchng) {
40137 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
40138 + "Port Overcurrent Changed--\n", hprt0.d32);
40139 + dwc_otg_hcd->flags.b.port_over_current_change = 1;
40140 + hprt0_modify.b.prtovrcurrchng = 1;
40144 + /* Clear Port Interrupts */
40145 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
40150 +/** This interrupt indicates that one or more host channels has a pending
40151 + * interrupt. There are multiple conditions that can cause each host channel
40152 + * interrupt. This function determines which conditions have occurred for each
40153 + * host channel interrupt and handles them appropriately. */
40154 +int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40158 + haint_data_t haint;
40160 + /* Clear appropriate bits in HCINTn to clear the interrupt bit in
40163 + haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
40165 + for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
40166 + if (haint.b2.chint & (1 << i)) {
40167 + retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
40175 + * Gets the actual length of a transfer after the transfer halts. _halt_status
40176 + * holds the reason for the halt.
40178 + * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE,
40179 + * *short_read is set to 1 upon return if less than the requested
40180 + * number of bytes were transferred. Otherwise, *short_read is set to 0 upon
40181 + * return. short_read may also be NULL on entry, in which case it remains
40184 +static uint32_t get_actual_xfer_length(dwc_hc_t * hc,
40185 + dwc_otg_hc_regs_t * hc_regs,
40186 + dwc_otg_qtd_t * qtd,
40187 + dwc_otg_halt_status_e halt_status,
40190 + hctsiz_data_t hctsiz;
40193 + if (short_read != NULL) {
40196 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40198 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
40199 + if (hc->ep_is_in) {
40200 + length = hc->xfer_len - hctsiz.b.xfersize;
40201 + if (short_read != NULL) {
40202 + *short_read = (hctsiz.b.xfersize != 0);
40204 + } else if (hc->qh->do_split) {
40205 + length = qtd->ssplit_out_xfer_count;
40207 + length = hc->xfer_len;
40211 + * Must use the hctsiz.pktcnt field to determine how much data
40212 + * has been transferred. This field reflects the number of
40213 + * packets that have been transferred via the USB. This is
40214 + * always an integral number of packets if the transfer was
40215 + * halted before its normal completion. (Can't use the
40216 + * hctsiz.xfersize field because that reflects the number of
40217 + * bytes transferred via the AHB, not the USB).
40220 + (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet;
40227 + * Updates the state of the URB after a Transfer Complete interrupt on the
40228 + * host channel. Updates the actual_length field of the URB based on the
40229 + * number of bytes transferred via the host channel. Sets the URB status
40230 + * if the data transfer is finished.
40232 + * @return 1 if the data transfer specified by the URB is completely finished,
40235 +static int update_urb_state_xfer_comp(dwc_hc_t * hc,
40236 + dwc_otg_hc_regs_t * hc_regs,
40237 + dwc_otg_hcd_urb_t * urb,
40238 + dwc_otg_qtd_t * qtd)
40240 + int xfer_done = 0;
40241 + int short_read = 0;
40245 + xfer_length = get_actual_xfer_length(hc, hc_regs, qtd,
40246 + DWC_OTG_HC_XFER_COMPLETE,
40250 + /* non DWORD-aligned buffer case handling. */
40251 + if (hc->align_buff && xfer_length && hc->ep_is_in) {
40252 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
40256 + urb->actual_length += xfer_length;
40258 + if (xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) &&
40259 + (urb->flags & URB_SEND_ZERO_PACKET)
40260 + && (urb->actual_length == urb->length)
40261 + && !(urb->length % hc->max_packet)) {
40263 + } else if (short_read || urb->actual_length >= urb->length) {
40270 + hctsiz_data_t hctsiz;
40271 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40272 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
40273 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
40275 + DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", hc->xfer_len);
40276 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n",
40277 + hctsiz.b.xfersize);
40278 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
40280 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
40281 + urb->actual_length);
40282 + DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n",
40283 + short_read, xfer_done);
40287 + return xfer_done;
40291 + * Save the starting data toggle for the next transfer. The data toggle is
40292 + * saved in the QH for non-control transfers and it's saved in the QTD for
40293 + * control transfers.
40295 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
40296 + dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd)
40298 + hctsiz_data_t hctsiz;
40299 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40301 + if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
40302 + dwc_otg_qh_t *qh = hc->qh;
40303 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
40304 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
40306 + qh->data_toggle = DWC_OTG_HC_PID_DATA1;
40309 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
40310 + qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
40312 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
40318 + * Updates the state of an Isochronous URB when the transfer is stopped for
40319 + * any reason. The fields of the current entry in the frame descriptor array
40320 + * are set based on the transfer state and the input _halt_status. Completes
40321 + * the Isochronous URB if all the URB frames have been completed.
40323 + * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be
40324 + * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
40326 +static dwc_otg_halt_status_e
40327 +update_isoc_urb_state(dwc_otg_hcd_t * hcd,
40329 + dwc_otg_hc_regs_t * hc_regs,
40330 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
40332 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40333 + dwc_otg_halt_status_e ret_val = halt_status;
40334 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
40336 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
40337 + switch (halt_status) {
40338 + case DWC_OTG_HC_XFER_COMPLETE:
40339 + frame_desc->status = 0;
40340 + frame_desc->actual_length =
40341 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
40343 + /* non DWORD-aligned buffer case handling. */
40344 + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
40345 + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
40346 + hc->qh->dw_align_buf, frame_desc->actual_length);
40350 + case DWC_OTG_HC_XFER_FRAME_OVERRUN:
40351 + urb->error_count++;
40352 + if (hc->ep_is_in) {
40353 + frame_desc->status = -DWC_E_NO_STREAM_RES;
40355 + frame_desc->status = -DWC_E_COMMUNICATION;
40357 + frame_desc->actual_length = 0;
40359 + case DWC_OTG_HC_XFER_BABBLE_ERR:
40360 + urb->error_count++;
40361 + frame_desc->status = -DWC_E_OVERFLOW;
40362 + /* Don't need to update actual_length in this case. */
40364 + case DWC_OTG_HC_XFER_XACT_ERR:
40365 + urb->error_count++;
40366 + frame_desc->status = -DWC_E_PROTOCOL;
40367 + frame_desc->actual_length =
40368 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
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);
40375 + /* Skip whole frame */
40376 + if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) &&
40377 + hc->ep_is_in && hcd->core_if->dma_enable) {
40378 + qtd->complete_split = 0;
40379 + qtd->isoc_split_offset = 0;
40384 + DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status);
40387 + if (++qtd->isoc_frame_index == urb->packet_count) {
40389 + * urb->status is not used for isoc transfers.
40390 + * The individual frame_desc statuses are used instead.
40392 + hcd->fops->complete(hcd, urb->priv, urb, 0);
40393 + ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
40395 + ret_val = DWC_OTG_HC_XFER_COMPLETE;
40401 + * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
40402 + * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
40403 + * still linked to the QH, the QH is added to the end of the inactive
40404 + * non-periodic schedule. For periodic QHs, removes the QH from the periodic
40405 + * schedule if no more QTDs are linked to the QH.
40407 +static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd)
40409 + int continue_split = 0;
40410 + dwc_otg_qtd_t *qtd;
40412 + DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd);
40414 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
40416 + if (qtd->complete_split) {
40417 + continue_split = 1;
40418 + } else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
40419 + qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) {
40420 + continue_split = 1;
40424 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
40425 + continue_split = 0;
40428 + qh->channel = NULL;
40429 + dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
40433 + * Releases a host channel for use by other transfers. Attempts to select and
40434 + * queue more transactions since at least one host channel is available.
40436 + * @param hcd The HCD state structure.
40437 + * @param hc The host channel to release.
40438 + * @param qtd The QTD associated with the host channel. This QTD may be freed
40439 + * if the transfer is complete or an error has occurred.
40440 + * @param halt_status Reason the channel is being released. This status
40441 + * determines the actions taken by this function.
40443 +static void release_channel(dwc_otg_hcd_t * hcd,
40445 + dwc_otg_qtd_t * qtd,
40446 + dwc_otg_halt_status_e halt_status)
40448 + dwc_otg_transaction_type_e tr_type;
40450 + dwc_irqflags_t flags;
40451 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
40453 + DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n",
40454 + __func__, hc->hc_num, halt_status, hc->xfer_len);
40456 + switch (halt_status) {
40457 + case DWC_OTG_HC_XFER_URB_COMPLETE:
40460 + case DWC_OTG_HC_XFER_AHB_ERR:
40461 + case DWC_OTG_HC_XFER_STALL:
40462 + case DWC_OTG_HC_XFER_BABBLE_ERR:
40465 + case DWC_OTG_HC_XFER_XACT_ERR:
40466 + if (qtd->error_count >= 3) {
40467 + DWC_DEBUGPL(DBG_HCDV,
40468 + " Complete URB with transaction error\n");
40470 + qtd->urb->status = -DWC_E_PROTOCOL;
40471 + hcd->fops->complete(hcd, qtd->urb->priv,
40472 + qtd->urb, -DWC_E_PROTOCOL);
40477 + case DWC_OTG_HC_XFER_URB_DEQUEUE:
40479 + * The QTD has already been removed and the QH has been
40480 + * deactivated. Don't want to do anything except release the
40481 + * host channel and try to queue more transfers.
40484 + case DWC_OTG_HC_XFER_NO_HALT_STATUS:
40487 + case DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE:
40488 + DWC_DEBUGPL(DBG_HCDV,
40489 + " Complete URB with I/O error\n");
40491 + qtd->urb->status = -DWC_E_IO;
40492 + hcd->fops->complete(hcd, qtd->urb->priv,
40493 + qtd->urb, -DWC_E_IO);
40500 + deactivate_qh(hcd, hc->qh, free_qtd);
40504 + * Release the host channel for use by other transfers. The cleanup
40505 + * function clears the channel interrupt enables and conditions, so
40506 + * there's no need to clear the Channel Halted interrupt separately.
40508 + dwc_otg_hc_cleanup(hcd->core_if, hc);
40509 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
40511 + if (!microframe_schedule) {
40512 + switch (hc->ep_type) {
40513 + case DWC_OTG_EP_TYPE_CONTROL:
40514 + case DWC_OTG_EP_TYPE_BULK:
40515 + hcd->non_periodic_channels--;
40520 + * Don't release reservations for periodic channels here.
40521 + * That's done when a periodic transfer is descheduled (i.e.
40522 + * when the QH is removed from the periodic schedule).
40528 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
40529 + hcd->available_host_channels++;
40530 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
40533 + /* Try to queue more transfers now that there's a free channel. */
40534 + tr_type = dwc_otg_hcd_select_transactions(hcd);
40535 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
40536 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
40538 + DWC_SPINLOCK_FREE(channel_lock);
40542 + * Halts a host channel. If the channel cannot be halted immediately because
40543 + * the request queue is full, this function ensures that the FIFO empty
40544 + * interrupt for the appropriate queue is enabled so that the halt request can
40545 + * be queued when there is space in the request queue.
40547 + * This function may also be called in DMA mode. In that case, the channel is
40548 + * simply released since the core always halts the channel automatically in
40551 +static void halt_channel(dwc_otg_hcd_t * hcd,
40553 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
40555 + if (hcd->core_if->dma_enable) {
40556 + release_channel(hcd, hc, qtd, halt_status);
40560 + /* Slave mode processing... */
40561 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
40563 + if (hc->halt_on_queue) {
40564 + gintmsk_data_t gintmsk = {.d32 = 0 };
40565 + dwc_otg_core_global_regs_t *global_regs;
40566 + global_regs = hcd->core_if->core_global_regs;
40568 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
40569 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
40571 + * Make sure the Non-periodic Tx FIFO empty interrupt
40572 + * is enabled so that the non-periodic schedule will
40575 + gintmsk.b.nptxfempty = 1;
40576 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
40579 + * Move the QH from the periodic queued schedule to
40580 + * the periodic assigned schedule. This allows the
40581 + * halt to be queued when the periodic schedule is
40584 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
40585 + &hc->qh->qh_list_entry);
40588 + * Make sure the Periodic Tx FIFO Empty interrupt is
40589 + * enabled so that the periodic schedule will be
40592 + gintmsk.b.ptxfempty = 1;
40593 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
40599 + * Performs common cleanup for non-periodic transfers after a Transfer
40600 + * Complete interrupt. This function should be called after any endpoint type
40601 + * specific handling is finished to release the host channel.
40603 +static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd,
40605 + dwc_otg_hc_regs_t * hc_regs,
40606 + dwc_otg_qtd_t * qtd,
40607 + dwc_otg_halt_status_e halt_status)
40609 + hcint_data_t hcint;
40611 + qtd->error_count = 0;
40613 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
40614 + if (hcint.b.nyet) {
40616 + * Got a NYET on the last transaction of the transfer. This
40617 + * means that the endpoint should be in the PING state at the
40618 + * beginning of the next transfer.
40620 + hc->qh->ping_state = 1;
40621 + clear_hc_int(hc_regs, nyet);
40625 + * Always halt and release the host channel to make it available for
40626 + * more transfers. There may still be more phases for a control
40627 + * transfer or more data packets for a bulk transfer at this point,
40628 + * but the host channel is still halted. A channel will be reassigned
40629 + * to the transfer when the non-periodic schedule is processed after
40630 + * the channel is released. This allows transactions to be queued
40631 + * properly via dwc_otg_hcd_queue_transactions, which also enables the
40632 + * Tx FIFO Empty interrupt if necessary.
40634 + if (hc->ep_is_in) {
40636 + * IN transfers in Slave mode require an explicit disable to
40637 + * halt the channel. (In DMA mode, this call simply releases
40640 + halt_channel(hcd, hc, qtd, halt_status);
40643 + * The channel is automatically disabled by the core for OUT
40644 + * transfers in Slave mode.
40646 + release_channel(hcd, hc, qtd, halt_status);
40651 + * Performs common cleanup for periodic transfers after a Transfer Complete
40652 + * interrupt. This function should be called after any endpoint type specific
40653 + * handling is finished to release the host channel.
40655 +static void complete_periodic_xfer(dwc_otg_hcd_t * hcd,
40657 + dwc_otg_hc_regs_t * hc_regs,
40658 + dwc_otg_qtd_t * qtd,
40659 + dwc_otg_halt_status_e halt_status)
40661 + hctsiz_data_t hctsiz;
40662 + qtd->error_count = 0;
40664 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40665 + if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) {
40666 + /* Core halts channel in these cases. */
40667 + release_channel(hcd, hc, qtd, halt_status);
40669 + /* Flush any outstanding requests from the Tx queue. */
40670 + halt_channel(hcd, hc, qtd, halt_status);
40674 +static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd,
40676 + dwc_otg_hc_regs_t * hc_regs,
40677 + dwc_otg_qtd_t * qtd)
40680 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
40681 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
40683 + len = get_actual_xfer_length(hc, hc_regs, qtd,
40684 + DWC_OTG_HC_XFER_COMPLETE, NULL);
40687 + qtd->complete_split = 0;
40688 + qtd->isoc_split_offset = 0;
40691 + frame_desc->actual_length += len;
40693 + if (hc->align_buff && len)
40694 + dwc_memcpy(qtd->urb->buf + frame_desc->offset +
40695 + qtd->isoc_split_offset, hc->qh->dw_align_buf, len);
40696 + qtd->isoc_split_offset += len;
40698 + if (frame_desc->length == frame_desc->actual_length) {
40699 + frame_desc->status = 0;
40700 + qtd->isoc_frame_index++;
40701 + qtd->complete_split = 0;
40702 + qtd->isoc_split_offset = 0;
40705 + if (qtd->isoc_frame_index == qtd->urb->packet_count) {
40706 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
40707 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
40709 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
40712 + return 1; /* Indicates that channel released */
40716 + * Handles a host channel Transfer Complete interrupt. This handler may be
40717 + * called in either DMA mode or Slave mode.
40719 +static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd,
40721 + dwc_otg_hc_regs_t * hc_regs,
40722 + dwc_otg_qtd_t * qtd)
40724 + int urb_xfer_done;
40725 + dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;
40726 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40727 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
40729 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
40730 + "Transfer Complete--\n", hc->hc_num);
40732 + if (hcd->core_if->dma_desc_enable) {
40733 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status);
40734 + if (pipe_type == UE_ISOCHRONOUS) {
40735 + /* Do not disable the interrupt, just clear it */
40736 + clear_hc_int(hc_regs, xfercomp);
40739 + goto handle_xfercomp_done;
40743 + * Handle xfer complete on CSPLIT.
40746 + if (hc->qh->do_split) {
40747 + if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in
40748 + && hcd->core_if->dma_enable) {
40749 + if (qtd->complete_split
40750 + && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs,
40752 + goto handle_xfercomp_done;
40754 + qtd->complete_split = 0;
40758 + /* Update the QTD and URB states. */
40759 + switch (pipe_type) {
40761 + switch (qtd->control_phase) {
40762 + case DWC_OTG_CONTROL_SETUP:
40763 + if (urb->length > 0) {
40764 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
40766 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
40768 + DWC_DEBUGPL(DBG_HCDV,
40769 + " Control setup transaction done\n");
40770 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40772 + case DWC_OTG_CONTROL_DATA:{
40774 + update_urb_state_xfer_comp(hc, hc_regs, urb,
40776 + if (urb_xfer_done) {
40777 + qtd->control_phase =
40778 + DWC_OTG_CONTROL_STATUS;
40779 + DWC_DEBUGPL(DBG_HCDV,
40780 + " Control data transfer done\n");
40782 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40784 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40787 + case DWC_OTG_CONTROL_STATUS:
40788 + DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n");
40789 + if (urb->status == -DWC_E_IN_PROGRESS) {
40792 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40793 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40797 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40800 + DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n");
40802 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
40803 + if (urb_xfer_done) {
40804 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40805 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40807 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40810 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40811 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40813 + case UE_INTERRUPT:
40814 + DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n");
40816 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
40819 + * Interrupt URB is done on the first transfer complete
40822 + if (urb_xfer_done) {
40823 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40824 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40826 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40829 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40830 + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40832 + case UE_ISOCHRONOUS:
40833 + DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n");
40834 + if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {
40836 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
40837 + DWC_OTG_HC_XFER_COMPLETE);
40839 + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40843 +handle_xfercomp_done:
40844 + disable_hc_int(hc_regs, xfercompl);
40850 + * Handles a host channel STALL interrupt. This handler may be called in
40851 + * either DMA mode or Slave mode.
40853 +static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd,
40855 + dwc_otg_hc_regs_t * hc_regs,
40856 + dwc_otg_qtd_t * qtd)
40858 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40859 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
40861 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
40862 + "STALL Received--\n", hc->hc_num);
40864 + if (hcd->core_if->dma_desc_enable) {
40865 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL);
40866 + goto handle_stall_done;
40869 + if (pipe_type == UE_CONTROL) {
40870 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
40873 + if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) {
40874 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
40876 + * USB protocol requires resetting the data toggle for bulk
40877 + * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
40878 + * setup command is issued to the endpoint. Anticipate the
40879 + * CLEAR_FEATURE command since a STALL has occurred and reset
40880 + * the data toggle now.
40882 + hc->qh->data_toggle = 0;
40885 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL);
40887 +handle_stall_done:
40888 + disable_hc_int(hc_regs, stall);
40894 + * Updates the state of the URB when a transfer has been stopped due to an
40895 + * abnormal condition before the transfer completes. Modifies the
40896 + * actual_length field of the URB to reflect the number of bytes that have
40897 + * actually been transferred via the host channel.
40899 +static void update_urb_state_xfer_intr(dwc_hc_t * hc,
40900 + dwc_otg_hc_regs_t * hc_regs,
40901 + dwc_otg_hcd_urb_t * urb,
40902 + dwc_otg_qtd_t * qtd,
40903 + dwc_otg_halt_status_e halt_status)
40905 + uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
40906 + halt_status, NULL);
40907 + /* non DWORD-aligned buffer case handling. */
40908 + if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
40909 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
40910 + bytes_transferred);
40913 + urb->actual_length += bytes_transferred;
40917 + hctsiz_data_t hctsiz;
40918 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40919 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
40920 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
40922 + DWC_DEBUGPL(DBG_HCDV, " hc->start_pkt_count %d\n",
40923 + hc->start_pkt_count);
40924 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
40925 + DWC_DEBUGPL(DBG_HCDV, " hc->max_packet %d\n", hc->max_packet);
40926 + DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n",
40927 + bytes_transferred);
40928 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
40929 + urb->actual_length);
40930 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
40937 + * Handles a host channel NAK interrupt. This handler may be called in either
40938 + * DMA mode or Slave mode.
40940 +static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
40942 + dwc_otg_hc_regs_t * hc_regs,
40943 + dwc_otg_qtd_t * qtd)
40945 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
40946 + "NAK Received--\n", hc->hc_num);
40949 + * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
40950 + * interrupt. Re-start the SSPLIT transfer.
40952 + if (hc->do_split) {
40953 + if (hc->complete_split) {
40954 + qtd->error_count = 0;
40956 + qtd->complete_split = 0;
40957 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
40958 + goto handle_nak_done;
40961 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
40964 + if (hcd->core_if->dma_enable && hc->ep_is_in) {
40966 + * NAK interrupts are enabled on bulk/control IN
40967 + * transfers in DMA mode for the sole purpose of
40968 + * resetting the error count after a transaction error
40969 + * occurs. The core will continue transferring data.
40971 + qtd->error_count = 0;
40972 + goto handle_nak_done;
40976 + * NAK interrupts normally occur during OUT transfers in DMA
40977 + * or Slave mode. For IN transfers, more requests will be
40978 + * queued as request queue space is available.
40980 + qtd->error_count = 0;
40982 + if (!hc->qh->ping_state) {
40983 + update_urb_state_xfer_intr(hc, hc_regs,
40985 + DWC_OTG_HC_XFER_NAK);
40986 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40988 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH)
40989 + hc->qh->ping_state = 1;
40993 + * Halt the channel so the transfer can be re-started from
40994 + * the appropriate point or the PING protocol will
40995 + * start/continue.
40997 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
40999 + case UE_INTERRUPT:
41000 + qtd->error_count = 0;
41001 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
41003 + case UE_ISOCHRONOUS:
41004 + /* Should never get called for isochronous transfers. */
41005 + DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n");
41010 + disable_hc_int(hc_regs, nak);
41016 + * Handles a host channel ACK interrupt. This interrupt is enabled when
41017 + * performing the PING protocol in Slave mode, when errors occur during
41018 + * either Slave mode or DMA mode, and during Start Split transactions.
41020 +static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd,
41022 + dwc_otg_hc_regs_t * hc_regs,
41023 + dwc_otg_qtd_t * qtd)
41025 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41026 + "ACK Received--\n", hc->hc_num);
41028 + if (hc->do_split) {
41030 + * Handle ACK on SSPLIT.
41031 + * ACK should not occur in CSPLIT.
41033 + if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) {
41034 + qtd->ssplit_out_xfer_count = hc->xfer_len;
41036 + if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) {
41037 + /* Don't need complete for isochronous out transfers. */
41038 + qtd->complete_split = 1;
41042 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
41043 + switch (hc->xact_pos) {
41044 + case DWC_HCSPLIT_XACTPOS_ALL:
41046 + case DWC_HCSPLIT_XACTPOS_END:
41047 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
41048 + qtd->isoc_split_offset = 0;
41050 + case DWC_HCSPLIT_XACTPOS_BEGIN:
41051 + case DWC_HCSPLIT_XACTPOS_MID:
41053 + * For BEGIN or MID, calculate the length for
41054 + * the next microframe to determine the correct
41055 + * SSPLIT token, either MID or END.
41058 + struct dwc_otg_hcd_iso_packet_desc
41063 + iso_descs[qtd->isoc_frame_index];
41064 + qtd->isoc_split_offset += 188;
41066 + if ((frame_desc->length -
41067 + qtd->isoc_split_offset) <= 188) {
41068 + qtd->isoc_split_pos =
41069 + DWC_HCSPLIT_XACTPOS_END;
41071 + qtd->isoc_split_pos =
41072 + DWC_HCSPLIT_XACTPOS_MID;
41079 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
41082 + qtd->error_count = 0;
41084 + if (hc->qh->ping_state) {
41085 + hc->qh->ping_state = 0;
41087 + * Halt the channel so the transfer can be re-started
41088 + * from the appropriate point. This only happens in
41089 + * Slave mode. In DMA mode, the ping_state is cleared
41090 + * when the transfer is started because the core
41091 + * automatically executes the PING, then the transfer.
41093 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
41098 + * If the ACK occurred when _not_ in the PING state, let the channel
41099 + * continue transferring data after clearing the error count.
41102 + disable_hc_int(hc_regs, ack);
41108 + * Handles a host channel NYET interrupt. This interrupt should only occur on
41109 + * Bulk and Control OUT endpoints and for complete split transactions. If a
41110 + * NYET occurs at the same time as a Transfer Complete interrupt, it is
41111 + * handled in the xfercomp interrupt handler, not here. This handler may be
41112 + * called in either DMA mode or Slave mode.
41114 +static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
41116 + dwc_otg_hc_regs_t * hc_regs,
41117 + dwc_otg_qtd_t * qtd)
41119 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41120 + "NYET Received--\n", hc->hc_num);
41124 + * re-do the CSPLIT immediately on non-periodic
41126 + if (hc->do_split && hc->complete_split) {
41127 + if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
41128 + && hcd->core_if->dma_enable) {
41129 + qtd->complete_split = 0;
41130 + qtd->isoc_split_offset = 0;
41131 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
41132 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
41133 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
41136 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
41137 + goto handle_nyet_done;
41140 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
41141 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
41142 + int frnum = dwc_otg_hcd_get_frame_number(hcd);
41144 + if (dwc_full_frame_num(frnum) !=
41145 + dwc_full_frame_num(hc->qh->sched_frame)) {
41147 + * No longer in the same full speed frame.
41148 + * Treat this as a transaction error.
41151 + /** @todo Fix system performance so this can
41152 + * be treated as an error. Right now complete
41153 + * splits cannot be scheduled precisely enough
41154 + * due to other system activity, so this error
41155 + * occurs regularly in Slave mode.
41157 + qtd->error_count++;
41159 + qtd->complete_split = 0;
41160 + halt_channel(hcd, hc, qtd,
41161 + DWC_OTG_HC_XFER_XACT_ERR);
41162 + /** @todo add support for isoc release */
41163 + goto handle_nyet_done;
41167 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
41168 + goto handle_nyet_done;
41171 + hc->qh->ping_state = 1;
41172 + qtd->error_count = 0;
41174 + update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd,
41175 + DWC_OTG_HC_XFER_NYET);
41176 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41179 + * Halt the channel and re-start the transfer so the PING
41180 + * protocol will start.
41182 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
41185 + disable_hc_int(hc_regs, nyet);
41190 + * Handles a host channel babble interrupt. This handler may be called in
41191 + * either DMA mode or Slave mode.
41193 +static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd,
41195 + dwc_otg_hc_regs_t * hc_regs,
41196 + dwc_otg_qtd_t * qtd)
41198 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41199 + "Babble Error--\n", hc->hc_num);
41201 + if (hcd->core_if->dma_desc_enable) {
41202 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41203 + DWC_OTG_HC_XFER_BABBLE_ERR);
41204 + goto handle_babble_done;
41207 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
41208 + hcd->fops->complete(hcd, qtd->urb->priv,
41209 + qtd->urb, -DWC_E_OVERFLOW);
41210 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
41212 + dwc_otg_halt_status_e halt_status;
41213 + halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41214 + DWC_OTG_HC_XFER_BABBLE_ERR);
41215 + halt_channel(hcd, hc, qtd, halt_status);
41218 +handle_babble_done:
41219 + disable_hc_int(hc_regs, bblerr);
41224 + * Handles a host channel AHB error interrupt. This handler is only called in
41227 +static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd,
41229 + dwc_otg_hc_regs_t * hc_regs,
41230 + dwc_otg_qtd_t * qtd)
41232 + hcchar_data_t hcchar;
41233 + hcsplt_data_t hcsplt;
41234 + hctsiz_data_t hctsiz;
41236 + char *pipetype, *speed;
41238 + dwc_otg_hcd_urb_t *urb = qtd->urb;
41240 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41241 + "AHB Error--\n", hc->hc_num);
41243 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41244 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
41245 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41246 + hcdma = DWC_READ_REG32(&hc_regs->hcdma);
41248 + DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num);
41249 + DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
41250 + DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
41251 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
41252 + DWC_ERROR(" Device address: %d\n",
41253 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
41254 + DWC_ERROR(" Endpoint: %d, %s\n",
41255 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
41256 + (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"));
41258 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
41260 + pipetype = "CONTROL";
41263 + pipetype = "BULK";
41265 + case UE_INTERRUPT:
41266 + pipetype = "INTERRUPT";
41268 + case UE_ISOCHRONOUS:
41269 + pipetype = "ISOCHRONOUS";
41272 + pipetype = "UNKNOWN";
41276 + DWC_ERROR(" Endpoint type: %s\n", pipetype);
41278 + switch (hc->speed) {
41279 + case DWC_OTG_EP_SPEED_HIGH:
41282 + case DWC_OTG_EP_SPEED_FULL:
41285 + case DWC_OTG_EP_SPEED_LOW:
41289 + speed = "UNKNOWN";
41293 + DWC_ERROR(" Speed: %s\n", speed);
41295 + DWC_ERROR(" Max packet size: %d\n",
41296 + dwc_otg_hcd_get_mps(&urb->pipe_info));
41297 + DWC_ERROR(" Data buffer length: %d\n", urb->length);
41298 + DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n",
41299 + urb->buf, (void *)urb->dma);
41300 + DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n",
41301 + urb->setup_packet, (void *)urb->setup_dma);
41302 + DWC_ERROR(" Interval: %d\n", urb->interval);
41304 + /* Core haltes the channel for Descriptor DMA mode */
41305 + if (hcd->core_if->dma_desc_enable) {
41306 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41307 + DWC_OTG_HC_XFER_AHB_ERR);
41308 + goto handle_ahberr_done;
41311 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO);
41314 + * Force a channel halt. Don't call halt_channel because that won't
41315 + * write to the HCCHARn register in DMA mode to force the halt.
41317 + dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
41318 +handle_ahberr_done:
41319 + disable_hc_int(hc_regs, ahberr);
41324 + * Handles a host channel transaction error interrupt. This handler may be
41325 + * called in either DMA mode or Slave mode.
41327 +static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd,
41329 + dwc_otg_hc_regs_t * hc_regs,
41330 + dwc_otg_qtd_t * qtd)
41332 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41333 + "Transaction Error--\n", hc->hc_num);
41335 + if (hcd->core_if->dma_desc_enable) {
41336 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41337 + DWC_OTG_HC_XFER_XACT_ERR);
41338 + goto handle_xacterr_done;
41341 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41344 + qtd->error_count++;
41345 + if (!hc->qh->ping_state) {
41347 + update_urb_state_xfer_intr(hc, hc_regs,
41349 + DWC_OTG_HC_XFER_XACT_ERR);
41350 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41351 + if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) {
41352 + hc->qh->ping_state = 1;
41357 + * Halt the channel so the transfer can be re-started from
41358 + * the appropriate point or the PING protocol will start.
41360 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41362 + case UE_INTERRUPT:
41363 + qtd->error_count++;
41364 + if (hc->do_split && hc->complete_split) {
41365 + qtd->complete_split = 0;
41367 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41369 + case UE_ISOCHRONOUS:
41371 + dwc_otg_halt_status_e halt_status;
41373 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41374 + DWC_OTG_HC_XFER_XACT_ERR);
41376 + halt_channel(hcd, hc, qtd, halt_status);
41380 +handle_xacterr_done:
41381 + disable_hc_int(hc_regs, xacterr);
41387 + * Handles a host channel frame overrun interrupt. This handler may be called
41388 + * in either DMA mode or Slave mode.
41390 +static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd,
41392 + dwc_otg_hc_regs_t * hc_regs,
41393 + dwc_otg_qtd_t * qtd)
41395 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41396 + "Frame Overrun--\n", hc->hc_num);
41398 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41402 + case UE_INTERRUPT:
41403 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
41405 + case UE_ISOCHRONOUS:
41407 + dwc_otg_halt_status_e halt_status;
41409 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41410 + DWC_OTG_HC_XFER_FRAME_OVERRUN);
41412 + halt_channel(hcd, hc, qtd, halt_status);
41417 + disable_hc_int(hc_regs, frmovrun);
41423 + * Handles a host channel data toggle error interrupt. This handler may be
41424 + * called in either DMA mode or Slave mode.
41426 +static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd,
41428 + dwc_otg_hc_regs_t * hc_regs,
41429 + dwc_otg_qtd_t * qtd)
41431 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41432 + "Data Toggle Error--\n", hc->hc_num);
41434 + if (hc->ep_is_in) {
41435 + qtd->error_count = 0;
41437 + DWC_ERROR("Data Toggle Error on OUT transfer,"
41438 + "channel %d\n", hc->hc_num);
41441 + disable_hc_int(hc_regs, datatglerr);
41448 + * This function is for debug only. It checks that a valid halt status is set
41449 + * and that HCCHARn.chdis is clear. If there's a problem, corrective action is
41450 + * taken and a warning is issued.
41451 + * @return 1 if halt status is ok, 0 otherwise.
41453 +static inline int halt_status_ok(dwc_otg_hcd_t * hcd,
41455 + dwc_otg_hc_regs_t * hc_regs,
41456 + dwc_otg_qtd_t * qtd)
41458 + hcchar_data_t hcchar;
41459 + hctsiz_data_t hctsiz;
41460 + hcint_data_t hcint;
41461 + hcintmsk_data_t hcintmsk;
41462 + hcsplt_data_t hcsplt;
41464 + if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
41466 + * This code is here only as a check. This condition should
41467 + * never happen. Ignore the halt if it does occur.
41469 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41470 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41471 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41472 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41473 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
41475 + ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
41476 + "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
41477 + "hcint 0x%08x, hcintmsk 0x%08x, "
41478 + "hcsplt 0x%08x, qtd->complete_split %d\n", __func__,
41479 + hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32,
41480 + hcintmsk.d32, hcsplt.d32, qtd->complete_split);
41482 + DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
41483 + __func__, hc->hc_num);
41485 + clear_hc_int(hc_regs, chhltd);
41490 + * This code is here only as a check. hcchar.chdis should
41491 + * never be set when the halt interrupt occurs. Halt the
41492 + * channel again if it does occur.
41494 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41495 + if (hcchar.b.chdis) {
41496 + DWC_WARN("%s: hcchar.chdis set unexpectedly, "
41497 + "hcchar 0x%08x, trying to halt again\n",
41498 + __func__, hcchar.d32);
41499 + clear_hc_int(hc_regs, chhltd);
41500 + hc->halt_pending = 0;
41501 + halt_channel(hcd, hc, qtd, hc->halt_status);
41510 + * Handles a host Channel Halted interrupt in DMA mode. This handler
41511 + * determines the reason the channel halted and proceeds accordingly.
41513 +static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
41515 + dwc_otg_hc_regs_t * hc_regs,
41516 + dwc_otg_qtd_t * qtd)
41518 + hcint_data_t hcint;
41519 + hcintmsk_data_t hcintmsk;
41520 + int out_nak_enh = 0;
41522 + /* For core with OUT NAK enhancement, the flow for high-
41523 + * speed CONTROL/BULK OUT is handled a little differently.
41525 + if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) {
41526 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in &&
41527 + (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
41528 + hc->ep_type == DWC_OTG_EP_TYPE_BULK)) {
41533 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
41534 + (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR
41535 + && !hcd->core_if->dma_desc_enable)) {
41537 + * Just release the channel. A dequeue can happen on a
41538 + * transfer timeout. In the case of an AHB Error, the channel
41539 + * was forced to halt because there's no way to gracefully
41542 + if (hcd->core_if->dma_desc_enable)
41543 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41544 + hc->halt_status);
41546 + release_channel(hcd, hc, qtd, hc->halt_status);
41550 + /* Read the HCINTn register to determine the cause for the halt. */
41551 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41552 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41554 + if (hcint.b.xfercomp) {
41555 + /** @todo This is here because of a possible hardware bug. Spec
41556 + * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
41557 + * interrupt w/ACK bit set should occur, but I only see the
41558 + * XFERCOMP bit, even with it masked out. This is a workaround
41559 + * for that behavior. Should fix this when hardware is fixed.
41561 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
41562 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
41564 + handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
41565 + } else if (hcint.b.stall) {
41566 + handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
41567 + } else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) {
41568 + if (out_nak_enh) {
41569 + if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) {
41570 + DWC_DEBUGPL(DBG_HCD, "XactErr with NYET/NAK/ACK\n");
41571 + qtd->error_count = 0;
41573 + DWC_DEBUGPL(DBG_HCD, "XactErr without NYET/NAK/ACK\n");
41578 + * Must handle xacterr before nak or ack. Could get a xacterr
41579 + * at the same time as either of these on a BULK/CONTROL OUT
41580 + * that started with a PING. The xacterr takes precedence.
41582 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
41583 + } else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) {
41584 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
41585 + } else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) {
41586 + handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
41587 + } else if (hcint.b.bblerr) {
41588 + handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
41589 + } else if (hcint.b.frmovrun) {
41590 + handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
41591 + } else if (!out_nak_enh) {
41592 + if (hcint.b.nyet) {
41594 + * Must handle nyet before nak or ack. Could get a nyet at the
41595 + * same time as either of those on a BULK/CONTROL OUT that
41596 + * started with a PING. The nyet takes precedence.
41598 + handle_hc_nyet_intr(hcd, hc, hc_regs, qtd);
41599 + } else if (hcint.b.nak && !hcintmsk.b.nak) {
41601 + * If nak is not masked, it's because a non-split IN transfer
41602 + * is in an error state. In that case, the nak is handled by
41603 + * the nak interrupt handler, not here. Handle nak here for
41604 + * BULK/CONTROL OUT transfers, which halt on a NAK to allow
41605 + * rewinding the buffer pointer.
41607 + handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
41608 + } else if (hcint.b.ack && !hcintmsk.b.ack) {
41610 + * If ack is not masked, it's because a non-split IN transfer
41611 + * is in an error state. In that case, the ack is handled by
41612 + * the ack interrupt handler, not here. Handle ack here for
41613 + * split transfers. Start splits halt on ACK.
41615 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
41617 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
41618 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
41620 + * A periodic transfer halted with no other channel
41621 + * interrupts set. Assume it was halted by the core
41622 + * because it could not be completed in its scheduled
41627 + ("%s: Halt channel %d (assume incomplete periodic transfer)\n",
41628 + __func__, hc->hc_num);
41630 + halt_channel(hcd, hc, qtd,
41631 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
41634 + ("%s: Channel %d, DMA Mode -- ChHltd set, but reason "
41635 + "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
41636 + __func__, hc->hc_num, hcint.d32,
41637 + DWC_READ_REG32(&hcd->
41638 + core_if->core_global_regs->
41644 + DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n",
41650 + * Handles a host channel Channel Halted interrupt.
41652 + * In slave mode, this handler is called only when the driver specifically
41653 + * requests a halt. This occurs during handling other host channel interrupts
41654 + * (e.g. nak, xacterr, stall, nyet, etc.).
41656 + * In DMA mode, this is the interrupt that occurs when the core has finished
41657 + * processing a transfer on a channel. Other host channel interrupts (except
41658 + * ahberr) are disabled in DMA mode.
41660 +static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
41662 + dwc_otg_hc_regs_t * hc_regs,
41663 + dwc_otg_qtd_t * qtd)
41665 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41666 + "Channel Halted--\n", hc->hc_num);
41668 + if (hcd->core_if->dma_enable) {
41669 + handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd);
41672 + if (!halt_status_ok(hcd, hc, hc_regs, qtd)) {
41676 + release_channel(hcd, hc, qtd, hc->halt_status);
41682 +/** Handles interrupt for a specific Host Channel */
41683 +int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
41686 + hcint_data_t hcint;
41687 + hcintmsk_data_t hcintmsk;
41689 + dwc_otg_hc_regs_t *hc_regs;
41690 + dwc_otg_qtd_t *qtd;
41692 + DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num);
41694 + hc = dwc_otg_hcd->hc_ptr_array[num];
41695 + hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
41696 + qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
41698 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41699 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41700 + DWC_DEBUGPL(DBG_HCDV,
41701 + " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
41702 + hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
41703 + hcint.d32 = hcint.d32 & hcintmsk.d32;
41705 + if (!dwc_otg_hcd->core_if->dma_enable) {
41706 + if (hcint.b.chhltd && hcint.d32 != 0x2) {
41707 + hcint.b.chhltd = 0;
41711 + if (hcint.b.xfercomp) {
41713 + handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41715 + * If NYET occurred at same time as Xfer Complete, the NYET is
41716 + * handled by the Xfer Complete interrupt handler. Don't want
41717 + * to call the NYET interrupt handler in this case.
41719 + hcint.b.nyet = 0;
41721 + if (hcint.b.chhltd) {
41722 + retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41724 + if (hcint.b.ahberr) {
41725 + retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41727 + if (hcint.b.stall) {
41728 + retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41730 + if (hcint.b.nak) {
41731 + retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41733 + if (hcint.b.ack) {
41734 + retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41736 + if (hcint.b.nyet) {
41737 + retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41739 + if (hcint.b.xacterr) {
41740 + retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41742 + if (hcint.b.bblerr) {
41743 + retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41745 + if (hcint.b.frmovrun) {
41747 + handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41749 + if (hcint.b.datatglerr) {
41751 + handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41757 +#endif /* DWC_DEVICE_ONLY */
41759 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
41761 +/* ==========================================================================
41762 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
41763 + * $Revision: #20 $
41764 + * $Date: 2011/10/26 $
41765 + * $Change: 1872981 $
41767 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
41768 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
41769 + * otherwise expressly agreed to in writing between Synopsys and you.
41771 + * The Software IS NOT an item of Licensed Software or Licensed Product under
41772 + * any End User Software License Agreement or Agreement for Licensed Product
41773 + * with Synopsys or any supplement thereto. You are permitted to use and
41774 + * redistribute this Software in source and binary forms, with or without
41775 + * modification, provided that redistributions of source code must retain this
41776 + * notice. You may not view, use, disclose, copy or distribute this file or
41777 + * any information contained herein except pursuant to this license grant from
41778 + * Synopsys. If you do not agree with this notice, including the disclaimer
41779 + * below, then you are not authorized to use the Software.
41781 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
41782 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41783 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41784 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
41785 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41786 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41787 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
41788 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41789 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41790 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
41792 + * ========================================================================== */
41793 +#ifndef DWC_DEVICE_ONLY
41798 + * This file contains the implementation of the HCD. In Linux, the HCD
41799 + * implements the hc_driver API.
41801 +#include <linux/kernel.h>
41802 +#include <linux/module.h>
41803 +#include <linux/moduleparam.h>
41804 +#include <linux/init.h>
41805 +#include <linux/device.h>
41806 +#include <linux/errno.h>
41807 +#include <linux/list.h>
41808 +#include <linux/interrupt.h>
41809 +#include <linux/string.h>
41810 +#include <linux/dma-mapping.h>
41811 +#include <linux/version.h>
41812 +#include <asm/io.h>
41813 +#include <linux/usb.h>
41814 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
41815 +#include <../drivers/usb/core/hcd.h>
41817 +#include <linux/usb/hcd.h>
41820 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
41821 +#define USB_URB_EP_LINKING 1
41823 +#define USB_URB_EP_LINKING 0
41826 +#include "dwc_otg_hcd_if.h"
41827 +#include "dwc_otg_dbg.h"
41828 +#include "dwc_otg_driver.h"
41829 +#include "dwc_otg_hcd.h"
41831 + * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
41832 + * qualified with its direction (possible 32 endpoints per device).
41834 +#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
41835 + ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
41837 +static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
41839 +/** @name Linux HC Driver API Functions */
41841 +/* manage i/o requests, device state */
41842 +static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
41843 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
41844 + struct usb_host_endpoint *ep,
41846 + struct urb *urb, gfp_t mem_flags);
41848 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
41849 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
41850 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
41852 +#else /* kernels at or post 2.6.30 */
41853 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd,
41854 + struct urb *urb, int status);
41855 +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) */
41857 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
41858 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
41859 +static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
41861 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
41862 +extern int hcd_start(struct usb_hcd *hcd);
41863 +extern void hcd_stop(struct usb_hcd *hcd);
41864 +static int get_frame_number(struct usb_hcd *hcd);
41865 +extern int hub_status_data(struct usb_hcd *hcd, char *buf);
41866 +extern int hub_control(struct usb_hcd *hcd,
41868 + u16 wValue, u16 wIndex, char *buf, u16 wLength);
41870 +struct wrapper_priv_data {
41871 + dwc_otg_hcd_t *dwc_otg_hcd;
41876 +static struct hc_driver dwc_otg_hc_driver = {
41878 + .description = dwc_otg_hcd_name,
41879 + .product_desc = "DWC OTG Controller",
41880 + .hcd_priv_size = sizeof(struct wrapper_priv_data),
41882 + .irq = dwc_otg_hcd_irq,
41884 + .flags = HCD_MEMORY | HCD_USB2,
41887 + .start = hcd_start,
41890 + .stop = hcd_stop,
41892 + .urb_enqueue = dwc_otg_urb_enqueue,
41893 + .urb_dequeue = dwc_otg_urb_dequeue,
41894 + .endpoint_disable = endpoint_disable,
41895 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
41896 + .endpoint_reset = endpoint_reset,
41898 + .get_frame_number = get_frame_number,
41900 + .hub_status_data = hub_status_data,
41901 + .hub_control = hub_control,
41906 +/** Gets the dwc_otg_hcd from a struct usb_hcd */
41907 +static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
41909 + struct wrapper_priv_data *p;
41910 + p = (struct wrapper_priv_data *)(hcd->hcd_priv);
41911 + return p->dwc_otg_hcd;
41914 +/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
41915 +static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
41917 + return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
41920 +/** Gets the usb_host_endpoint associated with an URB. */
41921 +inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
41923 + struct usb_device *dev = urb->dev;
41924 + int ep_num = usb_pipeendpoint(urb->pipe);
41926 + if (usb_pipein(urb->pipe))
41927 + return dev->ep_in[ep_num];
41929 + return dev->ep_out[ep_num];
41932 +static int _disconnect(dwc_otg_hcd_t * hcd)
41934 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
41936 + usb_hcd->self.is_b_host = 0;
41940 +static int _start(dwc_otg_hcd_t * hcd)
41942 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
41944 + usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
41945 + hcd_start(usb_hcd);
41950 +static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
41951 + uint32_t * port_addr)
41953 + struct urb *urb = (struct urb *)urb_handle;
41954 + struct usb_bus *bus;
41955 +#if 1 //GRAYG - temporary
41956 + if (NULL == urb_handle)
41957 + DWC_ERROR("**** %s - NULL URB handle\n", __func__);//GRAYG
41958 + if (NULL == urb->dev)
41959 + DWC_ERROR("**** %s - URB has no device\n", __func__);//GRAYG
41960 + if (NULL == port_addr)
41961 + DWC_ERROR("**** %s - NULL port_address\n", __func__);//GRAYG
41963 + if (urb->dev->tt) {
41964 + if (NULL == urb->dev->tt->hub) {
41965 + DWC_ERROR("**** %s - (URB's transactor has no TT - giving no hub)\n",
41966 + __func__); //GRAYG
41967 + //*hub_addr = (u8)usb_pipedevice(urb->pipe); //GRAYG
41968 + *hub_addr = 0; //GRAYG
41969 + // we probably shouldn't have a transaction translator if
41970 + // there's no associated hub?
41972 + bus = hcd_to_bus(dwc_otg_hcd_to_hcd(hcd));
41973 + if (urb->dev->tt->hub == bus->root_hub)
41976 + *hub_addr = urb->dev->tt->hub->devnum;
41978 + *port_addr = urb->dev->tt->multi ? urb->dev->ttport : 1;
41981 + *port_addr = urb->dev->ttport;
41986 +static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
41988 + struct urb *urb = (struct urb *)urb_handle;
41989 + return urb->dev->speed;
41992 +static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
41994 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
41995 + return usb_hcd->self.b_hnp_enable;
41998 +static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
42001 + hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
42002 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42003 + hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
42005 + hcd_to_bus(hcd)->bandwidth_int_reqs++;
42009 +static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
42012 + hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
42013 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42014 + hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
42016 + hcd_to_bus(hcd)->bandwidth_int_reqs--;
42021 + * Sets the final status of an URB and returns it to the device driver. Any
42022 + * required cleanup of the URB is performed.
42024 +static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
42025 + dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
42027 + struct urb *urb = (struct urb *)urb_handle;
42029 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42030 + DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
42031 + __func__, urb, usb_pipedevice(urb->pipe),
42032 + usb_pipeendpoint(urb->pipe),
42033 + usb_pipein(urb->pipe) ? "IN" : "OUT", status);
42034 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42036 + for (i = 0; i < urb->number_of_packets; i++) {
42037 + DWC_PRINTF(" ISO Desc %d status: %d\n",
42038 + i, urb->iso_frame_desc[i].status);
42043 + urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
42044 + /* Convert status value. */
42045 + switch (status) {
42046 + case -DWC_E_PROTOCOL:
42047 + status = -EPROTO;
42049 + case -DWC_E_IN_PROGRESS:
42050 + status = -EINPROGRESS;
42052 + case -DWC_E_PIPE:
42058 + case -DWC_E_TIMEOUT:
42059 + status = -ETIMEDOUT;
42061 + case -DWC_E_OVERFLOW:
42062 + status = -EOVERFLOW;
42066 + DWC_PRINTF("Uknown urb status %d\n", status);
42071 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42074 + urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
42075 + for (i = 0; i < urb->number_of_packets; ++i) {
42076 + urb->iso_frame_desc[i].actual_length =
42077 + dwc_otg_hcd_urb_get_iso_desc_actual_length
42078 + (dwc_otg_urb, i);
42079 + urb->iso_frame_desc[i].status =
42080 + dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
42084 + urb->status = status;
42085 + urb->hcpriv = NULL;
42087 + if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
42088 + (urb->actual_length < urb->transfer_buffer_length)) {
42089 + urb->status = -EREMOTEIO;
42093 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
42094 + (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
42095 + struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
42097 + free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
42098 + dwc_otg_hcd_get_ep_bandwidth(hcd,
42104 + DWC_FREE(dwc_otg_urb);
42106 +#if USB_URB_EP_LINKING
42107 + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
42109 + DWC_SPINUNLOCK(hcd->lock);
42110 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42111 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
42113 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
42115 + DWC_SPINLOCK(hcd->lock);
42120 +static struct dwc_otg_hcd_function_ops hcd_fops = {
42122 + .disconnect = _disconnect,
42123 + .hub_info = _hub_info,
42125 + .complete = _complete,
42126 + .get_b_hnp_enable = _get_b_hnp_enable,
42130 + * Initializes the HCD. This function allocates memory for and initializes the
42131 + * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
42132 + * USB bus with the core and calls the hc_driver->start() function. It returns
42133 + * a negative error on failure.
42135 +int hcd_init(dwc_bus_dev_t *_dev)
42137 + struct usb_hcd *hcd = NULL;
42138 + dwc_otg_hcd_t *dwc_otg_hcd = NULL;
42139 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
42143 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev);
42145 + /* Set device flags indicating whether the HCD supports DMA. */
42146 + if (dwc_otg_is_dma_enable(otg_dev->core_if))
42147 + dmamask = DMA_BIT_MASK(32);
42151 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
42152 + dma_set_mask(&_dev->dev, dmamask);
42153 + dma_set_coherent_mask(&_dev->dev, dmamask);
42154 +#elif defined(PCI_INTERFACE)
42155 + pci_set_dma_mask(_dev, dmamask);
42156 + pci_set_consistent_dma_mask(_dev, dmamask);
42160 + * Allocate memory for the base HCD plus the DWC OTG HCD.
42161 + * Initialize the base HCD.
42163 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
42164 + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
42166 + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
42168 +// hcd->uses_new_polling = 1;
42169 +// hcd->poll_rh = 0;
42172 + retval = -ENOMEM;
42176 + hcd->regs = otg_dev->os_dep.base;
42178 + /* Initialize the DWC OTG HCD. */
42179 + dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
42180 + if (!dwc_otg_hcd) {
42183 + ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
42185 + otg_dev->hcd = dwc_otg_hcd;
42187 + if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
42191 + otg_dev->hcd->otg_dev = otg_dev;
42192 + hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
42193 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
42194 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) //version field absent later
42195 + hcd->self.otg_version = dwc_otg_get_otg_version(otg_dev->core_if);
42197 + /* Don't support SG list at this point */
42198 + hcd->self.sg_tablesize = 0;
42201 + * Finish generic HCD initialization and start the HCD. This function
42202 + * allocates the DMA buffer pool, registers the USB bus, requests the
42203 + * IRQ line, and calls hcd_start method.
42205 +#ifdef PLATFORM_INTERFACE
42206 + retval = usb_add_hcd(hcd, platform_get_irq(_dev, 0), IRQF_SHARED | IRQF_DISABLED);
42208 + retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED);
42210 + if (retval < 0) {
42214 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
42218 + usb_put_hcd(hcd);
42224 + * Removes the HCD.
42225 + * Frees memory and resources associated with the HCD and deregisters the bus.
42227 +void hcd_remove(dwc_bus_dev_t *_dev)
42229 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
42230 + dwc_otg_hcd_t *dwc_otg_hcd;
42231 + struct usb_hcd *hcd;
42233 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE otg_dev=%p\n", otg_dev);
42236 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
42240 + dwc_otg_hcd = otg_dev->hcd;
42242 + if (!dwc_otg_hcd) {
42243 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
42247 + hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
42250 + DWC_DEBUGPL(DBG_ANY,
42251 + "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
42255 + usb_remove_hcd(hcd);
42256 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
42257 + dwc_otg_hcd_remove(dwc_otg_hcd);
42258 + usb_put_hcd(hcd);
42261 +/* =========================================================================
42262 + * Linux HC Driver Functions
42263 + * ========================================================================= */
42265 +/** Initializes the DWC_otg controller and its root hub and prepares it for host
42266 + * mode operation. Activates the root port. Returns 0 on success and a negative
42267 + * error code on failure. */
42268 +int hcd_start(struct usb_hcd *hcd)
42270 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42271 + struct usb_bus *bus;
42273 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
42274 + bus = hcd_to_bus(hcd);
42276 + hcd->state = HC_STATE_RUNNING;
42277 + if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
42281 + /* Initialize and connect root hub if one is not already attached */
42282 + if (bus->root_hub) {
42283 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
42284 + /* Inform the HUB driver to resume. */
42285 + usb_hcd_resume_root_hub(hcd);
42292 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
42295 +void hcd_stop(struct usb_hcd *hcd)
42297 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42299 + dwc_otg_hcd_stop(dwc_otg_hcd);
42302 +/** Returns the current frame number. */
42303 +static int get_frame_number(struct usb_hcd *hcd)
42305 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42307 + return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
42311 +static void dump_urb_info(struct urb *urb, char *fn_name)
42313 + DWC_PRINTF("%s, urb %p\n", fn_name, urb);
42314 + DWC_PRINTF(" Device address: %d\n", usb_pipedevice(urb->pipe));
42315 + DWC_PRINTF(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
42316 + (usb_pipein(urb->pipe) ? "IN" : "OUT"));
42317 + DWC_PRINTF(" Endpoint type: %s\n", ( {
42319 + switch (usb_pipetype(urb->pipe)) {
42320 +case PIPE_CONTROL:
42321 +pipetype = "CONTROL"; break; case PIPE_BULK:
42322 +pipetype = "BULK"; break; case PIPE_INTERRUPT:
42323 +pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
42324 +pipetype = "ISOCHRONOUS"; break; default:
42325 + pipetype = "UNKNOWN"; break;};
42328 + DWC_PRINTF(" Speed: %s\n", ( {
42329 + char *speed; switch (urb->dev->speed) {
42330 +case USB_SPEED_HIGH:
42331 +speed = "HIGH"; break; case USB_SPEED_FULL:
42332 +speed = "FULL"; break; case USB_SPEED_LOW:
42333 +speed = "LOW"; break; default:
42334 + speed = "UNKNOWN"; break;};
42337 + DWC_PRINTF(" Max packet size: %d\n",
42338 + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
42339 + DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length);
42340 + DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n",
42341 + urb->transfer_buffer, (void *)urb->transfer_dma);
42342 + DWC_PRINTF(" Setup buffer: %p, Setup DMA: %p\n",
42343 + urb->setup_packet, (void *)urb->setup_dma);
42344 + DWC_PRINTF(" Interval: %d\n", urb->interval);
42345 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42347 + for (i = 0; i < urb->number_of_packets; i++) {
42348 + DWC_PRINTF(" ISO Desc %d:\n", i);
42349 + DWC_PRINTF(" offset: %d, length %d\n",
42350 + urb->iso_frame_desc[i].offset,
42351 + urb->iso_frame_desc[i].length);
42357 +/** Starts processing a USB transfer request specified by a USB Request Block
42358 + * (URB). mem_flags indicates the type of memory allocation to use while
42359 + * processing this URB. */
42360 +static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
42361 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42362 + struct usb_host_endpoint *ep,
42364 + struct urb *urb, gfp_t mem_flags)
42367 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
42368 + struct usb_host_endpoint *ep = urb->ep;
42370 +#if USB_URB_EP_LINKING
42371 + dwc_irqflags_t irqflags;
42373 + void **ref_ep_hcpriv = &ep->hcpriv;
42374 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42375 + dwc_otg_hcd_urb_t *dwc_otg_urb;
42377 + int alloc_bandwidth = 0;
42378 + uint8_t ep_type = 0;
42379 + uint32_t flags = 0;
42383 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42384 + dump_urb_info(urb, "dwc_otg_urb_enqueue");
42388 + if (!urb->transfer_buffer && urb->transfer_buffer_length)
42391 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
42392 + || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
42393 + if (!dwc_otg_hcd_is_bandwidth_allocated
42394 + (dwc_otg_hcd, ref_ep_hcpriv)) {
42395 + alloc_bandwidth = 1;
42399 + switch (usb_pipetype(urb->pipe)) {
42400 + case PIPE_CONTROL:
42401 + ep_type = USB_ENDPOINT_XFER_CONTROL;
42403 + case PIPE_ISOCHRONOUS:
42404 + ep_type = USB_ENDPOINT_XFER_ISOC;
42407 + ep_type = USB_ENDPOINT_XFER_BULK;
42409 + case PIPE_INTERRUPT:
42410 + ep_type = USB_ENDPOINT_XFER_INT;
42413 + DWC_WARN("Wrong EP type - %d\n", usb_pipetype(urb->pipe));
42416 + /* # of packets is often 0 - do we really need to call this then? */
42417 + dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
42418 + urb->number_of_packets,
42419 + mem_flags == GFP_ATOMIC ? 1 : 0);
42421 + if(dwc_otg_urb == NULL)
42424 + urb->hcpriv = dwc_otg_urb;
42425 + if (!dwc_otg_urb && urb->number_of_packets)
42428 + dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
42429 + usb_pipeendpoint(urb->pipe), ep_type,
42430 + usb_pipein(urb->pipe),
42431 + usb_maxpacket(urb->dev, urb->pipe,
42432 + !(usb_pipein(urb->pipe))));
42434 + buf = urb->transfer_buffer;
42435 + if (hcd->self.uses_dma) {
42437 + * Calculate virtual address from physical address,
42438 + * because some class driver may not fill transfer_buffer.
42439 + * In Buffer DMA mode virual address is used,
42440 + * when handling non DWORD aligned buffers.
42442 + //buf = phys_to_virt(urb->transfer_dma);
42443 + // DMA addresses are bus addresses not physical addresses!
42444 + buf = dma_to_virt(&urb->dev->dev, urb->transfer_dma);
42447 + if (!(urb->transfer_flags & URB_NO_INTERRUPT))
42448 + flags |= URB_GIVEBACK_ASAP;
42449 + if (urb->transfer_flags & URB_ZERO_PACKET)
42450 + flags |= URB_SEND_ZERO_PACKET;
42452 + dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
42453 + urb->transfer_dma,
42454 + urb->transfer_buffer_length,
42455 + urb->setup_packet,
42456 + urb->setup_dma, flags, urb->interval);
42458 + for (i = 0; i < urb->number_of_packets; ++i) {
42459 + dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
42461 + iso_frame_desc[i].offset,
42463 + iso_frame_desc[i].length);
42466 +#if USB_URB_EP_LINKING
42467 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
42468 + retval = usb_hcd_link_urb_to_ep(hcd, urb);
42469 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
42473 + retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
42474 + /*(dwc_otg_qh_t **)*/
42476 + mem_flags == GFP_ATOMIC ? 1 : 0);
42477 + if (0 == retval) {
42478 + if (alloc_bandwidth) {
42479 + allocate_bus_bandwidth(hcd,
42480 + dwc_otg_hcd_get_ep_bandwidth(
42481 + dwc_otg_hcd, *ref_ep_hcpriv),
42485 +#if USB_URB_EP_LINKING
42486 + dwc_irqflags_t irqflags;
42487 + DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
42488 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
42489 + usb_hcd_unlink_urb_from_ep(hcd, urb);
42490 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
42492 + if (retval == -DWC_E_NO_DEVICE) {
42493 + retval = -ENODEV;
42500 +/** Aborts/cancels a USB transfer request. Always returns 0 to indicate
42502 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42503 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
42505 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
42508 + dwc_irqflags_t flags;
42509 + dwc_otg_hcd_t *dwc_otg_hcd;
42512 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
42514 + dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42517 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42518 + dump_urb_info(urb, "dwc_otg_urb_dequeue");
42522 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
42523 + rc = usb_hcd_check_unlink_urb(hcd, urb, status);
42525 + if(urb->hcpriv != NULL) {
42526 + dwc_otg_hcd_urb_dequeue(dwc_otg_hcd,
42527 + (dwc_otg_hcd_urb_t *)urb->hcpriv);
42529 + DWC_FREE(urb->hcpriv);
42530 + urb->hcpriv = NULL;
42535 + /* Higher layer software sets URB status. */
42536 +#if USB_URB_EP_LINKING
42537 + usb_hcd_unlink_urb_from_ep(hcd, urb);
42539 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42540 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42541 + usb_hcd_giveback_urb(hcd, urb);
42543 + usb_hcd_giveback_urb(hcd, urb, status);
42545 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42546 + DWC_PRINTF("Called usb_hcd_giveback_urb() \n");
42547 + DWC_PRINTF(" 1urb->status = %d\n", urb->status);
42549 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue OK\n");
42551 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42552 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue failed - rc %d\n",
42559 +/* Frees resources in the DWC_otg controller related to a given endpoint. Also
42560 + * clears state in the HCD related to the endpoint. Any URBs for the endpoint
42561 + * must already be dequeued. */
42562 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
42564 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42566 + DWC_DEBUGPL(DBG_HCD,
42567 + "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
42568 + "endpoint=%d\n", ep->desc.bEndpointAddress,
42569 + dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
42570 + dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
42571 + ep->hcpriv = NULL;
42574 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
42575 +/* Resets endpoint specific parameter values, in current version used to reset
42576 + * the data toggle(as a WA). This function can be called from usb_clear_halt routine */
42577 +static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
42579 + dwc_irqflags_t flags;
42580 + struct usb_device *udev = NULL;
42581 + int epnum = usb_endpoint_num(&ep->desc);
42582 + int is_out = usb_endpoint_dir_out(&ep->desc);
42583 + int is_control = usb_endpoint_xfer_control(&ep->desc);
42584 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42585 + struct device *dev = DWC_OTG_OS_GETDEV(dwc_otg_hcd->otg_dev->os_dep);
42588 + udev = to_usb_device(dev);
42592 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum);
42594 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
42595 + usb_settoggle(udev, epnum, is_out, 0);
42597 + usb_settoggle(udev, epnum, !is_out, 0);
42599 + if (ep->hcpriv) {
42600 + dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
42602 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42606 +/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
42607 + * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
42610 + * This function is called by the USB core when an interrupt occurs */
42611 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
42613 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42614 + int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
42615 + if (retval != 0) {
42616 + S3C2410X_CLEAR_EINTPEND();
42618 + return IRQ_RETVAL(retval);
42621 +/** Creates Status Change bitmap for the root hub and root port. The bitmap is
42622 + * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
42623 + * is the status change indicator for the single root port. Returns 1 if either
42624 + * change indicator is 1, otherwise returns 0. */
42625 +int hub_status_data(struct usb_hcd *hcd, char *buf)
42627 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42630 + buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
42632 + return (buf[0] != 0);
42635 +/** Handles hub class-specific requests. */
42636 +int hub_control(struct usb_hcd *hcd,
42637 + u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
42641 + retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
42642 + typeReq, wValue, wIndex, buf, wLength);
42644 + switch (retval) {
42645 + case -DWC_E_INVALID:
42646 + retval = -EINVAL;
42653 +#endif /* DWC_DEVICE_ONLY */
42655 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
42657 +/* ==========================================================================
42658 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
42659 + * $Revision: #44 $
42660 + * $Date: 2011/10/26 $
42661 + * $Change: 1873028 $
42663 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
42664 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
42665 + * otherwise expressly agreed to in writing between Synopsys and you.
42667 + * The Software IS NOT an item of Licensed Software or Licensed Product under
42668 + * any End User Software License Agreement or Agreement for Licensed Product
42669 + * with Synopsys or any supplement thereto. You are permitted to use and
42670 + * redistribute this Software in source and binary forms, with or without
42671 + * modification, provided that redistributions of source code must retain this
42672 + * notice. You may not view, use, disclose, copy or distribute this file or
42673 + * any information contained herein except pursuant to this license grant from
42674 + * Synopsys. If you do not agree with this notice, including the disclaimer
42675 + * below, then you are not authorized to use the Software.
42677 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
42678 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42679 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42680 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
42681 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42682 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
42683 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
42684 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42685 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42686 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
42688 + * ========================================================================== */
42689 +#ifndef DWC_DEVICE_ONLY
42694 + * This file contains the functions to manage Queue Heads and Queue
42695 + * Transfer Descriptors.
42698 +#include "dwc_otg_hcd.h"
42699 +#include "dwc_otg_regs.h"
42701 +extern bool microframe_schedule;
42704 + * Free each QTD in the QH's QTD-list then free the QH. QH should already be
42705 + * removed from a list. QTD list should already be empty if called from URB
42708 + * @param hcd HCD instance.
42709 + * @param qh The QH to free.
42711 +void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
42713 + dwc_otg_qtd_t *qtd, *qtd_tmp;
42714 + dwc_irqflags_t flags;
42716 + /* Free each QTD in the QTD list */
42717 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
42718 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
42719 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
42720 + dwc_otg_hcd_qtd_free(qtd);
42723 + if (hcd->core_if->dma_desc_enable) {
42724 + dwc_otg_hcd_qh_free_ddma(hcd, qh);
42725 + } else if (qh->dw_align_buf) {
42726 + uint32_t buf_size;
42727 + if (qh->ep_type == UE_ISOCHRONOUS) {
42730 + buf_size = hcd->core_if->core_params->max_transfer_size;
42732 + DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
42736 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
42740 +#define BitStuffTime(bytecount) ((8 * 7* bytecount) / 6)
42741 +#define HS_HOST_DELAY 5 /* nanoseconds */
42742 +#define FS_LS_HOST_DELAY 1000 /* nanoseconds */
42743 +#define HUB_LS_SETUP 333 /* nanoseconds */
42744 +#define NS_TO_US(ns) ((ns + 500) / 1000)
42745 + /* convert & round nanoseconds to microseconds */
42747 +static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
42749 + unsigned long retval;
42752 + case USB_SPEED_HIGH:
42755 + ((38 * 8 * 2083) +
42756 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
42760 + ((55 * 8 * 2083) +
42761 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
42765 + case USB_SPEED_FULL:
42768 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
42770 + retval = 7268 + FS_LS_HOST_DELAY + retval;
42772 + retval = 6265 + FS_LS_HOST_DELAY + retval;
42776 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
42777 + retval = 9107 + FS_LS_HOST_DELAY + retval;
42780 + case USB_SPEED_LOW:
42783 + (67667 * (31 + 10 * BitStuffTime(bytecount))) /
42786 + 64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
42790 + (66700 * (31 + 10 * BitStuffTime(bytecount))) /
42793 + 64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
42798 + DWC_WARN("Unknown device speed\n");
42802 + return NS_TO_US(retval);
42806 + * Initializes a QH structure.
42808 + * @param hcd The HCD state structure for the DWC OTG controller.
42809 + * @param qh The QH to init.
42810 + * @param urb Holds the information about the device/endpoint that we need
42811 + * to initialize the QH.
42813 +#define SCHEDULE_SLOP 10
42814 +void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
42816 + char *speed, *type;
42818 + uint32_t hub_addr, hub_port;
42820 + dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
42822 + /* Initialize QH */
42823 + qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
42824 + qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
42826 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
42827 + qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
42828 + DWC_CIRCLEQ_INIT(&qh->qtd_list);
42829 + DWC_LIST_INIT(&qh->qh_list_entry);
42830 + qh->channel = NULL;
42832 + /* FS/LS Enpoint on HS Hub
42833 + * NOT virtual root hub */
42834 + dev_speed = hcd->fops->speed(hcd, urb->priv);
42836 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
42837 + qh->do_split = 0;
42838 + if (microframe_schedule)
42839 + qh->speed = dev_speed;
42842 + if (((dev_speed == USB_SPEED_LOW) ||
42843 + (dev_speed == USB_SPEED_FULL)) &&
42844 + (hub_addr != 0 && hub_addr != 1)) {
42845 + DWC_DEBUGPL(DBG_HCD,
42846 + "QH init: EP %d: TT found at hub addr %d, for port %d\n",
42847 + dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
42849 + qh->do_split = 1;
42852 + if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
42853 + /* Compute scheduling parameters once and save them. */
42854 + hprt0_data_t hprt;
42856 + /** @todo Account for split transfers in the bus time. */
42858 + dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
42861 + calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
42862 + qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
42864 + /* Start in a slightly future (micro)frame. */
42865 + qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
42867 + qh->interval = urb->interval;
42870 + /* Increase interrupt polling rate for debugging. */
42871 + if (qh->ep_type == UE_INTERRUPT) {
42872 + qh->interval = 8;
42875 + hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
42876 + if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
42877 + ((dev_speed == USB_SPEED_LOW) ||
42878 + (dev_speed == USB_SPEED_FULL))) {
42879 + qh->interval *= 8;
42880 + qh->sched_frame |= 0x7;
42881 + qh->start_split_frame = qh->sched_frame;
42886 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
42887 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", qh);
42888 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n",
42889 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
42890 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n",
42891 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
42892 + dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
42893 + switch (dev_speed) {
42894 + case USB_SPEED_LOW:
42895 + qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
42898 + case USB_SPEED_FULL:
42899 + qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
42902 + case USB_SPEED_HIGH:
42903 + qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
42910 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", speed);
42912 + switch (qh->ep_type) {
42913 + case UE_ISOCHRONOUS:
42914 + type = "isochronous";
42916 + case UE_INTERRUPT:
42917 + type = "interrupt";
42920 + type = "control";
42930 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", type);
42933 + if (qh->ep_type == UE_INTERRUPT) {
42934 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
42936 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
42944 + * This function allocates and initializes a QH.
42946 + * @param hcd The HCD state structure for the DWC OTG controller.
42947 + * @param urb Holds the information about the device/endpoint that we need
42948 + * to initialize the QH.
42949 + * @param atomic_alloc Flag to do atomic allocation if needed
42951 + * @return Returns pointer to the newly allocated QH, or NULL on error. */
42952 +dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
42953 + dwc_otg_hcd_urb_t * urb, int atomic_alloc)
42955 + dwc_otg_qh_t *qh;
42957 + /* Allocate memory */
42958 + /** @todo add memflags argument */
42959 + qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
42960 + if (qh == NULL) {
42961 + DWC_ERROR("qh allocation failed");
42965 + qh_init(hcd, qh, urb);
42967 + if (hcd->core_if->dma_desc_enable
42968 + && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
42969 + dwc_otg_hcd_qh_free(hcd, qh);
42976 +/* microframe_schedule=0 start */
42979 + * Checks that a channel is available for a periodic transfer.
42981 + * @return 0 if successful, negative error code otherise.
42983 +static int periodic_channel_available(dwc_otg_hcd_t * hcd)
42986 + * Currently assuming that there is a dedicated host channnel for each
42987 + * periodic transaction plus at least one host channel for
42988 + * non-periodic transactions.
42991 + int num_channels;
42993 + num_channels = hcd->core_if->core_params->host_channels;
42994 + if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
42995 + && (hcd->periodic_channels < num_channels - 1)) {
42998 + DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
42999 + __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels); //NOTICE
43000 + status = -DWC_E_NO_SPACE;
43007 + * Checks that there is sufficient bandwidth for the specified QH in the
43008 + * periodic schedule. For simplicity, this calculation assumes that all the
43009 + * transfers in the periodic schedule may occur in the same (micro)frame.
43011 + * @param hcd The HCD state structure for the DWC OTG controller.
43012 + * @param qh QH containing periodic bandwidth required.
43014 + * @return 0 if successful, negative error code otherwise.
43016 +static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43019 + int16_t max_claimed_usecs;
43023 + if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
43025 + * High speed mode.
43026 + * Max periodic usecs is 80% x 125 usec = 100 usec.
43029 + max_claimed_usecs = 100 - qh->usecs;
43032 + * Full speed mode.
43033 + * Max periodic usecs is 90% x 1000 usec = 900 usec.
43035 + max_claimed_usecs = 900 - qh->usecs;
43038 + if (hcd->periodic_usecs > max_claimed_usecs) {
43039 + DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs); //NOTICE
43040 + status = -DWC_E_NO_SPACE;
43046 +/* microframe_schedule=0 end */
43049 + * Microframe scheduler
43050 + * track the total use in hcd->frame_usecs
43051 + * keep each qh use in qh->frame_usecs
43052 + * when surrendering the qh then donate the time back
43054 +const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 };
43057 + * called from dwc_otg_hcd.c:dwc_otg_hcd_init
43059 +int init_hcd_usecs(dwc_otg_hcd_t *_hcd)
43062 + for (i=0; i<8; i++) {
43063 + _hcd->frame_usecs[i] = max_uframe_usecs[i];
43068 +static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43071 + unsigned short utime;
43077 + utime = _qh->usecs;
43081 + while (done == 0) {
43082 + /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */
43083 + if (utime <= _hcd->frame_usecs[i]) {
43084 + _hcd->frame_usecs[i] -= utime;
43085 + _qh->frame_usecs[i] += utime;
43102 + * use this for FS apps that can span multiple uframes
43104 +static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43108 + unsigned short utime;
43112 + unsigned short xtime;
43115 + utime = _qh->usecs;
43120 + while (done == 0) {
43121 + if(_hcd->frame_usecs[i] <= 0) {
43131 + * we need n consecutive slots
43132 + * so use j as a start slot j plus j+1 must be enough time (for now)
43134 + xtime= _hcd->frame_usecs[i];
43135 + for (j = i+1 ; j < 8 ; j++ ) {
43137 + * if we add this frame remaining time to xtime we may
43138 + * be OK, if not we need to test j for a complete frame
43140 + if ((xtime+_hcd->frame_usecs[j]) < utime) {
43141 + if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) {
43147 + if (xtime >= utime) {
43149 + j = 8; /* stop loop with a good value ret */
43152 + /* add the frame time to x time */
43153 + xtime += _hcd->frame_usecs[j];
43154 + /* we must have a fully available next frame or break */
43155 + if ((xtime < utime)
43156 + && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) {
43158 + j = 8; /* stop loop with a bad value ret */
43164 + for (j = i; (t_left>0) && (j < 8); j++ ) {
43165 + t_left -= _hcd->frame_usecs[j];
43166 + if ( t_left <= 0 ) {
43167 + _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left;
43168 + _hcd->frame_usecs[j]= -t_left;
43172 + _qh->frame_usecs[j] += _hcd->frame_usecs[j];
43173 + _hcd->frame_usecs[j] = 0;
43187 +static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43192 + if (_qh->speed == USB_SPEED_HIGH) {
43193 + /* if this is a hs transaction we need a full frame */
43194 + ret = find_single_uframe(_hcd, _qh);
43196 + /* if this is a fs transaction we may need a sequence of frames */
43197 + ret = find_multi_uframe(_hcd, _qh);
43203 + * Checks that the max transfer size allowed in a host channel is large enough
43204 + * to handle the maximum data transfer in a single (micro)frame for a periodic
43207 + * @param hcd The HCD state structure for the DWC OTG controller.
43208 + * @param qh QH for a periodic endpoint.
43210 + * @return 0 if successful, negative error code otherwise.
43212 +static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43215 + uint32_t max_xfer_size;
43216 + uint32_t max_channel_xfer_size;
43220 + max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
43221 + max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
43223 + if (max_xfer_size > max_channel_xfer_size) {
43224 + DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
43225 + __func__, max_xfer_size, max_channel_xfer_size); //NOTICE
43226 + status = -DWC_E_NO_SPACE;
43233 + * Schedules an interrupt or isochronous transfer in the periodic schedule.
43235 + * @param hcd The HCD state structure for the DWC OTG controller.
43236 + * @param qh QH for the periodic transfer. The QH should already contain the
43237 + * scheduling information.
43239 + * @return 0 if successful, negative error code otherwise.
43241 +static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43245 + if (microframe_schedule) {
43247 + status = find_uframe(hcd, qh);
43249 + if (status == 0) {
43253 + frame = status-1;
43256 + /* Set the new frame up */
43257 + if (frame > -1) {
43258 + qh->sched_frame &= ~0x7;
43259 + qh->sched_frame |= (frame & 7);
43262 + if (status != -1)
43265 + status = periodic_channel_available(hcd);
43267 + DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE
43271 + status = check_periodic_bandwidth(hcd, qh);
43274 + DWC_INFO("%s: Insufficient periodic bandwidth for "
43275 + "periodic transfer.\n", __func__);
43278 + status = check_max_xfer_size(hcd, qh);
43280 + DWC_INFO("%s: Channel max transfer size too small "
43281 + "for periodic transfer.\n", __func__);
43285 + if (hcd->core_if->dma_desc_enable) {
43286 + /* Don't rely on SOF and start in ready schedule */
43287 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
43290 + /* Always start in the inactive schedule. */
43291 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
43294 + if (!microframe_schedule) {
43295 + /* Reserve the periodic channel. */
43296 + hcd->periodic_channels++;
43299 + /* Update claimed usecs per (micro)frame. */
43300 + hcd->periodic_usecs += qh->usecs;
43306 + * This function adds a QH to either the non periodic or periodic schedule if
43307 + * it is not already in the schedule. If the QH is already in the schedule, no
43308 + * action is taken.
43310 + * @return 0 if successful, negative error code otherwise.
43312 +int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43315 + gintmsk_data_t intr_mask = {.d32 = 0 };
43317 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
43318 + /* QH already in a schedule. */
43322 + /* Add the new QH to the appropriate schedule */
43323 + if (dwc_qh_is_non_per(qh)) {
43324 + /* Always start in the inactive schedule. */
43325 + DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
43326 + &qh->qh_list_entry);
43328 + status = schedule_periodic(hcd, qh);
43329 + if ( !hcd->periodic_qh_count ) {
43330 + intr_mask.b.sofintr = 1;
43331 + DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
43332 + intr_mask.d32, intr_mask.d32);
43334 + hcd->periodic_qh_count++;
43341 + * Removes an interrupt or isochronous transfer from the periodic schedule.
43343 + * @param hcd The HCD state structure for the DWC OTG controller.
43344 + * @param qh QH for the periodic transfer.
43346 +static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43349 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
43351 + /* Update claimed usecs per (micro)frame. */
43352 + hcd->periodic_usecs -= qh->usecs;
43354 + if (!microframe_schedule) {
43355 + /* Release the periodic channel reservation. */
43356 + hcd->periodic_channels--;
43358 + for (i = 0; i < 8; i++) {
43359 + hcd->frame_usecs[i] += qh->frame_usecs[i];
43360 + qh->frame_usecs[i] = 0;
43366 + * Removes a QH from either the non-periodic or periodic schedule. Memory is
43369 + * @param hcd The HCD state structure.
43370 + * @param qh QH to remove from schedule. */
43371 +void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43373 + gintmsk_data_t intr_mask = {.d32 = 0 };
43375 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
43376 + /* QH is not in a schedule. */
43380 + if (dwc_qh_is_non_per(qh)) {
43381 + if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
43382 + hcd->non_periodic_qh_ptr =
43383 + hcd->non_periodic_qh_ptr->next;
43385 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
43387 + deschedule_periodic(hcd, qh);
43388 + hcd->periodic_qh_count--;
43389 + if( !hcd->periodic_qh_count ) {
43390 + intr_mask.b.sofintr = 1;
43391 + DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
43392 + intr_mask.d32, 0);
43398 + * Deactivates a QH. For non-periodic QHs, removes the QH from the active
43399 + * non-periodic schedule. The QH is added to the inactive non-periodic
43400 + * schedule if any QTDs are still attached to the QH.
43402 + * For periodic QHs, the QH is removed from the periodic queued schedule. If
43403 + * there are any QTDs still attached to the QH, the QH is added to either the
43404 + * periodic inactive schedule or the periodic ready schedule and its next
43405 + * scheduled frame is calculated. The QH is placed in the ready schedule if
43406 + * the scheduled frame has been reached already. Otherwise it's placed in the
43407 + * inactive schedule. If there are no QTDs attached to the QH, the QH is
43408 + * completely removed from the periodic schedule.
43410 +void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
43411 + int sched_next_periodic_split)
43413 + if (dwc_qh_is_non_per(qh)) {
43414 + dwc_otg_hcd_qh_remove(hcd, qh);
43415 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
43416 + /* Add back to inactive non-periodic schedule. */
43417 + dwc_otg_hcd_qh_add(hcd, qh);
43420 + uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
43422 + if (qh->do_split) {
43423 + /* Schedule the next continuing periodic split transfer */
43424 + if (sched_next_periodic_split) {
43426 + qh->sched_frame = frame_number;
43427 + if (dwc_frame_num_le(frame_number,
43428 + dwc_frame_num_inc
43429 + (qh->start_split_frame,
43432 + * Allow one frame to elapse after start
43433 + * split microframe before scheduling
43434 + * complete split, but DONT if we are
43435 + * doing the next start split in the
43436 + * same frame for an ISOC out.
43438 + if ((qh->ep_type != UE_ISOCHRONOUS) ||
43439 + (qh->ep_is_in != 0)) {
43440 + qh->sched_frame =
43441 + dwc_frame_num_inc(qh->sched_frame, 1);
43445 + qh->sched_frame =
43446 + dwc_frame_num_inc(qh->start_split_frame,
43448 + if (dwc_frame_num_le
43449 + (qh->sched_frame, frame_number)) {
43450 + qh->sched_frame = frame_number;
43452 + qh->sched_frame |= 0x7;
43453 + qh->start_split_frame = qh->sched_frame;
43456 + qh->sched_frame =
43457 + dwc_frame_num_inc(qh->sched_frame, qh->interval);
43458 + if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
43459 + qh->sched_frame = frame_number;
43463 + if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
43464 + dwc_otg_hcd_qh_remove(hcd, qh);
43467 + * Remove from periodic_sched_queued and move to
43468 + * appropriate queue.
43470 + if ((microframe_schedule && dwc_frame_num_le(qh->sched_frame, frame_number)) ||
43471 + (!microframe_schedule && qh->sched_frame == frame_number)) {
43472 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
43473 + &qh->qh_list_entry);
43475 + DWC_LIST_MOVE_HEAD
43476 + (&hcd->periodic_sched_inactive,
43477 + &qh->qh_list_entry);
43484 + * This function allocates and initializes a QTD.
43486 + * @param urb The URB to create a QTD from. Each URB-QTD pair will end up
43487 + * pointing to each other so each pair should have a unique correlation.
43488 + * @param atomic_alloc Flag to do atomic alloc if needed
43490 + * @return Returns pointer to the newly allocated QTD, or NULL on error. */
43491 +dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
43493 + dwc_otg_qtd_t *qtd;
43495 + qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
43496 + if (qtd == NULL) {
43500 + dwc_otg_hcd_qtd_init(qtd, urb);
43505 + * Initializes a QTD structure.
43507 + * @param qtd The QTD to initialize.
43508 + * @param urb The URB to use for initialization. */
43509 +void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
43511 + dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
43513 + if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
43515 + * The only time the QTD data toggle is used is on the data
43516 + * phase of control transfers. This phase always starts with
43519 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
43520 + qtd->control_phase = DWC_OTG_CONTROL_SETUP;
43523 + /* start split */
43524 + qtd->complete_split = 0;
43525 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
43526 + qtd->isoc_split_offset = 0;
43527 + qtd->in_process = 0;
43529 + /* Store the qtd ptr in the urb to reference what QTD. */
43535 + * This function adds a QTD to the QTD-list of a QH. It will find the correct
43536 + * QH to place the QTD into. If it does not find a QH, then it will create a
43537 + * new QH. If the QH to which the QTD is added is not currently scheduled, it
43538 + * is placed into the proper schedule based on its EP type.
43540 + * @param[in] qtd The QTD to add
43541 + * @param[in] hcd The DWC HCD structure
43542 + * @param[out] qh out parameter to return queue head
43543 + * @param atomic_alloc Flag to do atomic alloc if needed
43545 + * @return 0 if successful, negative error code otherwise.
43547 +int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
43548 + dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
43551 + dwc_irqflags_t flags;
43553 + dwc_otg_hcd_urb_t *urb = qtd->urb;
43556 + * Get the QH which holds the QTD-list to insert to. Create QH if it
43559 + if (*qh == NULL) {
43560 + *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
43561 + if (*qh == NULL) {
43566 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
43567 + retval = dwc_otg_hcd_qh_add(hcd, *qh);
43568 + if (retval == 0) {
43569 + DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
43572 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
43579 +#endif /* DWC_DEVICE_ONLY */
43581 +++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
43583 +#ifndef _DWC_OS_DEP_H_
43584 +#define _DWC_OS_DEP_H_
43589 + * This file contains OS dependent structures.
43593 +#include <linux/kernel.h>
43594 +#include <linux/module.h>
43595 +#include <linux/moduleparam.h>
43596 +#include <linux/init.h>
43597 +#include <linux/device.h>
43598 +#include <linux/errno.h>
43599 +#include <linux/types.h>
43600 +#include <linux/slab.h>
43601 +#include <linux/list.h>
43602 +#include <linux/interrupt.h>
43603 +#include <linux/ctype.h>
43604 +#include <linux/string.h>
43605 +#include <linux/dma-mapping.h>
43606 +#include <linux/jiffies.h>
43607 +#include <linux/delay.h>
43608 +#include <linux/timer.h>
43609 +#include <linux/workqueue.h>
43610 +#include <linux/stat.h>
43611 +#include <linux/pci.h>
43613 +#include <linux/version.h>
43615 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
43616 +# include <linux/irq.h>
43619 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
43620 +# include <linux/usb/ch9.h>
43622 +# include <linux/usb_ch9.h>
43625 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
43626 +# include <linux/usb/gadget.h>
43628 +# include <linux/usb_gadget.h>
43631 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
43632 +# include <asm/irq.h>
43635 +#ifdef PCI_INTERFACE
43636 +# include <asm/io.h>
43639 +#ifdef LM_INTERFACE
43640 +# include <asm/unaligned.h>
43641 +# include <asm/sizes.h>
43642 +# include <asm/param.h>
43643 +# include <asm/io.h>
43644 +# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
43645 +# include <asm/arch/hardware.h>
43646 +# include <asm/arch/lm.h>
43647 +# include <asm/arch/irqs.h>
43648 +# include <asm/arch/regs-irq.h>
43650 +/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure -
43651 + here we assume that the machine architecture provides definitions
43652 + in its own header
43654 +# include <mach/lm.h>
43655 +# include <mach/hardware.h>
43659 +#ifdef PLATFORM_INTERFACE
43660 +#include <linux/platform_device.h>
43661 +#include <asm/mach/map.h>
43664 +/** The OS page size */
43665 +#define DWC_OS_PAGE_SIZE PAGE_SIZE
43667 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
43668 +typedef int gfp_t;
43671 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
43672 +# define IRQF_SHARED SA_SHIRQ
43675 +typedef struct os_dependent {
43676 + /** Base address returned from ioremap() */
43679 + /** Register offset for Diagnostic API */
43680 + uint32_t reg_offset;
43682 +#ifdef LM_INTERFACE
43683 + struct lm_device *lmdev;
43684 +#elif defined(PCI_INTERFACE)
43685 + struct pci_dev *pcidev;
43687 + /** Start address of a PCI region */
43688 + resource_size_t rsrc_start;
43690 + /** Length address of a PCI region */
43691 + resource_size_t rsrc_len;
43692 +#elif defined(PLATFORM_INTERFACE)
43693 + struct platform_device *platformdev;
43698 +#ifdef __cplusplus
43704 +/* Type for the our device on the chosen bus */
43705 +#if defined(LM_INTERFACE)
43706 +typedef struct lm_device dwc_bus_dev_t;
43707 +#elif defined(PCI_INTERFACE)
43708 +typedef struct pci_dev dwc_bus_dev_t;
43709 +#elif defined(PLATFORM_INTERFACE)
43710 +typedef struct platform_device dwc_bus_dev_t;
43713 +/* Helper macro to retrieve drvdata from the device on the chosen bus */
43714 +#if defined(LM_INTERFACE)
43715 +#define DWC_OTG_BUSDRVDATA(_dev) lm_get_drvdata(_dev)
43716 +#elif defined(PCI_INTERFACE)
43717 +#define DWC_OTG_BUSDRVDATA(_dev) pci_get_drvdata(_dev)
43718 +#elif defined(PLATFORM_INTERFACE)
43719 +#define DWC_OTG_BUSDRVDATA(_dev) platform_get_drvdata(_dev)
43723 + * Helper macro returning the otg_device structure of a given struct device
43725 + * c.f. static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
43727 +#ifdef LM_INTERFACE
43728 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43729 + struct lm_device *lm_dev = \
43730 + container_of(_dev, struct lm_device, dev); \
43731 + _var = lm_get_drvdata(lm_dev); \
43734 +#elif defined(PCI_INTERFACE)
43735 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43736 + _var = dev_get_drvdata(_dev); \
43739 +#elif defined(PLATFORM_INTERFACE)
43740 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43741 + struct platform_device *platform_dev = \
43742 + container_of(_dev, struct platform_device, dev); \
43743 + _var = platform_get_drvdata(platform_dev); \
43749 + * Helper macro returning the struct dev of the given struct os_dependent
43751 + * c.f. static struct device *dwc_otg_getdev(struct os_dependent *osdep)
43753 +#ifdef LM_INTERFACE
43754 +#define DWC_OTG_OS_GETDEV(_osdep) \
43755 + ((_osdep).lmdev == NULL? NULL: &(_osdep).lmdev->dev)
43756 +#elif defined(PCI_INTERFACE)
43757 +#define DWC_OTG_OS_GETDEV(_osdep) \
43758 + ((_osdep).pci_dev == NULL? NULL: &(_osdep).pci_dev->dev)
43759 +#elif defined(PLATFORM_INTERFACE)
43760 +#define DWC_OTG_OS_GETDEV(_osdep) \
43761 + ((_osdep).platformdev == NULL? NULL: &(_osdep).platformdev->dev)
43767 +#endif /* _DWC_OS_DEP_H_ */
43769 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.c
43771 +/* ==========================================================================
43772 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
43773 + * $Revision: #101 $
43774 + * $Date: 2012/08/10 $
43775 + * $Change: 2047372 $
43777 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
43778 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
43779 + * otherwise expressly agreed to in writing between Synopsys and you.
43781 + * The Software IS NOT an item of Licensed Software or Licensed Product under
43782 + * any End User Software License Agreement or Agreement for Licensed Product
43783 + * with Synopsys or any supplement thereto. You are permitted to use and
43784 + * redistribute this Software in source and binary forms, with or without
43785 + * modification, provided that redistributions of source code must retain this
43786 + * notice. You may not view, use, disclose, copy or distribute this file or
43787 + * any information contained herein except pursuant to this license grant from
43788 + * Synopsys. If you do not agree with this notice, including the disclaimer
43789 + * below, then you are not authorized to use the Software.
43791 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
43792 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43793 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43794 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
43795 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43796 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43797 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
43798 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43799 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43800 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
43802 + * ========================================================================== */
43803 +#ifndef DWC_HOST_ONLY
43806 + * This file implements PCD Core. All code in this file is portable and doesn't
43807 + * use any OS specific functions.
43808 + * PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code>
43809 + * header file, which can be used to implement OS specific PCD interface.
43811 + * An important function of the PCD is managing interrupts generated
43812 + * by the DWC_otg controller. The implementation of the DWC_otg device
43813 + * mode interrupt service routines is in dwc_otg_pcd_intr.c.
43815 + * @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
43816 + * @todo Does it work when the request size is greater than DEPTSIZ
43821 +#include "dwc_otg_pcd.h"
43823 +#ifdef DWC_UTE_CFI
43824 +#include "dwc_otg_cfi.h"
43826 +extern int init_cfi(cfiobject_t * cfiobj);
43830 + * Choose endpoint from ep arrays using usb_ep structure.
43832 +static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
43835 + if (pcd->ep0.priv == handle) {
43836 + return &pcd->ep0;
43838 + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
43839 + if (pcd->in_ep[i].priv == handle)
43840 + return &pcd->in_ep[i];
43841 + if (pcd->out_ep[i].priv == handle)
43842 + return &pcd->out_ep[i];
43849 + * This function completes a request. It call's the request call back.
43851 +void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req,
43854 + unsigned stopped = ep->stopped;
43856 + DWC_DEBUGPL(DBG_PCDV, "%s(ep %p req %p)\n", __func__, ep, req);
43857 + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
43859 + /* don't modify queue heads during completion callback */
43861 + /* spin_unlock/spin_lock now done in fops->complete() */
43862 + ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status,
43865 + if (ep->pcd->request_pending > 0) {
43866 + --ep->pcd->request_pending;
43869 + ep->stopped = stopped;
43874 + * This function terminates all the requsts in the EP request queue.
43876 +void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep)
43878 + dwc_otg_pcd_request_t *req;
43882 + /* called with irqs blocked?? */
43883 + while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
43884 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
43885 + dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN);
43889 +void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
43890 + const struct dwc_otg_pcd_function_ops *fops)
43892 + pcd->fops = fops;
43896 + * PCD Callback function for initializing the PCD when switching to
43899 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
43901 +static int32_t dwc_otg_pcd_start_cb(void *p)
43903 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
43904 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
43907 + * Initialized the Core for Device mode.
43909 + if (dwc_otg_is_device_mode(core_if)) {
43910 + dwc_otg_core_dev_init(core_if);
43911 + /* Set core_if's lock pointer to the pcd->lock */
43912 + core_if->lock = pcd->lock;
43917 +/** CFI-specific buffer allocation function for EP */
43918 +#ifdef DWC_UTE_CFI
43919 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
43920 + size_t buflen, int flags)
43922 + dwc_otg_pcd_ep_t *ep;
43923 + ep = get_ep_from_handle(pcd, pep);
43925 + DWC_WARN("bad ep\n");
43926 + return -DWC_E_INVALID;
43929 + return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen,
43933 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
43934 + size_t buflen, int flags);
43938 + * PCD Callback function for notifying the PCD when resuming from
43941 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
43943 +static int32_t dwc_otg_pcd_resume_cb(void *p)
43945 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
43947 + if (pcd->fops->resume) {
43948 + pcd->fops->resume(pcd);
43951 + /* Stop the SRP timeout timer. */
43952 + if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS)
43953 + || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {
43954 + if (GET_CORE_IF(pcd)->srp_timer_started) {
43955 + GET_CORE_IF(pcd)->srp_timer_started = 0;
43956 + DWC_TIMER_CANCEL(GET_CORE_IF(pcd)->srp_timer);
43963 + * PCD Callback function for notifying the PCD device is suspended.
43965 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
43967 +static int32_t dwc_otg_pcd_suspend_cb(void *p)
43969 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
43971 + if (pcd->fops->suspend) {
43972 + DWC_SPINUNLOCK(pcd->lock);
43973 + pcd->fops->suspend(pcd);
43974 + DWC_SPINLOCK(pcd->lock);
43981 + * PCD Callback function for stopping the PCD when switching to Host
43984 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
43986 +static int32_t dwc_otg_pcd_stop_cb(void *p)
43988 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
43989 + extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);
43991 + dwc_otg_pcd_stop(pcd);
43996 + * PCD Callback structure for handling mode switching.
43998 +static dwc_otg_cil_callbacks_t pcd_callbacks = {
43999 + .start = dwc_otg_pcd_start_cb,
44000 + .stop = dwc_otg_pcd_stop_cb,
44001 + .suspend = dwc_otg_pcd_suspend_cb,
44002 + .resume_wakeup = dwc_otg_pcd_resume_cb,
44003 + .p = 0, /* Set at registration */
44007 + * This function allocates a DMA Descriptor chain for the Endpoint
44008 + * buffer to be used for a transfer to/from the specified endpoint.
44010 +dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(dwc_dma_t * dma_desc_addr,
44013 + return DWC_DMA_ALLOC_ATOMIC(count * sizeof(dwc_otg_dev_dma_desc_t),
44018 + * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc.
44020 +void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr,
44021 + uint32_t dma_desc_addr, uint32_t count)
44023 + DWC_DMA_FREE(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr,
44027 +#ifdef DWC_EN_ISOC
44030 + * This function initializes a descriptor chain for Isochronous transfer
44032 + * @param core_if Programming view of DWC_otg controller.
44033 + * @param dwc_ep The EP to start the transfer on.
44036 +void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if,
44037 + dwc_ep_t * dwc_ep)
44040 + dsts_data_t dsts = {.d32 = 0 };
44041 + depctl_data_t depctl = {.d32 = 0 };
44042 + volatile uint32_t *addr;
44046 + if (dwc_ep->is_in)
44047 + dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;
44049 + dwc_ep->desc_cnt =
44050 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44051 + dwc_ep->bInterval;
44053 + /** Allocate descriptors for double buffering */
44054 + dwc_ep->iso_desc_addr =
44055 + dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr,
44056 + dwc_ep->desc_cnt * 2);
44057 + if (dwc_ep->desc_addr) {
44058 + DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__);
44062 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44064 + /** ISO OUT EP */
44065 + if (dwc_ep->is_in == 0) {
44066 + dev_dma_desc_sts_t sts = {.d32 = 0 };
44067 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
44068 + dma_addr_t dma_ad;
44069 + uint32_t data_per_desc;
44070 + dwc_otg_dev_out_ep_regs_t *out_regs =
44071 + core_if->dev_if->out_ep_regs[dwc_ep->num];
44074 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
44075 + dma_ad = (dma_addr_t) DWC_READ_REG32(&(out_regs->doepdma));
44077 + /** Buffer 0 descriptors setup */
44078 + dma_ad = dwc_ep->dma_addr0;
44080 + sts.b_iso_out.bs = BS_HOST_READY;
44081 + sts.b_iso_out.rxsts = 0;
44082 + sts.b_iso_out.l = 0;
44083 + sts.b_iso_out.sp = 0;
44084 + sts.b_iso_out.ioc = 0;
44085 + sts.b_iso_out.pid = 0;
44086 + sts.b_iso_out.framenum = 0;
44089 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44090 + i += dwc_ep->pkt_per_frm) {
44092 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
44093 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44094 + if (len > dwc_ep->data_per_frame)
44096 + dwc_ep->data_per_frame -
44097 + j * dwc_ep->maxpacket;
44099 + data_per_desc = dwc_ep->maxpacket;
44100 + len = data_per_desc % 4;
44102 + data_per_desc += 4 - len;
44104 + sts.b_iso_out.rxbytes = data_per_desc;
44105 + dma_desc->buf = dma_ad;
44106 + dma_desc->status.d32 = sts.d32;
44108 + offset += data_per_desc;
44110 + dma_ad += data_per_desc;
44114 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
44115 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44116 + if (len > dwc_ep->data_per_frame)
44118 + dwc_ep->data_per_frame -
44119 + j * dwc_ep->maxpacket;
44121 + data_per_desc = dwc_ep->maxpacket;
44122 + len = data_per_desc % 4;
44124 + data_per_desc += 4 - len;
44125 + sts.b_iso_out.rxbytes = data_per_desc;
44126 + dma_desc->buf = dma_ad;
44127 + dma_desc->status.d32 = sts.d32;
44129 + offset += data_per_desc;
44131 + dma_ad += data_per_desc;
44134 + sts.b_iso_out.ioc = 1;
44135 + len = (j + 1) * dwc_ep->maxpacket;
44136 + if (len > dwc_ep->data_per_frame)
44138 + dwc_ep->data_per_frame - j * dwc_ep->maxpacket;
44140 + data_per_desc = dwc_ep->maxpacket;
44141 + len = data_per_desc % 4;
44143 + data_per_desc += 4 - len;
44144 + sts.b_iso_out.rxbytes = data_per_desc;
44146 + dma_desc->buf = dma_ad;
44147 + dma_desc->status.d32 = sts.d32;
44150 + /** Buffer 1 descriptors setup */
44151 + sts.b_iso_out.ioc = 0;
44152 + dma_ad = dwc_ep->dma_addr1;
44155 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44156 + i += dwc_ep->pkt_per_frm) {
44157 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
44158 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44159 + if (len > dwc_ep->data_per_frame)
44161 + dwc_ep->data_per_frame -
44162 + j * dwc_ep->maxpacket;
44164 + data_per_desc = dwc_ep->maxpacket;
44165 + len = data_per_desc % 4;
44167 + data_per_desc += 4 - len;
44170 + sts.b_iso_out.rxbytes = data_per_desc;
44171 + dma_desc->buf = dma_ad;
44172 + dma_desc->status.d32 = sts.d32;
44174 + offset += data_per_desc;
44176 + dma_ad += data_per_desc;
44179 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
44181 + ((j + 1) * dwc_ep->maxpacket >
44182 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
44183 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
44185 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
44186 + sts.b_iso_out.rxbytes = data_per_desc;
44187 + dma_desc->buf = dma_ad;
44188 + dma_desc->status.d32 = sts.d32;
44190 + offset += data_per_desc;
44192 + dma_ad += data_per_desc;
44195 + sts.b_iso_out.ioc = 1;
44196 + sts.b_iso_out.l = 1;
44198 + ((j + 1) * dwc_ep->maxpacket >
44199 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
44200 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
44202 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
44203 + sts.b_iso_out.rxbytes = data_per_desc;
44205 + dma_desc->buf = dma_ad;
44206 + dma_desc->status.d32 = sts.d32;
44208 + dwc_ep->next_frame = 0;
44210 + /** Write dma_ad into DOEPDMA register */
44211 + DWC_WRITE_REG32(&(out_regs->doepdma),
44212 + (uint32_t) dwc_ep->iso_dma_desc_addr);
44217 + dev_dma_desc_sts_t sts = {.d32 = 0 };
44218 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
44219 + dma_addr_t dma_ad;
44220 + dwc_otg_dev_in_ep_regs_t *in_regs =
44221 + core_if->dev_if->in_ep_regs[dwc_ep->num];
44222 + unsigned int frmnumber;
44223 + fifosize_data_t txfifosize, rxfifosize;
44226 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[dwc_ep->num]->
44229 + DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
44231 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
44233 + dma_ad = dwc_ep->dma_addr0;
44236 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44238 + sts.b_iso_in.bs = BS_HOST_READY;
44239 + sts.b_iso_in.txsts = 0;
44240 + sts.b_iso_in.sp =
44241 + (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;
44242 + sts.b_iso_in.ioc = 0;
44243 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
44245 + frmnumber = dwc_ep->next_frame;
44247 + sts.b_iso_in.framenum = frmnumber;
44248 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
44249 + sts.b_iso_in.l = 0;
44251 + /** Buffer 0 descriptors setup */
44252 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
44253 + dma_desc->buf = dma_ad;
44254 + dma_desc->status.d32 = sts.d32;
44257 + dma_ad += dwc_ep->data_per_frame;
44258 + sts.b_iso_in.framenum += dwc_ep->bInterval;
44261 + sts.b_iso_in.ioc = 1;
44262 + dma_desc->buf = dma_ad;
44263 + dma_desc->status.d32 = sts.d32;
44266 + /** Buffer 1 descriptors setup */
44267 + sts.b_iso_in.ioc = 0;
44268 + dma_ad = dwc_ep->dma_addr1;
44270 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44271 + i += dwc_ep->pkt_per_frm) {
44272 + dma_desc->buf = dma_ad;
44273 + dma_desc->status.d32 = sts.d32;
44276 + dma_ad += dwc_ep->data_per_frame;
44277 + sts.b_iso_in.framenum += dwc_ep->bInterval;
44279 + sts.b_iso_in.ioc = 0;
44281 + sts.b_iso_in.ioc = 1;
44282 + sts.b_iso_in.l = 1;
44284 + dma_desc->buf = dma_ad;
44285 + dma_desc->status.d32 = sts.d32;
44287 + dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval;
44289 + /** Write dma_ad into diepdma register */
44290 + DWC_WRITE_REG32(&(in_regs->diepdma),
44291 + (uint32_t) dwc_ep->iso_dma_desc_addr);
44293 + /** Enable endpoint, clear nak */
44295 + depctl.b.epena = 1;
44296 + depctl.b.usbactep = 1;
44297 + depctl.b.cnak = 1;
44299 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
44300 + depctl.d32 = DWC_READ_REG32(addr);
44304 + * This function initializes a descriptor chain for Isochronous transfer
44306 + * @param core_if Programming view of DWC_otg controller.
44307 + * @param ep The EP to start the transfer on.
44310 +void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
44313 + depctl_data_t depctl = {.d32 = 0 };
44314 + volatile uint32_t *addr;
44317 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
44319 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
44322 + if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) {
44325 + deptsiz_data_t deptsiz = {.d32 = 0 };
44328 + ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval;
44330 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
44331 + ep->xfer_count = 0;
44333 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
44335 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
44338 + /* Program the transfer size and packet count
44339 + * as follows: xfersize = N * maxpacket +
44340 + * short_packet pktcnt = N + (short_packet
44343 + deptsiz.b.mc = ep->pkt_per_frm;
44344 + deptsiz.b.xfersize = ep->xfer_len;
44345 + deptsiz.b.pktcnt =
44346 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
44347 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
44348 + dieptsiz, deptsiz.d32);
44350 + /* Write the DMA register */
44351 + DWC_WRITE_REG32(&
44352 + (core_if->dev_if->in_ep_regs[ep->num]->
44353 + diepdma), (uint32_t) ep->dma_addr);
44356 + deptsiz.b.pktcnt =
44357 + (ep->xfer_len + (ep->maxpacket - 1)) /
44359 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
44361 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
44362 + doeptsiz, deptsiz.d32);
44364 + /* Write the DMA register */
44365 + DWC_WRITE_REG32(&
44366 + (core_if->dev_if->out_ep_regs[ep->num]->
44367 + doepdma), (uint32_t) ep->dma_addr);
44370 + /** Enable endpoint, clear nak */
44372 + depctl.b.epena = 1;
44373 + depctl.b.cnak = 1;
44375 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
44380 + * This function does the setup for a data transfer for an EP and
44381 + * starts the transfer. For an IN transfer, the packets will be
44382 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
44383 + * the packets are unloaded from the Rx FIFO in the ISR.
44385 + * @param core_if Programming view of DWC_otg controller.
44386 + * @param ep The EP to start the transfer on.
44389 +static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if,
44392 + if (core_if->dma_enable) {
44393 + if (core_if->dma_desc_enable) {
44395 + ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm;
44397 + ep->desc_cnt = ep->pkt_cnt;
44399 + dwc_otg_iso_ep_start_ddma_transfer(core_if, ep);
44401 + if (core_if->pti_enh_enable) {
44402 + dwc_otg_iso_ep_start_buf_transfer(core_if, ep);
44404 + ep->cur_pkt_addr =
44405 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->
44407 + ep->cur_pkt_dma_addr =
44408 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->
44410 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
44414 + ep->cur_pkt_addr =
44415 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
44416 + ep->cur_pkt_dma_addr =
44417 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
44418 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
44423 + * This function stops transfer for an EP and
44424 + * resets the ep's variables.
44426 + * @param core_if Programming view of DWC_otg controller.
44427 + * @param ep The EP to start the transfer on.
44430 +void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
44432 + depctl_data_t depctl = {.d32 = 0 };
44433 + volatile uint32_t *addr;
44435 + if (ep->is_in == 1) {
44436 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
44438 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
44441 + /* disable the ep */
44442 + depctl.d32 = DWC_READ_REG32(addr);
44444 + depctl.b.epdis = 1;
44445 + depctl.b.snak = 1;
44447 + DWC_WRITE_REG32(addr, depctl.d32);
44449 + if (core_if->dma_desc_enable &&
44450 + ep->iso_desc_addr && ep->iso_dma_desc_addr) {
44451 + dwc_otg_ep_free_desc_chain(ep->iso_desc_addr,
44452 + ep->iso_dma_desc_addr,
44453 + ep->desc_cnt * 2);
44456 + /* reset varibales */
44457 + ep->dma_addr0 = 0;
44458 + ep->dma_addr1 = 0;
44459 + ep->xfer_buff0 = 0;
44460 + ep->xfer_buff1 = 0;
44461 + ep->data_per_frame = 0;
44462 + ep->data_pattern_frame = 0;
44463 + ep->sync_frame = 0;
44464 + ep->buf_proc_intrvl = 0;
44465 + ep->bInterval = 0;
44466 + ep->proc_buf_num = 0;
44467 + ep->pkt_per_frm = 0;
44468 + ep->pkt_per_frm = 0;
44469 + ep->desc_cnt = 0;
44470 + ep->iso_desc_addr = 0;
44471 + ep->iso_dma_desc_addr = 0;
44474 +int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
44475 + uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0,
44476 + dwc_dma_t dma1, int sync_frame, int dp_frame,
44477 + int data_per_frame, int start_frame,
44478 + int buf_proc_intrvl, void *req_handle,
44479 + int atomic_alloc)
44481 + dwc_otg_pcd_ep_t *ep;
44482 + dwc_irqflags_t flags = 0;
44483 + dwc_ep_t *dwc_ep;
44484 + int32_t frm_data;
44485 + dsts_data_t dsts;
44486 + dwc_otg_core_if_t *core_if;
44488 + ep = get_ep_from_handle(pcd, ep_handle);
44490 + if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
44491 + DWC_WARN("bad ep\n");
44492 + return -DWC_E_INVALID;
44495 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
44496 + core_if = GET_CORE_IF(pcd);
44497 + dwc_ep = &ep->dwc_ep;
44499 + if (ep->iso_req_handle) {
44500 + DWC_WARN("ISO request in progress\n");
44503 + dwc_ep->dma_addr0 = dma0;
44504 + dwc_ep->dma_addr1 = dma1;
44506 + dwc_ep->xfer_buff0 = buf0;
44507 + dwc_ep->xfer_buff1 = buf1;
44509 + dwc_ep->data_per_frame = data_per_frame;
44511 + /** @todo - pattern data support is to be implemented in the future */
44512 + dwc_ep->data_pattern_frame = dp_frame;
44513 + dwc_ep->sync_frame = sync_frame;
44515 + dwc_ep->buf_proc_intrvl = buf_proc_intrvl;
44517 + dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);
44519 + dwc_ep->proc_buf_num = 0;
44521 + dwc_ep->pkt_per_frm = 0;
44522 + frm_data = ep->dwc_ep.data_per_frame;
44523 + while (frm_data > 0) {
44524 + dwc_ep->pkt_per_frm++;
44525 + frm_data -= ep->dwc_ep.maxpacket;
44528 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44530 + if (start_frame == -1) {
44531 + dwc_ep->next_frame = dsts.b.soffn + 1;
44532 + if (dwc_ep->bInterval != 1) {
44533 + dwc_ep->next_frame =
44534 + dwc_ep->next_frame + (dwc_ep->bInterval - 1 -
44535 + dwc_ep->next_frame %
44536 + dwc_ep->bInterval);
44539 + dwc_ep->next_frame = start_frame;
44542 + if (!core_if->pti_enh_enable) {
44543 + dwc_ep->pkt_cnt =
44544 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44545 + dwc_ep->bInterval;
44547 + dwc_ep->pkt_cnt =
44548 + (dwc_ep->data_per_frame *
44549 + (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval)
44550 + - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket;
44553 + if (core_if->dma_desc_enable) {
44554 + dwc_ep->desc_cnt =
44555 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44556 + dwc_ep->bInterval;
44559 + if (atomic_alloc) {
44560 + dwc_ep->pkt_info =
44561 + DWC_ALLOC_ATOMIC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44563 + dwc_ep->pkt_info =
44564 + DWC_ALLOC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44566 + if (!dwc_ep->pkt_info) {
44567 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44568 + return -DWC_E_NO_MEMORY;
44570 + if (core_if->pti_enh_enable) {
44571 + dwc_memset(dwc_ep->pkt_info, 0,
44572 + sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44575 + dwc_ep->cur_pkt = 0;
44576 + ep->iso_req_handle = req_handle;
44578 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44579 + dwc_otg_iso_ep_start_transfer(core_if, dwc_ep);
44583 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
44584 + void *req_handle)
44586 + dwc_irqflags_t flags = 0;
44587 + dwc_otg_pcd_ep_t *ep;
44588 + dwc_ep_t *dwc_ep;
44590 + ep = get_ep_from_handle(pcd, ep_handle);
44591 + if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
44592 + DWC_WARN("bad ep\n");
44593 + return -DWC_E_INVALID;
44595 + dwc_ep = &ep->dwc_ep;
44597 + dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep);
44599 + DWC_FREE(dwc_ep->pkt_info);
44600 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
44601 + if (ep->iso_req_handle != req_handle) {
44602 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44603 + return -DWC_E_INVALID;
44606 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44608 + ep->iso_req_handle = 0;
44613 + * This function is used for perodical data exchnage between PCD and gadget drivers.
44614 + * for Isochronous EPs
44616 + * - Every time a sync period completes this function is called to
44617 + * perform data exchange between PCD and gadget
44619 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
44620 + void *req_handle)
44623 + dwc_ep_t *dwc_ep;
44625 + dwc_ep = &ep->dwc_ep;
44627 + DWC_SPINUNLOCK(ep->pcd->lock);
44628 + pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle,
44629 + dwc_ep->proc_buf_num ^ 0x1);
44630 + DWC_SPINLOCK(ep->pcd->lock);
44632 + for (i = 0; i < dwc_ep->pkt_cnt; ++i) {
44633 + dwc_ep->pkt_info[i].status = 0;
44634 + dwc_ep->pkt_info[i].offset = 0;
44635 + dwc_ep->pkt_info[i].length = 0;
44639 +int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle,
44640 + void *iso_req_handle)
44642 + dwc_otg_pcd_ep_t *ep;
44643 + dwc_ep_t *dwc_ep;
44645 + ep = get_ep_from_handle(pcd, ep_handle);
44646 + if (!ep->desc || ep->dwc_ep.num == 0) {
44647 + DWC_WARN("bad ep\n");
44648 + return -DWC_E_INVALID;
44650 + dwc_ep = &ep->dwc_ep;
44652 + return dwc_ep->pkt_cnt;
44655 +void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle,
44656 + void *iso_req_handle, int packet,
44657 + int *status, int *actual, int *offset)
44659 + dwc_otg_pcd_ep_t *ep;
44660 + dwc_ep_t *dwc_ep;
44662 + ep = get_ep_from_handle(pcd, ep_handle);
44664 + DWC_WARN("bad ep\n");
44666 + dwc_ep = &ep->dwc_ep;
44668 + *status = dwc_ep->pkt_info[packet].status;
44669 + *actual = dwc_ep->pkt_info[packet].length;
44670 + *offset = dwc_ep->pkt_info[packet].offset;
44673 +#endif /* DWC_EN_ISOC */
44675 +static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
44676 + uint32_t is_in, uint32_t ep_num)
44678 + /* Init EP structure */
44679 + pcd_ep->desc = 0;
44680 + pcd_ep->pcd = pcd;
44681 + pcd_ep->stopped = 1;
44682 + pcd_ep->queue_sof = 0;
44684 + /* Init DWC ep structure */
44685 + pcd_ep->dwc_ep.is_in = is_in;
44686 + pcd_ep->dwc_ep.num = ep_num;
44687 + pcd_ep->dwc_ep.active = 0;
44688 + pcd_ep->dwc_ep.tx_fifo_num = 0;
44689 + /* Control until ep is actvated */
44690 + pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
44691 + pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
44692 + pcd_ep->dwc_ep.dma_addr = 0;
44693 + pcd_ep->dwc_ep.start_xfer_buff = 0;
44694 + pcd_ep->dwc_ep.xfer_buff = 0;
44695 + pcd_ep->dwc_ep.xfer_len = 0;
44696 + pcd_ep->dwc_ep.xfer_count = 0;
44697 + pcd_ep->dwc_ep.sent_zlp = 0;
44698 + pcd_ep->dwc_ep.total_len = 0;
44699 + pcd_ep->dwc_ep.desc_addr = 0;
44700 + pcd_ep->dwc_ep.dma_desc_addr = 0;
44701 + DWC_CIRCLEQ_INIT(&pcd_ep->queue);
44705 + * Initialize ep's
44707 +static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
44711 + dwc_otg_pcd_ep_t *ep;
44712 + int in_ep_cntr, out_ep_cntr;
44713 + uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
44714 + uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
44717 + * Initialize the EP0 structure.
44720 + dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
44723 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
44724 + for (i = 1; in_ep_cntr < num_in_eps; i++) {
44725 + if ((hwcfg1 & 0x1) == 0) {
44726 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr];
44729 + * @todo NGS: Add direction to EP, based on contents
44730 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
44733 + dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
44735 + DWC_CIRCLEQ_INIT(&ep->queue);
44741 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
44742 + for (i = 1; out_ep_cntr < num_out_eps; i++) {
44743 + if ((hwcfg1 & 0x1) == 0) {
44744 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr];
44747 + * @todo NGS: Add direction to EP, based on contents
44748 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
44751 + dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
44752 + DWC_CIRCLEQ_INIT(&ep->queue);
44757 + pcd->ep0state = EP0_DISCONNECT;
44758 + pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
44759 + pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
44763 + * This function is called when the SRP timer expires. The SRP should
44764 + * complete within 6 seconds.
44766 +static void srp_timeout(void *ptr)
44768 + gotgctl_data_t gotgctl;
44769 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
44770 + volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
44772 + gotgctl.d32 = DWC_READ_REG32(addr);
44774 + core_if->srp_timer_started = 0;
44776 + if (core_if->adp_enable) {
44777 + if (gotgctl.b.bsesvld == 0) {
44778 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
44779 + DWC_PRINTF("SRP Timeout BSESSVLD = 0\n");
44780 + /* Power off the core */
44781 + if (core_if->power_down == 2) {
44782 + gpwrdn.b.pwrdnswtch = 1;
44783 + DWC_MODIFY_REG32(&core_if->
44784 + core_global_regs->gpwrdn,
44789 + gpwrdn.b.pmuintsel = 1;
44790 + gpwrdn.b.pmuactv = 1;
44791 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
44793 + dwc_otg_adp_probe_start(core_if);
44795 + DWC_PRINTF("SRP Timeout BSESSVLD = 1\n");
44796 + core_if->op_state = B_PERIPHERAL;
44797 + dwc_otg_core_init(core_if);
44798 + dwc_otg_enable_global_interrupts(core_if);
44799 + cil_pcd_start(core_if);
44803 + if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
44804 + (core_if->core_params->i2c_enable)) {
44805 + DWC_PRINTF("SRP Timeout\n");
44807 + if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {
44808 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
44809 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
44812 + /* Clear Session Request */
44814 + gotgctl.b.sesreq = 1;
44815 + DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
44818 + core_if->srp_success = 0;
44820 + __DWC_ERROR("Device not connected/responding\n");
44821 + gotgctl.b.sesreq = 0;
44822 + DWC_WRITE_REG32(addr, gotgctl.d32);
44824 + } else if (gotgctl.b.sesreq) {
44825 + DWC_PRINTF("SRP Timeout\n");
44827 + __DWC_ERROR("Device not connected/responding\n");
44828 + gotgctl.b.sesreq = 0;
44829 + DWC_WRITE_REG32(addr, gotgctl.d32);
44831 + DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32);
44839 +extern void start_next_request(dwc_otg_pcd_ep_t * ep);
44841 +static void start_xfer_tasklet_func(void *data)
44843 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
44844 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
44847 + depctl_data_t diepctl;
44849 + DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
44851 + diepctl.d32 = DWC_READ_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl);
44853 + if (pcd->ep0.queue_sof) {
44854 + pcd->ep0.queue_sof = 0;
44855 + start_next_request(&pcd->ep0);
44859 + for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
44860 + depctl_data_t diepctl;
44862 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
44864 + if (pcd->in_ep[i].queue_sof) {
44865 + pcd->in_ep[i].queue_sof = 0;
44866 + start_next_request(&pcd->in_ep[i]);
44875 + * This function initialized the PCD portion of the driver.
44878 +dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
44880 + dwc_otg_pcd_t *pcd = NULL;
44881 + dwc_otg_dev_if_t *dev_if;
44885 + * Allocate PCD structure
44887 + pcd = DWC_ALLOC(sizeof(dwc_otg_pcd_t));
44889 + if (pcd == NULL) {
44893 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK))
44894 + DWC_SPINLOCK_ALLOC_LINUX_DEBUG(pcd->lock);
44896 + pcd->lock = DWC_SPINLOCK_ALLOC();
44898 + DWC_DEBUGPL(DBG_HCDV, "Init of PCD %p given core_if %p\n",
44899 + pcd, core_if);//GRAYG
44900 + if (!pcd->lock) {
44901 + DWC_ERROR("Could not allocate lock for pcd");
44905 + /* Set core_if's lock pointer to hcd->lock */
44906 + core_if->lock = pcd->lock;
44907 + pcd->core_if = core_if;
44909 + dev_if = core_if->dev_if;
44910 + dev_if->isoc_ep = NULL;
44912 + if (core_if->hwcfg4.b.ded_fifo_en) {
44913 + DWC_PRINTF("Dedicated Tx FIFOs mode\n");
44915 + DWC_PRINTF("Shared Tx FIFO mode\n");
44919 + * Initialized the Core for Device mode here if there is nod ADP support.
44920 + * Otherwise it will be done later in dwc_otg_adp_start routine.
44922 + if (dwc_otg_is_device_mode(core_if) /*&& !core_if->adp_enable*/) {
44923 + dwc_otg_core_dev_init(core_if);
44927 + * Register the PCD Callbacks.
44929 + dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd);
44932 + * Initialize the DMA buffer for SETUP packets
44934 + if (GET_CORE_IF(pcd)->dma_enable) {
44936 + DWC_DMA_ALLOC(sizeof(*pcd->setup_pkt) * 5,
44937 + &pcd->setup_pkt_dma_handle);
44938 + if (pcd->setup_pkt == NULL) {
44943 + pcd->status_buf =
44944 + DWC_DMA_ALLOC(sizeof(uint16_t),
44945 + &pcd->status_buf_dma_handle);
44946 + if (pcd->status_buf == NULL) {
44947 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
44948 + pcd->setup_pkt, pcd->setup_pkt_dma_handle);
44953 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
44954 + dev_if->setup_desc_addr[0] =
44955 + dwc_otg_ep_alloc_desc_chain
44956 + (&dev_if->dma_setup_desc_addr[0], 1);
44957 + dev_if->setup_desc_addr[1] =
44958 + dwc_otg_ep_alloc_desc_chain
44959 + (&dev_if->dma_setup_desc_addr[1], 1);
44960 + dev_if->in_desc_addr =
44961 + dwc_otg_ep_alloc_desc_chain
44962 + (&dev_if->dma_in_desc_addr, 1);
44963 + dev_if->out_desc_addr =
44964 + dwc_otg_ep_alloc_desc_chain
44965 + (&dev_if->dma_out_desc_addr, 1);
44966 + pcd->data_terminated = 0;
44968 + if (dev_if->setup_desc_addr[0] == 0
44969 + || dev_if->setup_desc_addr[1] == 0
44970 + || dev_if->in_desc_addr == 0
44971 + || dev_if->out_desc_addr == 0) {
44973 + if (dev_if->out_desc_addr)
44974 + dwc_otg_ep_free_desc_chain
44975 + (dev_if->out_desc_addr,
44976 + dev_if->dma_out_desc_addr, 1);
44977 + if (dev_if->in_desc_addr)
44978 + dwc_otg_ep_free_desc_chain
44979 + (dev_if->in_desc_addr,
44980 + dev_if->dma_in_desc_addr, 1);
44981 + if (dev_if->setup_desc_addr[1])
44982 + dwc_otg_ep_free_desc_chain
44983 + (dev_if->setup_desc_addr[1],
44984 + dev_if->dma_setup_desc_addr[1], 1);
44985 + if (dev_if->setup_desc_addr[0])
44986 + dwc_otg_ep_free_desc_chain
44987 + (dev_if->setup_desc_addr[0],
44988 + dev_if->dma_setup_desc_addr[0], 1);
44990 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
44992 + pcd->setup_pkt_dma_handle);
44993 + DWC_DMA_FREE(sizeof(*pcd->status_buf),
44995 + pcd->status_buf_dma_handle);
45003 + pcd->setup_pkt = DWC_ALLOC(sizeof(*pcd->setup_pkt) * 5);
45004 + if (pcd->setup_pkt == NULL) {
45009 + pcd->status_buf = DWC_ALLOC(sizeof(uint16_t));
45010 + if (pcd->status_buf == NULL) {
45011 + DWC_FREE(pcd->setup_pkt);
45017 + dwc_otg_pcd_reinit(pcd);
45019 + /* Allocate the cfi object for the PCD */
45020 +#ifdef DWC_UTE_CFI
45021 + pcd->cfi = DWC_ALLOC(sizeof(cfiobject_t));
45022 + if (NULL == pcd->cfi)
45024 + if (init_cfi(pcd->cfi)) {
45025 + CFI_INFO("%s: Failed to init the CFI object\n", __func__);
45030 + /* Initialize tasklets */
45031 + pcd->start_xfer_tasklet = DWC_TASK_ALLOC("xfer_tasklet",
45032 + start_xfer_tasklet_func, pcd);
45033 + pcd->test_mode_tasklet = DWC_TASK_ALLOC("test_mode_tasklet",
45034 + do_test_mode, pcd);
45036 + /* Initialize SRP timer */
45037 + core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
45039 + if (core_if->core_params->dev_out_nak) {
45041 + * Initialize xfer timeout timer. Implemented for
45042 + * 2.93a feature "Device DDMA OUT NAK Enhancement"
45044 + for(i = 0; i < MAX_EPS_CHANNELS; i++) {
45045 + pcd->core_if->ep_xfer_timer[i] =
45046 + DWC_TIMER_ALLOC("ep timer", ep_xfer_timeout,
45047 + &pcd->core_if->ep_xfer_info[i]);
45052 +#ifdef DWC_UTE_CFI
45055 + if (pcd->setup_pkt)
45056 + DWC_FREE(pcd->setup_pkt);
45057 + if (pcd->status_buf)
45058 + DWC_FREE(pcd->status_buf);
45059 +#ifdef DWC_UTE_CFI
45061 + DWC_FREE(pcd->cfi);
45070 + * Remove PCD specific data
45072 +void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd)
45074 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
45076 + if (pcd->core_if->core_params->dev_out_nak) {
45077 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
45078 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[i]);
45079 + pcd->core_if->ep_xfer_info[i].state = 0;
45083 + if (GET_CORE_IF(pcd)->dma_enable) {
45084 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt,
45085 + pcd->setup_pkt_dma_handle);
45086 + DWC_DMA_FREE(sizeof(uint16_t), pcd->status_buf,
45087 + pcd->status_buf_dma_handle);
45088 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45089 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0],
45090 + dev_if->dma_setup_desc_addr
45092 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1],
45093 + dev_if->dma_setup_desc_addr
45095 + dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr,
45096 + dev_if->dma_in_desc_addr, 1);
45097 + dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr,
45098 + dev_if->dma_out_desc_addr,
45102 + DWC_FREE(pcd->setup_pkt);
45103 + DWC_FREE(pcd->status_buf);
45105 + DWC_SPINLOCK_FREE(pcd->lock);
45106 + /* Set core_if's lock pointer to NULL */
45107 + pcd->core_if->lock = NULL;
45109 + DWC_TASK_FREE(pcd->start_xfer_tasklet);
45110 + DWC_TASK_FREE(pcd->test_mode_tasklet);
45111 + if (pcd->core_if->core_params->dev_out_nak) {
45112 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
45113 + if (pcd->core_if->ep_xfer_timer[i]) {
45114 + DWC_TIMER_FREE(pcd->core_if->ep_xfer_timer[i]);
45119 +/* Release the CFI object's dynamic memory */
45120 +#ifdef DWC_UTE_CFI
45121 + if (pcd->cfi->ops.release) {
45122 + pcd->cfi->ops.release(pcd->cfi);
45130 + * Returns whether registered pcd is dual speed or not
45132 +uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd)
45134 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45136 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) ||
45137 + ((core_if->hwcfg2.b.hs_phy_type == 2) &&
45138 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
45139 + (core_if->core_params->ulpi_fs_ls))) {
45147 + * Returns whether registered pcd is OTG capable or not
45149 +uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd)
45151 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45152 + gusbcfg_data_t usbcfg = {.d32 = 0 };
45154 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
45155 + if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) {
45163 + * This function assigns periodic Tx FIFO to an periodic EP
45164 + * in shared Tx FIFO mode
45166 +static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if)
45168 + uint32_t TxMsk = 1;
45171 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) {
45172 + if ((TxMsk & core_if->tx_msk) == 0) {
45173 + core_if->tx_msk |= TxMsk;
45182 + * This function assigns periodic Tx FIFO to an periodic EP
45183 + * in shared Tx FIFO mode
45185 +static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if)
45187 + uint32_t PerTxMsk = 1;
45189 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) {
45190 + if ((PerTxMsk & core_if->p_tx_msk) == 0) {
45191 + core_if->p_tx_msk |= PerTxMsk;
45200 + * This function releases periodic Tx FIFO
45201 + * in shared Tx FIFO mode
45203 +static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if,
45204 + uint32_t fifo_num)
45206 + core_if->p_tx_msk =
45207 + (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
45211 + * This function releases periodic Tx FIFO
45212 + * in shared Tx FIFO mode
45214 +static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num)
45216 + core_if->tx_msk =
45217 + (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
45221 + * This function is being called from gadget
45222 + * to enable PCD endpoint.
45224 +int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
45225 + const uint8_t * ep_desc, void *usb_ep)
45228 + dwc_otg_pcd_ep_t *ep = NULL;
45229 + const usb_endpoint_descriptor_t *desc;
45230 + dwc_irqflags_t flags;
45231 + fifosize_data_t dptxfsiz = {.d32 = 0 };
45232 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
45233 + gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
45237 + desc = (const usb_endpoint_descriptor_t *)ep_desc;
45240 + pcd->ep0.priv = usb_ep;
45242 + retval = -DWC_E_INVALID;
45246 + num = UE_GET_ADDR(desc->bEndpointAddress);
45247 + dir = UE_GET_DIR(desc->bEndpointAddress);
45249 + if (!desc->wMaxPacketSize) {
45250 + DWC_WARN("bad maxpacketsize\n");
45251 + retval = -DWC_E_INVALID;
45255 + if (dir == UE_DIR_IN) {
45256 + epcount = pcd->core_if->dev_if->num_in_eps;
45257 + for (i = 0; i < epcount; i++) {
45258 + if (num == pcd->in_ep[i].dwc_ep.num) {
45259 + ep = &pcd->in_ep[i];
45264 + epcount = pcd->core_if->dev_if->num_out_eps;
45265 + for (i = 0; i < epcount; i++) {
45266 + if (num == pcd->out_ep[i].dwc_ep.num) {
45267 + ep = &pcd->out_ep[i];
45274 + DWC_WARN("bad address\n");
45275 + retval = -DWC_E_INVALID;
45279 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45282 + ep->priv = usb_ep;
45285 + * Activate the EP
45289 + ep->dwc_ep.is_in = (dir == UE_DIR_IN);
45290 + ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize);
45292 + ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE;
45294 + if (ep->dwc_ep.is_in) {
45295 + if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45296 + ep->dwc_ep.tx_fifo_num = 0;
45298 + if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
45300 + * if ISOC EP then assign a Periodic Tx FIFO.
45302 + ep->dwc_ep.tx_fifo_num =
45303 + assign_perio_tx_fifo(GET_CORE_IF(pcd));
45307 + * if Dedicated FIFOs mode is on then assign a Tx FIFO.
45309 + ep->dwc_ep.tx_fifo_num =
45310 + assign_tx_fifo(GET_CORE_IF(pcd));
45313 + /* Calculating EP info controller base address */
45314 + if (ep->dwc_ep.tx_fifo_num
45315 + && GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45317 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
45318 + core_global_regs->gdfifocfg);
45319 + gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
45322 + (&GET_CORE_IF(pcd)->core_global_regs->
45323 + dtxfsiz[ep->dwc_ep.tx_fifo_num - 1]) >> 16);
45324 + gdfifocfg.b.epinfobase =
45325 + gdfifocfgbase.d32 + dptxfsiz.d32;
45326 + if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
45327 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
45328 + core_global_regs->gdfifocfg,
45333 + /* Set initial data PID. */
45334 + if (ep->dwc_ep.type == UE_BULK) {
45335 + ep->dwc_ep.data_pid_start = 0;
45338 + /* Alloc DMA Descriptors */
45339 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45340 +#ifndef DWC_UTE_PER_IO
45341 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
45343 + ep->dwc_ep.desc_addr =
45344 + dwc_otg_ep_alloc_desc_chain(&ep->
45345 + dwc_ep.dma_desc_addr,
45346 + MAX_DMA_DESC_CNT);
45347 + if (!ep->dwc_ep.desc_addr) {
45348 + DWC_WARN("%s, can't allocate DMA descriptor\n",
45350 + retval = -DWC_E_SHUTDOWN;
45351 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45354 +#ifndef DWC_UTE_PER_IO
45359 + DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n",
45360 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
45361 + ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc);
45362 +#ifdef DWC_UTE_PER_IO
45363 + ep->dwc_ep.xiso_bInterval = 1 << (ep->desc->bInterval - 1);
45365 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
45366 + ep->dwc_ep.bInterval = 1 << (ep->desc->bInterval - 1);
45367 + ep->dwc_ep.frame_num = 0xFFFFFFFF;
45370 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
45372 +#ifdef DWC_UTE_CFI
45373 + if (pcd->cfi->ops.ep_enable) {
45374 + pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep);
45378 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45385 + * This function is being called from gadget
45386 + * to disable PCD endpoint.
45388 +int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle)
45390 + dwc_otg_pcd_ep_t *ep;
45391 + dwc_irqflags_t flags;
45392 + dwc_otg_dev_dma_desc_t *desc_addr;
45393 + dwc_dma_t dma_desc_addr;
45394 + gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
45395 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
45396 + fifosize_data_t dptxfsiz = {.d32 = 0 };
45398 + ep = get_ep_from_handle(pcd, ep_handle);
45400 + if (!ep || !ep->desc) {
45401 + DWC_DEBUGPL(DBG_PCD, "bad ep address\n");
45402 + return -DWC_E_INVALID;
45405 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45407 + dwc_otg_request_nuke(ep);
45409 + dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep);
45410 + if (pcd->core_if->core_params->dev_out_nak) {
45411 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[ep->dwc_ep.num]);
45412 + pcd->core_if->ep_xfer_info[ep->dwc_ep.num].state = 0;
45418 + DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg);
45419 + gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
45421 + if (ep->dwc_ep.is_in) {
45422 + if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45423 + /* Flush the Tx FIFO */
45424 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd),
45425 + ep->dwc_ep.tx_fifo_num);
45427 + release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
45428 + release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
45429 + if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45430 + /* Decreasing EPinfo Base Addr */
45433 + (&GET_CORE_IF(pcd)->
45434 + core_global_regs->dtxfsiz[ep->dwc_ep.tx_fifo_num-1]) >> 16);
45435 + gdfifocfg.b.epinfobase = gdfifocfgbase.d32 - dptxfsiz.d32;
45436 + if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
45437 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg,
45443 + /* Free DMA Descriptors */
45444 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45445 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
45446 + desc_addr = ep->dwc_ep.desc_addr;
45447 + dma_desc_addr = ep->dwc_ep.dma_desc_addr;
45449 + /* Cannot call dma_free_coherent() with IRQs disabled */
45450 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45451 + dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
45452 + MAX_DMA_DESC_CNT);
45454 + goto out_unlocked;
45457 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45460 + DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num,
45461 + ep->dwc_ep.is_in ? "IN" : "OUT");
45466 +/******************************************************************************/
45467 +#ifdef DWC_UTE_PER_IO
45470 + * Free the request and its extended parts
45473 +void dwc_pcd_xiso_ereq_free(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req)
45475 + DWC_FREE(req->ext_req.per_io_frame_descs);
45480 + * Start the next request in the endpoint's queue.
45483 +int dwc_otg_pcd_xiso_start_next_request(dwc_otg_pcd_t * pcd,
45484 + dwc_otg_pcd_ep_t * ep)
45487 + dwc_otg_pcd_request_t *req = NULL;
45488 + dwc_ep_t *dwcep = NULL;
45489 + struct dwc_iso_xreq_port *ereq = NULL;
45490 + struct dwc_iso_pkt_desc_port *ddesc_iso;
45492 + depctl_data_t diepctl;
45494 + dwcep = &ep->dwc_ep;
45496 + if (dwcep->xiso_active_xfers > 0) {
45497 +#if 0 //Disable this to decrease s/w overhead that is crucial for Isoc transfers
45498 + DWC_WARN("There are currently active transfers for EP%d \
45499 + (active=%d; queued=%d)", dwcep->num, dwcep->xiso_active_xfers,
45500 + dwcep->xiso_queued_xfers);
45505 + nat = UGETW(ep->desc->wMaxPacketSize);
45506 + nat = (nat >> 11) & 0x03;
45508 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
45509 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
45510 + ereq = &req->ext_req;
45513 + /* Get the frame number */
45514 + dwcep->xiso_frame_num =
45515 + dwc_otg_get_frame_number(GET_CORE_IF(pcd));
45516 + DWC_DEBUG("FRM_NUM=%d", dwcep->xiso_frame_num);
45518 + ddesc_iso = ereq->per_io_frame_descs;
45520 + if (dwcep->is_in) {
45521 + /* Setup DMA Descriptor chain for IN Isoc request */
45522 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45523 + //if ((i % (nat + 1)) == 0)
45525 + dwcep->xiso_frame_num =
45526 + (dwcep->xiso_bInterval +
45527 + dwcep->xiso_frame_num) & 0x3FFF;
45528 + dwcep->desc_addr[i].buf =
45529 + req->dma + ddesc_iso[i].offset;
45530 + dwcep->desc_addr[i].status.b_iso_in.txbytes =
45531 + ddesc_iso[i].length;
45532 + dwcep->desc_addr[i].status.b_iso_in.framenum =
45533 + dwcep->xiso_frame_num;
45534 + dwcep->desc_addr[i].status.b_iso_in.bs =
45536 + dwcep->desc_addr[i].status.b_iso_in.txsts = 0;
45537 + dwcep->desc_addr[i].status.b_iso_in.sp =
45538 + (ddesc_iso[i].length %
45539 + dwcep->maxpacket) ? 1 : 0;
45540 + dwcep->desc_addr[i].status.b_iso_in.ioc = 0;
45541 + dwcep->desc_addr[i].status.b_iso_in.pid = nat + 1;
45542 + dwcep->desc_addr[i].status.b_iso_in.l = 0;
45544 + /* Process the last descriptor */
45545 + if (i == ereq->pio_pkt_count - 1) {
45546 + dwcep->desc_addr[i].status.b_iso_in.ioc = 1;
45547 + dwcep->desc_addr[i].status.b_iso_in.l = 1;
45551 + /* Setup and start the transfer for this endpoint */
45552 + dwcep->xiso_active_xfers++;
45553 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if->
45554 + in_ep_regs[dwcep->num]->diepdma,
45555 + dwcep->dma_desc_addr);
45557 + diepctl.b.epena = 1;
45558 + diepctl.b.cnak = 1;
45559 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
45560 + in_ep_regs[dwcep->num]->diepctl, 0,
45563 + /* Setup DMA Descriptor chain for OUT Isoc request */
45564 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45565 + //if ((i % (nat + 1)) == 0)
45566 + dwcep->xiso_frame_num = (dwcep->xiso_bInterval +
45567 + dwcep->xiso_frame_num) & 0x3FFF;
45568 + dwcep->desc_addr[i].buf =
45569 + req->dma + ddesc_iso[i].offset;
45570 + dwcep->desc_addr[i].status.b_iso_out.rxbytes =
45571 + ddesc_iso[i].length;
45572 + dwcep->desc_addr[i].status.b_iso_out.framenum =
45573 + dwcep->xiso_frame_num;
45574 + dwcep->desc_addr[i].status.b_iso_out.bs =
45576 + dwcep->desc_addr[i].status.b_iso_out.rxsts = 0;
45577 + dwcep->desc_addr[i].status.b_iso_out.sp =
45578 + (ddesc_iso[i].length %
45579 + dwcep->maxpacket) ? 1 : 0;
45580 + dwcep->desc_addr[i].status.b_iso_out.ioc = 0;
45581 + dwcep->desc_addr[i].status.b_iso_out.pid = nat + 1;
45582 + dwcep->desc_addr[i].status.b_iso_out.l = 0;
45584 + /* Process the last descriptor */
45585 + if (i == ereq->pio_pkt_count - 1) {
45586 + dwcep->desc_addr[i].status.b_iso_out.ioc = 1;
45587 + dwcep->desc_addr[i].status.b_iso_out.l = 1;
45591 + /* Setup and start the transfer for this endpoint */
45592 + dwcep->xiso_active_xfers++;
45593 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
45594 + dev_if->out_ep_regs[dwcep->num]->
45595 + doepdma, dwcep->dma_desc_addr);
45597 + diepctl.b.epena = 1;
45598 + diepctl.b.cnak = 1;
45599 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
45600 + dev_if->out_ep_regs[dwcep->num]->
45601 + doepctl, 0, diepctl.d32);
45612 + * - Remove the request from the queue
45614 +void complete_xiso_ep(dwc_otg_pcd_ep_t * ep)
45616 + dwc_otg_pcd_request_t *req = NULL;
45617 + struct dwc_iso_xreq_port *ereq = NULL;
45618 + struct dwc_iso_pkt_desc_port *ddesc_iso = NULL;
45619 + dwc_ep_t *dwcep = NULL;
45623 + dwcep = &ep->dwc_ep;
45625 + /* Get the first pending request from the queue */
45626 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
45627 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
45629 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
45632 + dwcep->xiso_active_xfers--;
45633 + dwcep->xiso_queued_xfers--;
45634 + /* Remove this request from the queue */
45635 + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
45637 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
45642 + ereq = &req->ext_req;
45643 + ddesc_iso = ereq->per_io_frame_descs;
45645 + if (dwcep->xiso_active_xfers < 0) {
45646 + DWC_WARN("EP#%d (xiso_active_xfers=%d)", dwcep->num,
45647 + dwcep->xiso_active_xfers);
45650 + /* Fill the Isoc descs of portable extended req from dma descriptors */
45651 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45652 + if (dwcep->is_in) { /* IN endpoints */
45653 + ddesc_iso[i].actual_length = ddesc_iso[i].length -
45654 + dwcep->desc_addr[i].status.b_iso_in.txbytes;
45655 + ddesc_iso[i].status =
45656 + dwcep->desc_addr[i].status.b_iso_in.txsts;
45657 + } else { /* OUT endpoints */
45658 + ddesc_iso[i].actual_length = ddesc_iso[i].length -
45659 + dwcep->desc_addr[i].status.b_iso_out.rxbytes;
45660 + ddesc_iso[i].status =
45661 + dwcep->desc_addr[i].status.b_iso_out.rxsts;
45665 + DWC_SPINUNLOCK(ep->pcd->lock);
45667 + /* Call the completion function in the non-portable logic */
45668 + ep->pcd->fops->xisoc_complete(ep->pcd, ep->priv, req->priv, 0,
45671 + DWC_SPINLOCK(ep->pcd->lock);
45673 + /* Free the request - specific freeing needed for extended request object */
45674 + dwc_pcd_xiso_ereq_free(ep, req);
45676 + /* Start the next request */
45677 + dwc_otg_pcd_xiso_start_next_request(ep->pcd, ep);
45683 + * Create and initialize the Isoc pkt descriptors of the extended request.
45686 +static int dwc_otg_pcd_xiso_create_pkt_descs(dwc_otg_pcd_request_t * req,
45687 + void *ereq_nonport,
45688 + int atomic_alloc)
45690 + struct dwc_iso_xreq_port *ereq = NULL;
45691 + struct dwc_iso_xreq_port *req_mapped = NULL;
45692 + struct dwc_iso_pkt_desc_port *ipds = NULL; /* To be created in this function */
45693 + uint32_t pkt_count;
45696 + ereq = &req->ext_req;
45697 + req_mapped = (struct dwc_iso_xreq_port *)ereq_nonport;
45698 + pkt_count = req_mapped->pio_pkt_count;
45700 + /* Create the isoc descs */
45701 + if (atomic_alloc) {
45702 + ipds = DWC_ALLOC_ATOMIC(sizeof(*ipds) * pkt_count);
45704 + ipds = DWC_ALLOC(sizeof(*ipds) * pkt_count);
45708 + DWC_ERROR("Failed to allocate isoc descriptors");
45709 + return -DWC_E_NO_MEMORY;
45712 + /* Initialize the extended request fields */
45713 + ereq->per_io_frame_descs = ipds;
45714 + ereq->error_count = 0;
45715 + ereq->pio_alloc_pkt_count = pkt_count;
45716 + ereq->pio_pkt_count = pkt_count;
45717 + ereq->tr_sub_flags = req_mapped->tr_sub_flags;
45719 + /* Init the Isoc descriptors */
45720 + for (i = 0; i < pkt_count; i++) {
45721 + ipds[i].length = req_mapped->per_io_frame_descs[i].length;
45722 + ipds[i].offset = req_mapped->per_io_frame_descs[i].offset;
45723 + ipds[i].status = req_mapped->per_io_frame_descs[i].status; /* 0 */
45724 + ipds[i].actual_length =
45725 + req_mapped->per_io_frame_descs[i].actual_length;
45731 +static void prn_ext_request(struct dwc_iso_xreq_port *ereq)
45733 + struct dwc_iso_pkt_desc_port *xfd = NULL;
45736 + DWC_DEBUG("per_io_frame_descs=%p", ereq->per_io_frame_descs);
45737 + DWC_DEBUG("tr_sub_flags=%d", ereq->tr_sub_flags);
45738 + DWC_DEBUG("error_count=%d", ereq->error_count);
45739 + DWC_DEBUG("pio_alloc_pkt_count=%d", ereq->pio_alloc_pkt_count);
45740 + DWC_DEBUG("pio_pkt_count=%d", ereq->pio_pkt_count);
45741 + DWC_DEBUG("res=%d", ereq->res);
45743 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45744 + xfd = &ereq->per_io_frame_descs[0];
45745 + DWC_DEBUG("FD #%d", i);
45747 + DWC_DEBUG("xfd->actual_length=%d", xfd->actual_length);
45748 + DWC_DEBUG("xfd->length=%d", xfd->length);
45749 + DWC_DEBUG("xfd->offset=%d", xfd->offset);
45750 + DWC_DEBUG("xfd->status=%d", xfd->status);
45757 +int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
45758 + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
45759 + int zero, void *req_handle, int atomic_alloc,
45760 + void *ereq_nonport)
45762 + dwc_otg_pcd_request_t *req = NULL;
45763 + dwc_otg_pcd_ep_t *ep;
45764 + dwc_irqflags_t flags;
45767 + ep = get_ep_from_handle(pcd, ep_handle);
45769 + DWC_WARN("bad ep\n");
45770 + return -DWC_E_INVALID;
45773 + /* We support this extension only for DDMA mode */
45774 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
45775 + if (!GET_CORE_IF(pcd)->dma_desc_enable)
45776 + return -DWC_E_INVALID;
45778 + /* Create a dwc_otg_pcd_request_t object */
45779 + if (atomic_alloc) {
45780 + req = DWC_ALLOC_ATOMIC(sizeof(*req));
45782 + req = DWC_ALLOC(sizeof(*req));
45786 + return -DWC_E_NO_MEMORY;
45789 + /* Create the Isoc descs for this request which shall be the exact match
45790 + * of the structure sent to us from the non-portable logic */
45792 + dwc_otg_pcd_xiso_create_pkt_descs(req, ereq_nonport, atomic_alloc);
45794 + DWC_WARN("Failed to init the Isoc descriptors");
45799 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45801 + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
45803 + req->dma = dma_buf;
45804 + req->length = buflen;
45805 + req->sent_zlp = zero;
45806 + req->priv = req_handle;
45808 + //DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45809 + ep->dwc_ep.dma_addr = dma_buf;
45810 + ep->dwc_ep.start_xfer_buff = buf;
45811 + ep->dwc_ep.xfer_buff = buf;
45812 + ep->dwc_ep.xfer_len = 0;
45813 + ep->dwc_ep.xfer_count = 0;
45814 + ep->dwc_ep.sent_zlp = 0;
45815 + ep->dwc_ep.total_len = buflen;
45817 + /* Add this request to the tail */
45818 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
45819 + ep->dwc_ep.xiso_queued_xfers++;
45821 +//DWC_DEBUG("CP_0");
45822 +//DWC_DEBUG("req->ext_req.tr_sub_flags=%d", req->ext_req.tr_sub_flags);
45823 +//prn_ext_request((struct dwc_iso_xreq_port *) ereq_nonport);
45824 +//prn_ext_request(&req->ext_req);
45826 + //DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45828 + /* If the req->status == ASAP then check if there is any active transfer
45829 + * for this endpoint. If no active transfers, then get the first entry
45830 + * from the queue and start that transfer
45832 + if (req->ext_req.tr_sub_flags == DWC_EREQ_TF_ASAP) {
45833 + res = dwc_otg_pcd_xiso_start_next_request(pcd, ep);
45835 + DWC_WARN("Failed to start the next Isoc transfer");
45836 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45842 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45847 +/* END ifdef DWC_UTE_PER_IO ***************************************************/
45848 +int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
45849 + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
45850 + int zero, void *req_handle, int atomic_alloc)
45852 + dwc_irqflags_t flags;
45853 + dwc_otg_pcd_request_t *req;
45854 + dwc_otg_pcd_ep_t *ep;
45855 + uint32_t max_transfer;
45857 + ep = get_ep_from_handle(pcd, ep_handle);
45858 + if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
45859 + DWC_WARN("bad ep\n");
45860 + return -DWC_E_INVALID;
45863 + if (atomic_alloc) {
45864 + req = DWC_ALLOC_ATOMIC(sizeof(*req));
45866 + req = DWC_ALLOC(sizeof(*req));
45870 + return -DWC_E_NO_MEMORY;
45872 + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
45873 + if (!GET_CORE_IF(pcd)->core_params->opt) {
45874 + if (ep->dwc_ep.num != 0) {
45875 + DWC_ERROR("queue req %p, len %d buf %p\n",
45876 + req_handle, buflen, buf);
45881 + req->dma = dma_buf;
45882 + req->length = buflen;
45883 + req->sent_zlp = zero;
45884 + req->priv = req_handle;
45885 + req->dw_align_buf = NULL;
45886 + if ((dma_buf & 0x3) && GET_CORE_IF(pcd)->dma_enable
45887 + && !GET_CORE_IF(pcd)->dma_desc_enable)
45888 + req->dw_align_buf = DWC_DMA_ALLOC(buflen,
45889 + &req->dw_align_buf_dma);
45890 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45893 + * After adding request to the queue for IN ISOC wait for In Token Received
45894 + * when TX FIFO is empty interrupt and for OUT ISOC wait for OUT Token
45895 + * Received when EP is disabled interrupt to obtain starting microframe
45896 + * (odd/even) start transfer
45898 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
45900 + depctl_data_t depctl = {.d32 =
45901 + DWC_READ_REG32(&pcd->core_if->dev_if->
45902 + in_ep_regs[ep->dwc_ep.num]->
45904 + ++pcd->request_pending;
45906 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
45907 + if (ep->dwc_ep.is_in) {
45908 + depctl.b.cnak = 1;
45909 + DWC_WRITE_REG32(&pcd->core_if->dev_if->
45910 + in_ep_regs[ep->dwc_ep.num]->
45911 + diepctl, depctl.d32);
45914 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45920 + * For EP0 IN without premature status, zlp is required?
45922 + if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {
45923 + DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num);
45924 + //_req->zero = 1;
45927 + /* Start the transfer */
45928 + if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) {
45929 + /* EP0 Transfer? */
45930 + if (ep->dwc_ep.num == 0) {
45931 + switch (pcd->ep0state) {
45932 + case EP0_IN_DATA_PHASE:
45933 + DWC_DEBUGPL(DBG_PCD,
45934 + "%s ep0: EP0_IN_DATA_PHASE\n",
45938 + case EP0_OUT_DATA_PHASE:
45939 + DWC_DEBUGPL(DBG_PCD,
45940 + "%s ep0: EP0_OUT_DATA_PHASE\n",
45942 + if (pcd->request_config) {
45943 + /* Complete STATUS PHASE */
45944 + ep->dwc_ep.is_in = 1;
45945 + pcd->ep0state = EP0_IN_STATUS_PHASE;
45949 + case EP0_IN_STATUS_PHASE:
45950 + DWC_DEBUGPL(DBG_PCD,
45951 + "%s ep0: EP0_IN_STATUS_PHASE\n",
45956 + DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
45958 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45959 + return -DWC_E_SHUTDOWN;
45962 + ep->dwc_ep.dma_addr = dma_buf;
45963 + ep->dwc_ep.start_xfer_buff = buf;
45964 + ep->dwc_ep.xfer_buff = buf;
45965 + ep->dwc_ep.xfer_len = buflen;
45966 + ep->dwc_ep.xfer_count = 0;
45967 + ep->dwc_ep.sent_zlp = 0;
45968 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
45971 + if ((ep->dwc_ep.xfer_len %
45972 + ep->dwc_ep.maxpacket == 0)
45973 + && (ep->dwc_ep.xfer_len != 0)) {
45974 + ep->dwc_ep.sent_zlp = 1;
45979 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
45981 + } // non-ep0 endpoints
45983 +#ifdef DWC_UTE_CFI
45984 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
45985 + /* store the request length */
45986 + ep->dwc_ep.cfi_req_len = buflen;
45987 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd,
45992 + GET_CORE_IF(ep->pcd)->core_params->
45993 + max_transfer_size;
45995 + /* Setup and start the Transfer */
45996 + if (req->dw_align_buf){
45997 + if (ep->dwc_ep.is_in)
45998 + dwc_memcpy(req->dw_align_buf,
46000 + ep->dwc_ep.dma_addr =
46001 + req->dw_align_buf_dma;
46002 + ep->dwc_ep.start_xfer_buff =
46003 + req->dw_align_buf;
46004 + ep->dwc_ep.xfer_buff =
46005 + req->dw_align_buf;
46007 + ep->dwc_ep.dma_addr = dma_buf;
46008 + ep->dwc_ep.start_xfer_buff = buf;
46009 + ep->dwc_ep.xfer_buff = buf;
46011 + ep->dwc_ep.xfer_len = 0;
46012 + ep->dwc_ep.xfer_count = 0;
46013 + ep->dwc_ep.sent_zlp = 0;
46014 + ep->dwc_ep.total_len = buflen;
46016 + ep->dwc_ep.maxxfer = max_transfer;
46017 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
46018 + uint32_t out_max_xfer =
46019 + DDMA_MAX_TRANSFER_SIZE -
46020 + (DDMA_MAX_TRANSFER_SIZE % 4);
46021 + if (ep->dwc_ep.is_in) {
46022 + if (ep->dwc_ep.maxxfer >
46023 + DDMA_MAX_TRANSFER_SIZE) {
46024 + ep->dwc_ep.maxxfer =
46025 + DDMA_MAX_TRANSFER_SIZE;
46028 + if (ep->dwc_ep.maxxfer >
46030 + ep->dwc_ep.maxxfer =
46035 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
46036 + ep->dwc_ep.maxxfer -=
46037 + (ep->dwc_ep.maxxfer %
46038 + ep->dwc_ep.maxpacket);
46042 + if ((ep->dwc_ep.total_len %
46043 + ep->dwc_ep.maxpacket == 0)
46044 + && (ep->dwc_ep.total_len != 0)) {
46045 + ep->dwc_ep.sent_zlp = 1;
46048 +#ifdef DWC_UTE_CFI
46051 + dwc_otg_ep_start_transfer(GET_CORE_IF(pcd),
46057 + ++pcd->request_pending;
46058 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
46059 + if (ep->dwc_ep.is_in && ep->stopped
46060 + && !(GET_CORE_IF(pcd)->dma_enable)) {
46061 + /** @todo NGS Create a function for this. */
46062 + diepmsk_data_t diepmsk = {.d32 = 0 };
46063 + diepmsk.b.intktxfemp = 1;
46064 + if (GET_CORE_IF(pcd)->multiproc_int_enable) {
46065 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
46066 + dev_if->dev_global_regs->diepeachintmsk
46067 + [ep->dwc_ep.num], 0,
46070 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
46071 + dev_if->dev_global_regs->
46072 + diepmsk, 0, diepmsk.d32);
46077 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46082 +int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
46083 + void *req_handle)
46085 + dwc_irqflags_t flags;
46086 + dwc_otg_pcd_request_t *req;
46087 + dwc_otg_pcd_ep_t *ep;
46089 + ep = get_ep_from_handle(pcd, ep_handle);
46090 + if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
46091 + DWC_WARN("bad argument\n");
46092 + return -DWC_E_INVALID;
46095 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46097 + /* make sure it's actually queued on this endpoint */
46098 + DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
46099 + if (req->priv == (void *)req_handle) {
46104 + if (req->priv != (void *)req_handle) {
46105 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46106 + return -DWC_E_INVALID;
46109 + if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) {
46110 + dwc_otg_request_done(ep, req, -DWC_E_RESTART);
46115 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46117 + return req ? 0 : -DWC_E_SHUTDOWN;
46122 + * dwc_otg_pcd_ep_wedge - sets the halt feature and ignores clear requests
46124 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
46125 + * requests. If the gadget driver clears the halt status, it will
46126 + * automatically unwedge the endpoint.
46128 + * Returns zero on success, else negative DWC error code.
46130 +int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle)
46132 + dwc_otg_pcd_ep_t *ep;
46133 + dwc_irqflags_t flags;
46136 + ep = get_ep_from_handle(pcd, ep_handle);
46138 + if ((!ep->desc && ep != &pcd->ep0) ||
46139 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
46140 + DWC_WARN("%s, bad ep\n", __func__);
46141 + return -DWC_E_INVALID;
46144 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46145 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
46146 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
46147 + ep->dwc_ep.is_in ? "IN" : "OUT");
46148 + retval = -DWC_E_AGAIN;
46150 + /* This code needs to be reviewed */
46151 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
46152 + dtxfsts_data_t txstatus;
46153 + fifosize_data_t txfifosize;
46156 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
46157 + core_global_regs->dtxfsiz[ep->dwc_ep.
46160 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
46161 + dev_if->in_ep_regs[ep->dwc_ep.num]->
46164 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
46165 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
46166 + retval = -DWC_E_AGAIN;
46168 + if (ep->dwc_ep.num == 0) {
46169 + pcd->ep0state = EP0_STALL;
46173 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
46177 + if (ep->dwc_ep.num == 0) {
46178 + pcd->ep0state = EP0_STALL;
46182 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46186 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46191 +int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value)
46193 + dwc_otg_pcd_ep_t *ep;
46194 + dwc_irqflags_t flags;
46197 + ep = get_ep_from_handle(pcd, ep_handle);
46199 + if (!ep || (!ep->desc && ep != &pcd->ep0) ||
46200 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
46201 + DWC_WARN("%s, bad ep\n", __func__);
46202 + return -DWC_E_INVALID;
46205 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46206 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
46207 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
46208 + ep->dwc_ep.is_in ? "IN" : "OUT");
46209 + retval = -DWC_E_AGAIN;
46210 + } else if (value == 0) {
46211 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46212 + } else if (value == 1) {
46213 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
46214 + dtxfsts_data_t txstatus;
46215 + fifosize_data_t txfifosize;
46218 + DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->
46219 + dtxfsiz[ep->dwc_ep.tx_fifo_num]);
46221 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
46222 + in_ep_regs[ep->dwc_ep.num]->dtxfsts);
46224 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
46225 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
46226 + retval = -DWC_E_AGAIN;
46228 + if (ep->dwc_ep.num == 0) {
46229 + pcd->ep0state = EP0_STALL;
46233 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
46237 + if (ep->dwc_ep.num == 0) {
46238 + pcd->ep0state = EP0_STALL;
46242 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46244 + } else if (value == 2) {
46245 + ep->dwc_ep.stall_clear_flag = 0;
46246 + } else if (value == 3) {
46247 + ep->dwc_ep.stall_clear_flag = 1;
46250 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46256 + * This function initiates remote wakeup of the host from suspend state.
46258 +void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set)
46260 + dctl_data_t dctl = { 0 };
46261 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46262 + dsts_data_t dsts;
46264 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
46265 + if (!dsts.b.suspsts) {
46266 + DWC_WARN("Remote wakeup while is not in suspend state\n");
46268 + /* Check if DEVICE_REMOTE_WAKEUP feature enabled */
46269 + if (pcd->remote_wakeup_enable) {
46272 + if (core_if->adp_enable) {
46273 + gpwrdn_data_t gpwrdn;
46275 + dwc_otg_adp_probe_stop(core_if);
46277 + /* Mask SRP detected interrupt from Power Down Logic */
46279 + gpwrdn.b.srp_det_msk = 1;
46280 + DWC_MODIFY_REG32(&core_if->
46281 + core_global_regs->gpwrdn,
46284 + /* Disable Power Down Logic */
46286 + gpwrdn.b.pmuactv = 1;
46287 + DWC_MODIFY_REG32(&core_if->
46288 + core_global_regs->gpwrdn,
46292 + * Initialize the Core for Device mode.
46294 + core_if->op_state = B_PERIPHERAL;
46295 + dwc_otg_core_init(core_if);
46296 + dwc_otg_enable_global_interrupts(core_if);
46297 + cil_pcd_start(core_if);
46299 + dwc_otg_initiate_srp(core_if);
46302 + dctl.b.rmtwkupsig = 1;
46303 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
46304 + dctl, 0, dctl.d32);
46305 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
46308 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
46309 + dctl, dctl.d32, 0);
46310 + DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
46313 + DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
46317 +#ifdef CONFIG_USB_DWC_OTG_LPM
46319 + * This function initiates remote wakeup of the host from L1 sleep state.
46321 +void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set)
46323 + glpmcfg_data_t lpmcfg;
46324 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46326 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
46328 + /* Check if we are in L1 state */
46329 + if (!lpmcfg.b.prt_sleep_sts) {
46330 + DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n");
46334 + /* Check if host allows remote wakeup */
46335 + if (!lpmcfg.b.rem_wkup_en) {
46336 + DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n");
46340 + /* Check if Resume OK */
46341 + if (!lpmcfg.b.sleep_state_resumeok) {
46342 + DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n");
46346 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
46347 + lpmcfg.b.en_utmi_sleep = 0;
46348 + lpmcfg.b.hird_thres &= (~(1 << 4));
46349 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
46352 + dctl_data_t dctl = {.d32 = 0 };
46353 + dctl.b.rmtwkupsig = 1;
46354 + /* Set RmtWkUpSig bit to start remote wakup signaling.
46355 + * Hardware will automatically clear this bit.
46357 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl,
46359 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
46366 + * Performs remote wakeup.
46368 +void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set)
46370 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46371 + dwc_irqflags_t flags;
46372 + if (dwc_otg_is_device_mode(core_if)) {
46373 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46374 +#ifdef CONFIG_USB_DWC_OTG_LPM
46375 + if (core_if->lx_state == DWC_OTG_L1) {
46376 + dwc_otg_pcd_rem_wkup_from_sleep(pcd, set);
46379 + dwc_otg_pcd_rem_wkup_from_suspend(pcd, set);
46380 +#ifdef CONFIG_USB_DWC_OTG_LPM
46383 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46388 +void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs)
46390 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46391 + dctl_data_t dctl = { 0 };
46393 + if (dwc_otg_is_device_mode(core_if)) {
46394 + dctl.b.sftdiscon = 1;
46395 + DWC_PRINTF("Soft disconnect for %d useconds\n",no_of_usecs);
46396 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
46397 + dwc_udelay(no_of_usecs);
46398 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32,0);
46401 + DWC_PRINTF("NOT SUPPORTED IN HOST MODE\n");
46407 +int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd)
46409 + dsts_data_t dsts;
46410 + gotgctl_data_t gotgctl;
46413 + * This function starts the Protocol if no session is in progress. If
46414 + * a session is already in progress, but the device is suspended,
46415 + * remote wakeup signaling is started.
46418 + /* Check if valid session */
46420 + DWC_READ_REG32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
46421 + if (gotgctl.b.bsesvld) {
46422 + /* Check if suspend state */
46425 + (GET_CORE_IF(pcd)->dev_if->
46426 + dev_global_regs->dsts));
46427 + if (dsts.b.suspsts) {
46428 + dwc_otg_pcd_remote_wakeup(pcd, 1);
46431 + dwc_otg_pcd_initiate_srp(pcd);
46439 + * Start the SRP timer to detect when the SRP does not complete within
46442 + * @param pcd the pcd structure.
46444 +void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd)
46446 + dwc_irqflags_t flags;
46447 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46448 + dwc_otg_initiate_srp(GET_CORE_IF(pcd));
46449 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46452 +int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd)
46454 + return dwc_otg_get_frame_number(GET_CORE_IF(pcd));
46457 +int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd)
46459 + return GET_CORE_IF(pcd)->core_params->lpm_enable;
46462 +uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd)
46464 + return pcd->b_hnp_enable;
46467 +uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd)
46469 + return pcd->a_hnp_support;
46472 +uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd)
46474 + return pcd->a_alt_hnp_support;
46477 +int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd)
46479 + return pcd->remote_wakeup_enable;
46482 +#endif /* DWC_HOST_ONLY */
46484 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.h
46486 +/* ==========================================================================
46487 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $
46488 + * $Revision: #48 $
46489 + * $Date: 2012/08/10 $
46490 + * $Change: 2047372 $
46492 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
46493 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
46494 + * otherwise expressly agreed to in writing between Synopsys and you.
46496 + * The Software IS NOT an item of Licensed Software or Licensed Product under
46497 + * any End User Software License Agreement or Agreement for Licensed Product
46498 + * with Synopsys or any supplement thereto. You are permitted to use and
46499 + * redistribute this Software in source and binary forms, with or without
46500 + * modification, provided that redistributions of source code must retain this
46501 + * notice. You may not view, use, disclose, copy or distribute this file or
46502 + * any information contained herein except pursuant to this license grant from
46503 + * Synopsys. If you do not agree with this notice, including the disclaimer
46504 + * below, then you are not authorized to use the Software.
46506 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
46507 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46508 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46509 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
46510 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46511 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
46512 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
46513 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46514 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46515 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46517 + * ========================================================================== */
46518 +#ifndef DWC_HOST_ONLY
46519 +#if !defined(__DWC_PCD_H__)
46520 +#define __DWC_PCD_H__
46522 +#include "dwc_otg_os_dep.h"
46524 +#include "dwc_otg_cil.h"
46525 +#include "dwc_otg_pcd_if.h"
46531 + * This file contains the structures, constants, and interfaces for
46532 + * the Perpherial Contoller Driver (PCD).
46534 + * The Peripheral Controller Driver (PCD) for Linux will implement the
46535 + * Gadget API, so that the existing Gadget drivers can be used. For
46536 + * the Mass Storage Function driver the File-backed USB Storage Gadget
46537 + * (FBS) driver will be used. The FBS driver supports the
46538 + * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only
46543 +/** Invalid DMA Address */
46544 +#define DWC_DMA_ADDR_INVALID (~(dwc_dma_t)0)
46546 +/** Max Transfer size for any EP */
46547 +#define DDMA_MAX_TRANSFER_SIZE 65535
46550 + * Get the pointer to the core_if from the pcd pointer.
46552 +#define GET_CORE_IF( _pcd ) (_pcd->core_if)
46557 +typedef enum ep0_state {
46558 + EP0_DISCONNECT, /* no host */
46560 + EP0_IN_DATA_PHASE,
46561 + EP0_OUT_DATA_PHASE,
46562 + EP0_IN_STATUS_PHASE,
46563 + EP0_OUT_STATUS_PHASE,
46567 +/** Fordward declaration.*/
46568 +struct dwc_otg_pcd;
46570 +/** DWC_otg iso request structure.
46573 +typedef struct usb_iso_request dwc_otg_pcd_iso_request_t;
46575 +#ifdef DWC_UTE_PER_IO
46578 + * This shall be the exact analogy of the same type structure defined in the
46579 + * usb_gadget.h. Each descriptor contains
46581 +struct dwc_iso_pkt_desc_port {
46583 + uint32_t length; /* expected length */
46584 + uint32_t actual_length;
46588 +struct dwc_iso_xreq_port {
46589 + /** transfer/submission flag */
46590 + uint32_t tr_sub_flags;
46591 + /** Start the request ASAP */
46592 +#define DWC_EREQ_TF_ASAP 0x00000002
46593 + /** Just enqueue the request w/o initiating a transfer */
46594 +#define DWC_EREQ_TF_ENQUEUE 0x00000004
46597 + * count of ISO packets attached to this request - shall
46598 + * not exceed the pio_alloc_pkt_count
46600 + uint32_t pio_pkt_count;
46601 + /** count of ISO packets allocated for this request */
46602 + uint32_t pio_alloc_pkt_count;
46603 + /** number of ISO packet errors */
46604 + uint32_t error_count;
46605 + /** reserved for future extension */
46607 + /** Will be allocated and freed in the UTE gadget and based on the CFC value */
46608 + struct dwc_iso_pkt_desc_port *per_io_frame_descs;
46611 +/** DWC_otg request structure.
46612 + * This structure is a list of requests.
46614 +typedef struct dwc_otg_pcd_request {
46620 + unsigned sent_zlp:1;
46622 + * Used instead of original buffer if
46623 + * it(physical address) is not dword-aligned.
46625 + uint8_t *dw_align_buf;
46626 + dwc_dma_t dw_align_buf_dma;
46628 + DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry;
46629 +#ifdef DWC_UTE_PER_IO
46630 + struct dwc_iso_xreq_port ext_req;
46631 + //void *priv_ereq_nport; /* */
46633 +} dwc_otg_pcd_request_t;
46635 +DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request);
46637 +/** PCD EP structure.
46638 + * This structure describes an EP, there is an array of EPs in the PCD
46641 +typedef struct dwc_otg_pcd_ep {
46642 + /** USB EP Descriptor */
46643 + const usb_endpoint_descriptor_t *desc;
46645 + /** queue of dwc_otg_pcd_requests. */
46646 + struct req_list queue;
46647 + unsigned stopped:1;
46648 + unsigned disabling:1;
46650 + unsigned queue_sof:1;
46652 +#ifdef DWC_EN_ISOC
46653 + /** ISOC req handle passed */
46654 + void *iso_req_handle;
46655 +#endif //_EN_ISOC_
46657 + /** DWC_otg ep data. */
46660 + /** Pointer to PCD */
46661 + struct dwc_otg_pcd *pcd;
46664 +} dwc_otg_pcd_ep_t;
46666 +/** DWC_otg PCD Structure.
46667 + * This structure encapsulates the data for the dwc_otg PCD.
46669 +struct dwc_otg_pcd {
46670 + const struct dwc_otg_pcd_function_ops *fops;
46671 + /** The DWC otg device pointer */
46672 + struct dwc_otg_device *otg_dev;
46673 + /** Core Interface */
46674 + dwc_otg_core_if_t *core_if;
46675 + /** State of EP0 */
46676 + ep0state_e ep0state;
46677 + /** EP0 Request is pending */
46678 + unsigned ep0_pending:1;
46679 + /** Indicates when SET CONFIGURATION Request is in process */
46680 + unsigned request_config:1;
46681 + /** The state of the Remote Wakeup Enable. */
46682 + unsigned remote_wakeup_enable:1;
46683 + /** The state of the B-Device HNP Enable. */
46684 + unsigned b_hnp_enable:1;
46685 + /** The state of A-Device HNP Support. */
46686 + unsigned a_hnp_support:1;
46687 + /** The state of the A-Device Alt HNP support. */
46688 + unsigned a_alt_hnp_support:1;
46689 + /** Count of pending Requests */
46690 + unsigned request_pending;
46692 + /** SETUP packet for EP0
46693 + * This structure is allocated as a DMA buffer on PCD initialization
46694 + * with enough space for up to 3 setup packets.
46697 + usb_device_request_t req;
46701 + dwc_dma_t setup_pkt_dma_handle;
46703 + /* Additional buffer and flag for CTRL_WR premature case */
46704 + uint8_t *backup_buf;
46705 + unsigned data_terminated;
46707 + /** 2-byte dma buffer used to return status from GET_STATUS */
46708 + uint16_t *status_buf;
46709 + dwc_dma_t status_buf_dma_handle;
46712 + dwc_otg_pcd_ep_t ep0;
46714 + /** Array of IN EPs. */
46715 + dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1];
46716 + /** Array of OUT EPs. */
46717 + dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1];
46718 + /** number of valid EPs in the above array. */
46719 +// unsigned num_eps : 4;
46720 + dwc_spinlock_t *lock;
46722 + /** Tasklet to defer starting of TEST mode transmissions until
46723 + * Status Phase has been completed.
46725 + dwc_tasklet_t *test_mode_tasklet;
46727 + /** Tasklet to delay starting of xfer in DMA mode */
46728 + dwc_tasklet_t *start_xfer_tasklet;
46730 + /** The test mode to enter when the tasklet is executed. */
46731 + unsigned test_mode;
46732 + /** The cfi_api structure that implements most of the CFI API
46733 + * and OTG specific core configuration functionality
46735 +#ifdef DWC_UTE_CFI
46736 + struct cfiobject *cfi;
46741 +//FIXME this functions should be static, and this prototypes should be removed
46742 +extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep);
46743 +extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep,
46744 + dwc_otg_pcd_request_t * req, int32_t status);
46746 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
46747 + void *req_handle);
46749 +extern void do_test_mode(void *data);
46751 +#endif /* DWC_HOST_ONLY */
46753 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
46755 +/* ==========================================================================
46756 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $
46757 + * $Revision: #11 $
46758 + * $Date: 2011/10/26 $
46759 + * $Change: 1873028 $
46761 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
46762 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
46763 + * otherwise expressly agreed to in writing between Synopsys and you.
46765 + * The Software IS NOT an item of Licensed Software or Licensed Product under
46766 + * any End User Software License Agreement or Agreement for Licensed Product
46767 + * with Synopsys or any supplement thereto. You are permitted to use and
46768 + * redistribute this Software in source and binary forms, with or without
46769 + * modification, provided that redistributions of source code must retain this
46770 + * notice. You may not view, use, disclose, copy or distribute this file or
46771 + * any information contained herein except pursuant to this license grant from
46772 + * Synopsys. If you do not agree with this notice, including the disclaimer
46773 + * below, then you are not authorized to use the Software.
46775 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
46776 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46777 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46778 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
46779 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46780 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
46781 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
46782 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46783 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46784 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46786 + * ========================================================================== */
46787 +#ifndef DWC_HOST_ONLY
46789 +#if !defined(__DWC_PCD_IF_H__)
46790 +#define __DWC_PCD_IF_H__
46792 +//#include "dwc_os.h"
46793 +#include "dwc_otg_core_if.h"
46796 + * This file defines DWC_OTG PCD Core API.
46799 +struct dwc_otg_pcd;
46800 +typedef struct dwc_otg_pcd dwc_otg_pcd_t;
46802 +/** Maxpacket size for EP0 */
46803 +#define MAX_EP0_SIZE 64
46804 +/** Maxpacket size for any EP */
46805 +#define MAX_PACKET_SIZE 1024
46807 +/** @name Function Driver Callbacks */
46810 +/** This function will be called whenever a previously queued request has
46811 + * completed. The status value will be set to -DWC_E_SHUTDOWN to indicated a
46812 + * failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset,
46813 + * or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid
46815 +typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
46816 + void *req_handle, int32_t status,
46817 + uint32_t actual);
46819 + * This function will be called whenever a previousle queued ISOC request has
46820 + * completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count
46822 + * The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_*
46825 +typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
46826 + void *req_handle, int proc_buf_num);
46827 +/** This function should handle any SETUP request that cannot be handled by the
46828 + * PCD Core. This includes most GET_DESCRIPTORs, SET_CONFIGS, Any
46829 + * class-specific requests, etc. The function must non-blocking.
46831 + * Returns 0 on success.
46832 + * Returns -DWC_E_NOT_SUPPORTED if the request is not supported.
46833 + * Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes.
46834 + * Returns -DWC_E_SHUTDOWN on any other error. */
46835 +typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes);
46836 +/** This is called whenever the device has been disconnected. The function
46837 + * driver should take appropriate action to clean up all pending requests in the
46838 + * PCD Core, remove all endpoints (except ep0), and initialize back to reset
46840 +typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd);
46841 +/** This function is called when device has been connected. */
46842 +typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed);
46843 +/** This function is called when device has been suspended */
46844 +typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd);
46845 +/** This function is called when device has received LPM tokens, i.e.
46846 + * device has been sent to sleep state. */
46847 +typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd);
46848 +/** This function is called when device has been resumed
46849 + * from suspend(L2) or L1 sleep state. */
46850 +typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd);
46851 +/** This function is called whenever hnp params has been changed.
46852 + * User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions
46853 + * to get hnp parameters. */
46854 +typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd);
46855 +/** This function is called whenever USB RESET is detected. */
46856 +typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd);
46858 +typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes);
46862 + * @param ep_handle Void pointer to the usb_ep structure
46863 + * @param ereq_port Pointer to the extended request structure created in the
46866 +typedef int (*xiso_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
46867 + void *req_handle, int32_t status,
46868 + void *ereq_port);
46869 +/** Function Driver Ops Data Structure */
46870 +struct dwc_otg_pcd_function_ops {
46871 + dwc_connect_cb_t connect;
46872 + dwc_disconnect_cb_t disconnect;
46873 + dwc_setup_cb_t setup;
46874 + dwc_completion_cb_t complete;
46875 + dwc_isoc_completion_cb_t isoc_complete;
46876 + dwc_suspend_cb_t suspend;
46877 + dwc_sleep_cb_t sleep;
46878 + dwc_resume_cb_t resume;
46879 + dwc_reset_cb_t reset;
46880 + dwc_hnp_params_changed_cb_t hnp_changed;
46881 + cfi_setup_cb_t cfi_setup;
46882 +#ifdef DWC_UTE_PER_IO
46883 + xiso_completion_cb_t xisoc_complete;
46888 +/** @name Function Driver Functions */
46891 +/** Call this function to get pointer on dwc_otg_pcd_t,
46892 + * this pointer will be used for all PCD API functions.
46894 + * @param core_if The DWC_OTG Core
46896 +extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if);
46898 +/** Frees PCD allocated by dwc_otg_pcd_init
46900 + * @param pcd The PCD
46902 +extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd);
46904 +/** Call this to bind the function driver to the PCD Core.
46906 + * @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
46907 + * @param fops The Function Driver Ops data structure containing pointers to all callbacks.
46909 +extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
46910 + const struct dwc_otg_pcd_function_ops *fops);
46912 +/** Enables an endpoint for use. This function enables an endpoint in
46913 + * the PCD. The endpoint is described by the ep_desc which has the
46914 + * same format as a USB ep descriptor. The ep_handle parameter is used to refer
46915 + * to the endpoint from other API functions and in callbacks. Normally this
46916 + * should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the
46917 + * core for that interface.
46919 + * Returns -DWC_E_INVALID if invalid parameters were passed.
46920 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
46921 + * Returns 0 on success.
46923 + * @param pcd The PCD
46924 + * @param ep_desc Endpoint descriptor
46925 + * @param usb_ep Handle on endpoint, that will be used to identify endpoint.
46927 +extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
46928 + const uint8_t * ep_desc, void *usb_ep);
46930 +/** Disable the endpoint referenced by ep_handle.
46932 + * Returns -DWC_E_INVALID if invalid parameters were passed.
46933 + * Returns -DWC_E_SHUTDOWN if any other error occurred.
46934 + * Returns 0 on success. */
46935 +extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle);
46937 +/** Queue a data transfer request on the endpoint referenced by ep_handle.
46938 + * After the transfer is completes, the complete callback will be called with
46939 + * the request status.
46941 + * @param pcd The PCD
46942 + * @param ep_handle The handle of the endpoint
46943 + * @param buf The buffer for the data
46944 + * @param dma_buf The DMA buffer for the data
46945 + * @param buflen The length of the data transfer
46946 + * @param zero Specifies whether to send zero length last packet.
46947 + * @param req_handle Set this handle to any value to use to reference this
46948 + * request in the ep_dequeue function or from the complete callback
46949 + * @param atomic_alloc If driver need to perform atomic allocations
46950 + * for internal data structures.
46952 + * Returns -DWC_E_INVALID if invalid parameters were passed.
46953 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
46954 + * Returns 0 on success. */
46955 +extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
46956 + uint8_t * buf, dwc_dma_t dma_buf,
46957 + uint32_t buflen, int zero, void *req_handle,
46958 + int atomic_alloc);
46959 +#ifdef DWC_UTE_PER_IO
46962 + * @param ereq_nonport Pointer to the extended request part of the
46963 + * usb_request structure defined in usb_gadget.h file.
46965 +extern int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
46966 + uint8_t * buf, dwc_dma_t dma_buf,
46967 + uint32_t buflen, int zero,
46968 + void *req_handle, int atomic_alloc,
46969 + void *ereq_nonport);
46973 +/** De-queue the specified data transfer that has not yet completed.
46975 + * Returns -DWC_E_INVALID if invalid parameters were passed.
46976 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
46977 + * Returns 0 on success. */
46978 +extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
46979 + void *req_handle);
46981 +/** Halt (STALL) an endpoint or clear it.
46983 + * Returns -DWC_E_INVALID if invalid parameters were passed.
46984 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
46985 + * Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later
46986 + * Returns 0 on success. */
46987 +extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value);
46989 +/** This function */
46990 +extern int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle);
46992 +/** This function should be called on every hardware interrupt */
46993 +extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd);
46995 +/** This function returns current frame number */
46996 +extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd);
46999 + * Start isochronous transfers on the endpoint referenced by ep_handle.
47000 + * For isochronous transfers duble buffering is used.
47001 + * After processing each of buffers comlete callback will be called with
47002 + * status for each transaction.
47004 + * @param pcd The PCD
47005 + * @param ep_handle The handle of the endpoint
47006 + * @param buf0 The virtual address of first data buffer
47007 + * @param buf1 The virtual address of second data buffer
47008 + * @param dma0 The DMA address of first data buffer
47009 + * @param dma1 The DMA address of second data buffer
47010 + * @param sync_frame Data pattern frame number
47011 + * @param dp_frame Data size for pattern frame
47012 + * @param data_per_frame Data size for regular frame
47013 + * @param start_frame Frame number to start transfers, if -1 then start transfers ASAP.
47014 + * @param buf_proc_intrvl Interval of ISOC Buffer processing
47015 + * @param req_handle Handle of ISOC request
47016 + * @param atomic_alloc Specefies whether to perform atomic allocation for
47017 + * internal data structures.
47019 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
47020 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function.
47021 + * Returns -DW_E_SHUTDOWN for any other error.
47022 + * Returns 0 on success
47024 +extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
47025 + uint8_t * buf0, uint8_t * buf1,
47026 + dwc_dma_t dma0, dwc_dma_t dma1,
47027 + int sync_frame, int dp_frame,
47028 + int data_per_frame, int start_frame,
47029 + int buf_proc_intrvl, void *req_handle,
47030 + int atomic_alloc);
47032 +/** Stop ISOC transfers on endpoint referenced by ep_handle.
47034 + * @param pcd The PCD
47035 + * @param ep_handle The handle of the endpoint
47036 + * @param req_handle Handle of ISOC request
47038 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function
47039 + * Returns 0 on success
47041 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
47042 + void *req_handle);
47044 +/** Get ISOC packet status.
47046 + * @param pcd The PCD
47047 + * @param ep_handle The handle of the endpoint
47048 + * @param iso_req_handle Isochronoush request handle
47049 + * @param packet Number of packet
47050 + * @param status Out parameter for returning status
47051 + * @param actual Out parameter for returning actual length
47052 + * @param offset Out parameter for returning offset
47055 +extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd,
47057 + void *iso_req_handle, int packet,
47058 + int *status, int *actual,
47061 +/** Get ISOC packet count.
47063 + * @param pcd The PCD
47064 + * @param ep_handle The handle of the endpoint
47065 + * @param iso_req_handle
47067 +extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd,
47069 + void *iso_req_handle);
47071 +/** This function starts the SRP Protocol if no session is in progress. If
47072 + * a session is already in progress, but the device is suspended,
47073 + * remote wakeup signaling is started.
47075 +extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd);
47077 +/** This function returns 1 if LPM support is enabled, and 0 otherwise. */
47078 +extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd);
47080 +/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */
47081 +extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd);
47083 +/** Initiate SRP */
47084 +extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd);
47086 +/** Starts remote wakeup signaling. */
47087 +extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set);
47089 +/** Starts micorsecond soft disconnect. */
47090 +extern void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs);
47091 +/** This function returns whether device is dualspeed.*/
47092 +extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd);
47094 +/** This function returns whether device is otg. */
47095 +extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd);
47097 +/** These functions allow to get hnp parameters */
47098 +extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd);
47099 +extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd);
47100 +extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd);
47102 +/** CFI specific Interface functions */
47103 +/** Allocate a cfi buffer */
47104 +extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep,
47105 + dwc_dma_t * addr, size_t buflen,
47108 +/******************************************************************************/
47112 +#endif /* __DWC_PCD_IF_H__ */
47114 +#endif /* DWC_HOST_ONLY */
47116 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
47118 +/* ==========================================================================
47119 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $
47120 + * $Revision: #116 $
47121 + * $Date: 2012/08/10 $
47122 + * $Change: 2047372 $
47124 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
47125 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
47126 + * otherwise expressly agreed to in writing between Synopsys and you.
47128 + * The Software IS NOT an item of Licensed Software or Licensed Product under
47129 + * any End User Software License Agreement or Agreement for Licensed Product
47130 + * with Synopsys or any supplement thereto. You are permitted to use and
47131 + * redistribute this Software in source and binary forms, with or without
47132 + * modification, provided that redistributions of source code must retain this
47133 + * notice. You may not view, use, disclose, copy or distribute this file or
47134 + * any information contained herein except pursuant to this license grant from
47135 + * Synopsys. If you do not agree with this notice, including the disclaimer
47136 + * below, then you are not authorized to use the Software.
47138 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
47139 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47140 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47141 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
47142 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
47143 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
47144 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
47145 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47146 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47147 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
47149 + * ========================================================================== */
47150 +#ifndef DWC_HOST_ONLY
47152 +#include "dwc_otg_pcd.h"
47154 +#ifdef DWC_UTE_CFI
47155 +#include "dwc_otg_cfi.h"
47158 +#ifdef DWC_UTE_PER_IO
47159 +extern void complete_xiso_ep(dwc_otg_pcd_ep_t * ep);
47161 +//#define PRINT_CFI_DMA_DESCS
47166 + * This function updates OTG.
47168 +static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset)
47172 + pcd->b_hnp_enable = 0;
47173 + pcd->a_hnp_support = 0;
47174 + pcd->a_alt_hnp_support = 0;
47177 + if (pcd->fops->hnp_changed) {
47178 + pcd->fops->hnp_changed(pcd);
47183 + * This file contains the implementation of the PCD Interrupt handlers.
47185 + * The PCD handles the device interrupts. Many conditions can cause a
47186 + * device interrupt. When an interrupt occurs, the device interrupt
47187 + * service routine determines the cause of the interrupt and
47188 + * dispatches handling to the appropriate function. These interrupt
47189 + * handling functions are described below.
47190 + * All interrupt registers are processed from LSB to MSB.
47194 + * This function prints the ep0 state for debug purposes.
47196 +static inline void print_ep0_state(dwc_otg_pcd_t * pcd)
47201 + switch (pcd->ep0state) {
47202 + case EP0_DISCONNECT:
47203 + dwc_strcpy(str, "EP0_DISCONNECT");
47206 + dwc_strcpy(str, "EP0_IDLE");
47208 + case EP0_IN_DATA_PHASE:
47209 + dwc_strcpy(str, "EP0_IN_DATA_PHASE");
47211 + case EP0_OUT_DATA_PHASE:
47212 + dwc_strcpy(str, "EP0_OUT_DATA_PHASE");
47214 + case EP0_IN_STATUS_PHASE:
47215 + dwc_strcpy(str, "EP0_IN_STATUS_PHASE");
47217 + case EP0_OUT_STATUS_PHASE:
47218 + dwc_strcpy(str, "EP0_OUT_STATUS_PHASE");
47221 + dwc_strcpy(str, "EP0_STALL");
47224 + dwc_strcpy(str, "EP0_INVALID");
47227 + DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state);
47232 + * This function calculate the size of the payload in the memory
47233 + * for out endpoints and prints size for debug purposes(used in
47234 + * 2.93a DevOutNak feature).
47236 +static inline void print_memory_payload(dwc_otg_pcd_t * pcd, dwc_ep_t * ep)
47239 + deptsiz_data_t deptsiz_init = {.d32 = 0 };
47240 + deptsiz_data_t deptsiz_updt = {.d32 = 0 };
47242 + unsigned payload;
47244 + deptsiz_init.d32 = pcd->core_if->start_doeptsiz_val[ep->num];
47245 + deptsiz_updt.d32 =
47246 + DWC_READ_REG32(&pcd->core_if->dev_if->
47247 + out_ep_regs[ep->num]->doeptsiz);
47248 + /* Payload will be */
47249 + payload = deptsiz_init.b.xfersize - deptsiz_updt.b.xfersize;
47250 + /* Packet count is decremented every time a packet
47251 + * is written to the RxFIFO not in to the external memory
47252 + * So, if payload == 0, then it means no packet was sent to ext memory*/
47253 + pack_num = (!payload) ? 0 : (deptsiz_init.b.pktcnt - deptsiz_updt.b.pktcnt);
47254 + DWC_DEBUGPL(DBG_PCDV,
47255 + "Payload for EP%d-%s\n",
47256 + ep->num, (ep->is_in ? "IN" : "OUT"));
47257 + DWC_DEBUGPL(DBG_PCDV,
47258 + "Number of transfered bytes = 0x%08x\n", payload);
47259 + DWC_DEBUGPL(DBG_PCDV,
47260 + "Number of transfered packets = %d\n", pack_num);
47265 +#ifdef DWC_UTE_CFI
47266 +static inline void print_desc(struct dwc_otg_dma_desc *ddesc,
47267 + const uint8_t * epname, int descnum)
47270 + ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n",
47271 + epname, descnum, ddesc->buf, ddesc->status.b.bytes,
47272 + ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts,
47273 + ddesc->status.b.bs);
47278 + * This function returns pointer to in ep struct with number ep_num
47280 +static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
47283 + int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
47284 + if (ep_num == 0) {
47285 + return &pcd->ep0;
47287 + for (i = 0; i < num_in_eps; ++i) {
47288 + if (pcd->in_ep[i].dwc_ep.num == ep_num)
47289 + return &pcd->in_ep[i];
47296 + * This function returns pointer to out ep struct with number ep_num
47298 +static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
47301 + int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
47302 + if (ep_num == 0) {
47303 + return &pcd->ep0;
47305 + for (i = 0; i < num_out_eps; ++i) {
47306 + if (pcd->out_ep[i].dwc_ep.num == ep_num)
47307 + return &pcd->out_ep[i];
47314 + * This functions gets a pointer to an EP from the wIndex address
47315 + * value of the control request.
47317 +dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex)
47319 + dwc_otg_pcd_ep_t *ep;
47320 + uint32_t ep_num = UE_GET_ADDR(wIndex);
47322 + if (ep_num == 0) {
47324 + } else if (UE_GET_DIR(wIndex) == UE_DIR_IN) { /* in ep */
47325 + ep = &pcd->in_ep[ep_num - 1];
47327 + ep = &pcd->out_ep[ep_num - 1];
47334 + * This function checks the EP request queue, if the queue is not
47335 + * empty the next request is started.
47337 +void start_next_request(dwc_otg_pcd_ep_t * ep)
47339 + dwc_otg_pcd_request_t *req = 0;
47340 + uint32_t max_transfer =
47341 + GET_CORE_IF(ep->pcd)->core_params->max_transfer_size;
47343 +#ifdef DWC_UTE_CFI
47344 + struct dwc_otg_pcd *pcd;
47348 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
47349 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
47351 +#ifdef DWC_UTE_CFI
47352 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
47353 + ep->dwc_ep.cfi_req_len = req->length;
47354 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req);
47357 + /* Setup and start the Transfer */
47358 + if (req->dw_align_buf) {
47359 + ep->dwc_ep.dma_addr = req->dw_align_buf_dma;
47360 + ep->dwc_ep.start_xfer_buff = req->dw_align_buf;
47361 + ep->dwc_ep.xfer_buff = req->dw_align_buf;
47363 + ep->dwc_ep.dma_addr = req->dma;
47364 + ep->dwc_ep.start_xfer_buff = req->buf;
47365 + ep->dwc_ep.xfer_buff = req->buf;
47367 + ep->dwc_ep.sent_zlp = 0;
47368 + ep->dwc_ep.total_len = req->length;
47369 + ep->dwc_ep.xfer_len = 0;
47370 + ep->dwc_ep.xfer_count = 0;
47372 + ep->dwc_ep.maxxfer = max_transfer;
47373 + if (GET_CORE_IF(ep->pcd)->dma_desc_enable) {
47374 + uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE
47375 + - (DDMA_MAX_TRANSFER_SIZE % 4);
47376 + if (ep->dwc_ep.is_in) {
47377 + if (ep->dwc_ep.maxxfer >
47378 + DDMA_MAX_TRANSFER_SIZE) {
47379 + ep->dwc_ep.maxxfer =
47380 + DDMA_MAX_TRANSFER_SIZE;
47383 + if (ep->dwc_ep.maxxfer > out_max_xfer) {
47384 + ep->dwc_ep.maxxfer =
47389 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
47390 + ep->dwc_ep.maxxfer -=
47391 + (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket);
47393 + if (req->sent_zlp) {
47394 + if ((ep->dwc_ep.total_len %
47395 + ep->dwc_ep.maxpacket == 0)
47396 + && (ep->dwc_ep.total_len != 0)) {
47397 + ep->dwc_ep.sent_zlp = 1;
47401 +#ifdef DWC_UTE_CFI
47404 + dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep);
47405 + } else if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
47406 + DWC_PRINTF("There are no more ISOC requests \n");
47407 + ep->dwc_ep.frame_num = 0xFFFFFFFF;
47412 + * This function handles the SOF Interrupts. At this time the SOF
47413 + * Interrupt is disabled.
47415 +int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd)
47417 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47419 + gintsts_data_t gintsts;
47421 + DWC_DEBUGPL(DBG_PCD, "SOF\n");
47423 + /* Clear interrupt */
47425 + gintsts.b.sofintr = 1;
47426 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
47432 + * This function handles the Rx Status Queue Level Interrupt, which
47433 + * indicates that there is a least one packet in the Rx FIFO. The
47434 + * packets are moved from the FIFO to memory, where they will be
47435 + * processed when the Endpoint Interrupt Register indicates Transfer
47436 + * Complete or SETUP Phase Done.
47438 + * Repeat the following until the Rx Status Queue is empty:
47439 + * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
47441 + * -# If Receive FIFO is empty then skip to step Clear the interrupt
47443 + * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
47444 + * SETUP data to the buffer
47445 + * -# If OUT Data Packet call dwc_otg_read_packet to copy the data
47446 + * to the destination buffer
47448 +int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd)
47450 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47451 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
47452 + gintmsk_data_t gintmask = {.d32 = 0 };
47453 + device_grxsts_data_t status;
47454 + dwc_otg_pcd_ep_t *ep;
47455 + gintsts_data_t gintsts;
47457 + static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" };
47460 + //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
47461 + /* Disable the Rx Status Queue Level interrupt */
47462 + gintmask.b.rxstsqlvl = 1;
47463 + DWC_MODIFY_REG32(&global_regs->gintmsk, gintmask.d32, 0);
47465 + /* Get the Status from the top of the FIFO */
47466 + status.d32 = DWC_READ_REG32(&global_regs->grxstsp);
47468 + DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
47469 + "pktsts:%x Frame:%d(0x%0x)\n",
47470 + status.b.epnum, status.b.bcnt,
47471 + dpid_str[status.b.dpid],
47472 + status.b.pktsts, status.b.fn, status.b.fn);
47473 + /* Get pointer to EP structure */
47474 + ep = get_out_ep(pcd, status.b.epnum);
47476 + switch (status.b.pktsts) {
47477 + case DWC_DSTS_GOUT_NAK:
47478 + DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
47480 + case DWC_STS_DATA_UPDT:
47481 + DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
47482 + if (status.b.bcnt && ep->dwc_ep.xfer_buff) {
47483 + /** @todo NGS Check for buffer overflow? */
47484 + dwc_otg_read_packet(core_if,
47485 + ep->dwc_ep.xfer_buff,
47487 + ep->dwc_ep.xfer_count += status.b.bcnt;
47488 + ep->dwc_ep.xfer_buff += status.b.bcnt;
47491 + case DWC_STS_XFER_COMP:
47492 + DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
47494 + case DWC_DSTS_SETUP_COMP:
47496 + DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
47499 + case DWC_DSTS_SETUP_UPDT:
47500 + dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32);
47502 + DWC_DEBUGPL(DBG_PCD,
47503 + "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
47504 + pcd->setup_pkt->req.bmRequestType,
47505 + pcd->setup_pkt->req.bRequest,
47506 + UGETW(pcd->setup_pkt->req.wValue),
47507 + UGETW(pcd->setup_pkt->req.wIndex),
47508 + UGETW(pcd->setup_pkt->req.wLength));
47510 + ep->dwc_ep.xfer_count += status.b.bcnt;
47513 + DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
47514 + status.b.pktsts);
47518 + /* Enable the Rx Status Queue Level interrupt */
47519 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmask.d32);
47520 + /* Clear interrupt */
47522 + gintsts.b.rxstsqlvl = 1;
47523 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
47525 + //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
47530 + * This function examines the Device IN Token Learning Queue to
47531 + * determine the EP number of the last IN token received. This
47532 + * implementation is for the Mass Storage device where there are only
47533 + * 2 IN EPs (Control-IN and BULK-IN).
47535 + * The EP numbers for the first six IN Tokens are in DTKNQR1 and there
47536 + * are 8 EP Numbers in each of the other possible DTKNQ Registers.
47538 + * @param core_if Programming view of DWC_otg controller.
47541 +static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if)
47543 + dwc_otg_device_global_regs_t *dev_global_regs =
47544 + core_if->dev_if->dev_global_regs;
47545 + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
47546 + /* Number of Token Queue Registers */
47547 + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
47548 + dtknq1_data_t dtknqr1;
47549 + uint32_t in_tkn_epnums[4];
47552 + volatile uint32_t *addr = &dev_global_regs->dtknqr1;
47555 + //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
47557 + /* Read the DTKNQ Registers */
47558 + for (i = 0; i < DTKNQ_REG_CNT; i++) {
47559 + in_tkn_epnums[i] = DWC_READ_REG32(addr);
47560 + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
47561 + in_tkn_epnums[i]);
47562 + if (addr == &dev_global_regs->dvbusdis) {
47563 + addr = &dev_global_regs->dtknqr3_dthrctl;
47570 + /* Copy the DTKNQR1 data to the bit field. */
47571 + dtknqr1.d32 = in_tkn_epnums[0];
47572 + /* Get the EP numbers */
47573 + in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
47574 + ndx = dtknqr1.b.intknwptr - 1;
47576 + //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
47578 + /** @todo Find a simpler way to calculate the max
47579 + * queue position.*/
47580 + int cnt = TOKEN_Q_DEPTH;
47581 + if (TOKEN_Q_DEPTH <= 6) {
47582 + cnt = TOKEN_Q_DEPTH - 1;
47583 + } else if (TOKEN_Q_DEPTH <= 14) {
47584 + cnt = TOKEN_Q_DEPTH - 7;
47585 + } else if (TOKEN_Q_DEPTH <= 22) {
47586 + cnt = TOKEN_Q_DEPTH - 15;
47588 + cnt = TOKEN_Q_DEPTH - 23;
47590 + epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF;
47593 + epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
47594 + } else if (ndx <= 13) {
47596 + epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
47597 + } else if (ndx <= 21) {
47599 + epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
47600 + } else if (ndx <= 29) {
47602 + epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
47605 + //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
47610 + * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
47611 + * The active request is checked for the next packet to be loaded into
47612 + * the non-periodic Tx FIFO.
47614 +int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd)
47616 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47617 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
47618 + dwc_otg_dev_in_ep_regs_t *ep_regs;
47619 + gnptxsts_data_t txstatus = {.d32 = 0 };
47620 + gintsts_data_t gintsts;
47623 + dwc_otg_pcd_ep_t *ep = 0;
47624 + uint32_t len = 0;
47627 + /* Get the epnum from the IN Token Learning Queue. */
47628 + epnum = get_ep_of_last_in_token(core_if);
47629 + ep = get_in_ep(pcd, epnum);
47631 + DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum);
47633 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
47635 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47636 + if (len > ep->dwc_ep.maxpacket) {
47637 + len = ep->dwc_ep.maxpacket;
47639 + dwords = (len + 3) / 4;
47641 + /* While there is space in the queue and space in the FIFO and
47642 + * More data to tranfer, Write packets to the Tx FIFO */
47643 + txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
47644 + DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32);
47646 + while (txstatus.b.nptxqspcavail > 0 &&
47647 + txstatus.b.nptxfspcavail > dwords &&
47648 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) {
47649 + /* Write the FIFO */
47650 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
47651 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47653 + if (len > ep->dwc_ep.maxpacket) {
47654 + len = ep->dwc_ep.maxpacket;
47657 + dwords = (len + 3) / 4;
47658 + txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
47659 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32);
47662 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
47663 + DWC_READ_REG32(&global_regs->gnptxsts));
47665 + /* Clear interrupt */
47667 + gintsts.b.nptxfempty = 1;
47668 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
47674 + * This function is called when dedicated Tx FIFO Empty interrupt occurs.
47675 + * The active request is checked for the next packet to be loaded into
47676 + * apropriate Tx FIFO.
47678 +static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum)
47680 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47681 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
47682 + dwc_otg_dev_in_ep_regs_t *ep_regs;
47683 + dtxfsts_data_t txstatus = {.d32 = 0 };
47684 + dwc_otg_pcd_ep_t *ep = 0;
47685 + uint32_t len = 0;
47688 + ep = get_in_ep(pcd, epnum);
47690 + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
47692 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
47694 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47696 + if (len > ep->dwc_ep.maxpacket) {
47697 + len = ep->dwc_ep.maxpacket;
47700 + dwords = (len + 3) / 4;
47702 + /* While there is space in the queue and space in the FIFO and
47703 + * More data to tranfer, Write packets to the Tx FIFO */
47704 + txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
47705 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
47707 + while (txstatus.b.txfspcavail > dwords &&
47708 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
47709 + ep->dwc_ep.xfer_len != 0) {
47710 + /* Write the FIFO */
47711 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
47713 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47714 + if (len > ep->dwc_ep.maxpacket) {
47715 + len = ep->dwc_ep.maxpacket;
47718 + dwords = (len + 3) / 4;
47720 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
47721 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
47725 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
47726 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
47732 + * This function is called when the Device is disconnected. It stops
47733 + * any active requests and informs the Gadget driver of the
47736 +void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd)
47738 + int i, num_in_eps, num_out_eps;
47739 + dwc_otg_pcd_ep_t *ep;
47741 + gintmsk_data_t intr_mask = {.d32 = 0 };
47743 + DWC_SPINLOCK(pcd->lock);
47745 + num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
47746 + num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
47748 + DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__);
47749 + /* don't disconnect drivers more than once */
47750 + if (pcd->ep0state == EP0_DISCONNECT) {
47751 + DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__);
47752 + DWC_SPINUNLOCK(pcd->lock);
47755 + pcd->ep0state = EP0_DISCONNECT;
47757 + /* Reset the OTG state. */
47758 + dwc_otg_pcd_update_otg(pcd, 1);
47760 + /* Disable the NP Tx Fifo Empty Interrupt. */
47761 + intr_mask.b.nptxfempty = 1;
47762 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
47763 + intr_mask.d32, 0);
47765 + /* Flush the FIFOs */
47766 + /**@todo NGS Flush Periodic FIFOs */
47767 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10);
47768 + dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd));
47770 + /* prevent new request submissions, kill any outstanding requests */
47772 + dwc_otg_request_nuke(ep);
47773 + /* prevent new request submissions, kill any outstanding requests */
47774 + for (i = 0; i < num_in_eps; i++) {
47775 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i];
47776 + dwc_otg_request_nuke(ep);
47778 + /* prevent new request submissions, kill any outstanding requests */
47779 + for (i = 0; i < num_out_eps; i++) {
47780 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i];
47781 + dwc_otg_request_nuke(ep);
47784 + /* report disconnect; the driver is already quiesced */
47785 + if (pcd->fops->disconnect) {
47786 + DWC_SPINUNLOCK(pcd->lock);
47787 + pcd->fops->disconnect(pcd);
47788 + DWC_SPINLOCK(pcd->lock);
47790 + DWC_SPINUNLOCK(pcd->lock);
47794 + * This interrupt indicates that ...
47796 +int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd)
47798 + gintmsk_data_t intr_mask = {.d32 = 0 };
47799 + gintsts_data_t gintsts;
47801 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr");
47802 + intr_mask.b.i2cintr = 1;
47803 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
47804 + intr_mask.d32, 0);
47806 + /* Clear interrupt */
47808 + gintsts.b.i2cintr = 1;
47809 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
47815 + * This interrupt indicates that ...
47817 +int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd)
47819 + gintsts_data_t gintsts;
47820 +#if defined(VERBOSE)
47821 + DWC_PRINTF("Early Suspend Detected\n");
47824 + /* Clear interrupt */
47826 + gintsts.b.erlysuspend = 1;
47827 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
47833 + * This function configures EPO to receive SETUP packets.
47835 + * @todo NGS: Update the comments from the HW FS.
47837 + * -# Program the following fields in the endpoint specific registers
47838 + * for Control OUT EP 0, in order to receive a setup packet
47839 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
47841 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
47842 + * to back setup packets)
47843 + * - In DMA mode, DOEPDMA0 Register with a memory address to
47844 + * store any setup packets received
47846 + * @param core_if Programming view of DWC_otg controller.
47847 + * @param pcd Programming view of the PCD.
47849 +static inline void ep0_out_start(dwc_otg_core_if_t * core_if,
47850 + dwc_otg_pcd_t * pcd)
47852 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
47853 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
47854 + dwc_otg_dev_dma_desc_t *dma_desc;
47855 + depctl_data_t doepctl = {.d32 = 0 };
47858 + DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__,
47859 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
47861 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
47862 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
47863 + if (doepctl.b.epena) {
47868 + doeptsize0.b.supcnt = 3;
47869 + doeptsize0.b.pktcnt = 1;
47870 + doeptsize0.b.xfersize = 8 * 3;
47872 + if (core_if->dma_enable) {
47873 + if (!core_if->dma_desc_enable) {
47874 + /** put here as for Hermes mode deptisz register should not be written */
47875 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
47878 + /** @todo dma needs to handle multiple setup packets (up to 3) */
47879 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
47880 + pcd->setup_pkt_dma_handle);
47882 + dev_if->setup_desc_index =
47883 + (dev_if->setup_desc_index + 1) & 1;
47885 + dev_if->setup_desc_addr[dev_if->setup_desc_index];
47887 + /** DMA Descriptor Setup */
47888 + dma_desc->status.b.bs = BS_HOST_BUSY;
47889 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
47890 + dma_desc->status.b.sr = 0;
47891 + dma_desc->status.b.mtrf = 0;
47893 + dma_desc->status.b.l = 1;
47894 + dma_desc->status.b.ioc = 1;
47895 + dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket;
47896 + dma_desc->buf = pcd->setup_pkt_dma_handle;
47897 + dma_desc->status.b.sts = 0;
47898 + dma_desc->status.b.bs = BS_HOST_READY;
47900 + /** DOEPDMA0 Register write */
47901 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
47902 + dev_if->dma_setup_desc_addr
47903 + [dev_if->setup_desc_index]);
47907 + /** put here as for Hermes mode deptisz register should not be written */
47908 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
47912 + /** DOEPCTL0 Register write cnak will be set after setup interrupt */
47914 + doepctl.b.epena = 1;
47915 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
47916 + doepctl.b.cnak = 1;
47917 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
47919 + DWC_MODIFY_REG32(&dev_if->out_ep_regs[0]->doepctl, 0, doepctl.d32);
47923 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
47924 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
47925 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
47926 + DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
47931 + * This interrupt occurs when a USB Reset is detected. When the USB
47932 + * Reset Interrupt occurs the device state is set to DEFAULT and the
47933 + * EP0 state is set to IDLE.
47934 + * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
47935 + * -# Unmask the following interrupt bits
47936 + * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
47937 + * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
47938 + * - DOEPMSK.SETUP = 1
47939 + * - DOEPMSK.XferCompl = 1
47940 + * - DIEPMSK.XferCompl = 1
47941 + * - DIEPMSK.TimeOut = 1
47942 + * -# Program the following fields in the endpoint specific registers
47943 + * for Control OUT EP 0, in order to receive a setup packet
47944 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
47946 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
47947 + * to back setup packets)
47948 + * - In DMA mode, DOEPDMA0 Register with a memory address to
47949 + * store any setup packets received
47950 + * At this point, all the required initialization, except for enabling
47951 + * the control 0 OUT endpoint is done, for receiving SETUP packets.
47953 +int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd)
47955 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47956 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
47957 + depctl_data_t doepctl = {.d32 = 0 };
47958 + depctl_data_t diepctl = {.d32 = 0 };
47959 + daint_data_t daintmsk = {.d32 = 0 };
47960 + doepmsk_data_t doepmsk = {.d32 = 0 };
47961 + diepmsk_data_t diepmsk = {.d32 = 0 };
47962 + dcfg_data_t dcfg = {.d32 = 0 };
47963 + grstctl_t resetctl = {.d32 = 0 };
47964 + dctl_data_t dctl = {.d32 = 0 };
47966 + gintsts_data_t gintsts;
47967 + pcgcctl_data_t power = {.d32 = 0 };
47969 + power.d32 = DWC_READ_REG32(core_if->pcgcctl);
47970 + if (power.b.stoppclk) {
47972 + power.b.stoppclk = 1;
47973 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
47975 + power.b.pwrclmp = 1;
47976 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
47978 + power.b.rstpdwnmodule = 1;
47979 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
47982 + core_if->lx_state = DWC_OTG_L0;
47984 + DWC_PRINTF("USB RESET\n");
47985 +#ifdef DWC_EN_ISOC
47986 + for (i = 1; i < 16; ++i) {
47987 + dwc_otg_pcd_ep_t *ep;
47988 + dwc_ep_t *dwc_ep;
47989 + ep = get_in_ep(pcd, i);
47991 + dwc_ep = &ep->dwc_ep;
47992 + dwc_ep->next_frame = 0xffffffff;
47995 +#endif /* DWC_EN_ISOC */
47997 + /* reset the HNP settings */
47998 + dwc_otg_pcd_update_otg(pcd, 1);
48000 + /* Clear the Remote Wakeup Signalling */
48001 + dctl.b.rmtwkupsig = 1;
48002 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
48004 + /* Set NAK for all OUT EPs */
48005 + doepctl.b.snak = 1;
48006 + for (i = 0; i <= dev_if->num_out_eps; i++) {
48007 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
48010 + /* Flush the NP Tx FIFO */
48011 + dwc_otg_flush_tx_fifo(core_if, 0x10);
48012 + /* Flush the Learning Queue */
48013 + resetctl.b.intknqflsh = 1;
48014 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
48016 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
48017 + core_if->start_predict = 0;
48018 + for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
48019 + core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
48021 + core_if->nextep_seq[0] = 0;
48022 + core_if->first_in_nextep_seq = 0;
48023 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
48024 + diepctl.b.nextep = 0;
48025 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
48027 + /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
48028 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
48029 + dcfg.b.epmscnt = 2;
48030 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
48032 + DWC_DEBUGPL(DBG_PCDV,
48033 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
48034 + __func__, core_if->first_in_nextep_seq);
48035 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
48036 + DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
48040 + if (core_if->multiproc_int_enable) {
48041 + daintmsk.b.inep0 = 1;
48042 + daintmsk.b.outep0 = 1;
48043 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk,
48046 + doepmsk.b.setup = 1;
48047 + doepmsk.b.xfercompl = 1;
48048 + doepmsk.b.ahberr = 1;
48049 + doepmsk.b.epdisabled = 1;
48051 + if ((core_if->dma_desc_enable) ||
48052 + (core_if->dma_enable
48053 + && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
48054 + doepmsk.b.stsphsercvd = 1;
48056 + if (core_if->dma_desc_enable)
48057 + doepmsk.b.bna = 1;
48059 + doepmsk.b.babble = 1;
48060 + doepmsk.b.nyet = 1;
48062 + if (core_if->dma_enable) {
48063 + doepmsk.b.nak = 1;
48066 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepeachintmsk[0],
48069 + diepmsk.b.xfercompl = 1;
48070 + diepmsk.b.timeout = 1;
48071 + diepmsk.b.epdisabled = 1;
48072 + diepmsk.b.ahberr = 1;
48073 + diepmsk.b.intknepmis = 1;
48074 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
48075 + diepmsk.b.intknepmis = 0;
48077 +/* if (core_if->dma_desc_enable) {
48078 + diepmsk.b.bna = 1;
48082 + if (core_if->dma_enable) {
48083 + diepmsk.b.nak = 1;
48086 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepeachintmsk[0],
48089 + daintmsk.b.inep0 = 1;
48090 + daintmsk.b.outep0 = 1;
48091 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk,
48094 + doepmsk.b.setup = 1;
48095 + doepmsk.b.xfercompl = 1;
48096 + doepmsk.b.ahberr = 1;
48097 + doepmsk.b.epdisabled = 1;
48099 + if ((core_if->dma_desc_enable) ||
48100 + (core_if->dma_enable
48101 + && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
48102 + doepmsk.b.stsphsercvd = 1;
48104 + if (core_if->dma_desc_enable)
48105 + doepmsk.b.bna = 1;
48106 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32);
48108 + diepmsk.b.xfercompl = 1;
48109 + diepmsk.b.timeout = 1;
48110 + diepmsk.b.epdisabled = 1;
48111 + diepmsk.b.ahberr = 1;
48112 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
48113 + diepmsk.b.intknepmis = 0;
48115 + if (core_if->dma_desc_enable) {
48116 + diepmsk.b.bna = 1;
48120 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32);
48123 + /* Reset Device Address */
48124 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
48125 + dcfg.b.devaddr = 0;
48126 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
48128 + /* setup EP0 to receive SETUP packets */
48129 + if (core_if->snpsid <= OTG_CORE_REV_2_94a)
48130 + ep0_out_start(core_if, pcd);
48132 + /* Clear interrupt */
48134 + gintsts.b.usbreset = 1;
48135 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48141 + * Get the device speed from the device status register and convert it
48142 + * to USB speed constant.
48144 + * @param core_if Programming view of DWC_otg controller.
48146 +static int get_device_speed(dwc_otg_core_if_t * core_if)
48148 + dsts_data_t dsts;
48150 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
48152 + switch (dsts.b.enumspd) {
48153 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
48154 + speed = USB_SPEED_HIGH;
48156 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
48157 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
48158 + speed = USB_SPEED_FULL;
48161 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
48162 + speed = USB_SPEED_LOW;
48170 + * Read the device status register and set the device speed in the
48171 + * data structure.
48172 + * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
48174 +int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd)
48176 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48177 + gintsts_data_t gintsts;
48178 + gusbcfg_data_t gusbcfg;
48179 + dwc_otg_core_global_regs_t *global_regs =
48180 + GET_CORE_IF(pcd)->core_global_regs;
48181 + uint8_t utmi16b, utmi8b;
48183 + DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
48185 + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
48186 + utmi16b = 6; //vahrama old value was 6;
48192 + dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep);
48193 + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a) {
48194 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48198 + print_ep0_state(pcd);
48201 + if (pcd->ep0state == EP0_DISCONNECT) {
48202 + pcd->ep0state = EP0_IDLE;
48203 + } else if (pcd->ep0state == EP0_STALL) {
48204 + pcd->ep0state = EP0_IDLE;
48207 + pcd->ep0state = EP0_IDLE;
48209 + ep0->stopped = 0;
48211 + speed = get_device_speed(GET_CORE_IF(pcd));
48212 + pcd->fops->connect(pcd, speed);
48214 + /* Set USB turnaround time based on device speed and PHY interface. */
48215 + gusbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
48216 + if (speed == USB_SPEED_HIGH) {
48217 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48218 + DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
48219 + /* ULPI interface */
48220 + gusbcfg.b.usbtrdtim = 9;
48222 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48223 + DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
48224 + /* UTMI+ interface */
48225 + if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) {
48226 + gusbcfg.b.usbtrdtim = utmi8b;
48227 + } else if (GET_CORE_IF(pcd)->hwcfg4.
48228 + b.utmi_phy_data_width == 1) {
48229 + gusbcfg.b.usbtrdtim = utmi16b;
48230 + } else if (GET_CORE_IF(pcd)->
48231 + core_params->phy_utmi_width == 8) {
48232 + gusbcfg.b.usbtrdtim = utmi8b;
48234 + gusbcfg.b.usbtrdtim = utmi16b;
48237 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48238 + DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
48239 + /* UTMI+ OR ULPI interface */
48240 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
48241 + /* ULPI interface */
48242 + gusbcfg.b.usbtrdtim = 9;
48244 + /* UTMI+ interface */
48245 + if (GET_CORE_IF(pcd)->
48246 + core_params->phy_utmi_width == 16) {
48247 + gusbcfg.b.usbtrdtim = utmi16b;
48249 + gusbcfg.b.usbtrdtim = utmi8b;
48254 + /* Full or low speed */
48255 + gusbcfg.b.usbtrdtim = 9;
48257 + DWC_WRITE_REG32(&global_regs->gusbcfg, gusbcfg.d32);
48259 + /* Clear interrupt */
48261 + gintsts.b.enumdone = 1;
48262 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48268 + * This interrupt indicates that the ISO OUT Packet was dropped due to
48269 + * Rx FIFO full or Rx Status Queue Full. If this interrupt occurs
48270 + * read all the data from the Rx FIFO.
48272 +int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd)
48274 + gintmsk_data_t intr_mask = {.d32 = 0 };
48275 + gintsts_data_t gintsts;
48277 + DWC_WARN("INTERRUPT Handler not implemented for %s\n",
48278 + "ISOC Out Dropped");
48280 + intr_mask.b.isooutdrop = 1;
48281 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48282 + intr_mask.d32, 0);
48284 + /* Clear interrupt */
48286 + gintsts.b.isooutdrop = 1;
48287 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48294 + * This interrupt indicates the end of the portion of the micro-frame
48295 + * for periodic transactions. If there is a periodic transaction for
48296 + * the next frame, load the packets into the EP periodic Tx FIFO.
48298 +int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd)
48300 + gintmsk_data_t intr_mask = {.d32 = 0 };
48301 + gintsts_data_t gintsts;
48302 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP");
48304 + intr_mask.b.eopframe = 1;
48305 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48306 + intr_mask.d32, 0);
48308 + /* Clear interrupt */
48310 + gintsts.b.eopframe = 1;
48311 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48318 + * This interrupt indicates that EP of the packet on the top of the
48319 + * non-periodic Tx FIFO does not match EP of the IN Token received.
48321 + * The "Device IN Token Queue" Registers are read to determine the
48322 + * order the IN Tokens have been received. The non-periodic Tx FIFO
48323 + * is flushed, so it can be reloaded in the order seen in the IN Token
48326 +int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_pcd_t * pcd)
48328 + gintsts_data_t gintsts;
48329 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48330 + dctl_data_t dctl;
48331 + gintmsk_data_t intr_mask = {.d32 = 0 };
48333 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable) {
48334 + core_if->start_predict = 1;
48336 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
48338 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
48339 + if (!gintsts.b.ginnakeff) {
48340 + /* Disable EP Mismatch interrupt */
48341 + intr_mask.d32 = 0;
48342 + intr_mask.b.epmismatch = 1;
48343 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
48344 + /* Enable the Global IN NAK Effective Interrupt */
48345 + intr_mask.d32 = 0;
48346 + intr_mask.b.ginnakeff = 1;
48347 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
48348 + /* Set the global non-periodic IN NAK handshake */
48349 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
48350 + dctl.b.sgnpinnak = 1;
48351 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
48353 + DWC_PRINTF("gintsts.b.ginnakeff = 1! dctl.b.sgnpinnak not set\n");
48355 + /* Disabling of all EP's will be done in dwc_otg_pcd_handle_in_nak_effective()
48356 + * handler after Global IN NAK Effective interrupt will be asserted */
48358 + /* Clear interrupt */
48360 + gintsts.b.epmismatch = 1;
48361 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48367 + * This interrupt is valid only in DMA mode. This interrupt indicates that the
48368 + * core has stopped fetching data for IN endpoints due to the unavailability of
48369 + * TxFIFO space or Request Queue space. This interrupt is used by the
48370 + * application for an endpoint mismatch algorithm.
48372 + * @param pcd The PCD
48374 +int32_t dwc_otg_pcd_handle_ep_fetsusp_intr(dwc_otg_pcd_t * pcd)
48376 + gintsts_data_t gintsts;
48377 + gintmsk_data_t gintmsk_data;
48378 + dctl_data_t dctl;
48379 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48380 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
48382 + /* Clear the global non-periodic IN NAK handshake */
48384 + dctl.b.cgnpinnak = 1;
48385 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
48387 + /* Mask GINTSTS.FETSUSP interrupt */
48388 + gintmsk_data.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
48389 + gintmsk_data.b.fetsusp = 0;
48390 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_data.d32);
48392 + /* Clear interrupt */
48394 + gintsts.b.fetsusp = 1;
48395 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48400 + * This funcion stalls EP0.
48402 +static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val)
48404 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48405 + usb_device_request_t *ctrl = &pcd->setup_pkt->req;
48406 + DWC_WARN("req %02x.%02x protocol STALL; err %d\n",
48407 + ctrl->bmRequestType, ctrl->bRequest, err_val);
48409 + ep0->dwc_ep.is_in = 1;
48410 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep);
48411 + pcd->ep0.stopped = 1;
48412 + pcd->ep0state = EP0_IDLE;
48413 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48417 + * This functions delegates the setup command to the gadget driver.
48419 +static inline void do_gadget_setup(dwc_otg_pcd_t * pcd,
48420 + usb_device_request_t * ctrl)
48423 + DWC_SPINUNLOCK(pcd->lock);
48424 + ret = pcd->fops->setup(pcd, (uint8_t *) ctrl);
48425 + DWC_SPINLOCK(pcd->lock);
48427 + ep0_do_stall(pcd, ret);
48430 + /** @todo This is a g_file_storage gadget driver specific
48431 + * workaround: a DELAYED_STATUS result from the fsg_setup
48432 + * routine will result in the gadget queueing a EP0 IN status
48433 + * phase for a two-stage control transfer. Exactly the same as
48434 + * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
48435 + * specific request. Need a generic way to know when the gadget
48436 + * driver will queue the status phase. Can we assume when we
48437 + * call the gadget driver setup() function that it will always
48438 + * queue and require the following flag? Need to look into
48442 + if (ret == 256 + 999) {
48443 + pcd->request_config = 1;
48447 +#ifdef DWC_UTE_CFI
48449 + * This functions delegates the CFI setup commands to the gadget driver.
48450 + * This function will return a negative value to indicate a failure.
48452 +static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd,
48453 + struct cfi_usb_ctrlrequest *ctrl_req)
48457 + if (pcd->fops && pcd->fops->cfi_setup) {
48458 + DWC_SPINUNLOCK(pcd->lock);
48459 + ret = pcd->fops->cfi_setup(pcd, ctrl_req);
48460 + DWC_SPINLOCK(pcd->lock);
48462 + ep0_do_stall(pcd, ret);
48472 + * This function starts the Zero-Length Packet for the IN status phase
48473 + * of a 2 stage control transfer.
48475 +static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd)
48477 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48478 + if (pcd->ep0state == EP0_STALL) {
48482 + pcd->ep0state = EP0_IN_STATUS_PHASE;
48484 + /* Prepare for more SETUP Packets */
48485 + DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
48486 + if ((GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a)
48487 + && (pcd->core_if->dma_desc_enable)
48488 + && (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len)) {
48489 + DWC_DEBUGPL(DBG_PCDV,
48490 + "Data terminated wait next packet in out_desc_addr\n");
48491 + pcd->backup_buf = phys_to_virt(ep0->dwc_ep.dma_addr);
48492 + pcd->data_terminated = 1;
48494 + ep0->dwc_ep.xfer_len = 0;
48495 + ep0->dwc_ep.xfer_count = 0;
48496 + ep0->dwc_ep.is_in = 1;
48497 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
48498 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48500 + /* Prepare for more SETUP Packets */
48501 + //ep0_out_start(GET_CORE_IF(pcd), pcd);
48505 + * This function starts the Zero-Length Packet for the OUT status phase
48506 + * of a 2 stage control transfer.
48508 +static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd)
48510 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48511 + if (pcd->ep0state == EP0_STALL) {
48512 + DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
48515 + pcd->ep0state = EP0_OUT_STATUS_PHASE;
48517 + DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
48518 + ep0->dwc_ep.xfer_len = 0;
48519 + ep0->dwc_ep.xfer_count = 0;
48520 + ep0->dwc_ep.is_in = 0;
48521 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
48522 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48524 + /* Prepare for more SETUP Packets */
48525 + if (GET_CORE_IF(pcd)->dma_enable == 0) {
48526 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48531 + * Clear the EP halt (STALL) and if pending requests start the
48534 +static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
48536 + if (ep->dwc_ep.stall_clear_flag == 0)
48537 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
48539 + /* Reactive the EP */
48540 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
48541 + if (ep->stopped) {
48543 + /* If there is a request in the EP queue start it */
48545 + /** @todo FIXME: this causes an EP mismatch in DMA mode.
48546 + * epmismatch not yet implemented. */
48549 + * Above fixme is solved by implmenting a tasklet to call the
48550 + * start_next_request(), outside of interrupt context at some
48551 + * time after the current time, after a clear-halt setup packet.
48552 + * Still need to implement ep mismatch in the future if a gadget
48553 + * ever uses more than one endpoint at once
48555 + ep->queue_sof = 1;
48556 + DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet);
48558 + /* Start Control Status Phase */
48559 + do_setup_in_status_phase(pcd);
48563 + * This function is called when the SET_FEATURE TEST_MODE Setup packet
48564 + * is sent from the host. The Device Control register is written with
48565 + * the Test Mode bits set to the specified Test Mode. This is done as
48566 + * a tasklet so that the "Status" phase of the control transfer
48567 + * completes before transmitting the TEST packets.
48569 + * @todo This has not been tested since the tasklet struct was put
48570 + * into the PCD struct!
48573 +void do_test_mode(void *data)
48575 + dctl_data_t dctl;
48576 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
48577 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48578 + int test_mode = pcd->test_mode;
48580 +// DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
48582 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
48583 + switch (test_mode) {
48584 + case 1: // TEST_J
48585 + dctl.b.tstctl = 1;
48588 + case 2: // TEST_K
48589 + dctl.b.tstctl = 2;
48592 + case 3: // TEST_SE0_NAK
48593 + dctl.b.tstctl = 3;
48596 + case 4: // TEST_PACKET
48597 + dctl.b.tstctl = 4;
48600 + case 5: // TEST_FORCE_ENABLE
48601 + dctl.b.tstctl = 5;
48604 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
48608 + * This function process the GET_STATUS Setup Commands.
48610 +static inline void do_get_status(dwc_otg_pcd_t * pcd)
48612 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48613 + dwc_otg_pcd_ep_t *ep;
48614 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48615 + uint16_t *status = pcd->status_buf;
48616 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48619 + DWC_DEBUGPL(DBG_PCD,
48620 + "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
48621 + ctrl.bmRequestType, ctrl.bRequest,
48622 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48623 + UGETW(ctrl.wLength));
48626 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48628 + if(UGETW(ctrl.wIndex) == 0xF000) { /* OTG Status selector */
48629 + DWC_PRINTF("wIndex - %d\n", UGETW(ctrl.wIndex));
48630 + DWC_PRINTF("OTG VERSION - %d\n", core_if->otg_ver);
48631 + DWC_PRINTF("OTG CAP - %d, %d\n",
48632 + core_if->core_params->otg_cap,
48633 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
48634 + if (core_if->otg_ver == 1
48635 + && core_if->core_params->otg_cap ==
48636 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48637 + uint8_t *otgsts = (uint8_t*)pcd->status_buf;
48638 + *otgsts = (core_if->otg_sts & 0x1);
48639 + pcd->ep0_pending = 1;
48640 + ep0->dwc_ep.start_xfer_buff =
48641 + (uint8_t *) otgsts;
48642 + ep0->dwc_ep.xfer_buff = (uint8_t *) otgsts;
48643 + ep0->dwc_ep.dma_addr =
48644 + pcd->status_buf_dma_handle;
48645 + ep0->dwc_ep.xfer_len = 1;
48646 + ep0->dwc_ep.xfer_count = 0;
48647 + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
48648 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
48652 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48657 + *status = 0x1; /* Self powered */
48658 + *status |= pcd->remote_wakeup_enable << 1;
48661 + case UT_INTERFACE:
48665 + case UT_ENDPOINT:
48666 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
48667 + if (ep == 0 || UGETW(ctrl.wLength) > 2) {
48668 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48671 + /** @todo check for EP stall */
48672 + *status = ep->stopped;
48675 + pcd->ep0_pending = 1;
48676 + ep0->dwc_ep.start_xfer_buff = (uint8_t *) status;
48677 + ep0->dwc_ep.xfer_buff = (uint8_t *) status;
48678 + ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle;
48679 + ep0->dwc_ep.xfer_len = 2;
48680 + ep0->dwc_ep.xfer_count = 0;
48681 + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
48682 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48686 + * This function process the SET_FEATURE Setup Commands.
48688 +static inline void do_set_feature(dwc_otg_pcd_t * pcd)
48690 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48691 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
48692 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48693 + dwc_otg_pcd_ep_t *ep = 0;
48694 + int32_t otg_cap_param = core_if->core_params->otg_cap;
48695 + gotgctl_data_t gotgctl = {.d32 = 0 };
48697 + DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
48698 + ctrl.bmRequestType, ctrl.bRequest,
48699 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48700 + UGETW(ctrl.wLength));
48701 + DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param);
48703 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48705 + switch (UGETW(ctrl.wValue)) {
48706 + case UF_DEVICE_REMOTE_WAKEUP:
48707 + pcd->remote_wakeup_enable = 1;
48710 + case UF_TEST_MODE:
48711 + /* Setup the Test Mode tasklet to do the Test
48712 + * Packet generation after the SETUP Status
48713 + * phase has completed. */
48715 + /** @todo This has not been tested since the
48716 + * tasklet struct was put into the PCD
48718 + pcd->test_mode = UGETW(ctrl.wIndex) >> 8;
48719 + DWC_TASK_SCHEDULE(pcd->test_mode_tasklet);
48722 + case UF_DEVICE_B_HNP_ENABLE:
48723 + DWC_DEBUGPL(DBG_PCDV,
48724 + "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
48726 + /* dev may initiate HNP */
48727 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48728 + pcd->b_hnp_enable = 1;
48729 + dwc_otg_pcd_update_otg(pcd, 0);
48730 + DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
48731 + /**@todo Is the gotgctl.devhnpen cleared
48732 + * by a USB Reset? */
48733 + gotgctl.b.devhnpen = 1;
48734 + gotgctl.b.hnpreq = 1;
48735 + DWC_WRITE_REG32(&global_regs->gotgctl,
48738 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48743 + case UF_DEVICE_A_HNP_SUPPORT:
48744 + /* RH port supports HNP */
48745 + DWC_DEBUGPL(DBG_PCDV,
48746 + "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
48747 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48748 + pcd->a_hnp_support = 1;
48749 + dwc_otg_pcd_update_otg(pcd, 0);
48751 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48756 + case UF_DEVICE_A_ALT_HNP_SUPPORT:
48757 + /* other RH port does */
48758 + DWC_DEBUGPL(DBG_PCDV,
48759 + "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
48760 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48761 + pcd->a_alt_hnp_support = 1;
48762 + dwc_otg_pcd_update_otg(pcd, 0);
48764 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48770 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48774 + do_setup_in_status_phase(pcd);
48777 + case UT_INTERFACE:
48778 + do_gadget_setup(pcd, &ctrl);
48781 + case UT_ENDPOINT:
48782 + if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) {
48783 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
48785 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48789 + dwc_otg_ep_set_stall(core_if, &ep->dwc_ep);
48791 + do_setup_in_status_phase(pcd);
48797 + * This function process the CLEAR_FEATURE Setup Commands.
48799 +static inline void do_clear_feature(dwc_otg_pcd_t * pcd)
48801 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48802 + dwc_otg_pcd_ep_t *ep = 0;
48804 + DWC_DEBUGPL(DBG_PCD,
48805 + "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
48806 + ctrl.bmRequestType, ctrl.bRequest,
48807 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48808 + UGETW(ctrl.wLength));
48810 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48812 + switch (UGETW(ctrl.wValue)) {
48813 + case UF_DEVICE_REMOTE_WAKEUP:
48814 + pcd->remote_wakeup_enable = 0;
48817 + case UF_TEST_MODE:
48818 + /** @todo Add CLEAR_FEATURE for TEST modes. */
48822 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48825 + do_setup_in_status_phase(pcd);
48828 + case UT_ENDPOINT:
48829 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
48831 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48835 + pcd_clear_halt(pcd, ep);
48842 + * This function process the SET_ADDRESS Setup Commands.
48844 +static inline void do_set_address(dwc_otg_pcd_t * pcd)
48846 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
48847 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48849 + if (ctrl.bmRequestType == UT_DEVICE) {
48850 + dcfg_data_t dcfg = {.d32 = 0 };
48853 +// DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
48855 + dcfg.b.devaddr = UGETW(ctrl.wValue);
48856 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32);
48857 + do_setup_in_status_phase(pcd);
48862 + * This function processes SETUP commands. In Linux, the USB Command
48863 + * processing is done in two places - the first being the PCD and the
48864 + * second in the Gadget Driver (for example, the File-Backed Storage
48865 + * Gadget Driver).
48868 + * <tr><td>Command </td><td>Driver </td><td>Description</td></tr>
48870 + * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as
48871 + * defined in chapter 9 of the USB 2.0 Specification chapter 9
48874 + * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint
48875 + * requests are the ENDPOINT_HALT feature is procesed, all others the
48876 + * interface requests are ignored.</td></tr>
48878 + * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint
48879 + * requests are processed by the PCD. Interface requests are passed
48880 + * to the Gadget Driver.</td></tr>
48882 + * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg,
48883 + * with device address received </td></tr>
48885 + * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the
48886 + * requested descriptor</td></tr>
48888 + * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional -
48889 + * not implemented by any of the existing Gadget Drivers.</td></tr>
48891 + * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable
48892 + * all EPs and enable EPs for new configuration.</td></tr>
48894 + * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return
48895 + * the current configuration</td></tr>
48897 + * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all
48898 + * EPs and enable EPs for new configuration.</td></tr>
48900 + * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the
48901 + * current interface.</td></tr>
48903 + * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug
48904 + * message.</td></tr>
48907 + * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are
48908 + * processed by pcd_setup. Calling the Function Driver's setup function from
48909 + * pcd_setup processes the gadget SETUP commands.
48911 +static inline void pcd_setup(dwc_otg_pcd_t * pcd)
48913 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48914 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
48915 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48916 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48918 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
48920 +#ifdef DWC_UTE_CFI
48922 + struct cfi_usb_ctrlrequest cfi_req;
48925 + doeptsize0.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doeptsiz);
48927 + /** In BDMA more then 1 setup packet is not supported till 3.00a */
48928 + if (core_if->dma_enable && core_if->dma_desc_enable == 0
48929 + && (doeptsize0.b.supcnt < 2)
48930 + && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
48932 + ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n");
48934 + if ((core_if->snpsid >= OTG_CORE_REV_3_00a)
48935 + && (core_if->dma_enable == 1) && (core_if->dma_desc_enable == 0)) {
48937 + (pcd->setup_pkt +
48938 + (3 - doeptsize0.b.supcnt - 1 +
48939 + ep0->dwc_ep.stp_rollover))->req;
48942 + DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
48943 + ctrl.bmRequestType, ctrl.bRequest,
48944 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48945 + UGETW(ctrl.wLength));
48948 + /* Clean up the request queue */
48949 + dwc_otg_request_nuke(ep0);
48950 + ep0->stopped = 0;
48952 + if (ctrl.bmRequestType & UE_DIR_IN) {
48953 + ep0->dwc_ep.is_in = 1;
48954 + pcd->ep0state = EP0_IN_DATA_PHASE;
48956 + ep0->dwc_ep.is_in = 0;
48957 + pcd->ep0state = EP0_OUT_DATA_PHASE;
48960 + if (UGETW(ctrl.wLength) == 0) {
48961 + ep0->dwc_ep.is_in = 1;
48962 + pcd->ep0state = EP0_IN_STATUS_PHASE;
48965 + if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) {
48967 +#ifdef DWC_UTE_CFI
48968 + DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t));
48970 + //printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n",
48971 + ctrl.bRequestType, ctrl.bRequest);
48972 + if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) {
48973 + if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) {
48974 + retval = cfi_setup(pcd, &cfi_req);
48975 + if (retval < 0) {
48976 + ep0_do_stall(pcd, retval);
48977 + pcd->ep0_pending = 0;
48981 + /* if need gadget setup then call it and check the retval */
48982 + if (pcd->cfi->need_gadget_att) {
48984 + cfi_gadget_setup(pcd,
48987 + if (retval < 0) {
48988 + pcd->ep0_pending = 0;
48993 + if (pcd->cfi->need_status_in_complete) {
48994 + do_setup_in_status_phase(pcd);
49001 + /* handle non-standard (class/vendor) requests in the gadget driver */
49002 + do_gadget_setup(pcd, &ctrl);
49006 + /** @todo NGS: Handle bad setup packet? */
49008 +///////////////////////////////////////////
49009 +//// --- Standard Request handling --- ////
49011 + switch (ctrl.bRequest) {
49012 + case UR_GET_STATUS:
49013 + do_get_status(pcd);
49016 + case UR_CLEAR_FEATURE:
49017 + do_clear_feature(pcd);
49020 + case UR_SET_FEATURE:
49021 + do_set_feature(pcd);
49024 + case UR_SET_ADDRESS:
49025 + do_set_address(pcd);
49028 + case UR_SET_INTERFACE:
49029 + case UR_SET_CONFIG:
49030 +// _pcd->request_config = 1; /* Configuration changed */
49031 + do_gadget_setup(pcd, &ctrl);
49034 + case UR_SYNCH_FRAME:
49035 + do_gadget_setup(pcd, &ctrl);
49039 + /* Call the Gadget Driver's setup functions */
49040 + do_gadget_setup(pcd, &ctrl);
49046 + * This function completes the ep0 control transfer.
49048 +static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep)
49050 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
49051 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49052 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
49053 + dev_if->in_ep_regs[ep->dwc_ep.num];
49055 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
49056 + dev_if->out_ep_regs[ep->dwc_ep.num];
49058 + deptsiz0_data_t deptsiz;
49059 + dev_dma_desc_sts_t desc_sts;
49060 + dwc_otg_pcd_request_t *req;
49062 + dwc_otg_pcd_t *pcd = ep->pcd;
49064 +#ifdef DWC_UTE_CFI
49065 + struct cfi_usb_ctrlrequest *ctrlreq;
49066 + int retval = -DWC_E_NOT_SUPPORTED;
49069 + desc_sts.b.bytes = 0;
49071 + if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49072 + if (ep->dwc_ep.is_in) {
49074 + DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
49076 + do_setup_out_status_phase(pcd);
49079 + DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
49082 +#ifdef DWC_UTE_CFI
49083 + ctrlreq = &pcd->cfi->ctrl_req;
49085 + if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) {
49086 + if (ctrlreq->bRequest > 0xB0
49087 + && ctrlreq->bRequest < 0xBF) {
49089 + /* Return if the PCD failed to handle the request */
49092 + ctrl_write_complete(pcd->cfi,
49095 + ("ERROR setting a new value in the PCD(%d)\n",
49097 + ep0_do_stall(pcd, retval);
49098 + pcd->ep0_pending = 0;
49102 + /* If the gadget needs to be notified on the request */
49103 + if (pcd->cfi->need_gadget_att == 1) {
49104 + //retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req);
49106 + cfi_gadget_setup(pcd,
49110 + /* Return from the function if the gadget failed to process
49111 + * the request properly - this should never happen !!!
49113 + if (retval < 0) {
49115 + ("ERROR setting a new value in the gadget(%d)\n",
49117 + pcd->ep0_pending = 0;
49122 + CFI_INFO("%s: RETVAL=%d\n", __func__,
49124 + /* If we hit here then the PCD and the gadget has properly
49125 + * handled the request - so send the ZLP IN to the host.
49127 + /* @todo: MAS - decide whether we need to start the setup
49128 + * stage based on the need_setup value of the cfi object
49130 + do_setup_in_status_phase(pcd);
49131 + pcd->ep0_pending = 0;
49137 + do_setup_in_status_phase(pcd);
49139 + pcd->ep0_pending = 0;
49143 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49146 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
49148 + if (pcd->ep0state == EP0_OUT_STATUS_PHASE
49149 + || pcd->ep0state == EP0_IN_STATUS_PHASE) {
49151 + } else if (ep->dwc_ep.is_in) {
49152 + deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
49153 + if (core_if->dma_desc_enable != 0)
49154 + desc_sts = dev_if->in_desc_addr->status;
49156 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xfersize=%d pktcnt=%d\n",
49157 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
49158 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49161 + if (((core_if->dma_desc_enable == 0)
49162 + && (deptsiz.b.xfersize == 0))
49163 + || ((core_if->dma_desc_enable != 0)
49164 + && (desc_sts.b.bytes == 0))) {
49165 + req->actual = ep->dwc_ep.xfer_count;
49166 + /* Is a Zero Len Packet needed? */
49167 + if (req->sent_zlp) {
49169 + DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
49171 + req->sent_zlp = 0;
49173 + do_setup_out_status_phase(pcd);
49178 + deptsiz.d32 = DWC_READ_REG32(&out_ep_regs->doeptsiz);
49179 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n",
49180 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
49181 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49183 + req->actual = ep->dwc_ep.xfer_count;
49185 + /* Is a Zero Len Packet needed? */
49186 + if (req->sent_zlp) {
49188 + DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
49190 + req->sent_zlp = 0;
49192 + /* For older cores do setup in status phase in Slave/BDMA modes,
49193 + * starting from 3.00 do that only in slave, and for DMA modes
49194 + * just re-enable ep 0 OUT here*/
49195 + if (core_if->dma_enable == 0
49196 + || (core_if->dma_desc_enable == 0
49197 + && core_if->snpsid <= OTG_CORE_REV_2_94a)) {
49198 + do_setup_in_status_phase(pcd);
49199 + } else if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
49200 + DWC_DEBUGPL(DBG_PCDV,
49201 + "Enable out ep before in status phase\n");
49202 + ep0_out_start(core_if, pcd);
49206 + /* Complete the request */
49208 + dwc_otg_request_done(ep, req, 0);
49209 + ep->dwc_ep.start_xfer_buff = 0;
49210 + ep->dwc_ep.xfer_buff = 0;
49211 + ep->dwc_ep.xfer_len = 0;
49217 +#ifdef DWC_UTE_CFI
49219 + * This function calculates traverses all the CFI DMA descriptors and
49220 + * and accumulates the bytes that are left to be transfered.
49222 + * @return The total bytes left to transfered, or a negative value as failure
49224 +static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep)
49228 + struct dwc_otg_dma_desc *ddesc = NULL;
49229 + struct cfi_ep *cfiep;
49231 + /* See if the pcd_ep has its respective cfi_ep mapped */
49232 + cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep);
49234 + CFI_INFO("%s: Failed to find ep\n", __func__);
49238 + ddesc = ep->dwc_ep.descs;
49240 + for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) {
49242 +#if defined(PRINT_CFI_DMA_DESCS)
49243 + print_desc(ddesc, ep->ep.name, i);
49245 + ret += ddesc->status.b.bytes;
49250 + CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__,
49258 + * This function completes the request for the EP. If there are
49259 + * additional requests for the EP in the queue they will be started.
49261 +static void complete_ep(dwc_otg_pcd_ep_t * ep)
49263 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
49264 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49265 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
49266 + dev_if->in_ep_regs[ep->dwc_ep.num];
49267 + deptsiz_data_t deptsiz;
49268 + dev_dma_desc_sts_t desc_sts;
49269 + dwc_otg_pcd_request_t *req = 0;
49270 + dwc_otg_dev_dma_desc_t *dma_desc;
49271 + uint32_t byte_count = 0;
49275 + DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num,
49276 + (ep->dwc_ep.is_in ? "IN" : "OUT"));
49278 + /* Get any pending requests */
49279 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49280 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
49282 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
49286 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
49290 + DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending);
49292 + if (ep->dwc_ep.is_in) {
49293 + deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
49295 + if (core_if->dma_enable) {
49296 + if (core_if->dma_desc_enable == 0) {
49297 + if (deptsiz.b.xfersize == 0
49298 + && deptsiz.b.pktcnt == 0) {
49300 + ep->dwc_ep.xfer_len -
49301 + ep->dwc_ep.xfer_count;
49303 + ep->dwc_ep.xfer_buff += byte_count;
49304 + ep->dwc_ep.dma_addr += byte_count;
49305 + ep->dwc_ep.xfer_count += byte_count;
49307 + DWC_DEBUGPL(DBG_PCDV,
49308 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
49311 + is_in ? "IN" : "OUT"),
49312 + ep->dwc_ep.xfer_len,
49313 + deptsiz.b.xfersize,
49314 + deptsiz.b.pktcnt);
49316 + if (ep->dwc_ep.xfer_len <
49317 + ep->dwc_ep.total_len) {
49318 + dwc_otg_ep_start_transfer
49319 + (core_if, &ep->dwc_ep);
49320 + } else if (ep->dwc_ep.sent_zlp) {
49322 + * This fragment of code should initiate 0
49323 + * length transfer in case if it is queued
49324 + * a transfer with size divisible to EPs max
49325 + * packet size and with usb_request zero field
49326 + * is set, which means that after data is transfered,
49327 + * it is also should be transfered
49328 + * a 0 length packet at the end. For Slave and
49329 + * Buffer DMA modes in this case SW has
49330 + * to initiate 2 transfers one with transfer size,
49331 + * and the second with 0 size. For Descriptor
49332 + * DMA mode SW is able to initiate a transfer,
49333 + * which will handle all the packets including
49334 + * the last 0 length.
49336 + ep->dwc_ep.sent_zlp = 0;
49337 + dwc_otg_ep_start_zl_transfer
49338 + (core_if, &ep->dwc_ep);
49343 + if (ep->dwc_ep.type ==
49344 + DWC_OTG_EP_TYPE_ISOC) {
49346 + dwc_otg_request_done(ep, req, 0);
49348 + ep->dwc_ep.start_xfer_buff = 0;
49349 + ep->dwc_ep.xfer_buff = 0;
49350 + ep->dwc_ep.xfer_len = 0;
49352 + /* If there is a request in the queue start it. */
49353 + start_next_request(ep);
49356 + ("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n",
49358 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
49359 + deptsiz.b.xfersize,
49360 + deptsiz.b.pktcnt);
49363 + dma_desc = ep->dwc_ep.desc_addr;
49365 + ep->dwc_ep.sent_zlp = 0;
49367 +#ifdef DWC_UTE_CFI
49368 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
49369 + ep->dwc_ep.buff_mode);
49370 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49373 + residue = cfi_calc_desc_residue(ep);
49377 + byte_count = residue;
49380 + for (i = 0; i < ep->dwc_ep.desc_cnt;
49382 + desc_sts = dma_desc->status;
49383 + byte_count += desc_sts.b.bytes;
49386 +#ifdef DWC_UTE_CFI
49389 + if (byte_count == 0) {
49390 + ep->dwc_ep.xfer_count =
49391 + ep->dwc_ep.total_len;
49394 + DWC_WARN("Incomplete transfer\n");
49398 + if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) {
49399 + DWC_DEBUGPL(DBG_PCDV,
49400 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
49402 + ep->dwc_ep.is_in ? "IN" : "OUT",
49403 + ep->dwc_ep.xfer_len,
49404 + deptsiz.b.xfersize,
49405 + deptsiz.b.pktcnt);
49407 + /* Check if the whole transfer was completed,
49408 + * if no, setup transfer for next portion of data
49410 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49411 + dwc_otg_ep_start_transfer(core_if,
49413 + } else if (ep->dwc_ep.sent_zlp) {
49415 + * This fragment of code should initiate 0
49416 + * length trasfer in case if it is queued
49417 + * a trasfer with size divisible to EPs max
49418 + * packet size and with usb_request zero field
49419 + * is set, which means that after data is transfered,
49420 + * it is also should be transfered
49421 + * a 0 length packet at the end. For Slave and
49422 + * Buffer DMA modes in this case SW has
49423 + * to initiate 2 transfers one with transfer size,
49424 + * and the second with 0 size. For Desriptor
49425 + * DMA mode SW is able to initiate a transfer,
49426 + * which will handle all the packets including
49427 + * the last 0 legth.
49429 + ep->dwc_ep.sent_zlp = 0;
49430 + dwc_otg_ep_start_zl_transfer(core_if,
49437 + ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n",
49439 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
49440 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49444 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
49445 + dev_if->out_ep_regs[ep->dwc_ep.num];
49446 + desc_sts.d32 = 0;
49447 + if (core_if->dma_enable) {
49448 + if (core_if->dma_desc_enable) {
49449 + dma_desc = ep->dwc_ep.desc_addr;
49451 + ep->dwc_ep.sent_zlp = 0;
49453 +#ifdef DWC_UTE_CFI
49454 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
49455 + ep->dwc_ep.buff_mode);
49456 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49458 + residue = cfi_calc_desc_residue(ep);
49461 + byte_count = residue;
49465 + for (i = 0; i < ep->dwc_ep.desc_cnt;
49467 + desc_sts = dma_desc->status;
49468 + byte_count += desc_sts.b.bytes;
49472 +#ifdef DWC_UTE_CFI
49475 + /* Checking for interrupt Out transfers with not
49476 + * dword aligned mps sizes
49478 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_INTR &&
49479 + (ep->dwc_ep.maxpacket%4)) {
49480 + ep->dwc_ep.xfer_count =
49481 + ep->dwc_ep.total_len - byte_count;
49482 + if ((ep->dwc_ep.xfer_len %
49483 + ep->dwc_ep.maxpacket)
49484 + && (ep->dwc_ep.xfer_len /
49485 + ep->dwc_ep.maxpacket <
49486 + MAX_DMA_DESC_CNT))
49487 + ep->dwc_ep.xfer_len -=
49488 + (ep->dwc_ep.desc_cnt -
49489 + 1) * ep->dwc_ep.maxpacket +
49490 + ep->dwc_ep.xfer_len %
49491 + ep->dwc_ep.maxpacket;
49493 + ep->dwc_ep.xfer_len -=
49494 + ep->dwc_ep.desc_cnt *
49495 + ep->dwc_ep.maxpacket;
49496 + if (ep->dwc_ep.xfer_len > 0) {
49497 + dwc_otg_ep_start_transfer
49498 + (core_if, &ep->dwc_ep);
49503 + ep->dwc_ep.xfer_count =
49504 + ep->dwc_ep.total_len - byte_count +
49507 + total_len & 0x3)) & 0x3);
49513 + DWC_READ_REG32(&out_ep_regs->doeptsiz);
49515 + byte_count = (ep->dwc_ep.xfer_len -
49516 + ep->dwc_ep.xfer_count -
49517 + deptsiz.b.xfersize);
49518 + ep->dwc_ep.xfer_buff += byte_count;
49519 + ep->dwc_ep.dma_addr += byte_count;
49520 + ep->dwc_ep.xfer_count += byte_count;
49522 + /* Check if the whole transfer was completed,
49523 + * if no, setup transfer for next portion of data
49525 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49526 + dwc_otg_ep_start_transfer(core_if,
49528 + } else if (ep->dwc_ep.sent_zlp) {
49530 + * This fragment of code should initiate 0
49531 + * length trasfer in case if it is queued
49532 + * a trasfer with size divisible to EPs max
49533 + * packet size and with usb_request zero field
49534 + * is set, which means that after data is transfered,
49535 + * it is also should be transfered
49536 + * a 0 length packet at the end. For Slave and
49537 + * Buffer DMA modes in this case SW has
49538 + * to initiate 2 transfers one with transfer size,
49539 + * and the second with 0 size. For Desriptor
49540 + * DMA mode SW is able to initiate a transfer,
49541 + * which will handle all the packets including
49542 + * the last 0 legth.
49544 + ep->dwc_ep.sent_zlp = 0;
49545 + dwc_otg_ep_start_zl_transfer(core_if,
49552 + /* Check if the whole transfer was completed,
49553 + * if no, setup transfer for next portion of data
49555 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49556 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
49557 + } else if (ep->dwc_ep.sent_zlp) {
49559 + * This fragment of code should initiate 0
49560 + * length transfer in case if it is queued
49561 + * a transfer with size divisible to EPs max
49562 + * packet size and with usb_request zero field
49563 + * is set, which means that after data is transfered,
49564 + * it is also should be transfered
49565 + * a 0 length packet at the end. For Slave and
49566 + * Buffer DMA modes in this case SW has
49567 + * to initiate 2 transfers one with transfer size,
49568 + * and the second with 0 size. For Descriptor
49569 + * DMA mode SW is able to initiate a transfer,
49570 + * which will handle all the packets including
49571 + * the last 0 length.
49573 + ep->dwc_ep.sent_zlp = 0;
49574 + dwc_otg_ep_start_zl_transfer(core_if,
49581 + DWC_DEBUGPL(DBG_PCDV,
49582 + "addr %p, %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n",
49583 + &out_ep_regs->doeptsiz, ep->dwc_ep.num,
49584 + ep->dwc_ep.is_in ? "IN" : "OUT",
49585 + ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count,
49586 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49589 + /* Complete the request */
49591 +#ifdef DWC_UTE_CFI
49592 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49593 + req->actual = ep->dwc_ep.cfi_req_len - byte_count;
49596 + req->actual = ep->dwc_ep.xfer_count;
49597 +#ifdef DWC_UTE_CFI
49600 + if (req->dw_align_buf) {
49601 + if (!ep->dwc_ep.is_in) {
49602 + dwc_memcpy(req->buf, req->dw_align_buf, req->length);
49604 + DWC_DMA_FREE(req->length, req->dw_align_buf,
49605 + req->dw_align_buf_dma);
49608 + dwc_otg_request_done(ep, req, 0);
49610 + ep->dwc_ep.start_xfer_buff = 0;
49611 + ep->dwc_ep.xfer_buff = 0;
49612 + ep->dwc_ep.xfer_len = 0;
49614 + /* If there is a request in the queue start it. */
49615 + start_next_request(ep);
49619 +#ifdef DWC_EN_ISOC
49622 + * This function BNA interrupt for Isochronous EPs
49625 +static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep)
49627 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
49628 + volatile uint32_t *addr;
49629 + depctl_data_t depctl = {.d32 = 0 };
49630 + dwc_otg_pcd_t *pcd = ep->pcd;
49631 + dwc_otg_dev_dma_desc_t *dma_desc;
49635 + dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num);
49637 + if (dwc_ep->is_in) {
49638 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49639 + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
49640 + sts.d32 = dma_desc->status.d32;
49641 + sts.b_iso_in.bs = BS_HOST_READY;
49642 + dma_desc->status.d32 = sts.d32;
49645 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49646 + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
49647 + sts.d32 = dma_desc->status.d32;
49648 + sts.b_iso_out.bs = BS_HOST_READY;
49649 + dma_desc->status.d32 = sts.d32;
49653 + if (dwc_ep->is_in == 0) {
49655 + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->
49659 + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
49661 + depctl.b.epena = 1;
49662 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
49666 + * This function sets latest iso packet information(non-PTI mode)
49668 + * @param core_if Programming view of DWC_otg controller.
49669 + * @param ep The EP to start the transfer on.
49672 +void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
49674 + deptsiz_data_t deptsiz = {.d32 = 0 };
49675 + dma_addr_t dma_addr;
49678 + if (ep->proc_buf_num)
49679 + dma_addr = ep->dma_addr1;
49681 + dma_addr = ep->dma_addr0;
49685 + DWC_READ_REG32(&core_if->dev_if->
49686 + in_ep_regs[ep->num]->dieptsiz);
49687 + offset = ep->data_per_frame;
49690 + DWC_READ_REG32(&core_if->dev_if->
49691 + out_ep_regs[ep->num]->doeptsiz);
49693 + ep->data_per_frame +
49694 + (0x4 & (0x4 - (ep->data_per_frame & 0x3)));
49697 + if (!deptsiz.b.xfersize) {
49698 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
49699 + ep->pkt_info[ep->cur_pkt].offset =
49700 + ep->cur_pkt_dma_addr - dma_addr;
49701 + ep->pkt_info[ep->cur_pkt].status = 0;
49703 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
49704 + ep->pkt_info[ep->cur_pkt].offset =
49705 + ep->cur_pkt_dma_addr - dma_addr;
49706 + ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA;
49708 + ep->cur_pkt_addr += offset;
49709 + ep->cur_pkt_dma_addr += offset;
49714 + * This function sets latest iso packet information(DDMA mode)
49716 + * @param core_if Programming view of DWC_otg controller.
49717 + * @param dwc_ep The EP to start the transfer on.
49720 +static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if,
49721 + dwc_ep_t * dwc_ep)
49723 + dwc_otg_dev_dma_desc_t *dma_desc;
49724 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49725 + iso_pkt_info_t *iso_packet;
49726 + uint32_t data_per_desc;
49730 + iso_packet = dwc_ep->pkt_info;
49732 + /** Reinit closed DMA Descriptors*/
49733 + /** ISO OUT EP */
49734 + if (dwc_ep->is_in == 0) {
49736 + dwc_ep->iso_desc_addr +
49737 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
49740 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
49741 + i += dwc_ep->pkt_per_frm) {
49742 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
49744 + ((j + 1) * dwc_ep->maxpacket >
49746 + data_per_frame) ? dwc_ep->data_per_frame -
49747 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49749 + (data_per_desc % 4) ? (4 -
49753 + sts.d32 = dma_desc->status.d32;
49755 + /* Write status in iso_packet_decsriptor */
49756 + iso_packet->status =
49757 + sts.b_iso_out.rxsts +
49758 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
49759 + if (iso_packet->status) {
49760 + iso_packet->status = -DWC_E_NO_DATA;
49763 + /* Received data length */
49764 + if (!sts.b_iso_out.rxbytes) {
49765 + iso_packet->length =
49767 + sts.b_iso_out.rxbytes;
49769 + iso_packet->length =
49771 + sts.b_iso_out.rxbytes + (4 -
49772 + dwc_ep->data_per_frame
49776 + iso_packet->offset = offset;
49778 + offset += data_per_desc;
49784 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
49786 + ((j + 1) * dwc_ep->maxpacket >
49787 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
49788 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49790 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
49792 + sts.d32 = dma_desc->status.d32;
49794 + /* Write status in iso_packet_decsriptor */
49795 + iso_packet->status =
49796 + sts.b_iso_out.rxsts +
49797 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
49798 + if (iso_packet->status) {
49799 + iso_packet->status = -DWC_E_NO_DATA;
49802 + /* Received data length */
49803 + iso_packet->length =
49804 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
49806 + iso_packet->offset = offset;
49808 + offset += data_per_desc;
49813 + sts.d32 = dma_desc->status.d32;
49815 + /* Write status in iso_packet_decsriptor */
49816 + iso_packet->status =
49817 + sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE);
49818 + if (iso_packet->status) {
49819 + iso_packet->status = -DWC_E_NO_DATA;
49821 + /* Received data length */
49822 + if (!sts.b_iso_out.rxbytes) {
49823 + iso_packet->length =
49824 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
49826 + iso_packet->length =
49827 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes +
49828 + (4 - dwc_ep->data_per_frame % 4);
49831 + iso_packet->offset = offset;
49836 + dwc_ep->iso_desc_addr +
49837 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
49839 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
49840 + sts.d32 = dma_desc->status.d32;
49842 + /* Write status in iso packet descriptor */
49843 + iso_packet->status =
49844 + sts.b_iso_in.txsts +
49845 + (sts.b_iso_in.bs ^ BS_DMA_DONE);
49846 + if (iso_packet->status != 0) {
49847 + iso_packet->status = -DWC_E_NO_DATA;
49850 + /* Bytes has been transfered */
49851 + iso_packet->length =
49852 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
49858 + sts.d32 = dma_desc->status.d32;
49859 + while (sts.b_iso_in.bs == BS_DMA_BUSY) {
49860 + sts.d32 = dma_desc->status.d32;
49863 + /* Write status in iso packet descriptor ??? do be done with ERROR codes */
49864 + iso_packet->status =
49865 + sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE);
49866 + if (iso_packet->status != 0) {
49867 + iso_packet->status = -DWC_E_NO_DATA;
49870 + /* Bytes has been transfered */
49871 + iso_packet->length =
49872 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
49877 + * This function reinitialize DMA Descriptors for Isochronous transfer
49879 + * @param core_if Programming view of DWC_otg controller.
49880 + * @param dwc_ep The EP to start the transfer on.
49883 +static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
49886 + dwc_otg_dev_dma_desc_t *dma_desc;
49887 + dma_addr_t dma_ad;
49888 + volatile uint32_t *addr;
49889 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49890 + uint32_t data_per_desc;
49892 + if (dwc_ep->is_in == 0) {
49893 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
49895 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
49898 + if (dwc_ep->proc_buf_num == 0) {
49899 + /** Buffer 0 descriptors setup */
49900 + dma_ad = dwc_ep->dma_addr0;
49902 + /** Buffer 1 descriptors setup */
49903 + dma_ad = dwc_ep->dma_addr1;
49906 + /** Reinit closed DMA Descriptors*/
49907 + /** ISO OUT EP */
49908 + if (dwc_ep->is_in == 0) {
49910 + dwc_ep->iso_desc_addr +
49911 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
49913 + sts.b_iso_out.bs = BS_HOST_READY;
49914 + sts.b_iso_out.rxsts = 0;
49915 + sts.b_iso_out.l = 0;
49916 + sts.b_iso_out.sp = 0;
49917 + sts.b_iso_out.ioc = 0;
49918 + sts.b_iso_out.pid = 0;
49919 + sts.b_iso_out.framenum = 0;
49921 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
49922 + i += dwc_ep->pkt_per_frm) {
49923 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
49925 + ((j + 1) * dwc_ep->maxpacket >
49927 + data_per_frame) ? dwc_ep->data_per_frame -
49928 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49930 + (data_per_desc % 4) ? (4 -
49933 + sts.b_iso_out.rxbytes = data_per_desc;
49934 + dma_desc->buf = dma_ad;
49935 + dma_desc->status.d32 = sts.d32;
49937 + dma_ad += data_per_desc;
49942 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
49945 + ((j + 1) * dwc_ep->maxpacket >
49946 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
49947 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49949 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
49950 + sts.b_iso_out.rxbytes = data_per_desc;
49952 + dma_desc->buf = dma_ad;
49953 + dma_desc->status.d32 = sts.d32;
49956 + dma_ad += data_per_desc;
49959 + sts.b_iso_out.ioc = 1;
49960 + sts.b_iso_out.l = dwc_ep->proc_buf_num;
49963 + ((j + 1) * dwc_ep->maxpacket >
49964 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
49965 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49967 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
49968 + sts.b_iso_out.rxbytes = data_per_desc;
49970 + dma_desc->buf = dma_ad;
49971 + dma_desc->status.d32 = sts.d32;
49976 + dwc_ep->iso_desc_addr +
49977 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
49979 + sts.b_iso_in.bs = BS_HOST_READY;
49980 + sts.b_iso_in.txsts = 0;
49981 + sts.b_iso_in.sp = 0;
49982 + sts.b_iso_in.ioc = 0;
49983 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
49984 + sts.b_iso_in.framenum = dwc_ep->next_frame;
49985 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
49986 + sts.b_iso_in.l = 0;
49988 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
49989 + dma_desc->buf = dma_ad;
49990 + dma_desc->status.d32 = sts.d32;
49992 + sts.b_iso_in.framenum += dwc_ep->bInterval;
49993 + dma_ad += dwc_ep->data_per_frame;
49997 + sts.b_iso_in.ioc = 1;
49998 + sts.b_iso_in.l = dwc_ep->proc_buf_num;
50000 + dma_desc->buf = dma_ad;
50001 + dma_desc->status.d32 = sts.d32;
50003 + dwc_ep->next_frame =
50004 + sts.b_iso_in.framenum + dwc_ep->bInterval * 1;
50006 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
50010 + * This function is to handle Iso EP transfer complete interrupt
50011 + * in case Iso out packet was dropped
50013 + * @param core_if Programming view of DWC_otg controller.
50014 + * @param dwc_ep The EP for wihich transfer complete was asserted
50017 +static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if,
50018 + dwc_ep_t * dwc_ep)
50020 + uint32_t dma_addr;
50021 + uint32_t drp_pkt;
50022 + uint32_t drp_pkt_cnt;
50023 + deptsiz_data_t deptsiz = {.d32 = 0 };
50024 + depctl_data_t depctl = {.d32 = 0 };
50028 + DWC_READ_REG32(&core_if->dev_if->
50029 + out_ep_regs[dwc_ep->num]->doeptsiz);
50031 + drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt;
50032 + drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm);
50034 + /* Setting dropped packets status */
50035 + for (i = 0; i < drp_pkt_cnt; ++i) {
50036 + dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA;
50038 + deptsiz.b.pktcnt--;
50041 + if (deptsiz.b.pktcnt > 0) {
50042 + deptsiz.b.xfersize =
50043 + dwc_ep->xfer_len - (dwc_ep->pkt_cnt -
50044 + deptsiz.b.pktcnt) * dwc_ep->maxpacket;
50046 + deptsiz.b.xfersize = 0;
50047 + deptsiz.b.pktcnt = 0;
50050 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz,
50053 + if (deptsiz.b.pktcnt > 0) {
50054 + if (dwc_ep->proc_buf_num) {
50056 + dwc_ep->dma_addr1 + dwc_ep->xfer_len -
50057 + deptsiz.b.xfersize;
50060 + dwc_ep->dma_addr0 + dwc_ep->xfer_len -
50061 + deptsiz.b.xfersize;;
50064 + DWC_WRITE_REG32(&core_if->dev_if->
50065 + out_ep_regs[dwc_ep->num]->doepdma, dma_addr);
50067 + /** Re-enable endpoint, clear nak */
50069 + depctl.b.epena = 1;
50070 + depctl.b.cnak = 1;
50072 + DWC_MODIFY_REG32(&core_if->dev_if->
50073 + out_ep_regs[dwc_ep->num]->doepctl, depctl.d32,
50082 + * This function sets iso packets information(PTI mode)
50084 + * @param core_if Programming view of DWC_otg controller.
50085 + * @param ep The EP to start the transfer on.
50088 +static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
50091 + dma_addr_t dma_ad;
50092 + iso_pkt_info_t *packet_info = ep->pkt_info;
50094 + uint32_t frame_data;
50095 + deptsiz_data_t deptsiz;
50097 + if (ep->proc_buf_num == 0) {
50098 + /** Buffer 0 descriptors setup */
50099 + dma_ad = ep->dma_addr0;
50101 + /** Buffer 1 descriptors setup */
50102 + dma_ad = ep->dma_addr1;
50107 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
50111 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
50115 + if (!deptsiz.b.xfersize) {
50117 + for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) {
50118 + frame_data = ep->data_per_frame;
50119 + for (j = 0; j < ep->pkt_per_frm; ++j) {
50121 + /* Packet status - is not set as initially
50122 + * it is set to 0 and if packet was sent
50123 + successfully, status field will remain 0*/
50125 + /* Bytes has been transfered */
50126 + packet_info->length =
50128 + frame_data) ? ep->maxpacket : frame_data;
50130 + /* Received packet offset */
50131 + packet_info->offset = offset;
50132 + offset += packet_info->length;
50133 + frame_data -= packet_info->length;
50140 + /* This is a workaround for in case of Transfer Complete with
50141 + * PktDrpSts interrupts merging - in this case Transfer complete
50142 + * interrupt for Isoc Out Endpoint is asserted without PktDrpSts
50143 + * set and with DOEPTSIZ register non zero. Investigations showed,
50144 + * that this happens when Out packet is dropped, but because of
50145 + * interrupts merging during first interrupt handling PktDrpSts
50146 + * bit is cleared and for next merged interrupts it is not reset.
50147 + * In this case SW hadles the interrupt as if PktDrpSts bit is set.
50152 + return handle_iso_out_pkt_dropped(core_if, ep);
50158 + * This function is to handle Iso EP transfer complete interrupt
50160 + * @param pcd The PCD
50161 + * @param ep The EP for which transfer complete was asserted
50164 +static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
50166 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
50167 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
50168 + uint8_t is_last = 0;
50170 + if (ep->dwc_ep.next_frame == 0xffffffff) {
50171 + DWC_WARN("Next frame is not set!\n");
50175 + if (core_if->dma_enable) {
50176 + if (core_if->dma_desc_enable) {
50177 + set_ddma_iso_pkts_info(core_if, dwc_ep);
50178 + reinit_ddma_iso_xfer(core_if, dwc_ep);
50181 + if (core_if->pti_enh_enable) {
50182 + if (set_iso_pkts_info(core_if, dwc_ep)) {
50183 + dwc_ep->proc_buf_num =
50184 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
50185 + dwc_otg_iso_ep_start_buf_transfer
50186 + (core_if, dwc_ep);
50190 + set_current_pkt_info(core_if, dwc_ep);
50191 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
50193 + dwc_ep->cur_pkt = 0;
50194 + dwc_ep->proc_buf_num =
50195 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
50196 + if (dwc_ep->proc_buf_num) {
50197 + dwc_ep->cur_pkt_addr =
50198 + dwc_ep->xfer_buff1;
50199 + dwc_ep->cur_pkt_dma_addr =
50200 + dwc_ep->dma_addr1;
50202 + dwc_ep->cur_pkt_addr =
50203 + dwc_ep->xfer_buff0;
50204 + dwc_ep->cur_pkt_dma_addr =
50205 + dwc_ep->dma_addr0;
50209 + dwc_otg_iso_ep_start_frm_transfer(core_if,
50214 + set_current_pkt_info(core_if, dwc_ep);
50215 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
50217 + dwc_ep->cur_pkt = 0;
50218 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
50219 + if (dwc_ep->proc_buf_num) {
50220 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1;
50221 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1;
50223 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0;
50224 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0;
50228 + dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep);
50231 + dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle);
50233 +#endif /* DWC_EN_ISOC */
50236 + * This function handle BNA interrupt for Non Isochronous EPs
50239 +static void dwc_otg_pcd_handle_noniso_bna(dwc_otg_pcd_ep_t * ep)
50241 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
50242 + volatile uint32_t *addr;
50243 + depctl_data_t depctl = {.d32 = 0 };
50244 + dwc_otg_pcd_t *pcd = ep->pcd;
50245 + dwc_otg_dev_dma_desc_t *dma_desc;
50246 + dev_dma_desc_sts_t sts = {.d32 = 0 };
50247 + dwc_otg_core_if_t *core_if = ep->pcd->core_if;
50250 + if (!dwc_ep->desc_cnt)
50251 + DWC_WARN("Ep%d %s Descriptor count = %d \n", dwc_ep->num,
50252 + (dwc_ep->is_in ? "IN" : "OUT"), dwc_ep->desc_cnt);
50254 + if (core_if->core_params->cont_on_bna && !dwc_ep->is_in
50255 + && dwc_ep->type != DWC_OTG_EP_TYPE_CONTROL) {
50256 + uint32_t doepdma;
50257 + dwc_otg_dev_out_ep_regs_t *out_regs =
50258 + core_if->dev_if->out_ep_regs[dwc_ep->num];
50259 + doepdma = DWC_READ_REG32(&(out_regs->doepdma));
50260 + start = (doepdma - dwc_ep->dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t);
50261 + dma_desc = &(dwc_ep->desc_addr[start]);
50264 + dma_desc = dwc_ep->desc_addr;
50268 + for (i = start; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
50269 + sts.d32 = dma_desc->status.d32;
50270 + sts.b.bs = BS_HOST_READY;
50271 + dma_desc->status.d32 = sts.d32;
50274 + if (dwc_ep->is_in == 0) {
50276 + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->
50280 + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
50282 + depctl.b.epena = 1;
50283 + depctl.b.cnak = 1;
50284 + DWC_MODIFY_REG32(addr, 0, depctl.d32);
50288 + * This function handles EP0 Control transfers.
50290 + * The state of the control transfers are tracked in
50291 + * <code>ep0state</code>.
50293 +static void handle_ep0(dwc_otg_pcd_t * pcd)
50295 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50296 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
50297 + dev_dma_desc_sts_t desc_sts;
50298 + deptsiz0_data_t deptsiz;
50299 + uint32_t byte_count;
50302 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
50303 + print_ep0_state(pcd);
50306 +// DWC_PRINTF("HANDLE EP0\n");
50308 + switch (pcd->ep0state) {
50309 + case EP0_DISCONNECT:
50313 + pcd->request_config = 0;
50318 + case EP0_IN_DATA_PHASE:
50320 + DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
50321 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
50322 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
50325 + if (core_if->dma_enable != 0) {
50327 + * For EP0 we can only program 1 packet at a time so we
50328 + * need to do the make calculations after each complete.
50329 + * Call write_packet to make the calculations, as in
50330 + * slave mode, and use those values to determine if we
50333 + if (core_if->dma_desc_enable == 0) {
50335 + DWC_READ_REG32(&core_if->
50336 + dev_if->in_ep_regs[0]->
50339 + ep0->dwc_ep.xfer_len - deptsiz.b.xfersize;
50342 + core_if->dev_if->in_desc_addr->status;
50344 + ep0->dwc_ep.xfer_len - desc_sts.b.bytes;
50346 + ep0->dwc_ep.xfer_count += byte_count;
50347 + ep0->dwc_ep.xfer_buff += byte_count;
50348 + ep0->dwc_ep.dma_addr += byte_count;
50350 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
50351 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50353 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
50354 + } else if (ep0->dwc_ep.sent_zlp) {
50355 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50357 + ep0->dwc_ep.sent_zlp = 0;
50358 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
50360 + ep0_complete_request(ep0);
50361 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
50364 + case EP0_OUT_DATA_PHASE:
50366 + DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
50367 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
50368 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
50370 + if (core_if->dma_enable != 0) {
50371 + if (core_if->dma_desc_enable == 0) {
50373 + DWC_READ_REG32(&core_if->
50374 + dev_if->out_ep_regs[0]->
50377 + ep0->dwc_ep.maxpacket - deptsiz.b.xfersize;
50380 + core_if->dev_if->out_desc_addr->status;
50382 + ep0->dwc_ep.maxpacket - desc_sts.b.bytes;
50384 + ep0->dwc_ep.xfer_count += byte_count;
50385 + ep0->dwc_ep.xfer_buff += byte_count;
50386 + ep0->dwc_ep.dma_addr += byte_count;
50388 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
50389 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50391 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
50392 + } else if (ep0->dwc_ep.sent_zlp) {
50393 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50395 + ep0->dwc_ep.sent_zlp = 0;
50396 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
50398 + ep0_complete_request(ep0);
50399 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
50403 + case EP0_IN_STATUS_PHASE:
50404 + case EP0_OUT_STATUS_PHASE:
50405 + DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
50406 + ep0_complete_request(ep0);
50407 + pcd->ep0state = EP0_IDLE;
50408 + ep0->stopped = 1;
50409 + ep0->dwc_ep.is_in = 0; /* OUT for next SETUP */
50411 + /* Prepare for more SETUP Packets */
50412 + if (core_if->dma_enable) {
50413 + ep0_out_start(core_if, pcd);
50418 + DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
50422 + print_ep0_state(pcd);
50427 + * Restart transfer
50429 +static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum)
50431 + dwc_otg_core_if_t *core_if;
50432 + dwc_otg_dev_if_t *dev_if;
50433 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50434 + dwc_otg_pcd_ep_t *ep;
50436 + ep = get_in_ep(pcd, epnum);
50438 +#ifdef DWC_EN_ISOC
50439 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
50442 +#endif /* DWC_EN_ISOC */
50444 + core_if = GET_CORE_IF(pcd);
50445 + dev_if = core_if->dev_if;
50447 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
50449 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x"
50450 + " stopped=%d\n", ep->dwc_ep.xfer_buff,
50451 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped);
50453 + * If xfersize is 0 and pktcnt in not 0, resend the last packet.
50455 + if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
50456 + ep->dwc_ep.start_xfer_buff != 0) {
50457 + if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) {
50458 + ep->dwc_ep.xfer_count = 0;
50459 + ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
50460 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
50462 + ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
50463 + /* convert packet size to dwords. */
50464 + ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
50465 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
50468 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x "
50469 + "xfer_len=%0x stopped=%d\n",
50470 + ep->dwc_ep.xfer_buff,
50471 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len,
50473 + if (epnum == 0) {
50474 + dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
50476 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
50482 + * This function create new nextep sequnce based on Learn Queue.
50484 + * @param core_if Programming view of DWC_otg controller
50486 +void predict_nextep_seq( dwc_otg_core_if_t * core_if)
50488 + dwc_otg_device_global_regs_t *dev_global_regs =
50489 + core_if->dev_if->dev_global_regs;
50490 + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
50491 + /* Number of Token Queue Registers */
50492 + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
50493 + dtknq1_data_t dtknqr1;
50494 + uint32_t in_tkn_epnums[4];
50495 + uint8_t seqnum[MAX_EPS_CHANNELS];
50496 + uint8_t intkn_seq[TOKEN_Q_DEPTH];
50497 + grstctl_t resetctl = {.d32 = 0 };
50502 + int sort_done = 0;
50504 + volatile uint32_t *addr = &dev_global_regs->dtknqr1;
50507 + DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
50509 + /* Read the DTKNQ Registers */
50510 + for (i = 0; i < DTKNQ_REG_CNT; i++) {
50511 + in_tkn_epnums[i] = DWC_READ_REG32(addr);
50512 + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
50513 + in_tkn_epnums[i]);
50514 + if (addr == &dev_global_regs->dvbusdis) {
50515 + addr = &dev_global_regs->dtknqr3_dthrctl;
50522 + /* Copy the DTKNQR1 data to the bit field. */
50523 + dtknqr1.d32 = in_tkn_epnums[0];
50524 + if (dtknqr1.b.wrap_bit) {
50525 + ndx = dtknqr1.b.intknwptr;
50528 + end = TOKEN_Q_DEPTH -1;
50531 + end = dtknqr1.b.intknwptr -1;
50537 + /* Fill seqnum[] by initial values: EP number + 31 */
50538 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
50539 + seqnum[i] = i +31;
50542 + /* Fill intkn_seq[] from in_tkn_epnums[0] */
50543 + for (i=0; i < 6; i++)
50544 + intkn_seq[i] = (in_tkn_epnums[0] >> ((7-i) * 4)) & 0xf;
50546 + if (TOKEN_Q_DEPTH > 6) {
50547 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50548 + for (i=6; i < 14; i++)
50550 + (in_tkn_epnums[1] >> ((7 - (i - 6)) * 4)) & 0xf;
50553 + if (TOKEN_Q_DEPTH > 14) {
50554 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50555 + for (i=14; i < 22; i++)
50557 + (in_tkn_epnums[2] >> ((7 - (i - 14)) * 4)) & 0xf;
50560 + if (TOKEN_Q_DEPTH > 22) {
50561 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50562 + for (i=22; i < 30; i++)
50564 + (in_tkn_epnums[3] >> ((7 - (i - 22)) * 4)) & 0xf;
50567 + DWC_DEBUGPL(DBG_PCDV, "%s start=%d end=%d intkn_seq[]:\n", __func__,
50569 + for (i=0; i<TOKEN_Q_DEPTH; i++)
50570 + DWC_DEBUGPL(DBG_PCDV,"%d\n", intkn_seq[i]);
50572 + /* Update seqnum based on intkn_seq[] */
50575 + seqnum[intkn_seq[ndx]] = i;
50578 + if (ndx == TOKEN_Q_DEPTH)
50580 + } while ( i < TOKEN_Q_DEPTH );
50582 + /* Mark non active EP's in seqnum[] by 0xff */
50583 + for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
50584 + if (core_if->nextep_seq[i] == 0xff )
50585 + seqnum[i] = 0xff;
50588 + /* Sort seqnum[] */
50590 + while (!sort_done) {
50592 + for (i=0; i<core_if->dev_if->num_in_eps; i++) {
50593 + if (seqnum[i] > seqnum[i+1]) {
50594 + temp = seqnum[i];
50595 + seqnum[i] = seqnum[i+1];
50596 + seqnum[i+1] = temp;
50602 + ndx = start + seqnum[0];
50603 + if (ndx >= TOKEN_Q_DEPTH)
50604 + ndx = ndx % TOKEN_Q_DEPTH;
50605 + core_if->first_in_nextep_seq = intkn_seq[ndx];
50607 + /* Update seqnum[] by EP numbers */
50608 + for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
50610 + if (seqnum[i] < 31) {
50611 + ndx = start + seqnum[i];
50612 + if (ndx >= TOKEN_Q_DEPTH)
50613 + ndx = ndx % TOKEN_Q_DEPTH;
50614 + seqnum[i] = intkn_seq[ndx];
50616 + if (seqnum[i] < 0xff) {
50617 + seqnum[i] = seqnum[i] - 31;
50624 + /* Update nextep_seq[] based on seqnum[] */
50625 + for (i=0; i<core_if->dev_if->num_in_eps; i++) {
50626 + if (seqnum[i] != 0xff) {
50627 + if (seqnum[i+1] != 0xff) {
50628 + core_if->nextep_seq[seqnum[i]] = seqnum[i+1];
50630 + core_if->nextep_seq[seqnum[i]] = core_if->first_in_nextep_seq;
50638 + DWC_DEBUGPL(DBG_PCDV, "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
50639 + __func__, core_if->first_in_nextep_seq);
50640 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
50641 + DWC_DEBUGPL(DBG_PCDV,"%2d\n", core_if->nextep_seq[i]);
50644 + /* Flush the Learning Queue */
50645 + resetctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->grstctl);
50646 + resetctl.b.intknqflsh = 1;
50647 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
50653 + * handle the IN EP disable interrupt.
50655 +static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd,
50656 + const uint32_t epnum)
50658 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50659 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
50660 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50661 + dctl_data_t dctl = {.d32 = 0 };
50662 + dwc_otg_pcd_ep_t *ep;
50663 + dwc_ep_t *dwc_ep;
50664 + gintmsk_data_t gintmsk_data;
50665 + depctl_data_t depctl;
50666 + uint32_t diepdma;
50667 + uint32_t remain_to_transfer = 0;
50669 + uint32_t xfer_size;
50671 + ep = get_in_ep(pcd, epnum);
50672 + dwc_ep = &ep->dwc_ep;
50674 + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
50675 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
50680 + DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum,
50681 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl));
50682 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
50683 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
50685 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
50686 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
50688 + if ((core_if->start_predict == 0) || (depctl.b.eptype & 1)) {
50689 + if (ep->stopped) {
50690 + if (core_if->en_multiple_tx_fifo)
50691 + /* Flush the Tx FIFO */
50692 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
50693 + /* Clear the Global IN NP NAK */
50695 + dctl.b.cgnpinnak = 1;
50696 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
50697 + /* Restart the transaction */
50698 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
50699 + restart_transfer(pcd, epnum);
50702 + /* Restart the transaction */
50703 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
50704 + restart_transfer(pcd, epnum);
50706 + DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
50711 + if (core_if->start_predict > 2) { // NP IN EP
50712 + core_if->start_predict--;
50716 + core_if->start_predict--;
50718 + if (core_if->start_predict == 1) { // All NP IN Ep's disabled now
50720 + predict_nextep_seq(core_if);
50722 + /* Update all active IN EP's NextEP field based of nextep_seq[] */
50723 + for ( i = 0; i <= core_if->dev_if->num_in_eps; i++) {
50725 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50726 + if (core_if->nextep_seq[i] != 0xff) { // Active NP IN EP
50727 + depctl.b.nextep = core_if->nextep_seq[i];
50728 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
50731 + /* Flush Shared NP TxFIFO */
50732 + dwc_otg_flush_tx_fifo(core_if, 0);
50733 + /* Rewind buffers */
50734 + if (!core_if->dma_desc_enable) {
50735 + i = core_if->first_in_nextep_seq;
50737 + ep = get_in_ep(pcd, i);
50738 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
50739 + xfer_size = ep->dwc_ep.total_len - ep->dwc_ep.xfer_count;
50740 + if (xfer_size > ep->dwc_ep.maxxfer)
50741 + xfer_size = ep->dwc_ep.maxxfer;
50742 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50743 + if (dieptsiz.b.pktcnt != 0) {
50744 + if (xfer_size == 0) {
50745 + remain_to_transfer = 0;
50747 + if ((xfer_size % ep->dwc_ep.maxpacket) == 0) {
50748 + remain_to_transfer =
50749 + dieptsiz.b.pktcnt * ep->dwc_ep.maxpacket;
50751 + remain_to_transfer = ((dieptsiz.b.pktcnt -1) * ep->dwc_ep.maxpacket)
50752 + + (xfer_size % ep->dwc_ep.maxpacket);
50755 + diepdma = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepdma);
50756 + dieptsiz.b.xfersize = remain_to_transfer;
50757 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, dieptsiz.d32);
50758 + diepdma = ep->dwc_ep.dma_addr + (xfer_size - remain_to_transfer);
50759 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, diepdma);
50761 + i = core_if->nextep_seq[i];
50762 + } while (i != core_if->first_in_nextep_seq);
50763 + } else { // dma_desc_enable
50764 + DWC_PRINTF("%s Learning Queue not supported in DDMA\n", __func__);
50767 + /* Restart transfers in predicted sequences */
50768 + i = core_if->first_in_nextep_seq;
50770 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
50771 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50772 + if (dieptsiz.b.pktcnt != 0) {
50773 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50774 + depctl.b.epena = 1;
50775 + depctl.b.cnak = 1;
50776 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
50778 + i = core_if->nextep_seq[i];
50779 + } while (i != core_if->first_in_nextep_seq);
50781 + /* Clear the global non-periodic IN NAK handshake */
50783 + dctl.b.cgnpinnak = 1;
50784 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
50786 + /* Unmask EP Mismatch interrupt */
50787 + gintmsk_data.d32 = 0;
50788 + gintmsk_data.b.epmismatch = 1;
50789 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk_data.d32);
50791 + core_if->start_predict = 0;
50797 + * Handler for the IN EP timeout handshake interrupt.
50799 +static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd,
50800 + const uint32_t epnum)
50802 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50803 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
50806 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50807 + uint32_t num = 0;
50809 + dctl_data_t dctl = {.d32 = 0 };
50810 + dwc_otg_pcd_ep_t *ep;
50812 + gintmsk_data_t intr_mask = {.d32 = 0 };
50814 + ep = get_in_ep(pcd, epnum);
50816 + /* Disable the NP Tx Fifo Empty Interrrupt */
50817 + if (!core_if->dma_enable) {
50818 + intr_mask.b.nptxfempty = 1;
50819 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
50820 + intr_mask.d32, 0);
50822 + /** @todo NGS Check EP type.
50823 + * Implement for Periodic EPs */
50825 + * Non-periodic EP
50827 + /* Enable the Global IN NAK Effective Interrupt */
50828 + intr_mask.b.ginnakeff = 1;
50829 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
50831 + /* Set Global IN NAK */
50832 + dctl.b.sgnpinnak = 1;
50833 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
50838 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[num]->dieptsiz);
50839 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
50840 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
50843 +#ifdef DISABLE_PERIODIC_EP
50845 + * Set the NAK bit for this EP to
50846 + * start the disable process.
50849 + diepctl.b.snak = 1;
50850 + DWC_MODIFY_REG32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32,
50852 + ep->disabling = 1;
50858 + * Handler for the IN EP NAK interrupt.
50860 +static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd,
50861 + const uint32_t epnum)
50863 + /** @todo implement ISR */
50864 + dwc_otg_core_if_t *core_if;
50865 + diepmsk_data_t intr_mask = {.d32 = 0 };
50867 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK");
50868 + core_if = GET_CORE_IF(pcd);
50869 + intr_mask.b.nak = 1;
50871 + if (core_if->multiproc_int_enable) {
50872 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
50873 + diepeachintmsk[epnum], intr_mask.d32, 0);
50875 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->diepmsk,
50876 + intr_mask.d32, 0);
50883 + * Handler for the OUT EP Babble interrupt.
50885 +static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd,
50886 + const uint32_t epnum)
50888 + /** @todo implement ISR */
50889 + dwc_otg_core_if_t *core_if;
50890 + doepmsk_data_t intr_mask = {.d32 = 0 };
50892 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
50893 + "OUT EP Babble");
50894 + core_if = GET_CORE_IF(pcd);
50895 + intr_mask.b.babble = 1;
50897 + if (core_if->multiproc_int_enable) {
50898 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
50899 + doepeachintmsk[epnum], intr_mask.d32, 0);
50901 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
50902 + intr_mask.d32, 0);
50909 + * Handler for the OUT EP NAK interrupt.
50911 +static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd,
50912 + const uint32_t epnum)
50914 + /** @todo implement ISR */
50915 + dwc_otg_core_if_t *core_if;
50916 + doepmsk_data_t intr_mask = {.d32 = 0 };
50918 + DWC_DEBUGPL(DBG_ANY, "INTERRUPT Handler not implemented for %s\n", "OUT EP NAK");
50919 + core_if = GET_CORE_IF(pcd);
50920 + intr_mask.b.nak = 1;
50922 + if (core_if->multiproc_int_enable) {
50923 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
50924 + doepeachintmsk[epnum], intr_mask.d32, 0);
50926 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
50927 + intr_mask.d32, 0);
50934 + * Handler for the OUT EP NYET interrupt.
50936 +static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd,
50937 + const uint32_t epnum)
50939 + /** @todo implement ISR */
50940 + dwc_otg_core_if_t *core_if;
50941 + doepmsk_data_t intr_mask = {.d32 = 0 };
50943 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET");
50944 + core_if = GET_CORE_IF(pcd);
50945 + intr_mask.b.nyet = 1;
50947 + if (core_if->multiproc_int_enable) {
50948 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
50949 + doepeachintmsk[epnum], intr_mask.d32, 0);
50951 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
50952 + intr_mask.d32, 0);
50959 + * This interrupt indicates that an IN EP has a pending Interrupt.
50960 + * The sequence for handling the IN EP interrupt is shown below:
50961 + * -# Read the Device All Endpoint Interrupt register
50962 + * -# Repeat the following for each IN EP interrupt bit set (from
50964 + * -# Read the Device Endpoint Interrupt (DIEPINTn) register
50965 + * -# If "Transfer Complete" call the request complete function
50966 + * -# If "Endpoint Disabled" complete the EP disable procedure.
50967 + * -# If "AHB Error Interrupt" log error
50968 + * -# If "Time-out Handshake" log error
50969 + * -# If "IN Token Received when TxFIFO Empty" write packet to Tx
50971 + * -# If "IN Token EP Mismatch" (disable, this is handled by EP
50972 + * Mismatch Interrupt)
50974 +static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd)
50976 +#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
50978 + diepint_data_t diepint = {.d32=0}; \
50979 + diepint.b.__intr = 1; \
50980 + DWC_WRITE_REG32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
50984 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50985 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
50986 + diepint_data_t diepint = {.d32 = 0 };
50987 + depctl_data_t depctl = {.d32 = 0 };
50988 + uint32_t ep_intr;
50989 + uint32_t epnum = 0;
50990 + dwc_otg_pcd_ep_t *ep;
50991 + dwc_ep_t *dwc_ep;
50992 + gintmsk_data_t intr_mask = {.d32 = 0 };
50994 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd);
50996 + /* Read in the device interrupt bits */
50997 + ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if);
50999 + /* Service the Device IN interrupts for each endpoint */
51000 + while (ep_intr) {
51001 + if (ep_intr & 0x1) {
51002 + uint32_t empty_msk;
51003 + /* Get EP pointer */
51004 + ep = get_in_ep(pcd, epnum);
51005 + dwc_ep = &ep->dwc_ep;
51008 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
51010 + DWC_READ_REG32(&dev_if->
51011 + dev_global_regs->dtknqr4_fifoemptymsk);
51013 + DWC_DEBUGPL(DBG_PCDV,
51014 + "IN EP INTERRUPT - %d\nepmty_msk - %8x diepctl - %8x\n",
51015 + epnum, empty_msk, depctl.d32);
51017 + DWC_DEBUGPL(DBG_PCD,
51018 + "EP%d-%s: type=%d, mps=%d\n",
51019 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
51020 + dwc_ep->type, dwc_ep->maxpacket);
51023 + dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep);
51025 + DWC_DEBUGPL(DBG_PCDV,
51026 + "EP %d Interrupt Register - 0x%x\n", epnum,
51028 + /* Transfer complete */
51029 + if (diepint.b.xfercompl) {
51030 + /* Disable the NP Tx FIFO Empty
51032 + if (core_if->en_multiple_tx_fifo == 0) {
51033 + intr_mask.b.nptxfempty = 1;
51035 + (&core_if->core_global_regs->gintmsk,
51036 + intr_mask.d32, 0);
51038 + /* Disable the Tx FIFO Empty Interrupt for this EP */
51039 + uint32_t fifoemptymsk =
51040 + 0x1 << dwc_ep->num;
51041 + DWC_MODIFY_REG32(&core_if->
51042 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
51043 + fifoemptymsk, 0);
51045 + /* Clear the bit in DIEPINTn for this interrupt */
51046 + CLEAR_IN_EP_INTR(core_if, epnum, xfercompl);
51048 + /* Complete the transfer */
51049 + if (epnum == 0) {
51052 +#ifdef DWC_EN_ISOC
51053 + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51054 + if (!ep->stopped)
51055 + complete_iso_ep(pcd, ep);
51057 +#endif /* DWC_EN_ISOC */
51058 +#ifdef DWC_UTE_PER_IO
51059 + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51060 + if (!ep->stopped)
51061 + complete_xiso_ep(ep);
51063 +#endif /* DWC_UTE_PER_IO */
51065 + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC &&
51066 + dwc_ep->bInterval > 1) {
51067 + dwc_ep->frame_num += dwc_ep->bInterval;
51068 + if (dwc_ep->frame_num > 0x3FFF)
51070 + dwc_ep->frm_overrun = 1;
51071 + dwc_ep->frame_num &= 0x3FFF;
51073 + dwc_ep->frm_overrun = 0;
51076 + if(diepint.b.nak)
51077 + CLEAR_IN_EP_INTR(core_if, epnum, nak);
51080 + /* Endpoint disable */
51081 + if (diepint.b.epdisabled) {
51082 + DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n",
51084 + handle_in_ep_disable_intr(pcd, epnum);
51086 + /* Clear the bit in DIEPINTn for this interrupt */
51087 + CLEAR_IN_EP_INTR(core_if, epnum, epdisabled);
51090 + if (diepint.b.ahberr) {
51091 + DWC_ERROR("EP%d IN AHB Error\n", epnum);
51092 + /* Clear the bit in DIEPINTn for this interrupt */
51093 + CLEAR_IN_EP_INTR(core_if, epnum, ahberr);
51095 + /* TimeOUT Handshake (non-ISOC IN EPs) */
51096 + if (diepint.b.timeout) {
51097 + DWC_ERROR("EP%d IN Time-out\n", epnum);
51098 + handle_in_ep_timeout_intr(pcd, epnum);
51100 + CLEAR_IN_EP_INTR(core_if, epnum, timeout);
51102 + /** IN Token received with TxF Empty */
51103 + if (diepint.b.intktxfemp) {
51104 + DWC_DEBUGPL(DBG_ANY,
51105 + "EP%d IN TKN TxFifo Empty\n",
51107 + if (!ep->stopped && epnum != 0) {
51109 + diepmsk_data_t diepmsk = {.d32 = 0 };
51110 + diepmsk.b.intktxfemp = 1;
51112 + if (core_if->multiproc_int_enable) {
51114 + (&dev_if->dev_global_regs->diepeachintmsk
51115 + [epnum], diepmsk.d32, 0);
51118 + (&dev_if->dev_global_regs->diepmsk,
51121 + } else if (core_if->dma_desc_enable
51123 + && pcd->ep0state ==
51124 + EP0_OUT_STATUS_PHASE) {
51125 + // EP0 IN set STALL
51127 + DWC_READ_REG32(&dev_if->in_ep_regs
51128 + [epnum]->diepctl);
51130 + /* set the disable and stall bits */
51131 + if (depctl.b.epena) {
51132 + depctl.b.epdis = 1;
51134 + depctl.b.stall = 1;
51135 + DWC_WRITE_REG32(&dev_if->in_ep_regs
51136 + [epnum]->diepctl,
51139 + CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp);
51141 + /** IN Token Received with EP mismatch */
51142 + if (diepint.b.intknepmis) {
51143 + DWC_DEBUGPL(DBG_ANY,
51144 + "EP%d IN TKN EP Mismatch\n", epnum);
51145 + CLEAR_IN_EP_INTR(core_if, epnum, intknepmis);
51147 + /** IN Endpoint NAK Effective */
51148 + if (diepint.b.inepnakeff) {
51149 + DWC_DEBUGPL(DBG_ANY,
51150 + "EP%d IN EP NAK Effective\n",
51152 + /* Periodic EP */
51153 + if (ep->disabling) {
51155 + depctl.b.snak = 1;
51156 + depctl.b.epdis = 1;
51157 + DWC_MODIFY_REG32(&dev_if->in_ep_regs
51158 + [epnum]->diepctl,
51162 + CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff);
51166 + /** IN EP Tx FIFO Empty Intr */
51167 + if (diepint.b.emptyintr) {
51168 + DWC_DEBUGPL(DBG_ANY,
51169 + "EP%d Tx FIFO Empty Intr \n",
51171 + write_empty_tx_fifo(pcd, epnum);
51173 + CLEAR_IN_EP_INTR(core_if, epnum, emptyintr);
51177 + /** IN EP BNA Intr */
51178 + if (diepint.b.bna) {
51179 + CLEAR_IN_EP_INTR(core_if, epnum, bna);
51180 + if (core_if->dma_desc_enable) {
51181 +#ifdef DWC_EN_ISOC
51182 + if (dwc_ep->type ==
51183 + DWC_OTG_EP_TYPE_ISOC) {
51185 + * This checking is performed to prevent first "false" BNA
51186 + * handling occuring right after reconnect
51188 + if (dwc_ep->next_frame !=
51190 + dwc_otg_pcd_handle_iso_bna(ep);
51192 +#endif /* DWC_EN_ISOC */
51194 + dwc_otg_pcd_handle_noniso_bna(ep);
51198 + /* NAK Interrutp */
51199 + if (diepint.b.nak) {
51200 + DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n",
51202 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
51203 + depctl_data_t depctl;
51204 + if (ep->dwc_ep.frame_num == 0xFFFFFFFF) {
51205 + ep->dwc_ep.frame_num = core_if->frame_num;
51206 + if (ep->dwc_ep.bInterval > 1) {
51208 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
51209 + if (ep->dwc_ep.frame_num & 0x1) {
51210 + depctl.b.setd1pid = 1;
51211 + depctl.b.setd0pid = 0;
51213 + depctl.b.setd0pid = 1;
51214 + depctl.b.setd1pid = 0;
51216 + DWC_WRITE_REG32(&dev_if->in_ep_regs[epnum]->diepctl, depctl.d32);
51218 + start_next_request(ep);
51220 + ep->dwc_ep.frame_num += ep->dwc_ep.bInterval;
51221 + if (dwc_ep->frame_num > 0x3FFF) {
51222 + dwc_ep->frm_overrun = 1;
51223 + dwc_ep->frame_num &= 0x3FFF;
51225 + dwc_ep->frm_overrun = 0;
51228 + CLEAR_IN_EP_INTR(core_if, epnum, nak);
51236 +#undef CLEAR_IN_EP_INTR
51240 + * This interrupt indicates that an OUT EP has a pending Interrupt.
51241 + * The sequence for handling the OUT EP interrupt is shown below:
51242 + * -# Read the Device All Endpoint Interrupt register
51243 + * -# Repeat the following for each OUT EP interrupt bit set (from
51245 + * -# Read the Device Endpoint Interrupt (DOEPINTn) register
51246 + * -# If "Transfer Complete" call the request complete function
51247 + * -# If "Endpoint Disabled" complete the EP disable procedure.
51248 + * -# If "AHB Error Interrupt" log error
51249 + * -# If "Setup Phase Done" process Setup Packet (See Standard USB
51250 + * Command Processing)
51252 +static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd)
51254 +#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
51256 + doepint_data_t doepint = {.d32=0}; \
51257 + doepint.b.__intr = 1; \
51258 + DWC_WRITE_REG32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
51262 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
51263 + uint32_t ep_intr;
51264 + doepint_data_t doepint = {.d32 = 0 };
51265 + uint32_t epnum = 0;
51266 + dwc_otg_pcd_ep_t *ep;
51267 + dwc_ep_t *dwc_ep;
51268 + dctl_data_t dctl = {.d32 = 0 };
51269 + gintmsk_data_t gintmsk = {.d32 = 0 };
51272 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
51274 + /* Read in the device interrupt bits */
51275 + ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if);
51277 + while (ep_intr) {
51278 + if (ep_intr & 0x1) {
51279 + /* Get EP pointer */
51280 + ep = get_out_ep(pcd, epnum);
51281 + dwc_ep = &ep->dwc_ep;
51284 + DWC_DEBUGPL(DBG_PCDV,
51285 + "EP%d-%s: type=%d, mps=%d\n",
51286 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
51287 + dwc_ep->type, dwc_ep->maxpacket);
51290 + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
51291 + /* Moved this interrupt upper due to core deffect of asserting
51292 + * OUT EP 0 xfercompl along with stsphsrcvd in BDMA */
51293 + if (doepint.b.stsphsercvd) {
51294 + deptsiz0_data_t deptsiz;
51295 + CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd);
51297 + DWC_READ_REG32(&core_if->dev_if->
51298 + out_ep_regs[0]->doeptsiz);
51299 + if (core_if->snpsid >= OTG_CORE_REV_3_00a
51300 + && core_if->dma_enable
51301 + && core_if->dma_desc_enable == 0
51302 + && doepint.b.xfercompl
51303 + && deptsiz.b.xfersize == 24) {
51304 + CLEAR_OUT_EP_INTR(core_if, epnum,
51306 + doepint.b.xfercompl = 0;
51307 + ep0_out_start(core_if, pcd);
51309 + if ((core_if->dma_desc_enable) ||
51310 + (core_if->dma_enable
51311 + && core_if->snpsid >=
51312 + OTG_CORE_REV_3_00a)) {
51313 + do_setup_in_status_phase(pcd);
51316 + /* Transfer complete */
51317 + if (doepint.b.xfercompl) {
51319 + if (epnum == 0) {
51320 + /* Clear the bit in DOEPINTn for this interrupt */
51321 + CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
51322 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
51323 + DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
51324 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepint),
51326 + DWC_DEBUGPL(DBG_PCDV, "DOEPCTL=%x \n",
51327 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepctl));
51329 + if (core_if->snpsid >= OTG_CORE_REV_3_00a
51330 + && core_if->dma_enable == 0) {
51331 + doepint_data_t doepint;
51332 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51333 + out_ep_regs[0]->doepint);
51334 + if (pcd->ep0state == EP0_IDLE && doepint.b.sr) {
51335 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51336 + goto exit_xfercompl;
51339 + /* In case of DDMA look at SR bit to go to the Data Stage */
51340 + if (core_if->dma_desc_enable) {
51341 + dev_dma_desc_sts_t status = {.d32 = 0};
51342 + if (pcd->ep0state == EP0_IDLE) {
51343 + status.d32 = core_if->dev_if->setup_desc_addr[core_if->
51344 + dev_if->setup_desc_index]->status.d32;
51345 + if(pcd->data_terminated) {
51346 + pcd->data_terminated = 0;
51347 + status.d32 = core_if->dev_if->out_desc_addr->status.d32;
51348 + dwc_memcpy(&pcd->setup_pkt->req, pcd->backup_buf, 8);
51350 + if (status.b.sr) {
51351 + if (doepint.b.setup) {
51352 + DWC_DEBUGPL(DBG_PCDV, "DMA DESC EP0_IDLE SR=1 setup=1\n");
51353 + /* Already started data stage, clear setup */
51354 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51355 + doepint.b.setup = 0;
51357 + /* Prepare for more setup packets */
51358 + if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
51359 + pcd->ep0state == EP0_IN_DATA_PHASE) {
51360 + ep0_out_start(core_if, pcd);
51363 + goto exit_xfercompl;
51365 + /* Prepare for more setup packets */
51366 + DWC_DEBUGPL(DBG_PCDV,
51367 + "EP0_IDLE SR=1 setup=0 new setup comes\n");
51368 + ep0_out_start(core_if, pcd);
51372 + dwc_otg_pcd_request_t *req;
51373 + dev_dma_desc_sts_t status = {.d32 = 0};
51374 + diepint_data_t diepint0;
51375 + diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
51376 + in_ep_regs[0]->diepint);
51378 + if (pcd->ep0state == EP0_STALL || pcd->ep0state == EP0_DISCONNECT) {
51379 + DWC_ERROR("EP0 is stalled/disconnected\n");
51382 + /* Clear IN xfercompl if set */
51383 + if (diepint0.b.xfercompl && (pcd->ep0state == EP0_IN_STATUS_PHASE
51384 + || pcd->ep0state == EP0_IN_DATA_PHASE)) {
51385 + DWC_WRITE_REG32(&core_if->dev_if->
51386 + in_ep_regs[0]->diepint, diepint0.d32);
51389 + status.d32 = core_if->dev_if->setup_desc_addr[core_if->
51390 + dev_if->setup_desc_index]->status.d32;
51392 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len
51393 + && (pcd->ep0state == EP0_OUT_DATA_PHASE))
51394 + status.d32 = core_if->dev_if->out_desc_addr->status.d32;
51395 + if (pcd->ep0state == EP0_OUT_STATUS_PHASE)
51396 + status.d32 = status.d32 = core_if->dev_if->
51397 + out_desc_addr->status.d32;
51399 + if (status.b.sr) {
51400 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51401 + DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
51403 + DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
51404 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51405 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
51406 + pcd->ep0state == EP0_OUT_DATA_PHASE) {
51407 + /* Read arrived setup packet from req->buf */
51408 + dwc_memcpy(&pcd->setup_pkt->req,
51409 + req->buf + ep->dwc_ep.xfer_count, 8);
51411 + req->actual = ep->dwc_ep.xfer_count;
51412 + dwc_otg_request_done(ep, req, -ECONNRESET);
51413 + ep->dwc_ep.start_xfer_buff = 0;
51414 + ep->dwc_ep.xfer_buff = 0;
51415 + ep->dwc_ep.xfer_len = 0;
51417 + pcd->ep0state = EP0_IDLE;
51418 + if (doepint.b.setup) {
51419 + DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
51420 + /* Data stage started, clear setup */
51421 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51422 + doepint.b.setup = 0;
51424 + /* Prepare for setup packets if ep0in was enabled*/
51425 + if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
51426 + ep0_out_start(core_if, pcd);
51429 + goto exit_xfercompl;
51431 + /* Prepare for more setup packets */
51432 + DWC_DEBUGPL(DBG_PCDV,
51433 + "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
51434 + ep0_out_start(core_if, pcd);
51439 + if (core_if->snpsid >= OTG_CORE_REV_2_94a && core_if->dma_enable
51440 + && core_if->dma_desc_enable == 0) {
51441 + doepint_data_t doepint_temp = {.d32 = 0};
51442 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
51443 + doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
51444 + out_ep_regs[ep->dwc_ep.num]->doepint);
51445 + doeptsize0.d32 = DWC_READ_REG32(&core_if->dev_if->
51446 + out_ep_regs[ep->dwc_ep.num]->doeptsiz);
51447 + if (pcd->ep0state == EP0_IDLE) {
51448 + if (doepint_temp.b.sr) {
51449 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51451 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51452 + out_ep_regs[0]->doepint);
51453 + if (doeptsize0.b.supcnt == 3) {
51454 + DWC_DEBUGPL(DBG_ANY, "Rolling over!!!!!!!\n");
51455 + ep->dwc_ep.stp_rollover = 1;
51457 + if (doepint.b.setup) {
51459 + /* Already started data stage, clear setup */
51460 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51461 + doepint.b.setup = 0;
51463 + ep->dwc_ep.stp_rollover = 0;
51464 + /* Prepare for more setup packets */
51465 + if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
51466 + pcd->ep0state == EP0_IN_DATA_PHASE) {
51467 + ep0_out_start(core_if, pcd);
51469 + goto exit_xfercompl;
51471 + /* Prepare for more setup packets */
51472 + DWC_DEBUGPL(DBG_ANY,
51473 + "EP0_IDLE SR=1 setup=0 new setup comes\n");
51474 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51475 + out_ep_regs[0]->doepint);
51476 + if(doepint.b.setup)
51478 + ep0_out_start(core_if, pcd);
51481 + dwc_otg_pcd_request_t *req;
51482 + diepint_data_t diepint0 = {.d32 = 0};
51483 + doepint_data_t doepint_temp = {.d32 = 0};
51484 + depctl_data_t diepctl0;
51485 + diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
51486 + in_ep_regs[0]->diepint);
51487 + diepctl0.d32 = DWC_READ_REG32(&core_if->dev_if->
51488 + in_ep_regs[0]->diepctl);
51490 + if (pcd->ep0state == EP0_IN_DATA_PHASE
51491 + || pcd->ep0state == EP0_IN_STATUS_PHASE) {
51492 + if (diepint0.b.xfercompl) {
51493 + DWC_WRITE_REG32(&core_if->dev_if->
51494 + in_ep_regs[0]->diepint, diepint0.d32);
51496 + if (diepctl0.b.epena) {
51497 + diepint_data_t diepint = {.d32 = 0};
51498 + diepctl0.b.snak = 1;
51499 + DWC_WRITE_REG32(&core_if->dev_if->
51500 + in_ep_regs[0]->diepctl, diepctl0.d32);
51503 + diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51504 + in_ep_regs[0]->diepint);
51505 + } while (!diepint.b.inepnakeff);
51506 + diepint.b.inepnakeff = 1;
51507 + DWC_WRITE_REG32(&core_if->dev_if->
51508 + in_ep_regs[0]->diepint, diepint.d32);
51509 + diepctl0.d32 = 0;
51510 + diepctl0.b.epdis = 1;
51511 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl,
51515 + diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51516 + in_ep_regs[0]->diepint);
51517 + } while (!diepint.b.epdisabled);
51518 + diepint.b.epdisabled = 1;
51519 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepint,
51523 + doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
51524 + out_ep_regs[ep->dwc_ep.num]->doepint);
51525 + if (doepint_temp.b.sr) {
51526 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51527 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51528 + DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
51530 + DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
51531 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51532 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
51533 + pcd->ep0state == EP0_OUT_DATA_PHASE) {
51534 + /* Read arrived setup packet from req->buf */
51535 + dwc_memcpy(&pcd->setup_pkt->req,
51536 + req->buf + ep->dwc_ep.xfer_count, 8);
51538 + req->actual = ep->dwc_ep.xfer_count;
51539 + dwc_otg_request_done(ep, req, -ECONNRESET);
51540 + ep->dwc_ep.start_xfer_buff = 0;
51541 + ep->dwc_ep.xfer_buff = 0;
51542 + ep->dwc_ep.xfer_len = 0;
51544 + pcd->ep0state = EP0_IDLE;
51545 + if (doepint.b.setup) {
51546 + DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
51547 + /* Data stage started, clear setup */
51548 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51549 + doepint.b.setup = 0;
51551 + /* Prepare for setup packets if ep0in was enabled*/
51552 + if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
51553 + ep0_out_start(core_if, pcd);
51555 + goto exit_xfercompl;
51557 + /* Prepare for more setup packets */
51558 + DWC_DEBUGPL(DBG_PCDV,
51559 + "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
51560 + ep0_out_start(core_if, pcd);
51565 + if (core_if->dma_enable == 0 || pcd->ep0state != EP0_IDLE)
51568 + DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
51569 + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep), doepint.d32);
51571 + if (core_if->dma_desc_enable == 0
51572 + || pcd->ep0state != EP0_IDLE)
51575 +#ifdef DWC_EN_ISOC
51576 + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51577 + if (doepint.b.pktdrpsts == 0) {
51578 + /* Clear the bit in DOEPINTn for this interrupt */
51579 + CLEAR_OUT_EP_INTR(core_if,
51582 + complete_iso_ep(pcd, ep);
51585 + doepint_data_t doepint = {.d32 = 0 };
51586 + doepint.b.xfercompl = 1;
51587 + doepint.b.pktdrpsts = 1;
51589 + (&core_if->dev_if->out_ep_regs
51590 + [epnum]->doepint,
51592 + if (handle_iso_out_pkt_dropped
51593 + (core_if, dwc_ep)) {
51594 + complete_iso_ep(pcd,
51598 +#endif /* DWC_EN_ISOC */
51599 +#ifdef DWC_UTE_PER_IO
51600 + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51601 + CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
51602 + if (!ep->stopped)
51603 + complete_xiso_ep(ep);
51604 +#endif /* DWC_UTE_PER_IO */
51606 + /* Clear the bit in DOEPINTn for this interrupt */
51607 + CLEAR_OUT_EP_INTR(core_if, epnum,
51610 + if (core_if->core_params->dev_out_nak) {
51611 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[epnum]);
51612 + pcd->core_if->ep_xfer_info[epnum].state = 0;
51614 + print_memory_payload(pcd, dwc_ep);
51622 + /* Endpoint disable */
51623 + if (doepint.b.epdisabled) {
51625 + /* Clear the bit in DOEPINTn for this interrupt */
51626 + CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled);
51627 + if (core_if->core_params->dev_out_nak) {
51629 + print_memory_payload(pcd, dwc_ep);
51631 + /* In case of timeout condition */
51632 + if (core_if->ep_xfer_info[epnum].state == 2) {
51633 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51634 + dev_global_regs->dctl);
51635 + dctl.b.cgoutnak = 1;
51636 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
51638 + /* Unmask goutnakeff interrupt which was masked
51639 + * during handle nak out interrupt */
51640 + gintmsk.b.goutnakeff = 1;
51641 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
51647 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
51649 + dctl_data_t dctl;
51650 + gintmsk_data_t intr_mask = {.d32 = 0};
51651 + dwc_otg_pcd_request_t *req = 0;
51653 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51654 + dev_global_regs->dctl);
51655 + dctl.b.cgoutnak = 1;
51656 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
51659 + intr_mask.d32 = 0;
51660 + intr_mask.b.incomplisoout = 1;
51662 + /* Get any pending requests */
51663 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51664 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51666 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
51668 + dwc_otg_request_done(ep, req, 0);
51669 + start_next_request(ep);
51672 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
51677 + if (doepint.b.ahberr) {
51678 + DWC_ERROR("EP%d OUT AHB Error\n", epnum);
51679 + DWC_ERROR("EP%d DEPDMA=0x%08x \n",
51680 + epnum, core_if->dev_if->out_ep_regs[epnum]->doepdma);
51681 + CLEAR_OUT_EP_INTR(core_if, epnum, ahberr);
51683 + /* Setup Phase Done (contorl EPs) */
51684 + if (doepint.b.setup) {
51686 + DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n", epnum);
51688 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51693 + /** OUT EP BNA Intr */
51694 + if (doepint.b.bna) {
51695 + CLEAR_OUT_EP_INTR(core_if, epnum, bna);
51696 + if (core_if->dma_desc_enable) {
51697 +#ifdef DWC_EN_ISOC
51698 + if (dwc_ep->type ==
51699 + DWC_OTG_EP_TYPE_ISOC) {
51701 + * This checking is performed to prevent first "false" BNA
51702 + * handling occuring right after reconnect
51704 + if (dwc_ep->next_frame !=
51706 + dwc_otg_pcd_handle_iso_bna(ep);
51708 +#endif /* DWC_EN_ISOC */
51710 + dwc_otg_pcd_handle_noniso_bna(ep);
51714 + /* Babble Interrupt */
51715 + if (doepint.b.babble) {
51716 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n",
51718 + handle_out_ep_babble_intr(pcd, epnum);
51720 + CLEAR_OUT_EP_INTR(core_if, epnum, babble);
51722 + if (doepint.b.outtknepdis) {
51723 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Token received when EP is \
51724 + disabled\n",epnum);
51725 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
51726 + doepmsk_data_t doepmsk = {.d32 = 0};
51727 + ep->dwc_ep.frame_num = core_if->frame_num;
51728 + if (ep->dwc_ep.bInterval > 1) {
51729 + depctl_data_t depctl;
51730 + depctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51731 + out_ep_regs[epnum]->doepctl);
51732 + if (ep->dwc_ep.frame_num & 0x1) {
51733 + depctl.b.setd1pid = 1;
51734 + depctl.b.setd0pid = 0;
51736 + depctl.b.setd0pid = 1;
51737 + depctl.b.setd1pid = 0;
51739 + DWC_WRITE_REG32(&core_if->dev_if->
51740 + out_ep_regs[epnum]->doepctl, depctl.d32);
51742 + start_next_request(ep);
51743 + doepmsk.b.outtknepdis = 1;
51744 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51747 + CLEAR_OUT_EP_INTR(core_if, epnum, outtknepdis);
51750 + /* NAK Interrutp */
51751 + if (doepint.b.nak) {
51752 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum);
51753 + handle_out_ep_nak_intr(pcd, epnum);
51755 + CLEAR_OUT_EP_INTR(core_if, epnum, nak);
51757 + /* NYET Interrutp */
51758 + if (doepint.b.nyet) {
51759 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum);
51760 + handle_out_ep_nyet_intr(pcd, epnum);
51762 + CLEAR_OUT_EP_INTR(core_if, epnum, nyet);
51772 +#undef CLEAR_OUT_EP_INTR
51774 +static int drop_transfer(uint32_t trgt_fr, uint32_t curr_fr, uint8_t frm_overrun)
51777 + if(!frm_overrun && curr_fr >= trgt_fr)
51779 + else if (frm_overrun
51780 + && (curr_fr >= trgt_fr && ((curr_fr - trgt_fr) < 0x3FFF / 2)))
51785 + * Incomplete ISO IN Transfer Interrupt.
51786 + * This interrupt indicates one of the following conditions occurred
51787 + * while transmitting an ISOC transaction.
51788 + * - Corrupted IN Token for ISOC EP.
51789 + * - Packet not complete in FIFO.
51790 + * The follow actions will be taken:
51791 + * -# Determine the EP
51792 + * -# Set incomplete flag in dwc_ep structure
51793 + * -# Disable EP; when "Endpoint Disabled" interrupt is received
51796 +int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd)
51798 + gintsts_data_t gintsts;
51800 +#ifdef DWC_EN_ISOC
51801 + dwc_otg_dev_if_t *dev_if;
51802 + deptsiz_data_t deptsiz = {.d32 = 0 };
51803 + depctl_data_t depctl = {.d32 = 0 };
51804 + dsts_data_t dsts = {.d32 = 0 };
51805 + dwc_ep_t *dwc_ep;
51808 + dev_if = GET_CORE_IF(pcd)->dev_if;
51810 + for (i = 1; i <= dev_if->num_in_eps; ++i) {
51811 + dwc_ep = &pcd->in_ep[i].dwc_ep;
51812 + if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51814 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
51816 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
51818 + if (depctl.b.epdis && deptsiz.d32) {
51819 + set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep);
51820 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
51821 + dwc_ep->cur_pkt = 0;
51822 + dwc_ep->proc_buf_num =
51823 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
51825 + if (dwc_ep->proc_buf_num) {
51826 + dwc_ep->cur_pkt_addr =
51827 + dwc_ep->xfer_buff1;
51828 + dwc_ep->cur_pkt_dma_addr =
51829 + dwc_ep->dma_addr1;
51831 + dwc_ep->cur_pkt_addr =
51832 + dwc_ep->xfer_buff0;
51833 + dwc_ep->cur_pkt_dma_addr =
51834 + dwc_ep->dma_addr0;
51840 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
51841 + dev_global_regs->dsts);
51842 + dwc_ep->next_frame = dsts.b.soffn;
51844 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
51852 + depctl_data_t depctl = {.d32 = 0 };
51853 + dwc_ep_t *dwc_ep;
51854 + dwc_otg_dev_if_t *dev_if;
51856 + dev_if = GET_CORE_IF(pcd)->dev_if;
51858 + DWC_DEBUGPL(DBG_PCD,"Incomplete ISO IN \n");
51860 + for (i = 1; i <= dev_if->num_in_eps; ++i) {
51861 + dwc_ep = &pcd->in_ep[i-1].dwc_ep;
51863 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
51864 + if (depctl.b.epena && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51865 + if (drop_transfer(dwc_ep->frame_num, GET_CORE_IF(pcd)->frame_num,
51866 + dwc_ep->frm_overrun))
51869 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
51870 + depctl.b.snak = 1;
51871 + depctl.b.epdis = 1;
51872 + DWC_MODIFY_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32, depctl.d32);
51877 + /*intr_mask.b.incomplisoin = 1;
51878 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
51879 + intr_mask.d32, 0); */
51880 +#endif //DWC_EN_ISOC
51882 + /* Clear interrupt */
51884 + gintsts.b.incomplisoin = 1;
51885 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
51892 + * Incomplete ISO OUT Transfer Interrupt.
51894 + * This interrupt indicates that the core has dropped an ISO OUT
51895 + * packet. The following conditions can be the cause:
51896 + * - FIFO Full, the entire packet would not fit in the FIFO.
51898 + * - Corrupted Token
51899 + * The follow actions will be taken:
51900 + * -# Determine the EP
51901 + * -# Set incomplete flag in dwc_ep structure
51902 + * -# Read any data from the FIFO
51903 + * -# Disable EP. When "Endpoint Disabled" interrupt is received
51906 +int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd)
51909 + gintsts_data_t gintsts;
51911 +#ifdef DWC_EN_ISOC
51912 + dwc_otg_dev_if_t *dev_if;
51913 + deptsiz_data_t deptsiz = {.d32 = 0 };
51914 + depctl_data_t depctl = {.d32 = 0 };
51915 + dsts_data_t dsts = {.d32 = 0 };
51916 + dwc_ep_t *dwc_ep;
51919 + dev_if = GET_CORE_IF(pcd)->dev_if;
51921 + for (i = 1; i <= dev_if->num_out_eps; ++i) {
51922 + dwc_ep = &pcd->in_ep[i].dwc_ep;
51923 + if (pcd->out_ep[i].dwc_ep.active &&
51924 + pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
51926 + DWC_READ_REG32(&dev_if->out_ep_regs[i]->doeptsiz);
51928 + DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
51930 + if (depctl.b.epdis && deptsiz.d32) {
51931 + set_current_pkt_info(GET_CORE_IF(pcd),
51932 + &pcd->out_ep[i].dwc_ep);
51933 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
51934 + dwc_ep->cur_pkt = 0;
51935 + dwc_ep->proc_buf_num =
51936 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
51938 + if (dwc_ep->proc_buf_num) {
51939 + dwc_ep->cur_pkt_addr =
51940 + dwc_ep->xfer_buff1;
51941 + dwc_ep->cur_pkt_dma_addr =
51942 + dwc_ep->dma_addr1;
51944 + dwc_ep->cur_pkt_addr =
51945 + dwc_ep->xfer_buff0;
51946 + dwc_ep->cur_pkt_dma_addr =
51947 + dwc_ep->dma_addr0;
51953 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
51954 + dev_global_regs->dsts);
51955 + dwc_ep->next_frame = dsts.b.soffn;
51957 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
51964 + /** @todo implement ISR */
51965 + gintmsk_data_t intr_mask = {.d32 = 0 };
51966 + dwc_otg_core_if_t *core_if;
51967 + deptsiz_data_t deptsiz = {.d32 = 0 };
51968 + depctl_data_t depctl = {.d32 = 0 };
51969 + dctl_data_t dctl = {.d32 = 0 };
51970 + dwc_ep_t *dwc_ep = NULL;
51972 + core_if = GET_CORE_IF(pcd);
51974 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
51975 + dwc_ep = &pcd->out_ep[i].dwc_ep;
51977 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
51978 + if (depctl.b.epena && depctl.b.dpid == (core_if->frame_num & 0x1)) {
51979 + core_if->dev_if->isoc_ep = dwc_ep;
51981 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz);
51985 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
51986 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
51987 + intr_mask.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
51989 + if (!intr_mask.b.goutnakeff) {
51991 + intr_mask.b.goutnakeff = 1;
51992 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32);
51994 + if (!gintsts.b.goutnakeff) {
51995 + dctl.b.sgoutnak = 1;
51997 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
51999 + depctl.d32 = DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
52000 + if (depctl.b.epena) {
52001 + depctl.b.epdis = 1;
52002 + depctl.b.snak = 1;
52004 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl, depctl.d32);
52006 + intr_mask.d32 = 0;
52007 + intr_mask.b.incomplisoout = 1;
52009 +#endif /* DWC_EN_ISOC */
52011 + /* Clear interrupt */
52013 + gintsts.b.incomplisoout = 1;
52014 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52021 + * This function handles the Global IN NAK Effective interrupt.
52024 +int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd)
52026 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
52027 + depctl_data_t diepctl = {.d32 = 0 };
52028 + gintmsk_data_t intr_mask = {.d32 = 0 };
52029 + gintsts_data_t gintsts;
52030 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
52033 + DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
52035 + /* Disable all active IN EPs */
52036 + for (i = 0; i <= dev_if->num_in_eps; i++) {
52037 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52038 + if (!(diepctl.b.eptype & 1) && diepctl.b.epena) {
52039 + if (core_if->start_predict > 0)
52040 + core_if->start_predict++;
52041 + diepctl.b.epdis = 1;
52042 + diepctl.b.snak = 1;
52043 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, diepctl.d32);
52048 + /* Disable the Global IN NAK Effective Interrupt */
52049 + intr_mask.b.ginnakeff = 1;
52050 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52051 + intr_mask.d32, 0);
52053 + /* Clear interrupt */
52055 + gintsts.b.ginnakeff = 1;
52056 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52063 + * OUT NAK Effective.
52066 +int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd)
52068 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
52069 + gintmsk_data_t intr_mask = {.d32 = 0 };
52070 + gintsts_data_t gintsts;
52071 + depctl_data_t doepctl;
52074 + /* Disable the Global OUT NAK Effective Interrupt */
52075 + intr_mask.b.goutnakeff = 1;
52076 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52077 + intr_mask.d32, 0);
52079 + /* If DEV OUT NAK enabled*/
52080 + if (pcd->core_if->core_params->dev_out_nak) {
52081 + /* Run over all out endpoints to determine the ep number on
52082 + * which the timeout has happened
52084 + for (i = 0; i <= dev_if->num_out_eps; i++) {
52085 + if ( pcd->core_if->ep_xfer_info[i].state == 2 )
52088 + if (i > dev_if->num_out_eps) {
52089 + dctl_data_t dctl;
52091 + DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
52092 + dctl.b.cgoutnak = 1;
52093 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl,
52098 + /* Disable the endpoint */
52099 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
52100 + if (doepctl.b.epena) {
52101 + doepctl.b.epdis = 1;
52102 + doepctl.b.snak = 1;
52104 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
52107 + /* We come here from Incomplete ISO OUT handler */
52108 + if (dev_if->isoc_ep) {
52109 + dwc_ep_t *dwc_ep = (dwc_ep_t *)dev_if->isoc_ep;
52110 + uint32_t epnum = dwc_ep->num;
52111 + doepint_data_t doepint;
52113 + DWC_READ_REG32(&dev_if->out_ep_regs[dwc_ep->num]->doepint);
52114 + dev_if->isoc_ep = NULL;
52116 + DWC_READ_REG32(&dev_if->out_ep_regs[epnum]->doepctl);
52117 + DWC_PRINTF("Before disable DOEPCTL = %08x\n", doepctl.d32);
52118 + if (doepctl.b.epena) {
52119 + doepctl.b.epdis = 1;
52120 + doepctl.b.snak = 1;
52122 + DWC_WRITE_REG32(&dev_if->out_ep_regs[epnum]->doepctl,
52126 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
52127 + "Global OUT NAK Effective\n");
52130 + /* Clear interrupt */
52132 + gintsts.b.goutnakeff = 1;
52133 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52140 + * PCD interrupt handler.
52142 + * The PCD handles the device interrupts. Many conditions can cause a
52143 + * device interrupt. When an interrupt occurs, the device interrupt
52144 + * service routine determines the cause of the interrupt and
52145 + * dispatches handling to the appropriate function. These interrupt
52146 + * handling functions are described below.
52148 + * All interrupt registers are processed from LSB to MSB.
52151 +int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd)
52153 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
52155 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
52157 + gintsts_data_t gintr_status;
52158 + int32_t retval = 0;
52160 + /* Exit from ISR if core is hibernated */
52161 + if (core_if->hibernation_suspend == 1) {
52165 + DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x gintmsk=%08x\n",
52167 + DWC_READ_REG32(&global_regs->gintsts),
52168 + DWC_READ_REG32(&global_regs->gintmsk));
52171 + if (dwc_otg_is_device_mode(core_if)) {
52172 + DWC_SPINLOCK(pcd->lock);
52174 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x gintmsk=%08x\n",
52176 + DWC_READ_REG32(&global_regs->gintsts),
52177 + DWC_READ_REG32(&global_regs->gintmsk));
52180 + gintr_status.d32 = dwc_otg_read_core_intr(core_if);
52182 + DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
52183 + __func__, gintr_status.d32);
52185 + if (gintr_status.b.sofintr) {
52186 + retval |= dwc_otg_pcd_handle_sof_intr(pcd);
52188 + if (gintr_status.b.rxstsqlvl) {
52190 + dwc_otg_pcd_handle_rx_status_q_level_intr(pcd);
52192 + if (gintr_status.b.nptxfempty) {
52193 + retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd);
52195 + if (gintr_status.b.goutnakeff) {
52196 + retval |= dwc_otg_pcd_handle_out_nak_effective(pcd);
52198 + if (gintr_status.b.i2cintr) {
52199 + retval |= dwc_otg_pcd_handle_i2c_intr(pcd);
52201 + if (gintr_status.b.erlysuspend) {
52202 + retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd);
52204 + if (gintr_status.b.usbreset) {
52205 + retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd);
52207 + if (gintr_status.b.enumdone) {
52208 + retval |= dwc_otg_pcd_handle_enum_done_intr(pcd);
52210 + if (gintr_status.b.isooutdrop) {
52212 + dwc_otg_pcd_handle_isoc_out_packet_dropped_intr
52215 + if (gintr_status.b.eopframe) {
52217 + dwc_otg_pcd_handle_end_periodic_frame_intr(pcd);
52219 + if (gintr_status.b.inepint) {
52220 + if (!core_if->multiproc_int_enable) {
52221 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
52224 + if (gintr_status.b.outepintr) {
52225 + if (!core_if->multiproc_int_enable) {
52226 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
52229 + if (gintr_status.b.epmismatch) {
52230 + retval |= dwc_otg_pcd_handle_ep_mismatch_intr(pcd);
52232 + if (gintr_status.b.fetsusp) {
52233 + retval |= dwc_otg_pcd_handle_ep_fetsusp_intr(pcd);
52235 + if (gintr_status.b.ginnakeff) {
52236 + retval |= dwc_otg_pcd_handle_in_nak_effective(pcd);
52238 + if (gintr_status.b.incomplisoin) {
52240 + dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd);
52242 + if (gintr_status.b.incomplisoout) {
52244 + dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd);
52247 + /* In MPI mode Device Endpoints interrupts are asserted
52248 + * without setting outepintr and inepint bits set, so these
52249 + * Interrupt handlers are called without checking these bit-fields
52251 + if (core_if->multiproc_int_enable) {
52252 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
52253 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
52256 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
52257 + DWC_READ_REG32(&global_regs->gintsts));
52259 + DWC_SPINUNLOCK(pcd->lock);
52264 +#endif /* DWC_HOST_ONLY */
52266 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
52268 + /* ==========================================================================
52269 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
52270 + * $Revision: #21 $
52271 + * $Date: 2012/08/10 $
52272 + * $Change: 2047372 $
52274 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
52275 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
52276 + * otherwise expressly agreed to in writing between Synopsys and you.
52278 + * The Software IS NOT an item of Licensed Software or Licensed Product under
52279 + * any End User Software License Agreement or Agreement for Licensed Product
52280 + * with Synopsys or any supplement thereto. You are permitted to use and
52281 + * redistribute this Software in source and binary forms, with or without
52282 + * modification, provided that redistributions of source code must retain this
52283 + * notice. You may not view, use, disclose, copy or distribute this file or
52284 + * any information contained herein except pursuant to this license grant from
52285 + * Synopsys. If you do not agree with this notice, including the disclaimer
52286 + * below, then you are not authorized to use the Software.
52288 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
52289 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52290 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52291 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
52292 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
52293 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
52294 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
52295 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52296 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52297 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
52299 + * ========================================================================== */
52300 +#ifndef DWC_HOST_ONLY
52303 + * This file implements the Peripheral Controller Driver.
52305 + * The Peripheral Controller Driver (PCD) is responsible for
52306 + * translating requests from the Function Driver into the appropriate
52307 + * actions on the DWC_otg controller. It isolates the Function Driver
52308 + * from the specifics of the controller by providing an API to the
52309 + * Function Driver.
52311 + * The Peripheral Controller Driver for Linux will implement the
52312 + * Gadget API, so that the existing Gadget drivers can be used.
52313 + * (Gadget Driver is the Linux terminology for a Function Driver.)
52315 + * The Linux Gadget API is defined in the header file
52316 + * <code><linux/usb_gadget.h></code>. The USB EP operations API is
52317 + * defined in the structure <code>usb_ep_ops</code> and the USB
52318 + * Controller API is defined in the structure
52319 + * <code>usb_gadget_ops</code>.
52323 +#include "dwc_otg_os_dep.h"
52324 +#include "dwc_otg_pcd_if.h"
52325 +#include "dwc_otg_pcd.h"
52326 +#include "dwc_otg_driver.h"
52327 +#include "dwc_otg_dbg.h"
52329 +static struct gadget_wrapper {
52330 + dwc_otg_pcd_t *pcd;
52332 + struct usb_gadget gadget;
52333 + struct usb_gadget_driver *driver;
52335 + struct usb_ep ep0;
52336 + struct usb_ep in_ep[16];
52337 + struct usb_ep out_ep[16];
52339 +} *gadget_wrapper;
52341 +/* Display the contents of the buffer */
52342 +extern void dump_msg(const u8 * buf, unsigned int length);
52344 + * Get the dwc_otg_pcd_ep_t* from usb_ep* pointer - NULL in case
52345 + * if the endpoint is not found
52347 +static struct dwc_otg_pcd_ep *ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
52350 + if (pcd->ep0.priv == handle) {
52351 + return &pcd->ep0;
52354 + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
52355 + if (pcd->in_ep[i].priv == handle)
52356 + return &pcd->in_ep[i];
52357 + if (pcd->out_ep[i].priv == handle)
52358 + return &pcd->out_ep[i];
52364 +/* USB Endpoint Operations */
52366 + * The following sections briefly describe the behavior of the Gadget
52367 + * API endpoint operations implemented in the DWC_otg driver
52368 + * software. Detailed descriptions of the generic behavior of each of
52369 + * these functions can be found in the Linux header file
52370 + * include/linux/usb_gadget.h.
52372 + * The Gadget API provides wrapper functions for each of the function
52373 + * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
52374 + * function, which then calls the underlying PCD function. The
52375 + * following sections are named according to the wrapper
52376 + * functions. Within each section, the corresponding DWC_otg PCD
52377 + * function name is specified.
52382 + * This function is called by the Gadget Driver for each EP to be
52383 + * configured for the current configuration (SET_CONFIGURATION).
52385 + * This function initializes the dwc_otg_ep_t data structure, and then
52386 + * calls dwc_otg_ep_activate.
52388 +static int ep_enable(struct usb_ep *usb_ep,
52389 + const struct usb_endpoint_descriptor *ep_desc)
52393 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
52395 + if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
52396 + DWC_WARN("%s, bad ep or descriptor\n", __func__);
52399 + if (usb_ep == &gadget_wrapper->ep0) {
52400 + DWC_WARN("%s, bad ep(0)\n", __func__);
52404 + /* Check FIFO size? */
52405 + if (!ep_desc->wMaxPacketSize) {
52406 + DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
52410 + if (!gadget_wrapper->driver ||
52411 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52412 + DWC_WARN("%s, bogus device state\n", __func__);
52413 + return -ESHUTDOWN;
52416 + /* Delete after check - MAS */
52418 + nat = (uint32_t) ep_desc->wMaxPacketSize;
52419 + printk(KERN_ALERT "%s: nat (before) =%d\n", __func__, nat);
52420 + nat = (nat >> 11) & 0x03;
52421 + printk(KERN_ALERT "%s: nat (after) =%d\n", __func__, nat);
52423 + retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
52424 + (const uint8_t *)ep_desc,
52427 + DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
52431 + usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
52437 + * This function is called when an EP is disabled due to disconnect or
52438 + * change in configuration. Any pending requests will terminate with a
52439 + * status of -ESHUTDOWN.
52441 + * This function modifies the dwc_otg_ep_t data structure for this EP,
52442 + * and then calls dwc_otg_ep_deactivate.
52444 +static int ep_disable(struct usb_ep *usb_ep)
52448 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
52450 + DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
52451 + usb_ep ? usb_ep->name : NULL);
52455 + retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
52457 + retval = -EINVAL;
52464 + * This function allocates a request object to use with the specified
52467 + * @param ep The endpoint to be used with with the request
52468 + * @param gfp_flags the GFP_* flags to use.
52470 +static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
52473 + struct usb_request *usb_req;
52475 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
52477 + DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
52480 + usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
52481 + if (0 == usb_req) {
52482 + DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
52485 + memset(usb_req, 0, sizeof(*usb_req));
52486 + usb_req->dma = DWC_DMA_ADDR_INVALID;
52492 + * This function frees a request object.
52494 + * @param ep The endpoint associated with the request
52495 + * @param req The request being freed
52497 +static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
52499 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
52501 + if (0 == ep || 0 == req) {
52502 + DWC_WARN("%s() %s\n", __func__,
52503 + "Invalid ep or req argument!\n");
52510 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52512 + * This function allocates an I/O buffer to be used for a transfer
52513 + * to/from the specified endpoint.
52515 + * @param usb_ep The endpoint to be used with with the request
52516 + * @param bytes The desired number of bytes for the buffer
52517 + * @param dma Pointer to the buffer's DMA address; must be valid
52518 + * @param gfp_flags the GFP_* flags to use.
52519 + * @return address of a new buffer or null is buffer could not be allocated.
52521 +static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
52522 + dma_addr_t * dma, gfp_t gfp_flags)
52525 + dwc_otg_pcd_t *pcd = 0;
52527 + pcd = gadget_wrapper->pcd;
52529 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
52532 + /* Check dword alignment */
52533 + if ((bytes & 0x3UL) != 0) {
52534 + DWC_WARN("%s() Buffer size is not a multiple of"
52535 + "DWORD size (%d)", __func__, bytes);
52538 + buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
52540 + /* Check dword alignment */
52541 + if (((int)buf & 0x3UL) != 0) {
52542 + DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
52550 + * This function frees an I/O buffer that was allocated by alloc_buffer.
52552 + * @param usb_ep the endpoint associated with the buffer
52553 + * @param buf address of the buffer
52554 + * @param dma The buffer's DMA address
52555 + * @param bytes The number of bytes of the buffer
52557 +static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
52558 + dma_addr_t dma, unsigned bytes)
52560 + dwc_otg_pcd_t *pcd = 0;
52562 + pcd = gadget_wrapper->pcd;
52564 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
52566 + dma_free_coherent(NULL, bytes, buf, dma);
52571 + * This function is used to submit an I/O Request to an EP.
52573 + * - When the request completes the request's completion callback
52574 + * is called to return the request to the driver.
52575 + * - An EP, except control EPs, may have multiple requests
52577 + * - Once submitted the request cannot be examined or modified.
52578 + * - Each request is turned into one or more packets.
52579 + * - A BULK EP can queue any amount of data; the transfer is
52581 + * - Zero length Packets are specified with the request 'zero'
52584 +static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
52587 + dwc_otg_pcd_t *pcd;
52588 + struct dwc_otg_pcd_ep *ep = NULL;
52589 + int retval = 0, is_isoc_ep = 0;
52590 + dma_addr_t dma_addr = DWC_DMA_ADDR_INVALID;
52592 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
52593 + __func__, usb_ep, usb_req, gfp_flags);
52595 + if (!usb_req || !usb_req->complete || !usb_req->buf) {
52596 + DWC_WARN("bad params\n");
52601 + DWC_WARN("bad ep\n");
52605 + pcd = gadget_wrapper->pcd;
52606 + if (!gadget_wrapper->driver ||
52607 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52608 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
52609 + gadget_wrapper->gadget.speed);
52610 + DWC_WARN("bogus device state\n");
52611 + return -ESHUTDOWN;
52614 + DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
52615 + usb_ep->name, usb_req, usb_req->length, usb_req->buf);
52617 + usb_req->status = -EINPROGRESS;
52618 + usb_req->actual = 0;
52620 + ep = ep_from_handle(pcd, usb_ep);
52624 + is_isoc_ep = (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ? 1 : 0;
52625 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52626 + dma_addr = usb_req->dma;
52628 + if (GET_CORE_IF(pcd)->dma_enable) {
52629 + dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
52630 + struct device *dev = NULL;
52632 + if (otg_dev != NULL)
52633 + dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
52635 + if (usb_req->length != 0 &&
52636 + usb_req->dma == DWC_DMA_ADDR_INVALID) {
52637 + dma_addr = dma_map_single(dev, usb_req->buf,
52639 + ep->dwc_ep.is_in ?
52641 + DMA_FROM_DEVICE);
52646 +#ifdef DWC_UTE_PER_IO
52647 + if (is_isoc_ep == 1) {
52648 + retval = dwc_otg_pcd_xiso_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
52649 + usb_req->length, usb_req->zero, usb_req,
52650 + gfp_flags == GFP_ATOMIC ? 1 : 0, &usb_req->ext_req);
52657 + retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
52658 + usb_req->length, usb_req->zero, usb_req,
52659 + gfp_flags == GFP_ATOMIC ? 1 : 0);
52668 + * This function cancels an I/O request from an EP.
52670 +static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
52672 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
52674 + if (!usb_ep || !usb_req) {
52675 + DWC_WARN("bad argument\n");
52678 + if (!gadget_wrapper->driver ||
52679 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52680 + DWC_WARN("bogus device state\n");
52681 + return -ESHUTDOWN;
52683 + if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
52691 + * usb_ep_set_halt stalls an endpoint.
52693 + * usb_ep_clear_halt clears an endpoint halt and resets its data
52696 + * Both of these functions are implemented with the same underlying
52697 + * function. The behavior depends on the value argument.
52699 + * @param[in] usb_ep the Endpoint to halt or clear halt.
52700 + * @param[in] value
52701 + * - 0 means clear_halt.
52702 + * - 1 means set_halt,
52703 + * - 2 means clear stall lock flag.
52704 + * - 3 means set stall lock flag.
52706 +static int ep_halt(struct usb_ep *usb_ep, int value)
52710 + DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
52713 + DWC_WARN("bad ep\n");
52717 + retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
52718 + if (retval == -DWC_E_AGAIN) {
52720 + } else if (retval) {
52721 + retval = -EINVAL;
52727 +//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
52730 + * ep_wedge: sets the halt feature and ignores clear requests
52732 + * @usb_ep: the endpoint being wedged
52734 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
52735 + * requests. If the gadget driver clears the halt status, it will
52736 + * automatically unwedge the endpoint.
52738 + * Returns zero on success, else negative errno. *
52739 + * Check usb_ep_set_wedge() at "usb_gadget.h" for details
52741 +static int ep_wedge(struct usb_ep *usb_ep)
52745 + DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name);
52748 + DWC_WARN("bad ep\n");
52752 + retval = dwc_otg_pcd_ep_wedge(gadget_wrapper->pcd, usb_ep);
52753 + if (retval == -DWC_E_AGAIN) {
52754 + retval = -EAGAIN;
52755 + } else if (retval) {
52756 + retval = -EINVAL;
52763 +#ifdef DWC_EN_ISOC
52765 + * This function is used to submit an ISOC Transfer Request to an EP.
52767 + * - Every time a sync period completes the request's completion callback
52768 + * is called to provide data to the gadget driver.
52769 + * - Once submitted the request cannot be modified.
52770 + * - Each request is turned into periodic data packets untill ISO
52771 + * Transfer is stopped..
52773 +static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
52778 + if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
52779 + DWC_WARN("bad params\n");
52784 + DWC_PRINTF("bad params\n");
52788 + req->status = -EINPROGRESS;
52791 + dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
52792 + req->buf1, req->dma0, req->dma1,
52793 + req->sync_frame, req->data_pattern_frame,
52794 + req->data_per_frame,
52796 + flags & USB_REQ_ISO_ASAP ? -1 :
52797 + req->start_frame, req->buf_proc_intrvl,
52798 + req, gfp_flags == GFP_ATOMIC ? 1 : 0);
52808 + * This function stops ISO EP Periodic Data Transfer.
52810 +static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
52814 + DWC_WARN("bad ep\n");
52817 + if (!gadget_wrapper->driver ||
52818 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52819 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
52820 + gadget_wrapper->gadget.speed);
52821 + DWC_WARN("bogus device state\n");
52824 + dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
52826 + retval = -EINVAL;
52832 +static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
52833 + int packets, gfp_t gfp_flags)
52835 + struct usb_iso_request *pReq = NULL;
52836 + uint32_t req_size;
52838 + req_size = sizeof(struct usb_iso_request);
52840 + (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
52842 + pReq = kmalloc(req_size, gfp_flags);
52844 + DWC_WARN("Can't allocate Iso Request\n");
52847 + pReq->iso_packet_desc0 = (void *)(pReq + 1);
52849 + pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
52854 +static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
52859 +static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
52861 + .enable = ep_enable,
52862 + .disable = ep_disable,
52864 + .alloc_request = dwc_otg_pcd_alloc_request,
52865 + .free_request = dwc_otg_pcd_free_request,
52867 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52868 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
52869 + .free_buffer = dwc_otg_pcd_free_buffer,
52872 + .queue = ep_queue,
52873 + .dequeue = ep_dequeue,
52875 + .set_halt = ep_halt,
52876 + .fifo_status = 0,
52879 + .iso_ep_start = iso_ep_start,
52880 + .iso_ep_stop = iso_ep_stop,
52881 + .alloc_iso_request = alloc_iso_request,
52882 + .free_iso_request = free_iso_request,
52887 + int (*enable) (struct usb_ep *ep,
52888 + const struct usb_endpoint_descriptor *desc);
52889 + int (*disable) (struct usb_ep *ep);
52891 + struct usb_request *(*alloc_request) (struct usb_ep *ep,
52892 + gfp_t gfp_flags);
52893 + void (*free_request) (struct usb_ep *ep, struct usb_request *req);
52895 + int (*queue) (struct usb_ep *ep, struct usb_request *req,
52896 + gfp_t gfp_flags);
52897 + int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
52899 + int (*set_halt) (struct usb_ep *ep, int value);
52900 + int (*set_wedge) (struct usb_ep *ep);
52902 + int (*fifo_status) (struct usb_ep *ep);
52903 + void (*fifo_flush) (struct usb_ep *ep);
52904 +static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
52905 + .enable = ep_enable,
52906 + .disable = ep_disable,
52908 + .alloc_request = dwc_otg_pcd_alloc_request,
52909 + .free_request = dwc_otg_pcd_free_request,
52911 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52912 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
52913 + .free_buffer = dwc_otg_pcd_free_buffer,
52915 + /* .set_wedge = ep_wedge, */
52916 + .set_wedge = NULL, /* uses set_halt instead */
52919 + .queue = ep_queue,
52920 + .dequeue = ep_dequeue,
52922 + .set_halt = ep_halt,
52923 + .fifo_status = 0,
52928 +#endif /* _EN_ISOC_ */
52929 +/* Gadget Operations */
52931 + * The following gadget operations will be implemented in the DWC_otg
52932 + * PCD. Functions in the API that are not described below are not
52935 + * The Gadget API provides wrapper functions for each of the function
52936 + * pointers defined in usb_gadget_ops. The Gadget Driver calls the
52937 + * wrapper function, which then calls the underlying PCD function. The
52938 + * following sections are named according to the wrapper functions
52939 + * (except for ioctl, which doesn't have a wrapper function). Within
52940 + * each section, the corresponding DWC_otg PCD function name is
52946 + *Gets the USB Frame number of the last SOF.
52948 +static int get_frame_number(struct usb_gadget *gadget)
52950 + struct gadget_wrapper *d;
52952 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
52954 + if (gadget == 0) {
52958 + d = container_of(gadget, struct gadget_wrapper, gadget);
52959 + return dwc_otg_pcd_get_frame_number(d->pcd);
52962 +#ifdef CONFIG_USB_DWC_OTG_LPM
52963 +static int test_lpm_enabled(struct usb_gadget *gadget)
52965 + struct gadget_wrapper *d;
52967 + d = container_of(gadget, struct gadget_wrapper, gadget);
52969 + return dwc_otg_pcd_is_lpm_enabled(d->pcd);
52974 + * Initiates Session Request Protocol (SRP) to wakeup the host if no
52975 + * session is in progress. If a session is already in progress, but
52976 + * the device is suspended, remote wakeup signaling is started.
52979 +static int wakeup(struct usb_gadget *gadget)
52981 + struct gadget_wrapper *d;
52983 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
52985 + if (gadget == 0) {
52988 + d = container_of(gadget, struct gadget_wrapper, gadget);
52990 + dwc_otg_pcd_wakeup(d->pcd);
52994 +static const struct usb_gadget_ops dwc_otg_pcd_ops = {
52995 + .get_frame = get_frame_number,
52996 + .wakeup = wakeup,
52997 +#ifdef CONFIG_USB_DWC_OTG_LPM
52998 + .lpm_support = test_lpm_enabled,
53000 + // current versions must always be self-powered
53003 +static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
53005 + int retval = -DWC_E_NOT_SUPPORTED;
53006 + if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
53007 + retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
53008 + (struct usb_ctrlrequest
53012 + if (retval == -ENOTSUPP) {
53013 + retval = -DWC_E_NOT_SUPPORTED;
53014 + } else if (retval < 0) {
53015 + retval = -DWC_E_INVALID;
53021 +#ifdef DWC_EN_ISOC
53022 +static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53023 + void *req_handle, int proc_buf_num)
53025 + int i, packet_count;
53026 + struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
53027 + struct usb_iso_request *iso_req = req_handle;
53029 + if (proc_buf_num) {
53030 + iso_packet = iso_req->iso_packet_desc1;
53032 + iso_packet = iso_req->iso_packet_desc0;
53035 + dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
53036 + for (i = 0; i < packet_count; ++i) {
53040 + dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
53041 + i, &status, &actual, &offset);
53042 + switch (status) {
53043 + case -DWC_E_NO_DATA:
53044 + status = -ENODATA;
53048 + DWC_PRINTF("unknown status in isoc packet\n");
53052 + iso_packet[i].status = status;
53053 + iso_packet[i].offset = offset;
53054 + iso_packet[i].actual_length = actual;
53057 + iso_req->status = 0;
53058 + iso_req->process_buffer(ep_handle, iso_req);
53062 +#endif /* DWC_EN_ISOC */
53064 +#ifdef DWC_UTE_PER_IO
53066 + * Copy the contents of the extended request to the Linux usb_request's
53067 + * extended part and call the gadget's completion.
53069 + * @param pcd Pointer to the pcd structure
53070 + * @param ep_handle Void pointer to the usb_ep structure
53071 + * @param req_handle Void pointer to the usb_request structure
53072 + * @param status Request status returned from the portable logic
53073 + * @param ereq_port Void pointer to the extended request structure
53074 + * created in the the portable part that contains the
53075 + * results of the processed iso packets.
53077 +static int _xisoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53078 + void *req_handle, int32_t status, void *ereq_port)
53080 + struct dwc_ute_iso_req_ext *ereqorg = NULL;
53081 + struct dwc_iso_xreq_port *ereqport = NULL;
53082 + struct dwc_ute_iso_packet_descriptor *desc_org = NULL;
53084 + struct usb_request *req;
53085 + //struct dwc_ute_iso_packet_descriptor *
53086 + //int status = 0;
53088 + req = (struct usb_request *)req_handle;
53089 + ereqorg = &req->ext_req;
53090 + ereqport = (struct dwc_iso_xreq_port *)ereq_port;
53091 + desc_org = ereqorg->per_io_frame_descs;
53093 + if (req && req->complete) {
53094 + /* Copy the request data from the portable logic to our request */
53095 + for (i = 0; i < ereqport->pio_pkt_count; i++) {
53096 + desc_org[i].actual_length =
53097 + ereqport->per_io_frame_descs[i].actual_length;
53098 + desc_org[i].status =
53099 + ereqport->per_io_frame_descs[i].status;
53102 + switch (status) {
53103 + case -DWC_E_SHUTDOWN:
53104 + req->status = -ESHUTDOWN;
53106 + case -DWC_E_RESTART:
53107 + req->status = -ECONNRESET;
53109 + case -DWC_E_INVALID:
53110 + req->status = -EINVAL;
53112 + case -DWC_E_TIMEOUT:
53113 + req->status = -ETIMEDOUT;
53116 + req->status = status;
53119 + /* And call the gadget's completion */
53120 + req->complete(ep_handle, req);
53125 +#endif /* DWC_UTE_PER_IO */
53127 +static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53128 + void *req_handle, int32_t status, uint32_t actual)
53130 + struct usb_request *req = (struct usb_request *)req_handle;
53131 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
53132 + struct dwc_otg_pcd_ep *ep = NULL;
53135 + if (req && req->complete) {
53136 + switch (status) {
53137 + case -DWC_E_SHUTDOWN:
53138 + req->status = -ESHUTDOWN;
53140 + case -DWC_E_RESTART:
53141 + req->status = -ECONNRESET;
53143 + case -DWC_E_INVALID:
53144 + req->status = -EINVAL;
53146 + case -DWC_E_TIMEOUT:
53147 + req->status = -ETIMEDOUT;
53150 + req->status = status;
53154 + req->actual = actual;
53155 + DWC_SPINUNLOCK(pcd->lock);
53156 + req->complete(ep_handle, req);
53157 + DWC_SPINLOCK(pcd->lock);
53159 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
53160 + ep = ep_from_handle(pcd, ep_handle);
53161 + if (GET_CORE_IF(pcd)->dma_enable) {
53162 + if (req->length != 0) {
53163 + dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
53164 + struct device *dev = NULL;
53166 + if (otg_dev != NULL)
53167 + dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
53169 + dma_unmap_single(dev, req->dma, req->length,
53170 + ep->dwc_ep.is_in ?
53171 + DMA_TO_DEVICE: DMA_FROM_DEVICE);
53179 +static int _connect(dwc_otg_pcd_t * pcd, int speed)
53181 + gadget_wrapper->gadget.speed = speed;
53185 +static int _disconnect(dwc_otg_pcd_t * pcd)
53187 + if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
53188 + gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
53193 +static int _resume(dwc_otg_pcd_t * pcd)
53195 + if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
53196 + gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
53202 +static int _suspend(dwc_otg_pcd_t * pcd)
53204 + if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
53205 + gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
53211 + * This function updates the otg values in the gadget structure.
53213 +static int _hnp_changed(dwc_otg_pcd_t * pcd)
53216 + if (!gadget_wrapper->gadget.is_otg)
53219 + gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
53220 + gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
53221 + gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
53225 +static int _reset(dwc_otg_pcd_t * pcd)
53230 +#ifdef DWC_UTE_CFI
53231 +static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
53233 + int retval = -DWC_E_INVALID;
53234 + if (gadget_wrapper->driver->cfi_feature_setup) {
53236 + gadget_wrapper->driver->
53237 + cfi_feature_setup(&gadget_wrapper->gadget,
53238 + (struct cfi_usb_ctrlrequest *)cfi_req);
53245 +static const struct dwc_otg_pcd_function_ops fops = {
53246 + .complete = _complete,
53247 +#ifdef DWC_EN_ISOC
53248 + .isoc_complete = _isoc_complete,
53251 + .disconnect = _disconnect,
53252 + .connect = _connect,
53253 + .resume = _resume,
53254 + .suspend = _suspend,
53255 + .hnp_changed = _hnp_changed,
53257 +#ifdef DWC_UTE_CFI
53258 + .cfi_setup = _cfi_setup,
53260 +#ifdef DWC_UTE_PER_IO
53261 + .xisoc_complete = _xisoc_complete,
53266 + * This function is the top level PCD interrupt handler.
53268 +static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
53270 + dwc_otg_pcd_t *pcd = dev;
53271 + int32_t retval = IRQ_NONE;
53273 + retval = dwc_otg_pcd_handle_intr(pcd);
53274 + if (retval != 0) {
53275 + S3C2410X_CLEAR_EINTPEND();
53277 + return IRQ_RETVAL(retval);
53281 + * This function initialized the usb_ep structures to there default
53284 + * @param d Pointer on gadget_wrapper.
53286 +void gadget_add_eps(struct gadget_wrapper *d)
53288 + static const char *names[] = {
53324 + struct usb_ep *ep;
53325 + int8_t dev_endpoints;
53327 + DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
53329 + INIT_LIST_HEAD(&d->gadget.ep_list);
53330 + d->gadget.ep0 = &d->ep0;
53331 + d->gadget.speed = USB_SPEED_UNKNOWN;
53333 + INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
53336 + * Initialize the EP0 structure.
53340 + /* Init the usb_ep structure. */
53341 + ep->name = names[0];
53342 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53345 + * @todo NGS: What should the max packet size be set to
53346 + * here? Before EP type is set?
53348 + ep->maxpacket = MAX_PACKET_SIZE;
53349 + dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
53351 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53354 + * Initialize the EP structures.
53356 + dev_endpoints = d->pcd->core_if->dev_if->num_in_eps;
53358 + for (i = 0; i < dev_endpoints; i++) {
53359 + ep = &d->in_ep[i];
53361 + /* Init the usb_ep structure. */
53362 + ep->name = names[d->pcd->in_ep[i].dwc_ep.num];
53363 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53366 + * @todo NGS: What should the max packet size be set to
53367 + * here? Before EP type is set?
53369 + ep->maxpacket = MAX_PACKET_SIZE;
53370 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53373 + dev_endpoints = d->pcd->core_if->dev_if->num_out_eps;
53375 + for (i = 0; i < dev_endpoints; i++) {
53376 + ep = &d->out_ep[i];
53378 + /* Init the usb_ep structure. */
53379 + ep->name = names[15 + d->pcd->out_ep[i].dwc_ep.num];
53380 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53383 + * @todo NGS: What should the max packet size be set to
53384 + * here? Before EP type is set?
53386 + ep->maxpacket = MAX_PACKET_SIZE;
53388 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53391 + /* remove ep0 from the list. There is a ep0 pointer. */
53392 + list_del_init(&d->ep0.ep_list);
53394 + d->ep0.maxpacket = MAX_EP0_SIZE;
53398 + * This function releases the Gadget device.
53399 + * required by device_unregister().
53401 + * @todo Should this do something? Should it free the PCD?
53403 +static void dwc_otg_pcd_gadget_release(struct device *dev)
53405 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
53408 +static struct gadget_wrapper *alloc_wrapper(dwc_bus_dev_t *_dev)
53410 + static char pcd_name[] = "dwc_otg_pcd";
53411 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53412 + struct gadget_wrapper *d;
53415 + d = DWC_ALLOC(sizeof(*d));
53420 + memset(d, 0, sizeof(*d));
53422 + d->gadget.name = pcd_name;
53423 + d->pcd = otg_dev->pcd;
53425 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
53426 + strcpy(d->gadget.dev.bus_id, "gadget");
53428 + dev_set_name(&d->gadget.dev, "%s", "gadget");
53431 + d->gadget.dev.parent = &_dev->dev;
53432 + d->gadget.dev.release = dwc_otg_pcd_gadget_release;
53433 + d->gadget.ops = &dwc_otg_pcd_ops;
53434 + d->gadget.max_speed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd) ? USB_SPEED_HIGH:USB_SPEED_FULL;
53435 + d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
53438 + /* Register the gadget device */
53439 + retval = device_register(&d->gadget.dev);
53440 + if (retval != 0) {
53441 + DWC_ERROR("device_register failed\n");
53449 +static void free_wrapper(struct gadget_wrapper *d)
53452 + /* should have been done already by driver model core */
53453 + DWC_WARN("driver '%s' is still registered\n",
53454 + d->driver->driver.name);
53455 + usb_gadget_unregister_driver(d->driver);
53458 + device_unregister(&d->gadget.dev);
53463 + * This function initialized the PCD portion of the driver.
53466 +int pcd_init(dwc_bus_dev_t *_dev)
53468 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53471 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev=%p\n", __func__, _dev, otg_dev);
53473 + otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
53475 + if (!otg_dev->pcd) {
53476 + DWC_ERROR("dwc_otg_pcd_init failed\n");
53480 + otg_dev->pcd->otg_dev = otg_dev;
53481 + gadget_wrapper = alloc_wrapper(_dev);
53484 + * Initialize EP structures
53486 + gadget_add_eps(gadget_wrapper);
53488 + * Setup interupt handler
53490 +#ifdef PLATFORM_INTERFACE
53491 + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
53492 + platform_get_irq(_dev, 0));
53493 + retval = request_irq(platform_get_irq(_dev, 0), dwc_otg_pcd_irq,
53494 + IRQF_SHARED, gadget_wrapper->gadget.name,
53496 + if (retval != 0) {
53497 + DWC_ERROR("request of irq%d failed\n",
53498 + platform_get_irq(_dev, 0));
53499 + free_wrapper(gadget_wrapper);
53503 + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
53505 + retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
53506 + IRQF_SHARED | IRQF_DISABLED,
53507 + gadget_wrapper->gadget.name, otg_dev->pcd);
53508 + if (retval != 0) {
53509 + DWC_ERROR("request of irq%d failed\n", _dev->irq);
53510 + free_wrapper(gadget_wrapper);
53515 + dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
53521 + * Cleanup the PCD.
53523 +void pcd_remove(dwc_bus_dev_t *_dev)
53525 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53526 + dwc_otg_pcd_t *pcd = otg_dev->pcd;
53528 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
53533 +#ifdef PLATFORM_INTERFACE
53534 + free_irq(platform_get_irq(_dev, 0), pcd);
53536 + free_irq(_dev->irq, pcd);
53538 + dwc_otg_pcd_remove(otg_dev->pcd);
53539 + free_wrapper(gadget_wrapper);
53540 + otg_dev->pcd = 0;
53544 + * This function registers a gadget driver with the PCD.
53546 + * When a driver is successfully registered, it will receive control
53547 + * requests including set_configuration(), which enables non-control
53548 + * requests. then usb traffic follows until a disconnect is reported.
53549 + * then a host may connect again, or the driver might get unbound.
53551 + * @param driver The driver being registered
53552 + * @param bind The bind function of gadget driver
53555 +int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
53559 + DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
53560 + driver->driver.name);
53562 + if (!driver || driver->max_speed == USB_SPEED_UNKNOWN ||
53564 + !driver->unbind || !driver->disconnect || !driver->setup) {
53565 + DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
53568 + if (gadget_wrapper == 0) {
53569 + DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
53572 + if (gadget_wrapper->driver != 0) {
53573 + DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
53577 + /* hook up the driver */
53578 + gadget_wrapper->driver = driver;
53579 + gadget_wrapper->gadget.dev.driver = &driver->driver;
53581 + DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
53582 + retval = driver->bind(&gadget_wrapper->gadget, gadget_wrapper->driver);
53584 + DWC_ERROR("bind to driver %s --> error %d\n",
53585 + driver->driver.name, retval);
53586 + gadget_wrapper->driver = 0;
53587 + gadget_wrapper->gadget.dev.driver = 0;
53590 + DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
53591 + driver->driver.name);
53594 +EXPORT_SYMBOL(usb_gadget_probe_driver);
53597 + * This function unregisters a gadget driver
53599 + * @param driver The driver being unregistered
53601 +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
53603 + //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
53605 + if (gadget_wrapper == 0) {
53606 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
53610 + if (driver == 0 || driver != gadget_wrapper->driver) {
53611 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
53616 + driver->unbind(&gadget_wrapper->gadget);
53617 + gadget_wrapper->driver = 0;
53619 + DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
53623 +EXPORT_SYMBOL(usb_gadget_unregister_driver);
53625 +#endif /* DWC_HOST_ONLY */
53627 +++ b/drivers/usb/host/dwc_otg/dwc_otg_regs.h
53629 +/* ==========================================================================
53630 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $
53631 + * $Revision: #98 $
53632 + * $Date: 2012/08/10 $
53633 + * $Change: 2047372 $
53635 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
53636 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
53637 + * otherwise expressly agreed to in writing between Synopsys and you.
53639 + * The Software IS NOT an item of Licensed Software or Licensed Product under
53640 + * any End User Software License Agreement or Agreement for Licensed Product
53641 + * with Synopsys or any supplement thereto. You are permitted to use and
53642 + * redistribute this Software in source and binary forms, with or without
53643 + * modification, provided that redistributions of source code must retain this
53644 + * notice. You may not view, use, disclose, copy or distribute this file or
53645 + * any information contained herein except pursuant to this license grant from
53646 + * Synopsys. If you do not agree with this notice, including the disclaimer
53647 + * below, then you are not authorized to use the Software.
53649 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
53650 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53651 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53652 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
53653 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53654 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53655 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
53656 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53657 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53658 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
53660 + * ========================================================================== */
53662 +#ifndef __DWC_OTG_REGS_H__
53663 +#define __DWC_OTG_REGS_H__
53665 +#include "dwc_otg_core_if.h"
53670 + * This file contains the data structures for accessing the DWC_otg core registers.
53672 + * The application interfaces with the HS OTG core by reading from and
53673 + * writing to the Control and Status Register (CSR) space through the
53674 + * AHB Slave interface. These registers are 32 bits wide, and the
53675 + * addresses are 32-bit-block aligned.
53676 + * CSRs are classified as follows:
53677 + * - Core Global Registers
53678 + * - Device Mode Registers
53679 + * - Device Global Registers
53680 + * - Device Endpoint Specific Registers
53681 + * - Host Mode Registers
53682 + * - Host Global Registers
53683 + * - Host Port CSRs
53684 + * - Host Channel Specific Registers
53686 + * Only the Core Global registers can be accessed in both Device and
53687 + * Host modes. When the HS OTG core is operating in one mode, either
53688 + * Device or Host, the application must not access registers from the
53689 + * other mode. When the core switches from one mode to another, the
53690 + * registers in the new mode of operation must be reprogrammed as they
53691 + * would be after a power-on reset.
53694 +/****************************************************************************/
53695 +/** DWC_otg Core registers .
53696 + * The dwc_otg_core_global_regs structure defines the size
53697 + * and relative field offsets for the Core Global registers.
53699 +typedef struct dwc_otg_core_global_regs {
53700 + /** OTG Control and Status Register. <i>Offset: 000h</i> */
53701 + volatile uint32_t gotgctl;
53702 + /** OTG Interrupt Register. <i>Offset: 004h</i> */
53703 + volatile uint32_t gotgint;
53704 + /**Core AHB Configuration Register. <i>Offset: 008h</i> */
53705 + volatile uint32_t gahbcfg;
53707 +#define DWC_GLBINTRMASK 0x0001
53708 +#define DWC_DMAENABLE 0x0020
53709 +#define DWC_NPTXEMPTYLVL_EMPTY 0x0080
53710 +#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000
53711 +#define DWC_PTXEMPTYLVL_EMPTY 0x0100
53712 +#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000
53714 + /**Core USB Configuration Register. <i>Offset: 00Ch</i> */
53715 + volatile uint32_t gusbcfg;
53716 + /**Core Reset Register. <i>Offset: 010h</i> */
53717 + volatile uint32_t grstctl;
53718 + /**Core Interrupt Register. <i>Offset: 014h</i> */
53719 + volatile uint32_t gintsts;
53720 + /**Core Interrupt Mask Register. <i>Offset: 018h</i> */
53721 + volatile uint32_t gintmsk;
53722 + /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */
53723 + volatile uint32_t grxstsr;
53724 + /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/
53725 + volatile uint32_t grxstsp;
53726 + /**Receive FIFO Size Register. <i>Offset: 024h</i> */
53727 + volatile uint32_t grxfsiz;
53728 + /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */
53729 + volatile uint32_t gnptxfsiz;
53730 + /**Non Periodic Transmit FIFO/Queue Status Register (Read
53731 + * Only). <i>Offset: 02Ch</i> */
53732 + volatile uint32_t gnptxsts;
53733 + /**I2C Access Register. <i>Offset: 030h</i> */
53734 + volatile uint32_t gi2cctl;
53735 + /**PHY Vendor Control Register. <i>Offset: 034h</i> */
53736 + volatile uint32_t gpvndctl;
53737 + /**General Purpose Input/Output Register. <i>Offset: 038h</i> */
53738 + volatile uint32_t ggpio;
53739 + /**User ID Register. <i>Offset: 03Ch</i> */
53740 + volatile uint32_t guid;
53741 + /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */
53742 + volatile uint32_t gsnpsid;
53743 + /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */
53744 + volatile uint32_t ghwcfg1;
53745 + /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */
53746 + volatile uint32_t ghwcfg2;
53747 +#define DWC_SLAVE_ONLY_ARCH 0
53748 +#define DWC_EXT_DMA_ARCH 1
53749 +#define DWC_INT_DMA_ARCH 2
53751 +#define DWC_MODE_HNP_SRP_CAPABLE 0
53752 +#define DWC_MODE_SRP_ONLY_CAPABLE 1
53753 +#define DWC_MODE_NO_HNP_SRP_CAPABLE 2
53754 +#define DWC_MODE_SRP_CAPABLE_DEVICE 3
53755 +#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4
53756 +#define DWC_MODE_SRP_CAPABLE_HOST 5
53757 +#define DWC_MODE_NO_SRP_CAPABLE_HOST 6
53759 + /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */
53760 + volatile uint32_t ghwcfg3;
53761 + /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/
53762 + volatile uint32_t ghwcfg4;
53763 + /** Core LPM Configuration register <i>Offset: 054h</i>*/
53764 + volatile uint32_t glpmcfg;
53765 + /** Global PowerDn Register <i>Offset: 058h</i> */
53766 + volatile uint32_t gpwrdn;
53767 + /** Global DFIFO SW Config Register <i>Offset: 05Ch</i> */
53768 + volatile uint32_t gdfifocfg;
53769 + /** ADP Control Register <i>Offset: 060h</i> */
53770 + volatile uint32_t adpctl;
53771 + /** Reserved <i>Offset: 064h-0FFh</i> */
53772 + volatile uint32_t reserved39[39];
53773 + /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */
53774 + volatile uint32_t hptxfsiz;
53775 + /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled,
53776 + otherwise Device Transmit FIFO#n Register.
53777 + * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */
53778 + volatile uint32_t dtxfsiz[15];
53779 +} dwc_otg_core_global_regs_t;
53782 + * This union represents the bit fields of the Core OTG Control
53783 + * and Status Register (GOTGCTL). Set the bits using the bit
53784 + * fields then write the <i>d32</i> value to the register.
53786 +typedef union gotgctl_data {
53787 + /** raw register data */
53789 + /** register bits */
53791 + unsigned sesreqscs:1;
53792 + unsigned sesreq:1;
53793 + unsigned vbvalidoven:1;
53794 + unsigned vbvalidovval:1;
53795 + unsigned avalidoven:1;
53796 + unsigned avalidovval:1;
53797 + unsigned bvalidoven:1;
53798 + unsigned bvalidovval:1;
53799 + unsigned hstnegscs:1;
53800 + unsigned hnpreq:1;
53801 + unsigned hstsethnpen:1;
53802 + unsigned devhnpen:1;
53803 + unsigned reserved12_15:4;
53804 + unsigned conidsts:1;
53805 + unsigned dbnctime:1;
53806 + unsigned asesvld:1;
53807 + unsigned bsesvld:1;
53808 + unsigned otgver:1;
53809 + unsigned reserved1:1;
53810 + unsigned multvalidbc:5;
53811 + unsigned chirpen:1;
53812 + unsigned reserved28_31:4;
53817 + * This union represents the bit fields of the Core OTG Interrupt Register
53818 + * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i>
53819 + * value to the register.
53821 +typedef union gotgint_data {
53822 + /** raw register data */
53824 + /** register bits */
53826 + /** Current Mode */
53827 + unsigned reserved0_1:2;
53829 + /** Session End Detected */
53830 + unsigned sesenddet:1;
53832 + unsigned reserved3_7:5;
53834 + /** Session Request Success Status Change */
53835 + unsigned sesreqsucstschng:1;
53836 + /** Host Negotiation Success Status Change */
53837 + unsigned hstnegsucstschng:1;
53839 + unsigned reserved10_16:7;
53841 + /** Host Negotiation Detected */
53842 + unsigned hstnegdet:1;
53843 + /** A-Device Timeout Change */
53844 + unsigned adevtoutchng:1;
53845 + /** Debounce Done */
53846 + unsigned debdone:1;
53847 + /** Multi-Valued input changed */
53850 + unsigned reserved31_21:11;
53856 + * This union represents the bit fields of the Core AHB Configuration
53857 + * Register (GAHBCFG). Set/clear the bits using the bit fields then
53858 + * write the <i>d32</i> value to the register.
53860 +typedef union gahbcfg_data {
53861 + /** raw register data */
53863 + /** register bits */
53865 + unsigned glblintrmsk:1;
53866 +#define DWC_GAHBCFG_GLBINT_ENABLE 1
53868 + unsigned hburstlen:4;
53869 +#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0
53870 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1
53871 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3
53872 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5
53873 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7
53875 + unsigned dmaenable:1;
53876 +#define DWC_GAHBCFG_DMAENABLE 1
53877 + unsigned reserved:1;
53878 + unsigned nptxfemplvl_txfemplvl:1;
53879 + unsigned ptxfemplvl:1;
53880 +#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1
53881 +#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0
53882 + unsigned reserved9_20:12;
53883 + unsigned remmemsupp:1;
53884 + unsigned notialldmawrit:1;
53885 + unsigned ahbsingle:1;
53886 + unsigned reserved24_31:8;
53891 + * This union represents the bit fields of the Core USB Configuration
53892 + * Register (GUSBCFG). Set the bits using the bit fields then write
53893 + * the <i>d32</i> value to the register.
53895 +typedef union gusbcfg_data {
53896 + /** raw register data */
53898 + /** register bits */
53900 + unsigned toutcal:3;
53901 + unsigned phyif:1;
53902 + unsigned ulpi_utmi_sel:1;
53903 + unsigned fsintf:1;
53904 + unsigned physel:1;
53905 + unsigned ddrsel:1;
53906 + unsigned srpcap:1;
53907 + unsigned hnpcap:1;
53908 + unsigned usbtrdtim:4;
53909 + unsigned reserved1:1;
53910 + unsigned phylpwrclksel:1;
53911 + unsigned otgutmifssel:1;
53912 + unsigned ulpi_fsls:1;
53913 + unsigned ulpi_auto_res:1;
53914 + unsigned ulpi_clk_sus_m:1;
53915 + unsigned ulpi_ext_vbus_drv:1;
53916 + unsigned ulpi_int_vbus_indicator:1;
53917 + unsigned term_sel_dl_pulse:1;
53918 + unsigned indicator_complement:1;
53919 + unsigned indicator_pass_through:1;
53920 + unsigned ulpi_int_prot_dis:1;
53921 + unsigned ic_usb_cap:1;
53922 + unsigned ic_traffic_pull_remove:1;
53923 + unsigned tx_end_delay:1;
53924 + unsigned force_host_mode:1;
53925 + unsigned force_dev_mode:1;
53926 + unsigned reserved31:1;
53931 + * This union represents the bit fields of the Core Reset Register
53932 + * (GRSTCTL). Set/clear the bits using the bit fields then write the
53933 + * <i>d32</i> value to the register.
53935 +typedef union grstctl_data {
53936 + /** raw register data */
53938 + /** register bits */
53940 + /** Core Soft Reset (CSftRst) (Device and Host)
53942 + * The application can flush the control logic in the
53943 + * entire core using this bit. This bit resets the
53944 + * pipelines in the AHB Clock domain as well as the
53945 + * PHY Clock domain.
53947 + * The state machines are reset to an IDLE state, the
53948 + * control bits in the CSRs are cleared, all the
53949 + * transmit FIFOs and the receive FIFO are flushed.
53951 + * The status mask bits that control the generation of
53952 + * the interrupt, are cleared, to clear the
53953 + * interrupt. The interrupt status bits are not
53954 + * cleared, so the application can get the status of
53955 + * any events that occurred in the core after it has
53958 + * Any transactions on the AHB are terminated as soon
53959 + * as possible following the protocol. Any
53960 + * transactions on the USB are terminated immediately.
53962 + * The configuration settings in the CSRs are
53963 + * unchanged, so the software doesn't have to
53964 + * reprogram these registers (Device
53965 + * Configuration/Host Configuration/Core System
53966 + * Configuration/Core PHY Configuration).
53968 + * The application can write to this bit, any time it
53969 + * wants to reset the core. This is a self clearing
53970 + * bit and the core clears this bit after all the
53971 + * necessary logic is reset in the core, which may
53972 + * take several clocks, depending on the current state
53975 + unsigned csftrst:1;
53976 + /** Hclk Soft Reset
53978 + * The application uses this bit to reset the control logic in
53979 + * the AHB clock domain. Only AHB clock domain pipelines are
53982 + unsigned hsftrst:1;
53983 + /** Host Frame Counter Reset (Host Only)<br>
53985 + * The application can reset the (micro)frame number
53986 + * counter inside the core, using this bit. When the
53987 + * (micro)frame counter is reset, the subsequent SOF
53988 + * sent out by the core, will have a (micro)frame
53991 + unsigned hstfrm:1;
53992 + /** In Token Sequence Learning Queue Flush
53993 + * (INTknQFlsh) (Device Only)
53995 + unsigned intknqflsh:1;
53996 + /** RxFIFO Flush (RxFFlsh) (Device and Host)
53998 + * The application can flush the entire Receive FIFO
53999 + * using this bit. The application must first
54000 + * ensure that the core is not in the middle of a
54001 + * transaction. The application should write into
54002 + * this bit, only after making sure that neither the
54003 + * DMA engine is reading from the RxFIFO nor the MAC
54004 + * is writing the data in to the FIFO. The
54005 + * application should wait until the bit is cleared
54006 + * before performing any other operations. This bit
54007 + * will takes 8 clocks (slowest of PHY or AHB clock)
54010 + unsigned rxfflsh:1;
54011 + /** TxFIFO Flush (TxFFlsh) (Device and Host).
54013 + * This bit is used to selectively flush a single or
54014 + * all transmit FIFOs. The application must first
54015 + * ensure that the core is not in the middle of a
54016 + * transaction. The application should write into
54017 + * this bit, only after making sure that neither the
54018 + * DMA engine is writing into the TxFIFO nor the MAC
54019 + * is reading the data out of the FIFO. The
54020 + * application should wait until the core clears this
54021 + * bit, before performing any operations. This bit
54022 + * will takes 8 clocks (slowest of PHY or AHB clock)
54025 + unsigned txfflsh:1;
54027 + /** TxFIFO Number (TxFNum) (Device and Host).
54029 + * This is the FIFO number which needs to be flushed,
54030 + * using the TxFIFO Flush bit. This field should not
54031 + * be changed until the TxFIFO Flush bit is cleared by
54033 + * - 0x0 : Non Periodic TxFIFO Flush
54034 + * - 0x1 : Periodic TxFIFO #1 Flush in device mode
54035 + * or Periodic TxFIFO in host mode
54036 + * - 0x2 : Periodic TxFIFO #2 Flush in device mode.
54038 + * - 0xF : Periodic TxFIFO #15 Flush in device mode
54039 + * - 0x10: Flush all the Transmit NonPeriodic and
54040 + * Transmit Periodic FIFOs in the core
54042 + unsigned txfnum:5;
54044 + unsigned reserved11_29:19;
54045 + /** DMA Request Signal. Indicated DMA request is in
54046 + * probress. Used for debug purpose. */
54047 + unsigned dmareq:1;
54048 + /** AHB Master Idle. Indicates the AHB Master State
54049 + * Machine is in IDLE condition. */
54050 + unsigned ahbidle:1;
54055 + * This union represents the bit fields of the Core Interrupt Mask
54056 + * Register (GINTMSK). Set/clear the bits using the bit fields then
54057 + * write the <i>d32</i> value to the register.
54059 +typedef union gintmsk_data {
54060 + /** raw register data */
54062 + /** register bits */
54064 + unsigned reserved0:1;
54065 + unsigned modemismatch:1;
54066 + unsigned otgintr:1;
54067 + unsigned sofintr:1;
54068 + unsigned rxstsqlvl:1;
54069 + unsigned nptxfempty:1;
54070 + unsigned ginnakeff:1;
54071 + unsigned goutnakeff:1;
54072 + unsigned ulpickint:1;
54073 + unsigned i2cintr:1;
54074 + unsigned erlysuspend:1;
54075 + unsigned usbsuspend:1;
54076 + unsigned usbreset:1;
54077 + unsigned enumdone:1;
54078 + unsigned isooutdrop:1;
54079 + unsigned eopframe:1;
54080 + unsigned restoredone:1;
54081 + unsigned epmismatch:1;
54082 + unsigned inepintr:1;
54083 + unsigned outepintr:1;
54084 + unsigned incomplisoin:1;
54085 + unsigned incomplisoout:1;
54086 + unsigned fetsusp:1;
54087 + unsigned resetdet:1;
54088 + unsigned portintr:1;
54089 + unsigned hcintr:1;
54090 + unsigned ptxfempty:1;
54091 + unsigned lpmtranrcvd:1;
54092 + unsigned conidstschng:1;
54093 + unsigned disconnect:1;
54094 + unsigned sessreqintr:1;
54095 + unsigned wkupintr:1;
54099 + * This union represents the bit fields of the Core Interrupt Register
54100 + * (GINTSTS). Set/clear the bits using the bit fields then write the
54101 + * <i>d32</i> value to the register.
54103 +typedef union gintsts_data {
54104 + /** raw register data */
54106 +#define DWC_SOF_INTR_MASK 0x0008
54107 + /** register bits */
54109 +#define DWC_HOST_MODE 1
54110 + unsigned curmode:1;
54111 + unsigned modemismatch:1;
54112 + unsigned otgintr:1;
54113 + unsigned sofintr:1;
54114 + unsigned rxstsqlvl:1;
54115 + unsigned nptxfempty:1;
54116 + unsigned ginnakeff:1;
54117 + unsigned goutnakeff:1;
54118 + unsigned ulpickint:1;
54119 + unsigned i2cintr:1;
54120 + unsigned erlysuspend:1;
54121 + unsigned usbsuspend:1;
54122 + unsigned usbreset:1;
54123 + unsigned enumdone:1;
54124 + unsigned isooutdrop:1;
54125 + unsigned eopframe:1;
54126 + unsigned restoredone:1;
54127 + unsigned epmismatch:1;
54128 + unsigned inepint:1;
54129 + unsigned outepintr:1;
54130 + unsigned incomplisoin:1;
54131 + unsigned incomplisoout:1;
54132 + unsigned fetsusp:1;
54133 + unsigned resetdet:1;
54134 + unsigned portintr:1;
54135 + unsigned hcintr:1;
54136 + unsigned ptxfempty:1;
54137 + unsigned lpmtranrcvd:1;
54138 + unsigned conidstschng:1;
54139 + unsigned disconnect:1;
54140 + unsigned sessreqintr:1;
54141 + unsigned wkupintr:1;
54146 + * This union represents the bit fields in the Device Receive Status Read and
54147 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
54148 + * element then read out the bits using the <i>b</i>it elements.
54150 +typedef union device_grxsts_data {
54151 + /** raw register data */
54153 + /** register bits */
54155 + unsigned epnum:4;
54156 + unsigned bcnt:11;
54159 +#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet
54160 +#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete
54162 +#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK
54163 +#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete
54164 +#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet
54165 + unsigned pktsts:4;
54167 + unsigned reserved25_31:7;
54169 +} device_grxsts_data_t;
54172 + * This union represents the bit fields in the Host Receive Status Read and
54173 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
54174 + * element then read out the bits using the <i>b</i>it elements.
54176 +typedef union host_grxsts_data {
54177 + /** raw register data */
54179 + /** register bits */
54181 + unsigned chnum:4;
54182 + unsigned bcnt:11;
54185 + unsigned pktsts:4;
54186 +#define DWC_GRXSTS_PKTSTS_IN 0x2
54187 +#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3
54188 +#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
54189 +#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7
54191 + unsigned reserved21_31:11;
54193 +} host_grxsts_data_t;
54196 + * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ,
54197 + * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the <i>d32</i> element
54198 + * then read out the bits using the <i>b</i>it elements.
54200 +typedef union fifosize_data {
54201 + /** raw register data */
54203 + /** register bits */
54205 + unsigned startaddr:16;
54206 + unsigned depth:16;
54208 +} fifosize_data_t;
54211 + * This union represents the bit fields in the Non-Periodic Transmit
54212 + * FIFO/Queue Status Register (GNPTXSTS). Read the register into the
54213 + * <i>d32</i> element then read out the bits using the <i>b</i>it
54216 +typedef union gnptxsts_data {
54217 + /** raw register data */
54219 + /** register bits */
54221 + unsigned nptxfspcavail:16;
54222 + unsigned nptxqspcavail:8;
54223 + /** Top of the Non-Periodic Transmit Request Queue
54224 + * - bit 24 - Terminate (Last entry for the selected
54226 + * - bits 26:25 - Token Type
54227 + * - 2'b00 - IN/OUT
54228 + * - 2'b01 - Zero Length OUT
54229 + * - 2'b10 - PING/Complete Split
54230 + * - 2'b11 - Channel Halt
54231 + * - bits 30:27 - Channel/EP Number
54233 + unsigned nptxqtop_terminate:1;
54234 + unsigned nptxqtop_token:2;
54235 + unsigned nptxqtop_chnep:4;
54236 + unsigned reserved:1;
54238 +} gnptxsts_data_t;
54241 + * This union represents the bit fields in the Transmit
54242 + * FIFO Status Register (DTXFSTS). Read the register into the
54243 + * <i>d32</i> element then read out the bits using the <i>b</i>it
54246 +typedef union dtxfsts_data {
54247 + /** raw register data */
54249 + /** register bits */
54251 + unsigned txfspcavail:16;
54252 + unsigned reserved:16;
54257 + * This union represents the bit fields in the I2C Control Register
54258 + * (I2CCTL). Read the register into the <i>d32</i> element then read out the
54259 + * bits using the <i>b</i>it elements.
54261 +typedef union gi2cctl_data {
54262 + /** raw register data */
54264 + /** register bits */
54266 + unsigned rwdata:8;
54267 + unsigned regaddr:8;
54269 + unsigned i2cen:1;
54271 + unsigned i2csuspctl:1;
54272 + unsigned i2cdevaddr:2;
54273 + unsigned i2cdatse0:1;
54274 + unsigned reserved:1;
54276 + unsigned bsydne:1;
54281 + * This union represents the bit fields in the PHY Vendor Control Register
54282 + * (GPVNDCTL). Read the register into the <i>d32</i> element then read out the
54283 + * bits using the <i>b</i>it elements.
54285 +typedef union gpvndctl_data {
54286 + /** raw register data */
54288 + /** register bits */
54290 + unsigned regdata:8;
54291 + unsigned vctrl:8;
54292 + unsigned regaddr16_21:6;
54293 + unsigned regwr:1;
54294 + unsigned reserved23_24:2;
54295 + unsigned newregreq:1;
54296 + unsigned vstsbsy:1;
54297 + unsigned vstsdone:1;
54298 + unsigned reserved28_30:3;
54299 + unsigned disulpidrvr:1;
54301 +} gpvndctl_data_t;
54304 + * This union represents the bit fields in the General Purpose
54305 + * Input/Output Register (GGPIO).
54306 + * Read the register into the <i>d32</i> element then read out the
54307 + * bits using the <i>b</i>it elements.
54309 +typedef union ggpio_data {
54310 + /** raw register data */
54312 + /** register bits */
54320 + * This union represents the bit fields in the User ID Register
54321 + * (GUID). Read the register into the <i>d32</i> element then read out the
54322 + * bits using the <i>b</i>it elements.
54324 +typedef union guid_data {
54325 + /** raw register data */
54327 + /** register bits */
54329 + unsigned rwdata:32;
54334 + * This union represents the bit fields in the Synopsys ID Register
54335 + * (GSNPSID). Read the register into the <i>d32</i> element then read out the
54336 + * bits using the <i>b</i>it elements.
54338 +typedef union gsnpsid_data {
54339 + /** raw register data */
54341 + /** register bits */
54343 + unsigned rwdata:32;
54348 + * This union represents the bit fields in the User HW Config1
54349 + * Register. Read the register into the <i>d32</i> element then read
54350 + * out the bits using the <i>b</i>it elements.
54352 +typedef union hwcfg1_data {
54353 + /** raw register data */
54355 + /** register bits */
54357 + unsigned ep_dir0:2;
54358 + unsigned ep_dir1:2;
54359 + unsigned ep_dir2:2;
54360 + unsigned ep_dir3:2;
54361 + unsigned ep_dir4:2;
54362 + unsigned ep_dir5:2;
54363 + unsigned ep_dir6:2;
54364 + unsigned ep_dir7:2;
54365 + unsigned ep_dir8:2;
54366 + unsigned ep_dir9:2;
54367 + unsigned ep_dir10:2;
54368 + unsigned ep_dir11:2;
54369 + unsigned ep_dir12:2;
54370 + unsigned ep_dir13:2;
54371 + unsigned ep_dir14:2;
54372 + unsigned ep_dir15:2;
54377 + * This union represents the bit fields in the User HW Config2
54378 + * Register. Read the register into the <i>d32</i> element then read
54379 + * out the bits using the <i>b</i>it elements.
54381 +typedef union hwcfg2_data {
54382 + /** raw register data */
54384 + /** register bits */
54387 + unsigned op_mode:3;
54388 +#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
54389 +#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
54390 +#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
54391 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
54392 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
54393 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
54394 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
54396 + unsigned architecture:2;
54397 + unsigned point2point:1;
54398 + unsigned hs_phy_type:2;
54399 +#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
54400 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
54401 +#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
54402 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
54404 + unsigned fs_phy_type:2;
54405 + unsigned num_dev_ep:4;
54406 + unsigned num_host_chan:4;
54407 + unsigned perio_ep_supported:1;
54408 + unsigned dynamic_fifo:1;
54409 + unsigned multi_proc_int:1;
54410 + unsigned reserved21:1;
54411 + unsigned nonperio_tx_q_depth:2;
54412 + unsigned host_perio_tx_q_depth:2;
54413 + unsigned dev_token_q_depth:5;
54414 + unsigned otg_enable_ic_usb:1;
54419 + * This union represents the bit fields in the User HW Config3
54420 + * Register. Read the register into the <i>d32</i> element then read
54421 + * out the bits using the <i>b</i>it elements.
54423 +typedef union hwcfg3_data {
54424 + /** raw register data */
54426 + /** register bits */
54429 + unsigned xfer_size_cntr_width:4;
54430 + unsigned packet_size_cntr_width:3;
54431 + unsigned otg_func:1;
54433 + unsigned vendor_ctrl_if:1;
54434 + unsigned optional_features:1;
54435 + unsigned synch_reset_type:1;
54436 + unsigned adp_supp:1;
54437 + unsigned otg_enable_hsic:1;
54438 + unsigned bc_support:1;
54439 + unsigned otg_lpm_en:1;
54440 + unsigned dfifo_depth:16;
54445 + * This union represents the bit fields in the User HW Config4
54446 + * Register. Read the register into the <i>d32</i> element then read
54447 + * out the bits using the <i>b</i>it elements.
54449 +typedef union hwcfg4_data {
54450 + /** raw register data */
54452 + /** register bits */
54454 + unsigned num_dev_perio_in_ep:4;
54455 + unsigned power_optimiz:1;
54456 + unsigned min_ahb_freq:1;
54457 + unsigned hiber:1;
54458 + unsigned xhiber:1;
54459 + unsigned reserved:6;
54460 + unsigned utmi_phy_data_width:2;
54461 + unsigned num_dev_mode_ctrl_ep:4;
54462 + unsigned iddig_filt_en:1;
54463 + unsigned vbus_valid_filt_en:1;
54464 + unsigned a_valid_filt_en:1;
54465 + unsigned b_valid_filt_en:1;
54466 + unsigned session_end_filt_en:1;
54467 + unsigned ded_fifo_en:1;
54468 + unsigned num_in_eps:4;
54469 + unsigned desc_dma:1;
54470 + unsigned desc_dma_dyn:1;
54475 + * This union represents the bit fields of the Core LPM Configuration
54476 + * Register (GLPMCFG). Set the bits using bit fields then write
54477 + * the <i>d32</i> value to the register.
54479 +typedef union glpmctl_data {
54480 + /** raw register data */
54482 + /** register bits */
54484 + /** LPM-Capable (LPMCap) (Device and Host)
54485 + * The application uses this bit to control
54486 + * the DWC_otg core LPM capabilities.
54488 + unsigned lpm_cap_en:1;
54489 + /** LPM response programmed by application (AppL1Res) (Device)
54490 + * Handshake response to LPM token pre-programmed
54491 + * by device application software.
54493 + unsigned appl_resp:1;
54494 + /** Host Initiated Resume Duration (HIRD) (Device and Host)
54495 + * In Host mode this field indicates the value of HIRD
54496 + * to be sent in an LPM transaction.
54497 + * In Device mode this field is updated with the
54498 + * Received LPM Token HIRD bmAttribute
54499 + * when an ACK/NYET/STALL response is sent
54500 + * to an LPM transaction.
54503 + /** RemoteWakeEnable (bRemoteWake) (Device and Host)
54504 + * In Host mode this bit indicates the value of remote
54505 + * wake up to be sent in wIndex field of LPM transaction.
54506 + * In Device mode this field is updated with the
54507 + * Received LPM Token bRemoteWake bmAttribute
54508 + * when an ACK/NYET/STALL response is sent
54509 + * to an LPM transaction.
54511 + unsigned rem_wkup_en:1;
54512 + /** Enable utmi_sleep_n (EnblSlpM) (Device and Host)
54513 + * The application uses this bit to control
54514 + * the utmi_sleep_n assertion to the PHY when in L1 state.
54516 + unsigned en_utmi_sleep:1;
54517 + /** HIRD Threshold (HIRD_Thres) (Device and Host)
54519 + unsigned hird_thres:5;
54520 + /** LPM Response (CoreL1Res) (Device and Host)
54521 + * In Host mode this bit contains handsake response to
54522 + * LPM transaction.
54523 + * In Device mode the response of the core to
54524 + * LPM transaction received is reflected in these two bits.
54525 + - 0x0 : ERROR (No handshake response)
54530 + unsigned lpm_resp:2;
54531 + /** Port Sleep Status (SlpSts) (Device and Host)
54532 + * This bit is set as long as a Sleep condition
54533 + * is present on the USB bus.
54535 + unsigned prt_sleep_sts:1;
54536 + /** Sleep State Resume OK (L1ResumeOK) (Device and Host)
54537 + * Indicates that the application or host
54538 + * can start resume from Sleep state.
54540 + unsigned sleep_state_resumeok:1;
54541 + /** LPM channel Index (LPM_Chnl_Indx) (Host)
54542 + * The channel number on which the LPM transaction
54543 + * has to be applied while sending
54544 + * an LPM transaction to the local device.
54546 + unsigned lpm_chan_index:4;
54547 + /** LPM Retry Count (LPM_Retry_Cnt) (Host)
54548 + * Number host retries that would be performed
54549 + * if the device response was not valid response.
54551 + unsigned retry_count:3;
54552 + /** Send LPM Transaction (SndLPM) (Host)
54553 + * When set by application software,
54554 + * an LPM transaction containing two tokens
54557 + unsigned send_lpm:1;
54558 + /** LPM Retry status (LPM_RetryCnt_Sts) (Host)
54559 + * Number of LPM Host Retries still remaining
54560 + * to be transmitted for the current LPM sequence
54562 + unsigned retry_count_sts:3;
54563 + unsigned reserved28_29:2;
54564 + /** In host mode once this bit is set, the host
54565 + * configures to drive the HSIC Idle state on the bus.
54566 + * It then waits for the device to initiate the Connect sequence.
54567 + * In device mode once this bit is set, the device waits for
54568 + * the HSIC Idle line state on the bus. Upon receving the Idle
54569 + * line state, it initiates the HSIC Connect sequence.
54571 + unsigned hsic_connect:1;
54572 + /** This bit overrides and functionally inverts
54573 + * the if_select_hsic input port signal.
54575 + unsigned inv_sel_hsic:1;
54580 + * This union represents the bit fields of the Core ADP Timer, Control and
54581 + * Status Register (ADPTIMCTLSTS). Set the bits using bit fields then write
54582 + * the <i>d32</i> value to the register.
54584 +typedef union adpctl_data {
54585 + /** raw register data */
54587 + /** register bits */
54589 + /** Probe Discharge (PRB_DSCHG)
54590 + * These bits set the times for TADP_DSCHG.
54591 + * These bits are defined as follows:
54594 + * 2'b10 - 16 msec
54595 + * 2'b11 - 32 msec
54597 + unsigned prb_dschg:2;
54598 + /** Probe Delta (PRB_DELTA)
54599 + * These bits set the resolution for RTIM value.
54600 + * The bits are defined in units of 32 kHz clock cycles as follows:
54601 + * 2'b00 - 1 cycles
54602 + * 2'b01 - 2 cycles
54603 + * 2'b10 - 3 cycles
54604 + * 2'b11 - 4 cycles
54605 + * For example if this value is chosen to 2'b01, it means that RTIM
54606 + * increments for every 3(three) 32Khz clock cycles.
54608 + unsigned prb_delta:2;
54609 + /** Probe Period (PRB_PER)
54610 + * These bits sets the TADP_PRD as shown in Figure 4 as follows:
54611 + * 2'b00 - 0.625 to 0.925 sec (typical 0.775 sec)
54612 + * 2'b01 - 1.25 to 1.85 sec (typical 1.55 sec)
54613 + * 2'b10 - 1.9 to 2.6 sec (typical 2.275 sec)
54614 + * 2'b11 - Reserved
54616 + unsigned prb_per:2;
54617 + /** These bits capture the latest time it took for VBUS to ramp from
54618 + * VADP_SINK to VADP_PRB.
54619 + * 0x000 - 1 cycles
54620 + * 0x001 - 2 cycles
54621 + * 0x002 - 3 cycles
54623 + * 0x7FF - 2048 cycles
54624 + * A time of 1024 cycles at 32 kHz corresponds to a time of 32 msec.
54626 + unsigned rtim:11;
54627 + /** Enable Probe (EnaPrb)
54628 + * When programmed to 1'b1, the core performs a probe operation.
54629 + * This bit is valid only if OTG_Ver = 1'b1.
54631 + unsigned enaprb:1;
54632 + /** Enable Sense (EnaSns)
54633 + * When programmed to 1'b1, the core performs a Sense operation.
54634 + * This bit is valid only if OTG_Ver = 1'b1.
54636 + unsigned enasns:1;
54637 + /** ADP Reset (ADPRes)
54638 + * When set, ADP controller is reset.
54639 + * This bit is valid only if OTG_Ver = 1'b1.
54641 + unsigned adpres:1;
54642 + /** ADP Enable (ADPEn)
54643 + * When set, the core performs either ADP probing or sensing
54644 + * based on EnaPrb or EnaSns.
54645 + * This bit is valid only if OTG_Ver = 1'b1.
54647 + unsigned adpen:1;
54648 + /** ADP Probe Interrupt (ADP_PRB_INT)
54649 + * When this bit is set, it means that the VBUS
54650 + * voltage is greater than VADP_PRB or VADP_PRB is reached.
54651 + * This bit is valid only if OTG_Ver = 1'b1.
54653 + unsigned adp_prb_int:1;
54655 + * ADP Sense Interrupt (ADP_SNS_INT)
54656 + * When this bit is set, it means that the VBUS voltage is greater than
54657 + * VADP_SNS value or VADP_SNS is reached.
54658 + * This bit is valid only if OTG_Ver = 1'b1.
54660 + unsigned adp_sns_int:1;
54661 + /** ADP Tomeout Interrupt (ADP_TMOUT_INT)
54662 + * This bit is relevant only for an ADP probe.
54663 + * When this bit is set, it means that the ramp time has
54664 + * completed ie ADPCTL.RTIM has reached its terminal value
54665 + * of 0x7FF. This is a debug feature that allows software
54666 + * to read the ramp time after each cycle.
54667 + * This bit is valid only if OTG_Ver = 1'b1.
54669 + unsigned adp_tmout_int:1;
54670 + /** ADP Probe Interrupt Mask (ADP_PRB_INT_MSK)
54671 + * When this bit is set, it unmasks the interrupt due to ADP_PRB_INT.
54672 + * This bit is valid only if OTG_Ver = 1'b1.
54674 + unsigned adp_prb_int_msk:1;
54675 + /** ADP Sense Interrupt Mask (ADP_SNS_INT_MSK)
54676 + * When this bit is set, it unmasks the interrupt due to ADP_SNS_INT.
54677 + * This bit is valid only if OTG_Ver = 1'b1.
54679 + unsigned adp_sns_int_msk:1;
54680 + /** ADP Timoeout Interrupt Mask (ADP_TMOUT_MSK)
54681 + * When this bit is set, it unmasks the interrupt due to ADP_TMOUT_INT.
54682 + * This bit is valid only if OTG_Ver = 1'b1.
54684 + unsigned adp_tmout_int_msk:1;
54685 + /** Access Request
54686 + * 2'b00 - Read/Write Valid (updated by the core)
54689 + * 2'b00 - Reserved
54693 + unsigned reserved29_31:3;
54697 +////////////////////////////////////////////
54698 +// Device Registers
54700 + * Device Global Registers. <i>Offsets 800h-BFFh</i>
54702 + * The following structures define the size and relative field offsets
54703 + * for the Device Mode Registers.
54705 + * <i>These registers are visible only in Device mode and must not be
54706 + * accessed in Host mode, as the results are unknown.</i>
54708 +typedef struct dwc_otg_dev_global_regs {
54709 + /** Device Configuration Register. <i>Offset 800h</i> */
54710 + volatile uint32_t dcfg;
54711 + /** Device Control Register. <i>Offset: 804h</i> */
54712 + volatile uint32_t dctl;
54713 + /** Device Status Register (Read Only). <i>Offset: 808h</i> */
54714 + volatile uint32_t dsts;
54715 + /** Reserved. <i>Offset: 80Ch</i> */
54717 + /** Device IN Endpoint Common Interrupt Mask
54718 + * Register. <i>Offset: 810h</i> */
54719 + volatile uint32_t diepmsk;
54720 + /** Device OUT Endpoint Common Interrupt Mask
54721 + * Register. <i>Offset: 814h</i> */
54722 + volatile uint32_t doepmsk;
54723 + /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */
54724 + volatile uint32_t daint;
54725 + /** Device All Endpoints Interrupt Mask Register. <i>Offset:
54727 + volatile uint32_t daintmsk;
54728 + /** Device IN Token Queue Read Register-1 (Read Only).
54729 + * <i>Offset: 820h</i> */
54730 + volatile uint32_t dtknqr1;
54731 + /** Device IN Token Queue Read Register-2 (Read Only).
54732 + * <i>Offset: 824h</i> */
54733 + volatile uint32_t dtknqr2;
54734 + /** Device VBUS discharge Register. <i>Offset: 828h</i> */
54735 + volatile uint32_t dvbusdis;
54736 + /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */
54737 + volatile uint32_t dvbuspulse;
54738 + /** Device IN Token Queue Read Register-3 (Read Only). /
54739 + * Device Thresholding control register (Read/Write)
54740 + * <i>Offset: 830h</i> */
54741 + volatile uint32_t dtknqr3_dthrctl;
54742 + /** Device IN Token Queue Read Register-4 (Read Only). /
54743 + * Device IN EPs empty Inr. Mask Register (Read/Write)
54744 + * <i>Offset: 834h</i> */
54745 + volatile uint32_t dtknqr4_fifoemptymsk;
54746 + /** Device Each Endpoint Interrupt Register (Read Only). /
54747 + * <i>Offset: 838h</i> */
54748 + volatile uint32_t deachint;
54749 + /** Device Each Endpoint Interrupt mask Register (Read/Write). /
54750 + * <i>Offset: 83Ch</i> */
54751 + volatile uint32_t deachintmsk;
54752 + /** Device Each In Endpoint Interrupt mask Register (Read/Write). /
54753 + * <i>Offset: 840h</i> */
54754 + volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS];
54755 + /** Device Each Out Endpoint Interrupt mask Register (Read/Write). /
54756 + * <i>Offset: 880h</i> */
54757 + volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS];
54758 +} dwc_otg_device_global_regs_t;
54761 + * This union represents the bit fields in the Device Configuration
54762 + * Register. Read the register into the <i>d32</i> member then
54763 + * set/clear the bits using the <i>b</i>it elements. Write the
54764 + * <i>d32</i> member to the dcfg register.
54766 +typedef union dcfg_data {
54767 + /** raw register data */
54769 + /** register bits */
54771 + /** Device Speed */
54772 + unsigned devspd:2;
54773 + /** Non Zero Length Status OUT Handshake */
54774 + unsigned nzstsouthshk:1;
54775 +#define DWC_DCFG_SEND_STALL 1
54777 + unsigned ena32khzs:1;
54778 + /** Device Addresses */
54779 + unsigned devaddr:7;
54780 + /** Periodic Frame Interval */
54781 + unsigned perfrint:2;
54782 +#define DWC_DCFG_FRAME_INTERVAL_80 0
54783 +#define DWC_DCFG_FRAME_INTERVAL_85 1
54784 +#define DWC_DCFG_FRAME_INTERVAL_90 2
54785 +#define DWC_DCFG_FRAME_INTERVAL_95 3
54787 + /** Enable Device OUT NAK for bulk in DDMA mode */
54788 + unsigned endevoutnak:1;
54790 + unsigned reserved14_17:4;
54791 + /** In Endpoint Mis-match count */
54792 + unsigned epmscnt:5;
54793 + /** Enable Descriptor DMA in Device mode */
54794 + unsigned descdma:1;
54795 + unsigned perschintvl:2;
54796 + unsigned resvalid:6;
54801 + * This union represents the bit fields in the Device Control
54802 + * Register. Read the register into the <i>d32</i> member then
54803 + * set/clear the bits using the <i>b</i>it elements.
54805 +typedef union dctl_data {
54806 + /** raw register data */
54808 + /** register bits */
54810 + /** Remote Wakeup */
54811 + unsigned rmtwkupsig:1;
54812 + /** Soft Disconnect */
54813 + unsigned sftdiscon:1;
54814 + /** Global Non-Periodic IN NAK Status */
54815 + unsigned gnpinnaksts:1;
54816 + /** Global OUT NAK Status */
54817 + unsigned goutnaksts:1;
54818 + /** Test Control */
54819 + unsigned tstctl:3;
54820 + /** Set Global Non-Periodic IN NAK */
54821 + unsigned sgnpinnak:1;
54822 + /** Clear Global Non-Periodic IN NAK */
54823 + unsigned cgnpinnak:1;
54824 + /** Set Global OUT NAK */
54825 + unsigned sgoutnak:1;
54826 + /** Clear Global OUT NAK */
54827 + unsigned cgoutnak:1;
54828 + /** Power-On Programming Done */
54829 + unsigned pwronprgdone:1;
54831 + unsigned reserved:1;
54832 + /** Global Multi Count */
54834 + /** Ignore Frame Number for ISOC EPs */
54835 + unsigned ifrmnum:1;
54836 + /** NAK on Babble */
54837 + unsigned nakonbble:1;
54838 + /** Enable Continue on BNA */
54839 + unsigned encontonbna:1;
54841 + unsigned reserved18_31:14;
54846 + * This union represents the bit fields in the Device Status
54847 + * Register. Read the register into the <i>d32</i> member then
54848 + * set/clear the bits using the <i>b</i>it elements.
54850 +typedef union dsts_data {
54851 + /** raw register data */
54853 + /** register bits */
54855 + /** Suspend Status */
54856 + unsigned suspsts:1;
54857 + /** Enumerated Speed */
54858 + unsigned enumspd:2;
54859 +#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
54860 +#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
54861 +#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2
54862 +#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3
54863 + /** Erratic Error */
54864 + unsigned errticerr:1;
54865 + unsigned reserved4_7:4;
54866 + /** Frame or Microframe Number of the received SOF */
54867 + unsigned soffn:14;
54868 + unsigned reserved22_31:10;
54873 + * This union represents the bit fields in the Device IN EP Interrupt
54874 + * Register and the Device IN EP Common Mask Register.
54876 + * - Read the register into the <i>d32</i> member then set/clear the
54877 + * bits using the <i>b</i>it elements.
54879 +typedef union diepint_data {
54880 + /** raw register data */
54882 + /** register bits */
54884 + /** Transfer complete mask */
54885 + unsigned xfercompl:1;
54886 + /** Endpoint disable mask */
54887 + unsigned epdisabled:1;
54888 + /** AHB Error mask */
54889 + unsigned ahberr:1;
54890 + /** TimeOUT Handshake mask (non-ISOC EPs) */
54891 + unsigned timeout:1;
54892 + /** IN Token received with TxF Empty mask */
54893 + unsigned intktxfemp:1;
54894 + /** IN Token Received with EP mismatch mask */
54895 + unsigned intknepmis:1;
54896 + /** IN Endpoint NAK Effective mask */
54897 + unsigned inepnakeff:1;
54899 + unsigned emptyintr:1;
54901 + unsigned txfifoundrn:1;
54903 + /** BNA Interrupt mask */
54906 + unsigned reserved10_12:3;
54907 + /** BNA Interrupt mask */
54910 + unsigned reserved14_31:18;
54915 + * This union represents the bit fields in the Device IN EP
54916 + * Common/Dedicated Interrupt Mask Register.
54918 +typedef union diepint_data diepmsk_data_t;
54921 + * This union represents the bit fields in the Device OUT EP Interrupt
54922 + * Registerand Device OUT EP Common Interrupt Mask Register.
54924 + * - Read the register into the <i>d32</i> member then set/clear the
54925 + * bits using the <i>b</i>it elements.
54927 +typedef union doepint_data {
54928 + /** raw register data */
54930 + /** register bits */
54932 + /** Transfer complete */
54933 + unsigned xfercompl:1;
54934 + /** Endpoint disable */
54935 + unsigned epdisabled:1;
54937 + unsigned ahberr:1;
54938 + /** Setup Phase Done (contorl EPs) */
54939 + unsigned setup:1;
54940 + /** OUT Token Received when Endpoint Disabled */
54941 + unsigned outtknepdis:1;
54943 + unsigned stsphsercvd:1;
54944 + /** Back-to-Back SETUP Packets Received */
54945 + unsigned back2backsetup:1;
54947 + unsigned reserved7:1;
54948 + /** OUT packet Error */
54949 + unsigned outpkterr:1;
54950 + /** BNA Interrupt */
54953 + unsigned reserved10:1;
54954 + /** Packet Drop Status */
54955 + unsigned pktdrpsts:1;
54956 + /** Babble Interrupt */
54957 + unsigned babble:1;
54958 + /** NAK Interrupt */
54960 + /** NYET Interrupt */
54962 + /** Bit indicating setup packet received */
54965 + unsigned reserved16_31:16;
54970 + * This union represents the bit fields in the Device OUT EP
54971 + * Common/Dedicated Interrupt Mask Register.
54973 +typedef union doepint_data doepmsk_data_t;
54976 + * This union represents the bit fields in the Device All EP Interrupt
54977 + * and Mask Registers.
54978 + * - Read the register into the <i>d32</i> member then set/clear the
54979 + * bits using the <i>b</i>it elements.
54981 +typedef union daint_data {
54982 + /** raw register data */
54984 + /** register bits */
54986 + /** IN Endpoint bits */
54988 + /** OUT Endpoint bits */
54992 + /** IN Endpoint bits */
54993 + unsigned inep0:1;
54994 + unsigned inep1:1;
54995 + unsigned inep2:1;
54996 + unsigned inep3:1;
54997 + unsigned inep4:1;
54998 + unsigned inep5:1;
54999 + unsigned inep6:1;
55000 + unsigned inep7:1;
55001 + unsigned inep8:1;
55002 + unsigned inep9:1;
55003 + unsigned inep10:1;
55004 + unsigned inep11:1;
55005 + unsigned inep12:1;
55006 + unsigned inep13:1;
55007 + unsigned inep14:1;
55008 + unsigned inep15:1;
55009 + /** OUT Endpoint bits */
55010 + unsigned outep0:1;
55011 + unsigned outep1:1;
55012 + unsigned outep2:1;
55013 + unsigned outep3:1;
55014 + unsigned outep4:1;
55015 + unsigned outep5:1;
55016 + unsigned outep6:1;
55017 + unsigned outep7:1;
55018 + unsigned outep8:1;
55019 + unsigned outep9:1;
55020 + unsigned outep10:1;
55021 + unsigned outep11:1;
55022 + unsigned outep12:1;
55023 + unsigned outep13:1;
55024 + unsigned outep14:1;
55025 + unsigned outep15:1;
55030 + * This union represents the bit fields in the Device IN Token Queue
55031 + * Read Registers.
55032 + * - Read the register into the <i>d32</i> member.
55033 + * - READ-ONLY Register
55035 +typedef union dtknq1_data {
55036 + /** raw register data */
55038 + /** register bits */
55040 + /** In Token Queue Write Pointer */
55041 + unsigned intknwptr:5;
55043 + unsigned reserved05_06:2;
55044 + /** write pointer has wrapped. */
55045 + unsigned wrap_bit:1;
55046 + /** EP Numbers of IN Tokens 0 ... 4 */
55047 + unsigned epnums0_5:24;
55052 + * This union represents Threshold control Register
55053 + * - Read and write the register into the <i>d32</i> member.
55054 + * - READ-WRITABLE Register
55056 +typedef union dthrctl_data {
55057 + /** raw register data */
55059 + /** register bits */
55061 + /** non ISO Tx Thr. Enable */
55062 + unsigned non_iso_thr_en:1;
55063 + /** ISO Tx Thr. Enable */
55064 + unsigned iso_thr_en:1;
55065 + /** Tx Thr. Length */
55066 + unsigned tx_thr_len:9;
55067 + /** AHB Threshold ratio */
55068 + unsigned ahb_thr_ratio:2;
55070 + unsigned reserved13_15:3;
55071 + /** Rx Thr. Enable */
55072 + unsigned rx_thr_en:1;
55073 + /** Rx Thr. Length */
55074 + unsigned rx_thr_len:9;
55075 + unsigned reserved26:1;
55076 + /** Arbiter Parking Enable*/
55077 + unsigned arbprken:1;
55079 + unsigned reserved28_31:4;
55084 + * Device Logical IN Endpoint-Specific Registers. <i>Offsets
55087 + * There will be one set of endpoint registers per logical endpoint
55090 + * <i>These registers are visible only in Device mode and must not be
55091 + * accessed in Host mode, as the results are unknown.</i>
55093 +typedef struct dwc_otg_dev_in_ep_regs {
55094 + /** Device IN Endpoint Control Register. <i>Offset:900h +
55095 + * (ep_num * 20h) + 00h</i> */
55096 + volatile uint32_t diepctl;
55097 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */
55098 + uint32_t reserved04;
55099 + /** Device IN Endpoint Interrupt Register. <i>Offset:900h +
55100 + * (ep_num * 20h) + 08h</i> */
55101 + volatile uint32_t diepint;
55102 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */
55103 + uint32_t reserved0C;
55104 + /** Device IN Endpoint Transfer Size
55105 + * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */
55106 + volatile uint32_t dieptsiz;
55107 + /** Device IN Endpoint DMA Address Register. <i>Offset:900h +
55108 + * (ep_num * 20h) + 14h</i> */
55109 + volatile uint32_t diepdma;
55110 + /** Device IN Endpoint Transmit FIFO Status Register. <i>Offset:900h +
55111 + * (ep_num * 20h) + 18h</i> */
55112 + volatile uint32_t dtxfsts;
55113 + /** Device IN Endpoint DMA Buffer Register. <i>Offset:900h +
55114 + * (ep_num * 20h) + 1Ch</i> */
55115 + volatile uint32_t diepdmab;
55116 +} dwc_otg_dev_in_ep_regs_t;
55119 + * Device Logical OUT Endpoint-Specific Registers. <i>Offsets:
55122 + * There will be one set of endpoint registers per logical endpoint
55125 + * <i>These registers are visible only in Device mode and must not be
55126 + * accessed in Host mode, as the results are unknown.</i>
55128 +typedef struct dwc_otg_dev_out_ep_regs {
55129 + /** Device OUT Endpoint Control Register. <i>Offset:B00h +
55130 + * (ep_num * 20h) + 00h</i> */
55131 + volatile uint32_t doepctl;
55132 + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 04h</i> */
55133 + uint32_t reserved04;
55134 + /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h +
55135 + * (ep_num * 20h) + 08h</i> */
55136 + volatile uint32_t doepint;
55137 + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */
55138 + uint32_t reserved0C;
55139 + /** Device OUT Endpoint Transfer Size Register. <i>Offset:
55140 + * B00h + (ep_num * 20h) + 10h</i> */
55141 + volatile uint32_t doeptsiz;
55142 + /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h
55143 + * + (ep_num * 20h) + 14h</i> */
55144 + volatile uint32_t doepdma;
55145 + /** Reserved. <i>Offset:B00h + * (ep_num * 20h) + 18h</i> */
55147 + /** Device OUT Endpoint DMA Buffer Register. <i>Offset:B00h
55148 + * + (ep_num * 20h) + 1Ch</i> */
55149 + uint32_t doepdmab;
55150 +} dwc_otg_dev_out_ep_regs_t;
55153 + * This union represents the bit fields in the Device EP Control
55154 + * Register. Read the register into the <i>d32</i> member then
55155 + * set/clear the bits using the <i>b</i>it elements.
55157 +typedef union depctl_data {
55158 + /** raw register data */
55160 + /** register bits */
55162 + /** Maximum Packet Size
55164 + * IN/OUT EP0 - 2 bits
55165 + * 2'b00: 64 Bytes
55170 +#define DWC_DEP0CTL_MPS_64 0
55171 +#define DWC_DEP0CTL_MPS_32 1
55172 +#define DWC_DEP0CTL_MPS_16 2
55173 +#define DWC_DEP0CTL_MPS_8 3
55175 + /** Next Endpoint
55177 + * OUT EPn/OUT EP0 - reserved */
55178 + unsigned nextep:4;
55180 + /** USB Active Endpoint */
55181 + unsigned usbactep:1;
55183 + /** Endpoint DPID (INTR/Bulk IN and OUT endpoints)
55184 + * This field contains the PID of the packet going to
55185 + * be received or transmitted on this endpoint. The
55186 + * application should program the PID of the first
55187 + * packet going to be received or transmitted on this
55188 + * endpoint , after the endpoint is
55189 + * activated. Application use the SetD1PID and
55190 + * SetD0PID fields of this register to program either
55193 + * The encoding for this field is
55199 + /** NAK Status */
55200 + unsigned naksts:1;
55202 + /** Endpoint Type
55204 + * 2'b01: Isochronous
55206 + * 2'b11: Interrupt */
55207 + unsigned eptype:2;
55210 + * OUT EPn/OUT EP0
55211 + * IN EPn/IN EP0 - reserved */
55214 + /** Stall Handshake */
55215 + unsigned stall:1;
55217 + /** Tx Fifo Number
55219 + * OUT EPn/OUT EP0 - reserved */
55220 + unsigned txfnum:4;
55226 + /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints)
55227 + * Writing to this field sets the Endpoint DPID (DPID)
55228 + * field in this register to DATA0. Set Even
55229 + * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints)
55230 + * Writing to this field sets the Even/Odd
55231 + * (micro)frame (EO_FrNum) field to even (micro)
55234 + unsigned setd0pid:1;
55235 + /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints)
55236 + * Writing to this field sets the Endpoint DPID (DPID)
55237 + * field in this register to DATA1 Set Odd
55238 + * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints)
55239 + * Writing to this field sets the Even/Odd
55240 + * (micro)frame (EO_FrNum) field to odd (micro) frame.
55242 + unsigned setd1pid:1;
55244 + /** Endpoint Disable */
55245 + unsigned epdis:1;
55246 + /** Endpoint Enable */
55247 + unsigned epena:1;
55252 + * This union represents the bit fields in the Device EP Transfer
55253 + * Size Register. Read the register into the <i>d32</i> member then
55254 + * set/clear the bits using the <i>b</i>it elements.
55256 +typedef union deptsiz_data {
55257 + /** raw register data */
55259 + /** register bits */
55261 + /** Transfer size */
55262 + unsigned xfersize:19;
55263 +/** Max packet count for EP (pow(2,10)-1) */
55264 +#define MAX_PKT_CNT 1023
55265 + /** Packet Count */
55266 + unsigned pktcnt:10;
55267 + /** Multi Count - Periodic IN endpoints */
55269 + unsigned reserved:1;
55274 + * This union represents the bit fields in the Device EP 0 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.
55278 +typedef union deptsiz0_data {
55279 + /** raw register data */
55281 + /** register bits */
55283 + /** Transfer size */
55284 + unsigned xfersize:7;
55286 + unsigned reserved7_18:12;
55287 + /** Packet Count */
55288 + unsigned pktcnt:2;
55290 + unsigned reserved21_28:8;
55291 + /**Setup Packet Count (DOEPTSIZ0 Only) */
55292 + unsigned supcnt:2;
55293 + unsigned reserved31;
55295 +} deptsiz0_data_t;
55297 +/////////////////////////////////////////////////
55298 +// DMA Descriptor Specific Structures
55301 +/** Buffer status definitions */
55303 +#define BS_HOST_READY 0x0
55304 +#define BS_DMA_BUSY 0x1
55305 +#define BS_DMA_DONE 0x2
55306 +#define BS_HOST_BUSY 0x3
55308 +/** Receive/Transmit status definitions */
55310 +#define RTS_SUCCESS 0x0
55311 +#define RTS_BUFFLUSH 0x1
55312 +#define RTS_RESERVED 0x2
55313 +#define RTS_BUFERR 0x3
55316 + * This union represents the bit fields in the DMA Descriptor
55317 + * status quadlet. Read the quadlet into the <i>d32</i> member then
55318 + * set/clear the bits using the <i>b</i>it, <i>b_iso_out</i> and
55319 + * <i>b_iso_in</i> elements.
55321 +typedef union dev_dma_desc_sts {
55322 + /** raw register data */
55324 + /** quadlet bits */
55326 + /** Received number of bytes */
55327 + unsigned bytes:16;
55328 + /** NAK bit - only for OUT EPs */
55330 + unsigned reserved17_22:6;
55331 + /** Multiple Transfer - only for OUT EPs */
55333 + /** Setup Packet received - only for OUT EPs */
55335 + /** Interrupt On Complete */
55337 + /** Short Packet */
55341 + /** Receive Status */
55343 + /** Buffer Status */
55347 +//#ifdef DWC_EN_ISOC
55348 + /** iso out quadlet bits */
55350 + /** Received number of bytes */
55351 + unsigned rxbytes:11;
55353 + unsigned reserved11:1;
55354 + /** Frame Number */
55355 + unsigned framenum:11;
55356 + /** Received ISO Data PID */
55358 + /** Interrupt On Complete */
55360 + /** Short Packet */
55364 + /** Receive Status */
55365 + unsigned rxsts:2;
55366 + /** Buffer Status */
55370 + /** iso in quadlet bits */
55372 + /** Transmited number of bytes */
55373 + unsigned txbytes:12;
55374 + /** Frame Number */
55375 + unsigned framenum:11;
55376 + /** Transmited ISO Data PID */
55378 + /** Interrupt On Complete */
55380 + /** Short Packet */
55384 + /** Transmit Status */
55385 + unsigned txsts:2;
55386 + /** Buffer Status */
55389 +//#endif /* DWC_EN_ISOC */
55390 +} dev_dma_desc_sts_t;
55393 + * DMA Descriptor structure
55395 + * DMA Descriptor structure contains two quadlets:
55396 + * Status quadlet and Data buffer pointer.
55398 +typedef struct dwc_otg_dev_dma_desc {
55399 + /** DMA Descriptor status quadlet */
55400 + dev_dma_desc_sts_t status;
55401 + /** DMA Descriptor data buffer pointer */
55403 +} dwc_otg_dev_dma_desc_t;
55406 + * The dwc_otg_dev_if structure contains information needed to manage
55407 + * the DWC_otg controller acting in device mode. It represents the
55408 + * programming view of the device-specific aspects of the controller.
55410 +typedef struct dwc_otg_dev_if {
55411 + /** Pointer to device Global registers.
55412 + * Device Global Registers starting at offset 800h
55414 + dwc_otg_device_global_regs_t *dev_global_regs;
55415 +#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
55418 + * Device Logical IN Endpoint-Specific Registers 900h-AFCh
55420 + dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS];
55421 +#define DWC_DEV_IN_EP_REG_OFFSET 0x900
55422 +#define DWC_EP_REG_OFFSET 0x20
55424 + /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
55425 + dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];
55426 +#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
55428 + /* Device configuration information */
55429 + uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */
55430 + uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */
55431 + uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/
55433 + /** Size of periodic FIFOs (Bytes) */
55434 + uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS];
55436 + /** Size of Tx FIFOs (Bytes) */
55437 + uint16_t tx_fifo_size[MAX_TX_FIFOS];
55439 + /** Thresholding enable flags and length varaiables **/
55440 + uint16_t rx_thr_en;
55441 + uint16_t iso_tx_thr_en;
55442 + uint16_t non_iso_tx_thr_en;
55444 + uint16_t rx_thr_length;
55445 + uint16_t tx_thr_length;
55448 + * Pointers to the DMA Descriptors for EP0 Control
55449 + * transfers (virtual and physical)
55452 + /** 2 descriptors for SETUP packets */
55453 + dwc_dma_t dma_setup_desc_addr[2];
55454 + dwc_otg_dev_dma_desc_t *setup_desc_addr[2];
55456 + /** Pointer to Descriptor with latest SETUP packet */
55457 + dwc_otg_dev_dma_desc_t *psetup;
55459 + /** Index of current SETUP handler descriptor */
55460 + uint32_t setup_desc_index;
55462 + /** Descriptor for Data In or Status In phases */
55463 + dwc_dma_t dma_in_desc_addr;
55464 + dwc_otg_dev_dma_desc_t *in_desc_addr;
55466 + /** Descriptor for Data Out or Status Out phases */
55467 + dwc_dma_t dma_out_desc_addr;
55468 + dwc_otg_dev_dma_desc_t *out_desc_addr;
55470 + /** Setup Packet Detected - if set clear NAK when queueing */
55472 + /** Isoc ep pointer on which incomplete happens */
55475 +} dwc_otg_dev_if_t;
55477 +/////////////////////////////////////////////////
55478 +// Host Mode Register Structures
55481 + * The Host Global Registers structure defines the size and relative
55482 + * field offsets for the Host Mode Global Registers. Host Global
55483 + * Registers offsets 400h-7FFh.
55485 +typedef struct dwc_otg_host_global_regs {
55486 + /** Host Configuration Register. <i>Offset: 400h</i> */
55487 + volatile uint32_t hcfg;
55488 + /** Host Frame Interval Register. <i>Offset: 404h</i> */
55489 + volatile uint32_t hfir;
55490 + /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */
55491 + volatile uint32_t hfnum;
55492 + /** Reserved. <i>Offset: 40Ch</i> */
55493 + uint32_t reserved40C;
55494 + /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */
55495 + volatile uint32_t hptxsts;
55496 + /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */
55497 + volatile uint32_t haint;
55498 + /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */
55499 + volatile uint32_t haintmsk;
55500 + /** Host Frame List Base Address Register . <i>Offset: 41Ch</i> */
55501 + volatile uint32_t hflbaddr;
55502 +} dwc_otg_host_global_regs_t;
55505 + * This union represents the bit fields in the Host Configuration Register.
55506 + * Read the register into the <i>d32</i> member then set/clear the bits using
55507 + * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register.
55509 +typedef union hcfg_data {
55510 + /** raw register data */
55513 + /** register bits */
55515 + /** FS/LS Phy Clock Select */
55516 + unsigned fslspclksel:2;
55517 +#define DWC_HCFG_30_60_MHZ 0
55518 +#define DWC_HCFG_48_MHZ 1
55519 +#define DWC_HCFG_6_MHZ 2
55521 + /** FS/LS Only Support */
55522 + unsigned fslssupp:1;
55523 + unsigned reserved3_6:4;
55524 + /** Enable 32-KHz Suspend Mode */
55525 + unsigned ena32khzs:1;
55526 + /** Resume Validation Periiod */
55527 + unsigned resvalid:8;
55528 + unsigned reserved16_22:7;
55529 + /** Enable Scatter/gather DMA in Host mode */
55530 + unsigned descdma:1;
55531 + /** Frame List Entries */
55532 + unsigned frlisten:2;
55533 + /** Enable Periodic Scheduling */
55534 + unsigned perschedena:1;
55535 + unsigned reserved27_30:4;
55536 + unsigned modechtimen:1;
55541 + * This union represents the bit fields in the Host Frame Remaing/Number
55544 +typedef union hfir_data {
55545 + /** raw register data */
55548 + /** register bits */
55550 + unsigned frint:16;
55551 + unsigned hfirrldctrl:1;
55552 + unsigned reserved:15;
55557 + * This union represents the bit fields in the Host Frame Remaing/Number
55560 +typedef union hfnum_data {
55561 + /** raw register data */
55564 + /** register bits */
55566 + unsigned frnum:16;
55567 +#define DWC_HFNUM_MAX_FRNUM 0x3FFF
55568 + unsigned frrem:16;
55572 +typedef union hptxsts_data {
55573 + /** raw register data */
55576 + /** register bits */
55578 + unsigned ptxfspcavail:16;
55579 + unsigned ptxqspcavail:8;
55580 + /** Top of the Periodic Transmit Request Queue
55581 + * - bit 24 - Terminate (last entry for the selected channel)
55582 + * - bits 26:25 - Token Type
55583 + * - 2'b00 - Zero length
55585 + * - 2'b10 - Disable
55586 + * - bits 30:27 - Channel Number
55587 + * - bit 31 - Odd/even microframe
55589 + unsigned ptxqtop_terminate:1;
55590 + unsigned ptxqtop_token:2;
55591 + unsigned ptxqtop_chnum:4;
55592 + unsigned ptxqtop_odd:1;
55597 + * This union represents the bit fields in the Host Port Control and Status
55598 + * Register. Read the register into the <i>d32</i> member then set/clear the
55599 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55600 + * hprt0 register.
55602 +typedef union hprt0_data {
55603 + /** raw register data */
55605 + /** register bits */
55607 + unsigned prtconnsts:1;
55608 + unsigned prtconndet:1;
55609 + unsigned prtena:1;
55610 + unsigned prtenchng:1;
55611 + unsigned prtovrcurract:1;
55612 + unsigned prtovrcurrchng:1;
55613 + unsigned prtres:1;
55614 + unsigned prtsusp:1;
55615 + unsigned prtrst:1;
55616 + unsigned reserved9:1;
55617 + unsigned prtlnsts:2;
55618 + unsigned prtpwr:1;
55619 + unsigned prttstctl:4;
55620 + unsigned prtspd:2;
55621 +#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
55622 +#define DWC_HPRT0_PRTSPD_FULL_SPEED 1
55623 +#define DWC_HPRT0_PRTSPD_LOW_SPEED 2
55624 + unsigned reserved19_31:13;
55629 + * This union represents the bit fields in the Host All Interrupt
55632 +typedef union haint_data {
55633 + /** raw register data */
55635 + /** register bits */
55653 + unsigned reserved:16;
55657 + unsigned chint:16;
55658 + unsigned reserved:16;
55663 + * This union represents the bit fields in the Host All Interrupt
55666 +typedef union haintmsk_data {
55667 + /** raw register data */
55669 + /** register bits */
55687 + unsigned reserved:16;
55691 + unsigned chint:16;
55692 + unsigned reserved:16;
55694 +} haintmsk_data_t;
55697 + * Host Channel Specific Registers. <i>500h-5FCh</i>
55699 +typedef struct dwc_otg_hc_regs {
55700 + /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */
55701 + volatile uint32_t hcchar;
55702 + /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */
55703 + volatile uint32_t hcsplt;
55704 + /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */
55705 + volatile uint32_t hcint;
55706 + /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */
55707 + volatile uint32_t hcintmsk;
55708 + /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */
55709 + volatile uint32_t hctsiz;
55710 + /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */
55711 + volatile uint32_t hcdma;
55712 + volatile uint32_t reserved;
55713 + /** Host Channel 0 DMA Buffer Address Register. <i>Offset: 500h + (chan_num * 20h) + 1Ch</i> */
55714 + volatile uint32_t hcdmab;
55715 +} dwc_otg_hc_regs_t;
55718 + * This union represents the bit fields in the Host Channel Characteristics
55719 + * Register. Read the register into the <i>d32</i> member then set/clear the
55720 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55721 + * hcchar register.
55723 +typedef union hcchar_data {
55724 + /** raw register data */
55727 + /** register bits */
55729 + /** Maximum packet size in bytes */
55732 + /** Endpoint number */
55733 + unsigned epnum:4;
55735 + /** 0: OUT, 1: IN */
55736 + unsigned epdir:1;
55738 + unsigned reserved:1;
55740 + /** 0: Full/high speed device, 1: Low speed device */
55741 + unsigned lspddev:1;
55743 + /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
55744 + unsigned eptype:2;
55746 + /** Packets per frame for periodic transfers. 0 is reserved. */
55747 + unsigned multicnt:2;
55749 + /** Device address */
55750 + unsigned devaddr:7;
55753 + * Frame to transmit periodic transaction.
55754 + * 0: even, 1: odd
55756 + unsigned oddfrm:1;
55758 + /** Channel disable */
55759 + unsigned chdis:1;
55761 + /** Channel enable */
55766 +typedef union hcsplt_data {
55767 + /** raw register data */
55770 + /** register bits */
55772 + /** Port Address */
55773 + unsigned prtaddr:7;
55775 + /** Hub Address */
55776 + unsigned hubaddr:7;
55778 + /** Transaction Position */
55779 + unsigned xactpos:2;
55780 +#define DWC_HCSPLIT_XACTPOS_MID 0
55781 +#define DWC_HCSPLIT_XACTPOS_END 1
55782 +#define DWC_HCSPLIT_XACTPOS_BEGIN 2
55783 +#define DWC_HCSPLIT_XACTPOS_ALL 3
55785 + /** Do Complete Split */
55786 + unsigned compsplt:1;
55789 + unsigned reserved:14;
55791 + /** Split Enble */
55792 + unsigned spltena:1;
55797 + * This union represents the bit fields in the Host All Interrupt
55800 +typedef union hcint_data {
55801 + /** raw register data */
55803 + /** register bits */
55805 + /** Transfer Complete */
55806 + unsigned xfercomp:1;
55807 + /** Channel Halted */
55808 + unsigned chhltd:1;
55810 + unsigned ahberr:1;
55811 + /** STALL Response Received */
55812 + unsigned stall:1;
55813 + /** NAK Response Received */
55815 + /** ACK Response Received */
55817 + /** NYET Response Received */
55819 + /** Transaction Err */
55820 + unsigned xacterr:1;
55821 + /** Babble Error */
55822 + unsigned bblerr:1;
55823 + /** Frame Overrun */
55824 + unsigned frmovrun:1;
55825 + /** Data Toggle Error */
55826 + unsigned datatglerr:1;
55827 + /** Buffer Not Available (only for DDMA mode) */
55829 + /** Exessive transaction error (only for DDMA mode) */
55830 + unsigned xcs_xact:1;
55831 + /** Frame List Rollover interrupt */
55832 + unsigned frm_list_roll:1;
55834 + unsigned reserved14_31:18;
55839 + * This union represents the bit fields in the Host Channel Interrupt Mask
55840 + * Register. Read the register into the <i>d32</i> member then set/clear the
55841 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55842 + * hcintmsk register.
55844 +typedef union hcintmsk_data {
55845 + /** raw register data */
55848 + /** register bits */
55850 + unsigned xfercompl:1;
55851 + unsigned chhltd:1;
55852 + unsigned ahberr:1;
55853 + unsigned stall:1;
55857 + unsigned xacterr:1;
55858 + unsigned bblerr:1;
55859 + unsigned frmovrun:1;
55860 + unsigned datatglerr:1;
55862 + unsigned xcs_xact:1;
55863 + unsigned frm_list_roll:1;
55864 + unsigned reserved14_31:18;
55866 +} hcintmsk_data_t;
55869 + * This union represents the bit fields in the Host Channel Transfer Size
55870 + * Register. Read the register into the <i>d32</i> member then set/clear the
55871 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55872 + * hcchar register.
55875 +typedef union hctsiz_data {
55876 + /** raw register data */
55879 + /** register bits */
55881 + /** Total transfer size in bytes */
55882 + unsigned xfersize:19;
55884 + /** Data packets to transfer */
55885 + unsigned pktcnt:10;
55888 + * Packet ID for next data packet
55892 + * 3: MDATA (non-Control), SETUP (Control)
55895 +#define DWC_HCTSIZ_DATA0 0
55896 +#define DWC_HCTSIZ_DATA1 2
55897 +#define DWC_HCTSIZ_DATA2 1
55898 +#define DWC_HCTSIZ_MDATA 3
55899 +#define DWC_HCTSIZ_SETUP 3
55901 + /** Do PING protocol when 1 */
55902 + unsigned dopng:1;
55905 + /** register bits */
55907 + /** Scheduling information */
55908 + unsigned schinfo:8;
55910 + /** Number of transfer descriptors.
55913 + * 256 only for HS isochronous endpoint.
55917 + /** Data packets to transfer */
55918 + unsigned reserved16_28:13;
55921 + * Packet ID for next data packet
55925 + * 3: MDATA (non-Control)
55929 + /** Do PING protocol when 1 */
55930 + unsigned dopng:1;
55935 + * This union represents the bit fields in the Host DMA Address
55936 + * Register used in Descriptor DMA mode.
55938 +typedef union hcdma_data {
55939 + /** raw register data */
55941 + /** register bits */
55943 + unsigned reserved0_2:3;
55944 + /** Current Transfer Descriptor. Not used for ISOC */
55946 + /** Start Address of Descriptor List */
55947 + unsigned dma_addr:21;
55952 + * This union represents the bit fields in the DMA Descriptor
55953 + * status quadlet for host mode. Read the quadlet into the <i>d32</i> member then
55954 + * set/clear the bits using the <i>b</i>it elements.
55956 +typedef union host_dma_desc_sts {
55957 + /** raw register data */
55959 + /** quadlet bits */
55961 + /* for non-isochronous */
55963 + /** Number of bytes */
55964 + unsigned n_bytes:17;
55965 + /** QTD offset to jump when Short Packet received - only for IN EPs */
55966 + unsigned qtd_offset:6;
55968 + * Set to request the core to jump to alternate QTD if
55969 + * Short Packet received - only for IN EPs
55971 + unsigned a_qtd:1;
55973 + * Setup Packet bit. When set indicates that buffer contains
55977 + /** Interrupt On Complete */
55979 + /** End of List */
55981 + unsigned reserved27:1;
55982 + /** Rx/Tx Status */
55984 +#define DMA_DESC_STS_PKTERR 1
55985 + unsigned reserved30:1;
55986 + /** Active Bit */
55989 + /* for isochronous */
55991 + /** Number of bytes */
55992 + unsigned n_bytes:12;
55993 + unsigned reserved12_24:13;
55994 + /** Interrupt On Complete */
55996 + unsigned reserved26_27:2;
55997 + /** Rx/Tx Status */
55999 + unsigned reserved30:1;
56000 + /** Active Bit */
56003 +} host_dma_desc_sts_t;
56005 +#define MAX_DMA_DESC_SIZE 131071
56006 +#define MAX_DMA_DESC_NUM_GENERIC 64
56007 +#define MAX_DMA_DESC_NUM_HS_ISOC 256
56008 +#define MAX_FRLIST_EN_NUM 64
56010 + * Host-mode DMA Descriptor structure
56012 + * DMA Descriptor structure contains two quadlets:
56013 + * Status quadlet and Data buffer pointer.
56015 +typedef struct dwc_otg_host_dma_desc {
56016 + /** DMA Descriptor status quadlet */
56017 + host_dma_desc_sts_t status;
56018 + /** DMA Descriptor data buffer pointer */
56020 +} dwc_otg_host_dma_desc_t;
56022 +/** OTG Host Interface Structure.
56024 + * The OTG Host Interface Structure structure contains information
56025 + * needed to manage the DWC_otg controller acting in host mode. It
56026 + * represents the programming view of the host-specific aspects of the
56029 +typedef struct dwc_otg_host_if {
56030 + /** Host Global Registers starting at offset 400h.*/
56031 + dwc_otg_host_global_regs_t *host_global_regs;
56032 +#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
56034 + /** Host Port 0 Control and Status Register */
56035 + volatile uint32_t *hprt0;
56036 +#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
56038 + /** Host Channel Specific Registers at offsets 500h-5FCh. */
56039 + dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS];
56040 +#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
56041 +#define DWC_OTG_CHAN_REGS_OFFSET 0x20
56043 + /* Host configuration information */
56044 + /** Number of Host Channels (range: 1-16) */
56045 + uint8_t num_host_channels;
56046 + /** Periodic EPs supported (0: no, 1: yes) */
56047 + uint8_t perio_eps_supported;
56048 + /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */
56049 + uint16_t perio_tx_fifo_size;
56051 +} dwc_otg_host_if_t;
56054 + * This union represents the bit fields in the Power and Clock Gating Control
56055 + * Register. Read the register into the <i>d32</i> member then set/clear the
56056 + * bits using the <i>b</i>it elements.
56058 +typedef union pcgcctl_data {
56059 + /** raw register data */
56062 + /** register bits */
56065 + unsigned stoppclk:1;
56067 + unsigned gatehclk:1;
56068 + /** Power Clamp */
56069 + unsigned pwrclmp:1;
56070 + /** Reset Power Down Modules */
56071 + unsigned rstpdwnmodule:1;
56073 + unsigned reserved:1;
56074 + /** Enable Sleep Clock Gating (Enbl_L1Gating) */
56075 + unsigned enbl_sleep_gating:1;
56076 + /** PHY In Sleep (PhySleep) */
56077 + unsigned phy_in_sleep:1;
56079 + unsigned deep_sleep:1;
56080 + unsigned resetaftsusp:1;
56081 + unsigned restoremode:1;
56082 + unsigned enbl_extnd_hiber:1;
56083 + unsigned extnd_hiber_pwrclmp:1;
56084 + unsigned extnd_hiber_switch:1;
56085 + unsigned ess_reg_restored:1;
56086 + unsigned prt_clk_sel:2;
56087 + unsigned port_power:1;
56088 + unsigned max_xcvrselect:2;
56089 + unsigned max_termsel:1;
56090 + unsigned mac_dev_addr:7;
56091 + unsigned p2hd_dev_enum_spd:2;
56092 + unsigned p2hd_prt_spd:2;
56093 + unsigned if_dev_mode:1;
56098 + * This union represents the bit fields in the Global Data FIFO Software
56099 + * Configuration Register. Read the register into the <i>d32</i> member then
56100 + * set/clear the bits using the <i>b</i>it elements.
56102 +typedef union gdfifocfg_data {
56103 + /* raw register data */
56105 + /** register bits */
56107 + /** OTG Data FIFO depth */
56108 + unsigned gdfifocfg:16;
56109 + /** Start address of EP info controller */
56110 + unsigned epinfobase:16;
56112 +} gdfifocfg_data_t;
56115 + * This union represents the bit fields in the Global Power Down Register
56116 + * Register. Read the register into the <i>d32</i> member then set/clear the
56117 + * bits using the <i>b</i>it elements.
56119 +typedef union gpwrdn_data {
56120 + /* raw register data */
56123 + /** register bits */
56125 + /** PMU Interrupt Select */
56126 + unsigned pmuintsel:1;
56127 + /** PMU Active */
56128 + unsigned pmuactv:1;
56130 + unsigned restore:1;
56131 + /** Power Down Clamp */
56132 + unsigned pwrdnclmp:1;
56133 + /** Power Down Reset */
56134 + unsigned pwrdnrstn:1;
56135 + /** Power Down Switch */
56136 + unsigned pwrdnswtch:1;
56137 + /** Disable VBUS */
56138 + unsigned dis_vbus:1;
56139 + /** Line State Change */
56140 + unsigned lnstschng:1;
56141 + /** Line state change mask */
56142 + unsigned lnstchng_msk:1;
56143 + /** Reset Detected */
56144 + unsigned rst_det:1;
56145 + /** Reset Detect mask */
56146 + unsigned rst_det_msk:1;
56147 + /** Disconnect Detected */
56148 + unsigned disconn_det:1;
56149 + /** Disconnect Detect mask */
56150 + unsigned disconn_det_msk:1;
56151 + /** Connect Detected*/
56152 + unsigned connect_det:1;
56153 + /** Connect Detected Mask*/
56154 + unsigned connect_det_msk:1;
56155 + /** SRP Detected */
56156 + unsigned srp_det:1;
56157 + /** SRP Detect mask */
56158 + unsigned srp_det_msk:1;
56159 + /** Status Change Interrupt */
56160 + unsigned sts_chngint:1;
56161 + /** Status Change Interrupt Mask */
56162 + unsigned sts_chngint_msk:1;
56163 + /** Line State */
56164 + unsigned linestate:2;
56165 + /** Indicates current mode(status of IDDIG signal) */
56166 + unsigned idsts:1;
56167 + /** B Session Valid signal status*/
56168 + unsigned bsessvld:1;
56169 + /** ADP Event Detected */
56170 + unsigned adp_int:1;
56171 + /** Multi Valued ID pin */
56172 + unsigned mult_val_id_bc:5;
56173 + /** Reserved 24_31 */
56174 + unsigned reserved29_31:3;
56180 +++ b/drivers/usb/host/dwc_otg/test/Makefile
56183 +PERL=/usr/bin/perl
56184 +PL_TESTS=test_sysfs.pl test_mod_param.pl
56191 + @echo Running perl tests
56192 + @for test in $(PL_TESTS); do \
56193 + if $(PERL) ./$$test ; then \
56194 + echo "=======> $$test, PASSED" ; \
56195 + else echo "=======> $$test, FAILED" ; \
56199 +++ b/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
56201 +package dwc_otg_test;
56206 +use vars qw(@ISA @EXPORT
56207 +$sysfsdir $paramdir $errors $params
56210 +@ISA = qw(Exporter);
56215 +$sysfsdir = "/sys/devices/lm0";
56216 +$paramdir = "/sys/module/dwc_otg";
56221 + NAME => "otg_cap",
56228 + NAME => "dma_enable",
56235 + NAME => "dma_burst_size",
56237 + ENUM => [1, 4, 8, 16, 32, 64, 128, 256],
56242 + NAME => "host_speed",
56249 + NAME => "host_support_fs_ls_low_power",
56256 + NAME => "host_ls_low_power_phy_clk",
56263 + NAME => "dev_speed",
56270 + NAME => "enable_dynamic_fifo",
56277 + NAME => "data_fifo_size",
56284 + NAME => "dev_rx_fifo_size",
56291 + NAME => "dev_nperio_tx_fifo_size",
56298 + NAME => "dev_perio_tx_fifo_size_1",
56305 + NAME => "dev_perio_tx_fifo_size_2",
56312 + NAME => "dev_perio_tx_fifo_size_3",
56319 + NAME => "dev_perio_tx_fifo_size_4",
56326 + NAME => "dev_perio_tx_fifo_size_5",
56333 + NAME => "dev_perio_tx_fifo_size_6",
56340 + NAME => "dev_perio_tx_fifo_size_7",
56347 + NAME => "dev_perio_tx_fifo_size_8",
56354 + NAME => "dev_perio_tx_fifo_size_9",
56361 + NAME => "dev_perio_tx_fifo_size_10",
56368 + NAME => "dev_perio_tx_fifo_size_11",
56375 + NAME => "dev_perio_tx_fifo_size_12",
56382 + NAME => "dev_perio_tx_fifo_size_13",
56389 + NAME => "dev_perio_tx_fifo_size_14",
56396 + NAME => "dev_perio_tx_fifo_size_15",
56403 + NAME => "host_rx_fifo_size",
56410 + NAME => "host_nperio_tx_fifo_size",
56417 + NAME => "host_perio_tx_fifo_size",
56424 + NAME => "max_transfer_size",
56425 + DEFAULT => 65535,
56431 + NAME => "max_packet_count",
56438 + NAME => "host_channels",
56445 + NAME => "dev_endpoints",
56452 + NAME => "phy_type",
56459 + NAME => "phy_utmi_width",
56466 + NAME => "phy_ulpi_ddr",
56480 + unless (m/armv4tl/) {
56481 + warn "# \n# Can't execute on $_. Run on integrator platform.\n# \n";
56490 + my $params = shift;
56491 + print "\nRemoving Module\n";
56492 + system "rmmod dwc_otg";
56493 + print "Loading Module\n";
56494 + if ($params ne "") {
56495 + print "Module Parameters: $params\n";
56497 + if (system("modprobe dwc_otg $params")) {
56498 + warn "Unable to load module\n";
56511 + if (defined $arg) {
56512 + warn "WARNING: $arg\n";
56515 + if ($errors > 0) {
56516 + warn "TEST FAILED with $errors errors\n";
56519 + print "TEST PASSED\n";
56520 + return 0 if (defined $arg);
56539 +++ b/drivers/usb/host/dwc_otg/test/test_mod_param.pl
56541 +#!/usr/bin/perl -w
56543 +# Run this program on the integrator.
56545 +# - Tests module parameter default values.
56546 +# - Tests setting of valid module parameter values via modprobe.
56547 +# - Tests invalid module parameter values.
56548 +# -----------------------------------------------------------------------------
56552 +check_arch() or die;
56557 + my ($param,$expected) = @_;
56558 + my $value = get($param);
56560 + if ($value == $expected) {
56561 + print "$param = $value, okay\n";
56565 + warn "ERROR: value of $param != $expected, $value\n";
56573 + my $param = shift;
56574 + my $tmp = `cat $paramdir/$param`;
56583 + print "\nTesting Module Parameters\n";
56585 + load_module("") or die;
56587 + # Test initial values
56588 + print "\nTesting Default Values\n";
56589 + foreach (@{$params}) {
56590 + test ($_->{NAME}, $_->{DEFAULT});
56594 + print "\nTesting Low Value\n";
56595 + my $cmd_params = "";
56596 + foreach (@{$params}) {
56597 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{LOW} ";
56599 + load_module($cmd_params) or die;
56601 + foreach (@{$params}) {
56602 + test ($_->{NAME}, $_->{LOW});
56605 + # Test high value
56606 + print "\nTesting High Value\n";
56607 + $cmd_params = "";
56608 + foreach (@{$params}) {
56609 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{HIGH} ";
56611 + load_module($cmd_params) or die;
56613 + foreach (@{$params}) {
56614 + test ($_->{NAME}, $_->{HIGH});
56618 + print "\nTesting Enumerated\n";
56619 + foreach (@{$params}) {
56620 + if (defined $_->{ENUM}) {
56622 + foreach $value (@{$_->{ENUM}}) {
56623 + $cmd_params = "$_->{NAME}=$value";
56624 + load_module($cmd_params) or die;
56625 + test ($_->{NAME}, $value);
56630 + # Test Invalid Values
56631 + print "\nTesting Invalid Values\n";
56632 + $cmd_params = "";
56633 + foreach (@{$params}) {
56634 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{LOW}-1;
56636 + load_module($cmd_params) or die;
56638 + foreach (@{$params}) {
56639 + test ($_->{NAME}, $_->{DEFAULT});
56642 + $cmd_params = "";
56643 + foreach (@{$params}) {
56644 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{HIGH}+1;
56646 + load_module($cmd_params) or die;
56648 + foreach (@{$params}) {
56649 + test ($_->{NAME}, $_->{DEFAULT});
56652 + print "\nTesting Enumerated\n";
56653 + foreach (@{$params}) {
56654 + if (defined $_->{ENUM}) {
56656 + foreach $value (@{$_->{ENUM}}) {
56657 + $value = $value + 1;
56658 + $cmd_params = "$_->{NAME}=$value";
56659 + load_module($cmd_params) or die;
56660 + test ($_->{NAME}, $_->{DEFAULT});
56661 + $value = $value - 2;
56662 + $cmd_params = "$_->{NAME}=$value";
56663 + load_module($cmd_params) or die;
56664 + test ($_->{NAME}, $_->{DEFAULT});
56669 + test_status() or die;
56675 +++ b/drivers/usb/host/dwc_otg/test/test_sysfs.pl
56677 +#!/usr/bin/perl -w
56679 +# Run this program on the integrator
56680 +# - Tests select sysfs attributes.
56681 +# - Todo ... test more attributes, hnp/srp, buspower/bussuspend, etc.
56682 +# -----------------------------------------------------------------------------
56686 +check_arch() or die;
56691 + my ($attr,$expected) = @_;
56692 + my $string = get($attr);
56694 + if ($string eq $expected) {
56695 + printf("$attr = $string, okay\n");
56698 + warn "ERROR: value of $attr != $expected, $string\n";
56706 + my ($reg, $value) = @_;
56707 + system "echo $value > $sysfsdir/$reg";
56713 + my $attr = shift;
56714 + my $string = `cat $sysfsdir/$attr`;
56716 + if ($string =~ m/\s\=\s/) {
56718 + ($tmp, $string) = split /\s=\s/, $string;
56726 + print("\nTesting Sysfs Attributes\n");
56728 + load_module("") or die;
56730 + # Test initial values of regoffset/regvalue/guid/gsnpsid
56731 + print("\nTesting Default Values\n");
56733 + test("regoffset", "0xffffffff");
56734 + test("regvalue", "invalid offset");
56735 + test("guid", "0x12345678"); # this will fail if it has been changed
56736 + test("gsnpsid", "0x4f54200a");
56738 + # Test operation of regoffset/regvalue
56739 + print("\nTesting regoffset\n");
56740 + set('regoffset', '5a5a5a5a');
56741 + test("regoffset", "0xffffffff");
56743 + set('regoffset', '0');
56744 + test("regoffset", "0x00000000");
56746 + set('regoffset', '40000');
56747 + test("regoffset", "0x00000000");
56749 + set('regoffset', '3ffff');
56750 + test("regoffset", "0x0003ffff");
56752 + set('regoffset', '1');
56753 + test("regoffset", "0x00000001");
56755 + print("\nTesting regvalue\n");
56756 + set('regoffset', '3c');
56757 + test("regvalue", "0x12345678");
56758 + set('regvalue', '5a5a5a5a');
56759 + test("regvalue", "0x5a5a5a5a");
56760 + set('regvalue','a5a5a5a5');
56761 + test("regvalue", "0xa5a5a5a5");
56762 + set('guid','12345678');
56764 + # Test HNP Capable
56765 + print("\nTesting HNP Capable bit\n");
56766 + set('hnpcapable', '1');
56767 + test("hnpcapable", "0x1");
56768 + set('hnpcapable','0');
56769 + test("hnpcapable", "0x0");
56771 + set('regoffset','0c');
56773 + my $old = get('gusbcfg');
56774 + print("setting hnpcapable\n");
56775 + set('hnpcapable', '1');
56776 + test("hnpcapable", "0x1");
56777 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<9)));
56778 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<9)));
56780 + $old = get('gusbcfg');
56781 + print("clearing hnpcapable\n");
56782 + set('hnpcapable', '0');
56783 + test("hnpcapable", "0x0");
56784 + test ('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<9)));
56785 + test ('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<9)));
56787 + # Test SRP Capable
56788 + print("\nTesting SRP Capable bit\n");
56789 + set('srpcapable', '1');
56790 + test("srpcapable", "0x1");
56791 + set('srpcapable','0');
56792 + test("srpcapable", "0x0");
56794 + set('regoffset','0c');
56796 + $old = get('gusbcfg');
56797 + print("setting srpcapable\n");
56798 + set('srpcapable', '1');
56799 + test("srpcapable", "0x1");
56800 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<8)));
56801 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<8)));
56803 + $old = get('gusbcfg');
56804 + print("clearing srpcapable\n");
56805 + set('srpcapable', '0');
56806 + test("srpcapable", "0x0");
56807 + test('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<8)));
56808 + test('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<8)));
56811 + print("\nTesting GGPIO\n");
56812 + set('ggpio','5a5a5a5a');
56813 + test('ggpio','0x5a5a0000');
56814 + set('ggpio','a5a5a5a5');
56815 + test('ggpio','0xa5a50000');
56816 + set('ggpio','11110000');
56817 + test('ggpio','0x11110000');
56818 + set('ggpio','00001111');
56819 + test('ggpio','0x00000000');
56822 + print("\nTesting DEVSPEED\n");
56823 + set('regoffset','800');
56824 + $old = get('regvalue');
56825 + set('devspeed','0');
56826 + test('devspeed','0x0');
56827 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
56828 + set('devspeed','1');
56829 + test('devspeed','0x1');
56830 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
56831 + set('devspeed','2');
56832 + test('devspeed','0x2');
56833 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 2));
56834 + set('devspeed','3');
56835 + test('devspeed','0x3');
56836 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 3));
56837 + set('devspeed','4');
56838 + test('devspeed','0x0');
56839 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
56840 + set('devspeed','5');
56841 + test('devspeed','0x1');
56842 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
56845 + # mode Returns the current mode:0 for device mode1 for host mode Read
56846 + # hnp Initiate the Host Negotiation Protocol. Read returns the status. Read/Write
56847 + # srp Initiate the Session Request Protocol. Read returns the status. Read/Write
56848 + # buspower Get or Set the Power State of the bus (0 - Off or 1 - On) Read/Write
56849 + # bussuspend Suspend the USB bus. Read/Write
56850 + # busconnected Get the connection status of the bus Read
56852 + # gotgctl Get or set the Core Control Status Register. Read/Write
56853 + ## gusbcfg Get or set the Core USB Configuration Register Read/Write
56854 + # grxfsiz Get or set the Receive FIFO Size Register Read/Write
56855 + # gnptxfsiz Get or set the non-periodic Transmit Size Register Read/Write
56856 + # gpvndctl Get or set the PHY Vendor Control Register Read/Write
56857 + ## ggpio Get the value in the lower 16-bits of the General Purpose IO Register or Set the upper 16 bits. Read/Write
56858 + ## guid Get or set the value of the User ID Register Read/Write
56859 + ## gsnpsid Get the value of the Synopsys ID Regester Read
56860 + ## devspeed Get or set the device speed setting in the DCFG register Read/Write
56861 + # enumspeed Gets the device enumeration Speed. Read
56862 + # hptxfsiz Get the value of the Host Periodic Transmit FIFO Read
56863 + # hprt0 Get or Set the value in the Host Port Control and Status Register Read/Write
56865 + test_status("TEST NYI") or die;