1 From 344d6f31638c96846ac26f40a74ee1cc495f421e Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Wed, 1 May 2013 19:46:17 +0100
4 Subject: [PATCH 002/196] Add dwc_otg driver
6 Signed-off-by: popcornmix <popcornmix@gmail.com>
8 drivers/usb/Makefile | 1 +
9 drivers/usb/core/generic.c | 1 +
10 drivers/usb/core/message.c | 79 +
11 drivers/usb/core/otg_whitelist.h | 172 +-
12 drivers/usb/gadget/file_storage.c | 3676 ++++++++++
13 drivers/usb/host/Kconfig | 13 +
14 drivers/usb/host/Makefile | 2 +
15 drivers/usb/host/dwc_common_port/Makefile | 58 +
16 drivers/usb/host/dwc_common_port/Makefile.fbsd | 17 +
17 drivers/usb/host/dwc_common_port/Makefile.linux | 49 +
18 drivers/usb/host/dwc_common_port/changes.txt | 174 +
19 drivers/usb/host/dwc_common_port/doc/doxygen.cfg | 270 +
20 drivers/usb/host/dwc_common_port/dwc_cc.c | 532 ++
21 drivers/usb/host/dwc_common_port/dwc_cc.h | 225 +
22 drivers/usb/host/dwc_common_port/dwc_common_fbsd.c | 1308 ++++
23 .../usb/host/dwc_common_port/dwc_common_linux.c | 1421 ++++
24 drivers/usb/host/dwc_common_port/dwc_common_nbsd.c | 1275 ++++
25 drivers/usb/host/dwc_common_port/dwc_crypto.c | 308 +
26 drivers/usb/host/dwc_common_port/dwc_crypto.h | 111 +
27 drivers/usb/host/dwc_common_port/dwc_dh.c | 291 +
28 drivers/usb/host/dwc_common_port/dwc_dh.h | 106 +
29 drivers/usb/host/dwc_common_port/dwc_list.h | 594 ++
30 drivers/usb/host/dwc_common_port/dwc_mem.c | 245 +
31 drivers/usb/host/dwc_common_port/dwc_modpow.c | 636 ++
32 drivers/usb/host/dwc_common_port/dwc_modpow.h | 34 +
33 drivers/usb/host/dwc_common_port/dwc_notifier.c | 319 +
34 drivers/usb/host/dwc_common_port/dwc_notifier.h | 122 +
35 drivers/usb/host/dwc_common_port/dwc_os.h | 1260 ++++
36 drivers/usb/host/dwc_common_port/usb.h | 946 +++
37 drivers/usb/host/dwc_otg/Makefile | 80 +
38 drivers/usb/host/dwc_otg/doc/doxygen.cfg | 224 +
39 drivers/usb/host/dwc_otg/dummy_audio.c | 1575 +++++
40 drivers/usb/host/dwc_otg/dwc_cfi_common.h | 142 +
41 drivers/usb/host/dwc_otg/dwc_otg_adp.c | 854 +++
42 drivers/usb/host/dwc_otg/dwc_otg_adp.h | 80 +
43 drivers/usb/host/dwc_otg/dwc_otg_attr.c | 1210 ++++
44 drivers/usb/host/dwc_otg/dwc_otg_attr.h | 89 +
45 drivers/usb/host/dwc_otg/dwc_otg_cfi.c | 1876 +++++
46 drivers/usb/host/dwc_otg/dwc_otg_cfi.h | 320 +
47 drivers/usb/host/dwc_otg/dwc_otg_cil.c | 7151 ++++++++++++++++++++
48 drivers/usb/host/dwc_otg/dwc_otg_cil.h | 1464 ++++
49 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 1563 +++++
50 drivers/usb/host/dwc_otg/dwc_otg_core_if.h | 705 ++
51 drivers/usb/host/dwc_otg/dwc_otg_dbg.h | 116 +
52 drivers/usb/host/dwc_otg/dwc_otg_driver.c | 1700 +++++
53 drivers/usb/host/dwc_otg/dwc_otg_driver.h | 86 +
54 drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 3473 ++++++++++
55 drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 824 +++
56 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 1133 ++++
57 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 412 ++
58 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2106 ++++++
59 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 893 +++
60 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 922 +++
61 drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 185 +
62 drivers/usb/host/dwc_otg/dwc_otg_pcd.c | 2708 ++++++++
63 drivers/usb/host/dwc_otg/dwc_otg_pcd.h | 266 +
64 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h | 360 +
65 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 5147 ++++++++++++++
66 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 1358 ++++
67 drivers/usb/host/dwc_otg/dwc_otg_regs.h | 2550 +++++++
68 drivers/usb/host/dwc_otg/test/Makefile | 16 +
69 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm | 337 +
70 drivers/usb/host/dwc_otg/test/test_mod_param.pl | 133 +
71 drivers/usb/host/dwc_otg/test/test_sysfs.pl | 193 +
72 64 files changed, 56447 insertions(+), 49 deletions(-)
73 create mode 100644 drivers/usb/gadget/file_storage.c
74 create mode 100644 drivers/usb/host/dwc_common_port/Makefile
75 create mode 100644 drivers/usb/host/dwc_common_port/Makefile.fbsd
76 create mode 100644 drivers/usb/host/dwc_common_port/Makefile.linux
77 create mode 100644 drivers/usb/host/dwc_common_port/changes.txt
78 create mode 100644 drivers/usb/host/dwc_common_port/doc/doxygen.cfg
79 create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.c
80 create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.h
81 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
82 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_linux.c
83 create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
84 create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.c
85 create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.h
86 create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.c
87 create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.h
88 create mode 100644 drivers/usb/host/dwc_common_port/dwc_list.h
89 create mode 100644 drivers/usb/host/dwc_common_port/dwc_mem.c
90 create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.c
91 create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.h
92 create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.c
93 create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.h
94 create mode 100644 drivers/usb/host/dwc_common_port/dwc_os.h
95 create mode 100644 drivers/usb/host/dwc_common_port/usb.h
96 create mode 100644 drivers/usb/host/dwc_otg/Makefile
97 create mode 100644 drivers/usb/host/dwc_otg/doc/doxygen.cfg
98 create mode 100644 drivers/usb/host/dwc_otg/dummy_audio.c
99 create mode 100644 drivers/usb/host/dwc_otg/dwc_cfi_common.h
100 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.c
101 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.h
102 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.c
103 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.h
104 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.c
105 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.h
106 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.c
107 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.h
108 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
109 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_core_if.h
110 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_dbg.h
111 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.c
112 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.h
113 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.c
114 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.h
115 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
116 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
117 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
118 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
119 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
120 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
121 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.c
122 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.h
123 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
124 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
125 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
126 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_regs.h
127 create mode 100644 drivers/usb/host/dwc_otg/test/Makefile
128 create mode 100644 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
129 create mode 100644 drivers/usb/host/dwc_otg/test/test_mod_param.pl
130 create mode 100644 drivers/usb/host/dwc_otg/test/test_sysfs.pl
132 diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
133 index c41feba..0b5c606 100644
134 --- a/drivers/usb/Makefile
135 +++ b/drivers/usb/Makefile
136 @@ -23,6 +23,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/
137 obj-$(CONFIG_USB_R8A66597_HCD) += host/
138 obj-$(CONFIG_USB_HWA_HCD) += host/
139 obj-$(CONFIG_USB_ISP1760_HCD) += host/
140 +obj-$(CONFIG_USB_DWCOTG) += host/
141 obj-$(CONFIG_USB_IMX21_HCD) += host/
142 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
144 diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
145 index acbfeb0..7d675c8 100644
146 --- a/drivers/usb/core/generic.c
147 +++ b/drivers/usb/core/generic.c
148 @@ -152,6 +152,7 @@ int usb_choose_configuration(struct usb_device *udev)
150 "no configuration chosen from %d choice%s\n",
151 num_configs, plural(num_configs));
152 + dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA);
156 diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
157 index 444d30e..3ff77fa 100644
158 --- a/drivers/usb/core/message.c
159 +++ b/drivers/usb/core/message.c
160 @@ -1875,6 +1875,85 @@ free_interfaces:
161 if (cp->string == NULL &&
162 !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
163 cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
164 +/* Uncomment this define to enable the HS Electrical Test support */
165 +#define DWC_HS_ELECT_TST 1
166 +#ifdef DWC_HS_ELECT_TST
167 + /* Here we implement the HS Electrical Test support. The
168 + * tester uses a vendor ID of 0x1A0A to indicate we should
169 + * run a special test sequence. The product ID tells us
170 + * which sequence to run. We invoke the test sequence by
171 + * sending a non-standard SetFeature command to our root
172 + * hub port. Our dwc_otg_hcd_hub_control() routine will
173 + * recognize the command and perform the desired test
176 + if (dev->descriptor.idVendor == 0x1A0A) {
177 + /* HSOTG Electrical Test */
178 + dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n");
180 + if (dev->bus && dev->bus->root_hub) {
181 + struct usb_device *hdev = dev->bus->root_hub;
182 + dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct);
184 + switch (dev->descriptor.idProduct) {
185 + case 0x0101: /* TEST_SE0_NAK */
186 + dev_warn(&dev->dev, "TEST_SE0_NAK\n");
187 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
188 + USB_REQ_SET_FEATURE, USB_RT_PORT,
189 + USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ);
192 + case 0x0102: /* TEST_J */
193 + dev_warn(&dev->dev, "TEST_J\n");
194 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
195 + USB_REQ_SET_FEATURE, USB_RT_PORT,
196 + USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ);
199 + case 0x0103: /* TEST_K */
200 + dev_warn(&dev->dev, "TEST_K\n");
201 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
202 + USB_REQ_SET_FEATURE, USB_RT_PORT,
203 + USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ);
206 + case 0x0104: /* TEST_PACKET */
207 + dev_warn(&dev->dev, "TEST_PACKET\n");
208 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
209 + USB_REQ_SET_FEATURE, USB_RT_PORT,
210 + USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ);
213 + case 0x0105: /* TEST_FORCE_ENABLE */
214 + dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n");
215 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
216 + USB_REQ_SET_FEATURE, USB_RT_PORT,
217 + USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ);
220 + case 0x0106: /* HS_HOST_PORT_SUSPEND_RESUME */
221 + dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n");
222 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
223 + USB_REQ_SET_FEATURE, USB_RT_PORT,
224 + USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ);
227 + case 0x0107: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
228 + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n");
229 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
230 + USB_REQ_SET_FEATURE, USB_RT_PORT,
231 + USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ);
234 + case 0x0108: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
235 + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n");
236 + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
237 + USB_REQ_SET_FEATURE, USB_RT_PORT,
238 + USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ);
242 +#endif /* DWC_HS_ELECT_TST */
244 /* Now that the interfaces are installed, re-enable LPM. */
245 usb_unlocked_enable_lpm(dev);
246 diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
247 index e8cdce5..3a0da17 100644
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 @@ -55,58 +104,83 @@ static int is_targeted(struct usb_device *dev)
342 /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
343 - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
344 - le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
347 - /* NOTE: can't use usb_match_id() since interface caches
348 - * aren't set up yet. this is cut/paste from that code.
350 - for (id = whitelist_table; id->match_flags; id++) {
351 - if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
352 - id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
355 - if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
356 - id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
359 - /* No need to test id->bcdDevice_lo != 0, since 0 is never
360 - greater than any unsigned number. */
361 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
362 - (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
365 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
366 - (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
369 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
370 - (id->bDeviceClass != dev->descriptor.bDeviceClass))
373 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
374 - (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
377 - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
378 - (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
380 + if (dev->descriptor.idVendor == 0x1a0a &&
381 + dev->descriptor.idProduct == 0xbadd) {
383 + } else if (!enable_whitelist) {
388 + dev_dbg(&dev->dev, "device V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
389 + dev->descriptor.idVendor,
390 + dev->descriptor.idProduct,
391 + dev->descriptor.bDeviceClass,
392 + dev->descriptor.bDeviceSubClass,
393 + dev->descriptor.bDeviceProtocol);
397 + /* NOTE: can't use usb_match_id() since interface caches
398 + * aren't set up yet. this is cut/paste from that code.
400 + for (id = whitelist_table; id->match_flags; id++) {
403 + "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
407 + id->bDeviceSubClass,
408 + id->bDeviceProtocol);
411 + if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
412 + id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
415 + if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
416 + id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
419 + /* No need to test id->bcdDevice_lo != 0, since 0 is never
420 + greater than any unsigned number. */
421 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
422 + (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
425 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
426 + (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
429 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
430 + (id->bDeviceClass != dev->descriptor.bDeviceClass))
433 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
434 + (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
437 + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
438 + (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
445 /* add other match criteria here ... */
448 - /* OTG MESSAGE: report errors here, customize to match your product */
449 - dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
450 - le16_to_cpu(dev->descriptor.idVendor),
451 - le16_to_cpu(dev->descriptor.idProduct));
452 #ifdef CONFIG_USB_OTG_WHITELIST
453 + report_errors(dev);
457 + if (enable_whitelist) {
458 + report_errors(dev);
466 diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
468 index 0000000..a896d73
470 +++ b/drivers/usb/gadget/file_storage.c
473 + * file_storage.c -- File-backed USB Storage Gadget, for USB development
475 + * Copyright (C) 2003-2008 Alan Stern
476 + * All rights reserved.
478 + * Redistribution and use in source and binary forms, with or without
479 + * modification, are permitted provided that the following conditions
481 + * 1. Redistributions of source code must retain the above copyright
482 + * notice, this list of conditions, and the following disclaimer,
483 + * without modification.
484 + * 2. Redistributions in binary form must reproduce the above copyright
485 + * notice, this list of conditions and the following disclaimer in the
486 + * documentation and/or other materials provided with the distribution.
487 + * 3. The names of the above-listed copyright holders may not be used
488 + * to endorse or promote products derived from this software without
489 + * specific prior written permission.
491 + * ALTERNATIVELY, this software may be distributed under the terms of the
492 + * GNU General Public License ("GPL") as published by the Free Software
493 + * Foundation, either version 2 of that License or (at your option) any
496 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
497 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
498 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
499 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
500 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
501 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
502 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
503 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
504 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
505 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
506 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
511 + * The File-backed Storage Gadget acts as a USB Mass Storage device,
512 + * appearing to the host as a disk drive or as a CD-ROM drive. In addition
513 + * to providing an example of a genuinely useful gadget driver for a USB
514 + * device, it also illustrates a technique of double-buffering for increased
515 + * throughput. Last but not least, it gives an easy way to probe the
516 + * behavior of the Mass Storage drivers in a USB host.
518 + * Backing storage is provided by a regular file or a block device, specified
519 + * by the "file" module parameter. Access can be limited to read-only by
520 + * setting the optional "ro" module parameter. (For CD-ROM emulation,
521 + * access is always read-only.) The gadget will indicate that it has
522 + * removable media if the optional "removable" module parameter is set.
524 + * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
525 + * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
526 + * by the optional "transport" module parameter. It also supports the
527 + * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
528 + * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
529 + * the optional "protocol" module parameter. In addition, the default
530 + * Vendor ID, Product ID, release number and serial number can be overridden.
532 + * There is support for multiple logical units (LUNs), each of which has
533 + * its own backing file. The number of LUNs can be set using the optional
534 + * "luns" module parameter (anywhere from 1 to 8), and the corresponding
535 + * files are specified using comma-separated lists for "file" and "ro".
536 + * The default number of LUNs is taken from the number of "file" elements;
537 + * it is 1 if "file" is not given. If "removable" is not set then a backing
538 + * file must be specified for each LUN. If it is set, then an unspecified
539 + * or empty backing filename means the LUN's medium is not loaded. Ideally
540 + * each LUN would be settable independently as a disk drive or a CD-ROM
541 + * drive, but currently all LUNs have to be the same type. The CD-ROM
542 + * emulation includes a single data track and no audio tracks; hence there
543 + * need be only one backing file per LUN.
545 + * Requirements are modest; only a bulk-in and a bulk-out endpoint are
546 + * needed (an interrupt-out endpoint is also needed for CBI). The memory
547 + * requirement amounts to two 16K buffers, size configurable by a parameter.
548 + * Support is included for both full-speed and high-speed operation.
550 + * Note that the driver is slightly non-portable in that it assumes a
551 + * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
552 + * interrupt-in endpoints. With most device controllers this isn't an
553 + * issue, but there may be some with hardware restrictions that prevent
554 + * a buffer from being used by more than one endpoint.
558 + * file=filename[,filename...]
559 + * Required if "removable" is not set, names of
560 + * the files or block devices used for
562 + * serial=HHHH... Required serial number (string of hex chars)
563 + * ro=b[,b...] Default false, booleans for read-only access
564 + * removable Default false, boolean for removable media
565 + * luns=N Default N = number of filenames, number of
567 + * nofua=b[,b...] Default false, booleans for ignore FUA flag
568 + * in SCSI WRITE(10,12) commands
569 + * stall Default determined according to the type of
570 + * USB device controller (usually true),
571 + * boolean to permit the driver to halt
573 + * cdrom Default false, boolean for whether to emulate
575 + * transport=XXX Default BBB, transport name (CB, CBI, or BBB)
576 + * protocol=YYY Default SCSI, protocol name (RBC, 8020 or
577 + * ATAPI, QIC, UFI, 8070, or SCSI;
579 + * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
580 + * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
581 + * release=0xRRRR Override the USB release number (bcdDevice)
582 + * buflen=N Default N=16384, buffer size used (will be
583 + * rounded down to a multiple of
586 + * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro",
587 + * "removable", "luns", "nofua", "stall", and "cdrom" options are available;
588 + * default values are used for everything else.
590 + * The pathnames of the backing files and the ro settings are available in
591 + * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of
592 + * the gadget's sysfs directory. If the "removable" option is set, writing to
593 + * these files will simulate ejecting/loading the medium (writing an empty
594 + * line means eject) and adjusting a write-enable tab. Changes to the ro
595 + * setting are not allowed when the medium is loaded or if CD-ROM emulation
598 + * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
599 + * The driver's SCSI command interface was based on the "Information
600 + * technology - Small Computer System Interface - 2" document from
601 + * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at
602 + * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception
603 + * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the
604 + * "Universal Serial Bus Mass Storage Class UFI Command Specification"
605 + * document, Revision 1.0, December 14, 1998, available at
606 + * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
613 + * The FSG driver is fairly straightforward. There is a main kernel
614 + * thread that handles most of the work. Interrupt routines field
615 + * callbacks from the controller driver: bulk- and interrupt-request
616 + * completion notifications, endpoint-0 events, and disconnect events.
617 + * Completion events are passed to the main thread by wakeup calls. Many
618 + * ep0 requests are handled at interrupt time, but SetInterface,
619 + * SetConfiguration, and device reset requests are forwarded to the
620 + * thread in the form of "exceptions" using SIGUSR1 signals (since they
621 + * should interrupt any ongoing file I/O operations).
623 + * The thread's main routine implements the standard command/data/status
624 + * parts of a SCSI interaction. It and its subroutines are full of tests
625 + * for pending signals/exceptions -- all this polling is necessary since
626 + * the kernel has no setjmp/longjmp equivalents. (Maybe this is an
627 + * indication that the driver really wants to be running in userspace.)
628 + * An important point is that so long as the thread is alive it keeps an
629 + * open reference to the backing file. This will prevent unmounting
630 + * the backing file's underlying filesystem and could cause problems
631 + * during system shutdown, for example. To prevent such problems, the
632 + * thread catches INT, TERM, and KILL signals and converts them into
633 + * an EXIT exception.
635 + * In normal operation the main thread is started during the gadget's
636 + * fsg_bind() callback and stopped during fsg_unbind(). But it can also
637 + * exit when it receives a signal, and there's no point leaving the
638 + * gadget running when the thread is dead. So just before the thread
639 + * exits, it deregisters the gadget driver. This makes things a little
640 + * tricky: The driver is deregistered at two places, and the exiting
641 + * thread can indirectly call fsg_unbind() which in turn can tell the
642 + * thread to exit. The first problem is resolved through the use of the
643 + * REGISTERED atomic bitflag; the driver will only be deregistered once.
644 + * The second problem is resolved by having fsg_unbind() check
645 + * fsg->state; it won't try to stop the thread if the state is already
646 + * FSG_STATE_TERMINATED.
648 + * To provide maximum throughput, the driver uses a circular pipeline of
649 + * buffer heads (struct fsg_buffhd). In principle the pipeline can be
650 + * arbitrarily long; in practice the benefits don't justify having more
651 + * than 2 stages (i.e., double buffering). But it helps to think of the
652 + * pipeline as being a long one. Each buffer head contains a bulk-in and
653 + * a bulk-out request pointer (since the buffer can be used for both
654 + * output and input -- directions always are given from the host's
655 + * point of view) as well as a pointer to the buffer and various state
658 + * Use of the pipeline follows a simple protocol. There is a variable
659 + * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
660 + * At any time that buffer head may still be in use from an earlier
661 + * request, so each buffer head has a state variable indicating whether
662 + * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the
663 + * buffer head to be EMPTY, filling the buffer either by file I/O or by
664 + * USB I/O (during which the buffer head is BUSY), and marking the buffer
665 + * head FULL when the I/O is complete. Then the buffer will be emptied
666 + * (again possibly by USB I/O, during which it is marked BUSY) and
667 + * finally marked EMPTY again (possibly by a completion routine).
669 + * A module parameter tells the driver to avoid stalling the bulk
670 + * endpoints wherever the transport specification allows. This is
671 + * necessary for some UDCs like the SuperH, which cannot reliably clear a
672 + * halt on a bulk endpoint. However, under certain circumstances the
673 + * Bulk-only specification requires a stall. In such cases the driver
674 + * will halt the endpoint and set a flag indicating that it should clear
675 + * the halt in software during the next device reset. Hopefully this
676 + * will permit everything to work correctly. Furthermore, although the
677 + * specification allows the bulk-out endpoint to halt when the host sends
678 + * too much data, implementing this would cause an unavoidable race.
679 + * The driver will always use the "no-stall" approach for OUT transfers.
681 + * One subtle point concerns sending status-stage responses for ep0
682 + * requests. Some of these requests, such as device reset, can involve
683 + * interrupting an ongoing file I/O operation, which might take an
684 + * arbitrarily long time. During that delay the host might give up on
685 + * the original ep0 request and issue a new one. When that happens the
686 + * driver should not notify the host about completion of the original
687 + * request, as the host will no longer be waiting for it. So the driver
688 + * assigns to each ep0 request a unique tag, and it keeps track of the
689 + * tag value of the request associated with a long-running exception
690 + * (device-reset, interface-change, or configuration-change). When the
691 + * exception handler is finished, the status-stage response is submitted
692 + * only if the current ep0 request tag is equal to the exception request
693 + * tag. Thus only the most recently received ep0 request will get a
694 + * status-stage response.
696 + * Warning: This driver source file is too long. It ought to be split up
697 + * into a header file plus about 3 separate .c files, to handle the details
698 + * of the Gadget, USB Mass Storage, and SCSI protocols.
702 +/* #define VERBOSE_DEBUG */
703 +/* #define DUMP_MSGS */
706 +#include <linux/blkdev.h>
707 +#include <linux/completion.h>
708 +#include <linux/dcache.h>
709 +#include <linux/delay.h>
710 +#include <linux/device.h>
711 +#include <linux/fcntl.h>
712 +#include <linux/file.h>
713 +#include <linux/fs.h>
714 +#include <linux/kref.h>
715 +#include <linux/kthread.h>
716 +#include <linux/limits.h>
717 +#include <linux/module.h>
718 +#include <linux/rwsem.h>
719 +#include <linux/slab.h>
720 +#include <linux/spinlock.h>
721 +#include <linux/string.h>
722 +#include <linux/freezer.h>
723 +#include <linux/utsname.h>
725 +#include <linux/usb/ch9.h>
726 +#include <linux/usb/gadget.h>
728 +#include "gadget_chips.h"
733 + * Kbuild is not very cooperative with respect to linking separately
734 + * compiled library objects into one module. So for now we won't use
735 + * separate compilation ... ensuring init/exit sections work to shrink
736 + * the runtime footprint, and giving us at least some parts of what
737 + * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
739 +#include "usbstring.c"
741 +#include "epautoconf.c"
743 +/*-------------------------------------------------------------------------*/
745 +#define DRIVER_DESC "File-backed Storage Gadget"
746 +#define DRIVER_NAME "g_file_storage"
747 +#define DRIVER_VERSION "1 September 2010"
749 +static char fsg_string_manufacturer[64];
750 +static const char fsg_string_product[] = DRIVER_DESC;
751 +static const char fsg_string_config[] = "Self-powered";
752 +static const char fsg_string_interface[] = "Mass Storage";
755 +#include "storage_common.c"
758 +MODULE_DESCRIPTION(DRIVER_DESC);
759 +MODULE_AUTHOR("Alan Stern");
760 +MODULE_LICENSE("Dual BSD/GPL");
763 + * This driver assumes self-powered hardware and has no way for users to
764 + * trigger remote wakeup. It uses autoconfiguration to select endpoints
765 + * and endpoint addresses.
769 +/*-------------------------------------------------------------------------*/
772 +/* Encapsulate the module parameter settings */
775 + char *file[FSG_MAX_LUNS];
777 + bool ro[FSG_MAX_LUNS];
778 + bool nofua[FSG_MAX_LUNS];
779 + unsigned int num_filenames;
780 + unsigned int num_ros;
781 + unsigned int num_nofuas;
782 + unsigned int nluns;
788 + char *transport_parm;
789 + char *protocol_parm;
790 + unsigned short vendor;
791 + unsigned short product;
792 + unsigned short release;
793 + unsigned int buflen;
795 + int transport_type;
796 + char *transport_name;
798 + char *protocol_name;
800 +} mod_data = { // Default values
801 + .transport_parm = "BBB",
802 + .protocol_parm = "SCSI",
806 + .vendor = FSG_VENDOR_ID,
807 + .product = FSG_PRODUCT_ID,
808 + .release = 0xffff, // Use controller chip type
813 +module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
815 +MODULE_PARM_DESC(file, "names of backing files or devices");
817 +module_param_named(serial, mod_data.serial, charp, S_IRUGO);
818 +MODULE_PARM_DESC(serial, "USB serial number");
820 +module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
821 +MODULE_PARM_DESC(ro, "true to force read-only");
823 +module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas,
825 +MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit");
827 +module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
828 +MODULE_PARM_DESC(luns, "number of LUNs");
830 +module_param_named(removable, mod_data.removable, bool, S_IRUGO);
831 +MODULE_PARM_DESC(removable, "true to simulate removable media");
833 +module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
834 +MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
836 +module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
837 +MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
839 +/* In the non-TEST version, only the module parameters listed above
840 + * are available. */
841 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
843 +module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO);
844 +MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");
846 +module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO);
847 +MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, "
850 +module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO);
851 +MODULE_PARM_DESC(vendor, "USB Vendor ID");
853 +module_param_named(product, mod_data.product, ushort, S_IRUGO);
854 +MODULE_PARM_DESC(product, "USB Product ID");
856 +module_param_named(release, mod_data.release, ushort, S_IRUGO);
857 +MODULE_PARM_DESC(release, "USB release number");
859 +module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
860 +MODULE_PARM_DESC(buflen, "I/O buffer size");
862 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
866 + * These definitions will permit the compiler to avoid generating code for
867 + * parts of the driver that aren't used in the non-TEST version. Even gcc
868 + * can recognize when a test of a constant expression yields a dead code
872 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
874 +#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK)
875 +#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI)
876 +#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI)
880 +#define transport_is_bbb() 1
881 +#define transport_is_cbi() 0
882 +#define protocol_is_scsi() 1
884 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
887 +/*-------------------------------------------------------------------------*/
891 + /* lock protects: state, all the req_busy's, and cbbuf_cmnd */
893 + struct usb_gadget *gadget;
895 + /* filesem protects: backing files in use */
896 + struct rw_semaphore filesem;
898 + /* reference counting: wait until all LUNs are released */
901 + struct usb_ep *ep0; // Handy copy of gadget->ep0
902 + struct usb_request *ep0req; // For control responses
903 + unsigned int ep0_req_tag;
904 + const char *ep0req_name;
906 + struct usb_request *intreq; // For interrupt responses
908 + struct fsg_buffhd *intr_buffhd;
910 + unsigned int bulk_out_maxpacket;
911 + enum fsg_state state; // For exception handling
912 + unsigned int exception_req_tag;
914 + u8 config, new_config;
916 + unsigned int running : 1;
917 + unsigned int bulk_in_enabled : 1;
918 + unsigned int bulk_out_enabled : 1;
919 + unsigned int intr_in_enabled : 1;
920 + unsigned int phase_error : 1;
921 + unsigned int short_packet_received : 1;
922 + unsigned int bad_lun_okay : 1;
924 + unsigned long atomic_bitflags;
925 +#define REGISTERED 0
926 +#define IGNORE_BULK_OUT 1
929 + struct usb_ep *bulk_in;
930 + struct usb_ep *bulk_out;
931 + struct usb_ep *intr_in;
933 + struct fsg_buffhd *next_buffhd_to_fill;
934 + struct fsg_buffhd *next_buffhd_to_drain;
936 + int thread_wakeup_needed;
937 + struct completion thread_notifier;
938 + struct task_struct *thread_task;
941 + u8 cmnd[MAX_COMMAND_SIZE];
942 + enum data_direction data_dir;
944 + u32 data_size_from_cmnd;
948 + u32 usb_amount_left;
950 + /* The CB protocol offers no way for a host to know when a command
951 + * has completed. As a result the next command may arrive early,
952 + * and we will still have to handle it. For that reason we need
953 + * a buffer to store new commands when using CB (or CBI, which
954 + * does not oblige a host to wait for command completion either). */
955 + int cbbuf_cmnd_size;
956 + u8 cbbuf_cmnd[MAX_COMMAND_SIZE];
958 + unsigned int nluns;
959 + struct fsg_lun *luns;
960 + struct fsg_lun *curlun;
961 + /* Must be the last entry */
962 + struct fsg_buffhd buffhds[];
965 +typedef void (*fsg_routine_t)(struct fsg_dev *);
967 +static int exception_in_progress(struct fsg_dev *fsg)
969 + return (fsg->state > FSG_STATE_IDLE);
972 +/* Make bulk-out requests be divisible by the maxpacket size */
973 +static void set_bulk_out_req_length(struct fsg_dev *fsg,
974 + struct fsg_buffhd *bh, unsigned int length)
978 + bh->bulk_out_intended_length = length;
979 + rem = length % fsg->bulk_out_maxpacket;
981 + length += fsg->bulk_out_maxpacket - rem;
982 + bh->outreq->length = length;
985 +static struct fsg_dev *the_fsg;
986 +static struct usb_gadget_driver fsg_driver;
989 +/*-------------------------------------------------------------------------*/
991 +static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
995 + if (ep == fsg->bulk_in)
997 + else if (ep == fsg->bulk_out)
1001 + DBG(fsg, "%s set halt\n", name);
1002 + return usb_ep_set_halt(ep);
1006 +/*-------------------------------------------------------------------------*/
1009 + * DESCRIPTORS ... most are static, but strings and (full) configuration
1010 + * descriptors are built on demand. Also the (static) config and interface
1011 + * descriptors are adjusted during fsg_bind().
1014 +/* There is only one configuration. */
1015 +#define CONFIG_VALUE 1
1017 +static struct usb_device_descriptor
1019 + .bLength = sizeof device_desc,
1020 + .bDescriptorType = USB_DT_DEVICE,
1022 + .bcdUSB = cpu_to_le16(0x0200),
1023 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
1025 + /* The next three values can be overridden by module parameters */
1026 + .idVendor = cpu_to_le16(FSG_VENDOR_ID),
1027 + .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
1028 + .bcdDevice = cpu_to_le16(0xffff),
1030 + .iManufacturer = FSG_STRING_MANUFACTURER,
1031 + .iProduct = FSG_STRING_PRODUCT,
1032 + .iSerialNumber = FSG_STRING_SERIAL,
1033 + .bNumConfigurations = 1,
1036 +static struct usb_config_descriptor
1038 + .bLength = sizeof config_desc,
1039 + .bDescriptorType = USB_DT_CONFIG,
1041 + /* wTotalLength computed by usb_gadget_config_buf() */
1042 + .bNumInterfaces = 1,
1043 + .bConfigurationValue = CONFIG_VALUE,
1044 + .iConfiguration = FSG_STRING_CONFIG,
1045 + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
1046 + .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
1050 +static struct usb_qualifier_descriptor
1052 + .bLength = sizeof dev_qualifier,
1053 + .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
1055 + .bcdUSB = cpu_to_le16(0x0200),
1056 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
1058 + .bNumConfigurations = 1,
1061 +static int populate_bos(struct fsg_dev *fsg, u8 *buf)
1063 + memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
1064 + buf += USB_DT_BOS_SIZE;
1066 + memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
1067 + buf += USB_DT_USB_EXT_CAP_SIZE;
1069 + memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
1071 + return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
1072 + + USB_DT_USB_EXT_CAP_SIZE;
1076 + * Config descriptors must agree with the code that sets configurations
1077 + * and with code managing interfaces and their altsettings. They must
1078 + * also handle different speeds and other-speed requests.
1080 +static int populate_config_buf(struct usb_gadget *gadget,
1081 + u8 *buf, u8 type, unsigned index)
1083 + enum usb_device_speed speed = gadget->speed;
1085 + const struct usb_descriptor_header **function;
1090 + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
1091 + speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
1092 + function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH
1093 + ? (const struct usb_descriptor_header **)fsg_hs_function
1094 + : (const struct usb_descriptor_header **)fsg_fs_function;
1096 + /* for now, don't advertise srp-only devices */
1097 + if (!gadget_is_otg(gadget))
1100 + len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
1101 + ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
1106 +/*-------------------------------------------------------------------------*/
1108 +/* These routines may be called in process context or in_irq */
1110 +/* Caller must hold fsg->lock */
1111 +static void wakeup_thread(struct fsg_dev *fsg)
1113 + /* Tell the main thread that something has happened */
1114 + fsg->thread_wakeup_needed = 1;
1115 + if (fsg->thread_task)
1116 + wake_up_process(fsg->thread_task);
1120 +static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
1122 + unsigned long flags;
1124 + /* Do nothing if a higher-priority exception is already in progress.
1125 + * If a lower-or-equal priority exception is in progress, preempt it
1126 + * and notify the main thread by sending it a signal. */
1127 + spin_lock_irqsave(&fsg->lock, flags);
1128 + if (fsg->state <= new_state) {
1129 + fsg->exception_req_tag = fsg->ep0_req_tag;
1130 + fsg->state = new_state;
1131 + if (fsg->thread_task)
1132 + send_sig_info(SIGUSR1, SEND_SIG_FORCED,
1133 + fsg->thread_task);
1135 + spin_unlock_irqrestore(&fsg->lock, flags);
1139 +/*-------------------------------------------------------------------------*/
1141 +/* The disconnect callback and ep0 routines. These always run in_irq,
1142 + * except that ep0_queue() is called in the main thread to acknowledge
1143 + * completion of various requests: set config, set interface, and
1144 + * Bulk-only device reset. */
1146 +static void fsg_disconnect(struct usb_gadget *gadget)
1148 + struct fsg_dev *fsg = get_gadget_data(gadget);
1150 + DBG(fsg, "disconnect or port reset\n");
1151 + raise_exception(fsg, FSG_STATE_DISCONNECT);
1155 +static int ep0_queue(struct fsg_dev *fsg)
1159 + rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
1160 + if (rc != 0 && rc != -ESHUTDOWN) {
1162 + /* We can't do much more than wait for a reset */
1163 + WARNING(fsg, "error in submission: %s --> %d\n",
1164 + fsg->ep0->name, rc);
1169 +static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
1171 + struct fsg_dev *fsg = ep->driver_data;
1173 + if (req->actual > 0)
1174 + dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
1175 + if (req->status || req->actual != req->length)
1176 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1177 + req->status, req->actual, req->length);
1178 + if (req->status == -ECONNRESET) // Request was cancelled
1179 + usb_ep_fifo_flush(ep);
1181 + if (req->status == 0 && req->context)
1182 + ((fsg_routine_t) (req->context))(fsg);
1186 +/*-------------------------------------------------------------------------*/
1188 +/* Bulk and interrupt endpoint completion handlers.
1189 + * These always run in_irq. */
1191 +static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
1193 + struct fsg_dev *fsg = ep->driver_data;
1194 + struct fsg_buffhd *bh = req->context;
1196 + if (req->status || req->actual != req->length)
1197 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1198 + req->status, req->actual, req->length);
1199 + if (req->status == -ECONNRESET) // Request was cancelled
1200 + usb_ep_fifo_flush(ep);
1202 + /* Hold the lock while we update the request and buffer states */
1204 + spin_lock(&fsg->lock);
1205 + bh->inreq_busy = 0;
1206 + bh->state = BUF_STATE_EMPTY;
1207 + wakeup_thread(fsg);
1208 + spin_unlock(&fsg->lock);
1211 +static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
1213 + struct fsg_dev *fsg = ep->driver_data;
1214 + struct fsg_buffhd *bh = req->context;
1216 + dump_msg(fsg, "bulk-out", req->buf, req->actual);
1217 + if (req->status || req->actual != bh->bulk_out_intended_length)
1218 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1219 + req->status, req->actual,
1220 + bh->bulk_out_intended_length);
1221 + if (req->status == -ECONNRESET) // Request was cancelled
1222 + usb_ep_fifo_flush(ep);
1224 + /* Hold the lock while we update the request and buffer states */
1226 + spin_lock(&fsg->lock);
1227 + bh->outreq_busy = 0;
1228 + bh->state = BUF_STATE_FULL;
1229 + wakeup_thread(fsg);
1230 + spin_unlock(&fsg->lock);
1234 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
1235 +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
1237 + struct fsg_dev *fsg = ep->driver_data;
1238 + struct fsg_buffhd *bh = req->context;
1240 + if (req->status || req->actual != req->length)
1241 + DBG(fsg, "%s --> %d, %u/%u\n", __func__,
1242 + req->status, req->actual, req->length);
1243 + if (req->status == -ECONNRESET) // Request was cancelled
1244 + usb_ep_fifo_flush(ep);
1246 + /* Hold the lock while we update the request and buffer states */
1248 + spin_lock(&fsg->lock);
1249 + fsg->intreq_busy = 0;
1250 + bh->state = BUF_STATE_EMPTY;
1251 + wakeup_thread(fsg);
1252 + spin_unlock(&fsg->lock);
1256 +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
1258 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
1261 +/*-------------------------------------------------------------------------*/
1263 +/* Ep0 class-specific handlers. These always run in_irq. */
1265 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
1266 +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1268 + struct usb_request *req = fsg->ep0req;
1269 + static u8 cbi_reset_cmnd[6] = {
1270 + SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
1272 + /* Error in command transfer? */
1273 + if (req->status || req->length != req->actual ||
1274 + req->actual < 6 || req->actual > MAX_COMMAND_SIZE) {
1276 + /* Not all controllers allow a protocol stall after
1277 + * receiving control-out data, but we'll try anyway. */
1278 + fsg_set_halt(fsg, fsg->ep0);
1279 + return; // Wait for reset
1282 + /* Is it the special reset command? */
1283 + if (req->actual >= sizeof cbi_reset_cmnd &&
1284 + memcmp(req->buf, cbi_reset_cmnd,
1285 + sizeof cbi_reset_cmnd) == 0) {
1287 + /* Raise an exception to stop the current operation
1288 + * and reinitialize our state. */
1289 + DBG(fsg, "cbi reset request\n");
1290 + raise_exception(fsg, FSG_STATE_RESET);
1294 + VDBG(fsg, "CB[I] accept device-specific command\n");
1295 + spin_lock(&fsg->lock);
1297 + /* Save the command for later */
1298 + if (fsg->cbbuf_cmnd_size)
1299 + WARNING(fsg, "CB[I] overwriting previous command\n");
1300 + fsg->cbbuf_cmnd_size = req->actual;
1301 + memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
1303 + wakeup_thread(fsg);
1304 + spin_unlock(&fsg->lock);
1308 +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
1310 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
1313 +static int class_setup_req(struct fsg_dev *fsg,
1314 + const struct usb_ctrlrequest *ctrl)
1316 + struct usb_request *req = fsg->ep0req;
1317 + int value = -EOPNOTSUPP;
1318 + u16 w_index = le16_to_cpu(ctrl->wIndex);
1319 + u16 w_value = le16_to_cpu(ctrl->wValue);
1320 + u16 w_length = le16_to_cpu(ctrl->wLength);
1325 + /* Handle Bulk-only class-specific requests */
1326 + if (transport_is_bbb()) {
1327 + switch (ctrl->bRequest) {
1329 + case US_BULK_RESET_REQUEST:
1330 + if (ctrl->bRequestType != (USB_DIR_OUT |
1331 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1333 + if (w_index != 0 || w_value != 0 || w_length != 0) {
1338 + /* Raise an exception to stop the current operation
1339 + * and reinitialize our state. */
1340 + DBG(fsg, "bulk reset request\n");
1341 + raise_exception(fsg, FSG_STATE_RESET);
1342 + value = DELAYED_STATUS;
1345 + case US_BULK_GET_MAX_LUN:
1346 + if (ctrl->bRequestType != (USB_DIR_IN |
1347 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1349 + if (w_index != 0 || w_value != 0 || w_length != 1) {
1353 + VDBG(fsg, "get max LUN\n");
1354 + *(u8 *) req->buf = fsg->nluns - 1;
1360 + /* Handle CBI class-specific requests */
1362 + switch (ctrl->bRequest) {
1364 + case USB_CBI_ADSC_REQUEST:
1365 + if (ctrl->bRequestType != (USB_DIR_OUT |
1366 + USB_TYPE_CLASS | USB_RECIP_INTERFACE))
1368 + if (w_index != 0 || w_value != 0) {
1372 + if (w_length > MAX_COMMAND_SIZE) {
1373 + value = -EOVERFLOW;
1377 + fsg->ep0req->context = received_cbi_adsc;
1382 + if (value == -EOPNOTSUPP)
1384 + "unknown class-specific control req "
1385 + "%02x.%02x v%04x i%04x l%u\n",
1386 + ctrl->bRequestType, ctrl->bRequest,
1387 + le16_to_cpu(ctrl->wValue), w_index, w_length);
1392 +/*-------------------------------------------------------------------------*/
1394 +/* Ep0 standard request handlers. These always run in_irq. */
1396 +static int standard_setup_req(struct fsg_dev *fsg,
1397 + const struct usb_ctrlrequest *ctrl)
1399 + struct usb_request *req = fsg->ep0req;
1400 + int value = -EOPNOTSUPP;
1401 + u16 w_index = le16_to_cpu(ctrl->wIndex);
1402 + u16 w_value = le16_to_cpu(ctrl->wValue);
1404 + /* Usually this just stores reply data in the pre-allocated ep0 buffer,
1405 + * but config change events will also reconfigure hardware. */
1406 + switch (ctrl->bRequest) {
1408 + case USB_REQ_GET_DESCRIPTOR:
1409 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1410 + USB_RECIP_DEVICE))
1412 + switch (w_value >> 8) {
1414 + case USB_DT_DEVICE:
1415 + VDBG(fsg, "get device descriptor\n");
1416 + device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
1417 + value = sizeof device_desc;
1418 + memcpy(req->buf, &device_desc, value);
1420 + case USB_DT_DEVICE_QUALIFIER:
1421 + VDBG(fsg, "get device qualifier\n");
1422 + if (!gadget_is_dualspeed(fsg->gadget) ||
1423 + fsg->gadget->speed == USB_SPEED_SUPER)
1426 + * Assume ep0 uses the same maxpacket value for both
1429 + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
1430 + value = sizeof dev_qualifier;
1431 + memcpy(req->buf, &dev_qualifier, value);
1434 + case USB_DT_OTHER_SPEED_CONFIG:
1435 + VDBG(fsg, "get other-speed config descriptor\n");
1436 + if (!gadget_is_dualspeed(fsg->gadget) ||
1437 + fsg->gadget->speed == USB_SPEED_SUPER)
1440 + case USB_DT_CONFIG:
1441 + VDBG(fsg, "get configuration descriptor\n");
1443 + value = populate_config_buf(fsg->gadget,
1449 + case USB_DT_STRING:
1450 + VDBG(fsg, "get string descriptor\n");
1452 + /* wIndex == language code */
1453 + value = usb_gadget_get_string(&fsg_stringtab,
1454 + w_value & 0xff, req->buf);
1458 + VDBG(fsg, "get bos descriptor\n");
1460 + if (gadget_is_superspeed(fsg->gadget))
1461 + value = populate_bos(fsg, req->buf);
1467 + /* One config, two speeds */
1468 + case USB_REQ_SET_CONFIGURATION:
1469 + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
1470 + USB_RECIP_DEVICE))
1472 + VDBG(fsg, "set configuration\n");
1473 + if (w_value == CONFIG_VALUE || w_value == 0) {
1474 + fsg->new_config = w_value;
1476 + /* Raise an exception to wipe out previous transaction
1477 + * state (queued bufs, etc) and set the new config. */
1478 + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
1479 + value = DELAYED_STATUS;
1482 + case USB_REQ_GET_CONFIGURATION:
1483 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1484 + USB_RECIP_DEVICE))
1486 + VDBG(fsg, "get configuration\n");
1487 + *(u8 *) req->buf = fsg->config;
1491 + case USB_REQ_SET_INTERFACE:
1492 + if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
1493 + USB_RECIP_INTERFACE))
1495 + if (fsg->config && w_index == 0) {
1497 + /* Raise an exception to wipe out previous transaction
1498 + * state (queued bufs, etc) and install the new
1499 + * interface altsetting. */
1500 + raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
1501 + value = DELAYED_STATUS;
1504 + case USB_REQ_GET_INTERFACE:
1505 + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
1506 + USB_RECIP_INTERFACE))
1510 + if (w_index != 0) {
1514 + VDBG(fsg, "get interface\n");
1515 + *(u8 *) req->buf = 0;
1521 + "unknown control req %02x.%02x v%04x i%04x l%u\n",
1522 + ctrl->bRequestType, ctrl->bRequest,
1523 + w_value, w_index, le16_to_cpu(ctrl->wLength));
1530 +static int fsg_setup(struct usb_gadget *gadget,
1531 + const struct usb_ctrlrequest *ctrl)
1533 + struct fsg_dev *fsg = get_gadget_data(gadget);
1535 + int w_length = le16_to_cpu(ctrl->wLength);
1537 + ++fsg->ep0_req_tag; // Record arrival of a new request
1538 + fsg->ep0req->context = NULL;
1539 + fsg->ep0req->length = 0;
1540 + dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
1542 + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
1543 + rc = class_setup_req(fsg, ctrl);
1545 + rc = standard_setup_req(fsg, ctrl);
1547 + /* Respond with data/status or defer until later? */
1548 + if (rc >= 0 && rc != DELAYED_STATUS) {
1549 + rc = min(rc, w_length);
1550 + fsg->ep0req->length = rc;
1551 + fsg->ep0req->zero = rc < w_length;
1552 + fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
1553 + "ep0-in" : "ep0-out");
1554 + rc = ep0_queue(fsg);
1557 + /* Device either stalls (rc < 0) or reports success */
1562 +/*-------------------------------------------------------------------------*/
1564 +/* All the following routines run in process context */
1567 +/* Use this for bulk or interrupt transfers, not ep0 */
1568 +static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
1569 + struct usb_request *req, int *pbusy,
1570 + enum fsg_buffer_state *state)
1574 + if (ep == fsg->bulk_in)
1575 + dump_msg(fsg, "bulk-in", req->buf, req->length);
1576 + else if (ep == fsg->intr_in)
1577 + dump_msg(fsg, "intr-in", req->buf, req->length);
1579 + spin_lock_irq(&fsg->lock);
1581 + *state = BUF_STATE_BUSY;
1582 + spin_unlock_irq(&fsg->lock);
1583 + rc = usb_ep_queue(ep, req, GFP_KERNEL);
1586 + *state = BUF_STATE_EMPTY;
1588 + /* We can't do much more than wait for a reset */
1590 + /* Note: currently the net2280 driver fails zero-length
1591 + * submissions if DMA is enabled. */
1592 + if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
1593 + req->length == 0))
1594 + WARNING(fsg, "error in submission: %s --> %d\n",
1600 +static int sleep_thread(struct fsg_dev *fsg)
1604 + /* Wait until a signal arrives or we are woken up */
1607 + set_current_state(TASK_INTERRUPTIBLE);
1608 + if (signal_pending(current)) {
1612 + if (fsg->thread_wakeup_needed)
1616 + __set_current_state(TASK_RUNNING);
1617 + fsg->thread_wakeup_needed = 0;
1622 +/*-------------------------------------------------------------------------*/
1624 +static int do_read(struct fsg_dev *fsg)
1626 + struct fsg_lun *curlun = fsg->curlun;
1628 + struct fsg_buffhd *bh;
1631 + loff_t file_offset, file_offset_tmp;
1632 + unsigned int amount;
1635 + /* Get the starting Logical Block Address and check that it's
1637 + if (fsg->cmnd[0] == READ_6)
1638 + lba = get_unaligned_be24(&fsg->cmnd[1]);
1640 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1642 + /* We allow DPO (Disable Page Out = don't save data in the
1643 + * cache) and FUA (Force Unit Access = don't read from the
1644 + * cache), but we don't implement them. */
1645 + if ((fsg->cmnd[1] & ~0x18) != 0) {
1646 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1650 + if (lba >= curlun->num_sectors) {
1651 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1654 + file_offset = ((loff_t) lba) << curlun->blkbits;
1656 + /* Carry out the file reads */
1657 + amount_left = fsg->data_size_from_cmnd;
1658 + if (unlikely(amount_left == 0))
1659 + return -EIO; // No default reply
1663 + /* Figure out how much we need to read:
1664 + * Try to read the remaining amount.
1665 + * But don't read more than the buffer size.
1666 + * And don't try to read past the end of the file.
1668 + amount = min((unsigned int) amount_left, mod_data.buflen);
1669 + amount = min((loff_t) amount,
1670 + curlun->file_length - file_offset);
1672 + /* Wait for the next buffer to become available */
1673 + bh = fsg->next_buffhd_to_fill;
1674 + while (bh->state != BUF_STATE_EMPTY) {
1675 + rc = sleep_thread(fsg);
1680 + /* If we were asked to read past the end of file,
1681 + * end with an empty buffer. */
1682 + if (amount == 0) {
1683 + curlun->sense_data =
1684 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1685 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1686 + curlun->info_valid = 1;
1687 + bh->inreq->length = 0;
1688 + bh->state = BUF_STATE_FULL;
1692 + /* Perform the read */
1693 + file_offset_tmp = file_offset;
1694 + nread = vfs_read(curlun->filp,
1695 + (char __user *) bh->buf,
1696 + amount, &file_offset_tmp);
1697 + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
1698 + (unsigned long long) file_offset,
1700 + if (signal_pending(current))
1704 + LDBG(curlun, "error in file read: %d\n",
1707 + } else if (nread < amount) {
1708 + LDBG(curlun, "partial file read: %d/%u\n",
1709 + (int) nread, amount);
1710 + nread = round_down(nread, curlun->blksize);
1712 + file_offset += nread;
1713 + amount_left -= nread;
1714 + fsg->residue -= nread;
1716 + /* Except at the end of the transfer, nread will be
1717 + * equal to the buffer size, which is divisible by the
1718 + * bulk-in maxpacket size.
1720 + bh->inreq->length = nread;
1721 + bh->state = BUF_STATE_FULL;
1723 + /* If an error occurred, report it and its position */
1724 + if (nread < amount) {
1725 + curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
1726 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1727 + curlun->info_valid = 1;
1731 + if (amount_left == 0)
1732 + break; // No more left to read
1734 + /* Send this buffer and go read some more */
1735 + bh->inreq->zero = 0;
1736 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
1737 + &bh->inreq_busy, &bh->state);
1738 + fsg->next_buffhd_to_fill = bh->next;
1741 + return -EIO; // No default reply
1745 +/*-------------------------------------------------------------------------*/
1747 +static int do_write(struct fsg_dev *fsg)
1749 + struct fsg_lun *curlun = fsg->curlun;
1751 + struct fsg_buffhd *bh;
1752 + int get_some_more;
1753 + u32 amount_left_to_req, amount_left_to_write;
1754 + loff_t usb_offset, file_offset, file_offset_tmp;
1755 + unsigned int amount;
1760 + curlun->sense_data = SS_WRITE_PROTECTED;
1763 + spin_lock(&curlun->filp->f_lock);
1764 + curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait
1765 + spin_unlock(&curlun->filp->f_lock);
1767 + /* Get the starting Logical Block Address and check that it's
1769 + if (fsg->cmnd[0] == WRITE_6)
1770 + lba = get_unaligned_be24(&fsg->cmnd[1]);
1772 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1774 + /* We allow DPO (Disable Page Out = don't save data in the
1775 + * cache) and FUA (Force Unit Access = write directly to the
1776 + * medium). We don't implement DPO; we implement FUA by
1777 + * performing synchronous output. */
1778 + if ((fsg->cmnd[1] & ~0x18) != 0) {
1779 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1783 + if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) {
1784 + spin_lock(&curlun->filp->f_lock);
1785 + curlun->filp->f_flags |= O_DSYNC;
1786 + spin_unlock(&curlun->filp->f_lock);
1789 + if (lba >= curlun->num_sectors) {
1790 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1794 + /* Carry out the file writes */
1795 + get_some_more = 1;
1796 + file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
1797 + amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
1799 + while (amount_left_to_write > 0) {
1801 + /* Queue a request for more data from the host */
1802 + bh = fsg->next_buffhd_to_fill;
1803 + if (bh->state == BUF_STATE_EMPTY && get_some_more) {
1805 + /* Figure out how much we want to get:
1806 + * Try to get the remaining amount,
1807 + * but not more than the buffer size.
1809 + amount = min(amount_left_to_req, mod_data.buflen);
1811 + /* Beyond the end of the backing file? */
1812 + if (usb_offset >= curlun->file_length) {
1813 + get_some_more = 0;
1814 + curlun->sense_data =
1815 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1816 + curlun->sense_data_info = usb_offset >> curlun->blkbits;
1817 + curlun->info_valid = 1;
1821 + /* Get the next buffer */
1822 + usb_offset += amount;
1823 + fsg->usb_amount_left -= amount;
1824 + amount_left_to_req -= amount;
1825 + if (amount_left_to_req == 0)
1826 + get_some_more = 0;
1828 + /* Except at the end of the transfer, amount will be
1829 + * equal to the buffer size, which is divisible by
1830 + * the bulk-out maxpacket size.
1832 + set_bulk_out_req_length(fsg, bh, amount);
1833 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
1834 + &bh->outreq_busy, &bh->state);
1835 + fsg->next_buffhd_to_fill = bh->next;
1839 + /* Write the received data to the backing file */
1840 + bh = fsg->next_buffhd_to_drain;
1841 + if (bh->state == BUF_STATE_EMPTY && !get_some_more)
1842 + break; // We stopped early
1843 + if (bh->state == BUF_STATE_FULL) {
1845 + fsg->next_buffhd_to_drain = bh->next;
1846 + bh->state = BUF_STATE_EMPTY;
1848 + /* Did something go wrong with the transfer? */
1849 + if (bh->outreq->status != 0) {
1850 + curlun->sense_data = SS_COMMUNICATION_FAILURE;
1851 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1852 + curlun->info_valid = 1;
1856 + amount = bh->outreq->actual;
1857 + if (curlun->file_length - file_offset < amount) {
1859 + "write %u @ %llu beyond end %llu\n",
1860 + amount, (unsigned long long) file_offset,
1861 + (unsigned long long) curlun->file_length);
1862 + amount = curlun->file_length - file_offset;
1865 + /* Don't accept excess data. The spec doesn't say
1866 + * what to do in this case. We'll ignore the error.
1868 + amount = min(amount, bh->bulk_out_intended_length);
1870 + /* Don't write a partial block */
1871 + amount = round_down(amount, curlun->blksize);
1875 + /* Perform the write */
1876 + file_offset_tmp = file_offset;
1877 + nwritten = vfs_write(curlun->filp,
1878 + (char __user *) bh->buf,
1879 + amount, &file_offset_tmp);
1880 + VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
1881 + (unsigned long long) file_offset,
1883 + if (signal_pending(current))
1884 + return -EINTR; // Interrupted!
1886 + if (nwritten < 0) {
1887 + LDBG(curlun, "error in file write: %d\n",
1890 + } else if (nwritten < amount) {
1891 + LDBG(curlun, "partial file write: %d/%u\n",
1892 + (int) nwritten, amount);
1893 + nwritten = round_down(nwritten, curlun->blksize);
1895 + file_offset += nwritten;
1896 + amount_left_to_write -= nwritten;
1897 + fsg->residue -= nwritten;
1899 + /* If an error occurred, report it and its position */
1900 + if (nwritten < amount) {
1901 + curlun->sense_data = SS_WRITE_ERROR;
1902 + curlun->sense_data_info = file_offset >> curlun->blkbits;
1903 + curlun->info_valid = 1;
1908 + /* Did the host decide to stop early? */
1909 + if (bh->outreq->actual < bh->bulk_out_intended_length) {
1910 + fsg->short_packet_received = 1;
1916 + /* Wait for something to happen */
1917 + rc = sleep_thread(fsg);
1922 + return -EIO; // No default reply
1926 +/*-------------------------------------------------------------------------*/
1928 +static int do_synchronize_cache(struct fsg_dev *fsg)
1930 + struct fsg_lun *curlun = fsg->curlun;
1933 + /* We ignore the requested LBA and write out all file's
1934 + * dirty data buffers. */
1935 + rc = fsg_lun_fsync_sub(curlun);
1937 + curlun->sense_data = SS_WRITE_ERROR;
1942 +/*-------------------------------------------------------------------------*/
1944 +static void invalidate_sub(struct fsg_lun *curlun)
1946 + struct file *filp = curlun->filp;
1947 + struct inode *inode = filp->f_path.dentry->d_inode;
1950 + rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
1951 + VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
1954 +static int do_verify(struct fsg_dev *fsg)
1956 + struct fsg_lun *curlun = fsg->curlun;
1958 + u32 verification_length;
1959 + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
1960 + loff_t file_offset, file_offset_tmp;
1962 + unsigned int amount;
1965 + /* Get the starting Logical Block Address and check that it's
1967 + lba = get_unaligned_be32(&fsg->cmnd[2]);
1968 + if (lba >= curlun->num_sectors) {
1969 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1973 + /* We allow DPO (Disable Page Out = don't save data in the
1974 + * cache) but we don't implement it. */
1975 + if ((fsg->cmnd[1] & ~0x10) != 0) {
1976 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1980 + verification_length = get_unaligned_be16(&fsg->cmnd[7]);
1981 + if (unlikely(verification_length == 0))
1982 + return -EIO; // No default reply
1984 + /* Prepare to carry out the file verify */
1985 + amount_left = verification_length << curlun->blkbits;
1986 + file_offset = ((loff_t) lba) << curlun->blkbits;
1988 + /* Write out all the dirty buffers before invalidating them */
1989 + fsg_lun_fsync_sub(curlun);
1990 + if (signal_pending(current))
1993 + invalidate_sub(curlun);
1994 + if (signal_pending(current))
1997 + /* Just try to read the requested blocks */
1998 + while (amount_left > 0) {
2000 + /* Figure out how much we need to read:
2001 + * Try to read the remaining amount, but not more than
2002 + * the buffer size.
2003 + * And don't try to read past the end of the file.
2005 + amount = min((unsigned int) amount_left, mod_data.buflen);
2006 + amount = min((loff_t) amount,
2007 + curlun->file_length - file_offset);
2008 + if (amount == 0) {
2009 + curlun->sense_data =
2010 + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
2011 + curlun->sense_data_info = file_offset >> curlun->blkbits;
2012 + curlun->info_valid = 1;
2016 + /* Perform the read */
2017 + file_offset_tmp = file_offset;
2018 + nread = vfs_read(curlun->filp,
2019 + (char __user *) bh->buf,
2020 + amount, &file_offset_tmp);
2021 + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
2022 + (unsigned long long) file_offset,
2024 + if (signal_pending(current))
2028 + LDBG(curlun, "error in file verify: %d\n",
2031 + } else if (nread < amount) {
2032 + LDBG(curlun, "partial file verify: %d/%u\n",
2033 + (int) nread, amount);
2034 + nread = round_down(nread, curlun->blksize);
2037 + curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
2038 + curlun->sense_data_info = file_offset >> curlun->blkbits;
2039 + curlun->info_valid = 1;
2042 + file_offset += nread;
2043 + amount_left -= nread;
2049 +/*-------------------------------------------------------------------------*/
2051 +static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2053 + u8 *buf = (u8 *) bh->buf;
2055 + static char vendor_id[] = "Linux ";
2056 + static char product_disk_id[] = "File-Stor Gadget";
2057 + static char product_cdrom_id[] = "File-CD Gadget ";
2059 + if (!fsg->curlun) { // Unsupported LUNs are okay
2060 + fsg->bad_lun_okay = 1;
2061 + memset(buf, 0, 36);
2062 + buf[0] = 0x7f; // Unsupported, no device-type
2063 + buf[4] = 31; // Additional length
2067 + memset(buf, 0, 8);
2068 + buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK);
2069 + if (mod_data.removable)
2071 + buf[2] = 2; // ANSI SCSI level 2
2072 + buf[3] = 2; // SCSI-2 INQUIRY data format
2073 + buf[4] = 31; // Additional length
2074 + // No special options
2075 + sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
2076 + (mod_data.cdrom ? product_cdrom_id :
2078 + mod_data.release);
2083 +static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2085 + struct fsg_lun *curlun = fsg->curlun;
2086 + u8 *buf = (u8 *) bh->buf;
2091 + * From the SCSI-2 spec., section 7.9 (Unit attention condition):
2093 + * If a REQUEST SENSE command is received from an initiator
2094 + * with a pending unit attention condition (before the target
2095 + * generates the contingent allegiance condition), then the
2096 + * target shall either:
2097 + * a) report any pending sense data and preserve the unit
2098 + * attention condition on the logical unit, or,
2099 + * b) report the unit attention condition, may discard any
2100 + * pending sense data, and clear the unit attention
2101 + * condition on the logical unit for that initiator.
2103 + * FSG normally uses option a); enable this code to use option b).
2106 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
2107 + curlun->sense_data = curlun->unit_attention_data;
2108 + curlun->unit_attention_data = SS_NO_SENSE;
2112 + if (!curlun) { // Unsupported LUNs are okay
2113 + fsg->bad_lun_okay = 1;
2114 + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
2118 + sd = curlun->sense_data;
2119 + sdinfo = curlun->sense_data_info;
2120 + valid = curlun->info_valid << 7;
2121 + curlun->sense_data = SS_NO_SENSE;
2122 + curlun->sense_data_info = 0;
2123 + curlun->info_valid = 0;
2126 + memset(buf, 0, 18);
2127 + buf[0] = valid | 0x70; // Valid, current error
2129 + put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */
2130 + buf[7] = 18 - 8; // Additional sense length
2131 + buf[12] = ASC(sd);
2132 + buf[13] = ASCQ(sd);
2137 +static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2139 + struct fsg_lun *curlun = fsg->curlun;
2140 + u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
2141 + int pmi = fsg->cmnd[8];
2142 + u8 *buf = (u8 *) bh->buf;
2144 + /* Check the PMI and LBA fields */
2145 + if (pmi > 1 || (pmi == 0 && lba != 0)) {
2146 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2150 + put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
2151 + /* Max logical block */
2152 + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
2157 +static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2159 + struct fsg_lun *curlun = fsg->curlun;
2160 + int msf = fsg->cmnd[1] & 0x02;
2161 + u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
2162 + u8 *buf = (u8 *) bh->buf;
2164 + if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
2165 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2168 + if (lba >= curlun->num_sectors) {
2169 + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
2173 + memset(buf, 0, 8);
2174 + buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */
2175 + store_cdrom_address(&buf[4], msf, lba);
2180 +static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2182 + struct fsg_lun *curlun = fsg->curlun;
2183 + int msf = fsg->cmnd[1] & 0x02;
2184 + int start_track = fsg->cmnd[6];
2185 + u8 *buf = (u8 *) bh->buf;
2187 + if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
2188 + start_track > 1) {
2189 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2193 + memset(buf, 0, 20);
2194 + buf[1] = (20-2); /* TOC data length */
2195 + buf[2] = 1; /* First track number */
2196 + buf[3] = 1; /* Last track number */
2197 + buf[5] = 0x16; /* Data track, copying allowed */
2198 + buf[6] = 0x01; /* Only track is number 1 */
2199 + store_cdrom_address(&buf[8], msf, 0);
2201 + buf[13] = 0x16; /* Lead-out track is data */
2202 + buf[14] = 0xAA; /* Lead-out track number */
2203 + store_cdrom_address(&buf[16], msf, curlun->num_sectors);
2208 +static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2210 + struct fsg_lun *curlun = fsg->curlun;
2211 + int mscmnd = fsg->cmnd[0];
2212 + u8 *buf = (u8 *) bh->buf;
2214 + int pc, page_code;
2215 + int changeable_values, all_pages;
2216 + int valid_page = 0;
2219 + if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD
2220 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2223 + pc = fsg->cmnd[2] >> 6;
2224 + page_code = fsg->cmnd[2] & 0x3f;
2226 + curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
2229 + changeable_values = (pc == 1);
2230 + all_pages = (page_code == 0x3f);
2232 + /* Write the mode parameter header. Fixed values are: default
2233 + * medium type, no cache control (DPOFUA), and no block descriptors.
2234 + * The only variable value is the WriteProtect bit. We will fill in
2235 + * the mode data length later. */
2236 + memset(buf, 0, 8);
2237 + if (mscmnd == MODE_SENSE) {
2238 + buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
2241 + } else { // MODE_SENSE_10
2242 + buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
2244 + limit = 65535; // Should really be mod_data.buflen
2247 + /* No block descriptors */
2249 + /* The mode pages, in numerical order. The only page we support
2250 + * is the Caching page. */
2251 + if (page_code == 0x08 || all_pages) {
2253 + buf[0] = 0x08; // Page code
2254 + buf[1] = 10; // Page length
2255 + memset(buf+2, 0, 10); // None of the fields are changeable
2257 + if (!changeable_values) {
2258 + buf[2] = 0x04; // Write cache enable,
2259 + // Read cache not disabled
2260 + // No cache retention priorities
2261 + put_unaligned_be16(0xffff, &buf[4]);
2262 + /* Don't disable prefetch */
2263 + /* Minimum prefetch = 0 */
2264 + put_unaligned_be16(0xffff, &buf[8]);
2265 + /* Maximum prefetch */
2266 + put_unaligned_be16(0xffff, &buf[10]);
2267 + /* Maximum prefetch ceiling */
2272 + /* Check that a valid page was requested and the mode data length
2273 + * isn't too long. */
2275 + if (!valid_page || len > limit) {
2276 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2280 + /* Store the mode data length */
2281 + if (mscmnd == MODE_SENSE)
2282 + buf0[0] = len - 1;
2284 + put_unaligned_be16(len - 2, buf0);
2289 +static int do_start_stop(struct fsg_dev *fsg)
2291 + struct fsg_lun *curlun = fsg->curlun;
2294 + if (!mod_data.removable) {
2295 + curlun->sense_data = SS_INVALID_COMMAND;
2299 + // int immed = fsg->cmnd[1] & 0x01;
2300 + loej = fsg->cmnd[4] & 0x02;
2301 + start = fsg->cmnd[4] & 0x01;
2303 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
2304 + if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed
2305 + (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start
2306 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2312 + /* Are we allowed to unload the media? */
2313 + if (curlun->prevent_medium_removal) {
2314 + LDBG(curlun, "unload attempt prevented\n");
2315 + curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
2318 + if (loej) { // Simulate an unload/eject
2319 + up_read(&fsg->filesem);
2320 + down_write(&fsg->filesem);
2321 + fsg_lun_close(curlun);
2322 + up_write(&fsg->filesem);
2323 + down_read(&fsg->filesem);
2327 + /* Our emulation doesn't support mounting; the medium is
2328 + * available for use as soon as it is loaded. */
2329 + if (!fsg_lun_is_open(curlun)) {
2330 + curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
2339 +static int do_prevent_allow(struct fsg_dev *fsg)
2341 + struct fsg_lun *curlun = fsg->curlun;
2344 + if (!mod_data.removable) {
2345 + curlun->sense_data = SS_INVALID_COMMAND;
2349 + prevent = fsg->cmnd[4] & 0x01;
2350 + if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent
2351 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2355 + if (curlun->prevent_medium_removal && !prevent)
2356 + fsg_lun_fsync_sub(curlun);
2357 + curlun->prevent_medium_removal = prevent;
2362 +static int do_read_format_capacities(struct fsg_dev *fsg,
2363 + struct fsg_buffhd *bh)
2365 + struct fsg_lun *curlun = fsg->curlun;
2366 + u8 *buf = (u8 *) bh->buf;
2368 + buf[0] = buf[1] = buf[2] = 0;
2369 + buf[3] = 8; // Only the Current/Maximum Capacity Descriptor
2372 + put_unaligned_be32(curlun->num_sectors, &buf[0]);
2373 + /* Number of blocks */
2374 + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
2375 + buf[4] = 0x02; /* Current capacity */
2380 +static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh)
2382 + struct fsg_lun *curlun = fsg->curlun;
2384 + /* We don't support MODE SELECT */
2385 + curlun->sense_data = SS_INVALID_COMMAND;
2390 +/*-------------------------------------------------------------------------*/
2392 +static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
2396 + rc = fsg_set_halt(fsg, fsg->bulk_in);
2397 + if (rc == -EAGAIN)
2398 + VDBG(fsg, "delayed bulk-in endpoint halt\n");
2400 + if (rc != -EAGAIN) {
2401 + WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
2406 + /* Wait for a short time and then try again */
2407 + if (msleep_interruptible(100) != 0)
2409 + rc = usb_ep_set_halt(fsg->bulk_in);
2414 +static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
2418 + DBG(fsg, "bulk-in set wedge\n");
2419 + rc = usb_ep_set_wedge(fsg->bulk_in);
2420 + if (rc == -EAGAIN)
2421 + VDBG(fsg, "delayed bulk-in endpoint wedge\n");
2423 + if (rc != -EAGAIN) {
2424 + WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
2429 + /* Wait for a short time and then try again */
2430 + if (msleep_interruptible(100) != 0)
2432 + rc = usb_ep_set_wedge(fsg->bulk_in);
2437 +static int throw_away_data(struct fsg_dev *fsg)
2439 + struct fsg_buffhd *bh;
2443 + while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY ||
2444 + fsg->usb_amount_left > 0) {
2446 + /* Throw away the data in a filled buffer */
2447 + if (bh->state == BUF_STATE_FULL) {
2449 + bh->state = BUF_STATE_EMPTY;
2450 + fsg->next_buffhd_to_drain = bh->next;
2452 + /* A short packet or an error ends everything */
2453 + if (bh->outreq->actual < bh->bulk_out_intended_length ||
2454 + bh->outreq->status != 0) {
2455 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2461 + /* Try to submit another request if we need one */
2462 + bh = fsg->next_buffhd_to_fill;
2463 + if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
2464 + amount = min(fsg->usb_amount_left,
2465 + (u32) mod_data.buflen);
2467 + /* Except at the end of the transfer, amount will be
2468 + * equal to the buffer size, which is divisible by
2469 + * the bulk-out maxpacket size.
2471 + set_bulk_out_req_length(fsg, bh, amount);
2472 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
2473 + &bh->outreq_busy, &bh->state);
2474 + fsg->next_buffhd_to_fill = bh->next;
2475 + fsg->usb_amount_left -= amount;
2479 + /* Otherwise wait for something to happen */
2480 + rc = sleep_thread(fsg);
2488 +static int finish_reply(struct fsg_dev *fsg)
2490 + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
2493 + switch (fsg->data_dir) {
2494 + case DATA_DIR_NONE:
2495 + break; // Nothing to send
2497 + /* If we don't know whether the host wants to read or write,
2498 + * this must be CB or CBI with an unknown command. We mustn't
2499 + * try to send or receive any data. So stall both bulk pipes
2500 + * if we can and wait for a reset. */
2501 + case DATA_DIR_UNKNOWN:
2502 + if (mod_data.can_stall) {
2503 + fsg_set_halt(fsg, fsg->bulk_out);
2504 + rc = halt_bulk_in_endpoint(fsg);
2508 + /* All but the last buffer of data must have already been sent */
2509 + case DATA_DIR_TO_HOST:
2510 + if (fsg->data_size == 0)
2511 + ; // Nothing to send
2513 + /* If there's no residue, simply send the last buffer */
2514 + else if (fsg->residue == 0) {
2515 + bh->inreq->zero = 0;
2516 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2517 + &bh->inreq_busy, &bh->state);
2518 + fsg->next_buffhd_to_fill = bh->next;
2521 + /* There is a residue. For CB and CBI, simply mark the end
2522 + * of the data with a short packet. However, if we are
2523 + * allowed to stall, there was no data at all (residue ==
2524 + * data_size), and the command failed (invalid LUN or
2525 + * sense data is set), then halt the bulk-in endpoint
2527 + else if (!transport_is_bbb()) {
2528 + if (mod_data.can_stall &&
2529 + fsg->residue == fsg->data_size &&
2530 + (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) {
2531 + bh->state = BUF_STATE_EMPTY;
2532 + rc = halt_bulk_in_endpoint(fsg);
2534 + bh->inreq->zero = 1;
2535 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2536 + &bh->inreq_busy, &bh->state);
2537 + fsg->next_buffhd_to_fill = bh->next;
2542 + * For Bulk-only, mark the end of the data with a short
2543 + * packet. If we are allowed to stall, halt the bulk-in
2544 + * endpoint. (Note: This violates the Bulk-Only Transport
2545 + * specification, which requires us to pad the data if we
2546 + * don't halt the endpoint. Presumably nobody will mind.)
2549 + bh->inreq->zero = 1;
2550 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2551 + &bh->inreq_busy, &bh->state);
2552 + fsg->next_buffhd_to_fill = bh->next;
2553 + if (mod_data.can_stall)
2554 + rc = halt_bulk_in_endpoint(fsg);
2558 + /* We have processed all we want from the data the host has sent.
2559 + * There may still be outstanding bulk-out requests. */
2560 + case DATA_DIR_FROM_HOST:
2561 + if (fsg->residue == 0)
2562 + ; // Nothing to receive
2564 + /* Did the host stop sending unexpectedly early? */
2565 + else if (fsg->short_packet_received) {
2566 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2570 + /* We haven't processed all the incoming data. Even though
2571 + * we may be allowed to stall, doing so would cause a race.
2572 + * The controller may already have ACK'ed all the remaining
2573 + * bulk-out packets, in which case the host wouldn't see a
2574 + * STALL. Not realizing the endpoint was halted, it wouldn't
2575 + * clear the halt -- leading to problems later on. */
2577 + else if (mod_data.can_stall) {
2578 + fsg_set_halt(fsg, fsg->bulk_out);
2579 + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
2584 + /* We can't stall. Read in the excess data and throw it
2587 + rc = throw_away_data(fsg);
2594 +static int send_status(struct fsg_dev *fsg)
2596 + struct fsg_lun *curlun = fsg->curlun;
2597 + struct fsg_buffhd *bh;
2599 + u8 status = US_BULK_STAT_OK;
2600 + u32 sd, sdinfo = 0;
2602 + /* Wait for the next buffer to become available */
2603 + bh = fsg->next_buffhd_to_fill;
2604 + while (bh->state != BUF_STATE_EMPTY) {
2605 + rc = sleep_thread(fsg);
2611 + sd = curlun->sense_data;
2612 + sdinfo = curlun->sense_data_info;
2613 + } else if (fsg->bad_lun_okay)
2616 + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
2618 + if (fsg->phase_error) {
2619 + DBG(fsg, "sending phase-error status\n");
2620 + status = US_BULK_STAT_PHASE;
2621 + sd = SS_INVALID_COMMAND;
2622 + } else if (sd != SS_NO_SENSE) {
2623 + DBG(fsg, "sending command-failure status\n");
2624 + status = US_BULK_STAT_FAIL;
2625 + VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
2627 + SK(sd), ASC(sd), ASCQ(sd), sdinfo);
2630 + if (transport_is_bbb()) {
2631 + struct bulk_cs_wrap *csw = bh->buf;
2633 + /* Store and send the Bulk-only CSW */
2634 + csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
2635 + csw->Tag = fsg->tag;
2636 + csw->Residue = cpu_to_le32(fsg->residue);
2637 + csw->Status = status;
2639 + bh->inreq->length = US_BULK_CS_WRAP_LEN;
2640 + bh->inreq->zero = 0;
2641 + start_transfer(fsg, fsg->bulk_in, bh->inreq,
2642 + &bh->inreq_busy, &bh->state);
2644 + } else if (mod_data.transport_type == USB_PR_CB) {
2646 + /* Control-Bulk transport has no status phase! */
2649 + } else { // USB_PR_CBI
2650 + struct interrupt_data *buf = bh->buf;
2652 + /* Store and send the Interrupt data. UFI sends the ASC
2653 + * and ASCQ bytes. Everything else sends a Type (which
2654 + * is always 0) and the status Value. */
2655 + if (mod_data.protocol_type == USB_SC_UFI) {
2656 + buf->bType = ASC(sd);
2657 + buf->bValue = ASCQ(sd);
2660 + buf->bValue = status;
2662 + fsg->intreq->length = CBI_INTERRUPT_DATA_LEN;
2664 + fsg->intr_buffhd = bh; // Point to the right buffhd
2665 + fsg->intreq->buf = bh->inreq->buf;
2666 + fsg->intreq->context = bh;
2667 + start_transfer(fsg, fsg->intr_in, fsg->intreq,
2668 + &fsg->intreq_busy, &bh->state);
2671 + fsg->next_buffhd_to_fill = bh->next;
2676 +/*-------------------------------------------------------------------------*/
2678 +/* Check whether the command is properly formed and whether its data size
2679 + * and direction agree with the values we already have. */
2680 +static int check_command(struct fsg_dev *fsg, int cmnd_size,
2681 + enum data_direction data_dir, unsigned int mask,
2682 + int needs_medium, const char *name)
2685 + int lun = fsg->cmnd[1] >> 5;
2686 + static const char dirletter[4] = {'u', 'o', 'i', 'n'};
2688 + struct fsg_lun *curlun;
2690 + /* Adjust the expected cmnd_size for protocol encapsulation padding.
2691 + * Transparent SCSI doesn't pad. */
2692 + if (protocol_is_scsi())
2695 + /* There's some disagreement as to whether RBC pads commands or not.
2696 + * We'll play it safe and accept either form. */
2697 + else if (mod_data.protocol_type == USB_SC_RBC) {
2698 + if (fsg->cmnd_size == 12)
2701 + /* All the other protocols pad to 12 bytes */
2706 + if (fsg->data_dir != DATA_DIR_UNKNOWN)
2707 + sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir],
2709 + VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
2710 + name, cmnd_size, dirletter[(int) data_dir],
2711 + fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen);
2713 + /* We can't reply at all until we know the correct data direction
2715 + if (fsg->data_size_from_cmnd == 0)
2716 + data_dir = DATA_DIR_NONE;
2717 + if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI
2718 + fsg->data_dir = data_dir;
2719 + fsg->data_size = fsg->data_size_from_cmnd;
2721 + } else { // Bulk-only
2722 + if (fsg->data_size < fsg->data_size_from_cmnd) {
2724 + /* Host data size < Device data size is a phase error.
2725 + * Carry out the command, but only transfer as much
2726 + * as we are allowed. */
2727 + fsg->data_size_from_cmnd = fsg->data_size;
2728 + fsg->phase_error = 1;
2731 + fsg->residue = fsg->usb_amount_left = fsg->data_size;
2733 + /* Conflicting data directions is a phase error */
2734 + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) {
2735 + fsg->phase_error = 1;
2739 + /* Verify the length of the command itself */
2740 + if (cmnd_size != fsg->cmnd_size) {
2742 + /* Special case workaround: There are plenty of buggy SCSI
2743 + * implementations. Many have issues with cbw->Length
2744 + * field passing a wrong command size. For those cases we
2745 + * always try to work around the problem by using the length
2746 + * sent by the host side provided it is at least as large
2747 + * as the correct command length.
2748 + * Examples of such cases would be MS-Windows, which issues
2749 + * REQUEST SENSE with cbw->Length == 12 where it should
2750 + * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
2751 + * REQUEST SENSE with cbw->Length == 10 where it should
2754 + if (cmnd_size <= fsg->cmnd_size) {
2755 + DBG(fsg, "%s is buggy! Expected length %d "
2756 + "but we got %d\n", name,
2757 + cmnd_size, fsg->cmnd_size);
2758 + cmnd_size = fsg->cmnd_size;
2760 + fsg->phase_error = 1;
2765 + /* Check that the LUN values are consistent */
2766 + if (transport_is_bbb()) {
2767 + if (fsg->lun != lun)
2768 + DBG(fsg, "using LUN %d from CBW, "
2769 + "not LUN %d from CDB\n",
2773 + /* Check the LUN */
2774 + curlun = fsg->curlun;
2776 + if (fsg->cmnd[0] != REQUEST_SENSE) {
2777 + curlun->sense_data = SS_NO_SENSE;
2778 + curlun->sense_data_info = 0;
2779 + curlun->info_valid = 0;
2782 + fsg->bad_lun_okay = 0;
2784 + /* INQUIRY and REQUEST SENSE commands are explicitly allowed
2785 + * to use unsupported LUNs; all others may not. */
2786 + if (fsg->cmnd[0] != INQUIRY &&
2787 + fsg->cmnd[0] != REQUEST_SENSE) {
2788 + DBG(fsg, "unsupported LUN %d\n", fsg->lun);
2793 + /* If a unit attention condition exists, only INQUIRY and
2794 + * REQUEST SENSE commands are allowed; anything else must fail. */
2795 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
2796 + fsg->cmnd[0] != INQUIRY &&
2797 + fsg->cmnd[0] != REQUEST_SENSE) {
2798 + curlun->sense_data = curlun->unit_attention_data;
2799 + curlun->unit_attention_data = SS_NO_SENSE;
2803 + /* Check that only command bytes listed in the mask are non-zero */
2804 + fsg->cmnd[1] &= 0x1f; // Mask away the LUN
2805 + for (i = 1; i < cmnd_size; ++i) {
2806 + if (fsg->cmnd[i] && !(mask & (1 << i))) {
2808 + curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
2813 + /* If the medium isn't mounted and the command needs to access
2814 + * it, return an error. */
2815 + if (curlun && !fsg_lun_is_open(curlun) && needs_medium) {
2816 + curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
2823 +/* wrapper of check_command for data size in blocks handling */
2824 +static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
2825 + enum data_direction data_dir, unsigned int mask,
2826 + int needs_medium, const char *name)
2829 + fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
2830 + return check_command(fsg, cmnd_size, data_dir,
2831 + mask, needs_medium, name);
2834 +static int do_scsi_command(struct fsg_dev *fsg)
2836 + struct fsg_buffhd *bh;
2838 + int reply = -EINVAL;
2840 + static char unknown[16];
2844 + /* Wait for the next buffer to become available for data or status */
2845 + bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
2846 + while (bh->state != BUF_STATE_EMPTY) {
2847 + rc = sleep_thread(fsg);
2851 + fsg->phase_error = 0;
2852 + fsg->short_packet_received = 0;
2854 + down_read(&fsg->filesem); // We're using the backing file
2855 + switch (fsg->cmnd[0]) {
2858 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2859 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2862 + reply = do_inquiry(fsg, bh);
2866 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2867 + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
2868 + (1<<1) | (1<<4), 0,
2869 + "MODE SELECT(6)")) == 0)
2870 + reply = do_mode_select(fsg, bh);
2873 + case MODE_SELECT_10:
2874 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2875 + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
2876 + (1<<1) | (3<<7), 0,
2877 + "MODE SELECT(10)")) == 0)
2878 + reply = do_mode_select(fsg, bh);
2882 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2883 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2884 + (1<<1) | (1<<2) | (1<<4), 0,
2885 + "MODE SENSE(6)")) == 0)
2886 + reply = do_mode_sense(fsg, bh);
2889 + case MODE_SENSE_10:
2890 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2891 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2892 + (1<<1) | (1<<2) | (3<<7), 0,
2893 + "MODE SENSE(10)")) == 0)
2894 + reply = do_mode_sense(fsg, bh);
2897 + case ALLOW_MEDIUM_REMOVAL:
2898 + fsg->data_size_from_cmnd = 0;
2899 + if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
2901 + "PREVENT-ALLOW MEDIUM REMOVAL")) == 0)
2902 + reply = do_prevent_allow(fsg);
2907 + fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
2908 + if ((reply = check_command_size_in_blocks(fsg, 6,
2910 + (7<<1) | (1<<4), 1,
2912 + reply = do_read(fsg);
2916 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2917 + if ((reply = check_command_size_in_blocks(fsg, 10,
2919 + (1<<1) | (0xf<<2) | (3<<7), 1,
2920 + "READ(10)")) == 0)
2921 + reply = do_read(fsg);
2925 + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
2926 + if ((reply = check_command_size_in_blocks(fsg, 12,
2928 + (1<<1) | (0xf<<2) | (0xf<<6), 1,
2929 + "READ(12)")) == 0)
2930 + reply = do_read(fsg);
2933 + case READ_CAPACITY:
2934 + fsg->data_size_from_cmnd = 8;
2935 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2936 + (0xf<<2) | (1<<8), 1,
2937 + "READ CAPACITY")) == 0)
2938 + reply = do_read_capacity(fsg, bh);
2942 + if (!mod_data.cdrom)
2943 + goto unknown_cmnd;
2944 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2945 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2946 + (3<<7) | (0x1f<<1), 1,
2947 + "READ HEADER")) == 0)
2948 + reply = do_read_header(fsg, bh);
2952 + if (!mod_data.cdrom)
2953 + goto unknown_cmnd;
2954 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2955 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2956 + (7<<6) | (1<<1), 1,
2957 + "READ TOC")) == 0)
2958 + reply = do_read_toc(fsg, bh);
2961 + case READ_FORMAT_CAPACITIES:
2962 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
2963 + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
2965 + "READ FORMAT CAPACITIES")) == 0)
2966 + reply = do_read_format_capacities(fsg, bh);
2969 + case REQUEST_SENSE:
2970 + fsg->data_size_from_cmnd = fsg->cmnd[4];
2971 + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
2973 + "REQUEST SENSE")) == 0)
2974 + reply = do_request_sense(fsg, bh);
2978 + fsg->data_size_from_cmnd = 0;
2979 + if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
2980 + (1<<1) | (1<<4), 0,
2981 + "START-STOP UNIT")) == 0)
2982 + reply = do_start_stop(fsg);
2985 + case SYNCHRONIZE_CACHE:
2986 + fsg->data_size_from_cmnd = 0;
2987 + if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
2988 + (0xf<<2) | (3<<7), 1,
2989 + "SYNCHRONIZE CACHE")) == 0)
2990 + reply = do_synchronize_cache(fsg);
2993 + case TEST_UNIT_READY:
2994 + fsg->data_size_from_cmnd = 0;
2995 + reply = check_command(fsg, 6, DATA_DIR_NONE,
2997 + "TEST UNIT READY");
3000 + /* Although optional, this command is used by MS-Windows. We
3001 + * support a minimal version: BytChk must be 0. */
3003 + fsg->data_size_from_cmnd = 0;
3004 + if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
3005 + (1<<1) | (0xf<<2) | (3<<7), 1,
3007 + reply = do_verify(fsg);
3012 + fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
3013 + if ((reply = check_command_size_in_blocks(fsg, 6,
3014 + DATA_DIR_FROM_HOST,
3015 + (7<<1) | (1<<4), 1,
3016 + "WRITE(6)")) == 0)
3017 + reply = do_write(fsg);
3021 + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
3022 + if ((reply = check_command_size_in_blocks(fsg, 10,
3023 + DATA_DIR_FROM_HOST,
3024 + (1<<1) | (0xf<<2) | (3<<7), 1,
3025 + "WRITE(10)")) == 0)
3026 + reply = do_write(fsg);
3030 + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
3031 + if ((reply = check_command_size_in_blocks(fsg, 12,
3032 + DATA_DIR_FROM_HOST,
3033 + (1<<1) | (0xf<<2) | (0xf<<6), 1,
3034 + "WRITE(12)")) == 0)
3035 + reply = do_write(fsg);
3038 + /* Some mandatory commands that we recognize but don't implement.
3039 + * They don't mean much in this setting. It's left as an exercise
3040 + * for anyone interested to implement RESERVE and RELEASE in terms
3041 + * of Posix locks. */
3045 + case SEND_DIAGNOSTIC:
3050 + fsg->data_size_from_cmnd = 0;
3051 + sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
3052 + if ((reply = check_command(fsg, fsg->cmnd_size,
3053 + DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) {
3054 + fsg->curlun->sense_data = SS_INVALID_COMMAND;
3059 + up_read(&fsg->filesem);
3061 + if (reply == -EINTR || signal_pending(current))
3064 + /* Set up the single reply buffer for finish_reply() */
3065 + if (reply == -EINVAL)
3066 + reply = 0; // Error reply length
3067 + if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
3068 + reply = min((u32) reply, fsg->data_size_from_cmnd);
3069 + bh->inreq->length = reply;
3070 + bh->state = BUF_STATE_FULL;
3071 + fsg->residue -= reply;
3072 + } // Otherwise it's already set
3078 +/*-------------------------------------------------------------------------*/
3080 +static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
3082 + struct usb_request *req = bh->outreq;
3083 + struct bulk_cb_wrap *cbw = req->buf;
3085 + /* Was this a real packet? Should it be ignored? */
3086 + if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
3089 + /* Is the CBW valid? */
3090 + if (req->actual != US_BULK_CB_WRAP_LEN ||
3091 + cbw->Signature != cpu_to_le32(
3092 + US_BULK_CB_SIGN)) {
3093 + DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
3095 + le32_to_cpu(cbw->Signature));
3097 + /* The Bulk-only spec says we MUST stall the IN endpoint
3098 + * (6.6.1), so it's unavoidable. It also says we must
3099 + * retain this state until the next reset, but there's
3100 + * no way to tell the controller driver it should ignore
3101 + * Clear-Feature(HALT) requests.
3103 + * We aren't required to halt the OUT endpoint; instead
3104 + * we can simply accept and discard any data received
3105 + * until the next reset. */
3106 + wedge_bulk_in_endpoint(fsg);
3107 + set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
3111 + /* Is the CBW meaningful? */
3112 + if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
3113 + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
3114 + DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
3116 + cbw->Lun, cbw->Flags, cbw->Length);
3118 + /* We can do anything we want here, so let's stall the
3119 + * bulk pipes if we are allowed to. */
3120 + if (mod_data.can_stall) {
3121 + fsg_set_halt(fsg, fsg->bulk_out);
3122 + halt_bulk_in_endpoint(fsg);
3127 + /* Save the command for later */
3128 + fsg->cmnd_size = cbw->Length;
3129 + memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
3130 + if (cbw->Flags & US_BULK_FLAG_IN)
3131 + fsg->data_dir = DATA_DIR_TO_HOST;
3133 + fsg->data_dir = DATA_DIR_FROM_HOST;
3134 + fsg->data_size = le32_to_cpu(cbw->DataTransferLength);
3135 + if (fsg->data_size == 0)
3136 + fsg->data_dir = DATA_DIR_NONE;
3137 + fsg->lun = cbw->Lun;
3138 + fsg->tag = cbw->Tag;
3143 +static int get_next_command(struct fsg_dev *fsg)
3145 + struct fsg_buffhd *bh;
3148 + if (transport_is_bbb()) {
3150 + /* Wait for the next buffer to become available */
3151 + bh = fsg->next_buffhd_to_fill;
3152 + while (bh->state != BUF_STATE_EMPTY) {
3153 + rc = sleep_thread(fsg);
3158 + /* Queue a request to read a Bulk-only CBW */
3159 + set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN);
3160 + start_transfer(fsg, fsg->bulk_out, bh->outreq,
3161 + &bh->outreq_busy, &bh->state);
3163 + /* We will drain the buffer in software, which means we
3164 + * can reuse it for the next filling. No need to advance
3165 + * next_buffhd_to_fill. */
3167 + /* Wait for the CBW to arrive */
3168 + while (bh->state != BUF_STATE_FULL) {
3169 + rc = sleep_thread(fsg);
3174 + rc = received_cbw(fsg, bh);
3175 + bh->state = BUF_STATE_EMPTY;
3177 + } else { // USB_PR_CB or USB_PR_CBI
3179 + /* Wait for the next command to arrive */
3180 + while (fsg->cbbuf_cmnd_size == 0) {
3181 + rc = sleep_thread(fsg);
3186 + /* Is the previous status interrupt request still busy?
3187 + * The host is allowed to skip reading the status,
3188 + * so we must cancel it. */
3189 + if (fsg->intreq_busy)
3190 + usb_ep_dequeue(fsg->intr_in, fsg->intreq);
3192 + /* Copy the command and mark the buffer empty */
3193 + fsg->data_dir = DATA_DIR_UNKNOWN;
3194 + spin_lock_irq(&fsg->lock);
3195 + fsg->cmnd_size = fsg->cbbuf_cmnd_size;
3196 + memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
3197 + fsg->cbbuf_cmnd_size = 0;
3198 + spin_unlock_irq(&fsg->lock);
3200 + /* Use LUN from the command */
3201 + fsg->lun = fsg->cmnd[1] >> 5;
3204 + /* Update current lun */
3205 + if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
3206 + fsg->curlun = &fsg->luns[fsg->lun];
3208 + fsg->curlun = NULL;
3214 +/*-------------------------------------------------------------------------*/
3216 +static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
3217 + const struct usb_endpoint_descriptor *d)
3221 + ep->driver_data = fsg;
3223 + rc = usb_ep_enable(ep);
3225 + ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
3229 +static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep,
3230 + struct usb_request **preq)
3232 + *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
3235 + ERROR(fsg, "can't allocate request for %s\n", ep->name);
3240 + * Reset interface setting and re-init endpoint state (toggle etc).
3241 + * Call with altsetting < 0 to disable the interface. The only other
3242 + * available altsetting is 0, which enables the interface.
3244 +static int do_set_interface(struct fsg_dev *fsg, int altsetting)
3248 + const struct usb_endpoint_descriptor *d;
3251 + DBG(fsg, "reset interface\n");
3254 + /* Deallocate the requests */
3255 + for (i = 0; i < fsg_num_buffers; ++i) {
3256 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3259 + usb_ep_free_request(fsg->bulk_in, bh->inreq);
3263 + usb_ep_free_request(fsg->bulk_out, bh->outreq);
3264 + bh->outreq = NULL;
3267 + if (fsg->intreq) {
3268 + usb_ep_free_request(fsg->intr_in, fsg->intreq);
3269 + fsg->intreq = NULL;
3272 + /* Disable the endpoints */
3273 + if (fsg->bulk_in_enabled) {
3274 + usb_ep_disable(fsg->bulk_in);
3275 + fsg->bulk_in_enabled = 0;
3277 + if (fsg->bulk_out_enabled) {
3278 + usb_ep_disable(fsg->bulk_out);
3279 + fsg->bulk_out_enabled = 0;
3281 + if (fsg->intr_in_enabled) {
3282 + usb_ep_disable(fsg->intr_in);
3283 + fsg->intr_in_enabled = 0;
3287 + if (altsetting < 0 || rc != 0)
3290 + DBG(fsg, "set interface %d\n", altsetting);
3292 + /* Enable the endpoints */
3293 + d = fsg_ep_desc(fsg->gadget,
3294 + &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
3295 + &fsg_ss_bulk_in_desc);
3296 + if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
3298 + fsg->bulk_in_enabled = 1;
3300 + d = fsg_ep_desc(fsg->gadget,
3301 + &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
3302 + &fsg_ss_bulk_out_desc);
3303 + if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
3305 + fsg->bulk_out_enabled = 1;
3306 + fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
3307 + clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
3309 + if (transport_is_cbi()) {
3310 + d = fsg_ep_desc(fsg->gadget,
3311 + &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
3312 + &fsg_ss_intr_in_desc);
3313 + if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
3315 + fsg->intr_in_enabled = 1;
3318 + /* Allocate the requests */
3319 + for (i = 0; i < fsg_num_buffers; ++i) {
3320 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3322 + if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
3324 + if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
3326 + bh->inreq->buf = bh->outreq->buf = bh->buf;
3327 + bh->inreq->context = bh->outreq->context = bh;
3328 + bh->inreq->complete = bulk_in_complete;
3329 + bh->outreq->complete = bulk_out_complete;
3331 + if (transport_is_cbi()) {
3332 + if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0)
3334 + fsg->intreq->complete = intr_in_complete;
3338 + for (i = 0; i < fsg->nluns; ++i)
3339 + fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
3345 + * Change our operational configuration. This code must agree with the code
3346 + * that returns config descriptors, and with interface altsetting code.
3348 + * It's also responsible for power management interactions. Some
3349 + * configurations might not work with our current power sources.
3350 + * For now we just assume the gadget is always self-powered.
3352 +static int do_set_config(struct fsg_dev *fsg, u8 new_config)
3356 + /* Disable the single interface */
3357 + if (fsg->config != 0) {
3358 + DBG(fsg, "reset config\n");
3360 + rc = do_set_interface(fsg, -1);
3363 + /* Enable the interface */
3364 + if (new_config != 0) {
3365 + fsg->config = new_config;
3366 + if ((rc = do_set_interface(fsg, 0)) != 0)
3367 + fsg->config = 0; // Reset on errors
3369 + INFO(fsg, "%s config #%d\n",
3370 + usb_speed_string(fsg->gadget->speed),
3377 +/*-------------------------------------------------------------------------*/
3379 +static void handle_exception(struct fsg_dev *fsg)
3385 + struct fsg_buffhd *bh;
3386 + enum fsg_state old_state;
3388 + struct fsg_lun *curlun;
3389 + unsigned int exception_req_tag;
3392 + /* Clear the existing signals. Anything but SIGUSR1 is converted
3393 + * into a high-priority EXIT exception. */
3395 + sig = dequeue_signal_lock(current, ¤t->blocked, &info);
3398 + if (sig != SIGUSR1) {
3399 + if (fsg->state < FSG_STATE_EXIT)
3400 + DBG(fsg, "Main thread exiting on signal\n");
3401 + raise_exception(fsg, FSG_STATE_EXIT);
3405 + /* Cancel all the pending transfers */
3406 + if (fsg->intreq_busy)
3407 + usb_ep_dequeue(fsg->intr_in, fsg->intreq);
3408 + for (i = 0; i < fsg_num_buffers; ++i) {
3409 + bh = &fsg->buffhds[i];
3410 + if (bh->inreq_busy)
3411 + usb_ep_dequeue(fsg->bulk_in, bh->inreq);
3412 + if (bh->outreq_busy)
3413 + usb_ep_dequeue(fsg->bulk_out, bh->outreq);
3416 + /* Wait until everything is idle */
3418 + num_active = fsg->intreq_busy;
3419 + for (i = 0; i < fsg_num_buffers; ++i) {
3420 + bh = &fsg->buffhds[i];
3421 + num_active += bh->inreq_busy + bh->outreq_busy;
3423 + if (num_active == 0)
3425 + if (sleep_thread(fsg))
3429 + /* Clear out the controller's fifos */
3430 + if (fsg->bulk_in_enabled)
3431 + usb_ep_fifo_flush(fsg->bulk_in);
3432 + if (fsg->bulk_out_enabled)
3433 + usb_ep_fifo_flush(fsg->bulk_out);
3434 + if (fsg->intr_in_enabled)
3435 + usb_ep_fifo_flush(fsg->intr_in);
3437 + /* Reset the I/O buffer states and pointers, the SCSI
3438 + * state, and the exception. Then invoke the handler. */
3439 + spin_lock_irq(&fsg->lock);
3441 + for (i = 0; i < fsg_num_buffers; ++i) {
3442 + bh = &fsg->buffhds[i];
3443 + bh->state = BUF_STATE_EMPTY;
3445 + fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain =
3448 + exception_req_tag = fsg->exception_req_tag;
3449 + new_config = fsg->new_config;
3450 + old_state = fsg->state;
3452 + if (old_state == FSG_STATE_ABORT_BULK_OUT)
3453 + fsg->state = FSG_STATE_STATUS_PHASE;
3455 + for (i = 0; i < fsg->nluns; ++i) {
3456 + curlun = &fsg->luns[i];
3457 + curlun->prevent_medium_removal = 0;
3458 + curlun->sense_data = curlun->unit_attention_data =
3460 + curlun->sense_data_info = 0;
3461 + curlun->info_valid = 0;
3463 + fsg->state = FSG_STATE_IDLE;
3465 + spin_unlock_irq(&fsg->lock);
3467 + /* Carry out any extra actions required for the exception */
3468 + switch (old_state) {
3472 + case FSG_STATE_ABORT_BULK_OUT:
3474 + spin_lock_irq(&fsg->lock);
3475 + if (fsg->state == FSG_STATE_STATUS_PHASE)
3476 + fsg->state = FSG_STATE_IDLE;
3477 + spin_unlock_irq(&fsg->lock);
3480 + case FSG_STATE_RESET:
3481 + /* In case we were forced against our will to halt a
3482 + * bulk endpoint, clear the halt now. (The SuperH UDC
3483 + * requires this.) */
3484 + if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
3485 + usb_ep_clear_halt(fsg->bulk_in);
3487 + if (transport_is_bbb()) {
3488 + if (fsg->ep0_req_tag == exception_req_tag)
3489 + ep0_queue(fsg); // Complete the status stage
3491 + } else if (transport_is_cbi())
3492 + send_status(fsg); // Status by interrupt pipe
3494 + /* Technically this should go here, but it would only be
3495 + * a waste of time. Ditto for the INTERFACE_CHANGE and
3496 + * CONFIG_CHANGE cases. */
3497 + // for (i = 0; i < fsg->nluns; ++i)
3498 + // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
3501 + case FSG_STATE_INTERFACE_CHANGE:
3502 + rc = do_set_interface(fsg, 0);
3503 + if (fsg->ep0_req_tag != exception_req_tag)
3505 + if (rc != 0) // STALL on errors
3506 + fsg_set_halt(fsg, fsg->ep0);
3507 + else // Complete the status stage
3511 + case FSG_STATE_CONFIG_CHANGE:
3512 + rc = do_set_config(fsg, new_config);
3513 + if (fsg->ep0_req_tag != exception_req_tag)
3515 + if (rc != 0) // STALL on errors
3516 + fsg_set_halt(fsg, fsg->ep0);
3517 + else // Complete the status stage
3521 + case FSG_STATE_DISCONNECT:
3522 + for (i = 0; i < fsg->nluns; ++i)
3523 + fsg_lun_fsync_sub(fsg->luns + i);
3524 + do_set_config(fsg, 0); // Unconfigured state
3527 + case FSG_STATE_EXIT:
3528 + case FSG_STATE_TERMINATED:
3529 + do_set_config(fsg, 0); // Free resources
3530 + spin_lock_irq(&fsg->lock);
3531 + fsg->state = FSG_STATE_TERMINATED; // Stop the thread
3532 + spin_unlock_irq(&fsg->lock);
3538 +/*-------------------------------------------------------------------------*/
3540 +static int fsg_main_thread(void *fsg_)
3542 + struct fsg_dev *fsg = fsg_;
3544 + /* Allow the thread to be killed by a signal, but set the signal mask
3545 + * to block everything but INT, TERM, KILL, and USR1. */
3546 + allow_signal(SIGINT);
3547 + allow_signal(SIGTERM);
3548 + allow_signal(SIGKILL);
3549 + allow_signal(SIGUSR1);
3551 + /* Allow the thread to be frozen */
3554 + /* Arrange for userspace references to be interpreted as kernel
3555 + * pointers. That way we can pass a kernel pointer to a routine
3556 + * that expects a __user pointer and it will work okay. */
3559 + /* The main loop */
3560 + while (fsg->state != FSG_STATE_TERMINATED) {
3561 + if (exception_in_progress(fsg) || signal_pending(current)) {
3562 + handle_exception(fsg);
3566 + if (!fsg->running) {
3567 + sleep_thread(fsg);
3571 + if (get_next_command(fsg))
3574 + spin_lock_irq(&fsg->lock);
3575 + if (!exception_in_progress(fsg))
3576 + fsg->state = FSG_STATE_DATA_PHASE;
3577 + spin_unlock_irq(&fsg->lock);
3579 + if (do_scsi_command(fsg) || finish_reply(fsg))
3582 + spin_lock_irq(&fsg->lock);
3583 + if (!exception_in_progress(fsg))
3584 + fsg->state = FSG_STATE_STATUS_PHASE;
3585 + spin_unlock_irq(&fsg->lock);
3587 + if (send_status(fsg))
3590 + spin_lock_irq(&fsg->lock);
3591 + if (!exception_in_progress(fsg))
3592 + fsg->state = FSG_STATE_IDLE;
3593 + spin_unlock_irq(&fsg->lock);
3596 + spin_lock_irq(&fsg->lock);
3597 + fsg->thread_task = NULL;
3598 + spin_unlock_irq(&fsg->lock);
3600 + /* If we are exiting because of a signal, unregister the
3601 + * gadget driver. */
3602 + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
3603 + usb_gadget_unregister_driver(&fsg_driver);
3605 + /* Let the unbind and cleanup routines know the thread has exited */
3606 + complete_and_exit(&fsg->thread_notifier, 0);
3610 +/*-------------------------------------------------------------------------*/
3613 +/* The write permissions and store_xxx pointers are set in fsg_bind() */
3614 +static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL);
3615 +static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL);
3616 +static DEVICE_ATTR(file, 0444, fsg_show_file, NULL);
3619 +/*-------------------------------------------------------------------------*/
3621 +static void fsg_release(struct kref *ref)
3623 + struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref);
3629 +static void lun_release(struct device *dev)
3631 + struct rw_semaphore *filesem = dev_get_drvdata(dev);
3632 + struct fsg_dev *fsg =
3633 + container_of(filesem, struct fsg_dev, filesem);
3635 + kref_put(&fsg->ref, fsg_release);
3638 +static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
3640 + struct fsg_dev *fsg = get_gadget_data(gadget);
3642 + struct fsg_lun *curlun;
3643 + struct usb_request *req = fsg->ep0req;
3645 + DBG(fsg, "unbind\n");
3646 + clear_bit(REGISTERED, &fsg->atomic_bitflags);
3648 + /* If the thread isn't already dead, tell it to exit now */
3649 + if (fsg->state != FSG_STATE_TERMINATED) {
3650 + raise_exception(fsg, FSG_STATE_EXIT);
3651 + wait_for_completion(&fsg->thread_notifier);
3653 + /* The cleanup routine waits for this completion also */
3654 + complete(&fsg->thread_notifier);
3657 + /* Unregister the sysfs attribute files and the LUNs */
3658 + for (i = 0; i < fsg->nluns; ++i) {
3659 + curlun = &fsg->luns[i];
3660 + if (curlun->registered) {
3661 + device_remove_file(&curlun->dev, &dev_attr_nofua);
3662 + device_remove_file(&curlun->dev, &dev_attr_ro);
3663 + device_remove_file(&curlun->dev, &dev_attr_file);
3664 + fsg_lun_close(curlun);
3665 + device_unregister(&curlun->dev);
3666 + curlun->registered = 0;
3670 + /* Free the data buffers */
3671 + for (i = 0; i < fsg_num_buffers; ++i)
3672 + kfree(fsg->buffhds[i].buf);
3674 + /* Free the request and buffer for endpoint 0 */
3677 + usb_ep_free_request(fsg->ep0, req);
3680 + set_gadget_data(gadget, NULL);
3684 +static int __init check_parameters(struct fsg_dev *fsg)
3689 + /* Store the default values */
3690 + mod_data.transport_type = USB_PR_BULK;
3691 + mod_data.transport_name = "Bulk-only";
3692 + mod_data.protocol_type = USB_SC_SCSI;
3693 + mod_data.protocol_name = "Transparent SCSI";
3695 + /* Some peripheral controllers are known not to be able to
3696 + * halt bulk endpoints correctly. If one of them is present,
3699 + if (gadget_is_at91(fsg->gadget))
3700 + mod_data.can_stall = 0;
3702 + if (mod_data.release == 0xffff) { // Parameter wasn't set
3703 + gcnum = usb_gadget_controller_number(fsg->gadget);
3705 + mod_data.release = 0x0300 + gcnum;
3707 + WARNING(fsg, "controller '%s' not recognized\n",
3708 + fsg->gadget->name);
3709 + mod_data.release = 0x0399;
3713 + prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
3715 +#ifdef CONFIG_USB_FILE_STORAGE_TEST
3716 + if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) {
3717 + ; // Use default setting
3718 + } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) {
3719 + mod_data.transport_type = USB_PR_CB;
3720 + mod_data.transport_name = "Control-Bulk";
3721 + } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) {
3722 + mod_data.transport_type = USB_PR_CBI;
3723 + mod_data.transport_name = "Control-Bulk-Interrupt";
3725 + ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm);
3729 + if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 ||
3730 + prot == USB_SC_SCSI) {
3731 + ; // Use default setting
3732 + } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 ||
3733 + prot == USB_SC_RBC) {
3734 + mod_data.protocol_type = USB_SC_RBC;
3735 + mod_data.protocol_name = "RBC";
3736 + } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 ||
3737 + strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 ||
3738 + prot == USB_SC_8020) {
3739 + mod_data.protocol_type = USB_SC_8020;
3740 + mod_data.protocol_name = "8020i (ATAPI)";
3741 + } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 ||
3742 + prot == USB_SC_QIC) {
3743 + mod_data.protocol_type = USB_SC_QIC;
3744 + mod_data.protocol_name = "QIC-157";
3745 + } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 ||
3746 + prot == USB_SC_UFI) {
3747 + mod_data.protocol_type = USB_SC_UFI;
3748 + mod_data.protocol_name = "UFI";
3749 + } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 ||
3750 + prot == USB_SC_8070) {
3751 + mod_data.protocol_type = USB_SC_8070;
3752 + mod_data.protocol_name = "8070i";
3754 + ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm);
3758 + mod_data.buflen &= PAGE_CACHE_MASK;
3759 + if (mod_data.buflen <= 0) {
3760 + ERROR(fsg, "invalid buflen\n");
3761 + return -ETOOSMALL;
3764 +#endif /* CONFIG_USB_FILE_STORAGE_TEST */
3766 + /* Serial string handling.
3767 + * On a real device, the serial string would be loaded
3768 + * from permanent storage. */
3769 + if (mod_data.serial) {
3774 + * The CB[I] specification limits the serial string to
3775 + * 12 uppercase hexadecimal characters.
3776 + * BBB need at least 12 uppercase hexadecimal characters,
3777 + * with a maximum of 126. */
3778 + for (ch = mod_data.serial; *ch; ++ch) {
3780 + if ((*ch < '0' || *ch > '9') &&
3781 + (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
3783 + "Invalid serial string character: %c\n",
3789 + (mod_data.transport_type == USB_PR_BULK && len < 12) ||
3790 + (mod_data.transport_type != USB_PR_BULK && len > 12)) {
3791 + WARNING(fsg, "Invalid serial string length!\n");
3794 + fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial;
3796 + WARNING(fsg, "No serial-number string provided!\n");
3798 + device_desc.iSerialNumber = 0;
3805 +static int __init fsg_bind(struct usb_gadget *gadget)
3807 + struct fsg_dev *fsg = the_fsg;
3810 + struct fsg_lun *curlun;
3811 + struct usb_ep *ep;
3812 + struct usb_request *req;
3813 + char *pathbuf, *p;
3815 + fsg->gadget = gadget;
3816 + set_gadget_data(gadget, fsg);
3817 + fsg->ep0 = gadget->ep0;
3818 + fsg->ep0->driver_data = fsg;
3820 + if ((rc = check_parameters(fsg)) != 0)
3823 + if (mod_data.removable) { // Enable the store_xxx attributes
3824 + dev_attr_file.attr.mode = 0644;
3825 + dev_attr_file.store = fsg_store_file;
3826 + if (!mod_data.cdrom) {
3827 + dev_attr_ro.attr.mode = 0644;
3828 + dev_attr_ro.store = fsg_store_ro;
3832 + /* Only for removable media? */
3833 + dev_attr_nofua.attr.mode = 0644;
3834 + dev_attr_nofua.store = fsg_store_nofua;
3836 + /* Find out how many LUNs there should be */
3837 + i = mod_data.nluns;
3839 + i = max(mod_data.num_filenames, 1u);
3840 + if (i > FSG_MAX_LUNS) {
3841 + ERROR(fsg, "invalid number of LUNs: %d\n", i);
3846 + /* Create the LUNs, open their backing files, and register the
3847 + * LUN devices in sysfs. */
3848 + fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL);
3855 + for (i = 0; i < fsg->nluns; ++i) {
3856 + curlun = &fsg->luns[i];
3857 + curlun->cdrom = !!mod_data.cdrom;
3858 + curlun->ro = mod_data.cdrom || mod_data.ro[i];
3859 + curlun->initially_ro = curlun->ro;
3860 + curlun->removable = mod_data.removable;
3861 + curlun->nofua = mod_data.nofua[i];
3862 + curlun->dev.release = lun_release;
3863 + curlun->dev.parent = &gadget->dev;
3864 + curlun->dev.driver = &fsg_driver.driver;
3865 + dev_set_drvdata(&curlun->dev, &fsg->filesem);
3866 + dev_set_name(&curlun->dev,"%s-lun%d",
3867 + dev_name(&gadget->dev), i);
3869 + kref_get(&fsg->ref);
3870 + rc = device_register(&curlun->dev);
3872 + INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
3873 + put_device(&curlun->dev);
3876 + curlun->registered = 1;
3878 + rc = device_create_file(&curlun->dev, &dev_attr_ro);
3881 + rc = device_create_file(&curlun->dev, &dev_attr_nofua);
3884 + rc = device_create_file(&curlun->dev, &dev_attr_file);
3888 + if (mod_data.file[i] && *mod_data.file[i]) {
3889 + rc = fsg_lun_open(curlun, mod_data.file[i]);
3892 + } else if (!mod_data.removable) {
3893 + ERROR(fsg, "no file given for LUN%d\n", i);
3899 + /* Find all the endpoints we will use */
3900 + usb_ep_autoconfig_reset(gadget);
3901 + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
3903 + goto autoconf_fail;
3904 + ep->driver_data = fsg; // claim the endpoint
3905 + fsg->bulk_in = ep;
3907 + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
3909 + goto autoconf_fail;
3910 + ep->driver_data = fsg; // claim the endpoint
3911 + fsg->bulk_out = ep;
3913 + if (transport_is_cbi()) {
3914 + ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc);
3916 + goto autoconf_fail;
3917 + ep->driver_data = fsg; // claim the endpoint
3918 + fsg->intr_in = ep;
3921 + /* Fix up the descriptors */
3922 + device_desc.idVendor = cpu_to_le16(mod_data.vendor);
3923 + device_desc.idProduct = cpu_to_le16(mod_data.product);
3924 + device_desc.bcdDevice = cpu_to_le16(mod_data.release);
3926 + i = (transport_is_cbi() ? 3 : 2); // Number of endpoints
3927 + fsg_intf_desc.bNumEndpoints = i;
3928 + fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type;
3929 + fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type;
3930 + fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3932 + if (gadget_is_dualspeed(gadget)) {
3933 + fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3935 + /* Assume endpoint addresses are the same for both speeds */
3936 + fsg_hs_bulk_in_desc.bEndpointAddress =
3937 + fsg_fs_bulk_in_desc.bEndpointAddress;
3938 + fsg_hs_bulk_out_desc.bEndpointAddress =
3939 + fsg_fs_bulk_out_desc.bEndpointAddress;
3940 + fsg_hs_intr_in_desc.bEndpointAddress =
3941 + fsg_fs_intr_in_desc.bEndpointAddress;
3944 + if (gadget_is_superspeed(gadget)) {
3945 + unsigned max_burst;
3947 + fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
3949 + /* Calculate bMaxBurst, we know packet size is 1024 */
3950 + max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
3952 + /* Assume endpoint addresses are the same for both speeds */
3953 + fsg_ss_bulk_in_desc.bEndpointAddress =
3954 + fsg_fs_bulk_in_desc.bEndpointAddress;
3955 + fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
3957 + fsg_ss_bulk_out_desc.bEndpointAddress =
3958 + fsg_fs_bulk_out_desc.bEndpointAddress;
3959 + fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
3962 + if (gadget_is_otg(gadget))
3963 + fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
3967 + /* Allocate the request and buffer for endpoint 0 */
3968 + fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
3971 + req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
3974 + req->complete = ep0_complete;
3976 + /* Allocate the data buffers */
3977 + for (i = 0; i < fsg_num_buffers; ++i) {
3978 + struct fsg_buffhd *bh = &fsg->buffhds[i];
3980 + /* Allocate for the bulk-in endpoint. We assume that
3981 + * the buffer will also work with the bulk-out (and
3982 + * interrupt-in) endpoint. */
3983 + bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
3986 + bh->next = bh + 1;
3988 + fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0];
3990 + /* This should reflect the actual gadget power source */
3991 + usb_gadget_set_selfpowered(gadget);
3993 + snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer,
3995 + init_utsname()->sysname, init_utsname()->release,
3998 + fsg->thread_task = kthread_create(fsg_main_thread, fsg,
3999 + "file-storage-gadget");
4000 + if (IS_ERR(fsg->thread_task)) {
4001 + rc = PTR_ERR(fsg->thread_task);
4005 + INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
4006 + INFO(fsg, "NOTE: This driver is deprecated. "
4007 + "Consider using g_mass_storage instead.\n");
4008 + INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
4010 + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
4011 + for (i = 0; i < fsg->nluns; ++i) {
4012 + curlun = &fsg->luns[i];
4013 + if (fsg_lun_is_open(curlun)) {
4016 + p = d_path(&curlun->filp->f_path,
4017 + pathbuf, PATH_MAX);
4021 + LINFO(curlun, "ro=%d, nofua=%d, file: %s\n",
4022 + curlun->ro, curlun->nofua, (p ? p : "(error)"));
4027 + DBG(fsg, "transport=%s (x%02x)\n",
4028 + mod_data.transport_name, mod_data.transport_type);
4029 + DBG(fsg, "protocol=%s (x%02x)\n",
4030 + mod_data.protocol_name, mod_data.protocol_type);
4031 + DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
4032 + mod_data.vendor, mod_data.product, mod_data.release);
4033 + DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n",
4034 + mod_data.removable, mod_data.can_stall,
4035 + mod_data.cdrom, mod_data.buflen);
4036 + DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
4038 + set_bit(REGISTERED, &fsg->atomic_bitflags);
4040 + /* Tell the thread to start working */
4041 + wake_up_process(fsg->thread_task);
4045 + ERROR(fsg, "unable to autoconfigure all endpoints\n");
4049 + fsg->state = FSG_STATE_TERMINATED; // The thread is dead
4050 + fsg_unbind(gadget);
4051 + complete(&fsg->thread_notifier);
4056 +/*-------------------------------------------------------------------------*/
4058 +static void fsg_suspend(struct usb_gadget *gadget)
4060 + struct fsg_dev *fsg = get_gadget_data(gadget);
4062 + DBG(fsg, "suspend\n");
4063 + set_bit(SUSPENDED, &fsg->atomic_bitflags);
4066 +static void fsg_resume(struct usb_gadget *gadget)
4068 + struct fsg_dev *fsg = get_gadget_data(gadget);
4070 + DBG(fsg, "resume\n");
4071 + clear_bit(SUSPENDED, &fsg->atomic_bitflags);
4075 +/*-------------------------------------------------------------------------*/
4077 +static struct usb_gadget_driver fsg_driver = {
4078 + .max_speed = USB_SPEED_SUPER,
4079 + .function = (char *) fsg_string_product,
4080 + .unbind = fsg_unbind,
4081 + .disconnect = fsg_disconnect,
4082 + .setup = fsg_setup,
4083 + .suspend = fsg_suspend,
4084 + .resume = fsg_resume,
4087 + .name = DRIVER_NAME,
4088 + .owner = THIS_MODULE,
4096 +static int __init fsg_alloc(void)
4098 + struct fsg_dev *fsg;
4100 + fsg = kzalloc(sizeof *fsg +
4101 + fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL);
4105 + spin_lock_init(&fsg->lock);
4106 + init_rwsem(&fsg->filesem);
4107 + kref_init(&fsg->ref);
4108 + init_completion(&fsg->thread_notifier);
4115 +static int __init fsg_init(void)
4118 + struct fsg_dev *fsg;
4120 + rc = fsg_num_buffers_validate();
4124 + if ((rc = fsg_alloc()) != 0)
4127 + if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
4128 + kref_put(&fsg->ref, fsg_release);
4131 +module_init(fsg_init);
4134 +static void __exit fsg_cleanup(void)
4136 + struct fsg_dev *fsg = the_fsg;
4138 + /* Unregister the driver iff the thread hasn't already done so */
4139 + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
4140 + usb_gadget_unregister_driver(&fsg_driver);
4142 + /* Wait for the thread to finish up */
4143 + wait_for_completion(&fsg->thread_notifier);
4145 + kref_put(&fsg->ref, fsg_release);
4147 +module_exit(fsg_cleanup);
4148 diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
4149 index 344d5e2..0937bde 100644
4150 --- a/drivers/usb/host/Kconfig
4151 +++ b/drivers/usb/host/Kconfig
4152 @@ -663,6 +663,19 @@ config USB_HWA_HCD
4153 To compile this driver a module, choose M here: the module
4154 will be called "hwa-hc".
4157 + tristate "Synopsis DWC host support"
4160 + The Synopsis DWC controller is a dual-role
4161 + host/peripheral/OTG ("On The Go") USB controllers.
4163 + Enable this option to support this IP in host controller mode.
4166 + To compile this driver as a module, choose M here: the
4167 + modules built will be called dwc_otg and dwc_common_port.
4169 config USB_IMX21_HCD
4170 tristate "i.MX21 HCD support"
4171 depends on ARM && ARCH_MXC
4172 diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
4173 index 4fb73c1..76d97de 100644
4174 --- a/drivers/usb/host/Makefile
4175 +++ b/drivers/usb/host/Makefile
4176 @@ -47,6 +47,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
4177 obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
4178 obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
4179 obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
4181 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/
4182 obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
4183 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
4184 obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
4185 diff --git a/drivers/usb/host/dwc_common_port/Makefile b/drivers/usb/host/dwc_common_port/Makefile
4186 new file mode 100644
4187 index 0000000..63e3485
4189 +++ b/drivers/usb/host/dwc_common_port/Makefile
4192 +# Makefile for DWC_common library
4195 +ifneq ($(KERNELRELEASE),)
4197 +EXTRA_CFLAGS += -DDWC_LINUX
4198 +#EXTRA_CFLAGS += -DDEBUG
4199 +#EXTRA_CFLAGS += -DDWC_DEBUG_REGS
4200 +#EXTRA_CFLAGS += -DDWC_DEBUG_MEMORY
4202 +EXTRA_CFLAGS += -DDWC_LIBMODULE
4203 +EXTRA_CFLAGS += -DDWC_CCLIB
4204 +#EXTRA_CFLAGS += -DDWC_CRYPTOLIB
4205 +EXTRA_CFLAGS += -DDWC_NOTIFYLIB
4206 +EXTRA_CFLAGS += -DDWC_UTFLIB
4208 +obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o
4209 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
4210 + dwc_crypto.o dwc_notifier.o \
4211 + dwc_common_linux.o dwc_mem.o
4213 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
4214 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
4216 +ifneq ($(kernrel3),2.6.20)
4217 +# grayg - I only know that we use EXTRA_CFLAGS in 2.6.31 actually
4218 +EXTRA_CFLAGS += $(CPPFLAGS)
4224 +#$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
4228 +$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
4229 + cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
4237 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
4239 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
4240 + $(DOXYGEN) doc/doxygen.cfg
4242 +tags: $(wildcard *.[hc])
4243 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
4248 + rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
4249 diff --git a/drivers/usb/host/dwc_common_port/Makefile.fbsd b/drivers/usb/host/dwc_common_port/Makefile.fbsd
4250 new file mode 100644
4251 index 0000000..45db991
4253 +++ b/drivers/usb/host/dwc_common_port/Makefile.fbsd
4255 +CFLAGS += -I/sys/i386/compile/GENERIC -I/sys/i386/include -I/usr/include
4256 +CFLAGS += -DDWC_FREEBSD
4258 +#CFLAGS += -DDWC_DEBUG_REGS
4259 +#CFLAGS += -DDWC_DEBUG_MEMORY
4261 +#CFLAGS += -DDWC_LIBMODULE
4262 +#CFLAGS += -DDWC_CCLIB
4263 +#CFLAGS += -DDWC_CRYPTOLIB
4264 +#CFLAGS += -DDWC_NOTIFYLIB
4265 +#CFLAGS += -DDWC_UTFLIB
4267 +KMOD = dwc_common_port_lib
4268 +SRCS = dwc_cc.c dwc_modpow.c dwc_dh.c dwc_crypto.c dwc_notifier.c \
4269 + dwc_common_fbsd.c dwc_mem.c
4271 +.include <bsd.kmod.mk>
4272 diff --git a/drivers/usb/host/dwc_common_port/Makefile.linux b/drivers/usb/host/dwc_common_port/Makefile.linux
4273 new file mode 100644
4274 index 0000000..961df3f
4276 +++ b/drivers/usb/host/dwc_common_port/Makefile.linux
4279 +# Makefile for DWC_common library
4281 +ifneq ($(KERNELRELEASE),)
4283 +EXTRA_CFLAGS += -DDWC_LINUX
4284 +#EXTRA_CFLAGS += -DDEBUG
4285 +#EXTRA_CFLAGS += -DDWC_DEBUG_REGS
4286 +#EXTRA_CFLAGS += -DDWC_DEBUG_MEMORY
4288 +EXTRA_CFLAGS += -DDWC_LIBMODULE
4289 +EXTRA_CFLAGS += -DDWC_CCLIB
4290 +EXTRA_CFLAGS += -DDWC_CRYPTOLIB
4291 +EXTRA_CFLAGS += -DDWC_NOTIFYLIB
4292 +EXTRA_CFLAGS += -DDWC_UTFLIB
4294 +obj-m := dwc_common_port_lib.o
4295 +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
4296 + dwc_crypto.o dwc_notifier.o \
4297 + dwc_common_linux.o dwc_mem.o
4302 +$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
4306 +$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
4307 + cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
4315 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
4317 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
4318 + $(DOXYGEN) doc/doxygen.cfg
4320 +tags: $(wildcard *.[hc])
4321 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
4326 + rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
4327 diff --git a/drivers/usb/host/dwc_common_port/changes.txt b/drivers/usb/host/dwc_common_port/changes.txt
4328 new file mode 100644
4329 index 0000000..f6839f9
4331 +++ b/drivers/usb/host/dwc_common_port/changes.txt
4334 +dwc_read_reg32() and friends now take an additional parameter, a pointer to an
4335 +IO context struct. The IO context struct should live in an os-dependent struct
4336 +in your driver. As an example, the dwc_usb3 driver has an os-dependent struct
4337 +named 'os_dep' embedded in the main device struct. So there these calls look
4340 + dwc_read_reg32(&usb3_dev->os_dep.ioctx, &pcd->dev_global_regs->dcfg);
4342 + dwc_write_reg32(&usb3_dev->os_dep.ioctx,
4343 + &pcd->dev_global_regs->dcfg, 0);
4345 +Note that for the existing Linux driver ports, it is not necessary to actually
4346 +define the 'ioctx' member in the os-dependent struct. Since Linux does not
4347 +require an IO context, its macros for dwc_read_reg32() and friends do not
4348 +use the context pointer, so it is optimized away by the compiler. But it is
4349 +necessary to add the pointer parameter to all of the call sites, to be ready
4350 +for any future ports (such as FreeBSD) which do require an IO context.
4353 +Similarly, dwc_alloc(), dwc_alloc_atomic(), dwc_strdup(), and dwc_free() now
4354 +take an additional parameter, a pointer to a memory context. Examples:
4356 + addr = dwc_alloc(&usb3_dev->os_dep.memctx, size);
4358 + dwc_free(&usb3_dev->os_dep.memctx, addr);
4360 +Again, for the Linux ports, it is not necessary to actually define the memctx
4361 +member, but it is necessary to add the pointer parameter to all of the call
4365 +Same for dwc_dma_alloc() and dwc_dma_free(). Examples:
4367 + virt_addr = dwc_dma_alloc(&usb3_dev->os_dep.dmactx, size, &phys_addr);
4369 + dwc_dma_free(&usb3_dev->os_dep.dmactx, size, virt_addr, phys_addr);
4372 +Same for dwc_mutex_alloc() and dwc_mutex_free(). Examples:
4374 + mutex = dwc_mutex_alloc(&usb3_dev->os_dep.mtxctx);
4376 + dwc_mutex_free(&usb3_dev->os_dep.mtxctx, mutex);
4379 +Same for dwc_spinlock_alloc() and dwc_spinlock_free(). Examples:
4381 + lock = dwc_spinlock_alloc(&usb3_dev->osdep.splctx);
4383 + dwc_spinlock_free(&usb3_dev->osdep.splctx, lock);
4386 +Same for dwc_timer_alloc(). Example:
4388 + timer = dwc_timer_alloc(&usb3_dev->os_dep.tmrctx, "dwc_usb3_tmr1",
4389 + cb_func, cb_data);
4392 +Same for dwc_waitq_alloc(). Example:
4394 + waitq = dwc_waitq_alloc(&usb3_dev->os_dep.wtqctx);
4397 +Same for dwc_thread_run(). Example:
4399 + thread = dwc_thread_run(&usb3_dev->os_dep.thdctx, func,
4400 + "dwc_usb3_thd1", data);
4403 +Same for dwc_workq_alloc(). Example:
4405 + workq = dwc_workq_alloc(&usb3_dev->osdep.wkqctx, "dwc_usb3_wkq1");
4408 +Same for dwc_task_alloc(). Example:
4410 + task = dwc_task_alloc(&usb3_dev->os_dep.tskctx, "dwc_usb3_tsk1",
4411 + cb_func, cb_data);
4414 +In addition to the context pointer additions, a few core functions have had
4415 +other changes made to their parameters:
4417 +The 'flags' parameter to dwc_spinlock_irqsave() and dwc_spinunlock_irqrestore()
4418 +has been changed from a uint64_t to a dwc_irqflags_t.
4420 +dwc_thread_should_stop() now takes a 'dwc_thread_t *' parameter, because the
4421 +FreeBSD equivalent of that function requires it.
4423 +And, in addition to the context pointer, dwc_task_alloc() also adds a
4424 +'char *name' parameter, to be consistent with dwc_thread_run() and
4425 +dwc_workq_alloc(), and because the FreeBSD equivalent of that function
4426 +requires a unique name.
4429 +Here is a complete list of the core functions that now take a pointer to a
4430 +context as their first parameter:
4446 + dwc_spinlock_alloc
4452 + dwc_task_alloc Also adds a 'char *name' as its 2nd parameter
4454 +And here are the core functions that have other changes to their parameters:
4456 + dwc_spinlock_irqsave 'flags' param is now a 'dwc_irqflags_t *'
4457 + dwc_spinunlock_irqrestore 'flags' param is now a 'dwc_irqflags_t'
4458 + dwc_thread_should_stop Adds a 'dwc_thread_t *' parameter
4462 +The changes to the core functions also require some of the other library
4463 +functions to change:
4465 + dwc_cc_if_alloc() and dwc_cc_if_free() now take a 'void *memctx'
4466 + (for memory allocation) as the 1st param and a 'void *mtxctx'
4467 + (for mutex allocation) as the 2nd param.
4469 + dwc_cc_clear(), dwc_cc_add(), dwc_cc_change(), dwc_cc_remove(),
4470 + dwc_cc_data_for_save(), and dwc_cc_restore_from_data() now take a
4471 + 'void *memctx' as the 1st param.
4473 + dwc_dh_modpow(), dwc_dh_pk(), and dwc_dh_derive_keys() now take a
4474 + 'void *memctx' as the 1st param.
4476 + dwc_modpow() now takes a 'void *memctx' as the 1st param.
4478 + dwc_alloc_notification_manager() now takes a 'void *memctx' as the
4479 + 1st param and a 'void *wkqctx' (for work queue allocation) as the 2nd
4480 + param, and also now returns an integer value that is non-zero if
4481 + allocation of its data structures or work queue fails.
4483 + dwc_register_notifier() now takes a 'void *memctx' as the 1st param.
4485 + dwc_memory_debug_start() now takes a 'void *mem_ctx' as the first
4486 + param, and also now returns an integer value that is non-zero if
4487 + allocation of its data structures fails.
4491 +Other miscellaneous changes:
4493 +The DEBUG_MEMORY and DEBUG_REGS #define's have been renamed to
4494 +DWC_DEBUG_MEMORY and DWC_DEBUG_REGS.
4496 +The following #define's have been added to allow selectively compiling library
4504 +A DWC_LIBMODULE #define has also been added. If this is not defined, then the
4505 +module code in dwc_common_linux.c is not compiled in. This allows linking the
4506 +library code directly into a driver module, instead of as a standalone module.
4507 diff --git a/drivers/usb/host/dwc_common_port/doc/doxygen.cfg b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
4508 new file mode 100644
4509 index 0000000..605b9dab
4511 +++ b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
4515 +#---------------------------------------------------------------------------
4516 +# Project related configuration options
4517 +#---------------------------------------------------------------------------
4518 +PROJECT_NAME = "Synopsys DWC Portability and Common Library for UWB"
4520 +OUTPUT_DIRECTORY = doc
4521 +CREATE_SUBDIRS = NO
4522 +OUTPUT_LANGUAGE = English
4523 +BRIEF_MEMBER_DESC = YES
4525 +ABBREVIATE_BRIEF = "The $name class" \
4526 + "The $name widget" \
4527 + "The $name file" \
4536 +ALWAYS_DETAILED_SEC = YES
4537 +INLINE_INHERITED_MEMB = NO
4538 +FULL_PATH_NAMES = NO
4539 +STRIP_FROM_PATH = ..
4540 +STRIP_FROM_INC_PATH =
4542 +JAVADOC_AUTOBRIEF = YES
4543 +MULTILINE_CPP_IS_BRIEF = NO
4544 +DETAILS_AT_TOP = YES
4546 +SEPARATE_MEMBER_PAGES = NO
4549 +OPTIMIZE_OUTPUT_FOR_C = YES
4550 +OPTIMIZE_OUTPUT_JAVA = NO
4551 +BUILTIN_STL_SUPPORT = NO
4552 +DISTRIBUTE_GROUP_DOC = NO
4554 +#---------------------------------------------------------------------------
4555 +# Build related configuration options
4556 +#---------------------------------------------------------------------------
4558 +EXTRACT_PRIVATE = NO
4559 +EXTRACT_STATIC = YES
4560 +EXTRACT_LOCAL_CLASSES = NO
4561 +EXTRACT_LOCAL_METHODS = NO
4562 +HIDE_UNDOC_MEMBERS = NO
4563 +HIDE_UNDOC_CLASSES = NO
4564 +HIDE_FRIEND_COMPOUNDS = NO
4565 +HIDE_IN_BODY_DOCS = NO
4567 +CASE_SENSE_NAMES = YES
4568 +HIDE_SCOPE_NAMES = NO
4569 +SHOW_INCLUDE_FILES = NO
4571 +SORT_MEMBER_DOCS = NO
4572 +SORT_BRIEF_DOCS = NO
4573 +SORT_BY_SCOPE_NAME = NO
4574 +GENERATE_TODOLIST = YES
4575 +GENERATE_TESTLIST = YES
4576 +GENERATE_BUGLIST = YES
4577 +GENERATE_DEPRECATEDLIST= YES
4579 +MAX_INITIALIZER_LINES = 30
4580 +SHOW_USED_FILES = YES
4581 +SHOW_DIRECTORIES = YES
4582 +FILE_VERSION_FILTER =
4583 +#---------------------------------------------------------------------------
4584 +# configuration options related to warning and progress messages
4585 +#---------------------------------------------------------------------------
4588 +WARN_IF_UNDOCUMENTED = NO
4589 +WARN_IF_DOC_ERROR = YES
4590 +WARN_NO_PARAMDOC = YES
4591 +WARN_FORMAT = "$file:$line: $text"
4593 +#---------------------------------------------------------------------------
4594 +# configuration options related to the input files
4595 +#---------------------------------------------------------------------------
4597 +FILE_PATTERNS = *.c \
4640 +EXCLUDE_SYMLINKS = NO
4643 +EXAMPLE_PATTERNS = *
4644 +EXAMPLE_RECURSIVE = NO
4648 +FILTER_SOURCE_FILES = NO
4649 +#---------------------------------------------------------------------------
4650 +# configuration options related to source browsing
4651 +#---------------------------------------------------------------------------
4652 +SOURCE_BROWSER = NO
4653 +INLINE_SOURCES = NO
4654 +STRIP_CODE_COMMENTS = YES
4655 +REFERENCED_BY_RELATION = YES
4656 +REFERENCES_RELATION = YES
4658 +VERBATIM_HEADERS = NO
4659 +#---------------------------------------------------------------------------
4660 +# configuration options related to the alphabetical class index
4661 +#---------------------------------------------------------------------------
4662 +ALPHABETICAL_INDEX = NO
4663 +COLS_IN_ALPHA_INDEX = 5
4665 +#---------------------------------------------------------------------------
4666 +# configuration options related to the HTML output
4667 +#---------------------------------------------------------------------------
4668 +GENERATE_HTML = YES
4670 +HTML_FILE_EXTENSION = .html
4674 +HTML_ALIGN_MEMBERS = YES
4675 +GENERATE_HTMLHELP = NO
4682 +ENUM_VALUES_PER_LINE = 4
4683 +GENERATE_TREEVIEW = YES
4684 +TREEVIEW_WIDTH = 250
4685 +#---------------------------------------------------------------------------
4686 +# configuration options related to the LaTeX output
4687 +#---------------------------------------------------------------------------
4688 +GENERATE_LATEX = NO
4689 +LATEX_OUTPUT = latex
4690 +LATEX_CMD_NAME = latex
4691 +MAKEINDEX_CMD_NAME = makeindex
4693 +PAPER_TYPE = a4wide
4696 +PDF_HYPERLINKS = NO
4698 +LATEX_BATCHMODE = NO
4699 +LATEX_HIDE_INDICES = NO
4700 +#---------------------------------------------------------------------------
4701 +# configuration options related to the RTF output
4702 +#---------------------------------------------------------------------------
4706 +RTF_HYPERLINKS = NO
4707 +RTF_STYLESHEET_FILE =
4708 +RTF_EXTENSIONS_FILE =
4709 +#---------------------------------------------------------------------------
4710 +# configuration options related to the man page output
4711 +#---------------------------------------------------------------------------
4716 +#---------------------------------------------------------------------------
4717 +# configuration options related to the XML output
4718 +#---------------------------------------------------------------------------
4723 +XML_PROGRAMLISTING = YES
4724 +#---------------------------------------------------------------------------
4725 +# configuration options for the AutoGen Definitions output
4726 +#---------------------------------------------------------------------------
4727 +GENERATE_AUTOGEN_DEF = NO
4728 +#---------------------------------------------------------------------------
4729 +# configuration options related to the Perl module output
4730 +#---------------------------------------------------------------------------
4731 +GENERATE_PERLMOD = NO
4733 +PERLMOD_PRETTY = YES
4734 +PERLMOD_MAKEVAR_PREFIX =
4735 +#---------------------------------------------------------------------------
4736 +# Configuration options related to the preprocessor
4737 +#---------------------------------------------------------------------------
4738 +ENABLE_PREPROCESSING = YES
4739 +MACRO_EXPANSION = NO
4740 +EXPAND_ONLY_PREDEF = NO
4741 +SEARCH_INCLUDES = YES
4743 +INCLUDE_FILE_PATTERNS =
4744 +PREDEFINED = DEBUG DEBUG_MEMORY
4745 +EXPAND_AS_DEFINED =
4746 +SKIP_FUNCTION_MACROS = YES
4747 +#---------------------------------------------------------------------------
4748 +# Configuration::additions related to external references
4749 +#---------------------------------------------------------------------------
4753 +EXTERNAL_GROUPS = YES
4754 +PERL_PATH = /usr/bin/perl
4755 +#---------------------------------------------------------------------------
4756 +# Configuration options related to the dot tool
4757 +#---------------------------------------------------------------------------
4758 +CLASS_DIAGRAMS = YES
4759 +HIDE_UNDOC_RELATIONS = YES
4762 +COLLABORATION_GRAPH = YES
4765 +TEMPLATE_RELATIONS = NO
4767 +INCLUDED_BY_GRAPH = YES
4769 +GRAPHICAL_HIERARCHY = YES
4770 +DIRECTORY_GRAPH = YES
4771 +DOT_IMAGE_FORMAT = png
4774 +MAX_DOT_GRAPH_DEPTH = 1000
4775 +DOT_TRANSPARENT = NO
4776 +DOT_MULTI_TARGETS = NO
4777 +GENERATE_LEGEND = YES
4779 +#---------------------------------------------------------------------------
4780 +# Configuration::additions related to the search engine
4781 +#---------------------------------------------------------------------------
4783 diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.c b/drivers/usb/host/dwc_common_port/dwc_cc.c
4784 new file mode 100644
4785 index 0000000..613c901
4787 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.c
4789 +/* =========================================================================
4790 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
4792 + * $Date: 2010/11/04 $
4793 + * $Change: 1621692 $
4795 + * Synopsys Portability Library Software and documentation
4796 + * (hereinafter, "Software") is an Unsupported proprietary work of
4797 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
4798 + * between Synopsys and you.
4800 + * The Software IS NOT an item of Licensed Software or Licensed Product
4801 + * under any End User Software License Agreement or Agreement for
4802 + * Licensed Product with Synopsys or any supplement thereto. You are
4803 + * permitted to use and redistribute this Software in source and binary
4804 + * forms, with or without modification, provided that redistributions
4805 + * of source code must retain this notice. You may not view, use,
4806 + * disclose, copy or distribute this file or any information contained
4807 + * herein except pursuant to this license grant from Synopsys. If you
4808 + * do not agree with this notice, including the disclaimer below, then
4809 + * you are not authorized to use the Software.
4811 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
4812 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4813 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
4814 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
4815 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
4816 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
4817 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
4818 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
4819 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4820 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
4821 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
4823 + * ========================================================================= */
4826 +#include "dwc_cc.h"
4828 +typedef struct dwc_cc
4836 + DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
4839 +DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
4841 +/** The main structure for CC management. */
4844 + dwc_mutex_t *mutex;
4847 + unsigned is_host:1;
4849 + dwc_notifier_t *notifier;
4851 + struct context_list list;
4855 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
4858 + DWC_PRINTF("%s: ", name);
4859 + for (i=0; i<len; i++) {
4860 + DWC_PRINTF("%02x ", bytes[i]);
4865 +#define dump_bytes(x...)
4868 +static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
4870 + dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
4874 + DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
4877 + cc->length = length;
4878 + cc->name = dwc_alloc(mem_ctx, length);
4880 + dwc_free(mem_ctx, cc);
4884 + DWC_MEMCPY(cc->name, name, length);
4890 +static void free_cc(void *mem_ctx, dwc_cc_t *cc)
4893 + dwc_free(mem_ctx, cc->name);
4895 + dwc_free(mem_ctx, cc);
4898 +static uint32_t next_uid(dwc_cc_if_t *cc_if)
4902 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4903 + if (cc->uid > uid) {
4915 +static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
4918 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4919 + if (cc->uid == uid) {
4926 +static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
4928 + unsigned int size = 0;
4930 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4933 + size += cc->length;
4939 +static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
4944 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4945 + if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
4952 +static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
4957 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
4958 + if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
4966 +/* Internal cc_add */
4967 +static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
4968 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
4973 + if (cc_if->is_host) {
4974 + uid = cc_match_cdid(cc_if, cdid);
4977 + uid = cc_match_chid(cc_if, chid);
4981 + DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
4982 + cc = cc_find(cc_if, uid);
4985 + cc = alloc_cc(mem_ctx, name, length);
4986 + cc->uid = next_uid(cc_if);
4987 + DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
4990 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
4991 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
4992 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
4994 + DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
4995 + dump_bytes("CHID", cc->chid, 16);
4996 + dump_bytes("CDID", cc->cdid, 16);
4997 + dump_bytes("CK", cc->ck, 16);
5001 +/* Internal cc_clear */
5002 +static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
5004 + while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
5005 + dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
5006 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
5007 + free_cc(mem_ctx, cc);
5011 +dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
5012 + dwc_notifier_t *notifier, unsigned is_host)
5014 + dwc_cc_if_t *cc_if = NULL;
5016 + /* Allocate a common_cc_if structure */
5017 + cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
5022 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
5023 + DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
5025 + cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
5027 + if (!cc_if->mutex) {
5028 + dwc_free(mem_ctx, cc_if);
5032 + DWC_CIRCLEQ_INIT(&cc_if->list);
5033 + cc_if->is_host = is_host;
5034 + cc_if->notifier = notifier;
5038 +void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
5040 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
5041 + DWC_MUTEX_FREE(cc_if->mutex);
5043 + dwc_mutex_free(mtx_ctx, cc_if->mutex);
5045 + cc_clear(mem_ctx, cc_if);
5046 + dwc_free(mem_ctx, cc_if);
5049 +static void cc_changed(dwc_cc_if_t *cc_if)
5051 + if (cc_if->notifier) {
5052 + dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
5056 +void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
5058 + DWC_MUTEX_LOCK(cc_if->mutex);
5059 + cc_clear(mem_ctx, cc_if);
5060 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5061 + cc_changed(cc_if);
5064 +int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
5065 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
5069 + DWC_MUTEX_LOCK(cc_if->mutex);
5070 + uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
5071 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5072 + cc_changed(cc_if);
5077 +void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
5078 + uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
5082 + DWC_DEBUGC("Change connection context %d", id);
5084 + DWC_MUTEX_LOCK(cc_if->mutex);
5085 + cc = cc_find(cc_if, id);
5087 + DWC_ERROR("Uid %d not found in cc list\n", id);
5088 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5093 + DWC_MEMCPY(&(cc->chid[0]), chid, 16);
5096 + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
5099 + DWC_MEMCPY(&(cc->ck[0]), ck, 16);
5104 + dwc_free(mem_ctx, cc->name);
5106 + cc->name = dwc_alloc(mem_ctx, length);
5108 + DWC_ERROR("Out of memory in dwc_cc_change()\n");
5109 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5112 + cc->length = length;
5113 + DWC_MEMCPY(cc->name, name, length);
5116 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5118 + cc_changed(cc_if);
5120 + DWC_DEBUGC("Changed connection context id=%d\n", id);
5121 + dump_bytes("New CHID", cc->chid, 16);
5122 + dump_bytes("New CDID", cc->cdid, 16);
5123 + dump_bytes("New CK", cc->ck, 16);
5126 +void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
5130 + DWC_DEBUGC("Removing connection context %d", id);
5132 + DWC_MUTEX_LOCK(cc_if->mutex);
5133 + cc = cc_find(cc_if, id);
5135 + DWC_ERROR("Uid %d not found in cc list\n", id);
5136 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5140 + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
5141 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5142 + free_cc(mem_ctx, cc);
5144 + cc_changed(cc_if);
5147 +uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
5153 + DWC_MUTEX_LOCK(cc_if->mutex);
5154 + *length = cc_data_size(cc_if);
5156 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5160 + DWC_DEBUGC("Creating data for saving (length=%d)", *length);
5162 + buf = dwc_alloc(mem_ctx, *length);
5165 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5170 + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
5171 + DWC_MEMCPY(x, cc->chid, 16);
5173 + DWC_MEMCPY(x, cc->cdid, 16);
5175 + DWC_MEMCPY(x, cc->ck, 16);
5178 + DWC_MEMCPY(x, &cc->length, 1);
5180 + DWC_MEMCPY(x, cc->name, cc->length);
5184 + DWC_MEMCPY(x, &zero, 1);
5188 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5193 +void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
5195 + uint8_t name_length;
5202 + DWC_MUTEX_LOCK(cc_if->mutex);
5203 + cc_clear(mem_ctx, cc_if);
5205 + while (i < length) {
5213 + name_length = data[i];
5216 + if (name_length) {
5224 + /* check to see if we haven't overflown the buffer */
5226 + DWC_ERROR("Data format error while attempting to load CCs "
5227 + "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
5231 + cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
5233 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5235 + cc_changed(cc_if);
5238 +uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
5242 + DWC_MUTEX_LOCK(cc_if->mutex);
5243 + uid = cc_match_chid(cc_if, chid);
5244 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5247 +uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
5251 + DWC_MUTEX_LOCK(cc_if->mutex);
5252 + uid = cc_match_cdid(cc_if, cdid);
5253 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5257 +uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
5259 + uint8_t *ck = NULL;
5262 + DWC_MUTEX_LOCK(cc_if->mutex);
5263 + cc = cc_find(cc_if, id);
5267 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5273 +uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
5275 + uint8_t *retval = NULL;
5278 + DWC_MUTEX_LOCK(cc_if->mutex);
5279 + cc = cc_find(cc_if, id);
5281 + retval = cc->chid;
5283 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5288 +uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
5290 + uint8_t *retval = NULL;
5293 + DWC_MUTEX_LOCK(cc_if->mutex);
5294 + cc = cc_find(cc_if, id);
5296 + retval = cc->cdid;
5298 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5303 +uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
5305 + uint8_t *retval = NULL;
5308 + DWC_MUTEX_LOCK(cc_if->mutex);
5310 + cc = cc_find(cc_if, id);
5312 + *length = cc->length;
5313 + retval = cc->name;
5315 + DWC_MUTEX_UNLOCK(cc_if->mutex);
5320 +#endif /* DWC_CCLIB */
5321 diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.h b/drivers/usb/host/dwc_common_port/dwc_cc.h
5322 new file mode 100644
5323 index 0000000..6b2bbaf
5325 +++ b/drivers/usb/host/dwc_common_port/dwc_cc.h
5327 +/* =========================================================================
5328 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $
5330 + * $Date: 2010/09/28 $
5331 + * $Change: 1596182 $
5333 + * Synopsys Portability Library Software and documentation
5334 + * (hereinafter, "Software") is an Unsupported proprietary work of
5335 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
5336 + * between Synopsys and you.
5338 + * The Software IS NOT an item of Licensed Software or Licensed Product
5339 + * under any End User Software License Agreement or Agreement for
5340 + * Licensed Product with Synopsys or any supplement thereto. You are
5341 + * permitted to use and redistribute this Software in source and binary
5342 + * forms, with or without modification, provided that redistributions
5343 + * of source code must retain this notice. You may not view, use,
5344 + * disclose, copy or distribute this file or any information contained
5345 + * herein except pursuant to this license grant from Synopsys. If you
5346 + * do not agree with this notice, including the disclaimer below, then
5347 + * you are not authorized to use the Software.
5349 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
5350 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5351 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
5352 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
5353 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
5354 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
5355 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
5356 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
5357 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5358 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
5359 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
5361 + * ========================================================================= */
5371 + * This file defines the Context Context library.
5373 + * The main data structure is dwc_cc_if_t which is returned by either the
5374 + * dwc_cc_if_alloc function or returned by the module to the user via a provided
5375 + * function. The data structure is opaque and should only be manipulated via the
5376 + * functions provied in this API.
5378 + * It manages a list of connection contexts and operations can be performed to
5379 + * add, remove, query, search, and change, those contexts. Additionally,
5380 + * a dwc_notifier_t object can be requested from the manager so that
5381 + * the user can be notified whenever the context list has changed.
5384 +#include "dwc_os.h"
5385 +#include "dwc_list.h"
5386 +#include "dwc_notifier.h"
5389 +/* Notifications */
5390 +#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
5393 +typedef struct dwc_cc_if dwc_cc_if_t;
5396 +/** @name Connection Context Operations */
5399 +/** This function allocates memory for a dwc_cc_if_t structure, initializes
5400 + * fields to default values, and returns a pointer to the structure or NULL on
5402 +extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
5403 + dwc_notifier_t *notifier, unsigned is_host);
5405 +/** Frees the memory for the specified CC structure allocated from
5406 + * dwc_cc_if_alloc(). */
5407 +extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if);
5409 +/** Removes all contexts from the connection context list */
5410 +extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if);
5412 +/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
5413 + * If a CHID already exists, the CK and name are overwritten. Statistics are
5414 + * not overwritten.
5416 + * @param cc_if The cc_if structure.
5417 + * @param chid A pointer to the 16-byte CHID. This value will be copied.
5418 + * @param ck A pointer to the 16-byte CK. This value will be copied.
5419 + * @param cdid A pointer to the 16-byte CDID. This value will be copied.
5420 + * @param name An optional host friendly name as defined in the association model
5421 + * spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name.
5422 + * @param length The length othe unicode string.
5423 + * @return A unique identifier used to refer to this context that is valid for
5424 + * as long as this context is still in the list. */
5425 +extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
5426 + uint8_t *cdid, uint8_t *ck, uint8_t *name,
5429 +/** Changes the CHID, CK, CDID, or Name values of a connection context in the
5430 + * list, preserving any accumulated statistics. This would typically be called
5431 + * if the host decideds to change the context with a SET_CONNECTION request.
5433 + * @param cc_if The cc_if structure.
5434 + * @param id The identifier of the connection context.
5435 + * @param chid A pointer to the 16-byte CHID. This value will be copied. NULL
5436 + * indicates no change.
5437 + * @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL
5438 + * indicates no change.
5439 + * @param ck A pointer to the 16-byte CK. This value will be copied. NULL
5440 + * indicates no change.
5441 + * @param name Host friendly name UTF16-LE. NULL indicates no change.
5442 + * @param length Length of name. */
5443 +extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id,
5444 + uint8_t *chid, uint8_t *cdid, uint8_t *ck,
5445 + uint8_t *name, uint8_t length);
5447 +/** Remove the specified connection context.
5448 + * @param cc_if The cc_if structure.
5449 + * @param id The identifier of the connection context to remove. */
5450 +extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id);
5452 +/** Get a binary block of data for the connection context list and attributes.
5453 + * This data can be used by the OS specific driver to save the connection
5454 + * context list into non-volatile memory.
5456 + * @param cc_if The cc_if structure.
5457 + * @param length Return the length of the data buffer.
5458 + * @return A pointer to the data buffer. The memory for this buffer should be
5459 + * freed with DWC_FREE() after use. */
5460 +extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if,
5461 + unsigned int *length);
5463 +/** Restore the connection context list from the binary data that was previously
5464 + * returned from a call to dwc_cc_data_for_save. This can be used by the OS specific
5465 + * driver to load a connection context list from non-volatile memory.
5467 + * @param cc_if The cc_if structure.
5468 + * @param data The data bytes as returned from dwc_cc_data_for_save.
5469 + * @param length The length of the data. */
5470 +extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if,
5471 + uint8_t *data, unsigned int length);
5473 +/** Find the connection context from the specified CHID.
5475 + * @param cc_if The cc_if structure.
5476 + * @param chid A pointer to the CHID data.
5477 + * @return A non-zero identifier of the connection context if the CHID matches.
5478 + * Otherwise returns 0. */
5479 +extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
5481 +/** Find the connection context from the specified CDID.
5483 + * @param cc_if The cc_if structure.
5484 + * @param cdid A pointer to the CDID data.
5485 + * @return A non-zero identifier of the connection context if the CHID matches.
5486 + * Otherwise returns 0. */
5487 +extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
5489 +/** Retrieve the CK from the specified connection context.
5491 + * @param cc_if The cc_if structure.
5492 + * @param id The identifier of the connection context.
5493 + * @return A pointer to the CK data. The memory does not need to be freed. */
5494 +extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
5496 +/** Retrieve the CHID from the specified connection context.
5498 + * @param cc_if The cc_if structure.
5499 + * @param id The identifier of the connection context.
5500 + * @return A pointer to the CHID data. The memory does not need to be freed. */
5501 +extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
5503 +/** Retrieve the CDID from the specified connection context.
5505 + * @param cc_if The cc_if structure.
5506 + * @param id The identifier of the connection context.
5507 + * @return A pointer to the CDID data. The memory does not need to be freed. */
5508 +extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
5510 +extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
5512 +/** Checks a buffer for non-zero.
5513 + * @param id A pointer to a 16 byte buffer.
5514 + * @return true if the 16 byte value is non-zero. */
5515 +static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
5517 + for (i=0; i<16; i++) {
5518 + if (id[i]) return 1;
5523 +/** Checks a buffer for zero.
5524 + * @param id A pointer to a 16 byte buffer.
5525 + * @return true if the 16 byte value is zero. */
5526 +static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
5527 + return !dwc_assoc_is_not_zero_id(id);
5530 +/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
5532 +static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
5533 + char *ptr = buffer;
5535 + for (i=0; i<16; i++) {
5536 + ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
5538 + ptr += DWC_SPRINTF(ptr, " ");
5541 + return ptr - buffer;
5550 +#endif /* _DWC_CC_H_ */
5552 diff --git a/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
5553 new file mode 100644
5554 index 0000000..6dd04b5
5556 +++ b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
5558 +#include "dwc_os.h"
5559 +#include "dwc_list.h"
5562 +# include "dwc_cc.h"
5565 +#ifdef DWC_CRYPTOLIB
5566 +# include "dwc_modpow.h"
5567 +# include "dwc_dh.h"
5568 +# include "dwc_crypto.h"
5571 +#ifdef DWC_NOTIFYLIB
5572 +# include "dwc_notifier.h"
5575 +/* OS-Level Implementations */
5577 +/* This is the FreeBSD 7.0 kernel implementation of the DWC platform library. */
5582 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
5584 + return memset(dest, byte, size);
5587 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
5589 + return memcpy(dest, src, size);
5592 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
5594 + bcopy(src, dest, size);
5598 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
5600 + return memcmp(m1, m2, size);
5603 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
5605 + return strncmp(s1, s2, size);
5608 +int DWC_STRCMP(void *s1, void *s2)
5610 + return strcmp(s1, s2);
5613 +int DWC_STRLEN(char const *str)
5615 + return strlen(str);
5618 +char *DWC_STRCPY(char *to, char const *from)
5620 + return strcpy(to, from);
5623 +char *DWC_STRDUP(char const *str)
5625 + int len = DWC_STRLEN(str) + 1;
5626 + char *new = DWC_ALLOC_ATOMIC(len);
5632 + DWC_MEMCPY(new, str, len);
5636 +int DWC_ATOI(char *str, int32_t *value)
5640 + *value = strtol(str, &end, 0);
5641 + if (*end == '\0') {
5648 +int DWC_ATOUI(char *str, uint32_t *value)
5652 + *value = strtoul(str, &end, 0);
5653 + if (*end == '\0') {
5662 +/* From usbstring.c */
5664 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
5670 + /* this insists on correct encodings, though not minimal ones.
5671 + * BUT it currently rejects legit 4-byte UTF-8 code points,
5672 + * which need surrogate pairs. (Unicode 3.1 can use them.)
5674 + while (len != 0 && (c = (u8) *s++) != 0) {
5675 + if (unlikely(c & 0x80)) {
5676 + // 2-byte sequence:
5677 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
5678 + if ((c & 0xe0) == 0xc0) {
5679 + uchar = (c & 0x1f) << 6;
5682 + if ((c & 0xc0) != 0xc0)
5687 + // 3-byte sequence (most CJKV characters):
5688 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
5689 + } else if ((c & 0xf0) == 0xe0) {
5690 + uchar = (c & 0x0f) << 12;
5693 + if ((c & 0xc0) != 0xc0)
5699 + if ((c & 0xc0) != 0xc0)
5704 + /* no bogus surrogates */
5705 + if (0xd800 <= uchar && uchar <= 0xdfff)
5708 + // 4-byte sequence (surrogate pairs, currently rare):
5709 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
5710 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
5711 + // (uuuuu = wwww + 1)
5712 + // FIXME accept the surrogate code points (only)
5717 + put_unaligned (cpu_to_le16 (uchar), cp++);
5726 +#endif /* DWC_UTFLIB */
5731 +dwc_bool_t DWC_IN_IRQ(void)
5733 +// return in_irq();
5737 +dwc_bool_t DWC_IN_BH(void)
5739 +// return in_softirq();
5743 +void DWC_VPRINTF(char *format, va_list args)
5745 + vprintf(format, args);
5748 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
5750 + return vsnprintf(str, size, format, args);
5753 +void DWC_PRINTF(char *format, ...)
5757 + va_start(args, format);
5758 + DWC_VPRINTF(format, args);
5762 +int DWC_SPRINTF(char *buffer, char *format, ...)
5767 + va_start(args, format);
5768 + retval = vsprintf(buffer, format, args);
5773 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
5778 + va_start(args, format);
5779 + retval = vsnprintf(buffer, size, format, args);
5784 +void __DWC_WARN(char *format, ...)
5788 + va_start(args, format);
5789 + DWC_VPRINTF(format, args);
5793 +void __DWC_ERROR(char *format, ...)
5797 + va_start(args, format);
5798 + DWC_VPRINTF(format, args);
5802 +void DWC_EXCEPTION(char *format, ...)
5806 + va_start(args, format);
5807 + DWC_VPRINTF(format, args);
5813 +void __DWC_DEBUG(char *format, ...)
5817 + va_start(args, format);
5818 + DWC_VPRINTF(format, args);
5827 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
5831 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
5832 + size, align, alloc);
5833 + return (dwc_pool_t *)pool;
5836 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
5838 + dma_pool_destroy((struct dma_pool *)pool);
5841 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
5843 +// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
5844 + return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
5847 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
5849 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
5853 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
5855 + dma_pool_free(pool, vaddr, daddr);
5859 +static void dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
5863 + *(bus_addr_t *)arg = segs[0].ds_addr;
5866 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
5868 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
5871 + error = bus_dma_tag_create(
5872 +#if __FreeBSD_version >= 700000
5873 + bus_get_dma_tag(dma->dev), /* parent */
5875 + NULL, /* parent */
5877 + 4, 0, /* alignment, bounds */
5878 + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
5879 + BUS_SPACE_MAXADDR, /* highaddr */
5880 + NULL, NULL, /* filter, filterarg */
5881 + size, /* maxsize */
5882 + 1, /* nsegments */
5883 + size, /* maxsegsize */
5885 + NULL, /* lockfunc */
5886 + NULL, /* lockarg */
5889 + device_printf(dma->dev, "%s: bus_dma_tag_create failed: %d\n",
5894 + error = bus_dmamem_alloc(dma->dma_tag, &dma->dma_vaddr,
5895 + BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map);
5897 + device_printf(dma->dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n",
5898 + __func__, (uintmax_t)size, error);
5902 + dma->dma_paddr = 0;
5903 + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size,
5904 + dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT);
5905 + if (error || dma->dma_paddr == 0) {
5906 + device_printf(dma->dev, "%s: bus_dmamap_load failed: %d\n",
5911 + *dma_addr = dma->dma_paddr;
5912 + return dma->dma_vaddr;
5915 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
5917 + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
5918 + bus_dma_tag_destroy(dma->dma_tag);
5920 + dma->dma_map = NULL;
5921 + dma->dma_tag = NULL;
5926 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
5928 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
5930 + if (dma->dma_tag == NULL)
5932 + if (dma->dma_map != NULL) {
5933 + bus_dmamap_sync(dma->dma_tag, dma->dma_map,
5934 + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
5935 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
5936 + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
5937 + dma->dma_map = NULL;
5940 + bus_dma_tag_destroy(dma->dma_tag);
5941 + dma->dma_tag = NULL;
5944 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
5946 + return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
5949 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
5951 + return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
5954 +void __DWC_FREE(void *mem_ctx, void *addr)
5956 + free(addr, M_DEVBUF);
5960 +#ifdef DWC_CRYPTOLIB
5963 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
5965 + get_random_bytes(buffer, length);
5968 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
5970 + struct crypto_blkcipher *tfm;
5971 + struct blkcipher_desc desc;
5972 + struct scatterlist sgd;
5973 + struct scatterlist sgs;
5975 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
5976 + if (tfm == NULL) {
5977 + printk("failed to load transform for aes CBC\n");
5981 + crypto_blkcipher_setkey(tfm, key, keylen);
5982 + crypto_blkcipher_set_iv(tfm, iv, 16);
5984 + sg_init_one(&sgd, out, messagelen);
5985 + sg_init_one(&sgs, message, messagelen);
5990 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
5991 + crypto_free_blkcipher(tfm);
5992 + DWC_ERROR("AES CBC encryption failed");
5996 + crypto_free_blkcipher(tfm);
6000 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
6002 + struct crypto_hash *tfm;
6003 + struct hash_desc desc;
6004 + struct scatterlist sg;
6006 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
6007 + if (IS_ERR(tfm)) {
6008 + DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
6014 + sg_init_one(&sg, message, len);
6015 + crypto_hash_digest(&desc, &sg, len, out);
6016 + crypto_free_hash(tfm);
6021 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
6022 + uint8_t *key, uint32_t keylen, uint8_t *out)
6024 + struct crypto_hash *tfm;
6025 + struct hash_desc desc;
6026 + struct scatterlist sg;
6028 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
6029 + if (IS_ERR(tfm)) {
6030 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
6036 + sg_init_one(&sg, message, messagelen);
6037 + crypto_hash_setkey(tfm, key, keylen);
6038 + crypto_hash_digest(&desc, &sg, messagelen, out);
6039 + crypto_free_hash(tfm);
6044 +#endif /* DWC_CRYPTOLIB */
6047 +/* Byte Ordering Conversions */
6049 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
6051 +#ifdef __LITTLE_ENDIAN
6054 + uint8_t *u_p = (uint8_t *)p;
6056 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6060 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
6062 +#ifdef __BIG_ENDIAN
6065 + uint8_t *u_p = (uint8_t *)p;
6067 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6071 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
6073 +#ifdef __LITTLE_ENDIAN
6076 + uint8_t *u_p = (uint8_t *)p;
6078 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6082 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
6084 +#ifdef __BIG_ENDIAN
6087 + uint8_t *u_p = (uint8_t *)p;
6089 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
6093 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
6095 +#ifdef __LITTLE_ENDIAN
6098 + uint8_t *u_p = (uint8_t *)p;
6099 + return (u_p[1] | (u_p[0] << 8));
6103 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
6105 +#ifdef __BIG_ENDIAN
6108 + uint8_t *u_p = (uint8_t *)p;
6109 + return (u_p[1] | (u_p[0] << 8));
6113 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
6115 +#ifdef __LITTLE_ENDIAN
6118 + uint8_t *u_p = (uint8_t *)p;
6119 + return (u_p[1] | (u_p[0] << 8));
6123 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
6125 +#ifdef __BIG_ENDIAN
6128 + uint8_t *u_p = (uint8_t *)p;
6129 + return (u_p[1] | (u_p[0] << 8));
6136 +uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
6138 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6139 + bus_size_t ior = (bus_size_t)reg;
6141 + return bus_space_read_4(io->iot, io->ioh, ior);
6145 +uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
6147 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6148 + bus_size_t ior = (bus_size_t)reg;
6150 + return bus_space_read_8(io->iot, io->ioh, ior);
6154 +void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
6156 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6157 + bus_size_t ior = (bus_size_t)reg;
6159 + bus_space_write_4(io->iot, io->ioh, ior, value);
6163 +void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
6165 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6166 + bus_size_t ior = (bus_size_t)reg;
6168 + bus_space_write_8(io->iot, io->ioh, ior, value);
6172 +void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
6173 + uint32_t set_mask)
6175 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6176 + bus_size_t ior = (bus_size_t)reg;
6178 + bus_space_write_4(io->iot, io->ioh, ior,
6179 + (bus_space_read_4(io->iot, io->ioh, ior) &
6180 + ~clear_mask) | set_mask);
6184 +void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
6185 + uint64_t set_mask)
6187 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
6188 + bus_size_t ior = (bus_size_t)reg;
6190 + bus_space_write_8(io->iot, io->ioh, ior,
6191 + (bus_space_read_8(io->iot, io->ioh, ior) &
6192 + ~clear_mask) | set_mask);
6199 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
6201 + struct mtx *sl = DWC_ALLOC(sizeof(*sl));
6204 + DWC_ERROR("Cannot allocate memory for spinlock");
6208 + mtx_init(sl, "dw3spn", NULL, MTX_SPIN);
6209 + return (dwc_spinlock_t *)sl;
6212 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
6214 + struct mtx *sl = (struct mtx *)lock;
6220 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
6222 + mtx_lock_spin((struct mtx *)lock); // ???
6225 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
6227 + mtx_unlock_spin((struct mtx *)lock); // ???
6230 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
6232 + mtx_lock_spin((struct mtx *)lock);
6235 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
6237 + mtx_unlock_spin((struct mtx *)lock);
6240 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
6243 + dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mtx));
6246 + DWC_ERROR("Cannot allocate memory for mutex");
6250 + m = (struct mtx *)mutex;
6251 + mtx_init(m, "dw3mtx", NULL, MTX_DEF);
6255 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
6257 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
6259 + mtx_destroy((struct mtx *)mutex);
6264 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
6266 + struct mtx *m = (struct mtx *)mutex;
6271 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
6273 + struct mtx *m = (struct mtx *)mutex;
6275 + return mtx_trylock(m);
6278 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
6280 + struct mtx *m = (struct mtx *)mutex;
6288 +void DWC_UDELAY(uint32_t usecs)
6293 +void DWC_MDELAY(uint32_t msecs)
6297 + } while (--msecs);
6300 +void DWC_MSLEEP(uint32_t msecs)
6302 + struct timeval tv;
6304 + tv.tv_sec = msecs / 1000;
6305 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
6306 + pause("dw3slp", tvtohz(&tv));
6309 +uint32_t DWC_TIME(void)
6311 + struct timeval tv;
6313 + microuptime(&tv); // or getmicrouptime? (less precise, but faster)
6314 + return tv.tv_sec * 1000 + tv.tv_usec / 1000;
6323 + dwc_spinlock_t *lock;
6324 + dwc_timer_callback_t cb;
6328 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
6330 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
6333 + DWC_ERROR("Cannot allocate memory for timer");
6337 + callout_init(&t->t, 1);
6339 + t->name = DWC_STRDUP(name);
6341 + DWC_ERROR("Cannot allocate memory for timer->name");
6345 + t->lock = DWC_SPINLOCK_ALLOC();
6347 + DWC_ERROR("Cannot allocate memory for lock");
6357 + DWC_FREE(t->name);
6364 +void DWC_TIMER_FREE(dwc_timer_t *timer)
6366 + callout_stop(&timer->t);
6367 + DWC_SPINLOCK_FREE(timer->lock);
6368 + DWC_FREE(timer->name);
6372 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
6374 + struct timeval tv;
6376 + tv.tv_sec = time / 1000;
6377 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
6378 + callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
6381 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
6383 + callout_stop(&timer->t);
6394 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
6396 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
6399 + DWC_ERROR("Cannot allocate memory for waitqueue");
6403 + mtx_init(&wq->lock, "dw3wtq", NULL, MTX_DEF);
6409 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
6411 + mtx_destroy(&wq->lock);
6415 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
6420 + mtx_lock(&wq->lock);
6423 + /* Skip the sleep if already aborted or triggered */
6424 + if (!wq->abort && !cond(data)) {
6426 + result = msleep(wq, &wq->lock, PCATCH, "dw3wat", 0); // infinite timeout
6430 + if (result == ERESTART) { // signaled - restart
6431 + result = -DWC_E_RESTART;
6433 + } else if (result == EINTR) { // signaled - interrupt
6434 + result = -DWC_E_ABORT;
6436 + } else if (wq->abort) {
6437 + result = -DWC_E_ABORT;
6445 + mtx_unlock(&wq->lock);
6449 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
6450 + void *data, int32_t msecs)
6452 + struct timeval tv, tv1, tv2;
6456 + tv.tv_sec = msecs / 1000;
6457 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
6459 + mtx_lock(&wq->lock);
6462 + /* Skip the sleep if already aborted or triggered */
6463 + if (!wq->abort && !cond(data)) {
6465 + getmicrouptime(&tv1);
6466 + result = msleep(wq, &wq->lock, PCATCH, "dw3wto", tvtohz(&tv));
6467 + getmicrouptime(&tv2);
6471 + if (result == 0) { // awoken
6473 + result = -DWC_E_ABORT;
6475 + tv2.tv_usec -= tv1.tv_usec;
6476 + if (tv2.tv_usec < 0) {
6477 + tv2.tv_usec += 1000000;
6481 + tv2.tv_sec -= tv1.tv_sec;
6482 + result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
6483 + result = msecs - result;
6487 + } else if (result == ERESTART) { // signaled - restart
6488 + result = -DWC_E_RESTART;
6490 + } else if (result == EINTR) { // signaled - interrupt
6491 + result = -DWC_E_ABORT;
6493 + } else { // timed out
6494 + result = -DWC_E_TIMEOUT;
6499 + mtx_unlock(&wq->lock);
6503 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
6508 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
6512 + mtx_lock(&wq->lock);
6517 + mtx_unlock(&wq->lock);
6523 +struct dwc_thread {
6524 + struct proc *proc;
6528 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
6531 + dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
6537 + thread->abort = 0;
6538 + retval = kthread_create((void (*)(void *))func, data, &thread->proc,
6539 + RFPROC | RFNOWAIT, 0, "%s", name);
6548 +int DWC_THREAD_STOP(dwc_thread_t *thread)
6552 + thread->abort = 1;
6553 + retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
6555 + if (retval == 0) {
6556 + /* DWC_THREAD_EXIT() will free the thread struct */
6560 + /* NOTE: We leak the thread struct if thread doesn't die */
6562 + if (retval == EWOULDBLOCK) {
6563 + return -DWC_E_TIMEOUT;
6566 + return -DWC_E_UNKNOWN;
6569 +dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
6571 + return thread->abort;
6574 +void DWC_THREAD_EXIT(dwc_thread_t *thread)
6576 + wakeup(&thread->abort);
6583 + - Runs in interrupt context (cannot sleep)
6584 + - Each tasklet runs on a single CPU [ How can we ensure this on FreeBSD? Does it matter? ]
6585 + - Different tasklets can be running simultaneously on different CPUs [ shouldn't matter ]
6587 +struct dwc_tasklet {
6589 + dwc_tasklet_callback_t cb;
6593 +static void tasklet_callback(void *data, int pending) // what to do with pending ???
6595 + dwc_tasklet_t *task = (dwc_tasklet_t *)data;
6597 + task->cb(task->data);
6600 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
6602 + dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
6606 + task->data = data;
6607 + TASK_INIT(&task->t, 0, tasklet_callback, task);
6609 + DWC_ERROR("Cannot allocate memory for tasklet");
6615 +void DWC_TASK_FREE(dwc_tasklet_t *task)
6617 + taskqueue_drain(taskqueue_fast, &task->t); // ???
6621 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
6623 + /* Uses predefined system queue */
6624 + taskqueue_enqueue_fast(taskqueue_fast, &task->t);
6629 + - Runs in process context (can sleep)
6631 +typedef struct work_container {
6632 + dwc_work_callback_t cb;
6639 + DWC_CIRCLEQ_ENTRY(work_container) entry;
6642 +} work_container_t;
6645 +DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
6649 + struct taskqueue *taskq;
6650 + dwc_spinlock_t *lock;
6651 + dwc_waitq_t *waitq;
6655 + struct work_container_queue entries;
6659 +static void do_work(void *data, int pending) // what to do with pending ???
6661 + work_container_t *container = (work_container_t *)data;
6662 + dwc_workq_t *wq = container->wq;
6663 + dwc_irqflags_t flags;
6665 + if (container->hz) {
6666 + pause("dw3wrk", container->hz);
6669 + container->cb(container->data);
6670 + DWC_DEBUG("Work done: %s, container=%p", container->name, container);
6672 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6675 + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
6677 + if (container->name)
6678 + DWC_FREE(container->name);
6679 + DWC_FREE(container);
6681 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6682 + DWC_WAITQ_TRIGGER(wq->waitq);
6685 +static int work_done(void *data)
6687 + dwc_workq_t *workq = (dwc_workq_t *)data;
6689 + return workq->pending == 0;
6692 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
6694 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
6697 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
6699 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
6702 + DWC_ERROR("Cannot allocate memory for workqueue");
6706 + wq->taskq = taskqueue_create(name, M_NOWAIT, taskqueue_thread_enqueue, &wq->taskq);
6708 + DWC_ERROR("Cannot allocate memory for taskqueue");
6714 + wq->lock = DWC_SPINLOCK_ALLOC();
6716 + DWC_ERROR("Cannot allocate memory for spinlock");
6720 + wq->waitq = DWC_WAITQ_ALLOC();
6722 + DWC_ERROR("Cannot allocate memory for waitqueue");
6726 + taskqueue_start_threads(&wq->taskq, 1, PWAIT, "%s taskq", "dw3tsk");
6729 + DWC_CIRCLEQ_INIT(&wq->entries);
6734 + DWC_SPINLOCK_FREE(wq->lock);
6736 + taskqueue_free(wq->taskq);
6743 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
6746 + dwc_irqflags_t flags;
6748 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6750 + if (wq->pending != 0) {
6751 + struct work_container *container;
6753 + DWC_ERROR("Destroying work queue with pending work");
6755 + DWC_CIRCLEQ_FOREACH(container, &wq->entries, entry) {
6756 + DWC_ERROR("Work %s still pending", container->name);
6760 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6762 + DWC_WAITQ_FREE(wq->waitq);
6763 + DWC_SPINLOCK_FREE(wq->lock);
6764 + taskqueue_free(wq->taskq);
6768 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
6769 + char *format, ...)
6771 + dwc_irqflags_t flags;
6772 + work_container_t *container;
6773 + static char name[128];
6776 + va_start(args, format);
6777 + DWC_VSNPRINTF(name, 128, format, args);
6780 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6782 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6783 + DWC_WAITQ_TRIGGER(wq->waitq);
6785 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
6787 + DWC_ERROR("Cannot allocate memory for container");
6791 + container->name = DWC_STRDUP(name);
6792 + if (!container->name) {
6793 + DWC_ERROR("Cannot allocate memory for container->name");
6794 + DWC_FREE(container);
6798 + container->cb = cb;
6799 + container->data = data;
6800 + container->wq = wq;
6801 + container->hz = 0;
6803 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
6805 + TASK_INIT(&container->task, 0, do_work, container);
6808 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
6810 + taskqueue_enqueue_fast(wq->taskq, &container->task);
6813 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
6814 + void *data, uint32_t time, char *format, ...)
6816 + dwc_irqflags_t flags;
6817 + work_container_t *container;
6818 + static char name[128];
6819 + struct timeval tv;
6822 + va_start(args, format);
6823 + DWC_VSNPRINTF(name, 128, format, args);
6826 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
6828 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
6829 + DWC_WAITQ_TRIGGER(wq->waitq);
6831 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
6833 + DWC_ERROR("Cannot allocate memory for container");
6837 + container->name = DWC_STRDUP(name);
6838 + if (!container->name) {
6839 + DWC_ERROR("Cannot allocate memory for container->name");
6840 + DWC_FREE(container);
6844 + container->cb = cb;
6845 + container->data = data;
6846 + container->wq = wq;
6848 + tv.tv_sec = time / 1000;
6849 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
6850 + container->hz = tvtohz(&tv);
6852 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
6854 + TASK_INIT(&container->task, 0, do_work, container);
6857 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
6859 + taskqueue_enqueue_fast(wq->taskq, &container->task);
6862 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
6864 + return wq->pending;
6866 diff --git a/drivers/usb/host/dwc_common_port/dwc_common_linux.c b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
6867 new file mode 100644
6868 index 0000000..f00a9ff
6870 +++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
6872 +#include <linux/kernel.h>
6873 +#include <linux/init.h>
6874 +#include <linux/module.h>
6875 +#include <linux/kthread.h>
6878 +# include "dwc_cc.h"
6881 +#ifdef DWC_CRYPTOLIB
6882 +# include "dwc_modpow.h"
6883 +# include "dwc_dh.h"
6884 +# include "dwc_crypto.h"
6887 +#ifdef DWC_NOTIFYLIB
6888 +# include "dwc_notifier.h"
6891 +/* OS-Level Implementations */
6893 +/* This is the Linux kernel implementation of the DWC platform library. */
6894 +#include <linux/moduleparam.h>
6895 +#include <linux/ctype.h>
6896 +#include <linux/crypto.h>
6897 +#include <linux/delay.h>
6898 +#include <linux/device.h>
6899 +#include <linux/dma-mapping.h>
6900 +#include <linux/cdev.h>
6901 +#include <linux/errno.h>
6902 +#include <linux/interrupt.h>
6903 +#include <linux/jiffies.h>
6904 +#include <linux/list.h>
6905 +#include <linux/pci.h>
6906 +#include <linux/random.h>
6907 +#include <linux/scatterlist.h>
6908 +#include <linux/slab.h>
6909 +#include <linux/stat.h>
6910 +#include <linux/string.h>
6911 +#include <linux/timer.h>
6912 +#include <linux/usb.h>
6914 +#include <linux/version.h>
6916 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
6917 +# include <linux/usb/gadget.h>
6919 +# include <linux/usb_gadget.h>
6922 +#include <asm/io.h>
6923 +#include <asm/page.h>
6924 +#include <asm/uaccess.h>
6925 +#include <asm/unaligned.h>
6927 +#include "dwc_os.h"
6928 +#include "dwc_list.h"
6933 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
6935 + return memset(dest, byte, size);
6938 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
6940 + return memcpy(dest, src, size);
6943 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
6945 + return memmove(dest, src, size);
6948 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
6950 + return memcmp(m1, m2, size);
6953 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
6955 + return strncmp(s1, s2, size);
6958 +int DWC_STRCMP(void *s1, void *s2)
6960 + return strcmp(s1, s2);
6963 +int DWC_STRLEN(char const *str)
6965 + return strlen(str);
6968 +char *DWC_STRCPY(char *to, char const *from)
6970 + return strcpy(to, from);
6973 +char *DWC_STRDUP(char const *str)
6975 + int len = DWC_STRLEN(str) + 1;
6976 + char *new = DWC_ALLOC_ATOMIC(len);
6982 + DWC_MEMCPY(new, str, len);
6986 +int DWC_ATOI(const char *str, int32_t *value)
6990 + *value = simple_strtol(str, &end, 0);
6991 + if (*end == '\0') {
6998 +int DWC_ATOUI(const char *str, uint32_t *value)
7002 + *value = simple_strtoul(str, &end, 0);
7003 + if (*end == '\0') {
7012 +/* From usbstring.c */
7014 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
7020 + /* this insists on correct encodings, though not minimal ones.
7021 + * BUT it currently rejects legit 4-byte UTF-8 code points,
7022 + * which need surrogate pairs. (Unicode 3.1 can use them.)
7024 + while (len != 0 && (c = (u8) *s++) != 0) {
7025 + if (unlikely(c & 0x80)) {
7026 + // 2-byte sequence:
7027 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
7028 + if ((c & 0xe0) == 0xc0) {
7029 + uchar = (c & 0x1f) << 6;
7032 + if ((c & 0xc0) != 0xc0)
7037 + // 3-byte sequence (most CJKV characters):
7038 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
7039 + } else if ((c & 0xf0) == 0xe0) {
7040 + uchar = (c & 0x0f) << 12;
7043 + if ((c & 0xc0) != 0xc0)
7049 + if ((c & 0xc0) != 0xc0)
7054 + /* no bogus surrogates */
7055 + if (0xd800 <= uchar && uchar <= 0xdfff)
7058 + // 4-byte sequence (surrogate pairs, currently rare):
7059 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
7060 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
7061 + // (uuuuu = wwww + 1)
7062 + // FIXME accept the surrogate code points (only)
7067 + put_unaligned (cpu_to_le16 (uchar), cp++);
7075 +#endif /* DWC_UTFLIB */
7080 +dwc_bool_t DWC_IN_IRQ(void)
7085 +dwc_bool_t DWC_IN_BH(void)
7087 + return in_softirq();
7090 +void DWC_VPRINTF(char *format, va_list args)
7092 + vprintk(format, args);
7095 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
7097 + return vsnprintf(str, size, format, args);
7100 +void DWC_PRINTF(char *format, ...)
7104 + va_start(args, format);
7105 + DWC_VPRINTF(format, args);
7109 +int DWC_SPRINTF(char *buffer, char *format, ...)
7114 + va_start(args, format);
7115 + retval = vsprintf(buffer, format, args);
7120 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
7125 + va_start(args, format);
7126 + retval = vsnprintf(buffer, size, format, args);
7131 +void __DWC_WARN(char *format, ...)
7135 + va_start(args, format);
7136 + DWC_PRINTF(KERN_WARNING);
7137 + DWC_VPRINTF(format, args);
7141 +void __DWC_ERROR(char *format, ...)
7145 + va_start(args, format);
7146 + DWC_PRINTF(KERN_ERR);
7147 + DWC_VPRINTF(format, args);
7151 +void DWC_EXCEPTION(char *format, ...)
7155 + va_start(args, format);
7156 + DWC_PRINTF(KERN_ERR);
7157 + DWC_VPRINTF(format, args);
7163 +void __DWC_DEBUG(char *format, ...)
7167 + va_start(args, format);
7168 + DWC_PRINTF(KERN_DEBUG);
7169 + DWC_VPRINTF(format, args);
7178 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
7182 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
7183 + size, align, alloc);
7184 + return (dwc_pool_t *)pool;
7187 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
7189 + dma_pool_destroy((struct dma_pool *)pool);
7192 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
7194 + return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
7197 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
7199 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
7203 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
7205 + dma_pool_free(pool, vaddr, daddr);
7209 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
7211 +#ifdef xxCOSIM /* Only works for 32-bit cosim */
7212 + void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL);
7214 + void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL | GFP_DMA32);
7220 + memset(buf, 0, (size_t)size);
7224 +void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
7226 + void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC);
7230 + memset(buf, 0, (size_t)size);
7234 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
7236 + dma_free_coherent(dma_ctx, size, virt_addr, dma_addr);
7239 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
7241 + return kzalloc(size, GFP_KERNEL);
7244 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
7246 + return kzalloc(size, GFP_ATOMIC);
7249 +void __DWC_FREE(void *mem_ctx, void *addr)
7255 +#ifdef DWC_CRYPTOLIB
7258 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
7260 + get_random_bytes(buffer, length);
7263 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
7265 + struct crypto_blkcipher *tfm;
7266 + struct blkcipher_desc desc;
7267 + struct scatterlist sgd;
7268 + struct scatterlist sgs;
7270 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
7271 + if (tfm == NULL) {
7272 + printk("failed to load transform for aes CBC\n");
7276 + crypto_blkcipher_setkey(tfm, key, keylen);
7277 + crypto_blkcipher_set_iv(tfm, iv, 16);
7279 + sg_init_one(&sgd, out, messagelen);
7280 + sg_init_one(&sgs, message, messagelen);
7285 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
7286 + crypto_free_blkcipher(tfm);
7287 + DWC_ERROR("AES CBC encryption failed");
7291 + crypto_free_blkcipher(tfm);
7295 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
7297 + struct crypto_hash *tfm;
7298 + struct hash_desc desc;
7299 + struct scatterlist sg;
7301 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
7302 + if (IS_ERR(tfm)) {
7303 + DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm));
7309 + sg_init_one(&sg, message, len);
7310 + crypto_hash_digest(&desc, &sg, len, out);
7311 + crypto_free_hash(tfm);
7316 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
7317 + uint8_t *key, uint32_t keylen, uint8_t *out)
7319 + struct crypto_hash *tfm;
7320 + struct hash_desc desc;
7321 + struct scatterlist sg;
7323 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
7324 + if (IS_ERR(tfm)) {
7325 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm));
7331 + sg_init_one(&sg, message, messagelen);
7332 + crypto_hash_setkey(tfm, key, keylen);
7333 + crypto_hash_digest(&desc, &sg, messagelen, out);
7334 + crypto_free_hash(tfm);
7338 +#endif /* DWC_CRYPTOLIB */
7341 +/* Byte Ordering Conversions */
7343 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
7345 +#ifdef __LITTLE_ENDIAN
7348 + uint8_t *u_p = (uint8_t *)p;
7350 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7354 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
7356 +#ifdef __BIG_ENDIAN
7359 + uint8_t *u_p = (uint8_t *)p;
7361 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7365 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
7367 +#ifdef __LITTLE_ENDIAN
7370 + uint8_t *u_p = (uint8_t *)p;
7372 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7376 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
7378 +#ifdef __BIG_ENDIAN
7381 + uint8_t *u_p = (uint8_t *)p;
7383 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
7387 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
7389 +#ifdef __LITTLE_ENDIAN
7392 + uint8_t *u_p = (uint8_t *)p;
7393 + return (u_p[1] | (u_p[0] << 8));
7397 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
7399 +#ifdef __BIG_ENDIAN
7402 + uint8_t *u_p = (uint8_t *)p;
7403 + return (u_p[1] | (u_p[0] << 8));
7407 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
7409 +#ifdef __LITTLE_ENDIAN
7412 + uint8_t *u_p = (uint8_t *)p;
7413 + return (u_p[1] | (u_p[0] << 8));
7417 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
7419 +#ifdef __BIG_ENDIAN
7422 + uint8_t *u_p = (uint8_t *)p;
7423 + return (u_p[1] | (u_p[0] << 8));
7430 +uint32_t DWC_READ_REG32(uint32_t volatile *reg)
7432 + return readl(reg);
7436 +uint64_t DWC_READ_REG64(uint64_t volatile *reg)
7441 +void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
7443 + writel(value, reg);
7447 +void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
7452 +void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
7454 + writel((readl(reg) & ~clear_mask) | set_mask, reg);
7458 +void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask)
7466 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
7468 + spinlock_t *sl = (spinlock_t *)1;
7470 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7471 + sl = DWC_ALLOC(sizeof(*sl));
7473 + DWC_ERROR("Cannot allocate memory for spinlock\n");
7477 + spin_lock_init(sl);
7479 + return (dwc_spinlock_t *)sl;
7482 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
7484 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7489 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
7491 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7492 + spin_lock((spinlock_t *)lock);
7496 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
7498 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7499 + spin_unlock((spinlock_t *)lock);
7503 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
7507 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7508 + spin_lock_irqsave((spinlock_t *)lock, f);
7510 + local_irq_save(f);
7515 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
7517 +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
7518 + spin_unlock_irqrestore((spinlock_t *)lock, flags);
7520 + local_irq_restore(flags);
7524 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
7527 + dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex));
7530 + DWC_ERROR("Cannot allocate memory for mutex\n");
7534 + m = (struct mutex *)mutex;
7539 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
7541 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
7543 + mutex_destroy((struct mutex *)mutex);
7548 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
7550 + struct mutex *m = (struct mutex *)mutex;
7554 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
7556 + struct mutex *m = (struct mutex *)mutex;
7557 + return mutex_trylock(m);
7560 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
7562 + struct mutex *m = (struct mutex *)mutex;
7569 +void DWC_UDELAY(uint32_t usecs)
7574 +void DWC_MDELAY(uint32_t msecs)
7579 +void DWC_MSLEEP(uint32_t msecs)
7584 +uint32_t DWC_TIME(void)
7586 + return jiffies_to_msecs(jiffies);
7593 + struct timer_list *t;
7595 + dwc_timer_callback_t cb;
7597 + uint8_t scheduled;
7598 + dwc_spinlock_t *lock;
7601 +static void timer_callback(unsigned long data)
7603 + dwc_timer_t *timer = (dwc_timer_t *)data;
7604 + dwc_irqflags_t flags;
7606 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7607 + timer->scheduled = 0;
7608 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7609 + DWC_DEBUGC("Timer %s callback", timer->name);
7610 + timer->cb(timer->data);
7613 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
7615 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
7618 + DWC_ERROR("Cannot allocate memory for timer");
7622 + t->t = DWC_ALLOC(sizeof(*t->t));
7624 + DWC_ERROR("Cannot allocate memory for timer->t");
7628 + t->name = DWC_STRDUP(name);
7630 + DWC_ERROR("Cannot allocate memory for timer->name");
7634 + t->lock = DWC_SPINLOCK_ALLOC();
7636 + DWC_ERROR("Cannot allocate memory for lock");
7641 + t->t->base = &boot_tvec_bases;
7642 + t->t->expires = jiffies;
7643 + setup_timer(t->t, timer_callback, (unsigned long)t);
7651 + DWC_FREE(t->name);
7659 +void DWC_TIMER_FREE(dwc_timer_t *timer)
7661 + dwc_irqflags_t flags;
7663 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7665 + if (timer->scheduled) {
7666 + del_timer(timer->t);
7667 + timer->scheduled = 0;
7670 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7671 + DWC_SPINLOCK_FREE(timer->lock);
7672 + DWC_FREE(timer->t);
7673 + DWC_FREE(timer->name);
7677 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
7679 + dwc_irqflags_t flags;
7681 + DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
7683 + if (!timer->scheduled) {
7684 + timer->scheduled = 1;
7685 + DWC_DEBUGC("Scheduling timer %s to expire in +%d msec", timer->name, time);
7686 + timer->t->expires = jiffies + msecs_to_jiffies(time);
7687 + add_timer(timer->t);
7689 + DWC_DEBUGC("Modifying timer %s to expire in +%d msec", timer->name, time);
7690 + mod_timer(timer->t, jiffies + msecs_to_jiffies(time));
7693 + DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
7696 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
7698 + del_timer(timer->t);
7705 + wait_queue_head_t queue;
7709 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
7711 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
7714 + DWC_ERROR("Cannot allocate memory for waitqueue\n");
7718 + init_waitqueue_head(&wq->queue);
7723 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
7728 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
7730 + int result = wait_event_interruptible(wq->queue,
7731 + cond(data) || wq->abort);
7732 + if (result == -ERESTARTSYS) {
7734 + return -DWC_E_RESTART;
7737 + if (wq->abort == 1) {
7739 + return -DWC_E_ABORT;
7744 + if (result == 0) {
7748 + return -DWC_E_UNKNOWN;
7751 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
7752 + void *data, int32_t msecs)
7755 + int result = wait_event_interruptible_timeout(wq->queue,
7756 + cond(data) || wq->abort,
7757 + msecs_to_jiffies(msecs));
7758 + if (result == -ERESTARTSYS) {
7760 + return -DWC_E_RESTART;
7763 + if (wq->abort == 1) {
7765 + return -DWC_E_ABORT;
7771 + tmsecs = jiffies_to_msecs(result);
7779 + if (result == 0) {
7780 + return -DWC_E_TIMEOUT;
7783 + return -DWC_E_UNKNOWN;
7786 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
7789 + wake_up_interruptible(&wq->queue);
7792 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
7795 + wake_up_interruptible(&wq->queue);
7801 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
7803 + struct task_struct *thread = kthread_run(func, data, name);
7805 + if (thread == ERR_PTR(-ENOMEM)) {
7809 + return (dwc_thread_t *)thread;
7812 +int DWC_THREAD_STOP(dwc_thread_t *thread)
7814 + return kthread_stop((struct task_struct *)thread);
7817 +dwc_bool_t DWC_THREAD_SHOULD_STOP(void)
7819 + return kthread_should_stop();
7824 + - run in interrupt context (cannot sleep)
7825 + - each tasklet runs on a single CPU
7826 + - different tasklets can be running simultaneously on different CPUs
7828 +struct dwc_tasklet {
7829 + struct tasklet_struct t;
7830 + dwc_tasklet_callback_t cb;
7834 +static void tasklet_callback(unsigned long data)
7836 + dwc_tasklet_t *t = (dwc_tasklet_t *)data;
7840 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
7842 + dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t));
7847 + tasklet_init(&t->t, tasklet_callback, (unsigned long)t);
7849 + DWC_ERROR("Cannot allocate memory for tasklet\n");
7855 +void DWC_TASK_FREE(dwc_tasklet_t *task)
7860 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
7862 + tasklet_schedule(&task->t);
7867 + - run in process context (can sleep)
7869 +typedef struct work_container {
7870 + dwc_work_callback_t cb;
7876 + DWC_CIRCLEQ_ENTRY(work_container) entry;
7878 + struct delayed_work work;
7879 +} work_container_t;
7882 +DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
7886 + struct workqueue_struct *wq;
7887 + dwc_spinlock_t *lock;
7888 + dwc_waitq_t *waitq;
7892 + struct work_container_queue entries;
7896 +static void do_work(struct work_struct *work)
7898 + dwc_irqflags_t flags;
7899 + struct delayed_work *dw = container_of(work, struct delayed_work, work);
7900 + work_container_t *container = container_of(dw, struct work_container, work);
7901 + dwc_workq_t *wq = container->wq;
7903 + container->cb(container->data);
7906 + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
7908 + DWC_DEBUGC("Work done: %s, container=%p", container->name, container);
7909 + if (container->name) {
7910 + DWC_FREE(container->name);
7912 + DWC_FREE(container);
7914 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
7916 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
7917 + DWC_WAITQ_TRIGGER(wq->waitq);
7920 +static int work_done(void *data)
7922 + dwc_workq_t *workq = (dwc_workq_t *)data;
7923 + return workq->pending == 0;
7926 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
7928 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
7931 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
7933 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
7939 + wq->wq = create_singlethread_workqueue(name);
7946 + wq->lock = DWC_SPINLOCK_ALLOC();
7951 + wq->waitq = DWC_WAITQ_ALLOC();
7957 + DWC_CIRCLEQ_INIT(&wq->entries);
7962 + DWC_SPINLOCK_FREE(wq->lock);
7964 + destroy_workqueue(wq->wq);
7971 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
7974 + if (wq->pending != 0) {
7975 + struct work_container *wc;
7976 + DWC_ERROR("Destroying work queue with pending work");
7977 + DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) {
7978 + DWC_ERROR("Work %s still pending", wc->name);
7982 + destroy_workqueue(wq->wq);
7983 + DWC_SPINLOCK_FREE(wq->lock);
7984 + DWC_WAITQ_FREE(wq->waitq);
7988 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
7989 + char *format, ...)
7991 + dwc_irqflags_t flags;
7992 + work_container_t *container;
7993 + static char name[128];
7996 + va_start(args, format);
7997 + DWC_VSNPRINTF(name, 128, format, args);
8000 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
8002 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
8003 + DWC_WAITQ_TRIGGER(wq->waitq);
8005 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
8007 + DWC_ERROR("Cannot allocate memory for container\n");
8011 + container->name = DWC_STRDUP(name);
8012 + if (!container->name) {
8013 + DWC_ERROR("Cannot allocate memory for container->name\n");
8014 + DWC_FREE(container);
8018 + container->cb = cb;
8019 + container->data = data;
8020 + container->wq = wq;
8021 + DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
8022 + INIT_WORK(&container->work.work, do_work);
8025 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
8027 + queue_work(wq->wq, &container->work.work);
8030 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
8031 + void *data, uint32_t time, char *format, ...)
8033 + dwc_irqflags_t flags;
8034 + work_container_t *container;
8035 + static char name[128];
8038 + va_start(args, format);
8039 + DWC_VSNPRINTF(name, 128, format, args);
8042 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
8044 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
8045 + DWC_WAITQ_TRIGGER(wq->waitq);
8047 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
8049 + DWC_ERROR("Cannot allocate memory for container\n");
8053 + container->name = DWC_STRDUP(name);
8054 + if (!container->name) {
8055 + DWC_ERROR("Cannot allocate memory for container->name\n");
8056 + DWC_FREE(container);
8060 + container->cb = cb;
8061 + container->data = data;
8062 + container->wq = wq;
8063 + DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
8064 + INIT_DELAYED_WORK(&container->work, do_work);
8067 + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
8069 + queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time));
8072 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
8074 + return wq->pending;
8078 +#ifdef DWC_LIBMODULE
8082 +EXPORT_SYMBOL(dwc_cc_if_alloc);
8083 +EXPORT_SYMBOL(dwc_cc_if_free);
8084 +EXPORT_SYMBOL(dwc_cc_clear);
8085 +EXPORT_SYMBOL(dwc_cc_add);
8086 +EXPORT_SYMBOL(dwc_cc_remove);
8087 +EXPORT_SYMBOL(dwc_cc_change);
8088 +EXPORT_SYMBOL(dwc_cc_data_for_save);
8089 +EXPORT_SYMBOL(dwc_cc_restore_from_data);
8090 +EXPORT_SYMBOL(dwc_cc_match_chid);
8091 +EXPORT_SYMBOL(dwc_cc_match_cdid);
8092 +EXPORT_SYMBOL(dwc_cc_ck);
8093 +EXPORT_SYMBOL(dwc_cc_chid);
8094 +EXPORT_SYMBOL(dwc_cc_cdid);
8095 +EXPORT_SYMBOL(dwc_cc_name);
8096 +#endif /* DWC_CCLIB */
8098 +#ifdef DWC_CRYPTOLIB
8099 +# ifndef CONFIG_MACH_IPMATE
8101 +EXPORT_SYMBOL(dwc_modpow);
8104 +EXPORT_SYMBOL(dwc_dh_modpow);
8105 +EXPORT_SYMBOL(dwc_dh_derive_keys);
8106 +EXPORT_SYMBOL(dwc_dh_pk);
8107 +# endif /* CONFIG_MACH_IPMATE */
8110 +EXPORT_SYMBOL(dwc_wusb_aes_encrypt);
8111 +EXPORT_SYMBOL(dwc_wusb_cmf);
8112 +EXPORT_SYMBOL(dwc_wusb_prf);
8113 +EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce);
8114 +EXPORT_SYMBOL(dwc_wusb_gen_nonce);
8115 +EXPORT_SYMBOL(dwc_wusb_gen_key);
8116 +EXPORT_SYMBOL(dwc_wusb_gen_mic);
8117 +#endif /* DWC_CRYPTOLIB */
8120 +#ifdef DWC_NOTIFYLIB
8121 +EXPORT_SYMBOL(dwc_alloc_notification_manager);
8122 +EXPORT_SYMBOL(dwc_free_notification_manager);
8123 +EXPORT_SYMBOL(dwc_register_notifier);
8124 +EXPORT_SYMBOL(dwc_unregister_notifier);
8125 +EXPORT_SYMBOL(dwc_add_observer);
8126 +EXPORT_SYMBOL(dwc_remove_observer);
8127 +EXPORT_SYMBOL(dwc_notify);
8130 +/* Memory Debugging Routines */
8131 +#ifdef DWC_DEBUG_MEMORY
8132 +EXPORT_SYMBOL(dwc_alloc_debug);
8133 +EXPORT_SYMBOL(dwc_alloc_atomic_debug);
8134 +EXPORT_SYMBOL(dwc_free_debug);
8135 +EXPORT_SYMBOL(dwc_dma_alloc_debug);
8136 +EXPORT_SYMBOL(dwc_dma_free_debug);
8139 +EXPORT_SYMBOL(DWC_MEMSET);
8140 +EXPORT_SYMBOL(DWC_MEMCPY);
8141 +EXPORT_SYMBOL(DWC_MEMMOVE);
8142 +EXPORT_SYMBOL(DWC_MEMCMP);
8143 +EXPORT_SYMBOL(DWC_STRNCMP);
8144 +EXPORT_SYMBOL(DWC_STRCMP);
8145 +EXPORT_SYMBOL(DWC_STRLEN);
8146 +EXPORT_SYMBOL(DWC_STRCPY);
8147 +EXPORT_SYMBOL(DWC_STRDUP);
8148 +EXPORT_SYMBOL(DWC_ATOI);
8149 +EXPORT_SYMBOL(DWC_ATOUI);
8152 +EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE);
8153 +#endif /* DWC_UTFLIB */
8155 +EXPORT_SYMBOL(DWC_IN_IRQ);
8156 +EXPORT_SYMBOL(DWC_IN_BH);
8157 +EXPORT_SYMBOL(DWC_VPRINTF);
8158 +EXPORT_SYMBOL(DWC_VSNPRINTF);
8159 +EXPORT_SYMBOL(DWC_PRINTF);
8160 +EXPORT_SYMBOL(DWC_SPRINTF);
8161 +EXPORT_SYMBOL(DWC_SNPRINTF);
8162 +EXPORT_SYMBOL(__DWC_WARN);
8163 +EXPORT_SYMBOL(__DWC_ERROR);
8164 +EXPORT_SYMBOL(DWC_EXCEPTION);
8167 +EXPORT_SYMBOL(__DWC_DEBUG);
8170 +EXPORT_SYMBOL(__DWC_DMA_ALLOC);
8171 +EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC);
8172 +EXPORT_SYMBOL(__DWC_DMA_FREE);
8173 +EXPORT_SYMBOL(__DWC_ALLOC);
8174 +EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC);
8175 +EXPORT_SYMBOL(__DWC_FREE);
8177 +#ifdef DWC_CRYPTOLIB
8178 +EXPORT_SYMBOL(DWC_RANDOM_BYTES);
8179 +EXPORT_SYMBOL(DWC_AES_CBC);
8180 +EXPORT_SYMBOL(DWC_SHA256);
8181 +EXPORT_SYMBOL(DWC_HMAC_SHA256);
8184 +EXPORT_SYMBOL(DWC_CPU_TO_LE32);
8185 +EXPORT_SYMBOL(DWC_CPU_TO_BE32);
8186 +EXPORT_SYMBOL(DWC_LE32_TO_CPU);
8187 +EXPORT_SYMBOL(DWC_BE32_TO_CPU);
8188 +EXPORT_SYMBOL(DWC_CPU_TO_LE16);
8189 +EXPORT_SYMBOL(DWC_CPU_TO_BE16);
8190 +EXPORT_SYMBOL(DWC_LE16_TO_CPU);
8191 +EXPORT_SYMBOL(DWC_BE16_TO_CPU);
8192 +EXPORT_SYMBOL(DWC_READ_REG32);
8193 +EXPORT_SYMBOL(DWC_WRITE_REG32);
8194 +EXPORT_SYMBOL(DWC_MODIFY_REG32);
8197 +EXPORT_SYMBOL(DWC_READ_REG64);
8198 +EXPORT_SYMBOL(DWC_WRITE_REG64);
8199 +EXPORT_SYMBOL(DWC_MODIFY_REG64);
8202 +EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC);
8203 +EXPORT_SYMBOL(DWC_SPINLOCK_FREE);
8204 +EXPORT_SYMBOL(DWC_SPINLOCK);
8205 +EXPORT_SYMBOL(DWC_SPINUNLOCK);
8206 +EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE);
8207 +EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE);
8208 +EXPORT_SYMBOL(DWC_MUTEX_ALLOC);
8210 +#if (!defined(DWC_LINUX) || !defined(CONFIG_DEBUG_MUTEXES))
8211 +EXPORT_SYMBOL(DWC_MUTEX_FREE);
8214 +EXPORT_SYMBOL(DWC_MUTEX_LOCK);
8215 +EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK);
8216 +EXPORT_SYMBOL(DWC_MUTEX_UNLOCK);
8217 +EXPORT_SYMBOL(DWC_UDELAY);
8218 +EXPORT_SYMBOL(DWC_MDELAY);
8219 +EXPORT_SYMBOL(DWC_MSLEEP);
8220 +EXPORT_SYMBOL(DWC_TIME);
8221 +EXPORT_SYMBOL(DWC_TIMER_ALLOC);
8222 +EXPORT_SYMBOL(DWC_TIMER_FREE);
8223 +EXPORT_SYMBOL(DWC_TIMER_SCHEDULE);
8224 +EXPORT_SYMBOL(DWC_TIMER_CANCEL);
8225 +EXPORT_SYMBOL(DWC_WAITQ_ALLOC);
8226 +EXPORT_SYMBOL(DWC_WAITQ_FREE);
8227 +EXPORT_SYMBOL(DWC_WAITQ_WAIT);
8228 +EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT);
8229 +EXPORT_SYMBOL(DWC_WAITQ_TRIGGER);
8230 +EXPORT_SYMBOL(DWC_WAITQ_ABORT);
8231 +EXPORT_SYMBOL(DWC_THREAD_RUN);
8232 +EXPORT_SYMBOL(DWC_THREAD_STOP);
8233 +EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP);
8234 +EXPORT_SYMBOL(DWC_TASK_ALLOC);
8235 +EXPORT_SYMBOL(DWC_TASK_FREE);
8236 +EXPORT_SYMBOL(DWC_TASK_SCHEDULE);
8237 +EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE);
8238 +EXPORT_SYMBOL(DWC_WORKQ_ALLOC);
8239 +EXPORT_SYMBOL(DWC_WORKQ_FREE);
8240 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE);
8241 +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED);
8242 +EXPORT_SYMBOL(DWC_WORKQ_PENDING);
8244 +static int dwc_common_port_init_module(void)
8248 + printk(KERN_DEBUG "Module dwc_common_port init\n" );
8250 +#ifdef DWC_DEBUG_MEMORY
8251 + result = dwc_memory_debug_start(NULL);
8254 + "dwc_memory_debug_start() failed with error %d\n",
8260 +#ifdef DWC_NOTIFYLIB
8261 + result = dwc_alloc_notification_manager(NULL, NULL);
8264 + "dwc_alloc_notification_manager() failed with error %d\n",
8272 +static void dwc_common_port_exit_module(void)
8274 + printk(KERN_DEBUG "Module dwc_common_port exit\n" );
8276 +#ifdef DWC_NOTIFYLIB
8277 + dwc_free_notification_manager();
8280 +#ifdef DWC_DEBUG_MEMORY
8281 + dwc_memory_debug_stop();
8285 +module_init(dwc_common_port_init_module);
8286 +module_exit(dwc_common_port_exit_module);
8288 +MODULE_DESCRIPTION("DWC Common Library - Portable version");
8289 +MODULE_AUTHOR("Synopsys Inc.");
8290 +MODULE_LICENSE ("GPL");
8292 +#endif /* DWC_LIBMODULE */
8293 diff --git a/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
8294 new file mode 100644
8295 index 0000000..49b07e1
8297 +++ b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
8299 +#include "dwc_os.h"
8300 +#include "dwc_list.h"
8303 +# include "dwc_cc.h"
8306 +#ifdef DWC_CRYPTOLIB
8307 +# include "dwc_modpow.h"
8308 +# include "dwc_dh.h"
8309 +# include "dwc_crypto.h"
8312 +#ifdef DWC_NOTIFYLIB
8313 +# include "dwc_notifier.h"
8316 +/* OS-Level Implementations */
8318 +/* This is the NetBSD 4.0.1 kernel implementation of the DWC platform library. */
8323 +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
8325 + return memset(dest, byte, size);
8328 +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
8330 + return memcpy(dest, src, size);
8333 +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
8335 + bcopy(src, dest, size);
8339 +int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
8341 + return memcmp(m1, m2, size);
8344 +int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
8346 + return strncmp(s1, s2, size);
8349 +int DWC_STRCMP(void *s1, void *s2)
8351 + return strcmp(s1, s2);
8354 +int DWC_STRLEN(char const *str)
8356 + return strlen(str);
8359 +char *DWC_STRCPY(char *to, char const *from)
8361 + return strcpy(to, from);
8364 +char *DWC_STRDUP(char const *str)
8366 + int len = DWC_STRLEN(str) + 1;
8367 + char *new = DWC_ALLOC_ATOMIC(len);
8373 + DWC_MEMCPY(new, str, len);
8377 +int DWC_ATOI(char *str, int32_t *value)
8381 + /* NetBSD doesn't have 'strtol' in the kernel, but 'strtoul'
8382 + * should be equivalent on 2's complement machines
8384 + *value = strtoul(str, &end, 0);
8385 + if (*end == '\0') {
8392 +int DWC_ATOUI(char *str, uint32_t *value)
8396 + *value = strtoul(str, &end, 0);
8397 + if (*end == '\0') {
8406 +/* From usbstring.c */
8408 +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
8414 + /* this insists on correct encodings, though not minimal ones.
8415 + * BUT it currently rejects legit 4-byte UTF-8 code points,
8416 + * which need surrogate pairs. (Unicode 3.1 can use them.)
8418 + while (len != 0 && (c = (u8) *s++) != 0) {
8419 + if (unlikely(c & 0x80)) {
8420 + // 2-byte sequence:
8421 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
8422 + if ((c & 0xe0) == 0xc0) {
8423 + uchar = (c & 0x1f) << 6;
8426 + if ((c & 0xc0) != 0xc0)
8431 + // 3-byte sequence (most CJKV characters):
8432 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
8433 + } else if ((c & 0xf0) == 0xe0) {
8434 + uchar = (c & 0x0f) << 12;
8437 + if ((c & 0xc0) != 0xc0)
8443 + if ((c & 0xc0) != 0xc0)
8448 + /* no bogus surrogates */
8449 + if (0xd800 <= uchar && uchar <= 0xdfff)
8452 + // 4-byte sequence (surrogate pairs, currently rare):
8453 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
8454 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
8455 + // (uuuuu = wwww + 1)
8456 + // FIXME accept the surrogate code points (only)
8461 + put_unaligned (cpu_to_le16 (uchar), cp++);
8470 +#endif /* DWC_UTFLIB */
8475 +dwc_bool_t DWC_IN_IRQ(void)
8477 +// return in_irq();
8481 +dwc_bool_t DWC_IN_BH(void)
8483 +// return in_softirq();
8487 +void DWC_VPRINTF(char *format, va_list args)
8489 + vprintf(format, args);
8492 +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
8494 + return vsnprintf(str, size, format, args);
8497 +void DWC_PRINTF(char *format, ...)
8501 + va_start(args, format);
8502 + DWC_VPRINTF(format, args);
8506 +int DWC_SPRINTF(char *buffer, char *format, ...)
8511 + va_start(args, format);
8512 + retval = vsprintf(buffer, format, args);
8517 +int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
8522 + va_start(args, format);
8523 + retval = vsnprintf(buffer, size, format, args);
8528 +void __DWC_WARN(char *format, ...)
8532 + va_start(args, format);
8533 + DWC_VPRINTF(format, args);
8537 +void __DWC_ERROR(char *format, ...)
8541 + va_start(args, format);
8542 + DWC_VPRINTF(format, args);
8546 +void DWC_EXCEPTION(char *format, ...)
8550 + va_start(args, format);
8551 + DWC_VPRINTF(format, args);
8557 +void __DWC_DEBUG(char *format, ...)
8561 + va_start(args, format);
8562 + DWC_VPRINTF(format, args);
8571 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
8575 + struct dma_pool *pool = dma_pool_create("Pool", NULL,
8576 + size, align, alloc);
8577 + return (dwc_pool_t *)pool;
8580 +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
8582 + dma_pool_destroy((struct dma_pool *)pool);
8585 +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
8587 +// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
8588 + return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
8591 +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
8593 + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
8597 +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
8599 + dma_pool_free(pool, vaddr, daddr);
8603 +void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
8605 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
8608 + error = bus_dmamem_alloc(dma->dma_tag, size, 1, size, dma->segs,
8609 + sizeof(dma->segs) / sizeof(dma->segs[0]),
8610 + &dma->nsegs, BUS_DMA_NOWAIT);
8612 + printf("%s: bus_dmamem_alloc(%ju) failed: %d\n", __func__,
8613 + (uintmax_t)size, error);
8617 + error = bus_dmamem_map(dma->dma_tag, dma->segs, dma->nsegs, size,
8618 + (caddr_t *)&dma->dma_vaddr,
8619 + BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
8621 + printf("%s: bus_dmamem_map failed: %d\n", __func__, error);
8625 + error = bus_dmamap_create(dma->dma_tag, size, 1, size, 0,
8626 + BUS_DMA_NOWAIT, &dma->dma_map);
8628 + printf("%s: bus_dmamap_create failed: %d\n", __func__, error);
8632 + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
8633 + size, NULL, BUS_DMA_NOWAIT);
8635 + printf("%s: bus_dmamap_load failed: %d\n", __func__, error);
8639 + dma->dma_paddr = (bus_addr_t)dma->segs[0].ds_addr;
8640 + *dma_addr = dma->dma_paddr;
8641 + return dma->dma_vaddr;
8644 + bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
8646 + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
8648 + bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
8650 + dma->dma_map = NULL;
8651 + dma->dma_vaddr = NULL;
8657 +void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
8659 + dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
8661 + if (dma->dma_map != NULL) {
8662 + bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, size,
8663 + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
8664 + bus_dmamap_unload(dma->dma_tag, dma->dma_map);
8665 + bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
8666 + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
8667 + bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
8668 + dma->dma_paddr = 0;
8669 + dma->dma_map = NULL;
8670 + dma->dma_vaddr = NULL;
8675 +void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
8677 + return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
8680 +void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
8682 + return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
8685 +void __DWC_FREE(void *mem_ctx, void *addr)
8687 + free(addr, M_DEVBUF);
8691 +#ifdef DWC_CRYPTOLIB
8694 +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
8696 + get_random_bytes(buffer, length);
8699 +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
8701 + struct crypto_blkcipher *tfm;
8702 + struct blkcipher_desc desc;
8703 + struct scatterlist sgd;
8704 + struct scatterlist sgs;
8706 + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
8707 + if (tfm == NULL) {
8708 + printk("failed to load transform for aes CBC\n");
8712 + crypto_blkcipher_setkey(tfm, key, keylen);
8713 + crypto_blkcipher_set_iv(tfm, iv, 16);
8715 + sg_init_one(&sgd, out, messagelen);
8716 + sg_init_one(&sgs, message, messagelen);
8721 + if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
8722 + crypto_free_blkcipher(tfm);
8723 + DWC_ERROR("AES CBC encryption failed");
8727 + crypto_free_blkcipher(tfm);
8731 +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
8733 + struct crypto_hash *tfm;
8734 + struct hash_desc desc;
8735 + struct scatterlist sg;
8737 + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
8738 + if (IS_ERR(tfm)) {
8739 + DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
8745 + sg_init_one(&sg, message, len);
8746 + crypto_hash_digest(&desc, &sg, len, out);
8747 + crypto_free_hash(tfm);
8752 +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
8753 + uint8_t *key, uint32_t keylen, uint8_t *out)
8755 + struct crypto_hash *tfm;
8756 + struct hash_desc desc;
8757 + struct scatterlist sg;
8759 + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
8760 + if (IS_ERR(tfm)) {
8761 + DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
8767 + sg_init_one(&sg, message, messagelen);
8768 + crypto_hash_setkey(tfm, key, keylen);
8769 + crypto_hash_digest(&desc, &sg, messagelen, out);
8770 + crypto_free_hash(tfm);
8775 +#endif /* DWC_CRYPTOLIB */
8778 +/* Byte Ordering Conversions */
8780 +uint32_t DWC_CPU_TO_LE32(uint32_t *p)
8782 +#ifdef __LITTLE_ENDIAN
8785 + uint8_t *u_p = (uint8_t *)p;
8787 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8791 +uint32_t DWC_CPU_TO_BE32(uint32_t *p)
8793 +#ifdef __BIG_ENDIAN
8796 + uint8_t *u_p = (uint8_t *)p;
8798 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8802 +uint32_t DWC_LE32_TO_CPU(uint32_t *p)
8804 +#ifdef __LITTLE_ENDIAN
8807 + uint8_t *u_p = (uint8_t *)p;
8809 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8813 +uint32_t DWC_BE32_TO_CPU(uint32_t *p)
8815 +#ifdef __BIG_ENDIAN
8818 + uint8_t *u_p = (uint8_t *)p;
8820 + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
8824 +uint16_t DWC_CPU_TO_LE16(uint16_t *p)
8826 +#ifdef __LITTLE_ENDIAN
8829 + uint8_t *u_p = (uint8_t *)p;
8830 + return (u_p[1] | (u_p[0] << 8));
8834 +uint16_t DWC_CPU_TO_BE16(uint16_t *p)
8836 +#ifdef __BIG_ENDIAN
8839 + uint8_t *u_p = (uint8_t *)p;
8840 + return (u_p[1] | (u_p[0] << 8));
8844 +uint16_t DWC_LE16_TO_CPU(uint16_t *p)
8846 +#ifdef __LITTLE_ENDIAN
8849 + uint8_t *u_p = (uint8_t *)p;
8850 + return (u_p[1] | (u_p[0] << 8));
8854 +uint16_t DWC_BE16_TO_CPU(uint16_t *p)
8856 +#ifdef __BIG_ENDIAN
8859 + uint8_t *u_p = (uint8_t *)p;
8860 + return (u_p[1] | (u_p[0] << 8));
8867 +uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
8869 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8870 + bus_size_t ior = (bus_size_t)reg;
8872 + return bus_space_read_4(io->iot, io->ioh, ior);
8876 +uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
8878 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8879 + bus_size_t ior = (bus_size_t)reg;
8881 + return bus_space_read_8(io->iot, io->ioh, ior);
8885 +void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
8887 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8888 + bus_size_t ior = (bus_size_t)reg;
8890 + bus_space_write_4(io->iot, io->ioh, ior, value);
8894 +void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
8896 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8897 + bus_size_t ior = (bus_size_t)reg;
8899 + bus_space_write_8(io->iot, io->ioh, ior, value);
8903 +void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
8904 + uint32_t set_mask)
8906 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8907 + bus_size_t ior = (bus_size_t)reg;
8909 + bus_space_write_4(io->iot, io->ioh, ior,
8910 + (bus_space_read_4(io->iot, io->ioh, ior) &
8911 + ~clear_mask) | set_mask);
8915 +void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
8916 + uint64_t set_mask)
8918 + dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
8919 + bus_size_t ior = (bus_size_t)reg;
8921 + bus_space_write_8(io->iot, io->ioh, ior,
8922 + (bus_space_read_8(io->iot, io->ioh, ior) &
8923 + ~clear_mask) | set_mask);
8930 +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
8932 + struct simplelock *sl = DWC_ALLOC(sizeof(*sl));
8935 + DWC_ERROR("Cannot allocate memory for spinlock");
8939 + simple_lock_init(sl);
8940 + return (dwc_spinlock_t *)sl;
8943 +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
8945 + struct simplelock *sl = (struct simplelock *)lock;
8950 +void DWC_SPINLOCK(dwc_spinlock_t *lock)
8952 + simple_lock((struct simplelock *)lock);
8955 +void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
8957 + simple_unlock((struct simplelock *)lock);
8960 +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
8962 + simple_lock((struct simplelock *)lock);
8963 + *flags = splbio();
8966 +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
8969 + simple_unlock((struct simplelock *)lock);
8972 +dwc_mutex_t *DWC_MUTEX_ALLOC(void)
8974 + dwc_mutex_t *mutex = DWC_ALLOC(sizeof(struct lock));
8977 + DWC_ERROR("Cannot allocate memory for mutex");
8981 + lockinit((struct lock *)mutex, 0, "dw3mtx", 0, 0);
8985 +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
8987 +void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
8993 +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
8995 + lockmgr((struct lock *)mutex, LK_EXCLUSIVE, NULL);
8998 +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
9002 + status = lockmgr((struct lock *)mutex, LK_EXCLUSIVE | LK_NOWAIT, NULL);
9003 + return status == 0;
9006 +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
9008 + lockmgr((struct lock *)mutex, LK_RELEASE, NULL);
9014 +void DWC_UDELAY(uint32_t usecs)
9019 +void DWC_MDELAY(uint32_t msecs)
9023 + } while (--msecs);
9026 +void DWC_MSLEEP(uint32_t msecs)
9028 + struct timeval tv;
9030 + tv.tv_sec = msecs / 1000;
9031 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
9032 + tsleep(&tv, 0, "dw3slp", tvtohz(&tv));
9035 +uint32_t DWC_TIME(void)
9037 + struct timeval tv;
9039 + microuptime(&tv); // or getmicrouptime? (less precise, but faster)
9040 + return tv.tv_sec * 1000 + tv.tv_usec / 1000;
9049 + dwc_spinlock_t *lock;
9050 + dwc_timer_callback_t cb;
9054 +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
9056 + dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
9059 + DWC_ERROR("Cannot allocate memory for timer");
9063 + callout_init(&t->t);
9065 + t->name = DWC_STRDUP(name);
9067 + DWC_ERROR("Cannot allocate memory for timer->name");
9071 + t->lock = DWC_SPINLOCK_ALLOC();
9073 + DWC_ERROR("Cannot allocate memory for timer->lock");
9083 + DWC_FREE(t->name);
9090 +void DWC_TIMER_FREE(dwc_timer_t *timer)
9092 + callout_stop(&timer->t);
9093 + DWC_SPINLOCK_FREE(timer->lock);
9094 + DWC_FREE(timer->name);
9098 +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
9100 + struct timeval tv;
9102 + tv.tv_sec = time / 1000;
9103 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
9104 + callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
9107 +void DWC_TIMER_CANCEL(dwc_timer_t *timer)
9109 + callout_stop(&timer->t);
9116 + struct simplelock lock;
9120 +dwc_waitq_t *DWC_WAITQ_ALLOC(void)
9122 + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
9125 + DWC_ERROR("Cannot allocate memory for waitqueue");
9129 + simple_lock_init(&wq->lock);
9135 +void DWC_WAITQ_FREE(dwc_waitq_t *wq)
9140 +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
9145 + simple_lock(&wq->lock);
9148 + /* Skip the sleep if already aborted or triggered */
9149 + if (!wq->abort && !cond(data)) {
9151 + result = ltsleep(wq, PCATCH, "dw3wat", 0, &wq->lock); // infinite timeout
9155 + if (result == 0) { // awoken
9158 + result = -DWC_E_ABORT;
9164 + simple_unlock(&wq->lock);
9168 + simple_unlock(&wq->lock);
9170 + if (result == ERESTART) { // signaled - restart
9171 + result = -DWC_E_RESTART;
9172 + } else { // signaled - must be EINTR
9173 + result = -DWC_E_ABORT;
9180 +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
9181 + void *data, int32_t msecs)
9183 + struct timeval tv, tv1, tv2;
9187 + tv.tv_sec = msecs / 1000;
9188 + tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
9190 + simple_lock(&wq->lock);
9193 + /* Skip the sleep if already aborted or triggered */
9194 + if (!wq->abort && !cond(data)) {
9196 + getmicrouptime(&tv1);
9197 + result = ltsleep(wq, PCATCH, "dw3wto", tvtohz(&tv), &wq->lock);
9198 + getmicrouptime(&tv2);
9202 + if (result == 0) { // awoken
9206 + simple_unlock(&wq->lock);
9207 + result = -DWC_E_ABORT;
9210 + simple_unlock(&wq->lock);
9212 + tv2.tv_usec -= tv1.tv_usec;
9213 + if (tv2.tv_usec < 0) {
9214 + tv2.tv_usec += 1000000;
9218 + tv2.tv_sec -= tv1.tv_sec;
9219 + result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
9220 + result = msecs - result;
9227 + simple_unlock(&wq->lock);
9229 + if (result == ERESTART) { // signaled - restart
9230 + result = -DWC_E_RESTART;
9232 + } else if (result == EINTR) { // signaled - interrupt
9233 + result = -DWC_E_ABORT;
9235 + } else { // timed out
9236 + result = -DWC_E_TIMEOUT;
9243 +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
9248 +void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
9252 + simple_lock(&wq->lock);
9257 + simple_unlock(&wq->lock);
9263 +struct dwc_thread {
9264 + struct proc *proc;
9268 +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
9271 + dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
9277 + thread->abort = 0;
9278 + retval = kthread_create1((void (*)(void *))func, data, &thread->proc,
9288 +int DWC_THREAD_STOP(dwc_thread_t *thread)
9292 + thread->abort = 1;
9293 + retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
9295 + if (retval == 0) {
9296 + /* DWC_THREAD_EXIT() will free the thread struct */
9300 + /* NOTE: We leak the thread struct if thread doesn't die */
9302 + if (retval == EWOULDBLOCK) {
9303 + return -DWC_E_TIMEOUT;
9306 + return -DWC_E_UNKNOWN;
9309 +dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
9311 + return thread->abort;
9314 +void DWC_THREAD_EXIT(dwc_thread_t *thread)
9316 + wakeup(&thread->abort);
9322 + - Runs in interrupt context (cannot sleep)
9323 + - Each tasklet runs on a single CPU
9324 + - Different tasklets can be running simultaneously on different CPUs
9325 + [ On NetBSD there is no corresponding mechanism, drivers don't have bottom-
9326 + halves. So we just call the callback directly from DWC_TASK_SCHEDULE() ]
9328 +struct dwc_tasklet {
9329 + dwc_tasklet_callback_t cb;
9333 +static void tasklet_callback(void *data)
9335 + dwc_tasklet_t *task = (dwc_tasklet_t *)data;
9337 + task->cb(task->data);
9340 +dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
9342 + dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
9346 + task->data = data;
9348 + DWC_ERROR("Cannot allocate memory for tasklet");
9354 +void DWC_TASK_FREE(dwc_tasklet_t *task)
9359 +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
9361 + tasklet_callback(task);
9366 + - Runs in process context (can sleep)
9368 +typedef struct work_container {
9369 + dwc_work_callback_t cb;
9375 +} work_container_t;
9378 + struct workqueue *taskq;
9379 + dwc_spinlock_t *lock;
9380 + dwc_waitq_t *waitq;
9382 + struct work_container *container;
9385 +static void do_work(struct work *task, void *data)
9387 + dwc_workq_t *wq = (dwc_workq_t *)data;
9388 + work_container_t *container = wq->container;
9389 + dwc_irqflags_t flags;
9391 + if (container->hz) {
9392 + tsleep(container, 0, "dw3wrk", container->hz);
9395 + container->cb(container->data);
9396 + DWC_DEBUG("Work done: %s, container=%p", container->name, container);
9398 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9399 + if (container->name)
9400 + DWC_FREE(container->name);
9401 + DWC_FREE(container);
9403 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9404 + DWC_WAITQ_TRIGGER(wq->waitq);
9407 +static int work_done(void *data)
9409 + dwc_workq_t *workq = (dwc_workq_t *)data;
9411 + return workq->pending == 0;
9414 +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
9416 + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
9419 +dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
9422 + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
9425 + DWC_ERROR("Cannot allocate memory for workqueue");
9429 + result = workqueue_create(&wq->taskq, name, do_work, wq, 0 /*PWAIT*/,
9432 + DWC_ERROR("Cannot create workqueue");
9438 + wq->lock = DWC_SPINLOCK_ALLOC();
9440 + DWC_ERROR("Cannot allocate memory for spinlock");
9444 + wq->waitq = DWC_WAITQ_ALLOC();
9446 + DWC_ERROR("Cannot allocate memory for waitqueue");
9453 + DWC_SPINLOCK_FREE(wq->lock);
9455 + workqueue_destroy(wq->taskq);
9462 +void DWC_WORKQ_FREE(dwc_workq_t *wq)
9465 + dwc_irqflags_t flags;
9467 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9469 + if (wq->pending != 0) {
9470 + struct work_container *container = wq->container;
9472 + DWC_ERROR("Destroying work queue with pending work");
9474 + if (container && container->name) {
9475 + DWC_ERROR("Work %s still pending", container->name);
9479 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9481 + DWC_WAITQ_FREE(wq->waitq);
9482 + DWC_SPINLOCK_FREE(wq->lock);
9483 + workqueue_destroy(wq->taskq);
9487 +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
9488 + char *format, ...)
9490 + dwc_irqflags_t flags;
9491 + work_container_t *container;
9492 + static char name[128];
9495 + va_start(args, format);
9496 + DWC_VSNPRINTF(name, 128, format, args);
9499 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9501 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9502 + DWC_WAITQ_TRIGGER(wq->waitq);
9504 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
9506 + DWC_ERROR("Cannot allocate memory for container");
9510 + container->name = DWC_STRDUP(name);
9511 + if (!container->name) {
9512 + DWC_ERROR("Cannot allocate memory for container->name");
9513 + DWC_FREE(container);
9517 + container->cb = cb;
9518 + container->data = data;
9519 + container->wq = wq;
9520 + container->hz = 0;
9521 + wq->container = container;
9523 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
9524 + workqueue_enqueue(wq->taskq, &container->task);
9527 +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
9528 + void *data, uint32_t time, char *format, ...)
9530 + dwc_irqflags_t flags;
9531 + work_container_t *container;
9532 + static char name[128];
9533 + struct timeval tv;
9536 + va_start(args, format);
9537 + DWC_VSNPRINTF(name, 128, format, args);
9540 + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
9542 + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
9543 + DWC_WAITQ_TRIGGER(wq->waitq);
9545 + container = DWC_ALLOC_ATOMIC(sizeof(*container));
9547 + DWC_ERROR("Cannot allocate memory for container");
9551 + container->name = DWC_STRDUP(name);
9552 + if (!container->name) {
9553 + DWC_ERROR("Cannot allocate memory for container->name");
9554 + DWC_FREE(container);
9558 + container->cb = cb;
9559 + container->data = data;
9560 + container->wq = wq;
9561 + tv.tv_sec = time / 1000;
9562 + tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
9563 + container->hz = tvtohz(&tv);
9564 + wq->container = container;
9566 + DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
9567 + workqueue_enqueue(wq->taskq, &container->task);
9570 +int DWC_WORKQ_PENDING(dwc_workq_t *wq)
9572 + return wq->pending;
9574 diff --git a/drivers/usb/host/dwc_common_port/dwc_crypto.c b/drivers/usb/host/dwc_common_port/dwc_crypto.c
9575 new file mode 100644
9576 index 0000000..3b03532
9578 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.c
9580 +/* =========================================================================
9581 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $
9583 + * $Date: 2010/09/28 $
9584 + * $Change: 1596182 $
9586 + * Synopsys Portability Library Software and documentation
9587 + * (hereinafter, "Software") is an Unsupported proprietary work of
9588 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9589 + * between Synopsys and you.
9591 + * The Software IS NOT an item of Licensed Software or Licensed Product
9592 + * under any End User Software License Agreement or Agreement for
9593 + * Licensed Product with Synopsys or any supplement thereto. You are
9594 + * permitted to use and redistribute this Software in source and binary
9595 + * forms, with or without modification, provided that redistributions
9596 + * of source code must retain this notice. You may not view, use,
9597 + * disclose, copy or distribute this file or any information contained
9598 + * herein except pursuant to this license grant from Synopsys. If you
9599 + * do not agree with this notice, including the disclaimer below, then
9600 + * you are not authorized to use the Software.
9602 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9603 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9604 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9605 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9606 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9607 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9608 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9609 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9610 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9611 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9612 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9614 + * ========================================================================= */
9617 + * This file contains the WUSB cryptographic routines.
9620 +#ifdef DWC_CRYPTOLIB
9622 +#include "dwc_crypto.h"
9626 +static inline void dump_bytes(char *name, uint8_t *bytes, int len)
9629 + DWC_PRINTF("%s: ", name);
9630 + for (i=0; i<len; i++) {
9631 + DWC_PRINTF("%02x ", bytes[i]);
9636 +#define dump_bytes(x...)
9639 +/* Display a block */
9640 +void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
9642 +#ifdef DWC_DEBUG_CRYPTO
9643 + int i, blksize = 16;
9645 + DWC_DEBUG("%s", prefix);
9647 + if (suffix == NULL) {
9652 + for (i = 0; i < blksize; i++)
9653 + DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? " " : " ");
9654 + DWC_PRINT(suffix);
9659 + * Encrypts an array of bytes using the AES encryption engine.
9660 + * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
9663 + * @return 0 on success, negative error code on error.
9665 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
9668 + DWC_MEMSET(block_t, 0, 16);
9670 + return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
9674 + * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
9675 + * This function takes a data string and returns the encrypted CBC
9676 + * Counter-mode MIC.
9678 + * @param key The 128-bit symmetric key.
9679 + * @param nonce The CCM nonce.
9680 + * @param label The unique 14-byte ASCII text label.
9681 + * @param bytes The byte array to be encrypted.
9682 + * @param len Length of the byte array.
9683 + * @param result Byte array to receive the 8-byte encrypted MIC.
9685 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
9686 + char *label, u8 *bytes, int len, u8 *result)
9692 + u16 la = (u16)(len + 14);
9694 + /* Set the AES-128 key */
9695 + //dwc_aes_setkey(tfm, key, 16);
9697 + /* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
9698 + block_m[0] = 0x59;
9699 + for (idx = 0; idx < 13; idx++)
9700 + block_m[idx + 1] = nonce[idx];
9704 + /* Produce the CBC IV */
9705 + dwc_wusb_aes_encrypt(block_m, key, block_x);
9706 + show_block(block_m, "CBC IV in: ", "\n", 0);
9707 + show_block(block_x, "CBC IV out:", "\n", 0);
9709 + /* Fill block B1 from l(a) = Blen + 14, and A */
9710 + block_x[0] ^= (u8)(la >> 8);
9711 + block_x[1] ^= (u8)la;
9712 + for (idx = 0; idx < 14; idx++)
9713 + block_x[idx + 2] ^= label[idx];
9714 + show_block(block_x, "After xor: ", "b1\n", 16);
9716 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9717 + show_block(block_x, "After AES: ", "b1\n", 16);
9722 + /* Fill remaining blocks with B */
9723 + while (len-- > 0) {
9724 + block_x[idx] ^= *bytes++;
9725 + if (++idx >= 16) {
9727 + show_block(block_x, "After xor: ", "\n", blkNum);
9728 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9729 + show_block(block_x, "After AES: ", "\n", blkNum);
9734 + /* Handle partial last block */
9736 + show_block(block_x, "After xor: ", "\n", blkNum);
9737 + dwc_wusb_aes_encrypt(block_x, key, block_x);
9738 + show_block(block_x, "After AES: ", "\n", blkNum);
9741 + /* Save the MIC tag */
9742 + DWC_MEMCPY(block_t, block_x, 8);
9743 + show_block(block_t, "MIC tag : ", NULL, 8);
9745 + /* Fill block A0 from flags = 0x01, N, and counter = 0 */
9746 + block_m[0] = 0x01;
9750 + /* Encrypt the counter */
9751 + dwc_wusb_aes_encrypt(block_m, key, block_x);
9752 + show_block(block_x, "CTR[MIC] : ", NULL, 8);
9754 + /* XOR with MIC tag */
9755 + for (idx = 0; idx < 8; idx++) {
9756 + block_t[idx] ^= block_x[idx];
9759 + /* Return result to caller */
9760 + DWC_MEMCPY(result, block_t, 8);
9761 + show_block(result, "CCM-MIC : ", NULL, 8);
9766 + * The PRF function described in section 6.5 of the WUSB spec. This function
9767 + * concatenates MIC values returned from dwc_cmf() to create a value of
9768 + * the requested length.
9770 + * @param prf_len Length of the PRF function in bits (64, 128, or 256).
9771 + * @param key, nonce, label, bytes, len Same as for dwc_cmf().
9772 + * @param result Byte array to receive the result.
9774 +void dwc_wusb_prf(int prf_len, u8 *key,
9775 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
9780 + for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
9781 + dwc_wusb_cmf(key, nonce, label, bytes, len, result);
9787 + * Fills in CCM Nonce per the WUSB spec.
9789 + * @param[in] haddr Host address.
9790 + * @param[in] daddr Device address.
9791 + * @param[in] tkid Session Key(PTK) identifier.
9792 + * @param[out] nonce Pointer to where the CCM Nonce output is to be written.
9794 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
9798 + DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
9800 + DWC_MEMSET(&nonce[0], 0, 16);
9802 + DWC_MEMCPY(&nonce[6], tkid, 3);
9803 + nonce[9] = daddr & 0xFF;
9804 + nonce[10] = (daddr >> 8) & 0xFF;
9805 + nonce[11] = haddr & 0xFF;
9806 + nonce[12] = (haddr >> 8) & 0xFF;
9808 + dump_bytes("CCM nonce", nonce, 16);
9812 + * Generates a 16-byte cryptographic-grade random number for the Host/Device
9815 +void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
9817 + uint8_t inonce[16];
9820 + /* Fill in the Nonce */
9821 + DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
9822 + inonce[9] = addr & 0xFF;
9823 + inonce[10] = (addr >> 8) & 0xFF;
9824 + inonce[11] = inonce[9];
9825 + inonce[12] = inonce[10];
9827 + /* Collect "randomness samples" */
9828 + DWC_RANDOM_BYTES((uint8_t *)temp, 16);
9830 + dwc_wusb_prf_128((uint8_t *)temp, nonce,
9831 + "Random Numbers", (uint8_t *)temp, sizeof(temp),
9836 + * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
9839 + * @param[in] ccm_nonce Pointer to CCM Nonce.
9840 + * @param[in] mk Master Key to derive the session from
9841 + * @param[in] hnonce Pointer to Host Nonce.
9842 + * @param[in] dnonce Pointer to Device Nonce.
9843 + * @param[out] kck Pointer to where the KCK output is to be written.
9844 + * @param[out] ptk Pointer to where the PTK output is to be written.
9846 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
9847 + uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
9849 + uint8_t idata[32];
9850 + uint8_t odata[32];
9852 + dump_bytes("ck", mk, 16);
9853 + dump_bytes("hnonce", hnonce, 16);
9854 + dump_bytes("dnonce", dnonce, 16);
9856 + /* The data is the HNonce and DNonce concatenated */
9857 + DWC_MEMCPY(&idata[0], hnonce, 16);
9858 + DWC_MEMCPY(&idata[16], dnonce, 16);
9860 + dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
9862 + /* Low 16 bytes of the result is the KCK, high 16 is the PTK */
9863 + DWC_MEMCPY(kck, &odata[0], 16);
9864 + DWC_MEMCPY(ptk, &odata[16], 16);
9866 + dump_bytes("kck", kck, 16);
9867 + dump_bytes("ptk", ptk, 16);
9871 + * Generates the Message Integrity Code over the Handshake data per the
9874 + * @param ccm_nonce Pointer to CCM Nonce.
9875 + * @param kck Pointer to Key Confirmation Key.
9876 + * @param data Pointer to Handshake data to be checked.
9877 + * @param mic Pointer to where the MIC output is to be written.
9879 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
9880 + uint8_t *data, uint8_t *mic)
9883 + dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
9884 + data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
9887 +#endif /* DWC_CRYPTOLIB */
9888 diff --git a/drivers/usb/host/dwc_common_port/dwc_crypto.h b/drivers/usb/host/dwc_common_port/dwc_crypto.h
9889 new file mode 100644
9890 index 0000000..26fcddc
9892 +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.h
9894 +/* =========================================================================
9895 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.h $
9897 + * $Date: 2010/09/28 $
9898 + * $Change: 1596182 $
9900 + * Synopsys Portability Library Software and documentation
9901 + * (hereinafter, "Software") is an Unsupported proprietary work of
9902 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
9903 + * between Synopsys and you.
9905 + * The Software IS NOT an item of Licensed Software or Licensed Product
9906 + * under any End User Software License Agreement or Agreement for
9907 + * Licensed Product with Synopsys or any supplement thereto. You are
9908 + * permitted to use and redistribute this Software in source and binary
9909 + * forms, with or without modification, provided that redistributions
9910 + * of source code must retain this notice. You may not view, use,
9911 + * disclose, copy or distribute this file or any information contained
9912 + * herein except pursuant to this license grant from Synopsys. If you
9913 + * do not agree with this notice, including the disclaimer below, then
9914 + * you are not authorized to use the Software.
9916 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
9917 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9918 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
9919 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
9920 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
9921 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9922 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9923 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
9924 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9925 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9926 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
9928 + * ========================================================================= */
9930 +#ifndef _DWC_CRYPTO_H_
9931 +#define _DWC_CRYPTO_H_
9939 + * This file contains declarations for the WUSB Cryptographic routines as
9940 + * defined in the WUSB spec. They are only to be used internally by the DWC UWB
9944 +#include "dwc_os.h"
9946 +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
9948 +void dwc_wusb_cmf(u8 *key, u8 *nonce,
9949 + char *label, u8 *bytes, int len, u8 *result);
9950 +void dwc_wusb_prf(int prf_len, u8 *key,
9951 + u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
9954 + * The PRF-64 function described in section 6.5 of the WUSB spec.
9956 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9958 +static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
9959 + char *label, u8 *bytes, int len, u8 *result)
9961 + dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
9965 + * The PRF-128 function described in section 6.5 of the WUSB spec.
9967 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9969 +static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
9970 + char *label, u8 *bytes, int len, u8 *result)
9972 + dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
9976 + * The PRF-256 function described in section 6.5 of the WUSB spec.
9978 + * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
9980 +static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
9981 + char *label, u8 *bytes, int len, u8 *result)
9983 + dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
9987 +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
9989 +void dwc_wusb_gen_nonce(uint16_t addr,
9992 +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
9993 + uint8_t *hnonce, uint8_t *dnonce,
9994 + uint8_t *kck, uint8_t *ptk);
9997 +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
9998 + *kck, uint8_t *data, uint8_t *mic);
10000 +#ifdef __cplusplus
10004 +#endif /* _DWC_CRYPTO_H_ */
10005 diff --git a/drivers/usb/host/dwc_common_port/dwc_dh.c b/drivers/usb/host/dwc_common_port/dwc_dh.c
10006 new file mode 100644
10007 index 0000000..997f753
10009 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.c
10011 +/* =========================================================================
10012 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
10013 + * $Revision: #3 $
10014 + * $Date: 2010/09/28 $
10015 + * $Change: 1596182 $
10017 + * Synopsys Portability Library Software and documentation
10018 + * (hereinafter, "Software") is an Unsupported proprietary work of
10019 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
10020 + * between Synopsys and you.
10022 + * The Software IS NOT an item of Licensed Software or Licensed Product
10023 + * under any End User Software License Agreement or Agreement for
10024 + * Licensed Product with Synopsys or any supplement thereto. You are
10025 + * permitted to use and redistribute this Software in source and binary
10026 + * forms, with or without modification, provided that redistributions
10027 + * of source code must retain this notice. You may not view, use,
10028 + * disclose, copy or distribute this file or any information contained
10029 + * herein except pursuant to this license grant from Synopsys. If you
10030 + * do not agree with this notice, including the disclaimer below, then
10031 + * you are not authorized to use the Software.
10033 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
10034 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10035 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
10036 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
10037 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
10038 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
10039 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
10040 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
10041 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10042 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
10043 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
10045 + * ========================================================================= */
10046 +#ifdef DWC_CRYPTOLIB
10048 +#ifndef CONFIG_MACH_IPMATE
10050 +#include "dwc_dh.h"
10051 +#include "dwc_modpow.h"
10054 +/* This function prints out a buffer in the format described in the Association
10055 + * Model specification. */
10056 +static void dh_dump(char *str, void *_num, int len)
10058 + uint8_t *num = _num;
10060 + DWC_PRINTF("%s\n", str);
10061 + for (i = 0; i < len; i ++) {
10062 + DWC_PRINTF("%02x", num[i]);
10063 + if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
10064 + if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
10067 + DWC_PRINTF("\n");
10070 +#define dh_dump(_x...) do {; } while(0)
10073 +/* Constant g value */
10074 +static __u32 dh_g[] = {
10078 +/* Constant p value */
10079 +static __u32 dh_p[] = {
10080 + 0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
10081 + 0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
10082 + 0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
10083 + 0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
10084 + 0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
10085 + 0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
10086 + 0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
10087 + 0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
10088 + 0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
10089 + 0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
10090 + 0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
10091 + 0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
10094 +static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
10096 + uint8_t *in = _in;
10097 + uint8_t *out = _out;
10099 + for (i=0; i<len; i++) {
10100 + out[i] = in[len-1-i];
10104 +/* Computes the modular exponentiation (num^exp % mod). num, exp, and mod are
10105 + * big endian numbers of size len, in bytes. Each len value must be a multiple
10107 +int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
10108 + void *exp, uint32_t exp_len,
10109 + void *mod, uint32_t mod_len,
10112 + /* modpow() takes little endian numbers. AM uses big-endian. This
10113 + * function swaps bytes of numbers before passing onto modpow. */
10116 + uint32_t *result;
10118 + uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
10119 + uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
10120 + uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
10122 + dh_swap_bytes(num, &bignum_num[1], num_len);
10123 + bignum_num[0] = num_len / 4;
10125 + dh_swap_bytes(exp, &bignum_exp[1], exp_len);
10126 + bignum_exp[0] = exp_len / 4;
10128 + dh_swap_bytes(mod, &bignum_mod[1], mod_len);
10129 + bignum_mod[0] = mod_len / 4;
10131 + result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
10134 + goto dh_modpow_nomem;
10137 + dh_swap_bytes(&result[1], out, result[0] * 4);
10138 + dwc_free(mem_ctx, result);
10141 + dwc_free(mem_ctx, bignum_num);
10142 + dwc_free(mem_ctx, bignum_exp);
10143 + dwc_free(mem_ctx, bignum_mod);
10148 +int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
10153 +#ifndef DH_TEST_VECTORS
10154 + DWC_RANDOM_BYTES(exp, 32);
10157 + /* Compute the pkd */
10158 + if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
10160 + dh_p, 384, pk))) {
10165 + DWC_MEMCPY(&m3[0], pk, 384);
10166 + DWC_SHA256(m3, 385, hash);
10168 + dh_dump("PK", pk, 384);
10169 + dh_dump("SHA-256(M3)", hash, 32);
10173 +int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
10174 + uint8_t *exp, int is_host,
10175 + char *dd, uint8_t *ck, uint8_t *kdk)
10179 + uint8_t sha_result[32];
10180 + uint8_t dhkey[384];
10181 + uint8_t shared_secret[384];
10194 + if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
10196 + dh_p, 384, shared_secret))) {
10199 + dh_dump("Shared Secret", shared_secret, 384);
10201 + DWC_SHA256(shared_secret, 384, dhkey);
10202 + dh_dump("DHKEY", dhkey, 384);
10204 + DWC_MEMCPY(&mv[0], pkd, 384);
10205 + DWC_MEMCPY(&mv[384], pkh, 384);
10206 + DWC_MEMCPY(&mv[768], "displayed digest", 16);
10207 + dh_dump("MV", mv, 784);
10209 + DWC_SHA256(mv, 784, sha_result);
10210 + dh_dump("SHA-256(MV)", sha_result, 32);
10211 + dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
10213 + dh_swap_bytes(sha_result, &vd, 4);
10215 + DWC_PRINTF("Vd (decimal) = %d\n", vd);
10221 + DWC_SPRINTF(dd, "%02d", vd);
10225 + DWC_SPRINTF(dd, "%03d", vd);
10229 + DWC_SPRINTF(dd, "%04d", vd);
10233 + DWC_PRINTF("Display Digits: %s\n", dd);
10236 + message = "connection key";
10237 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
10238 + dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
10239 + DWC_MEMCPY(ck, sha_result, 16);
10241 + message = "key derivation key";
10242 + DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
10243 + dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
10244 + DWC_MEMCPY(kdk, sha_result, 32);
10250 +#ifdef DH_TEST_VECTORS
10252 +static __u8 dh_a[] = {
10253 + 0x44, 0x00, 0x51, 0xd6,
10254 + 0xf0, 0xb5, 0x5e, 0xa9,
10255 + 0x67, 0xab, 0x31, 0xc6,
10256 + 0x8a, 0x8b, 0x5e, 0x37,
10257 + 0xd9, 0x10, 0xda, 0xe0,
10258 + 0xe2, 0xd4, 0x59, 0xa4,
10259 + 0x86, 0x45, 0x9c, 0xaa,
10260 + 0xdf, 0x36, 0x75, 0x16,
10263 +static __u8 dh_b[] = {
10264 + 0x5d, 0xae, 0xc7, 0x86,
10265 + 0x79, 0x80, 0xa3, 0x24,
10266 + 0x8c, 0xe3, 0x57, 0x8f,
10267 + 0xc7, 0x5f, 0x1b, 0x0f,
10268 + 0x2d, 0xf8, 0x9d, 0x30,
10269 + 0x6f, 0xa4, 0x52, 0xcd,
10270 + 0xe0, 0x7a, 0x04, 0x8a,
10271 + 0xde, 0xd9, 0x26, 0x56,
10274 +void dwc_run_dh_test_vectors(void *mem_ctx)
10276 + uint8_t pkd[384];
10277 + uint8_t pkh[384];
10278 + uint8_t hashd[32];
10279 + uint8_t hashh[32];
10284 + DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
10286 + /* compute the PKd and SHA-256(PKd || Nd) */
10287 + DWC_PRINTF("Computing PKd\n");
10288 + dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
10290 + /* compute the PKd and SHA-256(PKh || Nd) */
10291 + DWC_PRINTF("Computing PKh\n");
10292 + dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
10294 + /* compute the dhkey */
10295 + dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
10297 +#endif /* DH_TEST_VECTORS */
10299 +#endif /* !CONFIG_MACH_IPMATE */
10301 +#endif /* DWC_CRYPTOLIB */
10302 diff --git a/drivers/usb/host/dwc_common_port/dwc_dh.h b/drivers/usb/host/dwc_common_port/dwc_dh.h
10303 new file mode 100644
10304 index 0000000..25c1cc0
10306 +++ b/drivers/usb/host/dwc_common_port/dwc_dh.h
10308 +/* =========================================================================
10309 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.h $
10310 + * $Revision: #4 $
10311 + * $Date: 2010/09/28 $
10312 + * $Change: 1596182 $
10314 + * Synopsys Portability Library Software and documentation
10315 + * (hereinafter, "Software") is an Unsupported proprietary work of
10316 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
10317 + * between Synopsys and you.
10319 + * The Software IS NOT an item of Licensed Software or Licensed Product
10320 + * under any End User Software License Agreement or Agreement for
10321 + * Licensed Product with Synopsys or any supplement thereto. You are
10322 + * permitted to use and redistribute this Software in source and binary
10323 + * forms, with or without modification, provided that redistributions
10324 + * of source code must retain this notice. You may not view, use,
10325 + * disclose, copy or distribute this file or any information contained
10326 + * herein except pursuant to this license grant from Synopsys. If you
10327 + * do not agree with this notice, including the disclaimer below, then
10328 + * you are not authorized to use the Software.
10330 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
10331 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10332 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
10333 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
10334 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
10335 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
10336 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
10337 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
10338 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10339 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
10340 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
10342 + * ========================================================================= */
10343 +#ifndef _DWC_DH_H_
10344 +#define _DWC_DH_H_
10346 +#ifdef __cplusplus
10350 +#include "dwc_os.h"
10354 + * This file defines the common functions on device and host for performing
10355 + * numeric association as defined in the WUSB spec. They are only to be
10356 + * used internally by the DWC UWB modules. */
10358 +extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
10359 +extern int dwc_dh_hmac_sha256(uint8_t *message, uint32_t messagelen,
10360 + uint8_t *key, uint32_t keylen,
10362 +extern int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
10363 + void *exp, uint32_t exp_len,
10364 + void *mod, uint32_t mod_len,
10367 +/** Computes PKD or PKH, and SHA-256(PKd || Nd)
10369 + * PK = g^exp mod p.
10372 + * Nd = Number of digits on the device.
10375 + * exp = A 32-byte buffer to be filled with a randomly generated number.
10376 + * used as either A or B.
10377 + * pk = A 384-byte buffer to be filled with the PKH or PKD.
10378 + * hash = A 32-byte buffer to be filled with SHA-256(PK || ND).
10380 +extern int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash);
10382 +/** Computes the DHKEY, and VD.
10384 + * If called from host, then it will comput DHKEY=PKD^exp % p.
10385 + * If called from device, then it will comput DHKEY=PKH^exp % p.
10388 + * pkd = The PKD value.
10389 + * pkh = The PKH value.
10390 + * exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk.
10391 + * is_host = Set to non zero if a WUSB host is calling this function.
10395 + * dd = A pointer to an buffer to be set to the displayed digits string to be shown
10396 + * to the user. This buffer should be at 5 bytes long to hold 4 digits plus a
10397 + * null termination character. This buffer can be used directly for display.
10398 + * ck = A 16-byte buffer to be filled with the CK.
10399 + * kdk = A 32-byte buffer to be filled with the KDK.
10401 +extern int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
10402 + uint8_t *exp, int is_host,
10403 + char *dd, uint8_t *ck, uint8_t *kdk);
10405 +#ifdef DH_TEST_VECTORS
10406 +extern void dwc_run_dh_test_vectors(void);
10409 +#ifdef __cplusplus
10413 +#endif /* _DWC_DH_H_ */
10414 diff --git a/drivers/usb/host/dwc_common_port/dwc_list.h b/drivers/usb/host/dwc_common_port/dwc_list.h
10415 new file mode 100644
10416 index 0000000..89cc325
10418 +++ b/drivers/usb/host/dwc_common_port/dwc_list.h
10420 +/* $OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $ */
10421 +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
10424 + * Copyright (c) 1991, 1993
10425 + * The Regents of the University of California. All rights reserved.
10427 + * Redistribution and use in source and binary forms, with or without
10428 + * modification, are permitted provided that the following conditions
10430 + * 1. Redistributions of source code must retain the above copyright
10431 + * notice, this list of conditions and the following disclaimer.
10432 + * 2. Redistributions in binary form must reproduce the above copyright
10433 + * notice, this list of conditions and the following disclaimer in the
10434 + * documentation and/or other materials provided with the distribution.
10435 + * 3. Neither the name of the University nor the names of its contributors
10436 + * may be used to endorse or promote products derived from this software
10437 + * without specific prior written permission.
10439 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
10440 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10441 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10442 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
10443 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10444 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10445 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10446 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10447 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10448 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10451 + * @(#)queue.h 8.5 (Berkeley) 8/20/94
10454 +#ifndef _DWC_LIST_H_
10455 +#define _DWC_LIST_H_
10457 +#ifdef __cplusplus
10463 + * This file defines linked list operations. It is derived from BSD with
10464 + * only the MACRO names being prefixed with DWC_. This is because a few of
10465 + * these names conflict with those on Linux. For documentation on use, see the
10466 + * inline comments in the source code. The original license for this source
10467 + * code applies and is preserved in the dwc_list.h source file.
10471 + * This file defines five types of data structures: singly-linked lists,
10472 + * lists, simple queues, tail queues, and circular queues.
10475 + * A singly-linked list is headed by a single forward pointer. The elements
10476 + * are singly linked for minimum space and pointer manipulation overhead at
10477 + * the expense of O(n) removal for arbitrary elements. New elements can be
10478 + * added to the list after an existing element or at the head of the list.
10479 + * Elements being removed from the head of the list should use the explicit
10480 + * macro for this purpose for optimum efficiency. A singly-linked list may
10481 + * only be traversed in the forward direction. Singly-linked lists are ideal
10482 + * for applications with large datasets and few or no removals or for
10483 + * implementing a LIFO queue.
10485 + * A list is headed by a single forward pointer (or an array of forward
10486 + * pointers for a hash table header). The elements are doubly linked
10487 + * so that an arbitrary element can be removed without a need to
10488 + * traverse the list. New elements can be added to the list before
10489 + * or after an existing element or at the head of the list. A list
10490 + * may only be traversed in the forward direction.
10492 + * A simple queue is headed by a pair of pointers, one the head of the
10493 + * list and the other to the tail of the list. The elements are singly
10494 + * linked to save space, so elements can only be removed from the
10495 + * head of the list. New elements can be added to the list before or after
10496 + * an existing element, at the head of the list, or at the end of the
10497 + * list. A simple queue may only be traversed in the forward direction.
10499 + * A tail queue is headed by a pair of pointers, one to the head of the
10500 + * list and the other to the tail of the list. The elements are doubly
10501 + * linked so that an arbitrary element can be removed without a need to
10502 + * traverse the list. New elements can be added to the list before or
10503 + * after an existing element, at the head of the list, or at the end of
10504 + * the list. A tail queue may be traversed in either direction.
10506 + * A circle queue is headed by a pair of pointers, one to the head of the
10507 + * list and the other to the tail of the list. The elements are doubly
10508 + * linked so that an arbitrary element can be removed without a need to
10509 + * traverse the list. New elements can be added to the list before or after
10510 + * an existing element, at the head of the list, or at the end of the list.
10511 + * A circle queue may be traversed in either direction, but has a more
10512 + * complex end of list detection.
10514 + * For details on the use of these macros, see the queue(3) manual page.
10518 + * Double-linked List.
10521 +typedef struct dwc_list_link {
10522 + struct dwc_list_link *next;
10523 + struct dwc_list_link *prev;
10524 +} dwc_list_link_t;
10526 +#define DWC_LIST_INIT(link) do { \
10527 + (link)->next = (link); \
10528 + (link)->prev = (link); \
10531 +#define DWC_LIST_FIRST(link) ((link)->next)
10532 +#define DWC_LIST_LAST(link) ((link)->prev)
10533 +#define DWC_LIST_END(link) (link)
10534 +#define DWC_LIST_NEXT(link) ((link)->next)
10535 +#define DWC_LIST_PREV(link) ((link)->prev)
10536 +#define DWC_LIST_EMPTY(link) \
10537 + (DWC_LIST_FIRST(link) == DWC_LIST_END(link))
10538 +#define DWC_LIST_ENTRY(link, type, field) \
10539 + (type *)((uint8_t *)(link) - (size_t)(&((type *)0)->field))
10542 +#define DWC_LIST_INSERT_HEAD(list, link) do { \
10543 + (link)->next = (list)->next; \
10544 + (link)->prev = (list); \
10545 + (list)->next->prev = (link); \
10546 + (list)->next = (link); \
10549 +#define DWC_LIST_INSERT_TAIL(list, link) do { \
10550 + (link)->next = (list); \
10551 + (link)->prev = (list)->prev; \
10552 + (list)->prev->next = (link); \
10553 + (list)->prev = (link); \
10556 +#define DWC_LIST_INSERT_HEAD(list, link) do { \
10557 + dwc_list_link_t *__next__ = (list)->next; \
10558 + __next__->prev = (link); \
10559 + (link)->next = __next__; \
10560 + (link)->prev = (list); \
10561 + (list)->next = (link); \
10564 +#define DWC_LIST_INSERT_TAIL(list, link) do { \
10565 + dwc_list_link_t *__prev__ = (list)->prev; \
10566 + (list)->prev = (link); \
10567 + (link)->next = (list); \
10568 + (link)->prev = __prev__; \
10569 + __prev__->next = (link); \
10574 +static inline void __list_add(struct list_head *new,
10575 + struct list_head *prev,
10576 + struct list_head *next)
10578 + next->prev = new;
10579 + new->next = next;
10580 + new->prev = prev;
10581 + prev->next = new;
10584 +static inline void list_add(struct list_head *new, struct list_head *head)
10586 + __list_add(new, head, head->next);
10589 +static inline void list_add_tail(struct list_head *new, struct list_head *head)
10591 + __list_add(new, head->prev, head);
10594 +static inline void __list_del(struct list_head * prev, struct list_head * next)
10596 + next->prev = prev;
10597 + prev->next = next;
10600 +static inline void list_del(struct list_head *entry)
10602 + __list_del(entry->prev, entry->next);
10603 + entry->next = LIST_POISON1;
10604 + entry->prev = LIST_POISON2;
10608 +#define DWC_LIST_REMOVE(link) do { \
10609 + (link)->next->prev = (link)->prev; \
10610 + (link)->prev->next = (link)->next; \
10613 +#define DWC_LIST_REMOVE_INIT(link) do { \
10614 + DWC_LIST_REMOVE(link); \
10615 + DWC_LIST_INIT(link); \
10618 +#define DWC_LIST_MOVE_HEAD(list, link) do { \
10619 + DWC_LIST_REMOVE(link); \
10620 + DWC_LIST_INSERT_HEAD(list, link); \
10623 +#define DWC_LIST_MOVE_TAIL(list, link) do { \
10624 + DWC_LIST_REMOVE(link); \
10625 + DWC_LIST_INSERT_TAIL(list, link); \
10628 +#define DWC_LIST_FOREACH(var, list) \
10629 + for((var) = DWC_LIST_FIRST(list); \
10630 + (var) != DWC_LIST_END(list); \
10631 + (var) = DWC_LIST_NEXT(var))
10633 +#define DWC_LIST_FOREACH_SAFE(var, var2, list) \
10634 + for((var) = DWC_LIST_FIRST(list), (var2) = DWC_LIST_NEXT(var); \
10635 + (var) != DWC_LIST_END(list); \
10636 + (var) = (var2), (var2) = DWC_LIST_NEXT(var2))
10638 +#define DWC_LIST_FOREACH_REVERSE(var, list) \
10639 + for((var) = DWC_LIST_LAST(list); \
10640 + (var) != DWC_LIST_END(list); \
10641 + (var) = DWC_LIST_PREV(var))
10644 + * Singly-linked List definitions.
10646 +#define DWC_SLIST_HEAD(name, type) \
10648 + struct type *slh_first; /* first element */ \
10651 +#define DWC_SLIST_HEAD_INITIALIZER(head) \
10654 +#define DWC_SLIST_ENTRY(type) \
10656 + struct type *sle_next; /* next element */ \
10660 + * Singly-linked List access methods.
10662 +#define DWC_SLIST_FIRST(head) ((head)->slh_first)
10663 +#define DWC_SLIST_END(head) NULL
10664 +#define DWC_SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
10665 +#define DWC_SLIST_NEXT(elm, field) ((elm)->field.sle_next)
10667 +#define DWC_SLIST_FOREACH(var, head, field) \
10668 + for((var) = SLIST_FIRST(head); \
10669 + (var) != SLIST_END(head); \
10670 + (var) = SLIST_NEXT(var, field))
10672 +#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field) \
10673 + for((varp) = &SLIST_FIRST((head)); \
10674 + ((var) = *(varp)) != SLIST_END(head); \
10675 + (varp) = &SLIST_NEXT((var), field))
10678 + * Singly-linked List functions.
10680 +#define DWC_SLIST_INIT(head) { \
10681 + SLIST_FIRST(head) = SLIST_END(head); \
10684 +#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do { \
10685 + (elm)->field.sle_next = (slistelm)->field.sle_next; \
10686 + (slistelm)->field.sle_next = (elm); \
10689 +#define DWC_SLIST_INSERT_HEAD(head, elm, field) do { \
10690 + (elm)->field.sle_next = (head)->slh_first; \
10691 + (head)->slh_first = (elm); \
10694 +#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do { \
10695 + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
10698 +#define DWC_SLIST_REMOVE_HEAD(head, field) do { \
10699 + (head)->slh_first = (head)->slh_first->field.sle_next; \
10702 +#define DWC_SLIST_REMOVE(head, elm, type, field) do { \
10703 + if ((head)->slh_first == (elm)) { \
10704 + SLIST_REMOVE_HEAD((head), field); \
10707 + struct type *curelm = (head)->slh_first; \
10708 + while( curelm->field.sle_next != (elm) ) \
10709 + curelm = curelm->field.sle_next; \
10710 + curelm->field.sle_next = \
10711 + curelm->field.sle_next->field.sle_next; \
10716 + * Simple queue definitions.
10718 +#define DWC_SIMPLEQ_HEAD(name, type) \
10720 + struct type *sqh_first; /* first element */ \
10721 + struct type **sqh_last; /* addr of last next element */ \
10724 +#define DWC_SIMPLEQ_HEAD_INITIALIZER(head) \
10725 + { NULL, &(head).sqh_first }
10727 +#define DWC_SIMPLEQ_ENTRY(type) \
10729 + struct type *sqe_next; /* next element */ \
10733 + * Simple queue access methods.
10735 +#define DWC_SIMPLEQ_FIRST(head) ((head)->sqh_first)
10736 +#define DWC_SIMPLEQ_END(head) NULL
10737 +#define DWC_SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
10738 +#define DWC_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
10740 +#define DWC_SIMPLEQ_FOREACH(var, head, field) \
10741 + for((var) = SIMPLEQ_FIRST(head); \
10742 + (var) != SIMPLEQ_END(head); \
10743 + (var) = SIMPLEQ_NEXT(var, field))
10746 + * Simple queue functions.
10748 +#define DWC_SIMPLEQ_INIT(head) do { \
10749 + (head)->sqh_first = NULL; \
10750 + (head)->sqh_last = &(head)->sqh_first; \
10753 +#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
10754 + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
10755 + (head)->sqh_last = &(elm)->field.sqe_next; \
10756 + (head)->sqh_first = (elm); \
10759 +#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
10760 + (elm)->field.sqe_next = NULL; \
10761 + *(head)->sqh_last = (elm); \
10762 + (head)->sqh_last = &(elm)->field.sqe_next; \
10765 +#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
10766 + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
10767 + (head)->sqh_last = &(elm)->field.sqe_next; \
10768 + (listelm)->field.sqe_next = (elm); \
10771 +#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do { \
10772 + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
10773 + (head)->sqh_last = &(head)->sqh_first; \
10777 + * Tail queue definitions.
10779 +#define DWC_TAILQ_HEAD(name, type) \
10781 + struct type *tqh_first; /* first element */ \
10782 + struct type **tqh_last; /* addr of last next element */ \
10785 +#define DWC_TAILQ_HEAD_INITIALIZER(head) \
10786 + { NULL, &(head).tqh_first }
10788 +#define DWC_TAILQ_ENTRY(type) \
10790 + struct type *tqe_next; /* next element */ \
10791 + struct type **tqe_prev; /* address of previous next element */ \
10795 + * tail queue access methods
10797 +#define DWC_TAILQ_FIRST(head) ((head)->tqh_first)
10798 +#define DWC_TAILQ_END(head) NULL
10799 +#define DWC_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
10800 +#define DWC_TAILQ_LAST(head, headname) \
10801 + (*(((struct headname *)((head)->tqh_last))->tqh_last))
10803 +#define DWC_TAILQ_PREV(elm, headname, field) \
10804 + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
10805 +#define DWC_TAILQ_EMPTY(head) \
10806 + (TAILQ_FIRST(head) == TAILQ_END(head))
10808 +#define DWC_TAILQ_FOREACH(var, head, field) \
10809 + for((var) = TAILQ_FIRST(head); \
10810 + (var) != TAILQ_END(head); \
10811 + (var) = TAILQ_NEXT(var, field))
10813 +#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
10814 + for((var) = TAILQ_LAST(head, headname); \
10815 + (var) != TAILQ_END(head); \
10816 + (var) = TAILQ_PREV(var, headname, field))
10819 + * Tail queue functions.
10821 +#define DWC_TAILQ_INIT(head) do { \
10822 + (head)->tqh_first = NULL; \
10823 + (head)->tqh_last = &(head)->tqh_first; \
10826 +#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do { \
10827 + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
10828 + (head)->tqh_first->field.tqe_prev = \
10829 + &(elm)->field.tqe_next; \
10831 + (head)->tqh_last = &(elm)->field.tqe_next; \
10832 + (head)->tqh_first = (elm); \
10833 + (elm)->field.tqe_prev = &(head)->tqh_first; \
10836 +#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do { \
10837 + (elm)->field.tqe_next = NULL; \
10838 + (elm)->field.tqe_prev = (head)->tqh_last; \
10839 + *(head)->tqh_last = (elm); \
10840 + (head)->tqh_last = &(elm)->field.tqe_next; \
10843 +#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
10844 + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
10845 + (elm)->field.tqe_next->field.tqe_prev = \
10846 + &(elm)->field.tqe_next; \
10848 + (head)->tqh_last = &(elm)->field.tqe_next; \
10849 + (listelm)->field.tqe_next = (elm); \
10850 + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
10853 +#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
10854 + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
10855 + (elm)->field.tqe_next = (listelm); \
10856 + *(listelm)->field.tqe_prev = (elm); \
10857 + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
10860 +#define DWC_TAILQ_REMOVE(head, elm, field) do { \
10861 + if (((elm)->field.tqe_next) != NULL) \
10862 + (elm)->field.tqe_next->field.tqe_prev = \
10863 + (elm)->field.tqe_prev; \
10865 + (head)->tqh_last = (elm)->field.tqe_prev; \
10866 + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
10869 +#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do { \
10870 + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
10871 + (elm2)->field.tqe_next->field.tqe_prev = \
10872 + &(elm2)->field.tqe_next; \
10874 + (head)->tqh_last = &(elm2)->field.tqe_next; \
10875 + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
10876 + *(elm2)->field.tqe_prev = (elm2); \
10880 + * Circular queue definitions.
10882 +#define DWC_CIRCLEQ_HEAD(name, type) \
10884 + struct type *cqh_first; /* first element */ \
10885 + struct type *cqh_last; /* last element */ \
10888 +#define DWC_CIRCLEQ_HEAD_INITIALIZER(head) \
10889 + { DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
10891 +#define DWC_CIRCLEQ_ENTRY(type) \
10893 + struct type *cqe_next; /* next element */ \
10894 + struct type *cqe_prev; /* previous element */ \
10898 + * Circular queue access methods
10900 +#define DWC_CIRCLEQ_FIRST(head) ((head)->cqh_first)
10901 +#define DWC_CIRCLEQ_LAST(head) ((head)->cqh_last)
10902 +#define DWC_CIRCLEQ_END(head) ((void *)(head))
10903 +#define DWC_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
10904 +#define DWC_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
10905 +#define DWC_CIRCLEQ_EMPTY(head) \
10906 + (DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
10908 +#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
10910 +#define DWC_CIRCLEQ_FOREACH(var, head, field) \
10911 + for((var) = DWC_CIRCLEQ_FIRST(head); \
10912 + (var) != DWC_CIRCLEQ_END(head); \
10913 + (var) = DWC_CIRCLEQ_NEXT(var, field))
10915 +#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field) \
10916 + for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
10917 + (var) != DWC_CIRCLEQ_END(head); \
10918 + (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
10920 +#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field) \
10921 + for((var) = DWC_CIRCLEQ_LAST(head); \
10922 + (var) != DWC_CIRCLEQ_END(head); \
10923 + (var) = DWC_CIRCLEQ_PREV(var, field))
10926 + * Circular queue functions.
10928 +#define DWC_CIRCLEQ_INIT(head) do { \
10929 + (head)->cqh_first = DWC_CIRCLEQ_END(head); \
10930 + (head)->cqh_last = DWC_CIRCLEQ_END(head); \
10933 +#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do { \
10934 + (elm)->field.cqe_next = NULL; \
10935 + (elm)->field.cqe_prev = NULL; \
10938 +#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
10939 + (elm)->field.cqe_next = (listelm)->field.cqe_next; \
10940 + (elm)->field.cqe_prev = (listelm); \
10941 + if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
10942 + (head)->cqh_last = (elm); \
10944 + (listelm)->field.cqe_next->field.cqe_prev = (elm); \
10945 + (listelm)->field.cqe_next = (elm); \
10948 +#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
10949 + (elm)->field.cqe_next = (listelm); \
10950 + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
10951 + if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
10952 + (head)->cqh_first = (elm); \
10954 + (listelm)->field.cqe_prev->field.cqe_next = (elm); \
10955 + (listelm)->field.cqe_prev = (elm); \
10958 +#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
10959 + (elm)->field.cqe_next = (head)->cqh_first; \
10960 + (elm)->field.cqe_prev = DWC_CIRCLEQ_END(head); \
10961 + if ((head)->cqh_last == DWC_CIRCLEQ_END(head)) \
10962 + (head)->cqh_last = (elm); \
10964 + (head)->cqh_first->field.cqe_prev = (elm); \
10965 + (head)->cqh_first = (elm); \
10968 +#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
10969 + (elm)->field.cqe_next = DWC_CIRCLEQ_END(head); \
10970 + (elm)->field.cqe_prev = (head)->cqh_last; \
10971 + if ((head)->cqh_first == DWC_CIRCLEQ_END(head)) \
10972 + (head)->cqh_first = (elm); \
10974 + (head)->cqh_last->field.cqe_next = (elm); \
10975 + (head)->cqh_last = (elm); \
10978 +#define DWC_CIRCLEQ_REMOVE(head, elm, field) do { \
10979 + if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
10980 + (head)->cqh_last = (elm)->field.cqe_prev; \
10982 + (elm)->field.cqe_next->field.cqe_prev = \
10983 + (elm)->field.cqe_prev; \
10984 + if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
10985 + (head)->cqh_first = (elm)->field.cqe_next; \
10987 + (elm)->field.cqe_prev->field.cqe_next = \
10988 + (elm)->field.cqe_next; \
10991 +#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do { \
10992 + DWC_CIRCLEQ_REMOVE(head, elm, field); \
10993 + DWC_CIRCLEQ_INIT_ENTRY(elm, field); \
10996 +#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
10997 + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
10998 + DWC_CIRCLEQ_END(head)) \
10999 + (head).cqh_last = (elm2); \
11001 + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
11002 + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
11003 + DWC_CIRCLEQ_END(head)) \
11004 + (head).cqh_first = (elm2); \
11006 + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
11009 +#ifdef __cplusplus
11013 +#endif /* _DWC_LIST_H_ */
11014 diff --git a/drivers/usb/host/dwc_common_port/dwc_mem.c b/drivers/usb/host/dwc_common_port/dwc_mem.c
11015 new file mode 100644
11016 index 0000000..ad645ff
11018 +++ b/drivers/usb/host/dwc_common_port/dwc_mem.c
11020 +/* Memory Debugging */
11021 +#ifdef DWC_DEBUG_MEMORY
11023 +#include "dwc_os.h"
11024 +#include "dwc_list.h"
11026 +struct allocation {
11033 + DWC_CIRCLEQ_ENTRY(allocation) entry;
11036 +DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
11038 +struct allocation_manager {
11040 + struct allocation_queue allocations;
11051 +static struct allocation_manager *manager = NULL;
11053 +static int add_allocation(void *ctx, uint32_t size, char const *func, int line, void *addr,
11056 + struct allocation *a;
11058 + DWC_ASSERT(manager != NULL, "manager not allocated");
11060 + a = __DWC_ALLOC_ATOMIC(manager->mem_ctx, sizeof(*a));
11062 + return -DWC_E_NO_MEMORY;
11065 + a->func = __DWC_ALLOC_ATOMIC(manager->mem_ctx, DWC_STRLEN(func) + 1);
11067 + __DWC_FREE(manager->mem_ctx, a);
11068 + return -DWC_E_NO_MEMORY;
11071 + DWC_MEMCPY(a->func, func, DWC_STRLEN(func) + 1);
11077 + DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
11079 + /* Update stats */
11081 + manager->num_active++;
11082 + manager->total += size;
11083 + manager->cur += size;
11085 + if (manager->max < manager->cur) {
11086 + manager->max = manager->cur;
11092 +static struct allocation *find_allocation(void *ctx, void *addr)
11094 + struct allocation *a;
11096 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
11097 + if (a->ctx == ctx && a->addr == addr) {
11105 +static void free_allocation(void *ctx, void *addr, char const *func, int line)
11107 + struct allocation *a = find_allocation(ctx, addr);
11111 + "Free of address %p that was never allocated or already freed %s:%d",
11112 + addr, func, line);
11116 + DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
11118 + manager->num_active--;
11119 + manager->num_freed++;
11120 + manager->cur -= a->size;
11121 + __DWC_FREE(manager->mem_ctx, a->func);
11122 + __DWC_FREE(manager->mem_ctx, a);
11125 +int dwc_memory_debug_start(void *mem_ctx)
11127 + DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
11130 + return -DWC_E_BUSY;
11133 + manager = __DWC_ALLOC(mem_ctx, sizeof(*manager));
11135 + return -DWC_E_NO_MEMORY;
11138 + DWC_CIRCLEQ_INIT(&manager->allocations);
11139 + manager->mem_ctx = mem_ctx;
11140 + manager->num = 0;
11141 + manager->num_freed = 0;
11142 + manager->num_active = 0;
11143 + manager->total = 0;
11144 + manager->cur = 0;
11145 + manager->max = 0;
11150 +void dwc_memory_debug_stop(void)
11152 + struct allocation *a;
11154 + dwc_memory_debug_report();
11156 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
11157 + DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
11158 + free_allocation(a->ctx, a->addr, NULL, -1);
11161 + __DWC_FREE(manager->mem_ctx, manager);
11164 +void dwc_memory_debug_report(void)
11166 + struct allocation *a;
11168 + DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
11169 + DWC_PRINTF("Num Allocations = %d\n", manager->num);
11170 + DWC_PRINTF("Freed = %d\n", manager->num_freed);
11171 + DWC_PRINTF("Active = %d\n", manager->num_active);
11172 + DWC_PRINTF("Current Memory Used = %d\n", manager->cur);
11173 + DWC_PRINTF("Total Memory Used = %d\n", manager->total);
11174 + DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
11175 + DWC_PRINTF("Unfreed allocations:\n");
11177 + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
11178 + DWC_PRINTF(" addr=%p, size=%d from %s:%d, DMA=%d\n",
11179 + a->addr, a->size, a->func, a->line, a->dma);
11183 +/* The replacement functions */
11184 +void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line)
11186 + void *addr = __DWC_ALLOC(mem_ctx, size);
11192 + if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
11193 + __DWC_FREE(mem_ctx, addr);
11200 +void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func,
11203 + void *addr = __DWC_ALLOC_ATOMIC(mem_ctx, size);
11209 + if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
11210 + __DWC_FREE(mem_ctx, addr);
11217 +void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line)
11219 + free_allocation(mem_ctx, addr, func, line);
11220 + __DWC_FREE(mem_ctx, addr);
11223 +void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
11224 + char const *func, int line)
11226 + void *addr = __DWC_DMA_ALLOC(dma_ctx, size, dma_addr);
11232 + if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
11233 + __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
11240 +void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size,
11241 + dwc_dma_t *dma_addr, char const *func, int line)
11243 + void *addr = __DWC_DMA_ALLOC_ATOMIC(dma_ctx, size, dma_addr);
11249 + if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
11250 + __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
11257 +void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
11258 + dwc_dma_t dma_addr, char const *func, int line)
11260 + free_allocation(dma_ctx, virt_addr, func, line);
11261 + __DWC_DMA_FREE(dma_ctx, size, virt_addr, dma_addr);
11264 +#endif /* DWC_DEBUG_MEMORY */
11265 diff --git a/drivers/usb/host/dwc_common_port/dwc_modpow.c b/drivers/usb/host/dwc_common_port/dwc_modpow.c
11266 new file mode 100644
11267 index 0000000..b7c456b
11269 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.c
11271 +/* Bignum routines adapted from PUTTY sources. PuTTY copyright notice follows.
11273 + * PuTTY is copyright 1997-2007 Simon Tatham.
11275 + * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
11276 + * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
11277 + * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
11278 + * Kuhn, and CORE SDI S.A.
11280 + * Permission is hereby granted, free of charge, to any person
11281 + * obtaining a copy of this software and associated documentation files
11282 + * (the "Software"), to deal in the Software without restriction,
11283 + * including without limitation the rights to use, copy, modify, merge,
11284 + * publish, distribute, sublicense, and/or sell copies of the Software,
11285 + * and to permit persons to whom the Software is furnished to do so,
11286 + * subject to the following conditions:
11288 + * The above copyright notice and this permission notice shall be
11289 + * included in all copies or substantial portions of the Software.
11291 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11292 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11293 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11294 + * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
11295 + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
11296 + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
11297 + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11300 +#ifdef DWC_CRYPTOLIB
11302 +#ifndef CONFIG_MACH_IPMATE
11304 +#include "dwc_modpow.h"
11306 +#define BIGNUM_INT_MASK 0xFFFFFFFFUL
11307 +#define BIGNUM_TOP_BIT 0x80000000UL
11308 +#define BIGNUM_INT_BITS 32
11311 +static void *snmalloc(void *mem_ctx, size_t n, size_t size)
11315 + if (size == 0) size = 1;
11316 + p = dwc_alloc(mem_ctx, size);
11320 +#define snewn(ctx, n, type) ((type *)snmalloc((ctx), (n), sizeof(type)))
11321 +#define sfree dwc_free
11325 + * * Do not call the DIVMOD_WORD macro with expressions such as array
11326 + * subscripts, as some implementations object to this (see below).
11327 + * * Note that none of the division methods below will cope if the
11328 + * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
11329 + * to avoid this case.
11330 + * If this condition occurs, in the case of the x86 DIV instruction,
11331 + * an overflow exception will occur, which (according to a correspondent)
11332 + * will manifest on Windows as something like
11333 + * 0xC0000095: Integer overflow
11334 + * The C variant won't give the right answer, either.
11337 +#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
11339 +#if defined __GNUC__ && defined __i386__
11340 +#define DIVMOD_WORD(q, r, hi, lo, w) \
11341 + __asm__("div %2" : \
11342 + "=d" (r), "=a" (q) : \
11343 + "r" (w), "d" (hi), "a" (lo))
11345 +#define DIVMOD_WORD(q, r, hi, lo, w) do { \
11346 + BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
11355 +#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
11357 +#define BIGNUM_INTERNAL
11359 +static Bignum newbn(void *mem_ctx, int length)
11361 + Bignum b = snewn(mem_ctx, length + 1, BignumInt);
11363 + //abort(); /* FIXME */
11364 + DWC_MEMSET(b, 0, (length + 1) * sizeof(*b));
11369 +void freebn(void *mem_ctx, Bignum b)
11372 + * Burn the evidence, just in case.
11374 + DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1));
11375 + sfree(mem_ctx, b);
11379 + * Compute c = a * b.
11380 + * Input is in the first len words of a and b.
11381 + * Result is returned in the first 2*len words of c.
11383 +static void internal_mul(BignumInt *a, BignumInt *b,
11384 + BignumInt *c, int len)
11389 + for (j = 0; j < 2 * len; j++)
11392 + for (i = len - 1; i >= 0; i--) {
11394 + for (j = len - 1; j >= 0; j--) {
11395 + t += MUL_WORD(a[i], (BignumDblInt) b[j]);
11396 + t += (BignumDblInt) c[i + j + 1];
11397 + c[i + j + 1] = (BignumInt) t;
11398 + t = t >> BIGNUM_INT_BITS;
11400 + c[i] = (BignumInt) t;
11404 +static void internal_add_shifted(BignumInt *number,
11405 + unsigned n, int shift)
11407 + int word = 1 + (shift / BIGNUM_INT_BITS);
11408 + int bshift = shift % BIGNUM_INT_BITS;
11409 + BignumDblInt addend;
11411 + addend = (BignumDblInt)n << bshift;
11414 + addend += number[word];
11415 + number[word] = (BignumInt) addend & BIGNUM_INT_MASK;
11416 + addend >>= BIGNUM_INT_BITS;
11422 + * Compute a = a % m.
11423 + * Input in first alen words of a and first mlen words of m.
11424 + * Output in first alen words of a
11425 + * (of which first alen-mlen words will be zero).
11426 + * The MSW of m MUST have its high bit set.
11427 + * Quotient is accumulated in the `quotient' array, which is a Bignum
11428 + * rather than the internal bigendian format. Quotient parts are shifted
11429 + * left by `qshift' before adding into quot.
11431 +static void internal_mod(BignumInt *a, int alen,
11432 + BignumInt *m, int mlen,
11433 + BignumInt *quot, int qshift)
11435 + BignumInt m0, m1;
11445 + for (i = 0; i <= alen - mlen; i++) {
11447 + unsigned int q, r, c, ai1;
11456 + if (i == alen - 1)
11461 + /* Find q = h:a[i] / m0 */
11466 + * To illustrate it, suppose a BignumInt is 8 bits, and
11467 + * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then
11468 + * our initial division will be 0xA123 / 0xA1, which
11469 + * will give a quotient of 0x100 and a divide overflow.
11470 + * However, the invariants in this division algorithm
11471 + * are not violated, since the full number A1:23:... is
11472 + * _less_ than the quotient prefix A1:B2:... and so the
11473 + * following correction loop would have sorted it out.
11475 + * In this situation we set q to be the largest
11476 + * quotient we _can_ stomach (0xFF, of course).
11478 + q = BIGNUM_INT_MASK;
11480 + /* Macro doesn't want an array subscript expression passed
11481 + * into it (see definition), so use a temporary. */
11482 + BignumInt tmplo = a[i];
11483 + DIVMOD_WORD(q, r, h, tmplo, m0);
11485 + /* Refine our estimate of q by looking at
11486 + h:a[i]:a[i+1] / m0:m1 */
11487 + t = MUL_WORD(m1, q);
11488 + if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
11491 + r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */
11492 + if (r >= (BignumDblInt) m0 &&
11493 + t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
11497 + /* Subtract q * m from a[i...] */
11499 + for (k = mlen - 1; k >= 0; k--) {
11500 + t = MUL_WORD(q, m[k]);
11502 + c = (unsigned)(t >> BIGNUM_INT_BITS);
11503 + if ((BignumInt) t > a[i + k])
11505 + a[i + k] -= (BignumInt) t;
11508 + /* Add back m in case of borrow */
11511 + for (k = mlen - 1; k >= 0; k--) {
11514 + a[i + k] = (BignumInt) t;
11515 + t = t >> BIGNUM_INT_BITS;
11520 + internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
11525 + * Compute p % mod.
11526 + * The most significant word of mod MUST be non-zero.
11527 + * We assume that the result array is the same size as the mod array.
11528 + * We optionally write out a quotient if `quotient' is non-NULL.
11529 + * We can avoid writing out the result if `result' is NULL.
11531 +void bigdivmod(void *mem_ctx, Bignum p, Bignum mod, Bignum result, Bignum quotient)
11533 + BignumInt *n, *m;
11535 + int plen, mlen, i, j;
11537 + /* Allocate m of size mlen, copy mod to m */
11538 + /* We use big endian internally */
11540 + m = snewn(mem_ctx, mlen, BignumInt);
11542 + //abort(); /* FIXME */
11543 + for (j = 0; j < mlen; j++)
11544 + m[j] = mod[mod[0] - j];
11546 + /* Shift m left to make msb bit set */
11547 + for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
11548 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
11551 + for (i = 0; i < mlen - 1; i++)
11552 + m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift));
11553 + m[mlen - 1] = m[mlen - 1] << mshift;
11557 + /* Ensure plen > mlen */
11558 + if (plen <= mlen)
11561 + /* Allocate n of size plen, copy p to n */
11562 + n = snewn(mem_ctx, plen, BignumInt);
11564 + //abort(); /* FIXME */
11565 + for (j = 0; j < plen; j++)
11567 + for (j = 1; j <= (int)p[0]; j++)
11568 + n[plen - j] = p[j];
11570 + /* Main computation */
11571 + internal_mod(n, plen, m, mlen, quotient, mshift);
11573 + /* Fixup result in case the modulus was shifted */
11575 + for (i = plen - mlen - 1; i < plen - 1; i++)
11576 + n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift));
11577 + n[plen - 1] = n[plen - 1] << mshift;
11578 + internal_mod(n, plen, m, mlen, quotient, 0);
11579 + for (i = plen - 1; i >= plen - mlen; i--)
11580 + n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift));
11583 + /* Copy result to buffer */
11585 + for (i = 1; i <= (int)result[0]; i++) {
11586 + int j = plen - i;
11587 + result[i] = j >= 0 ? n[j] : 0;
11591 + /* Free temporary arrays */
11592 + for (i = 0; i < mlen; i++)
11594 + sfree(mem_ctx, m);
11595 + for (i = 0; i < plen; i++)
11597 + sfree(mem_ctx, n);
11601 + * Simple remainder.
11603 +Bignum bigmod(void *mem_ctx, Bignum a, Bignum b)
11605 + Bignum r = newbn(mem_ctx, b[0]);
11606 + bigdivmod(mem_ctx, a, b, r, NULL);
11611 + * Compute (base ^ exp) % mod.
11613 +Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod)
11615 + BignumInt *a, *b, *n, *m;
11618 + Bignum base, result;
11621 + * The most significant word of mod needs to be non-zero. It
11622 + * should already be, but let's make sure.
11624 + //assert(mod[mod[0]] != 0);
11627 + * Make sure the base is smaller than the modulus, by reducing
11628 + * it modulo the modulus if not.
11630 + base = bigmod(mem_ctx, base_in, mod);
11632 + /* Allocate m of size mlen, copy mod to m */
11633 + /* We use big endian internally */
11635 + m = snewn(mem_ctx, mlen, BignumInt);
11637 + //abort(); /* FIXME */
11638 + for (j = 0; j < mlen; j++)
11639 + m[j] = mod[mod[0] - j];
11641 + /* Shift m left to make msb bit set */
11642 + for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
11643 + if ((m[0] << mshift) & BIGNUM_TOP_BIT)
11646 + for (i = 0; i < mlen - 1; i++)
11648 + (m[i] << mshift) | (m[i + 1] >>
11649 + (BIGNUM_INT_BITS - mshift));
11650 + m[mlen - 1] = m[mlen - 1] << mshift;
11653 + /* Allocate n of size mlen, copy base to n */
11654 + n = snewn(mem_ctx, mlen, BignumInt);
11656 + //abort(); /* FIXME */
11657 + i = mlen - base[0];
11658 + for (j = 0; j < i; j++)
11660 + for (j = 0; j < base[0]; j++)
11661 + n[i + j] = base[base[0] - j];
11663 + /* Allocate a and b of size 2*mlen. Set a = 1 */
11664 + a = snewn(mem_ctx, 2 * mlen, BignumInt);
11666 + //abort(); /* FIXME */
11667 + b = snewn(mem_ctx, 2 * mlen, BignumInt);
11669 + //abort(); /* FIXME */
11670 + for (i = 0; i < 2 * mlen; i++)
11672 + a[2 * mlen - 1] = 1;
11674 + /* Skip leading zero bits of exp. */
11676 + j = BIGNUM_INT_BITS - 1;
11677 + while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
11681 + j = BIGNUM_INT_BITS - 1;
11685 + /* Main computation */
11686 + while (i < exp[0]) {
11688 + internal_mul(a + mlen, a + mlen, b, mlen);
11689 + internal_mod(b, mlen * 2, m, mlen, NULL, 0);
11690 + if ((exp[exp[0] - i] & (1 << j)) != 0) {
11691 + internal_mul(b + mlen, n, a, mlen);
11692 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
11702 + j = BIGNUM_INT_BITS - 1;
11705 + /* Fixup result in case the modulus was shifted */
11707 + for (i = mlen - 1; i < 2 * mlen - 1; i++)
11709 + (a[i] << mshift) | (a[i + 1] >>
11710 + (BIGNUM_INT_BITS - mshift));
11711 + a[2 * mlen - 1] = a[2 * mlen - 1] << mshift;
11712 + internal_mod(a, mlen * 2, m, mlen, NULL, 0);
11713 + for (i = 2 * mlen - 1; i >= mlen; i--)
11715 + (a[i] >> mshift) | (a[i - 1] <<
11716 + (BIGNUM_INT_BITS - mshift));
11719 + /* Copy result to buffer */
11720 + result = newbn(mem_ctx, mod[0]);
11721 + for (i = 0; i < mlen; i++)
11722 + result[result[0] - i] = a[i + mlen];
11723 + while (result[0] > 1 && result[result[0]] == 0)
11726 + /* Free temporary arrays */
11727 + for (i = 0; i < 2 * mlen; i++)
11729 + sfree(mem_ctx, a);
11730 + for (i = 0; i < 2 * mlen; i++)
11732 + sfree(mem_ctx, b);
11733 + for (i = 0; i < mlen; i++)
11735 + sfree(mem_ctx, m);
11736 + for (i = 0; i < mlen; i++)
11738 + sfree(mem_ctx, n);
11740 + freebn(mem_ctx, base);
11748 +static __u32 dh_p[] = {
11848 +static __u32 dh_a[] = {
11860 +static __u32 dh_b[] = {
11872 +static __u32 dh_g[] = {
11881 + k = dwc_modpow(NULL, dh_g, dh_a, dh_p);
11884 + for (i=0; i<k[0]; i++) {
11885 + __u32 word32 = k[k[0] - i];
11886 + __u16 l = word32 & 0xffff;
11887 + __u16 m = (word32 & 0xffff0000) >> 16;
11888 + printf("%04x %04x ", m, l);
11889 + if (!((i + 1)%13)) printf("\n");
11893 + if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) {
11894 + printf("PASS\n\n");
11897 + printf("FAIL\n\n");
11902 +#endif /* UNITTEST */
11904 +#endif /* CONFIG_MACH_IPMATE */
11906 +#endif /*DWC_CRYPTOLIB */
11907 diff --git a/drivers/usb/host/dwc_common_port/dwc_modpow.h b/drivers/usb/host/dwc_common_port/dwc_modpow.h
11908 new file mode 100644
11909 index 0000000..64f00c2
11911 +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.h
11915 + * See dwc_modpow.c for license and changes
11917 +#ifndef _DWC_MODPOW_H
11918 +#define _DWC_MODPOW_H
11920 +#ifdef __cplusplus
11924 +#include "dwc_os.h"
11928 + * This file defines the module exponentiation function which is only used
11929 + * internally by the DWC UWB modules for calculation of PKs during numeric
11930 + * association. The routine is taken from the PUTTY, an open source terminal
11931 + * emulator. The PUTTY License is preserved in the dwc_modpow.c file.
11935 +typedef uint32_t BignumInt;
11936 +typedef uint64_t BignumDblInt;
11937 +typedef BignumInt *Bignum;
11939 +/* Compute modular exponentiaion */
11940 +extern Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod);
11942 +#ifdef __cplusplus
11946 +#endif /* _LINUX_BIGNUM_H */
11947 diff --git a/drivers/usb/host/dwc_common_port/dwc_notifier.c b/drivers/usb/host/dwc_common_port/dwc_notifier.c
11948 new file mode 100644
11949 index 0000000..8b3772a
11951 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.c
11953 +#ifdef DWC_NOTIFYLIB
11955 +#include "dwc_notifier.h"
11956 +#include "dwc_list.h"
11958 +typedef struct dwc_observer {
11960 + dwc_notifier_callback_t callback;
11962 + char *notification;
11963 + DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
11966 +DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
11968 +typedef struct dwc_notifier {
11971 + struct observer_queue observers;
11972 + DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
11975 +DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
11977 +typedef struct manager {
11981 +// dwc_mutex_t *mutex;
11982 + struct notifier_queue notifiers;
11985 +static manager_t *manager = NULL;
11987 +static int create_manager(void *mem_ctx, void *wkq_ctx)
11989 + manager = dwc_alloc(mem_ctx, sizeof(manager_t));
11991 + return -DWC_E_NO_MEMORY;
11994 + DWC_CIRCLEQ_INIT(&manager->notifiers);
11996 + manager->wq = dwc_workq_alloc(wkq_ctx, "DWC Notification WorkQ");
11997 + if (!manager->wq) {
11998 + return -DWC_E_NO_MEMORY;
12004 +static void free_manager(void)
12006 + dwc_workq_free(manager->wq);
12008 + /* All notifiers must have unregistered themselves before this module
12009 + * can be removed. Hitting this assertion indicates a programmer
12011 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers),
12012 + "Notification manager being freed before all notifiers have been removed");
12013 + dwc_free(manager->mem_ctx, manager);
12017 +static void dump_manager(void)
12022 + DWC_ASSERT(manager, "Notification manager not found");
12024 + DWC_DEBUG("List of all notifiers and observers:\n");
12025 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
12026 + DWC_DEBUG("Notifier %p has observers:\n", n->object);
12027 + DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
12028 + DWC_DEBUG(" %p watching %s\n", o->observer, o->notification);
12033 +#define dump_manager(...)
12036 +static observer_t *alloc_observer(void *mem_ctx, void *observer, char *notification,
12037 + dwc_notifier_callback_t callback, void *data)
12039 + observer_t *new_observer = dwc_alloc(mem_ctx, sizeof(observer_t));
12041 + if (!new_observer) {
12045 + DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
12046 + new_observer->observer = observer;
12047 + new_observer->notification = notification;
12048 + new_observer->callback = callback;
12049 + new_observer->data = data;
12050 + return new_observer;
12053 +static void free_observer(void *mem_ctx, observer_t *observer)
12055 + dwc_free(mem_ctx, observer);
12058 +static notifier_t *alloc_notifier(void *mem_ctx, void *object)
12060 + notifier_t *notifier;
12066 + notifier = dwc_alloc(mem_ctx, sizeof(notifier_t));
12071 + DWC_CIRCLEQ_INIT(¬ifier->observers);
12072 + DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
12074 + notifier->mem_ctx = mem_ctx;
12075 + notifier->object = object;
12079 +static void free_notifier(notifier_t *notifier)
12081 + observer_t *observer;
12083 + DWC_CIRCLEQ_FOREACH(observer, ¬ifier->observers, list_entry) {
12084 + free_observer(notifier->mem_ctx, observer);
12087 + dwc_free(notifier->mem_ctx, notifier);
12090 +static notifier_t *find_notifier(void *object)
12092 + notifier_t *notifier;
12094 + DWC_ASSERT(manager, "Notification manager not found");
12100 + DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
12101 + if (notifier->object == object) {
12109 +int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx)
12111 + return create_manager(mem_ctx, wkq_ctx);
12114 +void dwc_free_notification_manager(void)
12119 +dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object)
12121 + notifier_t *notifier;
12123 + DWC_ASSERT(manager, "Notification manager not found");
12125 + notifier = find_notifier(object);
12127 + DWC_ERROR("Notifier %p is already registered\n", object);
12131 + notifier = alloc_notifier(mem_ctx, object);
12136 + DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
12138 + DWC_INFO("Notifier %p registered", object);
12144 +void dwc_unregister_notifier(dwc_notifier_t *notifier)
12146 + DWC_ASSERT(manager, "Notification manager not found");
12148 + if (!DWC_CIRCLEQ_EMPTY(¬ifier->observers)) {
12151 + DWC_ERROR("Notifier %p has active observers when removing\n", notifier->object);
12152 + DWC_CIRCLEQ_FOREACH(o, ¬ifier->observers, list_entry) {
12153 + DWC_DEBUGC(" %p watching %s\n", o->observer, o->notification);
12156 + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(¬ifier->observers),
12157 + "Notifier %p has active observers when removing", notifier);
12160 + DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
12161 + free_notifier(notifier);
12163 + DWC_INFO("Notifier unregistered");
12167 +/* Add an observer to observe the notifier for a particular state, event, or notification. */
12168 +int dwc_add_observer(void *observer, void *object, char *notification,
12169 + dwc_notifier_callback_t callback, void *data)
12171 + notifier_t *notifier = find_notifier(object);
12172 + observer_t *new_observer;
12175 + DWC_ERROR("Notifier %p is not found when adding observer\n", object);
12176 + return -DWC_E_INVALID;
12179 + new_observer = alloc_observer(notifier->mem_ctx, observer, notification, callback, data);
12180 + if (!new_observer) {
12181 + return -DWC_E_NO_MEMORY;
12184 + DWC_CIRCLEQ_INSERT_TAIL(¬ifier->observers, new_observer, list_entry);
12186 + DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
12187 + observer, object, notification, callback, data);
12193 +int dwc_remove_observer(void *observer)
12197 + DWC_ASSERT(manager, "Notification manager not found");
12199 + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
12203 + DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
12204 + if (o->observer == observer) {
12205 + DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
12206 + DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
12207 + o->observer, n->object, o->notification);
12208 + free_observer(n->mem_ctx, o);
12217 +typedef struct callback_data {
12219 + dwc_notifier_callback_t cb;
12223 + char *notification;
12224 + void *notification_data;
12227 +static void cb_task(void *data)
12229 + cb_data_t *cb = (cb_data_t *)data;
12231 + cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
12232 + dwc_free(cb->mem_ctx, cb);
12235 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
12239 + DWC_ASSERT(manager, "Notification manager not found");
12241 + DWC_CIRCLEQ_FOREACH(o, ¬ifier->observers, list_entry) {
12242 + int len = DWC_STRLEN(notification);
12244 + if (DWC_STRLEN(o->notification) != len) {
12248 + if (DWC_STRNCMP(o->notification, notification, len) == 0) {
12249 + cb_data_t *cb_data = dwc_alloc(notifier->mem_ctx, sizeof(cb_data_t));
12252 + DWC_ERROR("Failed to allocate callback data\n");
12256 + cb_data->mem_ctx = notifier->mem_ctx;
12257 + cb_data->cb = o->callback;
12258 + cb_data->observer = o->observer;
12259 + cb_data->data = o->data;
12260 + cb_data->object = notifier->object;
12261 + cb_data->notification = notification;
12262 + cb_data->notification_data = notification_data;
12263 + DWC_DEBUGC("Observer found %p for notification %s\n", o->observer, notification);
12264 + DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
12265 + "Notify callback from %p for Notification %s, to observer %p",
12266 + cb_data->object, notification, cb_data->observer);
12271 +#endif /* DWC_NOTIFYLIB */
12272 diff --git a/drivers/usb/host/dwc_common_port/dwc_notifier.h b/drivers/usb/host/dwc_common_port/dwc_notifier.h
12273 new file mode 100644
12274 index 0000000..4a8cdfe
12276 +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.h
12279 +#ifndef __DWC_NOTIFIER_H__
12280 +#define __DWC_NOTIFIER_H__
12282 +#ifdef __cplusplus
12286 +#include "dwc_os.h"
12290 + * A simple implementation of the Observer pattern. Any "module" can
12291 + * register as an observer or notifier. The notion of "module" is abstract and
12292 + * can mean anything used to identify either an observer or notifier. Usually
12293 + * it will be a pointer to a data structure which contains some state, ie an
12296 + * Before any notifiers can be added, the global notification manager must be
12297 + * brought up with dwc_alloc_notification_manager().
12298 + * dwc_free_notification_manager() will bring it down and free all resources.
12299 + * These would typically be called upon module load and unload. The
12300 + * notification manager is a single global instance that handles all registered
12301 + * observable modules and observers so this should be done only once.
12303 + * A module can be observable by using Notifications to publicize some general
12304 + * information about it's state or operation. It does not care who listens, or
12305 + * even if anyone listens, or what they do with the information. The observable
12306 + * modules do not need to know any information about it's observers or their
12307 + * interface, or their state or data.
12309 + * Any module can register to emit Notifications. It should publish a list of
12310 + * notifications that it can emit and their behavior, such as when they will get
12311 + * triggered, and what information will be provided to the observer. Then it
12312 + * should register itself as an observable module. See dwc_register_notifier().
12314 + * Any module can observe any observable, registered module, provided it has a
12315 + * handle to the other module and knows what notifications to observe. See
12316 + * dwc_add_observer().
12318 + * A function of type dwc_notifier_callback_t is called whenever a notification
12319 + * is triggered with one or more observers observing it. This function is
12320 + * called in it's own process so it may sleep or block if needed. It is
12321 + * guaranteed to be called sometime after the notification has occurred and will
12322 + * be called once per each time the notification is triggered. It will NOT be
12323 + * called in the same process context used to trigger the notification.
12325 + * @section Limitiations
12327 + * Keep in mind that Notifications that can be triggered in rapid sucession may
12328 + * schedule too many processes too handle. Be aware of this limitation when
12329 + * designing to use notifications, and only add notifications for appropriate
12330 + * observable information.
12332 + * Also Notification callbacks are not synchronous. If you need to synchronize
12333 + * the behavior between module/observer you must use other means. And perhaps
12334 + * that will mean Notifications are not the proper solution.
12337 +struct dwc_notifier;
12338 +typedef struct dwc_notifier dwc_notifier_t;
12340 +/** The callback function must be of this type.
12342 + * @param object This is the object that is being observed.
12343 + * @param notification This is the notification that was triggered.
12344 + * @param observer This is the observer
12345 + * @param notification_data This is notification-specific data that the notifier
12346 + * has included in this notification. The value of this should be published in
12347 + * the documentation of the observable module with the notifications.
12348 + * @param user_data This is any custom data that the observer provided when
12349 + * adding itself as an observer to the notification. */
12350 +typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer,
12351 + void *notification_data, void *user_data);
12353 +/** Brings up the notification manager. */
12354 +extern int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx);
12355 +/** Brings down the notification manager. */
12356 +extern void dwc_free_notification_manager(void);
12358 +/** This function registers an observable module. A dwc_notifier_t object is
12359 + * returned to the observable module. This is an opaque object that is used by
12360 + * the observable module to trigger notifications. This object should only be
12361 + * accessible to functions that are authorized to trigger notifications for this
12362 + * module. Observers do not need this object. */
12363 +extern dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object);
12365 +/** This function unregisters an observable module. All observers have to be
12366 + * removed prior to unregistration. */
12367 +extern void dwc_unregister_notifier(dwc_notifier_t *notifier);
12369 +/** Add a module as an observer to the observable module. The observable module
12370 + * needs to have previously registered with the notification manager.
12372 + * @param observer The observer module
12373 + * @param object The module to observe
12374 + * @param notification The notification to observe
12375 + * @param callback The callback function to call
12376 + * @param user_data Any additional user data to pass into the callback function */
12377 +extern int dwc_add_observer(void *observer, void *object, char *notification,
12378 + dwc_notifier_callback_t callback, void *user_data);
12380 +/** Removes the specified observer from all notifications that it is currently
12382 +extern int dwc_remove_observer(void *observer);
12384 +/** This function triggers a Notification. It should be called by the
12385 + * observable module, or any module or library which the observable module
12386 + * allows to trigger notification on it's behalf. Such as the dwc_cc_t.
12388 + * dwc_notify is a non-blocking function. Callbacks are scheduled called in
12389 + * their own process context for each trigger. Callbacks can be blocking.
12390 + * dwc_notify can be called from interrupt context if needed.
12393 +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data);
12395 +#ifdef __cplusplus
12399 +#endif /* __DWC_NOTIFIER_H__ */
12400 diff --git a/drivers/usb/host/dwc_common_port/dwc_os.h b/drivers/usb/host/dwc_common_port/dwc_os.h
12401 new file mode 100644
12402 index 0000000..308ddd5
12404 +++ b/drivers/usb/host/dwc_common_port/dwc_os.h
12406 +/* =========================================================================
12407 + * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_os.h $
12408 + * $Revision: #14 $
12409 + * $Date: 2010/11/04 $
12410 + * $Change: 1621695 $
12412 + * Synopsys Portability Library Software and documentation
12413 + * (hereinafter, "Software") is an Unsupported proprietary work of
12414 + * Synopsys, Inc. unless otherwise expressly agreed to in writing
12415 + * between Synopsys and you.
12417 + * The Software IS NOT an item of Licensed Software or Licensed Product
12418 + * under any End User Software License Agreement or Agreement for
12419 + * Licensed Product with Synopsys or any supplement thereto. You are
12420 + * permitted to use and redistribute this Software in source and binary
12421 + * forms, with or without modification, provided that redistributions
12422 + * of source code must retain this notice. You may not view, use,
12423 + * disclose, copy or distribute this file or any information contained
12424 + * herein except pursuant to this license grant from Synopsys. If you
12425 + * do not agree with this notice, including the disclaimer below, then
12426 + * you are not authorized to use the Software.
12428 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
12429 + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
12430 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12431 + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
12432 + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
12433 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
12434 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
12435 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
12436 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12437 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
12438 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
12440 + * ========================================================================= */
12441 +#ifndef _DWC_OS_H_
12442 +#define _DWC_OS_H_
12444 +#ifdef __cplusplus
12450 + * DWC portability library, low level os-wrapper functions
12454 +/* These basic types need to be defined by some OS header file or custom header
12455 + * file for your specific target architecture.
12457 + * uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
12459 + * Any custom or alternate header file must be added and enabled here.
12463 +# include <linux/types.h>
12464 +# ifdef CONFIG_DEBUG_MUTEXES
12465 +# include <linux/mutex.h>
12467 +# include <linux/errno.h>
12468 +# include <stdarg.h>
12471 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12472 +# include <os_dep.h>
12476 +/** @name Primitive Types and Values */
12478 +/** We define a boolean type for consistency. Can be either YES or NO */
12479 +typedef uint8_t dwc_bool_t;
12485 +/** @name Error Codes */
12486 +#define DWC_E_INVALID EINVAL
12487 +#define DWC_E_NO_MEMORY ENOMEM
12488 +#define DWC_E_NO_DEVICE ENODEV
12489 +#define DWC_E_NOT_SUPPORTED EOPNOTSUPP
12490 +#define DWC_E_TIMEOUT ETIMEDOUT
12491 +#define DWC_E_BUSY EBUSY
12492 +#define DWC_E_AGAIN EAGAIN
12493 +#define DWC_E_RESTART ERESTART
12494 +#define DWC_E_ABORT ECONNABORTED
12495 +#define DWC_E_SHUTDOWN ESHUTDOWN
12496 +#define DWC_E_NO_DATA ENODATA
12497 +#define DWC_E_DISCONNECT ECONNRESET
12498 +#define DWC_E_UNKNOWN EINVAL
12499 +#define DWC_E_NO_STREAM_RES ENOSR
12500 +#define DWC_E_COMMUNICATION ECOMM
12501 +#define DWC_E_OVERFLOW EOVERFLOW
12502 +#define DWC_E_PROTOCOL EPROTO
12503 +#define DWC_E_IN_PROGRESS EINPROGRESS
12504 +#define DWC_E_PIPE EPIPE
12505 +#define DWC_E_IO EIO
12506 +#define DWC_E_NO_SPACE ENOSPC
12510 +/** @name Error Codes */
12511 +#define DWC_E_INVALID 1001
12512 +#define DWC_E_NO_MEMORY 1002
12513 +#define DWC_E_NO_DEVICE 1003
12514 +#define DWC_E_NOT_SUPPORTED 1004
12515 +#define DWC_E_TIMEOUT 1005
12516 +#define DWC_E_BUSY 1006
12517 +#define DWC_E_AGAIN 1007
12518 +#define DWC_E_RESTART 1008
12519 +#define DWC_E_ABORT 1009
12520 +#define DWC_E_SHUTDOWN 1010
12521 +#define DWC_E_NO_DATA 1011
12522 +#define DWC_E_DISCONNECT 2000
12523 +#define DWC_E_UNKNOWN 3000
12524 +#define DWC_E_NO_STREAM_RES 4001
12525 +#define DWC_E_COMMUNICATION 4002
12526 +#define DWC_E_OVERFLOW 4003
12527 +#define DWC_E_PROTOCOL 4004
12528 +#define DWC_E_IN_PROGRESS 4005
12529 +#define DWC_E_PIPE 4006
12530 +#define DWC_E_IO 4007
12531 +#define DWC_E_NO_SPACE 4008
12536 +/** @name Tracing/Logging Functions
12538 + * These function provide the capability to add tracing, debugging, and error
12539 + * messages, as well exceptions as assertions. The WUDEV uses these
12540 + * extensively. These could be logged to the main console, the serial port, an
12541 + * internal buffer, etc. These functions could also be no-op if they are too
12542 + * expensive on your system. By default undefining the DEBUG macro already
12543 + * no-ops some of these functions. */
12545 +/** Returns non-zero if in interrupt context. */
12546 +extern dwc_bool_t DWC_IN_IRQ(void);
12547 +#define dwc_in_irq DWC_IN_IRQ
12549 +/** Returns "IRQ" if DWC_IN_IRQ is true. */
12550 +static inline char *dwc_irq(void) {
12551 + return DWC_IN_IRQ() ? "IRQ" : "";
12554 +/** Returns non-zero if in bottom-half context. */
12555 +extern dwc_bool_t DWC_IN_BH(void);
12556 +#define dwc_in_bh DWC_IN_BH
12558 +/** Returns "BH" if DWC_IN_BH is true. */
12559 +static inline char *dwc_bh(void) {
12560 + return DWC_IN_BH() ? "BH" : "";
12564 + * A vprintf() clone. Just call vprintf if you've got it.
12566 +extern void DWC_VPRINTF(char *format, va_list args);
12567 +#define dwc_vprintf DWC_VPRINTF
12570 + * A vsnprintf() clone. Just call vprintf if you've got it.
12572 +extern int DWC_VSNPRINTF(char *str, int size, char *format, va_list args);
12573 +#define dwc_vsnprintf DWC_VSNPRINTF
12576 + * printf() clone. Just call printf if you've go it.
12578 +extern void DWC_PRINTF(char *format, ...)
12579 +/* This provides compiler level static checking of the parameters if you're
12582 + __attribute__ ((format(printf, 1, 2)));
12586 +#define dwc_printf DWC_PRINTF
12589 + * sprintf() clone. Just call sprintf if you've got it.
12591 +extern int DWC_SPRINTF(char *string, char *format, ...)
12593 + __attribute__ ((format(printf, 2, 3)));
12597 +#define dwc_sprintf DWC_SPRINTF
12600 + * snprintf() clone. Just call snprintf if you've got it.
12602 +extern int DWC_SNPRINTF(char *string, int size, char *format, ...)
12604 + __attribute__ ((format(printf, 3, 4)));
12608 +#define dwc_snprintf DWC_SNPRINTF
12611 + * Prints a WARNING message. On systems that don't differentiate between
12612 + * warnings and regular log messages, just print it. Indicates that something
12613 + * may be wrong with the driver. Works like printf().
12615 + * Use the DWC_WARN macro to call this function.
12617 +extern void __DWC_WARN(char *format, ...)
12619 + __attribute__ ((format(printf, 1, 2)));
12625 + * Prints an error message. On systems that don't differentiate between errors
12626 + * and regular log messages, just print it. Indicates that something went wrong
12627 + * with the driver. Works like printf().
12629 + * Use the DWC_ERROR macro to call this function.
12631 +extern void __DWC_ERROR(char *format, ...)
12633 + __attribute__ ((format(printf, 1, 2)));
12639 + * Prints an exception error message and takes some user-defined action such as
12640 + * print out a backtrace or trigger a breakpoint. Indicates that something went
12641 + * abnormally wrong with the driver such as programmer error, or other
12642 + * exceptional condition. It should not be ignored so even on systems without
12643 + * printing capability, some action should be taken to notify the developer of
12644 + * it. Works like printf().
12646 +extern void DWC_EXCEPTION(char *format, ...)
12648 + __attribute__ ((format(printf, 1, 2)));
12652 +#define dwc_exception DWC_EXCEPTION
12654 +#ifndef DWC_OTG_DEBUG_LEV
12655 +#define DWC_OTG_DEBUG_LEV 0
12660 + * Prints out a debug message. Used for logging/trace messages.
12662 + * Use the DWC_DEBUG macro to call this function
12664 +extern void __DWC_DEBUG(char *format, ...)
12666 + __attribute__ ((format(printf, 1, 2)));
12671 +#define __DWC_DEBUG printk
12675 + * Prints out a Debug message.
12677 +#define DWC_DEBUG(_format, _args...) __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", \
12678 + __func__, dwc_irq(), ## _args)
12679 +#define dwc_debug DWC_DEBUG
12681 + * Prints out a Debug message if enabled at compile time.
12683 +#if DWC_OTG_DEBUG_LEV > 0
12684 +#define DWC_DEBUGC(_format, _args...) DWC_DEBUG(_format, ##_args )
12686 +#define DWC_DEBUGC(_format, _args...)
12688 +#define dwc_debugc DWC_DEBUGC
12690 + * Prints out an informative message.
12692 +#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", \
12693 + dwc_irq(), ## _args)
12694 +#define dwc_info DWC_INFO
12696 + * Prints out an informative message if enabled at compile time.
12698 +#if DWC_OTG_DEBUG_LEV > 1
12699 +#define DWC_INFOC(_format, _args...) DWC_INFO(_format, ##_args )
12701 +#define DWC_INFOC(_format, _args...)
12703 +#define dwc_infoc DWC_INFOC
12705 + * Prints out a warning message.
12707 +#define DWC_WARN(_format, _args...) __DWC_WARN("WARN:%s:%s:%d: " _format "\n", \
12708 + dwc_irq(), __func__, __LINE__, ## _args)
12709 +#define dwc_warn DWC_WARN
12711 + * Prints out an error message.
12713 +#define DWC_ERROR(_format, _args...) __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", \
12714 + dwc_irq(), __func__, __LINE__, ## _args)
12715 +#define dwc_error DWC_ERROR
12717 +#define DWC_PROTO_ERROR(_format, _args...) __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", \
12718 + dwc_irq(), __func__, __LINE__, ## _args)
12719 +#define dwc_proto_error DWC_PROTO_ERROR
12722 +/** Prints out a exception error message if the _expr expression fails. Disabled
12723 + * if DEBUG is not enabled. */
12724 +#define DWC_ASSERT(_expr, _format, _args...) do { \
12725 + if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), \
12726 + __FILE__, __LINE__, ## _args); } \
12729 +#define DWC_ASSERT(_x...)
12731 +#define dwc_assert DWC_ASSERT
12734 +/** @name Byte Ordering
12735 + * The following functions are for conversions between processor's byte ordering
12736 + * and specific ordering you want.
12739 +/** Converts 32 bit data in CPU byte ordering to little endian. */
12740 +extern uint32_t DWC_CPU_TO_LE32(uint32_t *p);
12741 +#define dwc_cpu_to_le32 DWC_CPU_TO_LE32
12743 +/** Converts 32 bit data in CPU byte orderint to big endian. */
12744 +extern uint32_t DWC_CPU_TO_BE32(uint32_t *p);
12745 +#define dwc_cpu_to_be32 DWC_CPU_TO_BE32
12747 +/** Converts 32 bit little endian data to CPU byte ordering. */
12748 +extern uint32_t DWC_LE32_TO_CPU(uint32_t *p);
12749 +#define dwc_le32_to_cpu DWC_LE32_TO_CPU
12751 +/** Converts 32 bit big endian data to CPU byte ordering. */
12752 +extern uint32_t DWC_BE32_TO_CPU(uint32_t *p);
12753 +#define dwc_be32_to_cpu DWC_BE32_TO_CPU
12755 +/** Converts 16 bit data in CPU byte ordering to little endian. */
12756 +extern uint16_t DWC_CPU_TO_LE16(uint16_t *p);
12757 +#define dwc_cpu_to_le16 DWC_CPU_TO_LE16
12759 +/** Converts 16 bit data in CPU byte orderint to big endian. */
12760 +extern uint16_t DWC_CPU_TO_BE16(uint16_t *p);
12761 +#define dwc_cpu_to_be16 DWC_CPU_TO_BE16
12763 +/** Converts 16 bit little endian data to CPU byte ordering. */
12764 +extern uint16_t DWC_LE16_TO_CPU(uint16_t *p);
12765 +#define dwc_le16_to_cpu DWC_LE16_TO_CPU
12767 +/** Converts 16 bit bi endian data to CPU byte ordering. */
12768 +extern uint16_t DWC_BE16_TO_CPU(uint16_t *p);
12769 +#define dwc_be16_to_cpu DWC_BE16_TO_CPU
12772 +/** @name Register Read/Write
12774 + * The following six functions should be implemented to read/write registers of
12775 + * 32-bit and 64-bit sizes. All modules use this to read/write register values.
12776 + * The reg value is a pointer to the register calculated from the void *base
12777 + * variable passed into the driver when it is started. */
12780 +/* Linux doesn't need any extra parameters for register read/write, so we
12781 + * just throw away the IO context parameter.
12783 +/** Reads the content of a 32-bit register. */
12784 +extern uint32_t DWC_READ_REG32(uint32_t volatile *reg);
12785 +#define dwc_read_reg32(_ctx_,_reg_) DWC_READ_REG32(_reg_)
12787 +/** Reads the content of a 64-bit register. */
12788 +extern uint64_t DWC_READ_REG64(uint64_t volatile *reg);
12789 +#define dwc_read_reg64(_ctx_,_reg_) DWC_READ_REG64(_reg_)
12791 +/** Writes to a 32-bit register. */
12792 +extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value);
12793 +#define dwc_write_reg32(_ctx_,_reg_,_val_) DWC_WRITE_REG32(_reg_, _val_)
12795 +/** Writes to a 64-bit register. */
12796 +extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value);
12797 +#define dwc_write_reg64(_ctx_,_reg_,_val_) DWC_WRITE_REG64(_reg_, _val_)
12800 + * Modify bit values in a register. Using the
12801 + * algorithm: (reg_contents & ~clear_mask) | set_mask.
12803 +extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
12804 +#define dwc_modify_reg32(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG32(_reg_,_cmsk_,_smsk_)
12805 +extern void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
12806 +#define dwc_modify_reg64(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG64(_reg_,_cmsk_,_smsk_)
12808 +#endif /* DWC_LINUX */
12810 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12811 +typedef struct dwc_ioctx {
12812 + struct device *dev;
12813 + bus_space_tag_t iot;
12814 + bus_space_handle_t ioh;
12817 +/** BSD needs two extra parameters for register read/write, so we pass
12818 + * them in using the IO context parameter.
12820 +/** Reads the content of a 32-bit register. */
12821 +extern uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg);
12822 +#define dwc_read_reg32 DWC_READ_REG32
12824 +/** Reads the content of a 64-bit register. */
12825 +extern uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg);
12826 +#define dwc_read_reg64 DWC_READ_REG64
12828 +/** Writes to a 32-bit register. */
12829 +extern void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value);
12830 +#define dwc_write_reg32 DWC_WRITE_REG32
12832 +/** Writes to a 64-bit register. */
12833 +extern void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value);
12834 +#define dwc_write_reg64 DWC_WRITE_REG64
12837 + * Modify bit values in a register. Using the
12838 + * algorithm: (reg_contents & ~clear_mask) | set_mask.
12840 +extern void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
12841 +#define dwc_modify_reg32 DWC_MODIFY_REG32
12842 +extern void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
12843 +#define dwc_modify_reg64 DWC_MODIFY_REG64
12845 +#endif /* DWC_FREEBSD || DWC_NETBSD */
12849 +/** @name Some convenience MACROS used internally. Define DWC_DEBUG_REGS to log the
12850 + * register writes. */
12854 +# ifdef DWC_DEBUG_REGS
12856 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12857 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
12858 + return DWC_READ_REG32(&container->regs->_reg[num]); \
12860 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
12861 + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
12862 + &(((uint32_t*)container->regs->_reg)[num]), data); \
12863 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
12866 +#define dwc_define_read_write_reg(_reg,_container_type) \
12867 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
12868 + return DWC_READ_REG32(&container->regs->_reg); \
12870 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
12871 + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
12872 + DWC_WRITE_REG32(&container->regs->_reg, data); \
12875 +# else /* DWC_DEBUG_REGS */
12877 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12878 +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
12879 + return DWC_READ_REG32(&container->regs->_reg[num]); \
12881 +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
12882 + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
12885 +#define dwc_define_read_write_reg(_reg,_container_type) \
12886 +static inline uint32_t dwc_read_##_reg(_container_type *container) { \
12887 + return DWC_READ_REG32(&container->regs->_reg); \
12889 +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
12890 + DWC_WRITE_REG32(&container->regs->_reg, data); \
12893 +# endif /* DWC_DEBUG_REGS */
12895 +#endif /* DWC_LINUX */
12897 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12899 +# ifdef DWC_DEBUG_REGS
12901 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12902 +static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
12903 + return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
12905 +static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
12906 + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
12907 + &(((uint32_t*)container->regs->_reg)[num]), data); \
12908 + DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
12911 +#define dwc_define_read_write_reg(_reg,_container_type) \
12912 +static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
12913 + return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
12915 +static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
12916 + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
12917 + DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
12920 +# else /* DWC_DEBUG_REGS */
12922 +#define dwc_define_read_write_reg_n(_reg,_container_type) \
12923 +static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
12924 + return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
12926 +static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
12927 + DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
12930 +#define dwc_define_read_write_reg(_reg,_container_type) \
12931 +static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
12932 + return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
12934 +static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
12935 + DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
12938 +# endif /* DWC_DEBUG_REGS */
12940 +#endif /* DWC_FREEBSD || DWC_NETBSD */
12945 +#ifdef DWC_CRYPTOLIB
12946 +/** @name Crypto Functions
12948 + * These are the low-level cryptographic functions used by the driver. */
12950 +/** Perform AES CBC */
12951 +extern int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out);
12952 +#define dwc_aes_cbc DWC_AES_CBC
12954 +/** Fill the provided buffer with random bytes. These should be cryptographic grade random numbers. */
12955 +extern void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length);
12956 +#define dwc_random_bytes DWC_RANDOM_BYTES
12958 +/** Perform the SHA-256 hash function */
12959 +extern int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out);
12960 +#define dwc_sha256 DWC_SHA256
12962 +/** Calculated the HMAC-SHA256 */
12963 +extern int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out);
12964 +#define dwc_hmac_sha256 DWC_HMAC_SHA256
12966 +#endif /* DWC_CRYPTOLIB */
12969 +/** @name Memory Allocation
12971 + * These function provide access to memory allocation. There are only 2 DMA
12972 + * functions and 3 Regular memory functions that need to be implemented. None
12973 + * of the memory debugging routines need to be implemented. The allocation
12974 + * routines all ZERO the contents of the memory.
12976 + * Defining DWC_DEBUG_MEMORY turns on memory debugging and statistic gathering.
12977 + * This checks for memory leaks, keeping track of alloc/free pairs. It also
12978 + * keeps track of how much memory the driver is using at any given time. */
12980 +#define DWC_PAGE_SIZE 4096
12981 +#define DWC_PAGE_OFFSET(addr) (((uint32_t)addr) & 0xfff)
12982 +#define DWC_PAGE_ALIGNED(addr) ((((uint32_t)addr) & 0xfff) == 0)
12984 +#define DWC_INVALID_DMA_ADDR 0x0
12987 +/** Type for a DMA address */
12988 +typedef dma_addr_t dwc_dma_t;
12991 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
12992 +typedef bus_addr_t dwc_dma_t;
12995 +#ifdef DWC_FREEBSD
12996 +typedef struct dwc_dmactx {
12997 + struct device *dev;
12998 + bus_dma_tag_t dma_tag;
12999 + bus_dmamap_t dma_map;
13000 + bus_addr_t dma_paddr;
13006 +typedef struct dwc_dmactx {
13007 + struct device *dev;
13008 + bus_dma_tag_t dma_tag;
13009 + bus_dmamap_t dma_map;
13010 + bus_dma_segment_t segs[1];
13012 + bus_addr_t dma_paddr;
13017 +/* @todo these functions will be added in the future */
13020 + * Creates a DMA pool from which you can allocate DMA buffers. Buffers
13021 + * allocated from this pool will be guaranteed to meet the size, alignment, and
13022 + * boundary requirements specified.
13024 + * @param[in] size Specifies the size of the buffers that will be allocated from
13026 + * @param[in] align Specifies the byte alignment requirements of the buffers
13027 + * allocated from this pool. Must be a power of 2.
13028 + * @param[in] boundary Specifies the N-byte boundary that buffers allocated from
13029 + * this pool must not cross.
13031 + * @returns A pointer to an internal opaque structure which is not to be
13032 + * accessed outside of these library functions. Use this handle to specify
13033 + * which pools to allocate/free DMA buffers from and also to destroy the pool,
13034 + * when you are done with it.
13036 +extern dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t boundary);
13039 + * Destroy a DMA pool. All buffers allocated from that pool must be freed first.
13041 +extern void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool);
13044 + * Allocate a buffer from the specified DMA pool and zeros its contents.
13046 +extern void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr);
13049 + * Free a previously allocated buffer from the DMA pool.
13051 +extern void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr);
13054 +/** Allocates a DMA capable buffer and zeroes its contents. */
13055 +extern void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
13057 +/** Allocates a DMA capable buffer and zeroes its contents in atomic contest */
13058 +extern void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
13060 +/** Frees a previously allocated buffer. */
13061 +extern void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr);
13063 +/** Allocates a block of memory and zeroes its contents. */
13064 +extern void *__DWC_ALLOC(void *mem_ctx, uint32_t size);
13066 +/** Allocates a block of memory and zeroes its contents, in an atomic manner
13067 + * which can be used inside interrupt context. The size should be sufficiently
13068 + * small, a few KB at most, such that failures are not likely to occur. Can just call
13069 + * __DWC_ALLOC if it is atomic. */
13070 +extern void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size);
13072 +/** Frees a previously allocated buffer. */
13073 +extern void __DWC_FREE(void *mem_ctx, void *addr);
13075 +#ifndef DWC_DEBUG_MEMORY
13077 +#define DWC_ALLOC(_size_) __DWC_ALLOC(NULL, _size_)
13078 +#define DWC_ALLOC_ATOMIC(_size_) __DWC_ALLOC_ATOMIC(NULL, _size_)
13079 +#define DWC_FREE(_addr_) __DWC_FREE(NULL, _addr_)
13082 +#define DWC_DMA_ALLOC(_size_,_dma_) __DWC_DMA_ALLOC(NULL, _size_, _dma_)
13083 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) __DWC_DMA_ALLOC_ATOMIC(NULL, _size_,_dma_)
13084 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) __DWC_DMA_FREE(NULL, _size_, _virt_, _dma_)
13087 +# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13088 +#define DWC_DMA_ALLOC __DWC_DMA_ALLOC
13089 +#define DWC_DMA_FREE __DWC_DMA_FREE
13091 +extern void *dwc_dma_alloc_atomic_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line);
13093 +#else /* DWC_DEBUG_MEMORY */
13095 +extern void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line);
13096 +extern void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func, int line);
13097 +extern void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line);
13098 +extern void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
13099 + char const *func, int line);
13100 +extern void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
13101 + char const *func, int line);
13102 +extern void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
13103 + dwc_dma_t dma_addr, char const *func, int line);
13105 +extern int dwc_memory_debug_start(void *mem_ctx);
13106 +extern void dwc_memory_debug_stop(void);
13107 +extern void dwc_memory_debug_report(void);
13109 +#define DWC_ALLOC(_size_) dwc_alloc_debug(NULL, _size_, __func__, __LINE__)
13110 +#define DWC_ALLOC_ATOMIC(_size_) dwc_alloc_atomic_debug(NULL, _size_, \
13111 + __func__, __LINE__)
13112 +#define DWC_FREE(_addr_) dwc_free_debug(NULL, _addr_, __func__, __LINE__)
13115 +#define DWC_DMA_ALLOC(_size_,_dma_) dwc_dma_alloc_debug(NULL, _size_, \
13116 + _dma_, __func__, __LINE__)
13117 +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) dwc_dma_alloc_atomic_debug(NULL, _size_, \
13118 + _dma_, __func__, __LINE__)
13119 +#define DWC_DMA_FREE(_size_,_virt_,_dma_) dwc_dma_free_debug(NULL, _size_, \
13120 + _virt_, _dma_, __func__, __LINE__)
13123 +# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13124 +#define DWC_DMA_ALLOC(_ctx_,_size_,_dma_) dwc_dma_alloc_debug(_ctx_, _size_, \
13125 + _dma_, __func__, __LINE__)
13126 +#define DWC_DMA_FREE(_ctx_,_size_,_virt_,_dma_) dwc_dma_free_debug(_ctx_, _size_, \
13127 + _virt_, _dma_, __func__, __LINE__)
13130 +#endif /* DWC_DEBUG_MEMORY */
13132 +#define dwc_alloc(_ctx_,_size_) DWC_ALLOC(_size_)
13133 +#define dwc_alloc_atomic(_ctx_,_size_) DWC_ALLOC_ATOMIC(_size_)
13134 +#define dwc_free(_ctx_,_addr_) DWC_FREE(_addr_)
13137 +/* Linux doesn't need any extra parameters for DMA buffer allocation, so we
13138 + * just throw away the DMA context parameter.
13140 +#define dwc_dma_alloc(_ctx_,_size_,_dma_) DWC_DMA_ALLOC(_size_, _dma_)
13141 +#define dwc_dma_alloc_atomic(_ctx_,_size_,_dma_) DWC_DMA_ALLOC_ATOMIC(_size_, _dma_)
13142 +#define dwc_dma_free(_ctx_,_size_,_virt_,_dma_) DWC_DMA_FREE(_size_, _virt_, _dma_)
13145 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13146 +/** BSD needs several extra parameters for DMA buffer allocation, so we pass
13147 + * them in using the DMA context parameter.
13149 +#define dwc_dma_alloc DWC_DMA_ALLOC
13150 +#define dwc_dma_free DWC_DMA_FREE
13154 +/** @name Memory and String Processing */
13156 +/** memset() clone */
13157 +extern void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size);
13158 +#define dwc_memset DWC_MEMSET
13160 +/** memcpy() clone */
13161 +extern void *DWC_MEMCPY(void *dest, void const *src, uint32_t size);
13162 +#define dwc_memcpy DWC_MEMCPY
13164 +/** memmove() clone */
13165 +extern void *DWC_MEMMOVE(void *dest, void *src, uint32_t size);
13166 +#define dwc_memmove DWC_MEMMOVE
13168 +/** memcmp() clone */
13169 +extern int DWC_MEMCMP(void *m1, void *m2, uint32_t size);
13170 +#define dwc_memcmp DWC_MEMCMP
13172 +/** strcmp() clone */
13173 +extern int DWC_STRCMP(void *s1, void *s2);
13174 +#define dwc_strcmp DWC_STRCMP
13176 +/** strncmp() clone */
13177 +extern int DWC_STRNCMP(void *s1, void *s2, uint32_t size);
13178 +#define dwc_strncmp DWC_STRNCMP
13180 +/** strlen() clone, for NULL terminated ASCII strings */
13181 +extern int DWC_STRLEN(char const *str);
13182 +#define dwc_strlen DWC_STRLEN
13184 +/** strcpy() clone, for NULL terminated ASCII strings */
13185 +extern char *DWC_STRCPY(char *to, const char *from);
13186 +#define dwc_strcpy DWC_STRCPY
13188 +/** strdup() clone. If you wish to use memory allocation debugging, this
13189 + * implementation of strdup should use the DWC_* memory routines instead of
13190 + * calling a predefined strdup. Otherwise the memory allocated by this routine
13191 + * will not be seen by the debugging routines. */
13192 +extern char *DWC_STRDUP(char const *str);
13193 +#define dwc_strdup(_ctx_,_str_) DWC_STRDUP(_str_)
13195 +/** NOT an atoi() clone. Read the description carefully. Returns an integer
13196 + * converted from the string str in base 10 unless the string begins with a "0x"
13197 + * in which case it is base 16. String must be a NULL terminated sequence of
13198 + * ASCII characters and may optionally begin with whitespace, a + or -, and a
13199 + * "0x" prefix if base 16. The remaining characters must be valid digits for
13200 + * the number and end with a NULL character. If any invalid characters are
13201 + * encountered or it returns with a negative error code and the results of the
13202 + * conversion are undefined. On sucess it returns 0. Overflow conditions are
13203 + * undefined. An example implementation using atoi() can be referenced from the
13204 + * Linux implementation. */
13205 +extern int DWC_ATOI(const char *str, int32_t *value);
13206 +#define dwc_atoi DWC_ATOI
13208 +/** Same as above but for unsigned. */
13209 +extern int DWC_ATOUI(const char *str, uint32_t *value);
13210 +#define dwc_atoui DWC_ATOUI
13213 +/** This routine returns a UTF16LE unicode encoded string from a UTF8 string. */
13214 +extern int DWC_UTF8_TO_UTF16LE(uint8_t const *utf8string, uint16_t *utf16string, unsigned len);
13215 +#define dwc_utf8_to_utf16le DWC_UTF8_TO_UTF16LE
13219 +/** @name Wait queues
13221 + * Wait queues provide a means of synchronizing between threads or processes. A
13222 + * process can block on a waitq if some condition is not true, waiting for it to
13223 + * become true. When the waitq is triggered all waiting process will get
13224 + * unblocked and the condition will be check again. Waitqs should be triggered
13225 + * every time a condition can potentially change.*/
13228 +/** Type for a waitq */
13229 +typedef struct dwc_waitq dwc_waitq_t;
13231 +/** The type of waitq condition callback function. This is called every time
13232 + * condition is evaluated. */
13233 +typedef int (*dwc_waitq_condition_t)(void *data);
13235 +/** Allocate a waitq */
13236 +extern dwc_waitq_t *DWC_WAITQ_ALLOC(void);
13237 +#define dwc_waitq_alloc(_ctx_) DWC_WAITQ_ALLOC()
13239 +/** Free a waitq */
13240 +extern void DWC_WAITQ_FREE(dwc_waitq_t *wq);
13241 +#define dwc_waitq_free DWC_WAITQ_FREE
13243 +/** Check the condition and if it is false, block on the waitq. When unblocked, check the
13244 + * condition again. The function returns when the condition becomes true. The return value
13245 + * is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. */
13246 +extern int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data);
13247 +#define dwc_waitq_wait DWC_WAITQ_WAIT
13249 +/** Check the condition and if it is false, block on the waitq. When unblocked,
13250 + * check the condition again. The function returns when the condition become
13251 + * true or the timeout has passed. The return value is 0 on condition true or
13252 + * DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on
13254 +extern int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
13255 + void *data, int32_t msecs);
13256 +#define dwc_waitq_wait_timeout DWC_WAITQ_WAIT_TIMEOUT
13258 +/** Trigger a waitq, unblocking all processes. This should be called whenever a condition
13259 + * has potentially changed. */
13260 +extern void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq);
13261 +#define dwc_waitq_trigger DWC_WAITQ_TRIGGER
13263 +/** Unblock all processes waiting on the waitq with an ABORTED result. */
13264 +extern void DWC_WAITQ_ABORT(dwc_waitq_t *wq);
13265 +#define dwc_waitq_abort DWC_WAITQ_ABORT
13270 + * A thread must be explicitly stopped. It must check DWC_THREAD_SHOULD_STOP
13271 + * whenever it is woken up, and then return. The DWC_THREAD_STOP function
13272 + * returns the value from the thread.
13275 +struct dwc_thread;
13277 +/** Type for a thread */
13278 +typedef struct dwc_thread dwc_thread_t;
13280 +/** The thread function */
13281 +typedef int (*dwc_thread_function_t)(void *data);
13283 +/** Create a thread and start it running the thread_function. Returns a handle
13284 + * to the thread */
13285 +extern dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data);
13286 +#define dwc_thread_run(_ctx_,_func_,_name_,_data_) DWC_THREAD_RUN(_func_, _name_, _data_)
13288 +/** Stops a thread. Return the value returned by the thread. Or will return
13289 + * DWC_ABORT if the thread never started. */
13290 +extern int DWC_THREAD_STOP(dwc_thread_t *thread);
13291 +#define dwc_thread_stop DWC_THREAD_STOP
13293 +/** Signifies to the thread that it must stop. */
13295 +/* Linux doesn't need any parameters for kthread_should_stop() */
13296 +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(void);
13297 +#define dwc_thread_should_stop(_thrd_) DWC_THREAD_SHOULD_STOP()
13299 +/* No thread_exit function in Linux */
13300 +#define dwc_thread_exit(_thrd_)
13303 +#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
13304 +/** BSD needs the thread pointer for kthread_suspend_check() */
13305 +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread);
13306 +#define dwc_thread_should_stop DWC_THREAD_SHOULD_STOP
13308 +/** The thread must call this to exit. */
13309 +extern void DWC_THREAD_EXIT(dwc_thread_t *thread);
13310 +#define dwc_thread_exit DWC_THREAD_EXIT
13314 +/** @name Work queues
13316 + * Workqs are used to queue a callback function to be called at some later time,
13317 + * in another thread. */
13320 +/** Type for a workq */
13321 +typedef struct dwc_workq dwc_workq_t;
13323 +/** The type of the callback function to be called. */
13324 +typedef void (*dwc_work_callback_t)(void *data);
13326 +/** Allocate a workq */
13327 +extern dwc_workq_t *DWC_WORKQ_ALLOC(char *name);
13328 +#define dwc_workq_alloc(_ctx_,_name_) DWC_WORKQ_ALLOC(_name_)
13330 +/** Free a workq. All work must be completed before being freed. */
13331 +extern void DWC_WORKQ_FREE(dwc_workq_t *workq);
13332 +#define dwc_workq_free DWC_WORKQ_FREE
13334 +/** Schedule a callback on the workq, passing in data. The function will be
13335 + * scheduled at some later time. */
13336 +extern void DWC_WORKQ_SCHEDULE(dwc_workq_t *workq, dwc_work_callback_t cb,
13337 + void *data, char *format, ...)
13339 + __attribute__ ((format(printf, 4, 5)));
13343 +#define dwc_workq_schedule DWC_WORKQ_SCHEDULE
13345 +/** Schedule a callback on the workq, that will be called until at least
13346 + * given number miliseconds have passed. */
13347 +extern void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *workq, dwc_work_callback_t cb,
13348 + void *data, uint32_t time, char *format, ...)
13350 + __attribute__ ((format(printf, 5, 6)));
13354 +#define dwc_workq_schedule_delayed DWC_WORKQ_SCHEDULE_DELAYED
13356 +/** The number of processes in the workq */
13357 +extern int DWC_WORKQ_PENDING(dwc_workq_t *workq);
13358 +#define dwc_workq_pending DWC_WORKQ_PENDING
13360 +/** Blocks until all the work in the workq is complete or timed out. Returns <
13361 + * 0 on timeout. */
13362 +extern int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout);
13363 +#define dwc_workq_wait_work_done DWC_WORKQ_WAIT_WORK_DONE
13366 +/** @name Tasklets
13369 +struct dwc_tasklet;
13371 +/** Type for a tasklet */
13372 +typedef struct dwc_tasklet dwc_tasklet_t;
13374 +/** The type of the callback function to be called */
13375 +typedef void (*dwc_tasklet_callback_t)(void *data);
13377 +/** Allocates a tasklet */
13378 +extern dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data);
13379 +#define dwc_task_alloc(_ctx_,_name_,_cb_,_data_) DWC_TASK_ALLOC(_name_, _cb_, _data_)
13381 +/** Frees a tasklet */
13382 +extern void DWC_TASK_FREE(dwc_tasklet_t *task);
13383 +#define dwc_task_free DWC_TASK_FREE
13385 +/** Schedules a tasklet to run */
13386 +extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
13387 +#define dwc_task_schedule DWC_TASK_SCHEDULE
13392 + * Callbacks must be small and atomic.
13396 +/** Type for a timer */
13397 +typedef struct dwc_timer dwc_timer_t;
13399 +/** The type of the callback function to be called */
13400 +typedef void (*dwc_timer_callback_t)(void *data);
13402 +/** Allocates a timer */
13403 +extern dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data);
13404 +#define dwc_timer_alloc(_ctx_,_name_,_cb_,_data_) DWC_TIMER_ALLOC(_name_,_cb_,_data_)
13406 +/** Frees a timer */
13407 +extern void DWC_TIMER_FREE(dwc_timer_t *timer);
13408 +#define dwc_timer_free DWC_TIMER_FREE
13410 +/** Schedules the timer to run at time ms from now. And will repeat at every
13411 + * repeat_interval msec therafter
13413 + * Modifies a timer that is still awaiting execution to a new expiration time.
13414 + * The mod_time is added to the old time. */
13415 +extern void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time);
13416 +#define dwc_timer_schedule DWC_TIMER_SCHEDULE
13418 +/** Disables the timer from execution. */
13419 +extern void DWC_TIMER_CANCEL(dwc_timer_t *timer);
13420 +#define dwc_timer_cancel DWC_TIMER_CANCEL
13423 +/** @name Spinlocks
13425 + * These locks are used when the work between the lock/unlock is atomic and
13426 + * short. Interrupts are also disabled during the lock/unlock and thus they are
13427 + * suitable to lock between interrupt/non-interrupt context. They also lock
13428 + * between processes if you have multiple CPUs or Preemption. If you don't have
13429 + * multiple CPUS or Preemption, then the you can simply implement the
13430 + * DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts. Because
13431 + * the work between the lock/unlock is atomic, the process context will never
13432 + * change, and so you never have to lock between processes. */
13434 +struct dwc_spinlock;
13436 +/** Type for a spinlock */
13437 +typedef struct dwc_spinlock dwc_spinlock_t;
13439 +/** Type for the 'flags' argument to spinlock funtions */
13440 +typedef unsigned long dwc_irqflags_t;
13442 +/** Returns an initialized lock variable. This function should allocate and
13443 + * initialize the OS-specific data structure used for locking. This data
13444 + * structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should
13445 + * be freed by the DWC_FREE_LOCK when it is no longer used. */
13446 +extern dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void);
13447 +#define dwc_spinlock_alloc(_ctx_) DWC_SPINLOCK_ALLOC()
13449 +/** Frees an initialized lock variable. */
13450 +extern void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock);
13451 +#define dwc_spinlock_free(_ctx_,_lock_) DWC_SPINLOCK_FREE(_lock_)
13453 +/** Disables interrupts and blocks until it acquires the lock.
13455 + * @param lock Pointer to the spinlock.
13456 + * @param flags Unsigned long for irq flags storage.
13458 +extern void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags);
13459 +#define dwc_spinlock_irqsave DWC_SPINLOCK_IRQSAVE
13461 +/** Re-enables the interrupt and releases the lock.
13463 + * @param lock Pointer to the spinlock.
13464 + * @param flags Unsigned long for irq flags storage. Must be the same as was
13465 + * passed into DWC_LOCK.
13467 +extern void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags);
13468 +#define dwc_spinunlock_irqrestore DWC_SPINUNLOCK_IRQRESTORE
13470 +/** Blocks until it acquires the lock.
13472 + * @param lock Pointer to the spinlock.
13474 +extern void DWC_SPINLOCK(dwc_spinlock_t *lock);
13475 +#define dwc_spinlock DWC_SPINLOCK
13477 +/** Releases the lock.
13479 + * @param lock Pointer to the spinlock.
13481 +extern void DWC_SPINUNLOCK(dwc_spinlock_t *lock);
13482 +#define dwc_spinunlock DWC_SPINUNLOCK
13487 + * Unlike spinlocks Mutexes lock only between processes and the work between the
13488 + * lock/unlock CAN block, therefore it CANNOT be called from interrupt context.
13493 +/** Type for a mutex */
13494 +typedef struct dwc_mutex dwc_mutex_t;
13496 +/* For Linux Mutex Debugging make it inline because the debugging routines use
13497 + * the symbol to determine recursive locking. This makes it falsely think
13498 + * recursive locking occurs. */
13499 +#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
13500 +#define DWC_MUTEX_ALLOC_LINUX_DEBUG(__mutexp) ({ \
13501 + __mutexp = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); \
13502 + mutex_init((struct mutex *)__mutexp); \
13506 +/** Allocate a mutex */
13507 +extern dwc_mutex_t *DWC_MUTEX_ALLOC(void);
13508 +#define dwc_mutex_alloc(_ctx_) DWC_MUTEX_ALLOC()
13510 +/* For memory leak debugging when using Linux Mutex Debugging */
13511 +#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
13512 +#define DWC_MUTEX_FREE(__mutexp) do { \
13513 + mutex_destroy((struct mutex *)__mutexp); \
13514 + DWC_FREE(__mutexp); \
13517 +/** Free a mutex */
13518 +extern void DWC_MUTEX_FREE(dwc_mutex_t *mutex);
13519 +#define dwc_mutex_free(_ctx_,_mutex_) DWC_MUTEX_FREE(_mutex_)
13522 +/** Lock a mutex */
13523 +extern void DWC_MUTEX_LOCK(dwc_mutex_t *mutex);
13524 +#define dwc_mutex_lock DWC_MUTEX_LOCK
13526 +/** Non-blocking lock returns 1 on successful lock. */
13527 +extern int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex);
13528 +#define dwc_mutex_trylock DWC_MUTEX_TRYLOCK
13530 +/** Unlock a mutex */
13531 +extern void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex);
13532 +#define dwc_mutex_unlock DWC_MUTEX_UNLOCK
13537 +/** Microsecond delay.
13539 + * @param usecs Microseconds to delay.
13541 +extern void DWC_UDELAY(uint32_t usecs);
13542 +#define dwc_udelay DWC_UDELAY
13544 +/** Millisecond delay.
13546 + * @param msecs Milliseconds to delay.
13548 +extern void DWC_MDELAY(uint32_t msecs);
13549 +#define dwc_mdelay DWC_MDELAY
13551 +/** Non-busy waiting.
13552 + * Sleeps for specified number of milliseconds.
13554 + * @param msecs Milliseconds to sleep.
13556 +extern void DWC_MSLEEP(uint32_t msecs);
13557 +#define dwc_msleep DWC_MSLEEP
13560 + * Returns number of milliseconds since boot.
13562 +extern uint32_t DWC_TIME(void);
13563 +#define dwc_time DWC_TIME
13568 +/* @mainpage DWC Portability and Common Library
13570 + * This is the documentation for the DWC Portability and Common Library.
13572 + * @section intro Introduction
13574 + * The DWC Portability library consists of wrapper calls and data structures to
13575 + * all low-level functions which are typically provided by the OS. The WUDEV
13576 + * driver uses only these functions. In order to port the WUDEV driver, only
13577 + * the functions in this library need to be re-implemented, with the same
13578 + * behavior as documented here.
13580 + * The Common library consists of higher level functions, which rely only on
13581 + * calling the functions from the DWC Portability library. These common
13582 + * routines are shared across modules. Some of the common libraries need to be
13583 + * used directly by the driver programmer when porting WUDEV. Such as the
13584 + * parameter and notification libraries.
13586 + * @section low Portability Library OS Wrapper Functions
13588 + * Any function starting with DWC and in all CAPS is a low-level OS-wrapper that
13589 + * needs to be implemented when porting, for example DWC_MUTEX_ALLOC(). All of
13590 + * these functions are included in the dwc_os.h file.
13592 + * There are many functions here covering a wide array of OS services. Please
13593 + * see dwc_os.h for details, and implementation notes for each function.
13595 + * @section common Common Library Functions
13597 + * Any function starting with dwc and in all lowercase is a common library
13598 + * routine. These functions have a portable implementation and do not need to
13599 + * be reimplemented when porting. The common routines can be used by any
13600 + * driver, and some must be used by the end user to control the drivers. For
13601 + * example, you must use the Parameter common library in order to set the
13602 + * parameters in the WUDEV module.
13604 + * The common libraries consist of the following:
13606 + * - Connection Contexts - Used internally and can be used by end-user. See dwc_cc.h
13607 + * - Parameters - Used internally and can be used by end-user. See dwc_params.h
13608 + * - Notifications - Used internally and can be used by end-user. See dwc_notifier.h
13609 + * - Lists - Used internally and can be used by end-user. See dwc_list.h
13610 + * - Memory Debugging - Used internally and can be used by end-user. See dwc_os.h
13611 + * - Modpow - Used internally only. See dwc_modpow.h
13612 + * - DH - Used internally only. See dwc_dh.h
13613 + * - Crypto - Used internally only. See dwc_crypto.h
13616 + * @section prereq Prerequistes For dwc_os.h
13617 + * @subsection types Data Types
13619 + * The dwc_os.h file assumes that several low-level data types are pre defined for the
13620 + * compilation environment. These data types are:
13622 + * - uint8_t - unsigned 8-bit data type
13623 + * - int8_t - signed 8-bit data type
13624 + * - uint16_t - unsigned 16-bit data type
13625 + * - int16_t - signed 16-bit data type
13626 + * - uint32_t - unsigned 32-bit data type
13627 + * - int32_t - signed 32-bit data type
13628 + * - uint64_t - unsigned 64-bit data type
13629 + * - int64_t - signed 64-bit data type
13631 + * Ensure that these are defined before using dwc_os.h. The easiest way to do
13632 + * that is to modify the top of the file to include the appropriate header.
13633 + * This is already done for the Linux environment. If the DWC_LINUX macro is
13634 + * defined, the correct header will be added. A standard header <stdint.h> is
13635 + * also used for environments where standard C headers are available.
13637 + * @subsection stdarg Variable Arguments
13639 + * Variable arguments are provided by a standard C header <stdarg.h>. it is
13640 + * available in Both the Linux and ANSI C enviornment. An equivalent must be
13641 + * provided in your enviornment in order to use dwc_os.h with the debug and
13642 + * tracing message functionality.
13644 + * @subsection thread Threading
13646 + * WUDEV Core must be run on an operating system that provides for multiple
13647 + * threads/processes. Threading can be implemented in many ways, even in
13648 + * embedded systems without an operating system. At the bare minimum, the
13649 + * system should be able to start any number of processes at any time to handle
13650 + * special work. It need not be a pre-emptive system. Process context can
13651 + * change upon a call to a blocking function. The hardware interrupt context
13652 + * that calls the module's ISR() function must be differentiable from process
13653 + * context, even if your processes are impemented via a hardware interrupt.
13654 + * Further locking mechanism between process must exist (or be implemented), and
13655 + * process context must have a way to disable interrupts for a period of time to
13656 + * lock them out. If all of this exists, the functions in dwc_os.h related to
13657 + * threading should be able to be implemented with the defined behavior.
13661 +#ifdef __cplusplus
13665 +#endif /* _DWC_OS_H_ */
13666 diff --git a/drivers/usb/host/dwc_common_port/usb.h b/drivers/usb/host/dwc_common_port/usb.h
13667 new file mode 100644
13668 index 0000000..27bda82
13670 +++ b/drivers/usb/host/dwc_common_port/usb.h
13673 + * Copyright (c) 1998 The NetBSD Foundation, Inc.
13674 + * All rights reserved.
13676 + * This code is derived from software contributed to The NetBSD Foundation
13677 + * by Lennart Augustsson (lennart@augustsson.net) at
13678 + * Carlstedt Research & Technology.
13680 + * Redistribution and use in source and binary forms, with or without
13681 + * modification, are permitted provided that the following conditions
13683 + * 1. Redistributions of source code must retain the above copyright
13684 + * notice, this list of conditions and the following disclaimer.
13685 + * 2. Redistributions in binary form must reproduce the above copyright
13686 + * notice, this list of conditions and the following disclaimer in the
13687 + * documentation and/or other materials provided with the distribution.
13688 + * 3. All advertising materials mentioning features or use of this software
13689 + * must display the following acknowledgement:
13690 + * This product includes software developed by the NetBSD
13691 + * Foundation, Inc. and its contributors.
13692 + * 4. Neither the name of The NetBSD Foundation nor the names of its
13693 + * contributors may be used to endorse or promote products derived
13694 + * from this software without specific prior written permission.
13696 + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
13697 + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13698 + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
13699 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
13700 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
13701 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
13702 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
13703 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
13704 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
13705 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
13706 + * POSSIBILITY OF SUCH DAMAGE.
13709 +/* Modified by Synopsys, Inc, 12/12/2007 */
13715 +#ifdef __cplusplus
13720 + * The USB records contain some unaligned little-endian word
13721 + * components. The U[SG]ETW macros take care of both the alignment
13722 + * and endian problem and should always be used to access non-byte
13725 +typedef u_int8_t uByte;
13726 +typedef u_int8_t uWord[2];
13727 +typedef u_int8_t uDWord[4];
13729 +#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
13730 +#define UCONSTW(x) { (x) & 0xff, ((x) >> 8) & 0xff }
13731 +#define UCONSTDW(x) { (x) & 0xff, ((x) >> 8) & 0xff, \
13732 + ((x) >> 16) & 0xff, ((x) >> 24) & 0xff }
13735 +#define UGETW(w) ((w)[0] | ((w)[1] << 8))
13736 +#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
13737 +#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
13738 +#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
13739 + (w)[1] = (u_int8_t)((v) >> 8), \
13740 + (w)[2] = (u_int8_t)((v) >> 16), \
13741 + (w)[3] = (u_int8_t)((v) >> 24))
13744 + * On little-endian machines that can handle unanliged accesses
13745 + * (e.g. i386) these macros can be replaced by the following.
13747 +#define UGETW(w) (*(u_int16_t *)(w))
13748 +#define USETW(w,v) (*(u_int16_t *)(w) = (v))
13749 +#define UGETDW(w) (*(u_int32_t *)(w))
13750 +#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
13754 + * Macros for accessing UAS IU fields, which are big-endian
13756 +#define IUSETW2(w,h,l) ((w)[0] = (u_int8_t)(h), (w)[1] = (u_int8_t)(l))
13757 +#define IUCONSTW(x) { ((x) >> 8) & 0xff, (x) & 0xff }
13758 +#define IUCONSTDW(x) { ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
13759 + ((x) >> 8) & 0xff, (x) & 0xff }
13760 +#define IUGETW(w) (((w)[0] << 8) | (w)[1])
13761 +#define IUSETW(w,v) ((w)[0] = (u_int8_t)((v) >> 8), (w)[1] = (u_int8_t)(v))
13762 +#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
13763 +#define IUSETDW(w,v) ((w)[0] = (u_int8_t)((v) >> 24), \
13764 + (w)[1] = (u_int8_t)((v) >> 16), \
13765 + (w)[2] = (u_int8_t)((v) >> 8), \
13766 + (w)[3] = (u_int8_t)(v))
13768 +#define UPACKED __attribute__((__packed__))
13771 + uByte bmRequestType;
13776 +} UPACKED usb_device_request_t;
13778 +#define UT_GET_DIR(a) ((a) & 0x80)
13779 +#define UT_WRITE 0x00
13780 +#define UT_READ 0x80
13782 +#define UT_GET_TYPE(a) ((a) & 0x60)
13783 +#define UT_STANDARD 0x00
13784 +#define UT_CLASS 0x20
13785 +#define UT_VENDOR 0x40
13787 +#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
13788 +#define UT_DEVICE 0x00
13789 +#define UT_INTERFACE 0x01
13790 +#define UT_ENDPOINT 0x02
13791 +#define UT_OTHER 0x03
13793 +#define UT_READ_DEVICE (UT_READ | UT_STANDARD | UT_DEVICE)
13794 +#define UT_READ_INTERFACE (UT_READ | UT_STANDARD | UT_INTERFACE)
13795 +#define UT_READ_ENDPOINT (UT_READ | UT_STANDARD | UT_ENDPOINT)
13796 +#define UT_WRITE_DEVICE (UT_WRITE | UT_STANDARD | UT_DEVICE)
13797 +#define UT_WRITE_INTERFACE (UT_WRITE | UT_STANDARD | UT_INTERFACE)
13798 +#define UT_WRITE_ENDPOINT (UT_WRITE | UT_STANDARD | UT_ENDPOINT)
13799 +#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE)
13800 +#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE)
13801 +#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER)
13802 +#define UT_READ_CLASS_ENDPOINT (UT_READ | UT_CLASS | UT_ENDPOINT)
13803 +#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE)
13804 +#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
13805 +#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER)
13806 +#define UT_WRITE_CLASS_ENDPOINT (UT_WRITE | UT_CLASS | UT_ENDPOINT)
13807 +#define UT_READ_VENDOR_DEVICE (UT_READ | UT_VENDOR | UT_DEVICE)
13808 +#define UT_READ_VENDOR_INTERFACE (UT_READ | UT_VENDOR | UT_INTERFACE)
13809 +#define UT_READ_VENDOR_OTHER (UT_READ | UT_VENDOR | UT_OTHER)
13810 +#define UT_READ_VENDOR_ENDPOINT (UT_READ | UT_VENDOR | UT_ENDPOINT)
13811 +#define UT_WRITE_VENDOR_DEVICE (UT_WRITE | UT_VENDOR | UT_DEVICE)
13812 +#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
13813 +#define UT_WRITE_VENDOR_OTHER (UT_WRITE | UT_VENDOR | UT_OTHER)
13814 +#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
13817 +#define UR_GET_STATUS 0x00
13818 +#define USTAT_STANDARD_STATUS 0x00
13819 +#define WUSTAT_WUSB_FEATURE 0x01
13820 +#define WUSTAT_CHANNEL_INFO 0x02
13821 +#define WUSTAT_RECEIVED_DATA 0x03
13822 +#define WUSTAT_MAS_AVAILABILITY 0x04
13823 +#define WUSTAT_CURRENT_TRANSMIT_POWER 0x05
13824 +#define UR_CLEAR_FEATURE 0x01
13825 +#define UR_SET_FEATURE 0x03
13826 +#define UR_SET_AND_TEST_FEATURE 0x0c
13827 +#define UR_SET_ADDRESS 0x05
13828 +#define UR_GET_DESCRIPTOR 0x06
13829 +#define UDESC_DEVICE 0x01
13830 +#define UDESC_CONFIG 0x02
13831 +#define UDESC_STRING 0x03
13832 +#define UDESC_INTERFACE 0x04
13833 +#define UDESC_ENDPOINT 0x05
13834 +#define UDESC_SS_USB_COMPANION 0x30
13835 +#define UDESC_DEVICE_QUALIFIER 0x06
13836 +#define UDESC_OTHER_SPEED_CONFIGURATION 0x07
13837 +#define UDESC_INTERFACE_POWER 0x08
13838 +#define UDESC_OTG 0x09
13839 +#define WUDESC_SECURITY 0x0c
13840 +#define WUDESC_KEY 0x0d
13841 +#define WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
13842 +#define WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
13843 +#define WUD_KEY_TYPE_ASSOC 0x01
13844 +#define WUD_KEY_TYPE_GTK 0x02
13845 +#define WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
13846 +#define WUD_KEY_ORIGIN_HOST 0x00
13847 +#define WUD_KEY_ORIGIN_DEVICE 0x01
13848 +#define WUDESC_ENCRYPTION_TYPE 0x0e
13849 +#define WUDESC_BOS 0x0f
13850 +#define WUDESC_DEVICE_CAPABILITY 0x10
13851 +#define WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
13852 +#define UDESC_BOS 0x0f
13853 +#define UDESC_DEVICE_CAPABILITY 0x10
13854 +#define UDESC_CS_DEVICE 0x21 /* class specific */
13855 +#define UDESC_CS_CONFIG 0x22
13856 +#define UDESC_CS_STRING 0x23
13857 +#define UDESC_CS_INTERFACE 0x24
13858 +#define UDESC_CS_ENDPOINT 0x25
13859 +#define UDESC_HUB 0x29
13860 +#define UR_SET_DESCRIPTOR 0x07
13861 +#define UR_GET_CONFIG 0x08
13862 +#define UR_SET_CONFIG 0x09
13863 +#define UR_GET_INTERFACE 0x0a
13864 +#define UR_SET_INTERFACE 0x0b
13865 +#define UR_SYNCH_FRAME 0x0c
13866 +#define WUR_SET_ENCRYPTION 0x0d
13867 +#define WUR_GET_ENCRYPTION 0x0e
13868 +#define WUR_SET_HANDSHAKE 0x0f
13869 +#define WUR_GET_HANDSHAKE 0x10
13870 +#define WUR_SET_CONNECTION 0x11
13871 +#define WUR_SET_SECURITY_DATA 0x12
13872 +#define WUR_GET_SECURITY_DATA 0x13
13873 +#define WUR_SET_WUSB_DATA 0x14
13874 +#define WUDATA_DRPIE_INFO 0x01
13875 +#define WUDATA_TRANSMIT_DATA 0x02
13876 +#define WUDATA_TRANSMIT_PARAMS 0x03
13877 +#define WUDATA_RECEIVE_PARAMS 0x04
13878 +#define WUDATA_TRANSMIT_POWER 0x05
13879 +#define WUR_LOOPBACK_DATA_WRITE 0x15
13880 +#define WUR_LOOPBACK_DATA_READ 0x16
13881 +#define WUR_SET_INTERFACE_DS 0x17
13883 +/* Feature numbers */
13884 +#define UF_ENDPOINT_HALT 0
13885 +#define UF_DEVICE_REMOTE_WAKEUP 1
13886 +#define UF_TEST_MODE 2
13887 +#define UF_DEVICE_B_HNP_ENABLE 3
13888 +#define UF_DEVICE_A_HNP_SUPPORT 4
13889 +#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
13890 +#define WUF_WUSB 3
13891 +#define WUF_TX_DRPIE 0x0
13892 +#define WUF_DEV_XMIT_PACKET 0x1
13893 +#define WUF_COUNT_PACKETS 0x2
13894 +#define WUF_CAPTURE_PACKETS 0x3
13895 +#define UF_FUNCTION_SUSPEND 0
13896 +#define UF_U1_ENABLE 48
13897 +#define UF_U2_ENABLE 49
13898 +#define UF_LTM_ENABLE 50
13900 +/* Class requests from the USB 2.0 hub spec, table 11-15 */
13901 +#define UCR_CLEAR_HUB_FEATURE (0x2000 | UR_CLEAR_FEATURE)
13902 +#define UCR_CLEAR_PORT_FEATURE (0x2300 | UR_CLEAR_FEATURE)
13903 +#define UCR_GET_HUB_DESCRIPTOR (0xa000 | UR_GET_DESCRIPTOR)
13904 +#define UCR_GET_HUB_STATUS (0xa000 | UR_GET_STATUS)
13905 +#define UCR_GET_PORT_STATUS (0xa300 | UR_GET_STATUS)
13906 +#define UCR_SET_HUB_FEATURE (0x2000 | UR_SET_FEATURE)
13907 +#define UCR_SET_PORT_FEATURE (0x2300 | UR_SET_FEATURE)
13908 +#define UCR_SET_AND_TEST_PORT_FEATURE (0xa300 | UR_SET_AND_TEST_FEATURE)
13911 +#include <pshpack1.h>
13916 + uByte bDescriptorType;
13917 + uByte bDescriptorSubtype;
13918 +} UPACKED usb_descriptor_t;
13922 + uByte bDescriptorType;
13923 +} UPACKED usb_descriptor_header_t;
13927 + uByte bDescriptorType;
13929 +#define UD_USB_2_0 0x0200
13930 +#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
13931 + uByte bDeviceClass;
13932 + uByte bDeviceSubClass;
13933 + uByte bDeviceProtocol;
13934 + uByte bMaxPacketSize;
13935 + /* The fields below are not part of the initial descriptor. */
13939 + uByte iManufacturer;
13941 + uByte iSerialNumber;
13942 + uByte bNumConfigurations;
13943 +} UPACKED usb_device_descriptor_t;
13944 +#define USB_DEVICE_DESCRIPTOR_SIZE 18
13948 + uByte bDescriptorType;
13949 + uWord wTotalLength;
13950 + uByte bNumInterface;
13951 + uByte bConfigurationValue;
13952 + uByte iConfiguration;
13953 +#define UC_ATT_ONE (1 << 7) /* must be set */
13954 +#define UC_ATT_SELFPOWER (1 << 6) /* self powered */
13955 +#define UC_ATT_WAKEUP (1 << 5) /* can wakeup */
13956 +#define UC_ATT_BATTERY (1 << 4) /* battery powered */
13957 + uByte bmAttributes;
13958 +#define UC_BUS_POWERED 0x80
13959 +#define UC_SELF_POWERED 0x40
13960 +#define UC_REMOTE_WAKEUP 0x20
13961 + uByte bMaxPower; /* max current in 2 mA units */
13962 +#define UC_POWER_FACTOR 2
13963 +} UPACKED usb_config_descriptor_t;
13964 +#define USB_CONFIG_DESCRIPTOR_SIZE 9
13968 + uByte bDescriptorType;
13969 + uByte bInterfaceNumber;
13970 + uByte bAlternateSetting;
13971 + uByte bNumEndpoints;
13972 + uByte bInterfaceClass;
13973 + uByte bInterfaceSubClass;
13974 + uByte bInterfaceProtocol;
13975 + uByte iInterface;
13976 +} UPACKED usb_interface_descriptor_t;
13977 +#define USB_INTERFACE_DESCRIPTOR_SIZE 9
13981 + uByte bDescriptorType;
13982 + uByte bEndpointAddress;
13983 +#define UE_GET_DIR(a) ((a) & 0x80)
13984 +#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7))
13985 +#define UE_DIR_IN 0x80
13986 +#define UE_DIR_OUT 0x00
13987 +#define UE_ADDR 0x0f
13988 +#define UE_GET_ADDR(a) ((a) & UE_ADDR)
13989 + uByte bmAttributes;
13990 +#define UE_XFERTYPE 0x03
13991 +#define UE_CONTROL 0x00
13992 +#define UE_ISOCHRONOUS 0x01
13993 +#define UE_BULK 0x02
13994 +#define UE_INTERRUPT 0x03
13995 +#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE)
13996 +#define UE_ISO_TYPE 0x0c
13997 +#define UE_ISO_ASYNC 0x04
13998 +#define UE_ISO_ADAPT 0x08
13999 +#define UE_ISO_SYNC 0x0c
14000 +#define UE_GET_ISO_TYPE(a) ((a) & UE_ISO_TYPE)
14001 + uWord wMaxPacketSize;
14003 +} UPACKED usb_endpoint_descriptor_t;
14004 +#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
14006 +typedef struct ss_endpoint_companion_descriptor {
14008 + uByte bDescriptorType;
14010 +#define USSE_GET_MAX_STREAMS(a) ((a) & 0x1f)
14011 +#define USSE_SET_MAX_STREAMS(a, b) ((a) | ((b) & 0x1f))
14012 +#define USSE_GET_MAX_PACKET_NUM(a) ((a) & 0x03)
14013 +#define USSE_SET_MAX_PACKET_NUM(a, b) ((a) | ((b) & 0x03))
14014 + uByte bmAttributes;
14015 + uWord wBytesPerInterval;
14016 +} UPACKED ss_endpoint_companion_descriptor_t;
14017 +#define USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE 6
14021 + uByte bDescriptorType;
14022 + uWord bString[127];
14023 +} UPACKED usb_string_descriptor_t;
14024 +#define USB_MAX_STRING_LEN 128
14025 +#define USB_LANGUAGE_TABLE 0 /* # of the string language id table */
14027 +/* Hub specific request */
14028 +#define UR_GET_BUS_STATE 0x02
14029 +#define UR_CLEAR_TT_BUFFER 0x08
14030 +#define UR_RESET_TT 0x09
14031 +#define UR_GET_TT_STATE 0x0a
14032 +#define UR_STOP_TT 0x0b
14034 +/* Hub features */
14035 +#define UHF_C_HUB_LOCAL_POWER 0
14036 +#define UHF_C_HUB_OVER_CURRENT 1
14037 +#define UHF_PORT_CONNECTION 0
14038 +#define UHF_PORT_ENABLE 1
14039 +#define UHF_PORT_SUSPEND 2
14040 +#define UHF_PORT_OVER_CURRENT 3
14041 +#define UHF_PORT_RESET 4
14042 +#define UHF_PORT_L1 5
14043 +#define UHF_PORT_POWER 8
14044 +#define UHF_PORT_LOW_SPEED 9
14045 +#define UHF_PORT_HIGH_SPEED 10
14046 +#define UHF_C_PORT_CONNECTION 16
14047 +#define UHF_C_PORT_ENABLE 17
14048 +#define UHF_C_PORT_SUSPEND 18
14049 +#define UHF_C_PORT_OVER_CURRENT 19
14050 +#define UHF_C_PORT_RESET 20
14051 +#define UHF_C_PORT_L1 23
14052 +#define UHF_PORT_TEST 21
14053 +#define UHF_PORT_INDICATOR 22
14056 + uByte bDescLength;
14057 + uByte bDescriptorType;
14059 + uWord wHubCharacteristics;
14060 +#define UHD_PWR 0x0003
14061 +#define UHD_PWR_GANGED 0x0000
14062 +#define UHD_PWR_INDIVIDUAL 0x0001
14063 +#define UHD_PWR_NO_SWITCH 0x0002
14064 +#define UHD_COMPOUND 0x0004
14065 +#define UHD_OC 0x0018
14066 +#define UHD_OC_GLOBAL 0x0000
14067 +#define UHD_OC_INDIVIDUAL 0x0008
14068 +#define UHD_OC_NONE 0x0010
14069 +#define UHD_TT_THINK 0x0060
14070 +#define UHD_TT_THINK_8 0x0000
14071 +#define UHD_TT_THINK_16 0x0020
14072 +#define UHD_TT_THINK_24 0x0040
14073 +#define UHD_TT_THINK_32 0x0060
14074 +#define UHD_PORT_IND 0x0080
14075 + uByte bPwrOn2PwrGood; /* delay in 2 ms units */
14076 +#define UHD_PWRON_FACTOR 2
14077 + uByte bHubContrCurrent;
14078 + uByte DeviceRemovable[32]; /* max 255 ports */
14079 +#define UHD_NOT_REMOV(desc, i) \
14080 + (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
14081 + /* deprecated */ uByte PortPowerCtrlMask[1];
14082 +} UPACKED usb_hub_descriptor_t;
14083 +#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
14087 + uByte bDescriptorType;
14089 + uByte bDeviceClass;
14090 + uByte bDeviceSubClass;
14091 + uByte bDeviceProtocol;
14092 + uByte bMaxPacketSize0;
14093 + uByte bNumConfigurations;
14095 +} UPACKED usb_device_qualifier_t;
14096 +#define USB_DEVICE_QUALIFIER_SIZE 10
14100 + uByte bDescriptorType;
14101 + uByte bmAttributes;
14102 +#define UOTG_SRP 0x01
14103 +#define UOTG_HNP 0x02
14104 +} UPACKED usb_otg_descriptor_t;
14106 +/* OTG feature selectors */
14107 +#define UOTG_B_HNP_ENABLE 3
14108 +#define UOTG_A_HNP_SUPPORT 4
14109 +#define UOTG_A_ALT_HNP_SUPPORT 5
14113 +/* Device status flags */
14114 +#define UDS_SELF_POWERED 0x0001
14115 +#define UDS_REMOTE_WAKEUP 0x0002
14116 +/* Endpoint status flags */
14117 +#define UES_HALT 0x0001
14118 +} UPACKED usb_status_t;
14121 + uWord wHubStatus;
14122 +#define UHS_LOCAL_POWER 0x0001
14123 +#define UHS_OVER_CURRENT 0x0002
14124 + uWord wHubChange;
14125 +} UPACKED usb_hub_status_t;
14128 + uWord wPortStatus;
14129 +#define UPS_CURRENT_CONNECT_STATUS 0x0001
14130 +#define UPS_PORT_ENABLED 0x0002
14131 +#define UPS_SUSPEND 0x0004
14132 +#define UPS_OVERCURRENT_INDICATOR 0x0008
14133 +#define UPS_RESET 0x0010
14134 +#define UPS_PORT_POWER 0x0100
14135 +#define UPS_LOW_SPEED 0x0200
14136 +#define UPS_HIGH_SPEED 0x0400
14137 +#define UPS_PORT_TEST 0x0800
14138 +#define UPS_PORT_INDICATOR 0x1000
14139 + uWord wPortChange;
14140 +#define UPS_C_CONNECT_STATUS 0x0001
14141 +#define UPS_C_PORT_ENABLED 0x0002
14142 +#define UPS_C_SUSPEND 0x0004
14143 +#define UPS_C_OVERCURRENT_INDICATOR 0x0008
14144 +#define UPS_C_PORT_RESET 0x0010
14145 +} UPACKED usb_port_status_t;
14148 +#include <poppack.h>
14151 +/* Device class codes */
14152 +#define UDCLASS_IN_INTERFACE 0x00
14153 +#define UDCLASS_COMM 0x02
14154 +#define UDCLASS_HUB 0x09
14155 +#define UDSUBCLASS_HUB 0x00
14156 +#define UDPROTO_FSHUB 0x00
14157 +#define UDPROTO_HSHUBSTT 0x01
14158 +#define UDPROTO_HSHUBMTT 0x02
14159 +#define UDCLASS_DIAGNOSTIC 0xdc
14160 +#define UDCLASS_WIRELESS 0xe0
14161 +#define UDSUBCLASS_RF 0x01
14162 +#define UDPROTO_BLUETOOTH 0x01
14163 +#define UDCLASS_VENDOR 0xff
14165 +/* Interface class codes */
14166 +#define UICLASS_UNSPEC 0x00
14168 +#define UICLASS_AUDIO 0x01
14169 +#define UISUBCLASS_AUDIOCONTROL 1
14170 +#define UISUBCLASS_AUDIOSTREAM 2
14171 +#define UISUBCLASS_MIDISTREAM 3
14173 +#define UICLASS_CDC 0x02 /* communication */
14174 +#define UISUBCLASS_DIRECT_LINE_CONTROL_MODEL 1
14175 +#define UISUBCLASS_ABSTRACT_CONTROL_MODEL 2
14176 +#define UISUBCLASS_TELEPHONE_CONTROL_MODEL 3
14177 +#define UISUBCLASS_MULTICHANNEL_CONTROL_MODEL 4
14178 +#define UISUBCLASS_CAPI_CONTROLMODEL 5
14179 +#define UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
14180 +#define UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
14181 +#define UIPROTO_CDC_AT 1
14183 +#define UICLASS_HID 0x03
14184 +#define UISUBCLASS_BOOT 1
14185 +#define UIPROTO_BOOT_KEYBOARD 1
14187 +#define UICLASS_PHYSICAL 0x05
14189 +#define UICLASS_IMAGE 0x06
14191 +#define UICLASS_PRINTER 0x07
14192 +#define UISUBCLASS_PRINTER 1
14193 +#define UIPROTO_PRINTER_UNI 1
14194 +#define UIPROTO_PRINTER_BI 2
14195 +#define UIPROTO_PRINTER_1284 3
14197 +#define UICLASS_MASS 0x08
14198 +#define UISUBCLASS_RBC 1
14199 +#define UISUBCLASS_SFF8020I 2
14200 +#define UISUBCLASS_QIC157 3
14201 +#define UISUBCLASS_UFI 4
14202 +#define UISUBCLASS_SFF8070I 5
14203 +#define UISUBCLASS_SCSI 6
14204 +#define UIPROTO_MASS_CBI_I 0
14205 +#define UIPROTO_MASS_CBI 1
14206 +#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */
14207 +#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */
14209 +#define UICLASS_HUB 0x09
14210 +#define UISUBCLASS_HUB 0
14211 +#define UIPROTO_FSHUB 0
14212 +#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */
14213 +#define UIPROTO_HSHUBMTT 1
14215 +#define UICLASS_CDC_DATA 0x0a
14216 +#define UISUBCLASS_DATA 0
14217 +#define UIPROTO_DATA_ISDNBRI 0x30 /* Physical iface */
14218 +#define UIPROTO_DATA_HDLC 0x31 /* HDLC */
14219 +#define UIPROTO_DATA_TRANSPARENT 0x32 /* Transparent */
14220 +#define UIPROTO_DATA_Q921M 0x50 /* Management for Q921 */
14221 +#define UIPROTO_DATA_Q921 0x51 /* Data for Q921 */
14222 +#define UIPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */
14223 +#define UIPROTO_DATA_V42BIS 0x90 /* Data compression */
14224 +#define UIPROTO_DATA_Q931 0x91 /* Euro-ISDN */
14225 +#define UIPROTO_DATA_V120 0x92 /* V.24 rate adaption */
14226 +#define UIPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */
14227 +#define UIPROTO_DATA_HOST_BASED 0xfd /* Host based driver */
14228 +#define UIPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc.*/
14229 +#define UIPROTO_DATA_VENDOR 0xff /* Vendor specific */
14231 +#define UICLASS_SMARTCARD 0x0b
14233 +/*#define UICLASS_FIRM_UPD 0x0c*/
14235 +#define UICLASS_SECURITY 0x0d
14237 +#define UICLASS_DIAGNOSTIC 0xdc
14239 +#define UICLASS_WIRELESS 0xe0
14240 +#define UISUBCLASS_RF 0x01
14241 +#define UIPROTO_BLUETOOTH 0x01
14243 +#define UICLASS_APPL_SPEC 0xfe
14244 +#define UISUBCLASS_FIRMWARE_DOWNLOAD 1
14245 +#define UISUBCLASS_IRDA 2
14246 +#define UIPROTO_IRDA 0
14248 +#define UICLASS_VENDOR 0xff
14250 +#define USB_HUB_MAX_DEPTH 5
14253 + * Minimum time a device needs to be powered down to go through
14254 + * a power cycle. XXX Are these time in the spec?
14256 +#define USB_POWER_DOWN_TIME 200 /* ms */
14257 +#define USB_PORT_POWER_DOWN_TIME 100 /* ms */
14260 +/* These are the values from the spec. */
14261 +#define USB_PORT_RESET_DELAY 10 /* ms */
14262 +#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
14263 +#define USB_PORT_RESET_RECOVERY 10 /* ms */
14264 +#define USB_PORT_POWERUP_DELAY 100 /* ms */
14265 +#define USB_SET_ADDRESS_SETTLE 2 /* ms */
14266 +#define USB_RESUME_DELAY (20*5) /* ms */
14267 +#define USB_RESUME_WAIT 10 /* ms */
14268 +#define USB_RESUME_RECOVERY 10 /* ms */
14269 +#define USB_EXTRA_POWER_UP_TIME 0 /* ms */
14271 +/* Allow for marginal (i.e. non-conforming) devices. */
14272 +#define USB_PORT_RESET_DELAY 50 /* ms */
14273 +#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
14274 +#define USB_PORT_RESET_RECOVERY 250 /* ms */
14275 +#define USB_PORT_POWERUP_DELAY 300 /* ms */
14276 +#define USB_SET_ADDRESS_SETTLE 10 /* ms */
14277 +#define USB_RESUME_DELAY (50*5) /* ms */
14278 +#define USB_RESUME_WAIT 50 /* ms */
14279 +#define USB_RESUME_RECOVERY 50 /* ms */
14280 +#define USB_EXTRA_POWER_UP_TIME 20 /* ms */
14283 +#define USB_MIN_POWER 100 /* mA */
14284 +#define USB_MAX_POWER 500 /* mA */
14286 +#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/
14288 +#define USB_UNCONFIG_NO 0
14289 +#define USB_UNCONFIG_INDEX (-1)
14291 +/*** ioctl() related stuff ***/
14293 +struct usb_ctl_request {
14295 + usb_device_request_t ucr_request;
14298 +#define USBD_SHORT_XFER_OK 0x04 /* allow short reads */
14299 + int ucr_actlen; /* actual length transferred */
14302 +struct usb_alt_interface {
14303 + int uai_config_index;
14304 + int uai_interface_index;
14308 +#define USB_CURRENT_CONFIG_INDEX (-1)
14309 +#define USB_CURRENT_ALT_INDEX (-1)
14311 +struct usb_config_desc {
14312 + int ucd_config_index;
14313 + usb_config_descriptor_t ucd_desc;
14316 +struct usb_interface_desc {
14317 + int uid_config_index;
14318 + int uid_interface_index;
14319 + int uid_alt_index;
14320 + usb_interface_descriptor_t uid_desc;
14323 +struct usb_endpoint_desc {
14324 + int ued_config_index;
14325 + int ued_interface_index;
14326 + int ued_alt_index;
14327 + int ued_endpoint_index;
14328 + usb_endpoint_descriptor_t ued_desc;
14331 +struct usb_full_desc {
14332 + int ufd_config_index;
14334 + u_char *ufd_data;
14337 +struct usb_string_desc {
14338 + int usd_string_index;
14339 + int usd_language_id;
14340 + usb_string_descriptor_t usd_desc;
14343 +struct usb_ctl_report_desc {
14345 + u_char ucrd_data[1024]; /* filled data size will vary */
14348 +typedef struct { u_int32_t cookie; } usb_event_cookie_t;
14350 +#define USB_MAX_DEVNAMES 4
14351 +#define USB_MAX_DEVNAMELEN 16
14352 +struct usb_device_info {
14353 + u_int8_t udi_bus;
14354 + u_int8_t udi_addr; /* device address */
14355 + usb_event_cookie_t udi_cookie;
14356 + char udi_product[USB_MAX_STRING_LEN];
14357 + char udi_vendor[USB_MAX_STRING_LEN];
14358 + char udi_release[8];
14359 + u_int16_t udi_productNo;
14360 + u_int16_t udi_vendorNo;
14361 + u_int16_t udi_releaseNo;
14362 + u_int8_t udi_class;
14363 + u_int8_t udi_subclass;
14364 + u_int8_t udi_protocol;
14365 + u_int8_t udi_config;
14366 + u_int8_t udi_speed;
14367 +#define USB_SPEED_UNKNOWN 0
14368 +#define USB_SPEED_LOW 1
14369 +#define USB_SPEED_FULL 2
14370 +#define USB_SPEED_HIGH 3
14371 +#define USB_SPEED_VARIABLE 4
14372 +#define USB_SPEED_SUPER 5
14373 + int udi_power; /* power consumption in mA, 0 if selfpowered */
14375 + char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
14376 + u_int8_t udi_ports[16];/* hub only: addresses of devices on ports */
14377 +#define USB_PORT_ENABLED 0xff
14378 +#define USB_PORT_SUSPENDED 0xfe
14379 +#define USB_PORT_POWERED 0xfd
14380 +#define USB_PORT_DISABLED 0xfc
14383 +struct usb_ctl_report {
14385 + u_char ucr_data[1024]; /* filled data size will vary */
14388 +struct usb_device_stats {
14389 + u_long uds_requests[4]; /* indexed by transfer type UE_* */
14392 +#define WUSB_MIN_IE 0x80
14393 +#define WUSB_WCTA_IE 0x80
14394 +#define WUSB_WCONNECTACK_IE 0x81
14395 +#define WUSB_WHOSTINFO_IE 0x82
14396 +#define WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
14397 +#define WUHI_CA_RECONN 0x00
14398 +#define WUHI_CA_LIMITED 0x01
14399 +#define WUHI_CA_ALL 0x03
14400 +#define WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
14401 +#define WUSB_WCHCHANGEANNOUNCE_IE 0x83
14402 +#define WUSB_WDEV_DISCONNECT_IE 0x84
14403 +#define WUSB_WHOST_DISCONNECT_IE 0x85
14404 +#define WUSB_WRELEASE_CHANNEL_IE 0x86
14405 +#define WUSB_WWORK_IE 0x87
14406 +#define WUSB_WCHANNEL_STOP_IE 0x88
14407 +#define WUSB_WDEV_KEEPALIVE_IE 0x89
14408 +#define WUSB_WISOCH_DISCARD_IE 0x8A
14409 +#define WUSB_WRESETDEVICE_IE 0x8B
14410 +#define WUSB_WXMIT_PACKET_ADJUST_IE 0x8C
14411 +#define WUSB_MAX_IE 0x8C
14413 +/* Device Notification Types */
14415 +#define WUSB_DN_MIN 0x01
14416 +#define WUSB_DN_CONNECT 0x01
14417 +# define WUSB_DA_OLDCONN 0x00
14418 +# define WUSB_DA_NEWCONN 0x01
14419 +# define WUSB_DA_SELF_BEACON 0x02
14420 +# define WUSB_DA_DIR_BEACON 0x04
14421 +# define WUSB_DA_NO_BEACON 0x06
14422 +#define WUSB_DN_DISCONNECT 0x02
14423 +#define WUSB_DN_EPRDY 0x03
14424 +#define WUSB_DN_MASAVAILCHANGED 0x04
14425 +#define WUSB_DN_REMOTEWAKEUP 0x05
14426 +#define WUSB_DN_SLEEP 0x06
14427 +#define WUSB_DN_ALIVE 0x07
14428 +#define WUSB_DN_MAX 0x07
14431 +#include <pshpack1.h>
14434 +/* WUSB Handshake Data. Used during the SET/GET HANDSHAKE requests */
14435 +typedef struct wusb_hndshk_data {
14436 + uByte bMessageNumber;
14443 +} UPACKED wusb_hndshk_data_t;
14444 +#define WUSB_HANDSHAKE_LEN_FOR_MIC 38
14446 +/* WUSB Connection Context */
14447 +typedef struct wusb_conn_context {
14451 +} UPACKED wusb_conn_context_t;
14453 +/* WUSB Security Descriptor */
14454 +typedef struct wusb_security_desc {
14456 + uByte bDescriptorType;
14457 + uWord wTotalLength;
14458 + uByte bNumEncryptionTypes;
14459 +} UPACKED wusb_security_desc_t;
14461 +/* WUSB Encryption Type Descriptor */
14462 +typedef struct wusb_encrypt_type_desc {
14464 + uByte bDescriptorType;
14466 + uByte bEncryptionType;
14467 +#define WUETD_UNSECURE 0
14468 +#define WUETD_WIRED 1
14469 +#define WUETD_CCM_1 2
14470 +#define WUETD_RSA_1 3
14472 + uByte bEncryptionValue;
14473 + uByte bAuthKeyIndex;
14474 +} UPACKED wusb_encrypt_type_desc_t;
14476 +/* WUSB Key Descriptor */
14477 +typedef struct wusb_key_desc {
14479 + uByte bDescriptorType;
14482 + uByte KeyData[1]; /* variable length */
14483 +} UPACKED wusb_key_desc_t;
14485 +/* WUSB BOS Descriptor (Binary device Object Store) */
14486 +typedef struct wusb_bos_desc {
14488 + uByte bDescriptorType;
14489 + uWord wTotalLength;
14490 + uByte bNumDeviceCaps;
14491 +} UPACKED wusb_bos_desc_t;
14493 +#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02
14494 +typedef struct usb_dev_cap_20_ext_desc {
14496 + uByte bDescriptorType;
14497 + uByte bDevCapabilityType;
14498 +#define USB_20_EXT_LPM 0x02
14499 + uDWord bmAttributes;
14500 +} UPACKED usb_dev_cap_20_ext_desc_t;
14502 +#define USB_DEVICE_CAPABILITY_SS_USB 0x03
14503 +typedef struct usb_dev_cap_ss_usb {
14505 + uByte bDescriptorType;
14506 + uByte bDevCapabilityType;
14507 +#define USB_DC_SS_USB_LTM_CAPABLE 0x02
14508 + uByte bmAttributes;
14509 +#define USB_DC_SS_USB_SPEED_SUPPORT_LOW 0x01
14510 +#define USB_DC_SS_USB_SPEED_SUPPORT_FULL 0x02
14511 +#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH 0x04
14512 +#define USB_DC_SS_USB_SPEED_SUPPORT_SS 0x08
14513 + uWord wSpeedsSupported;
14514 + uByte bFunctionalitySupport;
14515 + uByte bU1DevExitLat;
14516 + uWord wU2DevExitLat;
14517 +} UPACKED usb_dev_cap_ss_usb_t;
14519 +#define USB_DEVICE_CAPABILITY_CONTAINER_ID 0x04
14520 +typedef struct usb_dev_cap_container_id {
14522 + uByte bDescriptorType;
14523 + uByte bDevCapabilityType;
14525 + uByte containerID[16];
14526 +} UPACKED usb_dev_cap_container_id_t;
14528 +/* Device Capability Type Codes */
14529 +#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
14531 +/* Device Capability Descriptor */
14532 +typedef struct wusb_dev_cap_desc {
14534 + uByte bDescriptorType;
14535 + uByte bDevCapabilityType;
14536 + uByte caps[1]; /* Variable length */
14537 +} UPACKED wusb_dev_cap_desc_t;
14539 +/* Device Capability Descriptor */
14540 +typedef struct wusb_dev_cap_uwb_desc {
14542 + uByte bDescriptorType;
14543 + uByte bDevCapabilityType;
14544 + uByte bmAttributes;
14545 + uWord wPHYRates; /* Bitmap */
14546 + uByte bmTFITXPowerInfo;
14547 + uByte bmFFITXPowerInfo;
14548 + uWord bmBandGroup;
14550 +} UPACKED wusb_dev_cap_uwb_desc_t;
14552 +/* Wireless USB Endpoint Companion Descriptor */
14553 +typedef struct wusb_endpoint_companion_desc {
14555 + uByte bDescriptorType;
14557 + uByte bMaxSequence;
14558 + uWord wMaxStreamDelay;
14559 + uWord wOverTheAirPacketSize;
14560 + uByte bOverTheAirInterval;
14561 + uByte bmCompAttributes;
14562 +} UPACKED wusb_endpoint_companion_desc_t;
14564 +/* Wireless USB Numeric Association M1 Data Structure */
14565 +typedef struct wusb_m1_data {
14568 + uByte deviceFriendlyNameLength;
14569 + uByte sha_256_m3[32];
14570 + uByte deviceFriendlyName[256];
14571 +} UPACKED wusb_m1_data_t;
14573 +typedef struct wusb_m2_data {
14576 + uByte hostFriendlyNameLength;
14578 + uByte hostFriendlyName[256];
14579 +} UPACKED wusb_m2_data_t;
14581 +typedef struct wusb_m3_data {
14584 +} UPACKED wusb_m3_data_t;
14586 +typedef struct wusb_m4_data {
14587 + uDWord _attributeTypeIdAndLength_1;
14588 + uWord associationTypeId;
14590 + uDWord _attributeTypeIdAndLength_2;
14591 + uWord associationSubTypeId;
14593 + uDWord _attributeTypeIdAndLength_3;
14596 + uDWord _attributeTypeIdAndLength_4;
14597 + uDWord associationStatus;
14599 + uDWord _attributeTypeIdAndLength_5;
14602 + uDWord _attributeTypeIdAndLength_6;
14605 + uDWord _attributeTypeIdAndLength_7;
14606 + uByte bandGroups[2];
14607 +} UPACKED wusb_m4_data_t;
14610 +#include <poppack.h>
14613 +#ifdef __cplusplus
14617 +#endif /* _USB_H_ */
14618 diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile
14619 new file mode 100644
14620 index 0000000..c4c6e4e
14622 +++ b/drivers/usb/host/dwc_otg/Makefile
14625 +# Makefile for DWC_otg Highspeed USB controller driver
14628 +ifneq ($(KERNELRELEASE),)
14630 +# Use the BUS_INTERFACE variable to compile the software for either
14631 +# PCI(PCI_INTERFACE) or LM(LM_INTERFACE) bus.
14632 +ifeq ($(BUS_INTERFACE),)
14633 +# BUS_INTERFACE = -DPCI_INTERFACE
14634 +# BUS_INTERFACE = -DLM_INTERFACE
14635 + BUS_INTERFACE = -DPLATFORM_INTERFACE
14638 +#EXTRA_CFLAGS += -DDEBUG
14639 +#EXTRA_CFLAGS += -DDWC_OTG_DEBUGLEV=1 # reduce common debug msgs
14641 +# Use one of the following flags to compile the software in host-only or
14642 +# device-only mode.
14643 +#EXTRA_CFLAGS += -DDWC_HOST_ONLY
14644 +#EXTRA_CFLAGS += -DDWC_DEVICE_ONLY
14646 +EXTRA_CFLAGS += -Dlinux -DDWC_HS_ELECT_TST
14647 +#EXTRA_CFLAGS += -DDWC_EN_ISOC
14648 +EXTRA_CFLAGS += -I$(obj)/../dwc_common_port
14649 +#EXTRA_CFLAGS += -I$(PORTLIB)
14650 +EXTRA_CFLAGS += -DDWC_LINUX
14651 +EXTRA_CFLAGS += $(CFI)
14652 +EXTRA_CFLAGS += $(BUS_INTERFACE)
14653 +#EXTRA_CFLAGS += -DDWC_DEV_SRPCAP
14655 +obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o
14657 +dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o
14658 +dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
14659 +dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o
14660 +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
14661 +dwc_otg-objs += dwc_otg_adp.o
14663 +dwc_otg-objs += dwc_otg_cfi.o
14666 +kernrelwd := $(subst ., ,$(KERNELRELEASE))
14667 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
14669 +ifneq ($(kernrel3),2.6.20)
14670 +EXTRA_CFLAGS += $(CPPFLAGS)
14675 +PWD := $(shell pwd)
14676 +PORTLIB := $(PWD)/../dwc_common_port
14680 +DOXYGEN := $(DOXYGEN)
14683 + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
14686 + $(MAKE) -C$(KDIR) M=$(PORTLIB) modules_install
14687 + $(MAKE) -C$(KDIR) M=$(PWD) modules_install
14690 + $(MAKE) -C$(KDIR) M=$(PORTLIB) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
14691 + cp $(PORTLIB)/Module.symvers $(PWD)/
14693 +docs: $(wildcard *.[hc]) doc/doxygen.cfg
14694 + $(DOXYGEN) doc/doxygen.cfg
14696 +tags: $(wildcard *.[hc])
14697 + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
14701 + rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers
14704 diff --git a/drivers/usb/host/dwc_otg/doc/doxygen.cfg b/drivers/usb/host/dwc_otg/doc/doxygen.cfg
14705 new file mode 100644
14706 index 0000000..537c676
14708 +++ b/drivers/usb/host/dwc_otg/doc/doxygen.cfg
14710 +# Doxyfile 1.3.9.1
14712 +#---------------------------------------------------------------------------
14713 +# Project related configuration options
14714 +#---------------------------------------------------------------------------
14715 +PROJECT_NAME = "DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver"
14716 +PROJECT_NUMBER = v3.00a
14717 +OUTPUT_DIRECTORY = ./doc/
14718 +CREATE_SUBDIRS = NO
14719 +OUTPUT_LANGUAGE = English
14720 +BRIEF_MEMBER_DESC = YES
14721 +REPEAT_BRIEF = YES
14722 +ABBREVIATE_BRIEF = "The $name class" \
14723 + "The $name widget" \
14724 + "The $name file" \
14733 +ALWAYS_DETAILED_SEC = NO
14734 +INLINE_INHERITED_MEMB = NO
14735 +FULL_PATH_NAMES = NO
14737 +STRIP_FROM_INC_PATH =
14739 +JAVADOC_AUTOBRIEF = YES
14740 +MULTILINE_CPP_IS_BRIEF = NO
14741 +INHERIT_DOCS = YES
14742 +DISTRIBUTE_GROUP_DOC = NO
14745 +OPTIMIZE_OUTPUT_FOR_C = YES
14746 +OPTIMIZE_OUTPUT_JAVA = NO
14748 +#---------------------------------------------------------------------------
14749 +# Build related configuration options
14750 +#---------------------------------------------------------------------------
14752 +EXTRACT_PRIVATE = YES
14753 +EXTRACT_STATIC = YES
14754 +EXTRACT_LOCAL_CLASSES = YES
14755 +EXTRACT_LOCAL_METHODS = NO
14756 +HIDE_UNDOC_MEMBERS = NO
14757 +HIDE_UNDOC_CLASSES = NO
14758 +HIDE_FRIEND_COMPOUNDS = NO
14759 +HIDE_IN_BODY_DOCS = NO
14760 +INTERNAL_DOCS = NO
14761 +CASE_SENSE_NAMES = NO
14762 +HIDE_SCOPE_NAMES = NO
14763 +SHOW_INCLUDE_FILES = YES
14765 +SORT_MEMBER_DOCS = NO
14766 +SORT_BRIEF_DOCS = NO
14767 +SORT_BY_SCOPE_NAME = NO
14768 +GENERATE_TODOLIST = YES
14769 +GENERATE_TESTLIST = YES
14770 +GENERATE_BUGLIST = YES
14771 +GENERATE_DEPRECATEDLIST= YES
14772 +ENABLED_SECTIONS =
14773 +MAX_INITIALIZER_LINES = 30
14774 +SHOW_USED_FILES = YES
14775 +SHOW_DIRECTORIES = YES
14776 +#---------------------------------------------------------------------------
14777 +# configuration options related to warning and progress messages
14778 +#---------------------------------------------------------------------------
14781 +WARN_IF_UNDOCUMENTED = NO
14782 +WARN_IF_DOC_ERROR = YES
14783 +WARN_FORMAT = "$file:$line: $text"
14785 +#---------------------------------------------------------------------------
14786 +# configuration options related to the input files
14787 +#---------------------------------------------------------------------------
14789 +FILE_PATTERNS = *.c \
14794 +EXCLUDE = ./test/ \
14795 + ./dwc_otg/.AppleDouble/
14796 +EXCLUDE_SYMLINKS = YES
14797 +EXCLUDE_PATTERNS = *.mod.*
14799 +EXAMPLE_PATTERNS = *
14800 +EXAMPLE_RECURSIVE = NO
14804 +FILTER_SOURCE_FILES = NO
14805 +#---------------------------------------------------------------------------
14806 +# configuration options related to source browsing
14807 +#---------------------------------------------------------------------------
14808 +SOURCE_BROWSER = YES
14809 +INLINE_SOURCES = NO
14810 +STRIP_CODE_COMMENTS = YES
14811 +REFERENCED_BY_RELATION = NO
14812 +REFERENCES_RELATION = NO
14813 +VERBATIM_HEADERS = NO
14814 +#---------------------------------------------------------------------------
14815 +# configuration options related to the alphabetical class index
14816 +#---------------------------------------------------------------------------
14817 +ALPHABETICAL_INDEX = NO
14818 +COLS_IN_ALPHA_INDEX = 5
14820 +#---------------------------------------------------------------------------
14821 +# configuration options related to the HTML output
14822 +#---------------------------------------------------------------------------
14823 +GENERATE_HTML = YES
14824 +HTML_OUTPUT = html
14825 +HTML_FILE_EXTENSION = .html
14829 +HTML_ALIGN_MEMBERS = YES
14830 +GENERATE_HTMLHELP = NO
14836 +DISABLE_INDEX = NO
14837 +ENUM_VALUES_PER_LINE = 4
14838 +GENERATE_TREEVIEW = YES
14839 +TREEVIEW_WIDTH = 250
14840 +#---------------------------------------------------------------------------
14841 +# configuration options related to the LaTeX output
14842 +#---------------------------------------------------------------------------
14843 +GENERATE_LATEX = NO
14844 +LATEX_OUTPUT = latex
14845 +LATEX_CMD_NAME = latex
14846 +MAKEINDEX_CMD_NAME = makeindex
14847 +COMPACT_LATEX = NO
14848 +PAPER_TYPE = a4wide
14851 +PDF_HYPERLINKS = NO
14853 +LATEX_BATCHMODE = NO
14854 +LATEX_HIDE_INDICES = NO
14855 +#---------------------------------------------------------------------------
14856 +# configuration options related to the RTF output
14857 +#---------------------------------------------------------------------------
14861 +RTF_HYPERLINKS = NO
14862 +RTF_STYLESHEET_FILE =
14863 +RTF_EXTENSIONS_FILE =
14864 +#---------------------------------------------------------------------------
14865 +# configuration options related to the man page output
14866 +#---------------------------------------------------------------------------
14869 +MAN_EXTENSION = .3
14871 +#---------------------------------------------------------------------------
14872 +# configuration options related to the XML output
14873 +#---------------------------------------------------------------------------
14878 +XML_PROGRAMLISTING = YES
14879 +#---------------------------------------------------------------------------
14880 +# configuration options for the AutoGen Definitions output
14881 +#---------------------------------------------------------------------------
14882 +GENERATE_AUTOGEN_DEF = NO
14883 +#---------------------------------------------------------------------------
14884 +# configuration options related to the Perl module output
14885 +#---------------------------------------------------------------------------
14886 +GENERATE_PERLMOD = NO
14887 +PERLMOD_LATEX = NO
14888 +PERLMOD_PRETTY = YES
14889 +PERLMOD_MAKEVAR_PREFIX =
14890 +#---------------------------------------------------------------------------
14891 +# Configuration options related to the preprocessor
14892 +#---------------------------------------------------------------------------
14893 +ENABLE_PREPROCESSING = YES
14894 +MACRO_EXPANSION = YES
14895 +EXPAND_ONLY_PREDEF = YES
14896 +SEARCH_INCLUDES = YES
14898 +INCLUDE_FILE_PATTERNS =
14899 +PREDEFINED = DEVICE_ATTR DWC_EN_ISOC
14900 +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
14901 +SKIP_FUNCTION_MACROS = NO
14902 +#---------------------------------------------------------------------------
14903 +# Configuration::additions related to external references
14904 +#---------------------------------------------------------------------------
14906 +GENERATE_TAGFILE =
14908 +EXTERNAL_GROUPS = YES
14909 +PERL_PATH = /usr/bin/perl
14910 +#---------------------------------------------------------------------------
14911 +# Configuration options related to the dot tool
14912 +#---------------------------------------------------------------------------
14913 +CLASS_DIAGRAMS = YES
14914 +HIDE_UNDOC_RELATIONS = YES
14917 +COLLABORATION_GRAPH = YES
14919 +TEMPLATE_RELATIONS = NO
14920 +INCLUDE_GRAPH = YES
14921 +INCLUDED_BY_GRAPH = YES
14923 +GRAPHICAL_HIERARCHY = YES
14924 +DOT_IMAGE_FORMAT = png
14927 +MAX_DOT_GRAPH_DEPTH = 1000
14928 +GENERATE_LEGEND = YES
14930 +#---------------------------------------------------------------------------
14931 +# Configuration::additions related to the search engine
14932 +#---------------------------------------------------------------------------
14934 diff --git a/drivers/usb/host/dwc_otg/dummy_audio.c b/drivers/usb/host/dwc_otg/dummy_audio.c
14935 new file mode 100644
14936 index 0000000..530ac8b
14938 +++ b/drivers/usb/host/dwc_otg/dummy_audio.c
14941 + * zero.c -- Gadget Zero, for USB development
14943 + * Copyright (C) 2003-2004 David Brownell
14944 + * All rights reserved.
14946 + * Redistribution and use in source and binary forms, with or without
14947 + * modification, are permitted provided that the following conditions
14949 + * 1. Redistributions of source code must retain the above copyright
14950 + * notice, this list of conditions, and the following disclaimer,
14951 + * without modification.
14952 + * 2. Redistributions in binary form must reproduce the above copyright
14953 + * notice, this list of conditions and the following disclaimer in the
14954 + * documentation and/or other materials provided with the distribution.
14955 + * 3. The names of the above-listed copyright holders may not be used
14956 + * to endorse or promote products derived from this software without
14957 + * specific prior written permission.
14959 + * ALTERNATIVELY, this software may be distributed under the terms of the
14960 + * GNU General Public License ("GPL") as published by the Free Software
14961 + * Foundation, either version 2 of that License or (at your option) any
14964 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
14965 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14966 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14967 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
14968 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
14969 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
14970 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
14971 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
14972 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
14973 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
14974 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14979 + * Gadget Zero only needs two bulk endpoints, and is an example of how you
14980 + * can write a hardware-agnostic gadget driver running inside a USB device.
14982 + * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
14983 + * affect most of the driver.
14985 + * Use it with the Linux host/master side "usbtest" driver to get a basic
14986 + * functional test of your device-side usb stack, or with "usb-skeleton".
14988 + * It supports two similar configurations. One sinks whatever the usb host
14989 + * writes, and in return sources zeroes. The other loops whatever the host
14990 + * writes back, so the host can read it. Module options include:
14992 + * buflen=N default N=4096, buffer size used
14993 + * qlen=N default N=32, how many buffers in the loopback queue
14994 + * loopdefault default false, list loopback config first
14996 + * Many drivers will only have one configuration, letting them be much
14997 + * simpler if they also don't support high speed operation (like this
15001 +#include <linux/config.h>
15002 +#include <linux/module.h>
15003 +#include <linux/kernel.h>
15004 +#include <linux/delay.h>
15005 +#include <linux/ioport.h>
15006 +#include <linux/sched.h>
15007 +#include <linux/slab.h>
15008 +#include <linux/smp_lock.h>
15009 +#include <linux/errno.h>
15010 +#include <linux/init.h>
15011 +#include <linux/timer.h>
15012 +#include <linux/list.h>
15013 +#include <linux/interrupt.h>
15014 +#include <linux/uts.h>
15015 +#include <linux/version.h>
15016 +#include <linux/device.h>
15017 +#include <linux/moduleparam.h>
15018 +#include <linux/proc_fs.h>
15020 +#include <asm/byteorder.h>
15021 +#include <asm/io.h>
15022 +#include <asm/irq.h>
15023 +#include <asm/system.h>
15024 +#include <asm/unaligned.h>
15026 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
15027 +# include <linux/usb/ch9.h>
15029 +# include <linux/usb_ch9.h>
15032 +#include <linux/usb_gadget.h>
15035 +/*-------------------------------------------------------------------------*/
15036 +/*-------------------------------------------------------------------------*/
15039 +static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
15045 + /* this insists on correct encodings, though not minimal ones.
15046 + * BUT it currently rejects legit 4-byte UTF-8 code points,
15047 + * which need surrogate pairs. (Unicode 3.1 can use them.)
15049 + while (len != 0 && (c = (u8) *s++) != 0) {
15050 + if (unlikely(c & 0x80)) {
15051 + // 2-byte sequence:
15052 + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
15053 + if ((c & 0xe0) == 0xc0) {
15054 + uchar = (c & 0x1f) << 6;
15057 + if ((c & 0xc0) != 0xc0)
15062 + // 3-byte sequence (most CJKV characters):
15063 + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
15064 + } else if ((c & 0xf0) == 0xe0) {
15065 + uchar = (c & 0x0f) << 12;
15068 + if ((c & 0xc0) != 0xc0)
15074 + if ((c & 0xc0) != 0xc0)
15079 + /* no bogus surrogates */
15080 + if (0xd800 <= uchar && uchar <= 0xdfff)
15083 + // 4-byte sequence (surrogate pairs, currently rare):
15084 + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
15085 + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
15086 + // (uuuuu = wwww + 1)
15087 + // FIXME accept the surrogate code points (only)
15093 + put_unaligned (cpu_to_le16 (uchar), cp++);
15104 + * usb_gadget_get_string - fill out a string descriptor
15105 + * @table: of c strings encoded using UTF-8
15106 + * @id: string id, from low byte of wValue in get string descriptor
15107 + * @buf: at least 256 bytes
15109 + * Finds the UTF-8 string matching the ID, and converts it into a
15110 + * string descriptor in utf16-le.
15111 + * Returns length of descriptor (always even) or negative errno
15113 + * If your driver needs stings in multiple languages, you'll probably
15114 + * "switch (wIndex) { ... }" in your ep0 string descriptor logic,
15115 + * using this routine after choosing which set of UTF-8 strings to use.
15116 + * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
15117 + * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
15118 + * characters (which are also widely used in C strings).
15121 +usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
15123 + struct usb_string *s;
15126 + /* descriptor 0 has the language id */
15129 + buf [1] = USB_DT_STRING;
15130 + buf [2] = (u8) table->language;
15131 + buf [3] = (u8) (table->language >> 8);
15134 + for (s = table->strings; s && s->s; s++)
15138 + /* unrecognized: stall. */
15142 + /* string descriptors have length, tag, then UTF16-LE text */
15143 + len = min ((size_t) 126, strlen (s->s));
15144 + memset (buf + 2, 0, 2 * len); /* zero all the bytes */
15145 + len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
15148 + buf [0] = (len + 1) * 2;
15149 + buf [1] = USB_DT_STRING;
15154 +/*-------------------------------------------------------------------------*/
15155 +/*-------------------------------------------------------------------------*/
15159 + * usb_descriptor_fillbuf - fill buffer with descriptors
15160 + * @buf: Buffer to be filled
15161 + * @buflen: Size of buf
15162 + * @src: Array of descriptor pointers, terminated by null pointer.
15164 + * Copies descriptors into the buffer, returning the length or a
15165 + * negative error code if they can't all be copied. Useful when
15166 + * assembling descriptors for an associated set of interfaces used
15167 + * as part of configuring a composite device; or in other cases where
15168 + * sets of descriptors need to be marshaled.
15171 +usb_descriptor_fillbuf(void *buf, unsigned buflen,
15172 + const struct usb_descriptor_header **src)
15179 + /* fill buffer from src[] until null descriptor ptr */
15180 + for (; 0 != *src; src++) {
15181 + unsigned len = (*src)->bLength;
15183 + if (len > buflen)
15185 + memcpy(dest, *src, len);
15189 + return dest - (u8 *)buf;
15194 + * usb_gadget_config_buf - builts a complete configuration descriptor
15195 + * @config: Header for the descriptor, including characteristics such
15196 + * as power requirements and number of interfaces.
15197 + * @desc: Null-terminated vector of pointers to the descriptors (interface,
15198 + * endpoint, etc) defining all functions in this device configuration.
15199 + * @buf: Buffer for the resulting configuration descriptor.
15200 + * @length: Length of buffer. If this is not big enough to hold the
15201 + * entire configuration descriptor, an error code will be returned.
15203 + * This copies descriptors into the response buffer, building a descriptor
15204 + * for that configuration. It returns the buffer length or a negative
15205 + * status code. The config.wTotalLength field is set to match the length
15206 + * of the result, but other descriptor fields (including power usage and
15207 + * interface count) must be set by the caller.
15209 + * Gadget drivers could use this when constructing a config descriptor
15210 + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
15211 + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
15213 +int usb_gadget_config_buf(
15214 + const struct usb_config_descriptor *config,
15217 + const struct usb_descriptor_header **desc
15220 + struct usb_config_descriptor *cp = buf;
15223 + /* config descriptor first */
15224 + if (length < USB_DT_CONFIG_SIZE || !desc)
15228 + /* then interface/endpoint/class/vendor/... */
15229 + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
15230 + length - USB_DT_CONFIG_SIZE, desc);
15233 + len += USB_DT_CONFIG_SIZE;
15234 + if (len > 0xffff)
15237 + /* patch up the config descriptor */
15238 + cp->bLength = USB_DT_CONFIG_SIZE;
15239 + cp->bDescriptorType = USB_DT_CONFIG;
15240 + cp->wTotalLength = cpu_to_le16(len);
15241 + cp->bmAttributes |= USB_CONFIG_ATT_ONE;
15245 +/*-------------------------------------------------------------------------*/
15246 +/*-------------------------------------------------------------------------*/
15249 +#define RBUF_LEN (1024*1024)
15250 +static int rbuf_start;
15251 +static int rbuf_len;
15252 +static __u8 rbuf[RBUF_LEN];
15254 +/*-------------------------------------------------------------------------*/
15256 +#define DRIVER_VERSION "St Patrick's Day 2004"
15258 +static const char shortname [] = "zero";
15259 +static const char longname [] = "YAMAHA YST-MS35D USB Speaker ";
15261 +static const char source_sink [] = "source and sink data";
15262 +static const char loopback [] = "loop input to output";
15264 +/*-------------------------------------------------------------------------*/
15267 + * driver assumes self-powered hardware, and
15268 + * has no way for users to trigger remote wakeup.
15270 + * this version autoconfigures as much as possible,
15271 + * which is reasonable for most "bulk-only" drivers.
15273 +static const char *EP_IN_NAME; /* source */
15274 +static const char *EP_OUT_NAME; /* sink */
15276 +/*-------------------------------------------------------------------------*/
15278 +/* big enough to hold our biggest descriptor */
15279 +#define USB_BUFSIZ 512
15283 + struct usb_gadget *gadget;
15284 + struct usb_request *req; /* for control responses */
15286 + /* when configured, we have one of two configs:
15287 + * - source data (in to host) and sink it (out from host)
15288 + * - or loop it back (out from host back in to host)
15291 + struct usb_ep *in_ep, *out_ep;
15293 + /* autoresume timer */
15294 + struct timer_list resume;
15297 +#define xprintk(d,level,fmt,args...) \
15298 + dev_printk(level , &(d)->gadget->dev , fmt , ## args)
15301 +#define DBG(dev,fmt,args...) \
15302 + xprintk(dev , KERN_DEBUG , fmt , ## args)
15304 +#define DBG(dev,fmt,args...) \
15306 +#endif /* DEBUG */
15311 +#define VDBG(dev,fmt,args...) \
15313 +#endif /* VERBOSE */
15315 +#define ERROR(dev,fmt,args...) \
15316 + xprintk(dev , KERN_ERR , fmt , ## args)
15317 +#define WARN(dev,fmt,args...) \
15318 + xprintk(dev , KERN_WARNING , fmt , ## args)
15319 +#define INFO(dev,fmt,args...) \
15320 + xprintk(dev , KERN_INFO , fmt , ## args)
15322 +/*-------------------------------------------------------------------------*/
15324 +static unsigned buflen = 4096;
15325 +static unsigned qlen = 32;
15326 +static unsigned pattern = 0;
15328 +module_param (buflen, uint, S_IRUGO|S_IWUSR);
15329 +module_param (qlen, uint, S_IRUGO|S_IWUSR);
15330 +module_param (pattern, uint, S_IRUGO|S_IWUSR);
15333 + * if it's nonzero, autoresume says how many seconds to wait
15334 + * before trying to wake up the host after suspend.
15336 +static unsigned autoresume = 0;
15337 +module_param (autoresume, uint, 0);
15340 + * Normally the "loopback" configuration is second (index 1) so
15341 + * it's not the default. Here's where to change that order, to
15342 + * work better with hosts where config changes are problematic.
15343 + * Or controllers (like superh) that only support one config.
15345 +static int loopdefault = 0;
15347 +module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
15349 +/*-------------------------------------------------------------------------*/
15351 +/* Thanks to NetChip Technologies for donating this product ID.
15353 + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
15354 + * Instead: allocate your own, using normal USB-IF procedures.
15356 +#ifndef CONFIG_USB_ZERO_HNPTEST
15357 +#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
15358 +#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
15360 +#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
15361 +#define DRIVER_PRODUCT_NUM 0xbadd
15364 +/*-------------------------------------------------------------------------*/
15367 + * DESCRIPTORS ... most are static, but strings and (full)
15368 + * configuration descriptors are built on demand.
15372 +#define STRING_MANUFACTURER 25
15373 +#define STRING_PRODUCT 42
15374 +#define STRING_SERIAL 101
15376 +#define STRING_MANUFACTURER 1
15377 +#define STRING_PRODUCT 2
15378 +#define STRING_SERIAL 3
15380 +#define STRING_SOURCE_SINK 250
15381 +#define STRING_LOOPBACK 251
15384 + * This device advertises two configurations; these numbers work
15385 + * on a pxa250 as well as more flexible hardware.
15387 +#define CONFIG_SOURCE_SINK 3
15388 +#define CONFIG_LOOPBACK 2
15391 +static struct usb_device_descriptor
15393 + .bLength = sizeof device_desc,
15394 + .bDescriptorType = USB_DT_DEVICE,
15396 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
15397 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
15399 + .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
15400 + .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
15401 + .iManufacturer = STRING_MANUFACTURER,
15402 + .iProduct = STRING_PRODUCT,
15403 + .iSerialNumber = STRING_SERIAL,
15404 + .bNumConfigurations = 2,
15407 +static struct usb_device_descriptor
15409 + .bLength = sizeof device_desc,
15410 + .bDescriptorType = USB_DT_DEVICE,
15411 + .bcdUSB = __constant_cpu_to_le16 (0x0100),
15412 + .bDeviceClass = USB_CLASS_PER_INTERFACE,
15413 + .bDeviceSubClass = 0,
15414 + .bDeviceProtocol = 0,
15415 + .bMaxPacketSize0 = 64,
15416 + .bcdDevice = __constant_cpu_to_le16 (0x0100),
15417 + .idVendor = __constant_cpu_to_le16 (0x0499),
15418 + .idProduct = __constant_cpu_to_le16 (0x3002),
15419 + .iManufacturer = STRING_MANUFACTURER,
15420 + .iProduct = STRING_PRODUCT,
15421 + .iSerialNumber = STRING_SERIAL,
15422 + .bNumConfigurations = 1,
15425 +static struct usb_config_descriptor
15427 + .bLength = sizeof z_config,
15428 + .bDescriptorType = USB_DT_CONFIG,
15430 + /* compute wTotalLength on the fly */
15431 + .bNumInterfaces = 2,
15432 + .bConfigurationValue = 1,
15433 + .iConfiguration = 0,
15434 + .bmAttributes = 0x40,
15435 + .bMaxPower = 0, /* self-powered */
15439 +static struct usb_otg_descriptor
15440 +otg_descriptor = {
15441 + .bLength = sizeof otg_descriptor,
15442 + .bDescriptorType = USB_DT_OTG,
15444 + .bmAttributes = USB_OTG_SRP,
15447 +/* one interface in each configuration */
15448 +#ifdef CONFIG_USB_GADGET_DUALSPEED
15451 + * usb 2.0 devices need to expose both high speed and full speed
15452 + * descriptors, unless they only run at full speed.
15454 + * that means alternate endpoint descriptors (bigger packets)
15455 + * and a "device qualifier" ... plus more construction options
15456 + * for the config descriptor.
15459 +static struct usb_qualifier_descriptor
15461 + .bLength = sizeof dev_qualifier,
15462 + .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
15464 + .bcdUSB = __constant_cpu_to_le16 (0x0200),
15465 + .bDeviceClass = USB_CLASS_VENDOR_SPEC,
15467 + .bNumConfigurations = 2,
15471 +struct usb_cs_as_general_descriptor {
15473 + __u8 bDescriptorType;
15475 + __u8 bDescriptorSubType;
15476 + __u8 bTerminalLink;
15478 + __u16 wFormatTag;
15479 +} __attribute__ ((packed));
15481 +struct usb_cs_as_format_descriptor {
15483 + __u8 bDescriptorType;
15485 + __u8 bDescriptorSubType;
15486 + __u8 bFormatType;
15487 + __u8 bNrChannels;
15488 + __u8 bSubframeSize;
15489 + __u8 bBitResolution;
15490 + __u8 bSamfreqType;
15491 + __u8 tLowerSamFreq[3];
15492 + __u8 tUpperSamFreq[3];
15493 +} __attribute__ ((packed));
15495 +static const struct usb_interface_descriptor
15496 +z_audio_control_if_desc = {
15497 + .bLength = sizeof z_audio_control_if_desc,
15498 + .bDescriptorType = USB_DT_INTERFACE,
15499 + .bInterfaceNumber = 0,
15500 + .bAlternateSetting = 0,
15501 + .bNumEndpoints = 0,
15502 + .bInterfaceClass = USB_CLASS_AUDIO,
15503 + .bInterfaceSubClass = 0x1,
15504 + .bInterfaceProtocol = 0,
15508 +static const struct usb_interface_descriptor
15509 +z_audio_if_desc = {
15510 + .bLength = sizeof z_audio_if_desc,
15511 + .bDescriptorType = USB_DT_INTERFACE,
15512 + .bInterfaceNumber = 1,
15513 + .bAlternateSetting = 0,
15514 + .bNumEndpoints = 0,
15515 + .bInterfaceClass = USB_CLASS_AUDIO,
15516 + .bInterfaceSubClass = 0x2,
15517 + .bInterfaceProtocol = 0,
15521 +static const struct usb_interface_descriptor
15522 +z_audio_if_desc2 = {
15523 + .bLength = sizeof z_audio_if_desc,
15524 + .bDescriptorType = USB_DT_INTERFACE,
15525 + .bInterfaceNumber = 1,
15526 + .bAlternateSetting = 1,
15527 + .bNumEndpoints = 1,
15528 + .bInterfaceClass = USB_CLASS_AUDIO,
15529 + .bInterfaceSubClass = 0x2,
15530 + .bInterfaceProtocol = 0,
15534 +static const struct usb_cs_as_general_descriptor
15535 +z_audio_cs_as_if_desc = {
15537 + .bDescriptorType = 0x24,
15539 + .bDescriptorSubType = 0x01,
15540 + .bTerminalLink = 0x01,
15542 + .wFormatTag = __constant_cpu_to_le16 (0x0001)
15546 +static const struct usb_cs_as_format_descriptor
15547 +z_audio_cs_as_format_desc = {
15549 + .bDescriptorType = 0x24,
15551 + .bDescriptorSubType = 2,
15552 + .bFormatType = 1,
15553 + .bNrChannels = 1,
15554 + .bSubframeSize = 1,
15555 + .bBitResolution = 8,
15556 + .bSamfreqType = 0,
15557 + .tLowerSamFreq = {0x7e, 0x13, 0x00},
15558 + .tUpperSamFreq = {0xe2, 0xd6, 0x00},
15561 +static const struct usb_endpoint_descriptor
15564 + .bDescriptorType = 0x05,
15565 + .bEndpointAddress = 0x04,
15566 + .bmAttributes = 0x09,
15567 + .wMaxPacketSize = 0x0038,
15568 + .bInterval = 0x01,
15569 + .bRefresh = 0x00,
15570 + .bSynchAddress = 0x00,
15573 +static char z_iso_ep2[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15576 +static char z_ac_interface_header_desc[] =
15577 +{ 0x09, 0x24, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x01, 0x01 };
15580 +static char z_0[] = {0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
15581 + 0x03, 0x00, 0x00, 0x00};
15583 +static char z_1[] = {0x0d, 0x24, 0x06, 0x02, 0x01, 0x02, 0x15, 0x00,
15584 + 0x02, 0x00, 0x02, 0x00, 0x00};
15586 +static char z_2[] = {0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x02,
15589 +static char za_0[] = {0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00,
15592 +static char za_1[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15594 +static char za_2[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x01, 0x08, 0x00,
15595 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15597 +static char za_3[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
15600 +static char za_4[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15602 +static char za_5[] = {0x09, 0x04, 0x01, 0x03, 0x01, 0x01, 0x02, 0x00,
15605 +static char za_6[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15607 +static char za_7[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x00,
15608 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15610 +static char za_8[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
15613 +static char za_9[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15615 +static char za_10[] = {0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00,
15618 +static char za_11[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15620 +static char za_12[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00,
15621 + 0x73, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15623 +static char za_13[] = {0x09, 0x05, 0x04, 0x09, 0xe0, 0x00, 0x01, 0x00,
15626 +static char za_14[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15628 +static char za_15[] = {0x09, 0x04, 0x01, 0x05, 0x01, 0x01, 0x02, 0x00,
15631 +static char za_16[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15633 +static char za_17[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x03, 0x14, 0x00,
15634 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15636 +static char za_18[] = {0x09, 0x05, 0x04, 0x09, 0xa8, 0x00, 0x01, 0x00,
15639 +static char za_19[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15641 +static char za_20[] = {0x09, 0x04, 0x01, 0x06, 0x01, 0x01, 0x02, 0x00,
15644 +static char za_21[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
15646 +static char za_22[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x03, 0x14, 0x00,
15647 + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
15649 +static char za_23[] = {0x09, 0x05, 0x04, 0x09, 0x50, 0x01, 0x01, 0x00,
15652 +static char za_24[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
15656 +static const struct usb_descriptor_header *z_function [] = {
15657 + (struct usb_descriptor_header *) &z_audio_control_if_desc,
15658 + (struct usb_descriptor_header *) &z_ac_interface_header_desc,
15659 + (struct usb_descriptor_header *) &z_0,
15660 + (struct usb_descriptor_header *) &z_1,
15661 + (struct usb_descriptor_header *) &z_2,
15662 + (struct usb_descriptor_header *) &z_audio_if_desc,
15663 + (struct usb_descriptor_header *) &z_audio_if_desc2,
15664 + (struct usb_descriptor_header *) &z_audio_cs_as_if_desc,
15665 + (struct usb_descriptor_header *) &z_audio_cs_as_format_desc,
15666 + (struct usb_descriptor_header *) &z_iso_ep,
15667 + (struct usb_descriptor_header *) &z_iso_ep2,
15668 + (struct usb_descriptor_header *) &za_0,
15669 + (struct usb_descriptor_header *) &za_1,
15670 + (struct usb_descriptor_header *) &za_2,
15671 + (struct usb_descriptor_header *) &za_3,
15672 + (struct usb_descriptor_header *) &za_4,
15673 + (struct usb_descriptor_header *) &za_5,
15674 + (struct usb_descriptor_header *) &za_6,
15675 + (struct usb_descriptor_header *) &za_7,
15676 + (struct usb_descriptor_header *) &za_8,
15677 + (struct usb_descriptor_header *) &za_9,
15678 + (struct usb_descriptor_header *) &za_10,
15679 + (struct usb_descriptor_header *) &za_11,
15680 + (struct usb_descriptor_header *) &za_12,
15681 + (struct usb_descriptor_header *) &za_13,
15682 + (struct usb_descriptor_header *) &za_14,
15683 + (struct usb_descriptor_header *) &za_15,
15684 + (struct usb_descriptor_header *) &za_16,
15685 + (struct usb_descriptor_header *) &za_17,
15686 + (struct usb_descriptor_header *) &za_18,
15687 + (struct usb_descriptor_header *) &za_19,
15688 + (struct usb_descriptor_header *) &za_20,
15689 + (struct usb_descriptor_header *) &za_21,
15690 + (struct usb_descriptor_header *) &za_22,
15691 + (struct usb_descriptor_header *) &za_23,
15692 + (struct usb_descriptor_header *) &za_24,
15696 +/* maxpacket and other transfer characteristics vary by speed. */
15697 +#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
15701 +/* if there's no high speed support, maxpacket doesn't change. */
15702 +#define ep_desc(g,hs,fs) fs
15704 +#endif /* !CONFIG_USB_GADGET_DUALSPEED */
15706 +static char manufacturer [40];
15707 +//static char serial [40];
15708 +static char serial [] = "Ser 00 em";
15710 +/* static strings, in UTF-8 */
15711 +static struct usb_string strings [] = {
15712 + { STRING_MANUFACTURER, manufacturer, },
15713 + { STRING_PRODUCT, longname, },
15714 + { STRING_SERIAL, serial, },
15715 + { STRING_LOOPBACK, loopback, },
15716 + { STRING_SOURCE_SINK, source_sink, },
15717 + { } /* end of list */
15720 +static struct usb_gadget_strings stringtab = {
15721 + .language = 0x0409, /* en-us */
15722 + .strings = strings,
15726 + * config descriptors are also handcrafted. these must agree with code
15727 + * that sets configurations, and with code managing interfaces and their
15728 + * altsettings. other complexity may come from:
15730 + * - high speed support, including "other speed config" rules
15731 + * - multiple configurations
15732 + * - interfaces with alternate settings
15733 + * - embedded class or vendor-specific descriptors
15735 + * this handles high speed, and has a second config that could as easily
15736 + * have been an alternate interface setting (on most hardware).
15738 + * NOTE: to demonstrate (and test) more USB capabilities, this driver
15739 + * should include an altsetting to test interrupt transfers, including
15740 + * high bandwidth modes at high speed. (Maybe work like Intel's test
15744 +config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index)
15747 + const struct usb_descriptor_header **function;
15749 + function = z_function;
15750 + len = usb_gadget_config_buf (&z_config, buf, USB_BUFSIZ, function);
15753 + ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
15757 +/*-------------------------------------------------------------------------*/
15759 +static struct usb_request *
15760 +alloc_ep_req (struct usb_ep *ep, unsigned length)
15762 + struct usb_request *req;
15764 + req = usb_ep_alloc_request (ep, GFP_ATOMIC);
15766 + req->length = length;
15767 + req->buf = usb_ep_alloc_buffer (ep, length,
15768 + &req->dma, GFP_ATOMIC);
15770 + usb_ep_free_request (ep, req);
15777 +static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
15780 + usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
15781 + usb_ep_free_request (ep, req);
15784 +/*-------------------------------------------------------------------------*/
15786 +/* optionally require specific source/sink data patterns */
15790 + struct zero_dev *dev,
15791 + struct usb_ep *ep,
15792 + struct usb_request *req
15796 + u8 *buf = req->buf;
15798 + for (i = 0; i < req->actual; i++, buf++) {
15799 + switch (pattern) {
15800 + /* all-zeroes has no synchronization issues */
15805 + /* mod63 stays in sync with short-terminated transfers,
15806 + * or otherwise when host and gadget agree on how large
15807 + * each usb transfer request should be. resync is done
15808 + * with set_interface or set_config.
15811 + if (*buf == (u8)(i % 63))
15815 + ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
15816 + usb_ep_set_halt (ep);
15822 +/*-------------------------------------------------------------------------*/
15824 +static void zero_reset_config (struct zero_dev *dev)
15826 + if (dev->config == 0)
15829 + DBG (dev, "reset config\n");
15831 + /* just disable endpoints, forcing completion of pending i/o.
15832 + * all our completion handlers free their requests in this case.
15834 + if (dev->in_ep) {
15835 + usb_ep_disable (dev->in_ep);
15836 + dev->in_ep = NULL;
15838 + if (dev->out_ep) {
15839 + usb_ep_disable (dev->out_ep);
15840 + dev->out_ep = NULL;
15843 + del_timer (&dev->resume);
15846 +#define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
15849 +zero_isoc_complete (struct usb_ep *ep, struct usb_request *req)
15851 + struct zero_dev *dev = ep->driver_data;
15852 + int status = req->status;
15855 + switch (status) {
15857 + case 0: /* normal completion? */
15858 + //printk ("\nzero ---------------> isoc normal completion %d bytes\n", req->actual);
15859 + for (i=0, j=rbuf_start; i<req->actual; i++) {
15860 + //printk ("%02x ", ((__u8*)req->buf)[i]);
15861 + rbuf[j] = ((__u8*)req->buf)[i];
15863 + if (j >= RBUF_LEN) j=0;
15866 + //printk ("\n\n");
15868 + if (rbuf_len < RBUF_LEN) {
15869 + rbuf_len += req->actual;
15870 + if (rbuf_len > RBUF_LEN) {
15871 + rbuf_len = RBUF_LEN;
15877 + /* this endpoint is normally active while we're configured */
15878 + case -ECONNABORTED: /* hardware forced ep reset */
15879 + case -ECONNRESET: /* request dequeued */
15880 + case -ESHUTDOWN: /* disconnect from host */
15881 + VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
15882 + req->actual, req->length);
15883 + if (ep == dev->out_ep)
15884 + check_read_data (dev, ep, req);
15885 + free_ep_req (ep, req);
15888 + case -EOVERFLOW: /* buffer overrun on read means that
15889 + * we didn't provide a big enough
15894 + DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
15895 + status, req->actual, req->length);
15897 + case -EREMOTEIO: /* short read */
15901 + status = usb_ep_queue (ep, req, GFP_ATOMIC);
15903 + ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
15904 + ep->name, req->length, status);
15905 + usb_ep_set_halt (ep);
15906 + /* FIXME recover later ... somehow */
15910 +static struct usb_request *
15911 +zero_start_isoc_ep (struct usb_ep *ep, int gfp_flags)
15913 + struct usb_request *req;
15916 + req = alloc_ep_req (ep, 512);
15920 + req->complete = zero_isoc_complete;
15922 + status = usb_ep_queue (ep, req, gfp_flags);
15924 + struct zero_dev *dev = ep->driver_data;
15926 + ERROR (dev, "start %s --> %d\n", ep->name, status);
15927 + free_ep_req (ep, req);
15934 +/* change our operational config. this code must agree with the code
15935 + * that returns config descriptors, and altsetting code.
15937 + * it's also responsible for power management interactions. some
15938 + * configurations might not work with our current power sources.
15940 + * note that some device controller hardware will constrain what this
15941 + * code can do, perhaps by disallowing more than one configuration or
15942 + * by limiting configuration choices (like the pxa2xx).
15945 +zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
15948 + struct usb_gadget *gadget = dev->gadget;
15949 + const struct usb_endpoint_descriptor *d;
15950 + struct usb_ep *ep;
15952 + if (number == dev->config)
15955 + zero_reset_config (dev);
15957 + gadget_for_each_ep (ep, gadget) {
15959 + if (strcmp (ep->name, "ep4") == 0) {
15961 + d = (struct usb_endpoint_descripter *)&za_23; // isoc ep desc for audio i/f alt setting 6
15962 + result = usb_ep_enable (ep, d);
15964 + if (result == 0) {
15965 + ep->driver_data = dev;
15968 + if (zero_start_isoc_ep (ep, gfp_flags) != 0) {
15974 + usb_ep_disable (ep);
15981 + dev->config = number;
15985 +/*-------------------------------------------------------------------------*/
15987 +static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
15989 + if (req->status || req->actual != req->length)
15990 + DBG ((struct zero_dev *) ep->driver_data,
15991 + "setup complete --> %d, %d/%d\n",
15992 + req->status, req->actual, req->length);
15996 + * The setup() callback implements all the ep0 functionality that's
15997 + * not handled lower down, in hardware or the hardware driver (like
15998 + * device and endpoint feature flags, and their status). It's all
15999 + * housekeeping for the gadget function we're implementing. Most of
16000 + * the work is in config-specific setup.
16003 +zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
16005 + struct zero_dev *dev = get_gadget_data (gadget);
16006 + struct usb_request *req = dev->req;
16007 + int value = -EOPNOTSUPP;
16009 + /* usually this stores reply data in the pre-allocated ep0 buffer,
16010 + * but config change events will reconfigure hardware.
16013 + switch (ctrl->bRequest) {
16015 + case USB_REQ_GET_DESCRIPTOR:
16017 + switch (ctrl->wValue >> 8) {
16019 + case USB_DT_DEVICE:
16020 + value = min (ctrl->wLength, (u16) sizeof device_desc);
16021 + memcpy (req->buf, &device_desc, value);
16023 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16024 + case USB_DT_DEVICE_QUALIFIER:
16025 + if (!gadget->is_dualspeed)
16027 + value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
16028 + memcpy (req->buf, &dev_qualifier, value);
16031 + case USB_DT_OTHER_SPEED_CONFIG:
16032 + if (!gadget->is_dualspeed)
16035 +#endif /* CONFIG_USB_GADGET_DUALSPEED */
16036 + case USB_DT_CONFIG:
16037 + value = config_buf (gadget, req->buf,
16038 + ctrl->wValue >> 8,
16039 + ctrl->wValue & 0xff);
16041 + value = min (ctrl->wLength, (u16) value);
16044 + case USB_DT_STRING:
16045 + /* wIndex == language code.
16046 + * this driver only handles one language, you can
16047 + * add string tables for other languages, using
16048 + * any UTF-8 characters
16050 + value = usb_gadget_get_string (&stringtab,
16051 + ctrl->wValue & 0xff, req->buf);
16052 + if (value >= 0) {
16053 + value = min (ctrl->wLength, (u16) value);
16059 + /* currently two configs, two speeds */
16060 + case USB_REQ_SET_CONFIGURATION:
16061 + if (ctrl->bRequestType != 0)
16064 + spin_lock (&dev->lock);
16065 + value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
16066 + spin_unlock (&dev->lock);
16068 + case USB_REQ_GET_CONFIGURATION:
16069 + if (ctrl->bRequestType != USB_DIR_IN)
16071 + *(u8 *)req->buf = dev->config;
16072 + value = min (ctrl->wLength, (u16) 1);
16075 + /* until we add altsetting support, or other interfaces,
16076 + * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
16077 + * and already killed pending endpoint I/O.
16079 + case USB_REQ_SET_INTERFACE:
16081 + if (ctrl->bRequestType != USB_RECIP_INTERFACE)
16083 + spin_lock (&dev->lock);
16084 + if (dev->config) {
16085 + u8 config = dev->config;
16087 + /* resets interface configuration, forgets about
16088 + * previous transaction state (queued bufs, etc)
16089 + * and re-inits endpoint state (toggle etc)
16090 + * no response queued, just zero status == success.
16091 + * if we had more than one interface we couldn't
16092 + * use this "reset the config" shortcut.
16094 + zero_reset_config (dev);
16095 + zero_set_config (dev, config, GFP_ATOMIC);
16098 + spin_unlock (&dev->lock);
16100 + case USB_REQ_GET_INTERFACE:
16101 + if ((ctrl->bRequestType == 0x21) && (ctrl->wIndex == 0x02)) {
16102 + value = ctrl->wLength;
16106 + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
16108 + if (!dev->config)
16110 + if (ctrl->wIndex != 0) {
16114 + *(u8 *)req->buf = 0;
16115 + value = min (ctrl->wLength, (u16) 1);
16120 + * These are the same vendor-specific requests supported by
16121 + * Intel's USB 2.0 compliance test devices. We exceed that
16122 + * device spec by allowing multiple-packet requests.
16124 + case 0x5b: /* control WRITE test -- fill the buffer */
16125 + if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
16127 + if (ctrl->wValue || ctrl->wIndex)
16129 + /* just read that many bytes into the buffer */
16130 + if (ctrl->wLength > USB_BUFSIZ)
16132 + value = ctrl->wLength;
16134 + case 0x5c: /* control READ test -- return the buffer */
16135 + if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
16137 + if (ctrl->wValue || ctrl->wIndex)
16139 + /* expect those bytes are still in the buffer; send back */
16140 + if (ctrl->wLength > USB_BUFSIZ
16141 + || ctrl->wLength != req->length)
16143 + value = ctrl->wLength;
16146 + case 0x01: // SET_CUR
16151 + value = ctrl->wLength;
16154 + switch (ctrl->wValue) {
16157 + ((u8*)req->buf)[0] = 0x00;
16158 + ((u8*)req->buf)[1] = 0xe3;
16162 + ((u8*)req->buf)[0] = 0x00;
16165 + //((u8*)req->buf)[0] = 0x81;
16166 + //((u8*)req->buf)[1] = 0x81;
16167 + value = ctrl->wLength;
16170 + switch (ctrl->wValue) {
16173 + ((u8*)req->buf)[0] = 0x00;
16174 + ((u8*)req->buf)[1] = 0xc3;
16178 + ((u8*)req->buf)[0] = 0x00;
16181 + //((u8*)req->buf)[0] = 0x82;
16182 + //((u8*)req->buf)[1] = 0x82;
16183 + value = ctrl->wLength;
16186 + switch (ctrl->wValue) {
16189 + ((u8*)req->buf)[0] = 0x00;
16190 + ((u8*)req->buf)[1] = 0x00;
16193 + ((u8*)req->buf)[0] = 0x60;
16196 + ((u8*)req->buf)[0] = 0x18;
16199 + //((u8*)req->buf)[0] = 0x83;
16200 + //((u8*)req->buf)[1] = 0x83;
16201 + value = ctrl->wLength;
16204 + switch (ctrl->wValue) {
16207 + ((u8*)req->buf)[0] = 0x00;
16208 + ((u8*)req->buf)[1] = 0x01;
16212 + ((u8*)req->buf)[0] = 0x08;
16215 + //((u8*)req->buf)[0] = 0x84;
16216 + //((u8*)req->buf)[1] = 0x84;
16217 + value = ctrl->wLength;
16220 + ((u8*)req->buf)[0] = 0x85;
16221 + ((u8*)req->buf)[1] = 0x85;
16222 + value = ctrl->wLength;
16228 + printk("unknown control req%02x.%02x v%04x i%04x l%d\n",
16229 + ctrl->bRequestType, ctrl->bRequest,
16230 + ctrl->wValue, ctrl->wIndex, ctrl->wLength);
16233 + /* respond with data transfer before status phase? */
16234 + if (value >= 0) {
16235 + req->length = value;
16236 + req->zero = value < ctrl->wLength
16237 + && (value % gadget->ep0->maxpacket) == 0;
16238 + value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
16240 + DBG (dev, "ep_queue < 0 --> %d\n", value);
16242 + zero_setup_complete (gadget->ep0, req);
16246 + /* device either stalls (value < 0) or reports success */
16251 +zero_disconnect (struct usb_gadget *gadget)
16253 + struct zero_dev *dev = get_gadget_data (gadget);
16254 + unsigned long flags;
16256 + spin_lock_irqsave (&dev->lock, flags);
16257 + zero_reset_config (dev);
16259 + /* a more significant application might have some non-usb
16260 + * activities to quiesce here, saving resources like power
16261 + * or pushing the notification up a network stack.
16263 + spin_unlock_irqrestore (&dev->lock, flags);
16265 + /* next we may get setup() calls to enumerate new connections;
16266 + * or an unbind() during shutdown (including removing module).
16271 +zero_autoresume (unsigned long _dev)
16273 + struct zero_dev *dev = (struct zero_dev *) _dev;
16276 + /* normally the host would be woken up for something
16277 + * more significant than just a timer firing...
16279 + if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
16280 + status = usb_gadget_wakeup (dev->gadget);
16281 + DBG (dev, "wakeup --> %d\n", status);
16285 +/*-------------------------------------------------------------------------*/
16288 +zero_unbind (struct usb_gadget *gadget)
16290 + struct zero_dev *dev = get_gadget_data (gadget);
16292 + DBG (dev, "unbind\n");
16294 + /* we've already been disconnected ... no i/o is active */
16296 + free_ep_req (gadget->ep0, dev->req);
16297 + del_timer_sync (&dev->resume);
16299 + set_gadget_data (gadget, NULL);
16303 +zero_bind (struct usb_gadget *gadget)
16305 + struct zero_dev *dev;
16306 + //struct usb_ep *ep;
16308 + printk("binding\n");
16310 + * DRIVER POLICY CHOICE: you may want to do this differently.
16311 + * One thing to avoid is reusing a bcdDevice revision code
16312 + * with different host-visible configurations or behavior
16313 + * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
16315 + //device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
16318 + /* ok, we made sense of the hardware ... */
16319 + dev = kmalloc (sizeof *dev, SLAB_KERNEL);
16322 + memset (dev, 0, sizeof *dev);
16323 + spin_lock_init (&dev->lock);
16324 + dev->gadget = gadget;
16325 + set_gadget_data (gadget, dev);
16327 + /* preallocate control response and buffer */
16328 + dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
16331 + dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
16332 + &dev->req->dma, GFP_KERNEL);
16333 + if (!dev->req->buf)
16336 + dev->req->complete = zero_setup_complete;
16338 + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
16340 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16341 + /* assume ep0 uses the same value for both speeds ... */
16342 + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
16344 + /* and that all endpoints are dual-speed */
16345 + //hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
16346 + //hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
16349 + usb_gadget_set_selfpowered (gadget);
16351 + init_timer (&dev->resume);
16352 + dev->resume.function = zero_autoresume;
16353 + dev->resume.data = (unsigned long) dev;
16355 + gadget->ep0->driver_data = dev;
16357 + INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
16358 + INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
16359 + EP_OUT_NAME, EP_IN_NAME);
16361 + snprintf (manufacturer, sizeof manufacturer,
16362 + UTS_SYSNAME " " UTS_RELEASE " with %s",
16368 + zero_unbind (gadget);
16372 +/*-------------------------------------------------------------------------*/
16375 +zero_suspend (struct usb_gadget *gadget)
16377 + struct zero_dev *dev = get_gadget_data (gadget);
16379 + if (gadget->speed == USB_SPEED_UNKNOWN)
16382 + if (autoresume) {
16383 + mod_timer (&dev->resume, jiffies + (HZ * autoresume));
16384 + DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
16386 + DBG (dev, "suspend\n");
16390 +zero_resume (struct usb_gadget *gadget)
16392 + struct zero_dev *dev = get_gadget_data (gadget);
16394 + DBG (dev, "resume\n");
16395 + del_timer (&dev->resume);
16399 +/*-------------------------------------------------------------------------*/
16401 +static struct usb_gadget_driver zero_driver = {
16402 +#ifdef CONFIG_USB_GADGET_DUALSPEED
16403 + .speed = USB_SPEED_HIGH,
16405 + .speed = USB_SPEED_FULL,
16407 + .function = (char *) longname,
16408 + .bind = zero_bind,
16409 + .unbind = zero_unbind,
16411 + .setup = zero_setup,
16412 + .disconnect = zero_disconnect,
16414 + .suspend = zero_suspend,
16415 + .resume = zero_resume,
16418 + .name = (char *) shortname,
16419 + // .shutdown = ...
16420 + // .suspend = ...
16425 +MODULE_AUTHOR ("David Brownell");
16426 +MODULE_LICENSE ("Dual BSD/GPL");
16428 +static struct proc_dir_entry *pdir, *pfile;
16430 +static int isoc_read_data (char *page, char **start,
16431 + off_t off, int count,
16432 + int *eof, void *data)
16435 + static int c = 0;
16436 + static int done = 0;
16437 + static int s = 0;
16440 + printk ("\ncount: %d\n", count);
16441 + printk ("rbuf_start: %d\n", rbuf_start);
16442 + printk ("rbuf_len: %d\n", rbuf_len);
16443 + printk ("off: %d\n", off);
16444 + printk ("start: %p\n\n", *start);
16454 + if (rbuf_len == RBUF_LEN)
16459 + for (i=0; i<count && c<rbuf_len; i++, c++) {
16460 + page[i] = rbuf[(c+s) % RBUF_LEN];
16464 + if (c >= rbuf_len) {
16473 +static int __init init (void)
16478 + pdir = proc_mkdir("isoc_test", NULL);
16479 + if(pdir == NULL) {
16480 + retval = -ENOMEM;
16481 + printk("Error creating dir\n");
16484 + pdir->owner = THIS_MODULE;
16486 + pfile = create_proc_read_entry("isoc_data",
16490 + if (pfile == NULL) {
16491 + retval = -ENOMEM;
16492 + printk("Error creating file\n");
16495 + pfile->owner = THIS_MODULE;
16497 + return usb_gadget_register_driver (&zero_driver);
16500 + remove_proc_entry("isoc_data", NULL);
16504 +module_init (init);
16506 +static void __exit cleanup (void)
16509 + usb_gadget_unregister_driver (&zero_driver);
16511 + remove_proc_entry("isoc_data", pdir);
16512 + remove_proc_entry("isoc_test", NULL);
16514 +module_exit (cleanup);
16515 diff --git a/drivers/usb/host/dwc_otg/dwc_cfi_common.h b/drivers/usb/host/dwc_otg/dwc_cfi_common.h
16516 new file mode 100644
16517 index 0000000..be56af4
16519 +++ b/drivers/usb/host/dwc_otg/dwc_cfi_common.h
16521 +/* ==========================================================================
16522 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
16523 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
16524 + * otherwise expressly agreed to in writing between Synopsys and you.
16526 + * The Software IS NOT an item of Licensed Software or Licensed Product under
16527 + * any End User Software License Agreement or Agreement for Licensed Product
16528 + * with Synopsys or any supplement thereto. You are permitted to use and
16529 + * redistribute this Software in source and binary forms, with or without
16530 + * modification, provided that redistributions of source code must retain this
16531 + * notice. You may not view, use, disclose, copy or distribute this file or
16532 + * any information contained herein except pursuant to this license grant from
16533 + * Synopsys. If you do not agree with this notice, including the disclaimer
16534 + * below, then you are not authorized to use the Software.
16536 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
16537 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16538 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16539 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
16540 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16541 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16542 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
16543 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16544 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16545 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
16547 + * ========================================================================== */
16549 +#if !defined(__DWC_CFI_COMMON_H__)
16550 +#define __DWC_CFI_COMMON_H__
16552 +//#include <linux/types.h>
16557 + * This file contains the CFI specific common constants, interfaces
16558 + * (functions and macros) and structures for Linux. No PCD specific
16559 + * data structure or definition is to be included in this file.
16563 +/** This is a request for all Core Features */
16564 +#define VEN_CORE_GET_FEATURES 0xB1
16566 +/** This is a request to get the value of a specific Core Feature */
16567 +#define VEN_CORE_GET_FEATURE 0xB2
16569 +/** This command allows the host to set the value of a specific Core Feature */
16570 +#define VEN_CORE_SET_FEATURE 0xB3
16572 +/** This command allows the host to set the default values of
16573 + * either all or any specific Core Feature
16575 +#define VEN_CORE_RESET_FEATURES 0xB4
16577 +/** This command forces the PCD to write the deferred values of a Core Features */
16578 +#define VEN_CORE_ACTIVATE_FEATURES 0xB5
16580 +/** This request reads a DWORD value from a register at the specified offset */
16581 +#define VEN_CORE_READ_REGISTER 0xB6
16583 +/** This request writes a DWORD value into a register at the specified offset */
16584 +#define VEN_CORE_WRITE_REGISTER 0xB7
16586 +/** This structure is the header of the Core Features dataset returned to
16589 +struct cfi_all_features_header {
16590 +/** The features header structure length is */
16591 +#define CFI_ALL_FEATURES_HDR_LEN 8
16593 + * The total length of the features dataset returned to the Host
16595 + uint16_t wTotalLen;
16598 + * CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H).
16599 + * This field identifies the version of the CFI Specification with which
16600 + * the device is compliant.
16602 + uint16_t wVersion;
16604 + /** The ID of the Core */
16605 + uint16_t wCoreID;
16606 +#define CFI_CORE_ID_UDC 1
16607 +#define CFI_CORE_ID_OTG 2
16608 +#define CFI_CORE_ID_WUDEV 3
16610 + /** Number of features returned by VEN_CORE_GET_FEATURES request */
16611 + uint16_t wNumFeatures;
16614 +typedef struct cfi_all_features_header cfi_all_features_header_t;
16616 +/** This structure is a header of the Core Feature descriptor dataset returned to
16617 + * the Host after the VEN_CORE_GET_FEATURES request
16619 +struct cfi_feature_desc_header {
16620 +#define CFI_FEATURE_DESC_HDR_LEN 8
16622 + /** The feature ID */
16623 + uint16_t wFeatureID;
16625 + /** Length of this feature descriptor in bytes - including the
16626 + * length of the feature name string
16628 + uint16_t wLength;
16630 + /** The data length of this feature in bytes */
16631 + uint16_t wDataLength;
16634 + * Attributes of this features
16635 + * D0: Access rights
16639 + uint8_t bmAttributes;
16640 +#define CFI_FEATURE_ATTR_RO 1
16641 +#define CFI_FEATURE_ATTR_RW 0
16643 + /** Length of the feature name in bytes */
16644 + uint8_t bNameLen;
16646 + /** The feature name buffer */
16650 +typedef struct cfi_feature_desc_header cfi_feature_desc_header_t;
16653 + * This structure describes a NULL terminated string referenced by its id field.
16654 + * It is very similar to usb_string structure but has the id field type set to 16-bit.
16656 +struct cfi_string {
16658 + const uint8_t *s;
16660 +typedef struct cfi_string cfi_string_t;
16663 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_adp.c b/drivers/usb/host/dwc_otg/dwc_otg_adp.c
16664 new file mode 100644
16665 index 0000000..0877472
16667 +++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.c
16669 +/* ==========================================================================
16670 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.c $
16671 + * $Revision: #12 $
16672 + * $Date: 2011/10/26 $
16673 + * $Change: 1873028 $
16675 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
16676 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
16677 + * otherwise expressly agreed to in writing between Synopsys and you.
16679 + * The Software IS NOT an item of Licensed Software or Licensed Product under
16680 + * any End User Software License Agreement or Agreement for Licensed Product
16681 + * with Synopsys or any supplement thereto. You are permitted to use and
16682 + * redistribute this Software in source and binary forms, with or without
16683 + * modification, provided that redistributions of source code must retain this
16684 + * notice. You may not view, use, disclose, copy or distribute this file or
16685 + * any information contained herein except pursuant to this license grant from
16686 + * Synopsys. If you do not agree with this notice, including the disclaimer
16687 + * below, then you are not authorized to use the Software.
16689 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
16690 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16691 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16692 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
16693 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16694 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16695 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
16696 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16697 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16698 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
16700 + * ========================================================================== */
16702 +#include "dwc_os.h"
16703 +#include "dwc_otg_regs.h"
16704 +#include "dwc_otg_cil.h"
16705 +#include "dwc_otg_adp.h"
16709 + * This file contains the most of the Attach Detect Protocol implementation for
16710 + * the driver to support OTG Rev2.0.
16714 +void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value)
16716 + adpctl_data_t adpctl;
16718 + adpctl.d32 = value;
16719 + adpctl.b.ar = 0x2;
16721 + DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
16723 + while (adpctl.b.ar) {
16724 + adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
16730 + * Function is called to read ADP registers
16732 +uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if)
16734 + adpctl_data_t adpctl;
16737 + adpctl.b.ar = 0x1;
16739 + DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
16741 + while (adpctl.b.ar) {
16742 + adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
16745 + return adpctl.d32;
16749 + * Function is called to read ADPCTL register and filter Write-clear bits
16751 +uint32_t dwc_otg_adp_read_reg_filter(dwc_otg_core_if_t * core_if)
16753 + adpctl_data_t adpctl;
16755 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16756 + adpctl.b.adp_tmout_int = 0;
16757 + adpctl.b.adp_prb_int = 0;
16758 + adpctl.b.adp_tmout_int = 0;
16760 + return adpctl.d32;
16764 + * Function is called to write ADP registers
16766 +void dwc_otg_adp_modify_reg(dwc_otg_core_if_t * core_if, uint32_t clr,
16769 + dwc_otg_adp_write_reg(core_if,
16770 + (dwc_otg_adp_read_reg(core_if) & (~clr)) | set);
16773 +static void adp_sense_timeout(void *ptr)
16775 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
16776 + core_if->adp.sense_timer_started = 0;
16777 + DWC_PRINTF("ADP SENSE TIMEOUT\n");
16778 + if (core_if->adp_enable) {
16779 + dwc_otg_adp_sense_stop(core_if);
16780 + dwc_otg_adp_probe_start(core_if);
16785 + * This function is called when the ADP vbus timer expires. Timeout is 1.1s.
16787 +static void adp_vbuson_timeout(void *ptr)
16789 + gpwrdn_data_t gpwrdn;
16790 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
16791 + hprt0_data_t hprt0 = {.d32 = 0 };
16792 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
16793 + DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
16795 + core_if->adp.vbuson_timer_started = 0;
16796 + /* Turn off vbus */
16797 + hprt0.b.prtpwr = 1;
16798 + DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
16801 + /* Power off the core */
16802 + if (core_if->power_down == 2) {
16803 + /* Enable Wakeup Logic */
16804 +// gpwrdn.b.wkupactiv = 1;
16805 + gpwrdn.b.pmuactv = 0;
16806 + gpwrdn.b.pwrdnrstn = 1;
16807 + gpwrdn.b.pwrdnclmp = 1;
16808 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
16811 + /* Suspend the Phy Clock */
16812 + pcgcctl.b.stoppclk = 1;
16813 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
16815 + /* Switch on VDD */
16816 +// gpwrdn.b.wkupactiv = 1;
16817 + gpwrdn.b.pmuactv = 1;
16818 + gpwrdn.b.pwrdnrstn = 1;
16819 + gpwrdn.b.pwrdnclmp = 1;
16820 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
16823 + /* Enable Power Down Logic */
16824 + gpwrdn.b.pmuintsel = 1;
16825 + gpwrdn.b.pmuactv = 1;
16826 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16829 + /* Power off the core */
16830 + if (core_if->power_down == 2) {
16832 + gpwrdn.b.pwrdnswtch = 1;
16833 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
16837 + /* Unmask SRP detected interrupt from Power Down Logic */
16839 + gpwrdn.b.srp_det_msk = 1;
16840 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16842 + dwc_otg_adp_probe_start(core_if);
16843 + dwc_otg_dump_global_registers(core_if);
16844 + dwc_otg_dump_host_registers(core_if);
16850 + * Start the ADP Initial Probe timer to detect if Port Connected interrupt is
16851 + * not asserted within 1.1 seconds.
16853 + * @param core_if the pointer to core_if strucure.
16855 +void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
16857 + core_if->adp.vbuson_timer_started = 1;
16858 + if (core_if->adp.vbuson_timer)
16860 + DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
16861 + /* 1.1 secs + 60ms necessary for cil_hcd_start*/
16862 + DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
16864 + DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
16870 + * Masks all DWC OTG core interrupts
16873 +static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
16876 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
16878 + /* Mask Host Interrupts */
16880 + /* Clear and disable HCINTs */
16881 + for (i = 0; i < core_if->core_params->host_channels; i++) {
16882 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
16883 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);
16887 + /* Clear and disable HAINT */
16888 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
16889 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);
16891 + /* Mask Device Interrupts */
16892 + if (!core_if->multiproc_int_enable) {
16893 + /* Clear and disable IN Endpoint interrupts */
16894 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
16895 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
16896 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
16897 + diepint, 0xFFFFFFFF);
16900 + /* Clear and disable OUT Endpoint interrupts */
16901 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
16902 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
16903 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
16904 + doepint, 0xFFFFFFFF);
16907 + /* Clear and disable DAINT */
16908 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
16910 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
16912 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
16913 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
16914 + diepeachintmsk[i], 0);
16915 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
16916 + diepint, 0xFFFFFFFF);
16919 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
16920 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
16921 + doepeachintmsk[i], 0);
16922 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
16923 + doepint, 0xFFFFFFFF);
16926 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
16928 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
16933 + /* Disable interrupts */
16934 + ahbcfg.b.glblintrmsk = 1;
16935 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
16937 + /* Disable all interrupts. */
16938 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
16940 + /* Clear any pending interrupts */
16941 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
16943 + /* Clear any pending OTG Interrupts */
16944 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);
16948 + * Unmask Port Connection Detected interrupt
16951 +static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
16953 + gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };
16955 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
16960 + * Starts the ADP Probing
16962 + * @param core_if the pointer to core_if structure.
16964 +uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
16967 + adpctl_data_t adpctl = {.d32 = 0};
16968 + gpwrdn_data_t gpwrdn;
16970 + adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
16971 + .b.adp_sns_int = 1, b.adp_tmout_int};
16973 + dwc_otg_disable_global_interrupts(core_if);
16974 + DWC_PRINTF("ADP Probe Start\n");
16975 + core_if->adp.probe_enabled = 1;
16977 + adpctl.b.adpres = 1;
16978 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
16980 + while (adpctl.b.adpres) {
16981 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
16985 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
16987 + /* In Host mode unmask SRP detected interrupt */
16989 + gpwrdn.b.sts_chngint_msk = 1;
16990 + if (!gpwrdn.b.idsts) {
16991 + gpwrdn.b.srp_det_msk = 1;
16993 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
16995 + adpctl.b.adp_tmout_int_msk = 1;
16996 + adpctl.b.adp_prb_int_msk = 1;
16997 + adpctl.b.prb_dschg = 1;
16998 + adpctl.b.prb_delta = 1;
16999 + adpctl.b.prb_per = 1;
17000 + adpctl.b.adpen = 1;
17001 + adpctl.b.enaprb = 1;
17003 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17004 + DWC_PRINTF("ADP Probe Finish\n");
17009 + * Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted
17010 + * within 3 seconds.
17012 + * @param core_if the pointer to core_if strucure.
17014 +void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
17016 + core_if->adp.sense_timer_started = 1;
17017 + DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3000 /* 3 secs */ );
17021 + * Starts the ADP Sense
17023 + * @param core_if the pointer to core_if strucure.
17025 +uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
17027 + adpctl_data_t adpctl;
17029 + DWC_PRINTF("ADP Sense Start\n");
17031 + /* Unmask ADP sense interrupt and mask all other from the core */
17032 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
17033 + adpctl.b.adp_sns_int_msk = 1;
17034 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17035 + dwc_otg_disable_global_interrupts(core_if); // vahrama
17037 + /* Set ADP reset bit*/
17038 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
17039 + adpctl.b.adpres = 1;
17040 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17042 + while (adpctl.b.adpres) {
17043 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17046 + adpctl.b.adpres = 0;
17047 + adpctl.b.adpen = 1;
17048 + adpctl.b.enasns = 1;
17049 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17051 + dwc_otg_adp_sense_timer_start(core_if);
17057 + * Stops the ADP Probing
17059 + * @param core_if the pointer to core_if strucure.
17061 +uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if)
17064 + adpctl_data_t adpctl;
17065 + DWC_PRINTF("Stop ADP probe\n");
17066 + core_if->adp.probe_enabled = 0;
17067 + core_if->adp.probe_counter = 0;
17068 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17070 + adpctl.b.adpen = 0;
17071 + adpctl.b.adp_prb_int = 1;
17072 + adpctl.b.adp_tmout_int = 1;
17073 + adpctl.b.adp_sns_int = 1;
17074 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17080 + * Stops the ADP Sensing
17082 + * @param core_if the pointer to core_if strucure.
17084 +uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if)
17086 + adpctl_data_t adpctl;
17088 + core_if->adp.sense_enabled = 0;
17090 + adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
17091 + adpctl.b.enasns = 0;
17092 + adpctl.b.adp_sns_int = 1;
17093 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17099 + * Called to turn on the VBUS after initial ADP probe in host mode.
17100 + * If port power was already enabled in cil_hcd_start function then
17101 + * only schedule a timer.
17103 + * @param core_if the pointer to core_if structure.
17105 +void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
17107 + hprt0_data_t hprt0 = {.d32 = 0 };
17108 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
17109 + DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);
17111 + if (hprt0.b.prtpwr == 0) {
17112 + hprt0.b.prtpwr = 1;
17113 + //DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
17116 + dwc_otg_adp_vbuson_timer_start(core_if);
17120 + * Called right after driver is loaded
17121 + * to perform initial actions for ADP
17123 + * @param core_if the pointer to core_if structure.
17124 + * @param is_host - flag for current mode of operation either from GINTSTS or GPWRDN
17126 +void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host)
17128 + gpwrdn_data_t gpwrdn;
17130 + DWC_PRINTF("ADP Initial Start\n");
17131 + core_if->adp.adp_started = 1;
17133 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
17134 + dwc_otg_disable_global_interrupts(core_if);
17136 + DWC_PRINTF("HOST MODE\n");
17137 + /* Enable Power Down Logic Interrupt*/
17139 + gpwrdn.b.pmuintsel = 1;
17140 + gpwrdn.b.pmuactv = 1;
17141 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
17142 + /* Initialize first ADP probe to obtain Ramp Time value */
17143 + core_if->adp.initial_probe = 1;
17144 + dwc_otg_adp_probe_start(core_if);
17146 + gotgctl_data_t gotgctl;
17147 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
17148 + DWC_PRINTF("DEVICE MODE\n");
17149 + if (gotgctl.b.bsesvld == 0) {
17150 + /* Enable Power Down Logic Interrupt*/
17152 + DWC_PRINTF("VBUS is not valid - start ADP probe\n");
17153 + gpwrdn.b.pmuintsel = 1;
17154 + gpwrdn.b.pmuactv = 1;
17155 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
17156 + core_if->adp.initial_probe = 1;
17157 + dwc_otg_adp_probe_start(core_if);
17159 + DWC_PRINTF("VBUS is valid - initialize core as a Device\n");
17160 + core_if->op_state = B_PERIPHERAL;
17161 + dwc_otg_core_init(core_if);
17162 + dwc_otg_enable_global_interrupts(core_if);
17163 + cil_pcd_start(core_if);
17164 + dwc_otg_dump_global_registers(core_if);
17165 + dwc_otg_dump_dev_registers(core_if);
17170 +void dwc_otg_adp_init(dwc_otg_core_if_t * core_if)
17172 + core_if->adp.adp_started = 0;
17173 + core_if->adp.initial_probe = 0;
17174 + core_if->adp.probe_timer_values[0] = -1;
17175 + core_if->adp.probe_timer_values[1] = -1;
17176 + core_if->adp.probe_enabled = 0;
17177 + core_if->adp.sense_enabled = 0;
17178 + core_if->adp.sense_timer_started = 0;
17179 + core_if->adp.vbuson_timer_started = 0;
17180 + core_if->adp.probe_counter = 0;
17181 + core_if->adp.gpwrdn = 0;
17182 + core_if->adp.attached = DWC_OTG_ADP_UNKOWN;
17183 + /* Initialize timers */
17184 + core_if->adp.sense_timer =
17185 + DWC_TIMER_ALLOC("ADP SENSE TIMER", adp_sense_timeout, core_if);
17186 + core_if->adp.vbuson_timer =
17187 + DWC_TIMER_ALLOC("ADP VBUS ON TIMER", adp_vbuson_timeout, core_if);
17188 + if (!core_if->adp.sense_timer || !core_if->adp.vbuson_timer)
17190 + DWC_ERROR("Could not allocate memory for ADP timers\n");
17194 +void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if)
17196 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
17197 + gpwrdn.b.pmuintsel = 1;
17198 + gpwrdn.b.pmuactv = 1;
17199 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17201 + if (core_if->adp.probe_enabled)
17202 + dwc_otg_adp_probe_stop(core_if);
17203 + if (core_if->adp.sense_enabled)
17204 + dwc_otg_adp_sense_stop(core_if);
17205 + if (core_if->adp.sense_timer_started)
17206 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
17207 + if (core_if->adp.vbuson_timer_started)
17208 + DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
17209 + DWC_TIMER_FREE(core_if->adp.sense_timer);
17210 + DWC_TIMER_FREE(core_if->adp.vbuson_timer);
17213 +/////////////////////////////////////////////////////////////////////
17214 +////////////// ADP Interrupt Handlers ///////////////////////////////
17215 +/////////////////////////////////////////////////////////////////////
17217 + * This function sets Ramp Timer values
17219 +static uint32_t set_timer_value(dwc_otg_core_if_t * core_if, uint32_t val)
17221 + if (core_if->adp.probe_timer_values[0] == -1) {
17222 + core_if->adp.probe_timer_values[0] = val;
17223 + core_if->adp.probe_timer_values[1] = -1;
17226 + core_if->adp.probe_timer_values[1] =
17227 + core_if->adp.probe_timer_values[0];
17228 + core_if->adp.probe_timer_values[0] = val;
17234 + * This function compares Ramp Timer values
17236 +static uint32_t compare_timer_values(dwc_otg_core_if_t * core_if)
17239 + if (core_if->adp.probe_timer_values[0]>=core_if->adp.probe_timer_values[1])
17240 + diff = core_if->adp.probe_timer_values[0]-core_if->adp.probe_timer_values[1];
17242 + diff = core_if->adp.probe_timer_values[1]-core_if->adp.probe_timer_values[0];
17251 + * This function handles ADP Probe Interrupts
17253 +static int32_t dwc_otg_adp_handle_prb_intr(dwc_otg_core_if_t * core_if,
17256 + adpctl_data_t adpctl = {.d32 = 0 };
17257 + gpwrdn_data_t gpwrdn, temp;
17258 + adpctl.d32 = val;
17260 + temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17261 + core_if->adp.probe_counter++;
17262 + core_if->adp.gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17263 + if (adpctl.b.rtim == 0 && !temp.b.idsts){
17264 + DWC_PRINTF("RTIM value is 0\n");
17267 + if (set_timer_value(core_if, adpctl.b.rtim) &&
17268 + core_if->adp.initial_probe) {
17269 + core_if->adp.initial_probe = 0;
17270 + dwc_otg_adp_probe_stop(core_if);
17272 + gpwrdn.b.pmuactv = 1;
17273 + gpwrdn.b.pmuintsel = 1;
17274 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17275 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
17277 + /* check which value is for device mode and which for Host mode */
17278 + if (!temp.b.idsts) { /* considered host mode value is 0 */
17280 + * Turn on VBUS after initial ADP probe.
17282 + core_if->op_state = A_HOST;
17283 + dwc_otg_enable_global_interrupts(core_if);
17284 + DWC_SPINUNLOCK(core_if->lock);
17285 + cil_hcd_start(core_if);
17286 + dwc_otg_adp_turnon_vbus(core_if);
17287 + DWC_SPINLOCK(core_if->lock);
17290 + * Initiate SRP after initial ADP probe.
17292 + dwc_otg_enable_global_interrupts(core_if);
17293 + dwc_otg_initiate_srp(core_if);
17295 + } else if (core_if->adp.probe_counter > 2){
17296 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17297 + if (compare_timer_values(core_if)) {
17298 + DWC_PRINTF("Difference in timer values !!! \n");
17299 +// core_if->adp.attached = DWC_OTG_ADP_ATTACHED;
17300 + dwc_otg_adp_probe_stop(core_if);
17302 + /* Power on the core */
17303 + if (core_if->power_down == 2) {
17304 + gpwrdn.b.pwrdnswtch = 1;
17305 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17306 + gpwrdn, 0, gpwrdn.d32);
17309 + /* check which value is for device mode and which for Host mode */
17310 + if (!temp.b.idsts) { /* considered host mode value is 0 */
17311 + /* Disable Interrupt from Power Down Logic */
17313 + gpwrdn.b.pmuintsel = 1;
17314 + gpwrdn.b.pmuactv = 1;
17315 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17316 + gpwrdn, gpwrdn.d32, 0);
17319 + * Initialize the Core for Host mode.
17321 + core_if->op_state = A_HOST;
17322 + dwc_otg_core_init(core_if);
17323 + dwc_otg_enable_global_interrupts(core_if);
17324 + cil_hcd_start(core_if);
17326 + gotgctl_data_t gotgctl;
17327 + /* Mask SRP detected interrupt from Power Down Logic */
17329 + gpwrdn.b.srp_det_msk = 1;
17330 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17331 + gpwrdn, gpwrdn.d32, 0);
17333 + /* Disable Power Down Logic */
17335 + gpwrdn.b.pmuintsel = 1;
17336 + gpwrdn.b.pmuactv = 1;
17337 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17338 + gpwrdn, gpwrdn.d32, 0);
17341 + * Initialize the Core for Device mode.
17343 + core_if->op_state = B_PERIPHERAL;
17344 + dwc_otg_core_init(core_if);
17345 + dwc_otg_enable_global_interrupts(core_if);
17346 + cil_pcd_start(core_if);
17348 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
17349 + if (!gotgctl.b.bsesvld) {
17350 + dwc_otg_initiate_srp(core_if);
17354 + if (core_if->power_down == 2) {
17355 + if (gpwrdn.b.bsessvld) {
17356 + /* Mask SRP detected interrupt from Power Down Logic */
17358 + gpwrdn.b.srp_det_msk = 1;
17359 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17361 + /* Disable Power Down Logic */
17363 + gpwrdn.b.pmuactv = 1;
17364 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
17367 + * Initialize the Core for Device mode.
17369 + core_if->op_state = B_PERIPHERAL;
17370 + dwc_otg_core_init(core_if);
17371 + dwc_otg_enable_global_interrupts(core_if);
17372 + cil_pcd_start(core_if);
17377 + /* Clear interrupt */
17378 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17379 + adpctl.b.adp_prb_int = 1;
17380 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17386 + * This function hadles ADP Sense Interrupt
17388 +static int32_t dwc_otg_adp_handle_sns_intr(dwc_otg_core_if_t * core_if)
17390 + adpctl_data_t adpctl;
17391 + /* Stop ADP Sense timer */
17392 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
17394 + /* Restart ADP Sense timer */
17395 + dwc_otg_adp_sense_timer_start(core_if);
17397 + /* Clear interrupt */
17398 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17399 + adpctl.b.adp_sns_int = 1;
17400 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17406 + * This function handles ADP Probe Interrupts
17408 +static int32_t dwc_otg_adp_handle_prb_tmout_intr(dwc_otg_core_if_t * core_if,
17411 + adpctl_data_t adpctl = {.d32 = 0 };
17412 + adpctl.d32 = val;
17413 + set_timer_value(core_if, adpctl.b.rtim);
17415 + /* Clear interrupt */
17416 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17417 + adpctl.b.adp_tmout_int = 1;
17418 + dwc_otg_adp_write_reg(core_if, adpctl.d32);
17424 + * ADP Interrupt handler.
17427 +int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if)
17430 + adpctl_data_t adpctl = {.d32 = 0};
17432 + adpctl.d32 = dwc_otg_adp_read_reg(core_if);
17433 + DWC_PRINTF("ADPCTL = %08x\n",adpctl.d32);
17435 + if (adpctl.b.adp_sns_int & adpctl.b.adp_sns_int_msk) {
17436 + DWC_PRINTF("ADP Sense interrupt\n");
17437 + retval |= dwc_otg_adp_handle_sns_intr(core_if);
17439 + if (adpctl.b.adp_tmout_int & adpctl.b.adp_tmout_int_msk) {
17440 + DWC_PRINTF("ADP timeout interrupt\n");
17441 + retval |= dwc_otg_adp_handle_prb_tmout_intr(core_if, adpctl.d32);
17443 + if (adpctl.b.adp_prb_int & adpctl.b.adp_prb_int_msk) {
17444 + DWC_PRINTF("ADP Probe interrupt\n");
17445 + adpctl.b.adp_prb_int = 1;
17446 + retval |= dwc_otg_adp_handle_prb_intr(core_if, adpctl.d32);
17449 +// dwc_otg_adp_modify_reg(core_if, adpctl.d32, 0);
17450 + //dwc_otg_adp_write_reg(core_if, adpctl.d32);
17451 + DWC_PRINTF("RETURN FROM ADP ISR\n");
17458 + * @param core_if Programming view of DWC_otg controller.
17460 +int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if)
17463 +#ifndef DWC_HOST_ONLY
17464 + hprt0_data_t hprt0;
17465 + gpwrdn_data_t gpwrdn;
17466 + DWC_DEBUGPL(DBG_ANY, "++ Power Down Logic Session Request Interrupt++\n");
17468 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
17469 + /* check which value is for device mode and which for Host mode */
17470 + if (!gpwrdn.b.idsts) { /* considered host mode value is 0 */
17471 + DWC_PRINTF("SRP: Host mode\n");
17473 + if (core_if->adp_enable) {
17474 + dwc_otg_adp_probe_stop(core_if);
17476 + /* Power on the core */
17477 + if (core_if->power_down == 2) {
17478 + gpwrdn.b.pwrdnswtch = 1;
17479 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17480 + gpwrdn, 0, gpwrdn.d32);
17483 + core_if->op_state = A_HOST;
17484 + dwc_otg_core_init(core_if);
17485 + dwc_otg_enable_global_interrupts(core_if);
17486 + cil_hcd_start(core_if);
17489 + /* Turn on the port power bit. */
17490 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
17491 + hprt0.b.prtpwr = 1;
17492 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
17494 + /* Start the Connection timer. So a message can be displayed
17495 + * if connect does not occur within 10 seconds. */
17496 + cil_hcd_session_start(core_if);
17498 + DWC_PRINTF("SRP: Device mode %s\n", __FUNCTION__);
17499 + if (core_if->adp_enable) {
17500 + dwc_otg_adp_probe_stop(core_if);
17502 + /* Power on the core */
17503 + if (core_if->power_down == 2) {
17504 + gpwrdn.b.pwrdnswtch = 1;
17505 + DWC_MODIFY_REG32(&core_if->core_global_regs->
17506 + gpwrdn, 0, gpwrdn.d32);
17510 + gpwrdn.b.pmuactv = 0;
17511 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
17514 + core_if->op_state = B_PERIPHERAL;
17515 + dwc_otg_core_init(core_if);
17516 + dwc_otg_enable_global_interrupts(core_if);
17517 + cil_pcd_start(core_if);
17523 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_adp.h b/drivers/usb/host/dwc_otg/dwc_otg_adp.h
17524 new file mode 100644
17525 index 0000000..d8c3f85
17527 +++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.h
17529 +/* ==========================================================================
17530 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.h $
17531 + * $Revision: #7 $
17532 + * $Date: 2011/10/24 $
17533 + * $Change: 1871159 $
17535 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
17536 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
17537 + * otherwise expressly agreed to in writing between Synopsys and you.
17539 + * The Software IS NOT an item of Licensed Software or Licensed Product under
17540 + * any End User Software License Agreement or Agreement for Licensed Product
17541 + * with Synopsys or any supplement thereto. You are permitted to use and
17542 + * redistribute this Software in source and binary forms, with or without
17543 + * modification, provided that redistributions of source code must retain this
17544 + * notice. You may not view, use, disclose, copy or distribute this file or
17545 + * any information contained herein except pursuant to this license grant from
17546 + * Synopsys. If you do not agree with this notice, including the disclaimer
17547 + * below, then you are not authorized to use the Software.
17549 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
17550 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17551 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17552 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
17553 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17554 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17555 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17556 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17557 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17558 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
17560 + * ========================================================================== */
17562 +#ifndef __DWC_OTG_ADP_H__
17563 +#define __DWC_OTG_ADP_H__
17568 + * This file contains the Attach Detect Protocol interfaces and defines
17569 + * (functions) and structures for Linux.
17573 +#define DWC_OTG_ADP_UNATTACHED 0
17574 +#define DWC_OTG_ADP_ATTACHED 1
17575 +#define DWC_OTG_ADP_UNKOWN 2
17577 +typedef struct dwc_otg_adp {
17578 + uint32_t adp_started;
17579 + uint32_t initial_probe;
17580 + int32_t probe_timer_values[2];
17581 + uint32_t probe_enabled;
17582 + uint32_t sense_enabled;
17583 + dwc_timer_t *sense_timer;
17584 + uint32_t sense_timer_started;
17585 + dwc_timer_t *vbuson_timer;
17586 + uint32_t vbuson_timer_started;
17587 + uint32_t attached;
17588 + uint32_t probe_counter;
17593 + * Attach Detect Protocol functions
17596 +extern void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value);
17597 +extern uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if);
17598 +extern uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if);
17599 +extern uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if);
17600 +extern uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if);
17601 +extern uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if);
17602 +extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
17603 +extern void dwc_otg_adp_init(dwc_otg_core_if_t * core_if);
17604 +extern void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if);
17605 +extern int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if);
17606 +extern int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if);
17608 +#endif //__DWC_OTG_ADP_H__
17609 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.c b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
17610 new file mode 100644
17611 index 0000000..95eb7f8
17613 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
17615 +/* ==========================================================================
17616 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $
17617 + * $Revision: #44 $
17618 + * $Date: 2010/11/29 $
17619 + * $Change: 1636033 $
17621 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
17622 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
17623 + * otherwise expressly agreed to in writing between Synopsys and you.
17625 + * The Software IS NOT an item of Licensed Software or Licensed Product under
17626 + * any End User Software License Agreement or Agreement for Licensed Product
17627 + * with Synopsys or any supplement thereto. You are permitted to use and
17628 + * redistribute this Software in source and binary forms, with or without
17629 + * modification, provided that redistributions of source code must retain this
17630 + * notice. You may not view, use, disclose, copy or distribute this file or
17631 + * any information contained herein except pursuant to this license grant from
17632 + * Synopsys. If you do not agree with this notice, including the disclaimer
17633 + * below, then you are not authorized to use the Software.
17635 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
17636 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17637 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17638 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
17639 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17640 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17641 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17642 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17643 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17644 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
17646 + * ========================================================================== */
17650 + * The diagnostic interface will provide access to the controller for
17651 + * bringing up the hardware and testing. The Linux driver attributes
17652 + * feature will be used to provide the Linux Diagnostic
17653 + * Interface. These attributes are accessed through sysfs.
17656 +/** @page "Linux Module Attributes"
17658 + * The Linux module attributes feature is used to provide the Linux
17659 + * Diagnostic Interface. These attributes are accessed through sysfs.
17660 + * The diagnostic interface will provide access to the controller for
17661 + * bringing up the hardware and testing.
17663 + The following table shows the attributes.
17666 + <td><b> Name</b></td>
17667 + <td><b> Description</b></td>
17668 + <td><b> Access</b></td>
17673 + <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
17678 + <td> hnpcapable </td>
17679 + <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
17680 + Read returns the current value.</td>
17681 + <td> Read/Write</td>
17685 + <td> srpcapable </td>
17686 + <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
17687 + Read returns the current value.</td>
17688 + <td> Read/Write</td>
17692 + <td> hsic_connect </td>
17693 + <td> Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register.
17694 + Read returns the current value.</td>
17695 + <td> Read/Write</td>
17699 + <td> inv_sel_hsic </td>
17700 + <td> Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register.
17701 + Read returns the current value.</td>
17702 + <td> Read/Write</td>
17707 + <td> Initiates the Host Negotiation Protocol. Read returns the status.</td>
17708 + <td> Read/Write</td>
17713 + <td> Initiates the Session Request Protocol. Read returns the status.</td>
17714 + <td> Read/Write</td>
17718 + <td> buspower </td>
17719 + <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
17720 + <td> Read/Write</td>
17724 + <td> bussuspend </td>
17725 + <td> Suspends the USB bus.</td>
17726 + <td> Read/Write</td>
17730 + <td> busconnected </td>
17731 + <td> Gets the connection status of the bus</td>
17736 + <td> gotgctl </td>
17737 + <td> Gets or sets the Core Control Status Register.</td>
17738 + <td> Read/Write</td>
17742 + <td> gusbcfg </td>
17743 + <td> Gets or sets the Core USB Configuration Register</td>
17744 + <td> Read/Write</td>
17748 + <td> grxfsiz </td>
17749 + <td> Gets or sets the Receive FIFO Size Register</td>
17750 + <td> Read/Write</td>
17754 + <td> gnptxfsiz </td>
17755 + <td> Gets or sets the non-periodic Transmit Size Register</td>
17756 + <td> Read/Write</td>
17760 + <td> gpvndctl </td>
17761 + <td> Gets or sets the PHY Vendor Control Register</td>
17762 + <td> Read/Write</td>
17767 + <td> Gets the value in the lower 16-bits of the General Purpose IO Register
17768 + or sets the upper 16 bits.</td>
17769 + <td> Read/Write</td>
17774 + <td> Gets or sets the value of the User ID Register</td>
17775 + <td> Read/Write</td>
17779 + <td> gsnpsid </td>
17780 + <td> Gets the value of the Synopsys ID Regester</td>
17785 + <td> devspeed </td>
17786 + <td> Gets or sets the device speed setting in the DCFG register</td>
17787 + <td> Read/Write</td>
17791 + <td> enumspeed </td>
17792 + <td> Gets the device enumeration Speed.</td>
17797 + <td> hptxfsiz </td>
17798 + <td> Gets the value of the Host Periodic Transmit FIFO</td>
17804 + <td> Gets or sets the value in the Host Port Control and Status Register</td>
17805 + <td> Read/Write</td>
17809 + <td> regoffset </td>
17810 + <td> Sets the register offset for the next Register Access</td>
17811 + <td> Read/Write</td>
17815 + <td> regvalue </td>
17816 + <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
17817 + <td> Read/Write</td>
17821 + <td> remote_wakeup </td>
17822 + <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
17823 + wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
17824 + Wakeup signalling bit in the Device Control Register is set for 1
17825 + milli-second.</td>
17826 + <td> Read/Write</td>
17830 + <td> rem_wakeup_pwrdn </td>
17831 + <td> On read, shows the status core - hibernated or not. On write, initiates
17832 + a remote wakeup of the device from Hibernation. </td>
17833 + <td> Read/Write</td>
17837 + <td> mode_ch_tim_en </td>
17838 + <td> This bit is used to enable or disable the host core to wait for 200 PHY
17839 + clock cycles at the end of Resume to change the opmode signal to the PHY to 00
17840 + after Suspend or LPM. </td>
17841 + <td> Read/Write</td>
17845 + <td> fr_interval </td>
17846 + <td> On read, shows the value of HFIR Frame Interval. On write, dynamically
17847 + reload HFIR register during runtime. The application can write a value to this
17848 + register only after the Port Enable bit of the Host Port Control and Status
17849 + register (HPRT.PrtEnaPort) has been set </td>
17850 + <td> Read/Write</td>
17854 + <td> disconnect_us </td>
17855 + <td> On read, shows the status of disconnect_device_us. On write, sets disconnect_us
17856 + which causes soft disconnect for 100us. Applicable only for device mode of operation.</td>
17857 + <td> Read/Write</td>
17861 + <td> regdump </td>
17862 + <td> Dumps the contents of core registers.</td>
17867 + <td> spramdump </td>
17868 + <td> Dumps the contents of core registers.</td>
17873 + <td> hcddump </td>
17874 + <td> Dumps the current HCD state.</td>
17879 + <td> hcd_frrem </td>
17880 + <td> Shows the average value of the Frame Remaining
17881 + field in the Host Frame Number/Frame Remaining register when an SOF interrupt
17882 + occurs. This can be used to determine the average interrupt latency. Also
17883 + shows the average Frame Remaining value for start_transfer and the "a" and
17884 + "b" sample points. The "a" and "b" sample points may be used during debugging
17885 + bto determine how long it takes to execute a section of the HCD code.</td>
17890 + <td> rd_reg_test </td>
17891 + <td> Displays the time required to read the GNPTXFSIZ register many times
17892 + (the output shows the number of times the register is read).
17897 + <td> wr_reg_test </td>
17898 + <td> Displays the time required to write the GNPTXFSIZ register many times
17899 + (the output shows the number of times the register is written).
17904 + <td> lpm_response </td>
17905 + <td> Gets or sets lpm_response mode. Applicable only in device mode.
17910 + <td> sleep_status </td>
17911 + <td> Shows sleep status of device.
17918 + To get the current mode:
17919 + cat /sys/devices/lm0/mode
17921 + To power down the USB:
17922 + echo 0 > /sys/devices/lm0/buspower
17925 +#include "dwc_otg_os_dep.h"
17926 +#include "dwc_os.h"
17927 +#include "dwc_otg_driver.h"
17928 +#include "dwc_otg_attr.h"
17929 +#include "dwc_otg_core_if.h"
17930 +#include "dwc_otg_pcd_if.h"
17931 +#include "dwc_otg_hcd_if.h"
17934 + * MACROs for defining sysfs attribute
17936 +#ifdef LM_INTERFACE
17938 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17939 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17941 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17942 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17944 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17945 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17947 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17948 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17949 + const char *buf, size_t count) \
17951 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
17952 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
17953 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17954 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17958 +#elif defined(PCI_INTERFACE)
17960 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17961 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17963 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17965 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17966 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17968 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17969 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17970 + const char *buf, size_t count) \
17972 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
17973 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17974 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
17978 +#elif defined(PLATFORM_INTERFACE)
17980 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
17981 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
17983 + struct platform_device *platform_dev = \
17984 + container_of(_dev, struct platform_device, dev); \
17985 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17987 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
17988 + __func__, _dev, platform_dev, otg_dev); \
17989 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
17990 + return sprintf (buf, "%s = 0x%x\n", _string_, val); \
17992 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
17993 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
17994 + const char *buf, size_t count) \
17996 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
17997 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
17998 + uint32_t set = simple_strtoul(buf, NULL, 16); \
17999 + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
18005 + * MACROs for defining sysfs attribute for 32-bit registers
18007 +#ifdef LM_INTERFACE
18008 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
18009 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
18011 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
18012 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
18014 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
18015 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
18017 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
18018 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
18019 + const char *buf, size_t count) \
18021 + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
18022 + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
18023 + uint32_t val = simple_strtoul(buf, NULL, 16); \
18024 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
18027 +#elif defined(PCI_INTERFACE)
18028 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
18029 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
18031 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
18033 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
18034 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
18036 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
18037 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
18038 + const char *buf, size_t count) \
18040 + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
18041 + uint32_t val = simple_strtoul(buf, NULL, 16); \
18042 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
18046 +#elif defined(PLATFORM_INTERFACE)
18047 +#include "dwc_otg_dbg.h"
18048 +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
18049 +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
18051 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
18052 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
18054 + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
18055 + __func__, _dev, platform_dev, otg_dev); \
18056 + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
18057 + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
18059 +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
18060 +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
18061 + const char *buf, size_t count) \
18063 + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
18064 + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
18065 + uint32_t val = simple_strtoul(buf, NULL, 16); \
18066 + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
18072 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \
18073 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
18074 +DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
18075 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
18077 +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \
18078 +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
18079 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
18081 +#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
18082 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
18083 +DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
18084 +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
18086 +#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
18087 +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
18088 +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
18090 +/** @name Functions for Show/Store of Attributes */
18094 + * Helper function returning the otg_device structure of the given device
18096 +static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
18098 + dwc_otg_device_t *otg_dev;
18099 + DWC_OTG_GETDRVDEV(otg_dev, _dev);
18104 + * Show the register offset of the Register Access.
18106 +static ssize_t regoffset_show(struct device *_dev,
18107 + struct device_attribute *attr, char *buf)
18109 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18110 + return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
18111 + otg_dev->os_dep.reg_offset);
18115 + * Set the register offset for the next Register Access Read/Write
18117 +static ssize_t regoffset_store(struct device *_dev,
18118 + struct device_attribute *attr,
18119 + const char *buf, size_t count)
18121 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18122 + uint32_t offset = simple_strtoul(buf, NULL, 16);
18123 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
18124 + if (offset < SZ_256K) {
18125 +#elif defined(PCI_INTERFACE)
18126 + if (offset < 0x00040000) {
18128 + otg_dev->os_dep.reg_offset = offset;
18130 + dev_err(_dev, "invalid offset\n");
18136 +DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
18139 + * Show the value of the register at the offset in the reg_offset
18142 +static ssize_t regvalue_show(struct device *_dev,
18143 + struct device_attribute *attr, char *buf)
18145 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18147 + volatile uint32_t *addr;
18149 + if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
18150 + /* Calculate the address */
18151 + addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
18152 + (uint8_t *) otg_dev->os_dep.base);
18153 + val = DWC_READ_REG32(addr);
18154 + return snprintf(buf,
18155 + sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
18156 + "Reg@0x%06x = 0x%08x\n", otg_dev->os_dep.reg_offset,
18159 + dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->os_dep.reg_offset);
18160 + return sprintf(buf, "invalid offset\n");
18165 + * Store the value in the register at the offset in the reg_offset
18169 +static ssize_t regvalue_store(struct device *_dev,
18170 + struct device_attribute *attr,
18171 + const char *buf, size_t count)
18173 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18174 + volatile uint32_t *addr;
18175 + uint32_t val = simple_strtoul(buf, NULL, 16);
18176 + //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
18177 + if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
18178 + /* Calculate the address */
18179 + addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
18180 + (uint8_t *) otg_dev->os_dep.base);
18181 + DWC_WRITE_REG32(addr, val);
18183 + dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
18184 + otg_dev->os_dep.reg_offset);
18189 +DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
18194 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
18195 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
18196 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "SRPCapable");
18197 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
18198 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");
18200 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
18201 +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
18202 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");
18204 +DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
18205 +DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
18206 + &(otg_dev->core_if->core_global_regs->gusbcfg),
18208 +DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
18209 + &(otg_dev->core_if->core_global_regs->grxfsiz),
18211 +DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
18212 + &(otg_dev->core_if->core_global_regs->gnptxfsiz),
18214 +DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
18215 + &(otg_dev->core_if->core_global_regs->gpvndctl),
18217 +DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
18218 + &(otg_dev->core_if->core_global_regs->ggpio),
18220 +DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
18222 +DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
18223 + &(otg_dev->core_if->core_global_regs->gsnpsid),
18225 +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
18226 +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");
18228 +DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
18229 + &(otg_dev->core_if->core_global_regs->hptxfsiz),
18231 +DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
18234 + * @todo Add code to initiate the HNP.
18237 + * Show the HNP status bit
18239 +static ssize_t hnp_show(struct device *_dev,
18240 + struct device_attribute *attr, char *buf)
18242 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18243 + return sprintf(buf, "HstNegScs = 0x%x\n",
18244 + dwc_otg_get_hnpstatus(otg_dev->core_if));
18248 + * Set the HNP Request bit
18250 +static ssize_t hnp_store(struct device *_dev,
18251 + struct device_attribute *attr,
18252 + const char *buf, size_t count)
18254 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18255 + uint32_t in = simple_strtoul(buf, NULL, 16);
18256 + dwc_otg_set_hnpreq(otg_dev->core_if, in);
18260 +DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
18263 + * @todo Add code to initiate the SRP.
18266 + * Show the SRP status bit
18268 +static ssize_t srp_show(struct device *_dev,
18269 + struct device_attribute *attr, char *buf)
18271 +#ifndef DWC_HOST_ONLY
18272 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18273 + return sprintf(buf, "SesReqScs = 0x%x\n",
18274 + dwc_otg_get_srpstatus(otg_dev->core_if));
18276 + return sprintf(buf, "Host Only Mode!\n");
18281 + * Set the SRP Request bit
18283 +static ssize_t srp_store(struct device *_dev,
18284 + struct device_attribute *attr,
18285 + const char *buf, size_t count)
18287 +#ifndef DWC_HOST_ONLY
18288 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18289 + dwc_otg_pcd_initiate_srp(otg_dev->pcd);
18294 +DEVICE_ATTR(srp, 0644, srp_show, srp_store);
18297 + * @todo Need to do more for power on/off?
18300 + * Show the Bus Power status
18302 +static ssize_t buspower_show(struct device *_dev,
18303 + struct device_attribute *attr, char *buf)
18305 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18306 + return sprintf(buf, "Bus Power = 0x%x\n",
18307 + dwc_otg_get_prtpower(otg_dev->core_if));
18311 + * Set the Bus Power status
18313 +static ssize_t buspower_store(struct device *_dev,
18314 + struct device_attribute *attr,
18315 + const char *buf, size_t count)
18317 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18318 + uint32_t on = simple_strtoul(buf, NULL, 16);
18319 + dwc_otg_set_prtpower(otg_dev->core_if, on);
18323 +DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
18326 + * @todo Need to do more for suspend?
18329 + * Show the Bus Suspend status
18331 +static ssize_t bussuspend_show(struct device *_dev,
18332 + struct device_attribute *attr, char *buf)
18334 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18335 + return sprintf(buf, "Bus Suspend = 0x%x\n",
18336 + dwc_otg_get_prtsuspend(otg_dev->core_if));
18340 + * Set the Bus Suspend status
18342 +static ssize_t bussuspend_store(struct device *_dev,
18343 + struct device_attribute *attr,
18344 + const char *buf, size_t count)
18346 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18347 + uint32_t in = simple_strtoul(buf, NULL, 16);
18348 + dwc_otg_set_prtsuspend(otg_dev->core_if, in);
18352 +DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
18355 + * Show the Mode Change Ready Timer status
18357 +static ssize_t mode_ch_tim_en_show(struct device *_dev,
18358 + struct device_attribute *attr, char *buf)
18360 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18361 + return sprintf(buf, "Mode Change Ready Timer Enable = 0x%x\n",
18362 + dwc_otg_get_mode_ch_tim(otg_dev->core_if));
18366 + * Set the Mode Change Ready Timer status
18368 +static ssize_t mode_ch_tim_en_store(struct device *_dev,
18369 + struct device_attribute *attr,
18370 + const char *buf, size_t count)
18372 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18373 + uint32_t in = simple_strtoul(buf, NULL, 16);
18374 + dwc_otg_set_mode_ch_tim(otg_dev->core_if, in);
18378 +DEVICE_ATTR(mode_ch_tim_en, 0644, mode_ch_tim_en_show, mode_ch_tim_en_store);
18381 + * Show the value of HFIR Frame Interval bitfield
18383 +static ssize_t fr_interval_show(struct device *_dev,
18384 + struct device_attribute *attr, char *buf)
18386 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18387 + return sprintf(buf, "Frame Interval = 0x%x\n",
18388 + dwc_otg_get_fr_interval(otg_dev->core_if));
18392 + * Set the HFIR Frame Interval value
18394 +static ssize_t fr_interval_store(struct device *_dev,
18395 + struct device_attribute *attr,
18396 + const char *buf, size_t count)
18398 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18399 + uint32_t in = simple_strtoul(buf, NULL, 10);
18400 + dwc_otg_set_fr_interval(otg_dev->core_if, in);
18404 +DEVICE_ATTR(fr_interval, 0644, fr_interval_show, fr_interval_store);
18407 + * Show the status of Remote Wakeup.
18409 +static ssize_t remote_wakeup_show(struct device *_dev,
18410 + struct device_attribute *attr, char *buf)
18412 +#ifndef DWC_HOST_ONLY
18413 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18415 + return sprintf(buf,
18416 + "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
18417 + dwc_otg_get_remotewakesig(otg_dev->core_if),
18418 + dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
18419 + dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
18421 + return sprintf(buf, "Host Only Mode!\n");
18422 +#endif /* DWC_HOST_ONLY */
18426 + * Initiate a remote wakeup of the host. The Device control register
18427 + * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
18431 +static ssize_t remote_wakeup_store(struct device *_dev,
18432 + struct device_attribute *attr,
18433 + const char *buf, size_t count)
18435 +#ifndef DWC_HOST_ONLY
18436 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18437 + uint32_t val = simple_strtoul(buf, NULL, 16);
18440 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
18442 + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
18444 +#endif /* DWC_HOST_ONLY */
18448 +DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
18449 + remote_wakeup_store);
18452 + * Show the whether core is hibernated or not.
18454 +static ssize_t rem_wakeup_pwrdn_show(struct device *_dev,
18455 + struct device_attribute *attr, char *buf)
18457 +#ifndef DWC_HOST_ONLY
18458 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18460 + if (dwc_otg_get_core_state(otg_dev->core_if)) {
18461 + DWC_PRINTF("Core is in hibernation\n");
18463 + DWC_PRINTF("Core is not in hibernation\n");
18465 +#endif /* DWC_HOST_ONLY */
18469 +extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
18470 + int rem_wakeup, int reset);
18473 + * Initiate a remote wakeup of the device to exit from hibernation.
18475 +static ssize_t rem_wakeup_pwrdn_store(struct device *_dev,
18476 + struct device_attribute *attr,
18477 + const char *buf, size_t count)
18479 +#ifndef DWC_HOST_ONLY
18480 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18481 + dwc_otg_device_hibernation_restore(otg_dev->core_if, 1, 0);
18486 +DEVICE_ATTR(rem_wakeup_pwrdn, S_IRUGO | S_IWUSR, rem_wakeup_pwrdn_show,
18487 + rem_wakeup_pwrdn_store);
18489 +static ssize_t disconnect_us(struct device *_dev,
18490 + struct device_attribute *attr,
18491 + const char *buf, size_t count)
18494 +#ifndef DWC_HOST_ONLY
18495 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18496 + uint32_t val = simple_strtoul(buf, NULL, 16);
18497 + DWC_PRINTF("The Passed value is %04x\n", val);
18499 + dwc_otg_pcd_disconnect_us(otg_dev->pcd, 50);
18501 +#endif /* DWC_HOST_ONLY */
18505 +DEVICE_ATTR(disconnect_us, S_IWUSR, 0, disconnect_us);
18508 + * Dump global registers and either host or device registers (depending on the
18509 + * current mode of the core).
18511 +static ssize_t regdump_show(struct device *_dev,
18512 + struct device_attribute *attr, char *buf)
18514 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18516 + dwc_otg_dump_global_registers(otg_dev->core_if);
18517 + if (dwc_otg_is_host_mode(otg_dev->core_if)) {
18518 + dwc_otg_dump_host_registers(otg_dev->core_if);
18520 + dwc_otg_dump_dev_registers(otg_dev->core_if);
18523 + return sprintf(buf, "Register Dump\n");
18526 +DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);
18529 + * Dump global registers and either host or device registers (depending on the
18530 + * current mode of the core).
18532 +static ssize_t spramdump_show(struct device *_dev,
18533 + struct device_attribute *attr, char *buf)
18535 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18537 + dwc_otg_dump_spram(otg_dev->core_if);
18539 + return sprintf(buf, "SPRAM Dump\n");
18542 +DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);
18545 + * Dump the current hcd state.
18547 +static ssize_t hcddump_show(struct device *_dev,
18548 + struct device_attribute *attr, char *buf)
18550 +#ifndef DWC_DEVICE_ONLY
18551 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18552 + dwc_otg_hcd_dump_state(otg_dev->hcd);
18553 +#endif /* DWC_DEVICE_ONLY */
18554 + return sprintf(buf, "HCD Dump\n");
18557 +DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);
18560 + * Dump the average frame remaining at SOF. This can be used to
18561 + * determine average interrupt latency. Frame remaining is also shown for
18562 + * start transfer and two additional sample points.
18564 +static ssize_t hcd_frrem_show(struct device *_dev,
18565 + struct device_attribute *attr, char *buf)
18567 +#ifndef DWC_DEVICE_ONLY
18568 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18570 + dwc_otg_hcd_dump_frrem(otg_dev->hcd);
18571 +#endif /* DWC_DEVICE_ONLY */
18572 + return sprintf(buf, "HCD Dump Frame Remaining\n");
18575 +DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);
18578 + * Displays the time required to read the GNPTXFSIZ register many times (the
18579 + * output shows the number of times the register is read).
18581 +#define RW_REG_COUNT 10000000
18582 +#define MSEC_PER_JIFFIE 1000/HZ
18583 +static ssize_t rd_reg_test_show(struct device *_dev,
18584 + struct device_attribute *attr, char *buf)
18586 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18589 + int start_jiffies;
18591 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
18592 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
18593 + start_jiffies = jiffies;
18594 + for (i = 0; i < RW_REG_COUNT; i++) {
18595 + dwc_otg_get_gnptxfsiz(otg_dev->core_if);
18597 + time = jiffies - start_jiffies;
18598 + return sprintf(buf,
18599 + "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
18600 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
18603 +DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);
18606 + * Displays the time required to write the GNPTXFSIZ register many times (the
18607 + * output shows the number of times the register is written).
18609 +static ssize_t wr_reg_test_show(struct device *_dev,
18610 + struct device_attribute *attr, char *buf)
18612 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18613 + uint32_t reg_val;
18616 + int start_jiffies;
18618 + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
18619 + HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
18620 + reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
18621 + start_jiffies = jiffies;
18622 + for (i = 0; i < RW_REG_COUNT; i++) {
18623 + dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);
18625 + time = jiffies - start_jiffies;
18626 + return sprintf(buf,
18627 + "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
18628 + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
18631 +DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);
18633 +#ifdef CONFIG_USB_DWC_OTG_LPM
18636 +* Show the lpm_response attribute.
18638 +static ssize_t lpmresp_show(struct device *_dev,
18639 + struct device_attribute *attr, char *buf)
18641 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18643 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
18644 + return sprintf(buf, "** LPM is DISABLED **\n");
18646 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
18647 + return sprintf(buf, "** Current mode is not device mode\n");
18649 + return sprintf(buf, "lpm_response = %d\n",
18650 + dwc_otg_get_lpmresponse(otg_dev->core_if));
18654 +* Store the lpm_response attribute.
18656 +static ssize_t lpmresp_store(struct device *_dev,
18657 + struct device_attribute *attr,
18658 + const char *buf, size_t count)
18660 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18661 + uint32_t val = simple_strtoul(buf, NULL, 16);
18663 + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
18667 + if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
18671 + dwc_otg_set_lpmresponse(otg_dev->core_if, val);
18675 +DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);
18678 +* Show the sleep_status attribute.
18680 +static ssize_t sleepstatus_show(struct device *_dev,
18681 + struct device_attribute *attr, char *buf)
18683 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18684 + return sprintf(buf, "Sleep Status = %d\n",
18685 + dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
18689 + * Store the sleep_status attribure.
18691 +static ssize_t sleepstatus_store(struct device *_dev,
18692 + struct device_attribute *attr,
18693 + const char *buf, size_t count)
18695 + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
18696 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
18698 + if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
18699 + if (dwc_otg_is_host_mode(core_if)) {
18701 + DWC_PRINTF("Host initiated resume\n");
18702 + dwc_otg_set_prtresume(otg_dev->core_if, 1);
18709 +DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
18710 + sleepstatus_store);
18712 +#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */
18717 + * Create the device files
18719 +void dwc_otg_attr_create(
18720 +#ifdef LM_INTERFACE
18721 + struct lm_device *dev
18722 +#elif defined(PCI_INTERFACE)
18723 + struct pci_dev *dev
18724 +#elif defined(PLATFORM_INTERFACE)
18725 + struct platform_device *dev
18731 + error = device_create_file(&dev->dev, &dev_attr_regoffset);
18732 + error = device_create_file(&dev->dev, &dev_attr_regvalue);
18733 + error = device_create_file(&dev->dev, &dev_attr_mode);
18734 + error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
18735 + error = device_create_file(&dev->dev, &dev_attr_srpcapable);
18736 + error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
18737 + error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
18738 + error = device_create_file(&dev->dev, &dev_attr_hnp);
18739 + error = device_create_file(&dev->dev, &dev_attr_srp);
18740 + error = device_create_file(&dev->dev, &dev_attr_buspower);
18741 + error = device_create_file(&dev->dev, &dev_attr_bussuspend);
18742 + error = device_create_file(&dev->dev, &dev_attr_mode_ch_tim_en);
18743 + error = device_create_file(&dev->dev, &dev_attr_fr_interval);
18744 + error = device_create_file(&dev->dev, &dev_attr_busconnected);
18745 + error = device_create_file(&dev->dev, &dev_attr_gotgctl);
18746 + error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
18747 + error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
18748 + error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
18749 + error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
18750 + error = device_create_file(&dev->dev, &dev_attr_ggpio);
18751 + error = device_create_file(&dev->dev, &dev_attr_guid);
18752 + error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
18753 + error = device_create_file(&dev->dev, &dev_attr_devspeed);
18754 + error = device_create_file(&dev->dev, &dev_attr_enumspeed);
18755 + error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
18756 + error = device_create_file(&dev->dev, &dev_attr_hprt0);
18757 + error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
18758 + error = device_create_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
18759 + error = device_create_file(&dev->dev, &dev_attr_disconnect_us);
18760 + error = device_create_file(&dev->dev, &dev_attr_regdump);
18761 + error = device_create_file(&dev->dev, &dev_attr_spramdump);
18762 + error = device_create_file(&dev->dev, &dev_attr_hcddump);
18763 + error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
18764 + error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
18765 + error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
18766 +#ifdef CONFIG_USB_DWC_OTG_LPM
18767 + error = device_create_file(&dev->dev, &dev_attr_lpm_response);
18768 + error = device_create_file(&dev->dev, &dev_attr_sleep_status);
18773 + * Remove the device files
18775 +void dwc_otg_attr_remove(
18776 +#ifdef LM_INTERFACE
18777 + struct lm_device *dev
18778 +#elif defined(PCI_INTERFACE)
18779 + struct pci_dev *dev
18780 +#elif defined(PLATFORM_INTERFACE)
18781 + struct platform_device *dev
18785 + device_remove_file(&dev->dev, &dev_attr_regoffset);
18786 + device_remove_file(&dev->dev, &dev_attr_regvalue);
18787 + device_remove_file(&dev->dev, &dev_attr_mode);
18788 + device_remove_file(&dev->dev, &dev_attr_hnpcapable);
18789 + device_remove_file(&dev->dev, &dev_attr_srpcapable);
18790 + device_remove_file(&dev->dev, &dev_attr_hsic_connect);
18791 + device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
18792 + device_remove_file(&dev->dev, &dev_attr_hnp);
18793 + device_remove_file(&dev->dev, &dev_attr_srp);
18794 + device_remove_file(&dev->dev, &dev_attr_buspower);
18795 + device_remove_file(&dev->dev, &dev_attr_bussuspend);
18796 + device_remove_file(&dev->dev, &dev_attr_mode_ch_tim_en);
18797 + device_remove_file(&dev->dev, &dev_attr_fr_interval);
18798 + device_remove_file(&dev->dev, &dev_attr_busconnected);
18799 + device_remove_file(&dev->dev, &dev_attr_gotgctl);
18800 + device_remove_file(&dev->dev, &dev_attr_gusbcfg);
18801 + device_remove_file(&dev->dev, &dev_attr_grxfsiz);
18802 + device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
18803 + device_remove_file(&dev->dev, &dev_attr_gpvndctl);
18804 + device_remove_file(&dev->dev, &dev_attr_ggpio);
18805 + device_remove_file(&dev->dev, &dev_attr_guid);
18806 + device_remove_file(&dev->dev, &dev_attr_gsnpsid);
18807 + device_remove_file(&dev->dev, &dev_attr_devspeed);
18808 + device_remove_file(&dev->dev, &dev_attr_enumspeed);
18809 + device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
18810 + device_remove_file(&dev->dev, &dev_attr_hprt0);
18811 + device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
18812 + device_remove_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
18813 + device_remove_file(&dev->dev, &dev_attr_disconnect_us);
18814 + device_remove_file(&dev->dev, &dev_attr_regdump);
18815 + device_remove_file(&dev->dev, &dev_attr_spramdump);
18816 + device_remove_file(&dev->dev, &dev_attr_hcddump);
18817 + device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
18818 + device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
18819 + device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
18820 +#ifdef CONFIG_USB_DWC_OTG_LPM
18821 + device_remove_file(&dev->dev, &dev_attr_lpm_response);
18822 + device_remove_file(&dev->dev, &dev_attr_sleep_status);
18825 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.h b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
18826 new file mode 100644
18827 index 0000000..fc14d94
18829 +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
18831 +/* ==========================================================================
18832 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
18833 + * $Revision: #13 $
18834 + * $Date: 2010/06/21 $
18835 + * $Change: 1532021 $
18837 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
18838 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
18839 + * otherwise expressly agreed to in writing between Synopsys and you.
18841 + * The Software IS NOT an item of Licensed Software or Licensed Product under
18842 + * any End User Software License Agreement or Agreement for Licensed Product
18843 + * with Synopsys or any supplement thereto. You are permitted to use and
18844 + * redistribute this Software in source and binary forms, with or without
18845 + * modification, provided that redistributions of source code must retain this
18846 + * notice. You may not view, use, disclose, copy or distribute this file or
18847 + * any information contained herein except pursuant to this license grant from
18848 + * Synopsys. If you do not agree with this notice, including the disclaimer
18849 + * below, then you are not authorized to use the Software.
18851 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
18852 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18853 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18854 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
18855 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18856 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18857 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18858 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18859 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18860 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
18862 + * ========================================================================== */
18864 +#if !defined(__DWC_OTG_ATTR_H__)
18865 +#define __DWC_OTG_ATTR_H__
18868 + * This file contains the interface to the Linux device attributes.
18870 +extern struct device_attribute dev_attr_regoffset;
18871 +extern struct device_attribute dev_attr_regvalue;
18873 +extern struct device_attribute dev_attr_mode;
18874 +extern struct device_attribute dev_attr_hnpcapable;
18875 +extern struct device_attribute dev_attr_srpcapable;
18876 +extern struct device_attribute dev_attr_hnp;
18877 +extern struct device_attribute dev_attr_srp;
18878 +extern struct device_attribute dev_attr_buspower;
18879 +extern struct device_attribute dev_attr_bussuspend;
18880 +extern struct device_attribute dev_attr_mode_ch_tim_en;
18881 +extern struct device_attribute dev_attr_fr_interval;
18882 +extern struct device_attribute dev_attr_busconnected;
18883 +extern struct device_attribute dev_attr_gotgctl;
18884 +extern struct device_attribute dev_attr_gusbcfg;
18885 +extern struct device_attribute dev_attr_grxfsiz;
18886 +extern struct device_attribute dev_attr_gnptxfsiz;
18887 +extern struct device_attribute dev_attr_gpvndctl;
18888 +extern struct device_attribute dev_attr_ggpio;
18889 +extern struct device_attribute dev_attr_guid;
18890 +extern struct device_attribute dev_attr_gsnpsid;
18891 +extern struct device_attribute dev_attr_devspeed;
18892 +extern struct device_attribute dev_attr_enumspeed;
18893 +extern struct device_attribute dev_attr_hptxfsiz;
18894 +extern struct device_attribute dev_attr_hprt0;
18895 +#ifdef CONFIG_USB_DWC_OTG_LPM
18896 +extern struct device_attribute dev_attr_lpm_response;
18897 +extern struct device_attribute devi_attr_sleep_status;
18900 +void dwc_otg_attr_create(
18901 +#ifdef LM_INTERFACE
18902 + struct lm_device *dev
18903 +#elif defined(PCI_INTERFACE)
18904 + struct pci_dev *dev
18905 +#elif defined(PLATFORM_INTERFACE)
18906 + struct platform_device *dev
18910 +void dwc_otg_attr_remove(
18911 +#ifdef LM_INTERFACE
18912 + struct lm_device *dev
18913 +#elif defined(PCI_INTERFACE)
18914 + struct pci_dev *dev
18915 +#elif defined(PLATFORM_INTERFACE)
18916 + struct platform_device *dev
18920 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cfi.c b/drivers/usb/host/dwc_otg/dwc_otg_cfi.c
18921 new file mode 100644
18922 index 0000000..a9878d6
18924 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.c
18926 +/* ==========================================================================
18927 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
18928 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
18929 + * otherwise expressly agreed to in writing between Synopsys and you.
18931 + * The Software IS NOT an item of Licensed Software or Licensed Product under
18932 + * any End User Software License Agreement or Agreement for Licensed Product
18933 + * with Synopsys or any supplement thereto. You are permitted to use and
18934 + * redistribute this Software in source and binary forms, with or without
18935 + * modification, provided that redistributions of source code must retain this
18936 + * notice. You may not view, use, disclose, copy or distribute this file or
18937 + * any information contained herein except pursuant to this license grant from
18938 + * Synopsys. If you do not agree with this notice, including the disclaimer
18939 + * below, then you are not authorized to use the Software.
18941 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
18942 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18943 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18944 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
18945 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18946 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18947 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18948 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18949 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18950 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
18952 + * ========================================================================== */
18956 + * This file contains the most of the CFI(Core Feature Interface)
18957 + * implementation for the OTG.
18960 +#ifdef DWC_UTE_CFI
18962 +#include "dwc_otg_pcd.h"
18963 +#include "dwc_otg_cfi.h"
18965 +/** This definition should actually migrate to the Portability Library */
18966 +#define DWC_CONSTANT_CPU_TO_LE16(x) (x)
18968 +extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex);
18970 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen);
18971 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
18972 + struct dwc_otg_pcd *pcd,
18973 + struct cfi_usb_ctrlrequest *ctrl_req);
18974 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd);
18975 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18976 + struct cfi_usb_ctrlrequest *req);
18977 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18978 + struct cfi_usb_ctrlrequest *req);
18979 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
18980 + struct cfi_usb_ctrlrequest *req);
18981 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
18982 + struct cfi_usb_ctrlrequest *req);
18983 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep);
18985 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if);
18986 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue);
18987 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue);
18989 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if);
18991 +/** This is the header of the all features descriptor */
18992 +static cfi_all_features_header_t all_props_desc_header = {
18993 + .wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100),
18994 + .wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG),
18995 + .wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9),
18998 +/** This is an array of statically allocated feature descriptors */
18999 +static cfi_feature_desc_header_t prop_descs[] = {
19001 + /* FT_ID_DMA_MODE */
19003 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE),
19004 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19005 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1),
19008 + /* FT_ID_DMA_BUFFER_SETUP */
19010 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP),
19011 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19012 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
19015 + /* FT_ID_DMA_BUFF_ALIGN */
19017 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN),
19018 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19019 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
19022 + /* FT_ID_DMA_CONCAT_SETUP */
19024 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP),
19025 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19026 + //.wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
19029 + /* FT_ID_DMA_CIRCULAR */
19031 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR),
19032 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19033 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
19036 + /* FT_ID_THRESHOLD_SETUP */
19038 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP),
19039 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19040 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
19043 + /* FT_ID_DFIFO_DEPTH */
19045 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH),
19046 + .bmAttributes = CFI_FEATURE_ATTR_RO,
19047 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
19050 + /* FT_ID_TX_FIFO_DEPTH */
19052 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH),
19053 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19054 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
19057 + /* FT_ID_RX_FIFO_DEPTH */
19059 + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH),
19060 + .bmAttributes = CFI_FEATURE_ATTR_RW,
19061 + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
19065 +/** The table of feature names */
19066 +cfi_string_t prop_name_table[] = {
19067 + {FT_ID_DMA_MODE, "dma_mode"},
19068 + {FT_ID_DMA_BUFFER_SETUP, "buffer_setup"},
19069 + {FT_ID_DMA_BUFF_ALIGN, "buffer_align"},
19070 + {FT_ID_DMA_CONCAT_SETUP, "concat_setup"},
19071 + {FT_ID_DMA_CIRCULAR, "buffer_circular"},
19072 + {FT_ID_THRESHOLD_SETUP, "threshold_setup"},
19073 + {FT_ID_DFIFO_DEPTH, "dfifo_depth"},
19074 + {FT_ID_TX_FIFO_DEPTH, "txfifo_depth"},
19075 + {FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"},
19079 +/************************************************************************/
19082 + * Returns the name of the feature by its ID
19083 + * or NULL if no featute ID matches.
19086 +const uint8_t *get_prop_name(uint16_t prop_id, int *len)
19088 + cfi_string_t *pstr;
19091 + for (pstr = prop_name_table; pstr && pstr->s; pstr++) {
19092 + if (pstr->id == prop_id) {
19093 + *len = DWC_STRLEN(pstr->s);
19101 + * This function handles all CFI specific control requests.
19103 + * Return a negative value to stall the DCE.
19105 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)
19108 + dwc_otg_pcd_ep_t *ep = NULL;
19109 + cfiobject_t *cfi = pcd->cfi;
19110 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
19111 + uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength);
19112 + uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue);
19113 + uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex);
19114 + uint32_t regaddr = 0;
19115 + uint32_t regval = 0;
19117 + /* Save this Control Request in the CFI object.
19118 + * The data field will be assigned in the data stage completion CB function.
19120 + cfi->ctrl_req = *ctrl;
19121 + cfi->ctrl_req.data = NULL;
19123 + cfi->need_gadget_att = 0;
19124 + cfi->need_status_in_complete = 0;
19126 + switch (ctrl->bRequest) {
19127 + case VEN_CORE_GET_FEATURES:
19128 + retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN);
19129 + if (retval >= 0) {
19130 + //dump_msg(cfi->buf_in.buf, retval);
19133 + retval = min((uint16_t) retval, wLen);
19134 + /* Transfer this buffer to the host through the EP0-IN EP */
19135 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
19136 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
19137 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
19138 + ep->dwc_ep.xfer_len = retval;
19139 + ep->dwc_ep.xfer_count = 0;
19140 + ep->dwc_ep.sent_zlp = 0;
19141 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19143 + pcd->ep0_pending = 1;
19144 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19149 + case VEN_CORE_GET_FEATURE:
19150 + CFI_INFO("VEN_CORE_GET_FEATURE\n");
19151 + retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN,
19153 + if (retval >= 0) {
19156 + retval = min((uint16_t) retval, wLen);
19157 + /* Transfer this buffer to the host through the EP0-IN EP */
19158 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
19159 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
19160 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
19161 + ep->dwc_ep.xfer_len = retval;
19162 + ep->dwc_ep.xfer_count = 0;
19163 + ep->dwc_ep.sent_zlp = 0;
19164 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19166 + pcd->ep0_pending = 1;
19167 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19169 + CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval);
19170 + dump_msg(cfi->buf_in.buf, retval);
19173 + case VEN_CORE_SET_FEATURE:
19174 + CFI_INFO("VEN_CORE_SET_FEATURE\n");
19175 + /* Set up an XFER to get the data stage of the control request,
19176 + * which is the new value of the feature to be modified.
19179 + ep->dwc_ep.is_in = 0;
19180 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
19181 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
19182 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
19183 + ep->dwc_ep.xfer_len = wLen;
19184 + ep->dwc_ep.xfer_count = 0;
19185 + ep->dwc_ep.sent_zlp = 0;
19186 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19188 + pcd->ep0_pending = 1;
19189 + /* Read the control write's data stage */
19190 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19194 + case VEN_CORE_RESET_FEATURES:
19195 + CFI_INFO("VEN_CORE_RESET_FEATURES\n");
19196 + cfi->need_gadget_att = 1;
19197 + cfi->need_status_in_complete = 1;
19198 + retval = cfi_preproc_reset(pcd, ctrl);
19199 + CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval);
19202 + case VEN_CORE_ACTIVATE_FEATURES:
19203 + CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n");
19206 + case VEN_CORE_READ_REGISTER:
19207 + CFI_INFO("VEN_CORE_READ_REGISTER\n");
19208 + /* wValue optionally contains the HI WORD of the register offset and
19209 + * wIndex contains the LOW WORD of the register offset
19211 + if (wValue == 0) {
19212 + /* @TODO - MAS - fix the access to the base field */
19214 + //regaddr = (uint32_t) pcd->otg_dev->os_dep.base;
19215 + //GET_CORE_IF(pcd)->co
19216 + regaddr |= wIndex;
19218 + regaddr = (wValue << 16) | wIndex;
19221 + /* Read a 32-bit value of the memory at the regaddr */
19222 + regval = DWC_READ_REG32((uint32_t *) regaddr);
19225 + dwc_memcpy(cfi->buf_in.buf, ®val, sizeof(uint32_t));
19226 + ep->dwc_ep.is_in = 1;
19227 + ep->dwc_ep.dma_addr = cfi->buf_in.addr;
19228 + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
19229 + ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
19230 + ep->dwc_ep.xfer_len = wLen;
19231 + ep->dwc_ep.xfer_count = 0;
19232 + ep->dwc_ep.sent_zlp = 0;
19233 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19235 + pcd->ep0_pending = 1;
19236 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19237 + cfi->need_gadget_att = 0;
19241 + case VEN_CORE_WRITE_REGISTER:
19242 + CFI_INFO("VEN_CORE_WRITE_REGISTER\n");
19243 + /* Set up an XFER to get the data stage of the control request,
19244 + * which is the new value of the register to be modified.
19247 + ep->dwc_ep.is_in = 0;
19248 + ep->dwc_ep.dma_addr = cfi->buf_out.addr;
19249 + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
19250 + ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
19251 + ep->dwc_ep.xfer_len = wLen;
19252 + ep->dwc_ep.xfer_count = 0;
19253 + ep->dwc_ep.sent_zlp = 0;
19254 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
19256 + pcd->ep0_pending = 1;
19257 + /* Read the control write's data stage */
19258 + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
19263 + retval = -DWC_E_NOT_SUPPORTED;
19271 + * This function prepares the core features descriptors and copies its
19272 + * raw representation into the buffer <buf>.
19274 + * The buffer structure is as follows:
19275 + * all_features_header (8 bytes)
19276 + * features_#1 (8 bytes + feature name string length)
19277 + * features_#2 (8 bytes + feature name string length)
19279 + * features_#n - where n=the total count of feature descriptors
19281 +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen)
19283 + cfi_feature_desc_header_t *prop_hdr = prop_descs;
19284 + cfi_feature_desc_header_t *prop;
19285 + cfi_all_features_header_t *all_props_hdr = &all_props_desc_header;
19286 + cfi_all_features_header_t *tmp;
19287 + uint8_t *tmpbuf = buf;
19288 + const uint8_t *pname = NULL;
19289 + int i, j, namelen = 0, totlen;
19291 + /* Prepare and copy the core features into the buffer */
19292 + CFI_INFO("%s:\n", __func__);
19294 + tmp = (cfi_all_features_header_t *) tmpbuf;
19295 + *tmp = *all_props_hdr;
19296 + tmpbuf += CFI_ALL_FEATURES_HDR_LEN;
19298 + j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t);
19299 + for (i = 0; i < j; i++, prop_hdr++) {
19300 + pname = get_prop_name(prop_hdr->wFeatureID, &namelen);
19301 + prop = (cfi_feature_desc_header_t *) tmpbuf;
19302 + *prop = *prop_hdr;
19304 + prop->bNameLen = namelen;
19306 + DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN +
19309 + tmpbuf += CFI_FEATURE_DESC_HDR_LEN;
19310 + dwc_memcpy(tmpbuf, pname, namelen);
19311 + tmpbuf += namelen;
19314 + totlen = tmpbuf - buf;
19316 + if (totlen > 0) {
19317 + tmp = (cfi_all_features_header_t *) buf;
19318 + tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen);
19325 + * This function releases all the dynamic memory in the CFI object.
19327 +static void cfi_release(cfiobject_t * cfiobj)
19330 + dwc_list_link_t *tmp;
19332 + CFI_INFO("%s\n", __func__);
19334 + if (cfiobj->buf_in.buf) {
19335 + DWC_DMA_FREE(CFI_IN_BUF_LEN, cfiobj->buf_in.buf,
19336 + cfiobj->buf_in.addr);
19337 + cfiobj->buf_in.buf = NULL;
19340 + if (cfiobj->buf_out.buf) {
19341 + DWC_DMA_FREE(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf,
19342 + cfiobj->buf_out.addr);
19343 + cfiobj->buf_out.buf = NULL;
19346 + /* Free the Buffer Setup values for each EP */
19347 + //list_for_each_entry(cfiep, &cfiobj->active_eps, lh) {
19348 + DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) {
19349 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19350 + cfi_free_ep_bs_dyn_data(cfiep);
19355 + * This function frees the dynamically allocated EP buffer setup data.
19357 +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep)
19359 + if (cfiep->bm_sg) {
19360 + DWC_FREE(cfiep->bm_sg);
19361 + cfiep->bm_sg = NULL;
19364 + if (cfiep->bm_align) {
19365 + DWC_FREE(cfiep->bm_align);
19366 + cfiep->bm_align = NULL;
19369 + if (cfiep->bm_concat) {
19370 + if (NULL != cfiep->bm_concat->wTxBytes) {
19371 + DWC_FREE(cfiep->bm_concat->wTxBytes);
19372 + cfiep->bm_concat->wTxBytes = NULL;
19374 + DWC_FREE(cfiep->bm_concat);
19375 + cfiep->bm_concat = NULL;
19380 + * This function initializes the default values of the features
19381 + * for a specific endpoint and should be called only once when
19382 + * the EP is enabled first time.
19384 +static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep)
19388 + cfiep->bm_sg = DWC_ALLOC(sizeof(ddma_sg_buffer_setup_t));
19389 + if (NULL == cfiep->bm_sg) {
19390 + CFI_INFO("Failed to allocate memory for SG feature value\n");
19391 + return -DWC_E_NO_MEMORY;
19393 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19395 + /* For the Concatenation feature's default value we do not allocate
19396 + * memory for the wTxBytes field - it will be done in the set_feature_value
19397 + * request handler.
19399 + cfiep->bm_concat = DWC_ALLOC(sizeof(ddma_concat_buffer_setup_t));
19400 + if (NULL == cfiep->bm_concat) {
19402 + ("Failed to allocate memory for CONCATENATION feature value\n");
19403 + DWC_FREE(cfiep->bm_sg);
19404 + return -DWC_E_NO_MEMORY;
19406 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
19408 + cfiep->bm_align = DWC_ALLOC(sizeof(ddma_align_buffer_setup_t));
19409 + if (NULL == cfiep->bm_align) {
19411 + ("Failed to allocate memory for Alignment feature value\n");
19412 + DWC_FREE(cfiep->bm_sg);
19413 + DWC_FREE(cfiep->bm_concat);
19414 + return -DWC_E_NO_MEMORY;
19416 + dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t));
19422 + * The callback function that notifies the CFI on the activation of
19423 + * an endpoint in the PCD. The following steps are done in this function:
19425 + * Create a dynamically allocated cfi_ep_t object (a CFI wrapper to the PCD's
19426 + * active endpoint)
19427 + * Create MAX_DMA_DESCS_PER_EP count DMA Descriptors for the EP
19428 + * Set the Buffer Mode to standard
19429 + * Initialize the default values for all EP modes (SG, Circular, Concat, Align)
19430 + * Add the cfi_ep_t object to the list of active endpoints in the CFI object
19432 +static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
19433 + struct dwc_otg_pcd_ep *ep)
19436 + int retval = -DWC_E_NOT_SUPPORTED;
19438 + CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__,
19439 + "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress);
19440 + /* MAS - Check whether this endpoint already is in the list */
19441 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
19443 + if (NULL == cfiep) {
19444 + /* Allocate a cfi_ep_t object */
19445 + cfiep = DWC_ALLOC(sizeof(cfi_ep_t));
19446 + if (NULL == cfiep) {
19448 + ("Unable to allocate memory for <cfiep> in function %s\n",
19450 + return -DWC_E_NO_MEMORY;
19452 + dwc_memset(cfiep, 0, sizeof(cfi_ep_t));
19454 + /* Save the dwc_otg_pcd_ep pointer in the cfiep object */
19457 + /* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */
19458 + ep->dwc_ep.descs =
19459 + DWC_DMA_ALLOC(MAX_DMA_DESCS_PER_EP *
19460 + sizeof(dwc_otg_dma_desc_t),
19461 + &ep->dwc_ep.descs_dma_addr);
19463 + if (NULL == ep->dwc_ep.descs) {
19465 + return -DWC_E_NO_MEMORY;
19468 + DWC_LIST_INIT(&cfiep->lh);
19470 + /* Set the buffer mode to BM_STANDARD. It will be modified
19471 + * when building descriptors for a specific buffer mode */
19472 + ep->dwc_ep.buff_mode = BM_STANDARD;
19474 + /* Create and initialize the default values for this EP's Buffer modes */
19475 + if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0)
19478 + /* Add the cfi_ep_t object to the CFI object's list of active endpoints */
19479 + DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh);
19481 + } else { /* The sought EP already is in the list */
19482 + CFI_INFO("%s: The sought EP already is in the list\n",
19490 + * This function is called when the data stage of a 3-stage Control Write request
19494 +static int cfi_ctrl_write_complete(struct cfiobject *cfi,
19495 + struct dwc_otg_pcd *pcd)
19497 + uint32_t addr, reg_value;
19498 + uint16_t wIndex, wValue;
19499 + uint8_t bRequest;
19500 + uint8_t *buf = cfi->buf_out.buf;
19501 + //struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved;
19502 + struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req;
19503 + int retval = -DWC_E_NOT_SUPPORTED;
19505 + CFI_INFO("%s\n", __func__);
19507 + bRequest = ctrl_req->bRequest;
19508 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
19509 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
19512 + * Save the pointer to the data stage in the ctrl_req's <data> field.
19513 + * The request should be already saved in the command stage by now.
19515 + ctrl_req->data = cfi->buf_out.buf;
19516 + cfi->need_status_in_complete = 0;
19517 + cfi->need_gadget_att = 0;
19519 + switch (bRequest) {
19520 + case VEN_CORE_WRITE_REGISTER:
19521 + /* The buffer contains raw data of the new value for the register */
19522 + reg_value = *((uint32_t *) buf);
19523 + if (wValue == 0) {
19525 + //addr = (uint32_t) pcd->otg_dev->os_dep.base;
19528 + addr = (wValue << 16) | wIndex;
19531 + //writel(reg_value, addr);
19534 + cfi->need_status_in_complete = 1;
19537 + case VEN_CORE_SET_FEATURE:
19538 + /* The buffer contains raw data of the new value of the feature */
19539 + retval = cfi_set_feature_value(pcd);
19543 + cfi->need_status_in_complete = 1;
19554 + * This function builds the DMA descriptors for the SG buffer mode.
19556 +static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19557 + dwc_otg_pcd_request_t * req)
19559 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19560 + ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg;
19561 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19562 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
19563 + dma_addr_t buff_addr = req->dma;
19565 + uint32_t txsize, off;
19567 + txsize = sgval->wSize;
19568 + off = sgval->bOffset;
19570 +// CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n",
19571 +// __func__, cfiep->ep->ep.name, txsize, off);
19573 + for (i = 0; i < sgval->bCount; i++) {
19574 + desc->status.b.bs = BS_HOST_BUSY;
19575 + desc->buf = buff_addr;
19576 + desc->status.b.l = 0;
19577 + desc->status.b.ioc = 0;
19578 + desc->status.b.sp = 0;
19579 + desc->status.b.bytes = txsize;
19580 + desc->status.b.bs = BS_HOST_READY;
19582 + /* Set the next address of the buffer */
19583 + buff_addr += txsize + off;
19584 + desc_last = desc;
19588 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
19589 + desc_last->status.b.l = 1;
19590 + desc_last->status.b.ioc = 1;
19591 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
19592 + /* Save the last DMA descriptor pointer */
19593 + cfiep->dma_desc_last = desc_last;
19594 + cfiep->desc_count = sgval->bCount;
19598 + * This function builds the DMA descriptors for the Concatenation buffer mode.
19600 +static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19601 + dwc_otg_pcd_request_t * req)
19603 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19604 + ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat;
19605 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19606 + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
19607 + dma_addr_t buff_addr = req->dma;
19609 + uint16_t *txsize;
19611 + txsize = concatval->wTxBytes;
19613 + for (i = 0; i < concatval->hdr.bDescCount; i++) {
19614 + desc->buf = buff_addr;
19615 + desc->status.b.bs = BS_HOST_BUSY;
19616 + desc->status.b.l = 0;
19617 + desc->status.b.ioc = 0;
19618 + desc->status.b.sp = 0;
19619 + desc->status.b.bytes = *txsize;
19620 + desc->status.b.bs = BS_HOST_READY;
19623 + /* Set the next address of the buffer */
19624 + buff_addr += UGETW(ep->desc->wMaxPacketSize);
19625 + desc_last = desc;
19629 + /* Set the last, ioc and sp bits on the Last DMA Descriptor */
19630 + desc_last->status.b.l = 1;
19631 + desc_last->status.b.ioc = 1;
19632 + desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
19633 + cfiep->dma_desc_last = desc_last;
19634 + cfiep->desc_count = concatval->hdr.bDescCount;
19638 + * This function builds the DMA descriptors for the Circular buffer mode
19640 +static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19641 + dwc_otg_pcd_request_t * req)
19643 + /* @todo: MAS - add implementation when this feature needs to be tested */
19647 + * This function builds the DMA descriptors for the Alignment buffer mode
19649 +static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
19650 + dwc_otg_pcd_request_t * req)
19652 + struct dwc_otg_pcd_ep *ep = cfiep->ep;
19653 + ddma_align_buffer_setup_t *alignval = cfiep->bm_align;
19654 + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
19655 + dma_addr_t buff_addr = req->dma;
19657 + desc->status.b.bs = BS_HOST_BUSY;
19658 + desc->status.b.l = 1;
19659 + desc->status.b.ioc = 1;
19660 + desc->status.b.sp = ep->dwc_ep.sent_zlp;
19661 + desc->status.b.bytes = req->length;
19662 + /* Adjust the buffer alignment */
19663 + desc->buf = (buff_addr + alignval->bAlign);
19664 + desc->status.b.bs = BS_HOST_READY;
19665 + cfiep->dma_desc_last = desc;
19666 + cfiep->desc_count = 1;
19670 + * This function builds the DMA descriptors chain for different modes of the
19671 + * buffer setup of an endpoint.
19673 +static void cfi_build_descriptors(struct cfiobject *cfi,
19674 + struct dwc_otg_pcd *pcd,
19675 + struct dwc_otg_pcd_ep *ep,
19676 + dwc_otg_pcd_request_t * req)
19680 + /* Get the cfiep by the dwc_otg_pcd_ep */
19681 + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
19682 + if (NULL == cfiep) {
19683 + CFI_INFO("%s: Unable to find a matching active endpoint\n",
19688 + cfiep->xfer_len = req->length;
19690 + /* Iterate through all the DMA descriptors */
19691 + switch (cfiep->ep->dwc_ep.buff_mode) {
19693 + cfi_build_sg_descs(cfi, cfiep, req);
19697 + cfi_build_concat_descs(cfi, cfiep, req);
19700 + case BM_CIRCULAR:
19701 + cfi_build_circ_descs(cfi, cfiep, req);
19705 + cfi_build_align_descs(cfi, cfiep, req);
19714 + * Allocate DMA buffer for different Buffer modes.
19716 +static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
19717 + struct dwc_otg_pcd_ep *ep, dma_addr_t * dma,
19718 + unsigned size, gfp_t flags)
19720 + return DWC_DMA_ALLOC(size, dma);
19724 + * This function initializes the CFI object.
19726 +int init_cfi(cfiobject_t * cfiobj)
19728 + CFI_INFO("%s\n", __func__);
19730 + /* Allocate a buffer for IN XFERs */
19731 + cfiobj->buf_in.buf =
19732 + DWC_DMA_ALLOC(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr);
19733 + if (NULL == cfiobj->buf_in.buf) {
19734 + CFI_INFO("Unable to allocate buffer for INs\n");
19735 + return -DWC_E_NO_MEMORY;
19738 + /* Allocate a buffer for OUT XFERs */
19739 + cfiobj->buf_out.buf =
19740 + DWC_DMA_ALLOC(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr);
19741 + if (NULL == cfiobj->buf_out.buf) {
19742 + CFI_INFO("Unable to allocate buffer for OUT\n");
19743 + return -DWC_E_NO_MEMORY;
19746 + /* Initialize the callback function pointers */
19747 + cfiobj->ops.release = cfi_release;
19748 + cfiobj->ops.ep_enable = cfi_ep_enable;
19749 + cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete;
19750 + cfiobj->ops.build_descriptors = cfi_build_descriptors;
19751 + cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf;
19753 + /* Initialize the list of active endpoints in the CFI object */
19754 + DWC_LIST_INIT(&cfiobj->active_eps);
19760 + * This function reads the required feature's current value into the buffer
19762 + * @retval: Returns negative as error, or the data length of the feature
19764 +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
19765 + struct dwc_otg_pcd *pcd,
19766 + struct cfi_usb_ctrlrequest *ctrl_req)
19768 + int retval = -DWC_E_NOT_SUPPORTED;
19769 + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
19770 + uint16_t dfifo, rxfifo, txfifo;
19772 + switch (ctrl_req->wIndex) {
19773 + /* Whether the DDMA is enabled or not */
19774 + case FT_ID_DMA_MODE:
19775 + *buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0;
19779 + case FT_ID_DMA_BUFFER_SETUP:
19780 + retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req);
19783 + case FT_ID_DMA_BUFF_ALIGN:
19784 + retval = cfi_ep_get_align_val(buf, pcd, ctrl_req);
19787 + case FT_ID_DMA_CONCAT_SETUP:
19788 + retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req);
19791 + case FT_ID_DMA_CIRCULAR:
19792 + CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n");
19795 + case FT_ID_THRESHOLD_SETUP:
19796 + CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n");
19799 + case FT_ID_DFIFO_DEPTH:
19800 + dfifo = get_dfifo_size(coreif);
19801 + *((uint16_t *) buf) = dfifo;
19802 + retval = sizeof(uint16_t);
19805 + case FT_ID_TX_FIFO_DEPTH:
19806 + retval = get_txfifo_size(pcd, ctrl_req->wValue);
19807 + if (retval >= 0) {
19809 + *((uint16_t *) buf) = txfifo;
19810 + retval = sizeof(uint16_t);
19814 + case FT_ID_RX_FIFO_DEPTH:
19815 + retval = get_rxfifo_size(coreif, ctrl_req->wValue);
19816 + if (retval >= 0) {
19818 + *((uint16_t *) buf) = rxfifo;
19819 + retval = sizeof(uint16_t);
19828 + * This function resets the SG for the specified EP to its default value
19830 +static int cfi_reset_sg_val(cfi_ep_t * cfiep)
19832 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19837 + * This function resets the Alignment for the specified EP to its default value
19839 +static int cfi_reset_align_val(cfi_ep_t * cfiep)
19841 + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
19846 + * This function resets the Concatenation for the specified EP to its default value
19847 + * This function will also set the value of the wTxBytes field to NULL after
19848 + * freeing the memory previously allocated for this field.
19850 +static int cfi_reset_concat_val(cfi_ep_t * cfiep)
19852 + /* First we need to free the wTxBytes field */
19853 + if (cfiep->bm_concat->wTxBytes) {
19854 + DWC_FREE(cfiep->bm_concat->wTxBytes);
19855 + cfiep->bm_concat->wTxBytes = NULL;
19858 + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
19863 + * This function resets all the buffer setups of the specified endpoint
19865 +static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep)
19867 + cfi_reset_sg_val(cfiep);
19868 + cfi_reset_align_val(cfiep);
19869 + cfi_reset_concat_val(cfiep);
19873 +static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr,
19874 + uint8_t rx_rst, uint8_t tx_rst)
19876 + int retval = -DWC_E_INVALID;
19877 + uint16_t tx_siz[15];
19878 + uint16_t rx_siz = 0;
19879 + dwc_otg_pcd_ep_t *ep = NULL;
19880 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
19881 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
19884 + rx_siz = params->dev_rx_fifo_size;
19885 + params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz;
19889 + if (ep_addr == 0) {
19892 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
19894 + core_if->core_params->dev_tx_fifo_size[i];
19895 + core_if->core_params->dev_tx_fifo_size[i] =
19896 + core_if->init_txfsiz[i];
19900 + ep = get_ep_by_addr(pcd, ep_addr);
19902 + if (NULL == ep) {
19904 + ("%s: Unable to get the endpoint addr=0x%02x\n",
19905 + __func__, ep_addr);
19906 + return -DWC_E_INVALID;
19910 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num -
19912 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] =
19913 + GET_CORE_IF(pcd)->init_txfsiz[ep->
19914 + dwc_ep.tx_fifo_num -
19919 + if (resize_fifos(GET_CORE_IF(pcd))) {
19923 + ("%s: Error resetting the feature Reset All(FIFO size)\n",
19926 + params->dev_rx_fifo_size = rx_siz;
19930 + if (ep_addr == 0) {
19932 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps;
19935 + core_params->dev_tx_fifo_size[i] =
19939 + params->dev_tx_fifo_size[ep->
19940 + dwc_ep.tx_fifo_num -
19944 + retval = -DWC_E_INVALID;
19949 +static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr)
19953 + cfiobject_t *cfi = pcd->cfi;
19954 + dwc_list_link_t *tmp;
19956 + retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1);
19957 + if (retval < 0) {
19961 + /* If the EP address is known then reset the features for only that EP */
19963 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
19964 + if (NULL == cfiep) {
19965 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
19967 + return -DWC_E_INVALID;
19969 + retval = cfi_ep_reset_all_setup_vals(cfiep);
19970 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
19972 + /* Otherwise (wValue == 0), reset all features of all EP's */
19974 + /* Traverse all the active EP's and reset the feature(s) value(s) */
19975 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
19976 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
19977 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
19978 + retval = cfi_ep_reset_all_setup_vals(cfiep);
19979 + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
19980 + if (retval < 0) {
19982 + ("%s: Error resetting the feature Reset All\n",
19991 +static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd,
19996 + cfiobject_t *cfi = pcd->cfi;
19997 + dwc_list_link_t *tmp;
19999 + /* If the EP address is known then reset the features for only that EP */
20001 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
20002 + if (NULL == cfiep) {
20003 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
20005 + return -DWC_E_INVALID;
20007 + retval = cfi_reset_sg_val(cfiep);
20009 + /* Otherwise (wValue == 0), reset all features of all EP's */
20011 + /* Traverse all the active EP's and reset the feature(s) value(s) */
20012 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
20013 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
20014 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
20015 + retval = cfi_reset_sg_val(cfiep);
20016 + if (retval < 0) {
20018 + ("%s: Error resetting the feature Buffer Setup\n",
20027 +static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr)
20031 + cfiobject_t *cfi = pcd->cfi;
20032 + dwc_list_link_t *tmp;
20034 + /* If the EP address is known then reset the features for only that EP */
20036 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
20037 + if (NULL == cfiep) {
20038 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
20040 + return -DWC_E_INVALID;
20042 + retval = cfi_reset_concat_val(cfiep);
20044 + /* Otherwise (wValue == 0), reset all features of all EP's */
20046 + /* Traverse all the active EP's and reset the feature(s) value(s) */
20047 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
20048 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
20049 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
20050 + retval = cfi_reset_concat_val(cfiep);
20051 + if (retval < 0) {
20053 + ("%s: Error resetting the feature Concatenation Value\n",
20062 +static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr)
20066 + cfiobject_t *cfi = pcd->cfi;
20067 + dwc_list_link_t *tmp;
20069 + /* If the EP address is known then reset the features for only that EP */
20071 + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
20072 + if (NULL == cfiep) {
20073 + CFI_INFO("%s: Error getting the EP address 0x%02x\n",
20075 + return -DWC_E_INVALID;
20077 + retval = cfi_reset_align_val(cfiep);
20079 + /* Otherwise (wValue == 0), reset all features of all EP's */
20081 + /* Traverse all the active EP's and reset the feature(s) value(s) */
20082 + //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
20083 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
20084 + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
20085 + retval = cfi_reset_align_val(cfiep);
20086 + if (retval < 0) {
20088 + ("%s: Error resetting the feature Aliignment Value\n",
20098 +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
20099 + struct cfi_usb_ctrlrequest *req)
20103 + switch (req->wIndex) {
20105 + /* Reset all features */
20106 + retval = cfi_handle_reset_all(pcd, req->wValue & 0xff);
20109 + case FT_ID_DMA_BUFFER_SETUP:
20110 + /* Reset the SG buffer setup */
20112 + cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff);
20115 + case FT_ID_DMA_CONCAT_SETUP:
20116 + /* Reset the Concatenation buffer setup */
20117 + retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff);
20120 + case FT_ID_DMA_BUFF_ALIGN:
20121 + /* Reset the Alignment buffer setup */
20122 + retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff);
20125 + case FT_ID_TX_FIFO_DEPTH:
20127 + cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1);
20128 + pcd->cfi->need_gadget_att = 0;
20131 + case FT_ID_RX_FIFO_DEPTH:
20132 + retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0);
20133 + pcd->cfi->need_gadget_att = 0;
20142 + * This function sets a new value for the SG buffer setup.
20144 +static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20146 + uint8_t inaddr, outaddr;
20147 + cfi_ep_t *epin, *epout;
20148 + ddma_sg_buffer_setup_t *psgval;
20149 + uint32_t desccount, size;
20151 + CFI_INFO("%s\n", __func__);
20153 + psgval = (ddma_sg_buffer_setup_t *) buf;
20154 + desccount = (uint32_t) psgval->bCount;
20155 + size = (uint32_t) psgval->wSize;
20157 + /* Check the DMA descriptor count */
20158 + if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) {
20160 + ("%s: The count of DMA Descriptors should be between 1 and %d\n",
20161 + __func__, MAX_DMA_DESCS_PER_EP);
20162 + return -DWC_E_INVALID;
20165 + /* Check the DMA descriptor count */
20169 + CFI_INFO("%s: The transfer size should be at least 1 byte\n",
20172 + return -DWC_E_INVALID;
20176 + inaddr = psgval->bInEndpointAddress;
20177 + outaddr = psgval->bOutEndpointAddress;
20179 + epin = get_cfi_ep_by_addr(pcd->cfi, inaddr);
20180 + epout = get_cfi_ep_by_addr(pcd->cfi, outaddr);
20182 + if (NULL == epin || NULL == epout) {
20184 + ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n",
20185 + __func__, inaddr, outaddr);
20186 + return -DWC_E_INVALID;
20189 + epin->ep->dwc_ep.buff_mode = BM_SG;
20190 + dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
20192 + epout->ep->dwc_ep.buff_mode = BM_SG;
20193 + dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
20199 + * This function sets a new value for the buffer Alignment setup.
20201 +static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20205 + ddma_align_buffer_setup_t *palignval;
20207 + palignval = (ddma_align_buffer_setup_t *) buf;
20208 + addr = palignval->bEndpointAddress;
20210 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20212 + if (NULL == ep) {
20213 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20215 + return -DWC_E_INVALID;
20218 + ep->ep->dwc_ep.buff_mode = BM_ALIGN;
20219 + dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t));
20225 + * This function sets a new value for the Concatenation buffer setup.
20227 +static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
20231 + struct _ddma_concat_buffer_setup_hdr *pConcatValHdr;
20233 + uint32_t desccount;
20237 + pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf;
20238 + desccount = (uint32_t) pConcatValHdr->bDescCount;
20239 + pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN);
20241 + /* Check the DMA descriptor count */
20242 + if (desccount > MAX_DMA_DESCS_PER_EP) {
20243 + CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n",
20244 + __func__, MAX_DMA_DESCS_PER_EP);
20245 + return -DWC_E_INVALID;
20248 + addr = pConcatValHdr->bEndpointAddress;
20249 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20250 + if (NULL == ep) {
20251 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20253 + return -DWC_E_INVALID;
20256 + mps = UGETW(ep->ep->desc->wMaxPacketSize);
20259 + for (i = 0; i < desccount; i++) {
20260 + CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]);
20262 + CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps);
20265 + /* Check the wTxSizes to be less than or equal to the mps */
20266 + for (i = 0; i < desccount; i++) {
20267 + if (pVals[i] > mps) {
20269 + ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n",
20270 + __func__, i, pVals[i]);
20271 + return -DWC_E_INVALID;
20275 + ep->ep->dwc_ep.buff_mode = BM_CONCAT;
20276 + dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN);
20278 + /* Free the previously allocated storage for the wTxBytes */
20279 + if (ep->bm_concat->wTxBytes) {
20280 + DWC_FREE(ep->bm_concat->wTxBytes);
20283 + /* Allocate a new storage for the wTxBytes field */
20284 + ep->bm_concat->wTxBytes =
20285 + DWC_ALLOC(sizeof(uint16_t) * pConcatValHdr->bDescCount);
20286 + if (NULL == ep->bm_concat->wTxBytes) {
20287 + CFI_INFO("%s: Unable to allocate memory\n", __func__);
20288 + return -DWC_E_NO_MEMORY;
20291 + /* Copy the new values into the wTxBytes filed */
20292 + dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN,
20293 + sizeof(uint16_t) * pConcatValHdr->bDescCount);
20299 + * This function calculates the total of all FIFO sizes
20301 + * @param core_if Programming view of DWC_otg controller
20303 + * @return The total of data FIFO sizes.
20306 +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if)
20308 + dwc_otg_core_params_t *params = core_if->core_params;
20309 + uint16_t dfifo_total = 0;
20312 + /* The shared RxFIFO size */
20314 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
20316 + /* Add up each TxFIFO size to the total */
20317 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20318 + dfifo_total += params->dev_tx_fifo_size[i];
20321 + return dfifo_total;
20325 + * This function returns Rx FIFO size
20327 + * @param core_if Programming view of DWC_otg controller
20329 + * @return The total of data FIFO sizes.
20332 +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue)
20334 + switch (wValue >> 8) {
20336 + return (core_if->pwron_rxfsiz <
20337 + 32768) ? core_if->pwron_rxfsiz : 32768;
20340 + return core_if->core_params->dev_rx_fifo_size;
20343 + return -DWC_E_INVALID;
20349 + * This function returns Tx FIFO size for IN EP
20351 + * @param core_if Programming view of DWC_otg controller
20353 + * @return The total of data FIFO sizes.
20356 +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue)
20358 + dwc_otg_pcd_ep_t *ep;
20360 + ep = get_ep_by_addr(pcd, wValue & 0xff);
20362 + if (NULL == ep) {
20363 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20364 + __func__, wValue & 0xff);
20365 + return -DWC_E_INVALID;
20368 + if (!ep->dwc_ep.is_in) {
20370 + ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n",
20371 + __func__, wValue & 0xff);
20372 + return -DWC_E_INVALID;
20375 + switch (wValue >> 8) {
20377 + return (GET_CORE_IF(pcd)->pwron_txfsiz
20378 + [ep->dwc_ep.tx_fifo_num - 1] <
20379 + 768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->
20380 + dwc_ep.tx_fifo_num
20384 + return GET_CORE_IF(pcd)->core_params->
20385 + dev_tx_fifo_size[ep->dwc_ep.num - 1];
20388 + return -DWC_E_INVALID;
20394 + * This function checks if the submitted combination of
20395 + * device mode FIFO sizes is possible or not.
20397 + * @param core_if Programming view of DWC_otg controller
20399 + * @return 1 if possible, 0 otherwise.
20402 +static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if)
20404 + uint16_t dfifo_actual = 0;
20405 + dwc_otg_core_params_t *params = core_if->core_params;
20406 + uint16_t start_addr = 0;
20410 + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
20412 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20413 + dfifo_actual += params->dev_tx_fifo_size[i];
20416 + if (dfifo_actual > core_if->total_fifo_size) {
20420 + if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16)
20423 + if (params->dev_nperio_tx_fifo_size > 32768
20424 + || params->dev_nperio_tx_fifo_size < 16)
20427 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20429 + if (params->dev_tx_fifo_size[i] > 768
20430 + || params->dev_tx_fifo_size[i] < 4)
20434 + if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz)
20436 + start_addr = params->dev_rx_fifo_size;
20438 + if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz)
20440 + start_addr += params->dev_nperio_tx_fifo_size;
20442 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20444 + if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i])
20446 + start_addr += params->dev_tx_fifo_size[i];
20453 + * This function resizes Device mode FIFOs
20455 + * @param core_if Programming view of DWC_otg controller
20457 + * @return 1 if successful, 0 otherwise
20460 +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if)
20463 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
20464 + dwc_otg_core_params_t *params = core_if->core_params;
20465 + uint32_t rx_fifo_size;
20466 + fifosize_data_t nptxfifosize;
20467 + fifosize_data_t txfifosize[15];
20469 + uint32_t rx_fsz_bak;
20470 + uint32_t nptxfsz_bak;
20471 + uint32_t txfsz_bak[15];
20473 + uint16_t start_address;
20474 + uint8_t retval = 1;
20476 + if (!check_fifo_sizes(core_if)) {
20480 + /* Configure data FIFO sizes */
20481 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
20482 + rx_fsz_bak = DWC_READ_REG32(&global_regs->grxfsiz);
20483 + rx_fifo_size = params->dev_rx_fifo_size;
20484 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
20487 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
20488 + * Indexes of the FIFO size module parameters in the
20489 + * dev_tx_fifo_size array and the FIFO size registers in
20490 + * the dtxfsiz array run from 0 to 14.
20493 + /* Non-periodic Tx FIFO */
20494 + nptxfsz_bak = DWC_READ_REG32(&global_regs->gnptxfsiz);
20495 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
20496 + start_address = params->dev_rx_fifo_size;
20497 + nptxfifosize.b.startaddr = start_address;
20499 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
20501 + start_address += nptxfifosize.b.depth;
20503 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20504 + txfsz_bak[i] = DWC_READ_REG32(&global_regs->dtxfsiz[i]);
20506 + txfifosize[i].b.depth = params->dev_tx_fifo_size[i];
20507 + txfifosize[i].b.startaddr = start_address;
20508 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
20509 + txfifosize[i].d32);
20511 + start_address += txfifosize[i].b.depth;
20514 + /** Check if register values are set correctly */
20515 + if (rx_fifo_size != DWC_READ_REG32(&global_regs->grxfsiz)) {
20519 + if (nptxfifosize.d32 != DWC_READ_REG32(&global_regs->gnptxfsiz)) {
20523 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20524 + if (txfifosize[i].d32 !=
20525 + DWC_READ_REG32(&global_regs->dtxfsiz[i])) {
20530 + /** If register values are not set correctly, reset old values */
20531 + if (retval == 0) {
20532 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fsz_bak);
20534 + /* Non-periodic Tx FIFO */
20535 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfsz_bak);
20537 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
20538 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
20546 + /* Flush the FIFOs */
20547 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
20548 + dwc_otg_flush_rx_fifo(core_if);
20554 + * This function sets a new value for the buffer Alignment setup.
20556 +static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
20561 + uint16_t ep_addr;
20562 + dwc_otg_pcd_ep_t *ep;
20563 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
20564 + tx_fifo_size_setup_t *ptxfifoval;
20566 + ptxfifoval = (tx_fifo_size_setup_t *) buf;
20567 + ep_addr = ptxfifoval->bEndpointAddress;
20568 + size = ptxfifoval->wDepth;
20570 + ep = get_ep_by_addr(pcd, ep_addr);
20573 + ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n",
20574 + __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num);
20576 + if (NULL == ep) {
20577 + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
20578 + __func__, ep_addr);
20579 + return -DWC_E_INVALID;
20582 + fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1];
20583 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size;
20585 + if (resize_fifos(GET_CORE_IF(pcd))) {
20589 + ("%s: Error setting the feature Tx FIFO Size for EP%d\n",
20590 + __func__, ep_addr);
20591 + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz;
20592 + retval = -DWC_E_INVALID;
20599 + * This function sets a new value for the buffer Alignment setup.
20601 +static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
20606 + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
20607 + rx_fifo_size_setup_t *prxfifoval;
20609 + prxfifoval = (rx_fifo_size_setup_t *) buf;
20610 + size = prxfifoval->wDepth;
20612 + fsiz = params->dev_rx_fifo_size;
20613 + params->dev_rx_fifo_size = size;
20615 + if (resize_fifos(GET_CORE_IF(pcd))) {
20618 + CFI_INFO("%s: Error setting the feature Rx FIFO Size\n",
20620 + params->dev_rx_fifo_size = fsiz;
20621 + retval = -DWC_E_INVALID;
20628 + * This function reads the SG of an EP's buffer setup into the buffer buf
20630 +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20631 + struct cfi_usb_ctrlrequest *req)
20633 + int retval = -DWC_E_INVALID;
20637 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20638 + addr = req->wValue & 0xFF;
20639 + if (addr == 0) /* The address should be non-zero */
20642 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20643 + if (NULL == ep) {
20644 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20649 + dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN);
20650 + retval = BS_SG_VAL_DESC_LEN;
20655 + * This function reads the Concatenation value of an EP's buffer mode into
20658 +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20659 + struct cfi_usb_ctrlrequest *req)
20661 + int retval = -DWC_E_INVALID;
20664 + uint8_t desc_count;
20666 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20667 + addr = req->wValue & 0xFF;
20668 + if (addr == 0) /* The address should be non-zero */
20671 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20672 + if (NULL == ep) {
20673 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20678 + /* Copy the header to the buffer */
20679 + dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN);
20680 + /* Advance the buffer pointer by the header size */
20681 + buf += BS_CONCAT_VAL_HDR_LEN;
20683 + desc_count = ep->bm_concat->hdr.bDescCount;
20684 + /* Copy alll the wTxBytes to the buffer */
20685 + dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count);
20687 + retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count;
20692 + * This function reads the buffer Alignment value of an EP's buffer mode into
20695 + * @return The total number of bytes copied to the buffer or negative error code.
20697 +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
20698 + struct cfi_usb_ctrlrequest *req)
20700 + int retval = -DWC_E_INVALID;
20704 + /* The Low Byte of the wValue contains a non-zero address of the endpoint */
20705 + addr = req->wValue & 0xFF;
20706 + if (addr == 0) /* The address should be non-zero */
20709 + ep = get_cfi_ep_by_addr(pcd->cfi, addr);
20710 + if (NULL == ep) {
20711 + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
20716 + dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN);
20717 + retval = BS_ALIGN_VAL_HDR_LEN;
20723 + * This function sets a new value for the specified feature
20725 + * @param pcd A pointer to the PCD object
20727 + * @return 0 if successful, negative error code otherwise to stall the DCE.
20729 +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd)
20731 + int retval = -DWC_E_NOT_SUPPORTED;
20732 + uint16_t wIndex, wValue;
20733 + uint8_t bRequest;
20734 + struct dwc_otg_core_if *coreif;
20735 + cfiobject_t *cfi = pcd->cfi;
20736 + struct cfi_usb_ctrlrequest *ctrl_req;
20738 + ctrl_req = &cfi->ctrl_req;
20740 + buf = pcd->cfi->ctrl_req.data;
20742 + coreif = GET_CORE_IF(pcd);
20743 + bRequest = ctrl_req->bRequest;
20744 + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
20745 + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
20747 + /* See which feature is to be modified */
20748 + switch (wIndex) {
20749 + case FT_ID_DMA_BUFFER_SETUP:
20750 + /* Modify the feature */
20751 + if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0)
20754 + /* And send this request to the gadget */
20755 + cfi->need_gadget_att = 1;
20758 + case FT_ID_DMA_BUFF_ALIGN:
20759 + if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0)
20761 + cfi->need_gadget_att = 1;
20764 + case FT_ID_DMA_CONCAT_SETUP:
20765 + /* Modify the feature */
20766 + if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0)
20768 + cfi->need_gadget_att = 1;
20771 + case FT_ID_DMA_CIRCULAR:
20772 + CFI_INFO("FT_ID_DMA_CIRCULAR\n");
20775 + case FT_ID_THRESHOLD_SETUP:
20776 + CFI_INFO("FT_ID_THRESHOLD_SETUP\n");
20779 + case FT_ID_DFIFO_DEPTH:
20780 + CFI_INFO("FT_ID_DFIFO_DEPTH\n");
20783 + case FT_ID_TX_FIFO_DEPTH:
20784 + CFI_INFO("FT_ID_TX_FIFO_DEPTH\n");
20785 + if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0)
20787 + cfi->need_gadget_att = 0;
20790 + case FT_ID_RX_FIFO_DEPTH:
20791 + CFI_INFO("FT_ID_RX_FIFO_DEPTH\n");
20792 + if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0)
20794 + cfi->need_gadget_att = 0;
20801 +#endif //DWC_UTE_CFI
20802 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cfi.h b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h
20803 new file mode 100644
20804 index 0000000..cbccdab
20806 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h
20808 +/* ==========================================================================
20809 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
20810 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
20811 + * otherwise expressly agreed to in writing between Synopsys and you.
20813 + * The Software IS NOT an item of Licensed Software or Licensed Product under
20814 + * any End User Software License Agreement or Agreement for Licensed Product
20815 + * with Synopsys or any supplement thereto. You are permitted to use and
20816 + * redistribute this Software in source and binary forms, with or without
20817 + * modification, provided that redistributions of source code must retain this
20818 + * notice. You may not view, use, disclose, copy or distribute this file or
20819 + * any information contained herein except pursuant to this license grant from
20820 + * Synopsys. If you do not agree with this notice, including the disclaimer
20821 + * below, then you are not authorized to use the Software.
20823 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
20824 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20825 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20826 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
20827 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20828 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20829 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20830 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20831 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20832 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
20834 + * ========================================================================== */
20836 +#if !defined(__DWC_OTG_CFI_H__)
20837 +#define __DWC_OTG_CFI_H__
20839 +#include "dwc_otg_pcd.h"
20840 +#include "dwc_cfi_common.h"
20844 + * This file contains the CFI related OTG PCD specific common constants,
20845 + * interfaces(functions and macros) and data structures.The CFI Protocol is an
20846 + * optional interface for internal testing purposes that a DUT may implement to
20847 + * support testing of configurable features.
20851 +struct dwc_otg_pcd;
20852 +struct dwc_otg_pcd_ep;
20854 +/** OTG CFI Features (properties) ID constants */
20855 +/** This is a request for all Core Features */
20856 +#define FT_ID_DMA_MODE 0x0001
20857 +#define FT_ID_DMA_BUFFER_SETUP 0x0002
20858 +#define FT_ID_DMA_BUFF_ALIGN 0x0003
20859 +#define FT_ID_DMA_CONCAT_SETUP 0x0004
20860 +#define FT_ID_DMA_CIRCULAR 0x0005
20861 +#define FT_ID_THRESHOLD_SETUP 0x0006
20862 +#define FT_ID_DFIFO_DEPTH 0x0007
20863 +#define FT_ID_TX_FIFO_DEPTH 0x0008
20864 +#define FT_ID_RX_FIFO_DEPTH 0x0009
20866 +/**********************************************************/
20867 +#define CFI_INFO_DEF
20869 +#ifdef CFI_INFO_DEF
20870 +#define CFI_INFO(fmt...) DWC_PRINTF("CFI: " fmt);
20872 +#define CFI_INFO(fmt...)
20875 +#define min(x,y) ({ \
20876 + x < y ? x : y; })
20878 +#define max(x,y) ({ \
20879 + x > y ? x : y; })
20882 + * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is
20883 + * also used for setting up a buffer for Circular DDMA.
20885 +struct _ddma_sg_buffer_setup {
20886 +#define BS_SG_VAL_DESC_LEN 6
20887 + /* The OUT EP address */
20888 + uint8_t bOutEndpointAddress;
20889 + /* The IN EP address */
20890 + uint8_t bInEndpointAddress;
20891 + /* Number of bytes to put between transfer segments (must be DWORD boundaries) */
20893 + /* The number of transfer segments (a DMA descriptors per each segment) */
20895 + /* Size (in byte) of each transfer segment */
20897 +} __attribute__ ((packed));
20898 +typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
20900 +/** Descriptor DMA Concatenation Buffer setup structure */
20901 +struct _ddma_concat_buffer_setup_hdr {
20902 +#define BS_CONCAT_VAL_HDR_LEN 4
20903 + /* The endpoint for which the buffer is to be set up */
20904 + uint8_t bEndpointAddress;
20905 + /* The count of descriptors to be used */
20906 + uint8_t bDescCount;
20907 + /* The total size of the transfer */
20909 +} __attribute__ ((packed));
20910 +typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
20912 +/** Descriptor DMA Concatenation Buffer setup structure */
20913 +struct _ddma_concat_buffer_setup {
20914 + /* The SG header */
20915 + ddma_concat_buffer_setup_hdr_t hdr;
20917 + /* The XFER sizes pointer (allocated dynamically) */
20918 + uint16_t *wTxBytes;
20919 +} __attribute__ ((packed));
20920 +typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
20922 +/** Descriptor DMA Alignment Buffer setup structure */
20923 +struct _ddma_align_buffer_setup {
20924 +#define BS_ALIGN_VAL_HDR_LEN 2
20925 + uint8_t bEndpointAddress;
20927 +} __attribute__ ((packed));
20928 +typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
20930 +/** Transmit FIFO Size setup structure */
20931 +struct _tx_fifo_size_setup {
20932 + uint8_t bEndpointAddress;
20934 +} __attribute__ ((packed));
20935 +typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
20937 +/** Transmit FIFO Size setup structure */
20938 +struct _rx_fifo_size_setup {
20940 +} __attribute__ ((packed));
20941 +typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
20944 + * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest
20945 + * This structure encapsulates the standard usb_ctrlrequest and adds a pointer
20946 + * to the data returned in the data stage of a 3-stage Control Write requests.
20948 +struct cfi_usb_ctrlrequest {
20949 + uint8_t bRequestType;
20950 + uint8_t bRequest;
20953 + uint16_t wLength;
20957 +/*---------------------------------------------------------------------------*/
20960 + * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures.
20961 + * This structure is used to store the buffer setup data for any
20962 + * enabled endpoint in the PCD.
20965 + /* Entry for the list container */
20966 + dwc_list_link_t lh;
20967 + /* Pointer to the active PCD endpoint structure */
20968 + struct dwc_otg_pcd_ep *ep;
20969 + /* The last descriptor in the chain of DMA descriptors of the endpoint */
20970 + struct dwc_otg_dma_desc *dma_desc_last;
20971 + /* The SG feature value */
20972 + ddma_sg_buffer_setup_t *bm_sg;
20973 + /* The Circular feature value */
20974 + ddma_sg_buffer_setup_t *bm_circ;
20975 + /* The Concatenation feature value */
20976 + ddma_concat_buffer_setup_t *bm_concat;
20977 + /* The Alignment feature value */
20978 + ddma_align_buffer_setup_t *bm_align;
20979 + /* XFER length */
20980 + uint32_t xfer_len;
20982 + * Count of DMA descriptors currently used.
20983 + * The total should not exceed the MAX_DMA_DESCS_PER_EP value
20984 + * defined in the dwc_otg_cil.h
20986 + uint32_t desc_count;
20988 +typedef struct cfi_ep cfi_ep_t;
20990 +typedef struct cfi_dma_buff {
20991 +#define CFI_IN_BUF_LEN 1024
20992 +#define CFI_OUT_BUF_LEN 1024
21000 + * This is the interface for the CFI operations.
21002 + * @param ep_enable Called when any endpoint is enabled and activated.
21003 + * @param release Called when the CFI object is released and it needs to correctly
21004 + * deallocate the dynamic memory
21005 + * @param ctrl_write_complete Called when the data stage of the request is complete
21007 +typedef struct cfi_ops {
21008 + int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
21009 + struct dwc_otg_pcd_ep * ep);
21010 + void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
21011 + struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
21012 + unsigned size, gfp_t flags);
21013 + void (*release) (struct cfiobject * cfi);
21014 + int (*ctrl_write_complete) (struct cfiobject * cfi,
21015 + struct dwc_otg_pcd * pcd);
21016 + void (*build_descriptors) (struct cfiobject * cfi,
21017 + struct dwc_otg_pcd * pcd,
21018 + struct dwc_otg_pcd_ep * ep,
21019 + dwc_otg_pcd_request_t * req);
21022 +struct cfiobject {
21024 + struct dwc_otg_pcd *pcd;
21025 + struct usb_gadget *gadget;
21027 + /* Buffers used to send/receive CFI-related request data */
21028 + cfi_dma_buff_t buf_in;
21029 + cfi_dma_buff_t buf_out;
21031 + /* CFI specific Control request wrapper */
21032 + struct cfi_usb_ctrlrequest ctrl_req;
21034 + /* The list of active EP's in the PCD of type cfi_ep_t */
21035 + dwc_list_link_t active_eps;
21037 + /* This flag shall control the propagation of a specific request
21038 + * to the gadget's processing routines.
21039 + * 0 - no gadget handling
21040 + * 1 - the gadget needs to know about this request (w/o completing a status
21041 + * phase - just return a 0 to the _setup callback)
21043 + uint8_t need_gadget_att;
21045 + /* Flag indicating whether the status IN phase needs to be
21046 + * completed by the PCD
21048 + uint8_t need_status_in_complete;
21050 +typedef struct cfiobject cfiobject_t;
21054 +#if defined(DUMP_MSG)
21055 +static inline void dump_msg(const u8 * buf, unsigned int length)
21057 + unsigned int start, num, i;
21058 + char line[52], *p;
21060 + if (length >= 512)
21064 + while (length > 0) {
21065 + num = min(length, 16u);
21067 + for (i = 0; i < num; ++i) {
21070 + DWC_SPRINTF(p, " %02x", buf[i]);
21074 + DWC_DEBUG("%6x: %s\n", start, line);
21081 +static inline void dump_msg(const u8 * buf, unsigned int length)
21087 + * This function returns a pointer to cfi_ep_t object with the addr address.
21089 +static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
21092 + struct cfi_ep *pcfiep;
21093 + dwc_list_link_t *tmp;
21095 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
21096 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
21098 + if (pcfiep->ep->desc->bEndpointAddress == addr) {
21107 + * This function returns a pointer to cfi_ep_t object that matches
21108 + * the dwc_otg_pcd_ep object.
21110 +static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
21111 + struct dwc_otg_pcd_ep *ep)
21113 + struct cfi_ep *pcfiep = NULL;
21114 + dwc_list_link_t *tmp;
21116 + DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
21117 + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
21118 + if (pcfiep->ep == ep) {
21125 +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
21127 +#endif /* (__DWC_OTG_CFI_H__) */
21128 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil.c b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
21129 new file mode 100644
21130 index 0000000..9b67537
21132 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
21134 +/* ==========================================================================
21135 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $
21136 + * $Revision: #191 $
21137 + * $Date: 2012/08/10 $
21138 + * $Change: 2047372 $
21140 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
21141 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
21142 + * otherwise expressly agreed to in writing between Synopsys and you.
21144 + * The Software IS NOT an item of Licensed Software or Licensed Product under
21145 + * any End User Software License Agreement or Agreement for Licensed Product
21146 + * with Synopsys or any supplement thereto. You are permitted to use and
21147 + * redistribute this Software in source and binary forms, with or without
21148 + * modification, provided that redistributions of source code must retain this
21149 + * notice. You may not view, use, disclose, copy or distribute this file or
21150 + * any information contained herein except pursuant to this license grant from
21151 + * Synopsys. If you do not agree with this notice, including the disclaimer
21152 + * below, then you are not authorized to use the Software.
21154 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
21155 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21156 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21157 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
21158 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21159 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21160 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21161 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21162 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21163 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
21165 + * ========================================================================== */
21169 + * The Core Interface Layer provides basic services for accessing and
21170 + * managing the DWC_otg hardware. These services are used by both the
21171 + * Host Controller Driver and the Peripheral Controller Driver.
21173 + * The CIL manages the memory map for the core so that the HCD and PCD
21174 + * don't have to do this separately. It also handles basic tasks like
21175 + * reading/writing the registers and data FIFOs in the controller.
21176 + * Some of the data access functions provide encapsulation of several
21177 + * operations required to perform a task, such as writing multiple
21178 + * registers to start a transfer. Finally, the CIL performs basic
21179 + * services that are not specific to either the host or device modes
21180 + * of operation. These services include management of the OTG Host
21181 + * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
21182 + * Diagnostic API is also provided to allow testing of the controller
21185 + * The Core Interface Layer has the following requirements:
21186 + * - Provides basic controller operations.
21187 + * - Minimal use of OS services.
21188 + * - The OS services used will be abstracted by using inline functions
21193 +#include "dwc_os.h"
21194 +#include "dwc_otg_regs.h"
21195 +#include "dwc_otg_cil.h"
21197 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if);
21200 + * This function is called to initialize the DWC_otg CSR data
21201 + * structures. The register addresses in the device and host
21202 + * structures are initialized from the base address supplied by the
21203 + * caller. The calling function must make the OS calls to get the
21204 + * base address of the DWC_otg controller registers. The core_params
21205 + * argument holds the parameters that specify how the core should be
21208 + * @param reg_base_addr Base address of DWC_otg core registers
21211 +dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr)
21213 + dwc_otg_core_if_t *core_if = 0;
21214 + dwc_otg_dev_if_t *dev_if = 0;
21215 + dwc_otg_host_if_t *host_if = 0;
21216 + uint8_t *reg_base = (uint8_t *) reg_base_addr;
21219 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr);
21221 + core_if = DWC_ALLOC(sizeof(dwc_otg_core_if_t));
21223 + if (core_if == NULL) {
21224 + DWC_DEBUGPL(DBG_CIL,
21225 + "Allocation of dwc_otg_core_if_t failed\n");
21228 + core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base;
21231 + * Allocate the Device Mode structures.
21233 + dev_if = DWC_ALLOC(sizeof(dwc_otg_dev_if_t));
21235 + if (dev_if == NULL) {
21236 + DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
21237 + DWC_FREE(core_if);
21241 + dev_if->dev_global_regs =
21242 + (dwc_otg_device_global_regs_t *) (reg_base +
21243 + DWC_DEV_GLOBAL_REG_OFFSET);
21245 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21246 + dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
21247 + (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
21248 + (i * DWC_EP_REG_OFFSET));
21250 + dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
21251 + (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
21252 + (i * DWC_EP_REG_OFFSET));
21253 + DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
21254 + i, &dev_if->in_ep_regs[i]->diepctl);
21255 + DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
21256 + i, &dev_if->out_ep_regs[i]->doepctl);
21259 + dev_if->speed = 0; // unknown
21261 + core_if->dev_if = dev_if;
21264 + * Allocate the Host Mode structures.
21266 + host_if = DWC_ALLOC(sizeof(dwc_otg_host_if_t));
21268 + if (host_if == NULL) {
21269 + DWC_DEBUGPL(DBG_CIL,
21270 + "Allocation of dwc_otg_host_if_t failed\n");
21271 + DWC_FREE(dev_if);
21272 + DWC_FREE(core_if);
21276 + host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
21277 + (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
21280 + (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
21282 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21283 + host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
21284 + (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
21285 + (i * DWC_OTG_CHAN_REGS_OFFSET));
21286 + DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
21287 + i, &host_if->hc_regs[i]->hcchar);
21290 + host_if->num_host_channels = MAX_EPS_CHANNELS;
21291 + core_if->host_if = host_if;
21293 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21294 + core_if->data_fifo[i] =
21295 + (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
21296 + (i * DWC_OTG_DATA_FIFO_SIZE));
21297 + DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08lx\n",
21298 + i, (unsigned long)core_if->data_fifo[i]);
21301 + core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
21303 + /* Initiate lx_state to L3 disconnected state */
21304 + core_if->lx_state = DWC_OTG_L3;
21306 + * Store the contents of the hardware configuration registers here for
21307 + * easy access later.
21309 + core_if->hwcfg1.d32 =
21310 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg1);
21311 + core_if->hwcfg2.d32 =
21312 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
21313 + core_if->hwcfg3.d32 =
21314 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg3);
21315 + core_if->hwcfg4.d32 =
21316 + DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
21318 + /* Force host mode to get HPTXFSIZ exact power on value */
21320 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
21321 + gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21322 + gusbcfg.b.force_host_mode = 1;
21323 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
21325 + core_if->hptxfsiz.d32 =
21326 + DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
21327 + gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21328 + gusbcfg.b.force_host_mode = 0;
21329 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
21333 + DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
21334 + DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
21335 + DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
21336 + DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
21338 + core_if->hcfg.d32 =
21339 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
21340 + core_if->dcfg.d32 =
21341 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
21343 + DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32);
21344 + DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32);
21346 + DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
21347 + DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
21348 + DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
21349 + DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
21350 + core_if->hwcfg2.b.num_host_chan);
21351 + DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
21352 + core_if->hwcfg2.b.nonperio_tx_q_depth);
21353 + DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
21354 + core_if->hwcfg2.b.host_perio_tx_q_depth);
21355 + DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
21356 + core_if->hwcfg2.b.dev_token_q_depth);
21358 + DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
21359 + core_if->hwcfg3.b.dfifo_depth);
21360 + DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
21361 + core_if->hwcfg3.b.xfer_size_cntr_width);
21364 + * Set the SRP sucess bit for FS-I2c
21366 + core_if->srp_success = 0;
21367 + core_if->srp_timer_started = 0;
21370 + * Create new workqueue and init works
21372 + core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg");
21373 + if (core_if->wq_otg == 0) {
21374 + DWC_WARN("DWC_WORKQ_ALLOC failed\n");
21375 + DWC_FREE(host_if);
21376 + DWC_FREE(dev_if);
21377 + DWC_FREE(core_if);
21381 + core_if->snpsid = DWC_READ_REG32(&core_if->core_global_regs->gsnpsid);
21383 + DWC_PRINTF("Core Release: %x.%x%x%x\n",
21384 + (core_if->snpsid >> 12 & 0xF),
21385 + (core_if->snpsid >> 8 & 0xF),
21386 + (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF));
21388 + core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer",
21389 + w_wakeup_detected, core_if);
21390 + if (core_if->wkp_timer == 0) {
21391 + DWC_WARN("DWC_TIMER_ALLOC failed\n");
21392 + DWC_FREE(host_if);
21393 + DWC_FREE(dev_if);
21394 + DWC_WORKQ_FREE(core_if->wq_otg);
21395 + DWC_FREE(core_if);
21399 + if (dwc_otg_setup_params(core_if)) {
21400 + DWC_WARN("Error while setting core params\n");
21403 + core_if->hibernation_suspend = 0;
21405 + /** ADP initialization */
21406 + dwc_otg_adp_init(core_if);
21412 + * This function frees the structures allocated by dwc_otg_cil_init().
21414 + * @param core_if The core interface pointer returned from
21415 + * dwc_otg_cil_init().
21418 +void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if)
21420 + dctl_data_t dctl = {.d32 = 0 };
21421 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
21423 + /* Disable all interrupts */
21424 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 1, 0);
21425 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
21427 + dctl.b.sftdiscon = 1;
21428 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
21429 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0,
21433 + if (core_if->wq_otg) {
21434 + DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500);
21435 + DWC_WORKQ_FREE(core_if->wq_otg);
21437 + if (core_if->dev_if) {
21438 + DWC_FREE(core_if->dev_if);
21440 + if (core_if->host_if) {
21441 + DWC_FREE(core_if->host_if);
21444 + /** Remove ADP Stuff */
21445 + dwc_otg_adp_remove(core_if);
21446 + if (core_if->core_params) {
21447 + DWC_FREE(core_if->core_params);
21449 + if (core_if->wkp_timer) {
21450 + DWC_TIMER_FREE(core_if->wkp_timer);
21452 + if (core_if->srp_timer) {
21453 + DWC_TIMER_FREE(core_if->srp_timer);
21455 + DWC_FREE(core_if);
21459 + * This function enables the controller's Global Interrupt in the AHB Config
21462 + * @param core_if Programming view of DWC_otg controller.
21464 +void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if)
21466 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
21467 + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */
21468 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
21472 + * This function disables the controller's Global Interrupt in the AHB Config
21475 + * @param core_if Programming view of DWC_otg controller.
21477 +void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if)
21479 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
21480 + ahbcfg.b.glblintrmsk = 1; /* Disable interrupts */
21481 + DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
21485 + * This function initializes the commmon interrupts, used in both
21486 + * device and host modes.
21488 + * @param core_if Programming view of the DWC_otg controller
21491 +static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if)
21493 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
21494 + gintmsk_data_t intr_mask = {.d32 = 0 };
21496 + /* Clear any pending OTG Interrupts */
21497 + DWC_WRITE_REG32(&global_regs->gotgint, 0xFFFFFFFF);
21499 + /* Clear any pending interrupts */
21500 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
21503 + * Enable the interrupts in the GINTMSK.
21505 + intr_mask.b.modemismatch = 1;
21506 + intr_mask.b.otgintr = 1;
21508 + if (!core_if->dma_enable) {
21509 + intr_mask.b.rxstsqlvl = 1;
21512 + intr_mask.b.conidstschng = 1;
21513 + intr_mask.b.wkupintr = 1;
21514 + intr_mask.b.disconnect = 0;
21515 + intr_mask.b.usbsuspend = 1;
21516 + intr_mask.b.sessreqintr = 1;
21517 +#ifdef CONFIG_USB_DWC_OTG_LPM
21518 + if (core_if->core_params->lpm_enable) {
21519 + intr_mask.b.lpmtranrcvd = 1;
21522 + DWC_WRITE_REG32(&global_regs->gintmsk, intr_mask.d32);
21526 + * The restore operation is modified to support Synopsys Emulated Powerdown and
21527 + * Hibernation. This function is for exiting from Device mode hibernation by
21528 + * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
21529 + * @param core_if Programming view of DWC_otg controller.
21530 + * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
21531 + * @param reset - indicates whether resume is initiated by Reset.
21533 +int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
21534 + int rem_wakeup, int reset)
21536 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
21537 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
21538 + dctl_data_t dctl = {.d32 = 0 };
21540 + int timeout = 2000;
21542 + if (!core_if->hibernation_suspend) {
21543 + DWC_PRINTF("Already exited from Hibernation\n");
21547 + DWC_DEBUGPL(DBG_PCD, "%s called\n", __FUNCTION__);
21548 + /* Switch-on voltage to the core */
21549 + gpwrdn.b.pwrdnswtch = 1;
21550 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21555 + gpwrdn.b.pwrdnrstn = 1;
21556 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21559 + /* Assert Restore signal */
21561 + gpwrdn.b.restore = 1;
21562 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21565 + /* Disable power clamps */
21567 + gpwrdn.b.pwrdnclmp = 1;
21568 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21570 + if (rem_wakeup) {
21574 + /* Deassert Reset core */
21576 + gpwrdn.b.pwrdnrstn = 1;
21577 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21580 + /* Disable PMU interrupt */
21582 + gpwrdn.b.pmuintsel = 1;
21583 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21585 + /* Mask interrupts from gpwrdn */
21587 + gpwrdn.b.connect_det_msk = 1;
21588 + gpwrdn.b.srp_det_msk = 1;
21589 + gpwrdn.b.disconn_det_msk = 1;
21590 + gpwrdn.b.rst_det_msk = 1;
21591 + gpwrdn.b.lnstchng_msk = 1;
21592 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21594 + /* Indicates that we are going out from hibernation */
21595 + core_if->hibernation_suspend = 0;
21598 + * Set Restore Essential Regs bit in PCGCCTL register, restore_mode = 1
21599 + * indicates restore from remote_wakeup
21601 + restore_essential_regs(core_if, rem_wakeup, 0);
21604 + * Wait a little for seeing new value of variable hibernation_suspend if
21605 + * Restore done interrupt received before polling
21609 + if (core_if->hibernation_suspend == 0) {
21611 + * Wait For Restore_done Interrupt. This mechanism of polling the
21612 + * interrupt is introduced to avoid any possible race conditions
21615 + gintsts_data_t gintsts;
21617 + DWC_READ_REG32(&core_if->core_global_regs->gintsts);
21618 + if (gintsts.b.restoredone) {
21620 + gintsts.b.restoredone = 1;
21621 + DWC_WRITE_REG32(&core_if->core_global_regs->
21622 + gintsts, gintsts.d32);
21623 + DWC_PRINTF("Restore Done Interrupt seen\n");
21627 + } while (--timeout);
21629 + DWC_PRINTF("Restore Done interrupt wasn't generated here\n");
21632 + /* Clear all pending interupts */
21633 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21635 + /* De-assert Restore */
21637 + gpwrdn.b.restore = 1;
21638 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21641 + if (!rem_wakeup) {
21643 + pcgcctl.b.rstpdwnmodule = 1;
21644 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
21647 + /* Restore GUSBCFG and DCFG */
21648 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
21649 + core_if->gr_backup->gusbcfg_local);
21650 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
21651 + core_if->dr_backup->dcfg);
21653 + /* De-assert Wakeup Logic */
21655 + gpwrdn.b.pmuactv = 1;
21656 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21659 + if (!rem_wakeup) {
21660 + /* Set Device programming done bit */
21661 + dctl.b.pwronprgdone = 1;
21662 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
21664 + /* Start Remote Wakeup Signaling */
21665 + dctl.d32 = core_if->dr_backup->dctl;
21666 + dctl.b.rmtwkupsig = 1;
21667 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
21671 + /* Clear all pending interupts */
21672 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21674 + /* Restore global registers */
21675 + dwc_otg_restore_global_regs(core_if);
21676 + /* Restore device global registers */
21677 + dwc_otg_restore_dev_regs(core_if, rem_wakeup);
21679 + if (rem_wakeup) {
21682 + dctl.b.rmtwkupsig = 1;
21683 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
21686 + core_if->hibernation_suspend = 0;
21687 + /* The core will be in ON STATE */
21688 + core_if->lx_state = DWC_OTG_L0;
21689 + DWC_PRINTF("Hibernation recovery completes here\n");
21695 + * The restore operation is modified to support Synopsys Emulated Powerdown and
21696 + * Hibernation. This function is for exiting from Host mode hibernation by
21697 + * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
21698 + * @param core_if Programming view of DWC_otg controller.
21699 + * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
21700 + * @param reset - indicates whether resume is initiated by Reset.
21702 +int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
21703 + int rem_wakeup, int reset)
21705 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
21706 + hprt0_data_t hprt0 = {.d32 = 0 };
21708 + int timeout = 2000;
21710 + DWC_DEBUGPL(DBG_HCD, "%s called\n", __FUNCTION__);
21711 + /* Switch-on voltage to the core */
21712 + gpwrdn.b.pwrdnswtch = 1;
21713 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21718 + gpwrdn.b.pwrdnrstn = 1;
21719 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21722 + /* Assert Restore signal */
21724 + gpwrdn.b.restore = 1;
21725 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21728 + /* Disable power clamps */
21730 + gpwrdn.b.pwrdnclmp = 1;
21731 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21733 + if (!rem_wakeup) {
21737 + /* Deassert Reset core */
21739 + gpwrdn.b.pwrdnrstn = 1;
21740 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
21743 + /* Disable PMU interrupt */
21745 + gpwrdn.b.pmuintsel = 1;
21746 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21749 + gpwrdn.b.connect_det_msk = 1;
21750 + gpwrdn.b.srp_det_msk = 1;
21751 + gpwrdn.b.disconn_det_msk = 1;
21752 + gpwrdn.b.rst_det_msk = 1;
21753 + gpwrdn.b.lnstchng_msk = 1;
21754 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21756 + /* Indicates that we are going out from hibernation */
21757 + core_if->hibernation_suspend = 0;
21759 + /* Set Restore Essential Regs bit in PCGCCTL register */
21760 + restore_essential_regs(core_if, rem_wakeup, 1);
21762 + /* Wait a little for seeing new value of variable hibernation_suspend if
21763 + * Restore done interrupt received before polling */
21766 + if (core_if->hibernation_suspend == 0) {
21767 + /* Wait For Restore_done Interrupt. This mechanism of polling the
21768 + * interrupt is introduced to avoid any possible race conditions
21771 + gintsts_data_t gintsts;
21772 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
21773 + if (gintsts.b.restoredone) {
21775 + gintsts.b.restoredone = 1;
21776 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
21777 + DWC_DEBUGPL(DBG_HCD,"Restore Done Interrupt seen\n");
21781 + } while (--timeout);
21783 + DWC_WARN("Restore Done interrupt wasn't generated\n");
21787 + /* Set the flag's value to 0 again after receiving restore done interrupt */
21788 + core_if->hibernation_suspend = 0;
21790 + /* This step is not described in functional spec but if not wait for this
21791 + * delay, mismatch interrupts occurred because just after restore core is
21792 + * in Device mode(gintsts.curmode == 0) */
21795 + /* Clear all pending interrupts */
21796 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21798 + /* De-assert Restore */
21800 + gpwrdn.b.restore = 1;
21801 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21804 + /* Restore GUSBCFG and HCFG */
21805 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
21806 + core_if->gr_backup->gusbcfg_local);
21807 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
21808 + core_if->hr_backup->hcfg_local);
21810 + /* De-assert Wakeup Logic */
21812 + gpwrdn.b.pmuactv = 1;
21813 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
21816 + /* Start the Resume operation by programming HPRT0 */
21817 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21818 + hprt0.b.prtpwr = 1;
21819 + hprt0.b.prtena = 0;
21820 + hprt0.b.prtsusp = 0;
21821 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21823 + DWC_PRINTF("Resume Starts Now\n");
21824 + if (!reset) { // Indicates it is Resume Operation
21825 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21826 + hprt0.b.prtres = 1;
21827 + hprt0.b.prtpwr = 1;
21828 + hprt0.b.prtena = 0;
21829 + hprt0.b.prtsusp = 0;
21830 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21833 + hprt0.b.prtres = 0;
21834 + /* Wait for Resume time and then program HPRT again */
21836 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21838 + } else { // Indicates it is Reset Operation
21839 + hprt0.d32 = core_if->hr_backup->hprt0_local;
21840 + hprt0.b.prtrst = 1;
21841 + hprt0.b.prtpwr = 1;
21842 + hprt0.b.prtena = 0;
21843 + hprt0.b.prtsusp = 0;
21844 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21845 + /* Wait for Reset time and then program HPRT again */
21847 + hprt0.b.prtrst = 0;
21848 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21850 + /* Clear all interrupt status */
21851 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
21852 + hprt0.b.prtconndet = 1;
21853 + hprt0.b.prtenchng = 1;
21854 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
21856 + /* Clear all pending interupts */
21857 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
21859 + /* Restore global registers */
21860 + dwc_otg_restore_global_regs(core_if);
21861 + /* Restore host global registers */
21862 + dwc_otg_restore_host_regs(core_if, reset);
21864 + /* The core will be in ON STATE */
21865 + core_if->lx_state = DWC_OTG_L0;
21866 + DWC_PRINTF("Hibernation recovery is complete here\n");
21870 +/** Saves some register values into system memory. */
21871 +int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if)
21873 + struct dwc_otg_global_regs_backup *gr;
21876 + gr = core_if->gr_backup;
21878 + gr = DWC_ALLOC(sizeof(*gr));
21880 + return -DWC_E_NO_MEMORY;
21882 + core_if->gr_backup = gr;
21885 + gr->gotgctl_local = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
21886 + gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
21887 + gr->gahbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
21888 + gr->gusbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
21889 + gr->grxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
21890 + gr->gnptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
21891 + gr->hptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
21892 +#ifdef CONFIG_USB_DWC_OTG_LPM
21893 + gr->glpmcfg_local = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
21895 + gr->gi2cctl_local = DWC_READ_REG32(&core_if->core_global_regs->gi2cctl);
21896 + gr->pcgcctl_local = DWC_READ_REG32(core_if->pcgcctl);
21897 + gr->gdfifocfg_local =
21898 + DWC_READ_REG32(&core_if->core_global_regs->gdfifocfg);
21899 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
21900 + gr->dtxfsiz_local[i] =
21901 + DWC_READ_REG32(&(core_if->core_global_regs->dtxfsiz[i]));
21904 + DWC_DEBUGPL(DBG_ANY, "===========Backing Global registers==========\n");
21905 + DWC_DEBUGPL(DBG_ANY, "Backed up gotgctl = %08x\n", gr->gotgctl_local);
21906 + DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
21907 + DWC_DEBUGPL(DBG_ANY, "Backed up gahbcfg = %08x\n", gr->gahbcfg_local);
21908 + DWC_DEBUGPL(DBG_ANY, "Backed up gusbcfg = %08x\n", gr->gusbcfg_local);
21909 + DWC_DEBUGPL(DBG_ANY, "Backed up grxfsiz = %08x\n", gr->grxfsiz_local);
21910 + DWC_DEBUGPL(DBG_ANY, "Backed up gnptxfsiz = %08x\n",
21911 + gr->gnptxfsiz_local);
21912 + DWC_DEBUGPL(DBG_ANY, "Backed up hptxfsiz = %08x\n",
21913 + gr->hptxfsiz_local);
21914 +#ifdef CONFIG_USB_DWC_OTG_LPM
21915 + DWC_DEBUGPL(DBG_ANY, "Backed up glpmcfg = %08x\n", gr->glpmcfg_local);
21917 + DWC_DEBUGPL(DBG_ANY, "Backed up gi2cctl = %08x\n", gr->gi2cctl_local);
21918 + DWC_DEBUGPL(DBG_ANY, "Backed up pcgcctl = %08x\n", gr->pcgcctl_local);
21919 + DWC_DEBUGPL(DBG_ANY,"Backed up gdfifocfg = %08x\n",gr->gdfifocfg_local);
21924 +/** Saves GINTMSK register before setting the msk bits. */
21925 +int dwc_otg_save_gintmsk_reg(dwc_otg_core_if_t * core_if)
21927 + struct dwc_otg_global_regs_backup *gr;
21929 + gr = core_if->gr_backup;
21931 + gr = DWC_ALLOC(sizeof(*gr));
21933 + return -DWC_E_NO_MEMORY;
21935 + core_if->gr_backup = gr;
21938 + gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
21940 + DWC_DEBUGPL(DBG_ANY,"=============Backing GINTMSK registers============\n");
21941 + DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
21946 +int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if)
21948 + struct dwc_otg_dev_regs_backup *dr;
21951 + dr = core_if->dr_backup;
21953 + dr = DWC_ALLOC(sizeof(*dr));
21955 + return -DWC_E_NO_MEMORY;
21957 + core_if->dr_backup = dr;
21960 + dr->dcfg = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
21961 + dr->dctl = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
21963 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
21965 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->diepmsk);
21967 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->doepmsk);
21969 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21971 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
21972 + dr->dieptsiz[i] =
21973 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz);
21975 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma);
21978 + DWC_DEBUGPL(DBG_ANY,
21979 + "=============Backing Host registers==============\n");
21980 + DWC_DEBUGPL(DBG_ANY, "Backed up dcfg = %08x\n", dr->dcfg);
21981 + DWC_DEBUGPL(DBG_ANY, "Backed up dctl = %08x\n", dr->dctl);
21982 + DWC_DEBUGPL(DBG_ANY, "Backed up daintmsk = %08x\n",
21984 + DWC_DEBUGPL(DBG_ANY, "Backed up diepmsk = %08x\n", dr->diepmsk);
21985 + DWC_DEBUGPL(DBG_ANY, "Backed up doepmsk = %08x\n", dr->doepmsk);
21986 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
21987 + DWC_DEBUGPL(DBG_ANY, "Backed up diepctl[%d] = %08x\n", i,
21989 + DWC_DEBUGPL(DBG_ANY, "Backed up dieptsiz[%d] = %08x\n",
21990 + i, dr->dieptsiz[i]);
21991 + DWC_DEBUGPL(DBG_ANY, "Backed up diepdma[%d] = %08x\n", i,
21998 +int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if)
22000 + struct dwc_otg_host_regs_backup *hr;
22003 + hr = core_if->hr_backup;
22005 + hr = DWC_ALLOC(sizeof(*hr));
22007 + return -DWC_E_NO_MEMORY;
22009 + core_if->hr_backup = hr;
22013 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
22014 + hr->haintmsk_local =
22015 + DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
22016 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
22017 + hr->hcintmsk_local[i] =
22018 + DWC_READ_REG32(&core_if->host_if->hc_regs[i]->hcintmsk);
22020 + hr->hprt0_local = DWC_READ_REG32(core_if->host_if->hprt0);
22022 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
22024 + DWC_DEBUGPL(DBG_ANY,
22025 + "=============Backing Host registers===============\n");
22026 + DWC_DEBUGPL(DBG_ANY, "Backed up hcfg = %08x\n",
22028 + DWC_DEBUGPL(DBG_ANY, "Backed up haintmsk = %08x\n", hr->haintmsk_local);
22029 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
22030 + DWC_DEBUGPL(DBG_ANY, "Backed up hcintmsk[%02d]=%08x\n", i,
22031 + hr->hcintmsk_local[i]);
22033 + DWC_DEBUGPL(DBG_ANY, "Backed up hprt0 = %08x\n",
22034 + hr->hprt0_local);
22035 + DWC_DEBUGPL(DBG_ANY, "Backed up hfir = %08x\n",
22041 +int dwc_otg_restore_global_regs(dwc_otg_core_if_t *core_if)
22043 + struct dwc_otg_global_regs_backup *gr;
22046 + gr = core_if->gr_backup;
22048 + return -DWC_E_INVALID;
22051 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, gr->gotgctl_local);
22052 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gr->gintmsk_local);
22053 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gr->gusbcfg_local);
22054 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gr->gahbcfg_local);
22055 + DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, gr->grxfsiz_local);
22056 + DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz,
22057 + gr->gnptxfsiz_local);
22058 + DWC_WRITE_REG32(&core_if->core_global_regs->hptxfsiz,
22059 + gr->hptxfsiz_local);
22060 + DWC_WRITE_REG32(&core_if->core_global_regs->gdfifocfg,
22061 + gr->gdfifocfg_local);
22062 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
22063 + DWC_WRITE_REG32(&core_if->core_global_regs->dtxfsiz[i],
22064 + gr->dtxfsiz_local[i]);
22067 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
22068 + DWC_WRITE_REG32(core_if->host_if->hprt0, 0x0000100A);
22069 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg,
22070 + (gr->gahbcfg_local));
22074 +int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if, int rem_wakeup)
22076 + struct dwc_otg_dev_regs_backup *dr;
22079 + dr = core_if->dr_backup;
22082 + return -DWC_E_INVALID;
22085 + if (!rem_wakeup) {
22086 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
22090 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, dr->daintmsk);
22091 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, dr->diepmsk);
22092 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, dr->doepmsk);
22094 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
22095 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz, dr->dieptsiz[i]);
22096 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma, dr->diepdma[i]);
22097 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl, dr->diepctl[i]);
22103 +int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset)
22105 + struct dwc_otg_host_regs_backup *hr;
22107 + hr = core_if->hr_backup;
22110 + return -DWC_E_INVALID;
22113 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hr->hcfg_local);
22116 + // DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hr->hfir_local);
22119 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk,
22120 + hr->haintmsk_local);
22121 + for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
22122 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk,
22123 + hr->hcintmsk_local[i]);
22129 +int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if)
22131 + struct dwc_otg_global_regs_backup *gr;
22133 + gr = core_if->gr_backup;
22135 + /* Restore values for LPM and I2C */
22136 +#ifdef CONFIG_USB_DWC_OTG_LPM
22137 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, gr->glpmcfg_local);
22139 + DWC_WRITE_REG32(&core_if->core_global_regs->gi2cctl, gr->gi2cctl_local);
22144 +int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode, int is_host)
22146 + struct dwc_otg_global_regs_backup *gr;
22147 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
22148 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
22149 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
22150 + gintmsk_data_t gintmsk = {.d32 = 0 };
22152 + /* Restore LPM and I2C registers */
22153 + restore_lpm_i2c_regs(core_if);
22155 + /* Set PCGCCTL to 0 */
22156 + DWC_WRITE_REG32(core_if->pcgcctl, 0x00000000);
22158 + gr = core_if->gr_backup;
22159 + /* Load restore values for [31:14] bits */
22160 + DWC_WRITE_REG32(core_if->pcgcctl,
22161 + ((gr->pcgcctl_local & 0xffffc000) | 0x00020000));
22163 + /* Umnask global Interrupt in GAHBCFG and restore it */
22164 + gahbcfg.d32 = gr->gahbcfg_local;
22165 + gahbcfg.b.glblintrmsk = 1;
22166 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
22168 + /* Clear all pending interupts */
22169 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
22171 + /* Unmask restore done interrupt */
22172 + gintmsk.b.restoredone = 1;
22173 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
22175 + /* Restore GUSBCFG and HCFG/DCFG */
22176 + gusbcfg.d32 = core_if->gr_backup->gusbcfg_local;
22177 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
22180 + hcfg_data_t hcfg = {.d32 = 0 };
22181 + hcfg.d32 = core_if->hr_backup->hcfg_local;
22182 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
22185 + /* Load restore values for [31:14] bits */
22186 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22187 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22190 + pcgcctl.b.restoremode = 1;
22191 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22194 + /* Load restore values for [31:14] bits and set EssRegRestored bit */
22195 + pcgcctl.d32 = gr->pcgcctl_local | 0xffffc000;
22196 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22197 + pcgcctl.b.ess_reg_restored = 1;
22199 + pcgcctl.b.restoremode = 1;
22200 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22202 + dcfg_data_t dcfg = {.d32 = 0 };
22203 + dcfg.d32 = core_if->dr_backup->dcfg;
22204 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
22206 + /* Load restore values for [31:14] bits */
22207 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22208 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22210 + pcgcctl.d32 |= 0x208;
22212 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22215 + /* Load restore values for [31:14] bits */
22216 + pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
22217 + pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
22218 + pcgcctl.b.ess_reg_restored = 1;
22220 + pcgcctl.d32 |= 0x208;
22221 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
22228 + * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
22231 +static void init_fslspclksel(dwc_otg_core_if_t * core_if)
22234 + hcfg_data_t hcfg;
22236 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
22237 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22238 + (core_if->core_params->ulpi_fs_ls)) ||
22239 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22240 + /* Full speed PHY */
22241 + val = DWC_HCFG_48_MHZ;
22243 + /* High speed PHY running at full speed or high speed */
22244 + val = DWC_HCFG_30_60_MHZ;
22247 + DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
22248 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
22249 + hcfg.b.fslspclksel = val;
22250 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
22254 + * Initializes the DevSpd field of the DCFG register depending on the PHY type
22255 + * and the enumeration speed of the device.
22257 +static void init_devspd(dwc_otg_core_if_t * core_if)
22260 + dcfg_data_t dcfg;
22262 + if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
22263 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22264 + (core_if->core_params->ulpi_fs_ls)) ||
22265 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22266 + /* Full speed PHY */
22268 + } else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
22269 + /* High speed PHY running at full speed */
22272 + /* High speed PHY running at high speed */
22276 + DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
22278 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
22279 + dcfg.b.devspd = val;
22280 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
22284 + * This function calculates the number of IN EPS
22285 + * using GHWCFG1 and GHWCFG2 registers values
22287 + * @param core_if Programming view of the DWC_otg controller
22289 +static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if)
22291 + uint32_t num_in_eps = 0;
22292 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
22293 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3;
22294 + uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps;
22297 + for (i = 0; i < num_eps; ++i) {
22298 + if (!(hwcfg1 & 0x1))
22304 + if (core_if->hwcfg4.b.ded_fifo_en) {
22306 + (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
22309 + return num_in_eps;
22313 + * This function calculates the number of OUT EPS
22314 + * using GHWCFG1 and GHWCFG2 registers values
22316 + * @param core_if Programming view of the DWC_otg controller
22318 +static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if)
22320 + uint32_t num_out_eps = 0;
22321 + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
22322 + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2;
22325 + for (i = 0; i < num_eps; ++i) {
22326 + if (!(hwcfg1 & 0x1))
22331 + return num_out_eps;
22335 + * This function initializes the DWC_otg controller registers and
22336 + * prepares the core for device mode or host mode operation.
22338 + * @param core_if Programming view of the DWC_otg controller
22341 +void dwc_otg_core_init(dwc_otg_core_if_t * core_if)
22344 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22345 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
22346 + gahbcfg_data_t ahbcfg = {.d32 = 0 };
22347 + gusbcfg_data_t usbcfg = {.d32 = 0 };
22348 + gi2cctl_data_t i2cctl = {.d32 = 0 };
22350 + DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p) regs at %p\n",
22351 + core_if, global_regs);
22353 + /* Common Initialization */
22354 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22356 + /* Program the ULPI External VBUS bit if needed */
22357 + usbcfg.b.ulpi_ext_vbus_drv =
22358 + (core_if->core_params->phy_ulpi_ext_vbus ==
22359 + DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
22361 + /* Set external TS Dline pulsing */
22362 + usbcfg.b.term_sel_dl_pulse =
22363 + (core_if->core_params->ts_dline == 1) ? 1 : 0;
22364 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22366 + /* Reset the Controller */
22367 + dwc_otg_core_reset(core_if);
22369 + core_if->adp_enable = core_if->core_params->adp_supp_enable;
22370 + core_if->power_down = core_if->core_params->power_down;
22371 + core_if->otg_sts = 0;
22373 + /* Initialize parameters from Hardware configuration registers. */
22374 + dev_if->num_in_eps = calc_num_in_eps(core_if);
22375 + dev_if->num_out_eps = calc_num_out_eps(core_if);
22377 + DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
22378 + core_if->hwcfg4.b.num_dev_perio_in_ep);
22380 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
22381 + dev_if->perio_tx_fifo_size[i] =
22382 + DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
22383 + DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
22384 + i, dev_if->perio_tx_fifo_size[i]);
22387 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
22388 + dev_if->tx_fifo_size[i] =
22389 + DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
22390 + DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
22391 + i, dev_if->tx_fifo_size[i]);
22394 + core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
22395 + core_if->rx_fifo_size = DWC_READ_REG32(&global_regs->grxfsiz);
22396 + core_if->nperio_tx_fifo_size =
22397 + DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16;
22399 + DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
22400 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
22401 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
22402 + core_if->nperio_tx_fifo_size);
22404 + /* This programming sequence needs to happen in FS mode before any other
22405 + * programming occurs */
22406 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
22407 + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
22408 + /* If FS mode with FS PHY */
22410 + /* core_init() is now called on every switch so only call the
22411 + * following for the first time through. */
22412 + if (!core_if->phy_init_done) {
22413 + core_if->phy_init_done = 1;
22414 + DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
22415 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22416 + usbcfg.b.physel = 1;
22417 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22419 + /* Reset after a PHY select */
22420 + dwc_otg_core_reset(core_if);
22423 + /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
22424 + * do this on HNP Dev/Host mode switches (done in dev_init and
22426 + if (dwc_otg_is_host_mode(core_if)) {
22427 + init_fslspclksel(core_if);
22429 + init_devspd(core_if);
22432 + if (core_if->core_params->i2c_enable) {
22433 + DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
22434 + /* Program GUSBCFG.OtgUtmifsSel to I2C */
22435 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22436 + usbcfg.b.otgutmifssel = 1;
22437 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22439 + /* Program GI2CCTL.I2CEn */
22440 + i2cctl.d32 = DWC_READ_REG32(&global_regs->gi2cctl);
22441 + i2cctl.b.i2cdevaddr = 1;
22442 + i2cctl.b.i2cen = 0;
22443 + DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
22444 + i2cctl.b.i2cen = 1;
22445 + DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
22448 + } /* endif speed == DWC_SPEED_PARAM_FULL */
22450 + /* High speed PHY. */
22451 + if (!core_if->phy_init_done) {
22452 + core_if->phy_init_done = 1;
22453 + /* HS PHY parameters. These parameters are preserved
22454 + * during soft reset so only program the first time. Do
22455 + * a soft reset immediately after setting phyif. */
22457 + if (core_if->core_params->phy_type == 2) {
22458 + /* ULPI interface */
22459 + usbcfg.b.ulpi_utmi_sel = 1;
22460 + usbcfg.b.phyif = 0;
22461 + usbcfg.b.ddrsel =
22462 + core_if->core_params->phy_ulpi_ddr;
22463 + } else if (core_if->core_params->phy_type == 1) {
22464 + /* UTMI+ interface */
22465 + usbcfg.b.ulpi_utmi_sel = 0;
22466 + if (core_if->core_params->phy_utmi_width == 16) {
22467 + usbcfg.b.phyif = 1;
22470 + usbcfg.b.phyif = 0;
22473 + DWC_ERROR("FS PHY TYPE\n");
22475 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22476 + /* Reset after setting the PHY parameters */
22477 + dwc_otg_core_reset(core_if);
22481 + if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
22482 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
22483 + (core_if->core_params->ulpi_fs_ls)) {
22484 + DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
22485 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22486 + usbcfg.b.ulpi_fsls = 1;
22487 + usbcfg.b.ulpi_clk_sus_m = 1;
22488 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22490 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22491 + usbcfg.b.ulpi_fsls = 0;
22492 + usbcfg.b.ulpi_clk_sus_m = 0;
22493 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22496 + /* Program the GAHBCFG Register. */
22497 + switch (core_if->hwcfg2.b.architecture) {
22499 + case DWC_SLAVE_ONLY_ARCH:
22500 + DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
22501 + ahbcfg.b.nptxfemplvl_txfemplvl =
22502 + DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
22503 + ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
22504 + core_if->dma_enable = 0;
22505 + core_if->dma_desc_enable = 0;
22508 + case DWC_EXT_DMA_ARCH:
22509 + DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
22511 + uint8_t brst_sz = core_if->core_params->dma_burst_size;
22512 + ahbcfg.b.hburstlen = 0;
22513 + while (brst_sz > 1) {
22514 + ahbcfg.b.hburstlen++;
22518 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
22519 + core_if->dma_desc_enable =
22520 + (core_if->core_params->dma_desc_enable != 0);
22523 + case DWC_INT_DMA_ARCH:
22524 + DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
22525 + /* Old value was DWC_GAHBCFG_INT_DMA_BURST_INCR - done for
22526 + Host mode ISOC in issue fix - vahrama */
22527 + /* Broadcom had altered to (1<<3)|(0<<0) - WRESP=1, max 4 beats */
22528 + ahbcfg.b.hburstlen = (1<<3)|(0<<0);//DWC_GAHBCFG_INT_DMA_BURST_INCR4;
22529 + core_if->dma_enable = (core_if->core_params->dma_enable != 0);
22530 + core_if->dma_desc_enable =
22531 + (core_if->core_params->dma_desc_enable != 0);
22535 + if (core_if->dma_enable) {
22536 + if (core_if->dma_desc_enable) {
22537 + DWC_PRINTF("Using Descriptor DMA mode\n");
22539 + DWC_PRINTF("Using Buffer DMA mode\n");
22543 + DWC_PRINTF("Using Slave mode\n");
22544 + core_if->dma_desc_enable = 0;
22547 + if (core_if->core_params->ahb_single) {
22548 + ahbcfg.b.ahbsingle = 1;
22551 + ahbcfg.b.dmaenable = core_if->dma_enable;
22552 + DWC_WRITE_REG32(&global_regs->gahbcfg, ahbcfg.d32);
22554 + core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en;
22556 + core_if->pti_enh_enable = core_if->core_params->pti_enable != 0;
22557 + core_if->multiproc_int_enable = core_if->core_params->mpi_enable;
22558 + DWC_PRINTF("Periodic Transfer Interrupt Enhancement - %s\n",
22559 + ((core_if->pti_enh_enable) ? "enabled" : "disabled"));
22560 + DWC_PRINTF("Multiprocessor Interrupt Enhancement - %s\n",
22561 + ((core_if->multiproc_int_enable) ? "enabled" : "disabled"));
22564 + * Program the GUSBCFG register.
22566 + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
22568 + switch (core_if->hwcfg2.b.op_mode) {
22569 + case DWC_MODE_HNP_SRP_CAPABLE:
22570 + usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
22571 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
22572 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22573 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22576 + case DWC_MODE_SRP_ONLY_CAPABLE:
22577 + usbcfg.b.hnpcap = 0;
22578 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22579 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22582 + case DWC_MODE_NO_HNP_SRP_CAPABLE:
22583 + usbcfg.b.hnpcap = 0;
22584 + usbcfg.b.srpcap = 0;
22587 + case DWC_MODE_SRP_CAPABLE_DEVICE:
22588 + usbcfg.b.hnpcap = 0;
22589 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22590 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22593 + case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
22594 + usbcfg.b.hnpcap = 0;
22595 + usbcfg.b.srpcap = 0;
22598 + case DWC_MODE_SRP_CAPABLE_HOST:
22599 + usbcfg.b.hnpcap = 0;
22600 + usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
22601 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
22604 + case DWC_MODE_NO_SRP_CAPABLE_HOST:
22605 + usbcfg.b.hnpcap = 0;
22606 + usbcfg.b.srpcap = 0;
22610 + DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
22612 +#ifdef CONFIG_USB_DWC_OTG_LPM
22613 + if (core_if->core_params->lpm_enable) {
22614 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
22616 + /* To enable LPM support set lpm_cap_en bit */
22617 + lpmcfg.b.lpm_cap_en = 1;
22619 + /* Make AppL1Res ACK */
22620 + lpmcfg.b.appl_resp = 1;
22622 + /* Retry 3 times */
22623 + lpmcfg.b.retry_count = 3;
22625 + DWC_MODIFY_REG32(&core_if->core_global_regs->glpmcfg,
22630 + if (core_if->core_params->ic_usb_cap) {
22631 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
22632 + gusbcfg.b.ic_usb_cap = 1;
22633 + DWC_MODIFY_REG32(&core_if->core_global_regs->gusbcfg,
22637 + gotgctl_data_t gotgctl = {.d32 = 0 };
22638 + gotgctl.b.otgver = core_if->core_params->otg_ver;
22639 + DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, 0,
22641 + /* Set OTG version supported */
22642 + core_if->otg_ver = core_if->core_params->otg_ver;
22643 + DWC_PRINTF("OTG VER PARAM: %d, OTG VER FLAG: %d\n",
22644 + core_if->core_params->otg_ver, core_if->otg_ver);
22648 + /* Enable common interrupts */
22649 + dwc_otg_enable_common_interrupts(core_if);
22651 + /* Do device or host intialization based on mode during PCD
22652 + * and HCD initialization */
22653 + if (dwc_otg_is_host_mode(core_if)) {
22654 + DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
22655 + core_if->op_state = A_HOST;
22657 + DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
22658 + core_if->op_state = B_PERIPHERAL;
22659 +#ifdef DWC_DEVICE_ONLY
22660 + dwc_otg_core_dev_init(core_if);
22666 + * This function enables the Device mode interrupts.
22668 + * @param core_if Programming view of DWC_otg controller
22670 +void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if)
22672 + gintmsk_data_t intr_mask = {.d32 = 0 };
22673 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22675 + DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
22677 + /* Disable all interrupts. */
22678 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
22680 + /* Clear any pending interrupts */
22681 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
22683 + /* Enable the common interrupts */
22684 + dwc_otg_enable_common_interrupts(core_if);
22686 + /* Enable interrupts */
22687 + intr_mask.b.usbreset = 1;
22688 + intr_mask.b.enumdone = 1;
22689 + /* Disable Disconnect interrupt in Device mode */
22690 + intr_mask.b.disconnect = 0;
22692 + if (!core_if->multiproc_int_enable) {
22693 + intr_mask.b.inepintr = 1;
22694 + intr_mask.b.outepintr = 1;
22697 + intr_mask.b.erlysuspend = 1;
22699 + if (core_if->en_multiple_tx_fifo == 0) {
22700 + intr_mask.b.epmismatch = 1;
22703 + //intr_mask.b.incomplisoout = 1;
22704 + intr_mask.b.incomplisoin = 1;
22706 +/* Enable the ignore frame number for ISOC xfers - MAS */
22707 +/* Disable to support high bandwith ISOC transfers - manukz */
22709 +#ifdef DWC_UTE_PER_IO
22710 + if (core_if->dma_enable) {
22711 + if (core_if->dma_desc_enable) {
22712 + dctl_data_t dctl1 = {.d32 = 0 };
22713 + dctl1.b.ifrmnum = 1;
22714 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
22715 + dctl, 0, dctl1.d32);
22716 + DWC_DEBUG("----Enabled Ignore frame number (0x%08x)",
22717 + DWC_READ_REG32(&core_if->dev_if->
22718 + dev_global_regs->dctl));
22723 +#ifdef DWC_EN_ISOC
22724 + if (core_if->dma_enable) {
22725 + if (core_if->dma_desc_enable == 0) {
22726 + if (core_if->pti_enh_enable) {
22727 + dctl_data_t dctl = {.d32 = 0 };
22728 + dctl.b.ifrmnum = 1;
22729 + DWC_MODIFY_REG32(&core_if->
22730 + dev_if->dev_global_regs->dctl,
22733 + intr_mask.b.incomplisoin = 1;
22734 + intr_mask.b.incomplisoout = 1;
22738 + intr_mask.b.incomplisoin = 1;
22739 + intr_mask.b.incomplisoout = 1;
22741 +#endif /* DWC_EN_ISOC */
22743 + /** @todo NGS: Should this be a module parameter? */
22744 +#ifdef USE_PERIODIC_EP
22745 + intr_mask.b.isooutdrop = 1;
22746 + intr_mask.b.eopframe = 1;
22747 + intr_mask.b.incomplisoin = 1;
22748 + intr_mask.b.incomplisoout = 1;
22751 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
22753 + DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
22754 + DWC_READ_REG32(&global_regs->gintmsk));
22758 + * This function initializes the DWC_otg controller registers for
22761 + * @param core_if Programming view of DWC_otg controller
22764 +void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if)
22767 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
22768 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
22769 + dwc_otg_core_params_t *params = core_if->core_params;
22770 + dcfg_data_t dcfg = {.d32 = 0 };
22771 + depctl_data_t diepctl = {.d32 = 0 };
22772 + grstctl_t resetctl = {.d32 = 0 };
22773 + uint32_t rx_fifo_size;
22774 + fifosize_data_t nptxfifosize;
22775 + fifosize_data_t txfifosize;
22776 + dthrctl_data_t dthrctl;
22777 + fifosize_data_t ptxfifosize;
22778 + uint16_t rxfsiz, nptxfsiz;
22779 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
22780 + hwcfg3_data_t hwcfg3 = {.d32 = 0 };
22782 + /* Restart the Phy Clock */
22783 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
22785 + /* Device configuration register */
22786 + init_devspd(core_if);
22787 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
22788 + dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0;
22789 + dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
22790 + /* Enable Device OUT NAK in case of DDMA mode*/
22791 + if (core_if->core_params->dev_out_nak) {
22792 + dcfg.b.endevoutnak = 1;
22795 + if (core_if->core_params->cont_on_bna) {
22796 + dctl_data_t dctl = {.d32 = 0 };
22797 + dctl.b.encontonbna = 1;
22798 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
22802 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
22804 + /* Configure data FIFO sizes */
22805 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
22806 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
22807 + core_if->total_fifo_size);
22808 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
22809 + params->dev_rx_fifo_size);
22810 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
22811 + params->dev_nperio_tx_fifo_size);
22814 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
22815 + DWC_READ_REG32(&global_regs->grxfsiz));
22817 +#ifdef DWC_UTE_CFI
22818 + core_if->pwron_rxfsiz = DWC_READ_REG32(&global_regs->grxfsiz);
22819 + core_if->init_rxfsiz = params->dev_rx_fifo_size;
22821 + rx_fifo_size = params->dev_rx_fifo_size;
22822 + DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
22824 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
22825 + DWC_READ_REG32(&global_regs->grxfsiz));
22827 + /** Set Periodic Tx FIFO Mask all bits 0 */
22828 + core_if->p_tx_msk = 0;
22830 + /** Set Tx FIFO Mask all bits 0 */
22831 + core_if->tx_msk = 0;
22833 + if (core_if->en_multiple_tx_fifo == 0) {
22834 + /* Non-periodic Tx FIFO */
22835 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
22836 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22838 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
22839 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
22841 + DWC_WRITE_REG32(&global_regs->gnptxfsiz,
22842 + nptxfifosize.d32);
22844 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
22845 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22847 + /**@todo NGS: Fix Periodic FIFO Sizing! */
22849 + * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
22850 + * Indexes of the FIFO size module parameters in the
22851 + * dev_perio_tx_fifo_size array and the FIFO size registers in
22852 + * the dptxfsiz array run from 0 to 14.
22854 + /** @todo Finish debug of this */
22855 + ptxfifosize.b.startaddr =
22856 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
22857 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
22858 + ptxfifosize.b.depth =
22859 + params->dev_perio_tx_fifo_size[i];
22860 + DWC_DEBUGPL(DBG_CIL,
22861 + "initial dtxfsiz[%d]=%08x\n", i,
22862 + DWC_READ_REG32(&global_regs->dtxfsiz
22864 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
22865 + ptxfifosize.d32);
22866 + DWC_DEBUGPL(DBG_CIL, "new dtxfsiz[%d]=%08x\n",
22868 + DWC_READ_REG32(&global_regs->dtxfsiz
22870 + ptxfifosize.b.startaddr += ptxfifosize.b.depth;
22874 + * Tx FIFOs These FIFOs are numbered from 1 to 15.
22875 + * Indexes of the FIFO size module parameters in the
22876 + * dev_tx_fifo_size array and the FIFO size registers in
22877 + * the dtxfsiz array run from 0 to 14.
22880 + /* Non-periodic Tx FIFO */
22881 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
22882 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22884 +#ifdef DWC_UTE_CFI
22885 + core_if->pwron_gnptxfsiz =
22886 + (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
22887 + core_if->init_gnptxfsiz =
22888 + params->dev_nperio_tx_fifo_size;
22890 + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
22891 + nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
22893 + DWC_WRITE_REG32(&global_regs->gnptxfsiz,
22894 + nptxfifosize.d32);
22896 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
22897 + DWC_READ_REG32(&global_regs->gnptxfsiz));
22899 + txfifosize.b.startaddr =
22900 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
22902 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
22904 + txfifosize.b.depth =
22905 + params->dev_tx_fifo_size[i];
22907 + DWC_DEBUGPL(DBG_CIL,
22908 + "initial dtxfsiz[%d]=%08x\n",
22910 + DWC_READ_REG32(&global_regs->dtxfsiz
22913 +#ifdef DWC_UTE_CFI
22914 + core_if->pwron_txfsiz[i] =
22916 + (&global_regs->dtxfsiz[i]) >> 16);
22917 + core_if->init_txfsiz[i] =
22918 + params->dev_tx_fifo_size[i];
22920 + DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
22923 + DWC_DEBUGPL(DBG_CIL,
22924 + "new dtxfsiz[%d]=%08x\n",
22926 + DWC_READ_REG32(&global_regs->dtxfsiz
22929 + txfifosize.b.startaddr += txfifosize.b.depth;
22931 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
22932 + /* Calculating DFIFOCFG for Device mode to include RxFIFO and NPTXFIFO */
22933 + gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
22934 + hwcfg3.d32 = DWC_READ_REG32(&global_regs->ghwcfg3);
22935 + gdfifocfg.b.gdfifocfg = (DWC_READ_REG32(&global_regs->ghwcfg3) >> 16);
22936 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
22937 + rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
22938 + nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
22939 + gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz;
22940 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
22944 + /* Flush the FIFOs */
22945 + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
22946 + dwc_otg_flush_rx_fifo(core_if);
22948 + /* Flush the Learning Queue. */
22949 + resetctl.b.intknqflsh = 1;
22950 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
22952 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
22953 + core_if->start_predict = 0;
22954 + for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
22955 + core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
22957 + core_if->nextep_seq[0] = 0;
22958 + core_if->first_in_nextep_seq = 0;
22959 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
22960 + diepctl.b.nextep = 0;
22961 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
22963 + /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
22964 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
22965 + dcfg.b.epmscnt = 2;
22966 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
22968 + DWC_DEBUGPL(DBG_CILV,"%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
22969 + __func__, core_if->first_in_nextep_seq);
22970 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
22971 + DWC_DEBUGPL(DBG_CILV, "%2d ", core_if->nextep_seq[i]);
22973 + DWC_DEBUGPL(DBG_CILV,"\n");
22976 + /* Clear all pending Device Interrupts */
22977 + /** @todo - if the condition needed to be checked
22978 + * or in any case all pending interrutps should be cleared?
22980 + if (core_if->multiproc_int_enable) {
22981 + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
22982 + DWC_WRITE_REG32(&dev_if->
22983 + dev_global_regs->diepeachintmsk[i], 0);
22987 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
22988 + DWC_WRITE_REG32(&dev_if->
22989 + dev_global_regs->doepeachintmsk[i], 0);
22992 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF);
22993 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk, 0);
22995 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, 0);
22996 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, 0);
22997 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
22998 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk, 0);
23001 + for (i = 0; i <= dev_if->num_in_eps; i++) {
23002 + depctl_data_t depctl;
23003 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
23004 + if (depctl.b.epena) {
23006 + depctl.b.epdis = 1;
23007 + depctl.b.snak = 1;
23012 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
23014 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
23015 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, 0);
23016 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
23019 + for (i = 0; i <= dev_if->num_out_eps; i++) {
23020 + depctl_data_t depctl;
23021 + depctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
23022 + if (depctl.b.epena) {
23023 + dctl_data_t dctl = {.d32 = 0 };
23024 + gintmsk_data_t gintsts = {.d32 = 0 };
23025 + doepint_data_t doepint = {.d32 = 0 };
23026 + dctl.b.sgoutnak = 1;
23027 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
23030 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
23031 + } while (!gintsts.b.goutnakeff);
23033 + gintsts.b.goutnakeff = 1;
23034 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
23037 + depctl.b.epdis = 1;
23038 + depctl.b.snak = 1;
23039 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepctl, depctl.d32);
23042 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
23043 + out_ep_regs[i]->doepint);
23044 + } while (!doepint.b.epdisabled);
23046 + doepint.b.epdisabled = 1;
23047 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepint, doepint.d32);
23050 + dctl.b.cgoutnak = 1;
23051 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
23056 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
23058 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
23059 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepdma, 0);
23060 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
23063 + if (core_if->en_multiple_tx_fifo && core_if->dma_enable) {
23064 + dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1;
23065 + dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1;
23066 + dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1;
23068 + dev_if->rx_thr_length = params->rx_thr_length;
23069 + dev_if->tx_thr_length = params->tx_thr_length;
23071 + dev_if->setup_desc_index = 0;
23074 + dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
23075 + dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
23076 + dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
23077 + dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
23078 + dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
23079 + dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio;
23081 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dtknqr3_dthrctl,
23084 + DWC_DEBUGPL(DBG_CIL,
23085 + "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
23086 + dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en,
23087 + dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len,
23088 + dthrctl.b.rx_thr_len);
23092 + dwc_otg_enable_device_interrupts(core_if);
23095 + diepmsk_data_t msk = {.d32 = 0 };
23096 + msk.b.txfifoundrn = 1;
23097 + if (core_if->multiproc_int_enable) {
23098 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->
23099 + diepeachintmsk[0], msk.d32, msk.d32);
23101 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk,
23102 + msk.d32, msk.d32);
23106 + if (core_if->multiproc_int_enable) {
23107 + /* Set NAK on Babble */
23108 + dctl_data_t dctl = {.d32 = 0 };
23109 + dctl.b.nakonbble = 1;
23110 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
23113 + if (core_if->snpsid >= OTG_CORE_REV_2_94a) {
23114 + dctl_data_t dctl = {.d32 = 0 };
23115 + dctl.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
23116 + dctl.b.sftdiscon = 0;
23117 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl, dctl.d32);
23122 + * This function enables the Host mode interrupts.
23124 + * @param core_if Programming view of DWC_otg controller
23126 +void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if)
23128 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
23129 + gintmsk_data_t intr_mask = {.d32 = 0 };
23131 + DWC_DEBUGPL(DBG_CIL, "%s(%p)\n", __func__, core_if);
23133 + /* Disable all interrupts. */
23134 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
23136 + /* Clear any pending interrupts. */
23137 + DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
23139 + /* Enable the common interrupts */
23140 + dwc_otg_enable_common_interrupts(core_if);
23143 + * Enable host mode interrupts without disturbing common
23147 + intr_mask.b.disconnect = 1;
23148 + intr_mask.b.portintr = 1;
23149 + intr_mask.b.hcintr = 1;
23151 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
23155 + * This function disables the Host Mode interrupts.
23157 + * @param core_if Programming view of DWC_otg controller
23159 +void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if)
23161 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
23162 + gintmsk_data_t intr_mask = {.d32 = 0 };
23164 + DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
23167 + * Disable host mode interrupts without disturbing common
23170 + intr_mask.b.sofintr = 1;
23171 + intr_mask.b.portintr = 1;
23172 + intr_mask.b.hcintr = 1;
23173 + intr_mask.b.ptxfempty = 1;
23174 + intr_mask.b.nptxfempty = 1;
23176 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, 0);
23180 + * This function initializes the DWC_otg controller registers for
23183 + * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
23184 + * request queues. Host channels are reset to ensure that they are ready for
23185 + * performing transfers.
23187 + * @param core_if Programming view of DWC_otg controller
23190 +void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
23192 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
23193 + dwc_otg_host_if_t *host_if = core_if->host_if;
23194 + dwc_otg_core_params_t *params = core_if->core_params;
23195 + hprt0_data_t hprt0 = {.d32 = 0 };
23196 + fifosize_data_t nptxfifosize;
23197 + fifosize_data_t ptxfifosize;
23198 + uint16_t rxfsiz, nptxfsiz, hptxfsiz;
23199 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
23201 + hcchar_data_t hcchar;
23202 + hcfg_data_t hcfg;
23203 + hfir_data_t hfir;
23204 + dwc_otg_hc_regs_t *hc_regs;
23205 + int num_channels;
23206 + gotgctl_data_t gotgctl = {.d32 = 0 };
23208 + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
23210 + /* Restart the Phy Clock */
23211 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
23213 + /* Initialize Host Configuration Register */
23214 + init_fslspclksel(core_if);
23215 + if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
23216 + hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
23217 + hcfg.b.fslssupp = 1;
23218 + DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
23222 + /* This bit allows dynamic reloading of the HFIR register
23223 + * during runtime. This bit needs to be programmed during
23224 + * initial configuration and its value must not be changed
23225 + * during runtime.*/
23226 + if (core_if->core_params->reload_ctl == 1) {
23227 + hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
23228 + hfir.b.hfirrldctrl = 1;
23229 + DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
23232 + if (core_if->core_params->dma_desc_enable) {
23233 + uint8_t op_mode = core_if->hwcfg2.b.op_mode;
23235 + (core_if->hwcfg4.b.desc_dma
23236 + && (core_if->snpsid >= OTG_CORE_REV_2_90a)
23237 + && ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
23238 + || (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
23240 + DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG)
23241 + || (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)
23243 + DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) {
23245 + DWC_ERROR("Host can't operate in Descriptor DMA mode.\n"
23246 + "Either core version is below 2.90a or "
23247 + "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n"
23248 + "To run the driver in Buffer DMA host mode set dma_desc_enable "
23249 + "module parameter to 0.\n");
23252 + hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
23253 + hcfg.b.descdma = 1;
23254 + DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
23257 + /* Configure data FIFO sizes */
23258 + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
23259 + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
23260 + core_if->total_fifo_size);
23261 + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
23262 + params->host_rx_fifo_size);
23263 + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
23264 + params->host_nperio_tx_fifo_size);
23265 + DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
23266 + params->host_perio_tx_fifo_size);
23269 + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
23270 + DWC_READ_REG32(&global_regs->grxfsiz));
23271 + DWC_WRITE_REG32(&global_regs->grxfsiz,
23272 + params->host_rx_fifo_size);
23273 + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
23274 + DWC_READ_REG32(&global_regs->grxfsiz));
23276 + /* Non-periodic Tx FIFO */
23277 + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
23278 + DWC_READ_REG32(&global_regs->gnptxfsiz));
23279 + nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
23280 + nptxfifosize.b.startaddr = params->host_rx_fifo_size;
23281 + DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
23282 + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
23283 + DWC_READ_REG32(&global_regs->gnptxfsiz));
23285 + /* Periodic Tx FIFO */
23286 + DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
23287 + DWC_READ_REG32(&global_regs->hptxfsiz));
23288 + ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
23289 + ptxfifosize.b.startaddr =
23290 + nptxfifosize.b.startaddr + nptxfifosize.b.depth;
23291 + DWC_WRITE_REG32(&global_regs->hptxfsiz, ptxfifosize.d32);
23292 + DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
23293 + DWC_READ_REG32(&global_regs->hptxfsiz));
23295 + if (core_if->en_multiple_tx_fifo
23296 + && core_if->snpsid <= OTG_CORE_REV_2_94a) {
23297 + /* Global DFIFOCFG calculation for Host mode - include RxFIFO, NPTXFIFO and HPTXFIFO */
23298 + gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
23299 + rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
23300 + nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
23301 + hptxfsiz = (DWC_READ_REG32(&global_regs->hptxfsiz) >> 16);
23302 + gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz + hptxfsiz;
23303 + DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
23307 + /* TODO - check this */
23308 + /* Clear Host Set HNP Enable in the OTG Control Register */
23309 + gotgctl.b.hstsethnpen = 1;
23310 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
23311 + /* Make sure the FIFOs are flushed. */
23312 + dwc_otg_flush_tx_fifo(core_if, 0x10 /* all TX FIFOs */ );
23313 + dwc_otg_flush_rx_fifo(core_if);
23315 + /* Clear Host Set HNP Enable in the OTG Control Register */
23316 + gotgctl.b.hstsethnpen = 1;
23317 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
23319 + if (!core_if->core_params->dma_desc_enable) {
23320 + /* Flush out any leftover queued requests. */
23321 + num_channels = core_if->core_params->host_channels;
23323 + for (i = 0; i < num_channels; i++) {
23324 + hc_regs = core_if->host_if->hc_regs[i];
23325 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23326 + hcchar.b.chen = 0;
23327 + hcchar.b.chdis = 1;
23328 + hcchar.b.epdir = 0;
23329 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23332 + /* Halt all channels to put them into a known state. */
23333 + for (i = 0; i < num_channels; i++) {
23335 + hc_regs = core_if->host_if->hc_regs[i];
23336 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23337 + hcchar.b.chen = 1;
23338 + hcchar.b.chdis = 1;
23339 + hcchar.b.epdir = 0;
23340 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23341 + DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d regs %p\n", __func__, i, hc_regs);
23343 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23344 + if (++count > 1000) {
23346 + ("%s: Unable to clear halt on channel %d (timeout HCCHAR 0x%X @%p)\n",
23347 + __func__, i, hcchar.d32, &hc_regs->hcchar);
23351 + } while (hcchar.b.chen);
23355 + /* Turn on the vbus power. */
23356 + DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state);
23357 + if (core_if->op_state == A_HOST) {
23358 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
23359 + DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
23360 + if (hprt0.b.prtpwr == 0) {
23361 + hprt0.b.prtpwr = 1;
23362 + DWC_WRITE_REG32(host_if->hprt0, hprt0.d32);
23366 + dwc_otg_enable_host_interrupts(core_if);
23370 + * Prepares a host channel for transferring packets to/from a specific
23371 + * endpoint. The HCCHARn register is set up with the characteristics specified
23372 + * in _hc. Host channel interrupts that may need to be serviced while this
23373 + * transfer is in progress are enabled.
23375 + * @param core_if Programming view of DWC_otg controller
23376 + * @param hc Information needed to initialize the host channel
23378 +void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23380 + uint32_t intr_enable;
23381 + hcintmsk_data_t hc_intr_mask;
23382 + gintmsk_data_t gintmsk = {.d32 = 0 };
23383 + hcchar_data_t hcchar;
23384 + hcsplt_data_t hcsplt;
23386 + uint8_t hc_num = hc->hc_num;
23387 + dwc_otg_host_if_t *host_if = core_if->host_if;
23388 + dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
23390 + /* Clear old interrupt conditions for this host channel. */
23391 + hc_intr_mask.d32 = 0xFFFFFFFF;
23392 + hc_intr_mask.b.reserved14_31 = 0;
23393 + DWC_WRITE_REG32(&hc_regs->hcint, hc_intr_mask.d32);
23395 + /* Enable channel interrupts required for this transfer. */
23396 + hc_intr_mask.d32 = 0;
23397 + hc_intr_mask.b.chhltd = 1;
23398 + if (core_if->dma_enable) {
23399 + /* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */
23400 + if (!core_if->dma_desc_enable)
23401 + hc_intr_mask.b.ahberr = 1;
23403 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23404 + hc_intr_mask.b.xfercompl = 1;
23407 + if (hc->error_state && !hc->do_split &&
23408 + hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
23409 + hc_intr_mask.b.ack = 1;
23410 + if (hc->ep_is_in) {
23411 + hc_intr_mask.b.datatglerr = 1;
23412 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
23413 + hc_intr_mask.b.nak = 1;
23418 + switch (hc->ep_type) {
23419 + case DWC_OTG_EP_TYPE_CONTROL:
23420 + case DWC_OTG_EP_TYPE_BULK:
23421 + hc_intr_mask.b.xfercompl = 1;
23422 + hc_intr_mask.b.stall = 1;
23423 + hc_intr_mask.b.xacterr = 1;
23424 + hc_intr_mask.b.datatglerr = 1;
23425 + if (hc->ep_is_in) {
23426 + hc_intr_mask.b.bblerr = 1;
23428 + hc_intr_mask.b.nak = 1;
23429 + hc_intr_mask.b.nyet = 1;
23430 + if (hc->do_ping) {
23431 + hc_intr_mask.b.ack = 1;
23435 + if (hc->do_split) {
23436 + hc_intr_mask.b.nak = 1;
23437 + if (hc->complete_split) {
23438 + hc_intr_mask.b.nyet = 1;
23440 + hc_intr_mask.b.ack = 1;
23444 + if (hc->error_state) {
23445 + hc_intr_mask.b.ack = 1;
23448 + case DWC_OTG_EP_TYPE_INTR:
23449 + hc_intr_mask.b.xfercompl = 1;
23450 + hc_intr_mask.b.nak = 1;
23451 + hc_intr_mask.b.stall = 1;
23452 + hc_intr_mask.b.xacterr = 1;
23453 + hc_intr_mask.b.datatglerr = 1;
23454 + hc_intr_mask.b.frmovrun = 1;
23456 + if (hc->ep_is_in) {
23457 + hc_intr_mask.b.bblerr = 1;
23459 + if (hc->error_state) {
23460 + hc_intr_mask.b.ack = 1;
23462 + if (hc->do_split) {
23463 + if (hc->complete_split) {
23464 + hc_intr_mask.b.nyet = 1;
23466 + hc_intr_mask.b.ack = 1;
23470 + case DWC_OTG_EP_TYPE_ISOC:
23471 + hc_intr_mask.b.xfercompl = 1;
23472 + hc_intr_mask.b.frmovrun = 1;
23473 + hc_intr_mask.b.ack = 1;
23475 + if (hc->ep_is_in) {
23476 + hc_intr_mask.b.xacterr = 1;
23477 + hc_intr_mask.b.bblerr = 1;
23482 + DWC_WRITE_REG32(&hc_regs->hcintmsk, hc_intr_mask.d32);
23484 + /* Enable the top level host channel interrupt. */
23485 + intr_enable = (1 << hc_num);
23486 + DWC_MODIFY_REG32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
23488 + /* Make sure host channel interrupts are enabled. */
23489 + gintmsk.b.hcintr = 1;
23490 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
23493 + * Program the HCCHARn register with the endpoint characteristics for
23494 + * the current transfer.
23497 + hcchar.b.devaddr = hc->dev_addr;
23498 + hcchar.b.epnum = hc->ep_num;
23499 + hcchar.b.epdir = hc->ep_is_in;
23500 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
23501 + hcchar.b.eptype = hc->ep_type;
23502 + hcchar.b.mps = hc->max_packet;
23504 + DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
23506 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d, Dev Addr %d, EP #%d\n",
23507 + __func__, hc->hc_num, hcchar.b.devaddr, hcchar.b.epnum);
23508 + DWC_DEBUGPL(DBG_HCDV, " Is In %d, Is Low Speed %d, EP Type %d, "
23509 + "Max Pkt %d, Multi Cnt %d\n",
23510 + hcchar.b.epdir, hcchar.b.lspddev, hcchar.b.eptype,
23511 + hcchar.b.mps, hcchar.b.multicnt);
23514 + * Program the HCSPLIT register for SPLITs
23517 + if (hc->do_split) {
23518 + DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
23520 + hc->complete_split ? "CSPLIT" : "SSPLIT");
23521 + hcsplt.b.compsplt = hc->complete_split;
23522 + hcsplt.b.xactpos = hc->xact_pos;
23523 + hcsplt.b.hubaddr = hc->hub_addr;
23524 + hcsplt.b.prtaddr = hc->port_addr;
23525 + DWC_DEBUGPL(DBG_HCDV, "\t comp split %d\n", hc->complete_split);
23526 + DWC_DEBUGPL(DBG_HCDV, "\t xact pos %d\n", hc->xact_pos);
23527 + DWC_DEBUGPL(DBG_HCDV, "\t hub addr %d\n", hc->hub_addr);
23528 + DWC_DEBUGPL(DBG_HCDV, "\t port addr %d\n", hc->port_addr);
23529 + DWC_DEBUGPL(DBG_HCDV, "\t is_in %d\n", hc->ep_is_in);
23530 + DWC_DEBUGPL(DBG_HCDV, "\t Max Pkt: %d\n", hcchar.b.mps);
23531 + DWC_DEBUGPL(DBG_HCDV, "\t xferlen: %d\n", hc->xfer_len);
23533 + DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
23538 + * Attempts to halt a host channel. This function should only be called in
23539 + * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
23540 + * normal circumstances in DMA mode, the controller halts the channel when the
23541 + * transfer is complete or a condition occurs that requires application
23544 + * In slave mode, checks for a free request queue entry, then sets the Channel
23545 + * Enable and Channel Disable bits of the Host Channel Characteristics
23546 + * register of the specified channel to intiate the halt. If there is no free
23547 + * request queue entry, sets only the Channel Disable bit of the HCCHARn
23548 + * register to flush requests for this channel. In the latter case, sets a
23549 + * flag to indicate that the host channel needs to be halted when a request
23550 + * queue slot is open.
23552 + * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
23553 + * HCCHARn register. The controller ensures there is space in the request
23554 + * queue before submitting the halt request.
23556 + * Some time may elapse before the core flushes any posted requests for this
23557 + * host channel and halts. The Channel Halted interrupt handler completes the
23558 + * deactivation of the host channel.
23560 + * @param core_if Controller register interface.
23561 + * @param hc Host channel to halt.
23562 + * @param halt_status Reason for halting the channel.
23564 +void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if,
23565 + dwc_hc_t * hc, dwc_otg_halt_status_e halt_status)
23567 + gnptxsts_data_t nptxsts;
23568 + hptxsts_data_t hptxsts;
23569 + hcchar_data_t hcchar;
23570 + dwc_otg_hc_regs_t *hc_regs;
23571 + dwc_otg_core_global_regs_t *global_regs;
23572 + dwc_otg_host_global_regs_t *host_global_regs;
23574 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23575 + global_regs = core_if->core_global_regs;
23576 + host_global_regs = core_if->host_if->host_global_regs;
23578 + DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS),
23579 + "halt_status = %d\n", halt_status);
23581 + if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
23582 + halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
23584 + * Disable all channel interrupts except Ch Halted. The QTD
23585 + * and QH state associated with this transfer has been cleared
23586 + * (in the case of URB_DEQUEUE), so the channel needs to be
23587 + * shut down carefully to prevent crashes.
23589 + hcintmsk_data_t hcintmsk;
23590 + hcintmsk.d32 = 0;
23591 + hcintmsk.b.chhltd = 1;
23592 + DWC_WRITE_REG32(&hc_regs->hcintmsk, hcintmsk.d32);
23595 + * Make sure no other interrupts besides halt are currently
23596 + * pending. Handling another interrupt could cause a crash due
23597 + * to the QTD and QH state.
23599 + DWC_WRITE_REG32(&hc_regs->hcint, ~hcintmsk.d32);
23602 + * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
23603 + * even if the channel was already halted for some other
23606 + hc->halt_status = halt_status;
23608 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23609 + if (hcchar.b.chen == 0) {
23611 + * The channel is either already halted or it hasn't
23612 + * started yet. In DMA mode, the transfer may halt if
23613 + * it finishes normally or a condition occurs that
23614 + * requires driver intervention. Don't want to halt
23615 + * the channel again. In either Slave or DMA mode,
23616 + * it's possible that the transfer has been assigned
23617 + * to a channel, but not started yet when an URB is
23618 + * dequeued. Don't want to halt a channel that hasn't
23624 + if (hc->halt_pending) {
23626 + * A halt has already been issued for this channel. This might
23627 + * happen when a transfer is aborted by a higher level in
23632 + ("*** %s: Channel %d, _hc->halt_pending already set ***\n",
23633 + __func__, hc->hc_num);
23639 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23641 + /* No need to set the bit in DDMA for disabling the channel */
23642 + //TODO check it everywhere channel is disabled
23643 + if (!core_if->core_params->dma_desc_enable)
23644 + hcchar.b.chen = 1;
23645 + hcchar.b.chdis = 1;
23647 + if (!core_if->dma_enable) {
23648 + /* Check for space in the request queue to issue the halt. */
23649 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
23650 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
23651 + nptxsts.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
23652 + if (nptxsts.b.nptxqspcavail == 0) {
23653 + hcchar.b.chen = 0;
23657 + DWC_READ_REG32(&host_global_regs->hptxsts);
23658 + if ((hptxsts.b.ptxqspcavail == 0)
23659 + || (core_if->queuing_high_bandwidth)) {
23660 + hcchar.b.chen = 0;
23664 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
23666 + hc->halt_status = halt_status;
23668 + if (hcchar.b.chen) {
23669 + hc->halt_pending = 1;
23670 + hc->halt_on_queue = 0;
23672 + hc->halt_on_queue = 1;
23675 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23676 + DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32);
23677 + DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", hc->halt_pending);
23678 + DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", hc->halt_on_queue);
23679 + DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", hc->halt_status);
23685 + * Clears the transfer state for a host channel. This function is normally
23686 + * called after a transfer is done and the host channel is being released.
23688 + * @param core_if Programming view of DWC_otg controller.
23689 + * @param hc Identifies the host channel to clean up.
23691 +void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23693 + dwc_otg_hc_regs_t *hc_regs;
23695 + hc->xfer_started = 0;
23698 + * Clear channel interrupt enables and any unhandled channel interrupt
23701 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23702 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0);
23703 + DWC_WRITE_REG32(&hc_regs->hcint, 0xFFFFFFFF);
23705 + DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]);
23710 + * Sets the channel property that indicates in which frame a periodic transfer
23711 + * should occur. This is always set to the _next_ frame. This function has no
23712 + * effect on non-periodic transfers.
23714 + * @param core_if Programming view of DWC_otg controller.
23715 + * @param hc Identifies the host channel to set up and its properties.
23716 + * @param hcchar Current value of the HCCHAR register for the specified host
23719 +static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if,
23720 + dwc_hc_t * hc, hcchar_data_t * hcchar)
23722 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23723 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23724 + hfnum_data_t hfnum;
23726 + DWC_READ_REG32(&core_if->host_if->host_global_regs->hfnum);
23728 + /* 1 if _next_ frame is odd, 0 if it's even */
23729 + hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
23731 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
23732 + && !hc->complete_split) {
23733 + switch (hfnum.b.frnum & 0x7) {
23735 + core_if->hfnum_7_samples++;
23736 + core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
23739 + core_if->hfnum_0_samples++;
23740 + core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
23743 + core_if->hfnum_other_samples++;
23744 + core_if->hfnum_other_frrem_accum +=
23754 +void hc_xfer_timeout(void *ptr)
23756 + hc_xfer_info_t *xfer_info = NULL;
23760 + xfer_info = (hc_xfer_info_t *) ptr;
23762 + if (!xfer_info->hc) {
23763 + DWC_ERROR("xfer_info->hc = %p\n", xfer_info->hc);
23767 + hc_num = xfer_info->hc->hc_num;
23768 + DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
23769 + DWC_WARN(" start_hcchar_val 0x%08x\n",
23770 + xfer_info->core_if->start_hcchar_val[hc_num]);
23774 +void ep_xfer_timeout(void *ptr)
23776 + ep_xfer_info_t *xfer_info = NULL;
23778 + dctl_data_t dctl = {.d32 = 0 };
23779 + gintsts_data_t gintsts = {.d32 = 0 };
23780 + gintmsk_data_t gintmsk = {.d32 = 0 };
23783 + xfer_info = (ep_xfer_info_t *) ptr;
23785 + if (!xfer_info->ep) {
23786 + DWC_ERROR("xfer_info->ep = %p\n", xfer_info->ep);
23790 + ep_num = xfer_info->ep->num;
23791 + DWC_WARN("%s: timeout on endpoit %d\n", __func__, ep_num);
23792 + /* Put the sate to 2 as it was time outed */
23793 + xfer_info->state = 2;
23796 + DWC_READ_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl);
23798 + DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintsts);
23800 + DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintmsk);
23802 + if (!gintmsk.b.goutnakeff) {
23804 + gintmsk.b.goutnakeff = 1;
23805 + DWC_WRITE_REG32(&xfer_info->core_if->core_global_regs->gintmsk,
23810 + if (!gintsts.b.goutnakeff) {
23811 + dctl.b.sgoutnak = 1;
23813 + DWC_WRITE_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl,
23818 +void set_pid_isoc(dwc_hc_t * hc)
23820 + /* Set up the initial PID for the transfer. */
23821 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
23822 + if (hc->ep_is_in) {
23823 + if (hc->multi_count == 1) {
23824 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23825 + } else if (hc->multi_count == 2) {
23826 + hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
23828 + hc->data_pid_start = DWC_OTG_HC_PID_DATA2;
23831 + if (hc->multi_count == 1) {
23832 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23834 + hc->data_pid_start = DWC_OTG_HC_PID_MDATA;
23838 + hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
23843 + * This function does the setup for a data transfer for a host channel and
23844 + * starts the transfer. May be called in either Slave mode or DMA mode. In
23845 + * Slave mode, the caller must ensure that there is sufficient space in the
23846 + * request queue and Tx Data FIFO.
23848 + * For an OUT transfer in Slave mode, it loads a data packet into the
23849 + * appropriate FIFO. If necessary, additional data packets will be loaded in
23852 + * For an IN transfer in Slave mode, a data packet is requested. The data
23853 + * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
23854 + * additional data packets are requested in the Host ISR.
23856 + * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
23857 + * register along with a packet count of 1 and the channel is enabled. This
23858 + * causes a single PING transaction to occur. Other fields in HCTSIZ are
23859 + * simply set to 0 since no data transfer occurs in this case.
23861 + * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
23862 + * all the information required to perform the subsequent data transfer. In
23863 + * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
23864 + * controller performs the entire PING protocol, then starts the data
23867 + * @param core_if Programming view of DWC_otg controller.
23868 + * @param hc Information needed to initialize the host channel. The xfer_len
23869 + * value may be reduced to accommodate the max widths of the XferSize and
23870 + * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
23871 + * to reflect the final xfer_len value.
23873 +void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
23875 + hcchar_data_t hcchar;
23876 + hctsiz_data_t hctsiz;
23877 + uint16_t num_packets;
23878 + uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
23879 + uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
23880 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
23884 + if (hc->do_ping) {
23885 + if (!core_if->dma_enable) {
23886 + dwc_otg_hc_do_ping(core_if, hc);
23887 + hc->xfer_started = 1;
23890 + hctsiz.b.dopng = 1;
23894 + if (hc->do_split) {
23897 + if (hc->complete_split && !hc->ep_is_in) {
23898 + /* For CSPLIT OUT Transfer, set the size to 0 so the
23899 + * core doesn't expect any data written to the FIFO */
23900 + hc->xfer_len = 0;
23901 + } else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
23902 + hc->xfer_len = hc->max_packet;
23903 + } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
23904 + hc->xfer_len = 188;
23907 + hctsiz.b.xfersize = hc->xfer_len;
23910 + * Ensure that the transfer length and packet count will fit
23911 + * in the widths allocated for them in the HCTSIZn register.
23913 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23914 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23916 + * Make sure the transfer size is no larger than one
23917 + * (micro)frame's worth of data. (A check was done
23918 + * when the periodic transfer was accepted to ensure
23919 + * that a (micro)frame's worth of data can be
23920 + * programmed into a channel.)
23922 + uint32_t max_periodic_len =
23923 + hc->multi_count * hc->max_packet;
23924 + if (hc->xfer_len > max_periodic_len) {
23925 + hc->xfer_len = max_periodic_len;
23928 + } else if (hc->xfer_len > max_hc_xfer_size) {
23929 + /* Make sure that xfer_len is a multiple of max packet size. */
23930 + hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
23933 + if (hc->xfer_len > 0) {
23935 + (hc->xfer_len + hc->max_packet -
23936 + 1) / hc->max_packet;
23937 + if (num_packets > max_hc_pkt_count) {
23938 + num_packets = max_hc_pkt_count;
23939 + hc->xfer_len = num_packets * hc->max_packet;
23942 + /* Need 1 packet for transfer length of 0. */
23946 + if (hc->ep_is_in) {
23947 + /* Always program an integral # of max packets for IN transfers. */
23948 + hc->xfer_len = num_packets * hc->max_packet;
23951 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
23952 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
23954 + * Make sure that the multi_count field matches the
23955 + * actual transfer length.
23957 + hc->multi_count = num_packets;
23960 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
23961 + set_pid_isoc(hc);
23963 + hctsiz.b.xfersize = hc->xfer_len;
23966 + hc->start_pkt_count = num_packets;
23967 + hctsiz.b.pktcnt = num_packets;
23968 + hctsiz.b.pid = hc->data_pid_start;
23969 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
23971 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
23972 + DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize);
23973 + DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt);
23974 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
23976 + if (core_if->dma_enable) {
23977 + dwc_dma_t dma_addr;
23978 + if (hc->align_buff) {
23979 + dma_addr = hc->align_buff;
23981 + dma_addr = ((unsigned long)hc->xfer_buff & 0xffffffff);
23983 + DWC_WRITE_REG32(&hc_regs->hcdma, dma_addr);
23986 + /* Start the split */
23987 + if (hc->do_split) {
23988 + hcsplt_data_t hcsplt;
23989 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
23990 + hcsplt.b.spltena = 1;
23991 + DWC_WRITE_REG32(&hc_regs->hcsplt, hcsplt.d32);
23994 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
23995 + hcchar.b.multicnt = hc->multi_count;
23996 + hc_set_even_odd_frame(core_if, hc, &hcchar);
23998 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
23999 + if (hcchar.b.chdis) {
24000 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
24001 + __func__, hc->hc_num, hcchar.d32);
24005 + /* Set host channel enable after all other setup is complete. */
24006 + hcchar.b.chen = 1;
24007 + hcchar.b.chdis = 0;
24008 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24010 + hc->xfer_started = 1;
24013 + if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
24014 + /* Load OUT packet into the appropriate Tx FIFO. */
24015 + dwc_otg_hc_write_packet(core_if, hc);
24018 + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
24019 + DWC_DEBUGPL(DBG_HCDV, "transfer %d from core_if %p\n",
24020 + hc->hc_num, core_if);//GRAYG
24021 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
24022 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
24024 + /* Start a timer for this transfer. */
24025 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
24031 + * This function does the setup for a data transfer for a host channel
24032 + * and starts the transfer in Descriptor DMA mode.
24034 + * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
24035 + * Sets PID and NTD values. For periodic transfers
24036 + * initializes SCHED_INFO field with micro-frame bitmap.
24038 + * Initializes HCDMA register with descriptor list address and CTD value
24039 + * then starts the transfer via enabling the channel.
24041 + * @param core_if Programming view of DWC_otg controller.
24042 + * @param hc Information needed to initialize the host channel.
24044 +void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24046 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
24047 + hcchar_data_t hcchar;
24048 + hctsiz_data_t hctsiz;
24049 + hcdma_data_t hcdma;
24054 + hctsiz.b_ddma.dopng = 1;
24056 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
24057 + set_pid_isoc(hc);
24059 + /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
24060 + hctsiz.b_ddma.pid = hc->data_pid_start;
24061 + hctsiz.b_ddma.ntd = hc->ntd - 1; /* 0 - 1 descriptor, 1 - 2 descriptors, etc. */
24062 + hctsiz.b_ddma.schinfo = hc->schinfo; /* Non-zero only for high-speed interrupt endpoints */
24064 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
24065 + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
24066 + DWC_DEBUGPL(DBG_HCDV, " NTD: %d\n", hctsiz.b_ddma.ntd);
24068 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
24071 + hcdma.b.dma_addr = ((uint32_t) hc->desc_list_addr) >> 11;
24073 + /* Always start from first descriptor. */
24075 + DWC_WRITE_REG32(&hc_regs->hcdma, hcdma.d32);
24077 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24078 + hcchar.b.multicnt = hc->multi_count;
24081 + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
24082 + if (hcchar.b.chdis) {
24083 + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
24084 + __func__, hc->hc_num, hcchar.d32);
24088 + /* Set host channel enable after all other setup is complete. */
24089 + hcchar.b.chen = 1;
24090 + hcchar.b.chdis = 0;
24092 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24094 + hc->xfer_started = 1;
24098 + if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR)
24099 + && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) {
24100 + DWC_DEBUGPL(DBG_HCDV, "DMA transfer %d from core_if %p\n",
24101 + hc->hc_num, core_if);//GRAYG
24102 + core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
24103 + core_if->hc_xfer_info[hc->hc_num].hc = hc;
24104 + /* Start a timer for this transfer. */
24105 + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
24112 + * This function continues a data transfer that was started by previous call
24113 + * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
24114 + * sufficient space in the request queue and Tx Data FIFO. This function
24115 + * should only be called in Slave mode. In DMA mode, the controller acts
24116 + * autonomously to complete transfers programmed to a host channel.
24118 + * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
24119 + * if there is any data remaining to be queued. For an IN transfer, another
24120 + * data packet is always requested. For the SETUP phase of a control transfer,
24121 + * this function does nothing.
24123 + * @return 1 if a new request is queued, 0 if no more requests are required
24124 + * for this transfer.
24126 +int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24128 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
24130 + if (hc->do_split) {
24131 + /* SPLITs always queue just once per channel */
24133 + } else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
24134 + /* SETUPs are queued only once since they can't be NAKed. */
24136 + } else if (hc->ep_is_in) {
24138 + * Always queue another request for other IN transfers. If
24139 + * back-to-back INs are issued and NAKs are received for both,
24140 + * the driver may still be processing the first NAK when the
24141 + * second NAK is received. When the interrupt handler clears
24142 + * the NAK interrupt for the first NAK, the second NAK will
24143 + * not be seen. So we can't depend on the NAK interrupt
24144 + * handler to requeue a NAKed request. Instead, IN requests
24145 + * are issued each time this function is called. When the
24146 + * transfer completes, the extra requests for the channel will
24149 + hcchar_data_t hcchar;
24150 + dwc_otg_hc_regs_t *hc_regs =
24151 + core_if->host_if->hc_regs[hc->hc_num];
24153 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24154 + hc_set_even_odd_frame(core_if, hc, &hcchar);
24155 + hcchar.b.chen = 1;
24156 + hcchar.b.chdis = 0;
24157 + DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n",
24159 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24163 + /* OUT transfers. */
24164 + if (hc->xfer_count < hc->xfer_len) {
24165 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
24166 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
24167 + hcchar_data_t hcchar;
24168 + dwc_otg_hc_regs_t *hc_regs;
24169 + hc_regs = core_if->host_if->hc_regs[hc->hc_num];
24170 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24171 + hc_set_even_odd_frame(core_if, hc, &hcchar);
24174 + /* Load OUT packet into the appropriate Tx FIFO. */
24175 + dwc_otg_hc_write_packet(core_if, hc);
24185 + * Starts a PING transfer. This function should only be called in Slave mode.
24186 + * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
24188 +void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24190 + hcchar_data_t hcchar;
24191 + hctsiz_data_t hctsiz;
24192 + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
24194 + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
24197 + hctsiz.b.dopng = 1;
24198 + hctsiz.b.pktcnt = 1;
24199 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
24201 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
24202 + hcchar.b.chen = 1;
24203 + hcchar.b.chdis = 0;
24204 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
24208 + * This function writes a packet into the Tx FIFO associated with the Host
24209 + * Channel. For a channel associated with a non-periodic EP, the non-periodic
24210 + * Tx FIFO is written. For a channel associated with a periodic EP, the
24211 + * periodic Tx FIFO is written. This function should only be called in Slave
24214 + * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
24215 + * then number of bytes written to the Tx FIFO.
24217 +void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
24220 + uint32_t remaining_count;
24221 + uint32_t byte_count;
24222 + uint32_t dword_count;
24224 + uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
24225 + uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
24227 + remaining_count = hc->xfer_len - hc->xfer_count;
24228 + if (remaining_count > hc->max_packet) {
24229 + byte_count = hc->max_packet;
24231 + byte_count = remaining_count;
24234 + dword_count = (byte_count + 3) / 4;
24236 + if ((((unsigned long)data_buff) & 0x3) == 0) {
24237 + /* xfer_buff is DWORD aligned. */
24238 + for (i = 0; i < dword_count; i++, data_buff++) {
24239 + DWC_WRITE_REG32(data_fifo, *data_buff);
24242 + /* xfer_buff is not DWORD aligned. */
24243 + for (i = 0; i < dword_count; i++, data_buff++) {
24246 + (data_buff[0] | data_buff[1] << 8 | data_buff[2] <<
24247 + 16 | data_buff[3] << 24);
24248 + DWC_WRITE_REG32(data_fifo, data);
24252 + hc->xfer_count += byte_count;
24253 + hc->xfer_buff += byte_count;
24257 + * Gets the current USB frame number. This is the frame number from the last
24260 +uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if)
24262 + dsts_data_t dsts;
24263 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
24265 + /* read current frame/microframe number from DSTS register */
24266 + return dsts.b.soffn;
24270 + * Calculates and gets the frame Interval value of HFIR register according PHY
24271 + * type and speed.The application can modify a value of HFIR register only after
24272 + * the Port Enable bit of the Host Port Control and Status register
24273 + * (HPRT.PrtEnaPort) has been set.
24276 +uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if)
24278 + gusbcfg_data_t usbcfg;
24279 + hwcfg2_data_t hwcfg2;
24280 + hprt0_data_t hprt0;
24281 + int clock = 60; // default value
24282 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
24283 + hwcfg2.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
24284 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
24285 + if (!usbcfg.b.physel && usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
24287 + if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 3)
24289 + if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24290 + !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
24292 + if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24293 + !usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
24295 + if (usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
24296 + !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
24298 + if (usbcfg.b.physel && !usbcfg.b.phyif && hwcfg2.b.fs_phy_type == 2)
24300 + if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 1)
24302 + if (hprt0.b.prtspd == 0)
24303 + /* High speed case */
24304 + return 125 * clock;
24307 + return 1000 * clock;
24311 + * This function reads a setup packet from the Rx FIFO into the destination
24312 + * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl)
24313 + * Interrupt routine when a SETUP packet has been received in Slave mode.
24315 + * @param core_if Programming view of DWC_otg controller.
24316 + * @param dest Destination buffer for packet data.
24318 +void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest)
24320 + device_grxsts_data_t status;
24321 + /* Get the 8 bytes of a setup transaction data */
24323 + /* Pop 2 DWORDS off the receive data FIFO into memory */
24324 + dest[0] = DWC_READ_REG32(core_if->data_fifo[0]);
24325 + dest[1] = DWC_READ_REG32(core_if->data_fifo[0]);
24326 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
24328 + DWC_READ_REG32(&core_if->core_global_regs->grxstsp);
24329 + DWC_DEBUGPL(DBG_ANY,
24330 + "EP:%d BCnt:%d " "pktsts:%x Frame:%d(0x%0x)\n",
24331 + status.b.epnum, status.b.bcnt, status.b.pktsts,
24332 + status.b.fn, status.b.fn);
24337 + * This function enables EP0 OUT to receive SETUP packets and configures EP0
24338 + * IN for transmitting packets. It is normally called when the
24339 + * "Enumeration Done" interrupt occurs.
24341 + * @param core_if Programming view of DWC_otg controller.
24342 + * @param ep The EP0 data.
24344 +void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24346 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24347 + dsts_data_t dsts;
24348 + depctl_data_t diepctl;
24349 + depctl_data_t doepctl;
24350 + dctl_data_t dctl = {.d32 = 0 };
24352 + ep->stp_rollover = 0;
24353 + /* Read the Device Status and Endpoint 0 Control registers */
24354 + dsts.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dsts);
24355 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
24356 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
24358 + /* Set the MPS of the IN EP based on the enumeration speed */
24359 + switch (dsts.b.enumspd) {
24360 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
24361 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
24362 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
24363 + diepctl.b.mps = DWC_DEP0CTL_MPS_64;
24365 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
24366 + diepctl.b.mps = DWC_DEP0CTL_MPS_8;
24370 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
24372 + /* Enable OUT EP for receive */
24373 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
24374 + doepctl.b.epena = 1;
24375 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
24378 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
24379 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
24380 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
24381 + DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
24383 + dctl.b.cgnpinnak = 1;
24385 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
24386 + DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
24387 + DWC_READ_REG32(&dev_if->dev_global_regs->dctl));
24392 + * This function activates an EP. The Device EP control register for
24393 + * the EP is configured as defined in the ep structure. Note: This
24394 + * function is not used for EP0.
24396 + * @param core_if Programming view of DWC_otg controller.
24397 + * @param ep The EP to activate.
24399 +void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24401 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24402 + depctl_data_t depctl;
24403 + volatile uint32_t *addr;
24404 + daint_data_t daintmsk = {.d32 = 0 };
24405 + dcfg_data_t dcfg;
24408 + DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
24409 + (ep->is_in ? "IN" : "OUT"));
24411 +#ifdef DWC_UTE_PER_IO
24412 + ep->xiso_frame_num = 0xFFFFFFFF;
24413 + ep->xiso_active_xfers = 0;
24414 + ep->xiso_queued_xfers = 0;
24416 + /* Read DEPCTLn register */
24417 + if (ep->is_in == 1) {
24418 + addr = &dev_if->in_ep_regs[ep->num]->diepctl;
24419 + daintmsk.ep.in = 1 << ep->num;
24421 + addr = &dev_if->out_ep_regs[ep->num]->doepctl;
24422 + daintmsk.ep.out = 1 << ep->num;
24425 + /* If the EP is already active don't change the EP Control
24427 + depctl.d32 = DWC_READ_REG32(addr);
24428 + if (!depctl.b.usbactep) {
24429 + depctl.b.mps = ep->maxpacket;
24430 + depctl.b.eptype = ep->type;
24431 + depctl.b.txfnum = ep->tx_fifo_num;
24433 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24434 + depctl.b.setd0pid = 1; // ???
24436 + depctl.b.setd0pid = 1;
24438 + depctl.b.usbactep = 1;
24440 + /* Update nextep_seq array and EPMSCNT in DCFG*/
24441 + if (!(depctl.b.eptype & 1) && (ep->is_in == 1)) { // NP IN EP
24442 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
24443 + if (core_if->nextep_seq[i] == core_if->first_in_nextep_seq)
24446 + core_if->nextep_seq[i] = ep->num;
24447 + core_if->nextep_seq[ep->num] = core_if->first_in_nextep_seq;
24448 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24449 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
24450 + dcfg.b.epmscnt++;
24451 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
24453 + DWC_DEBUGPL(DBG_PCDV,
24454 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
24455 + __func__, core_if->first_in_nextep_seq);
24456 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
24457 + DWC_DEBUGPL(DBG_PCDV, "%2d\n",
24458 + core_if->nextep_seq[i]);
24464 + DWC_WRITE_REG32(addr, depctl.d32);
24465 + DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", DWC_READ_REG32(addr));
24468 + /* Enable the Interrupt for this EP */
24469 + if (core_if->multiproc_int_enable) {
24470 + if (ep->is_in == 1) {
24471 + diepmsk_data_t diepmsk = {.d32 = 0 };
24472 + diepmsk.b.xfercompl = 1;
24473 + diepmsk.b.timeout = 1;
24474 + diepmsk.b.epdisabled = 1;
24475 + diepmsk.b.ahberr = 1;
24476 + diepmsk.b.intknepmis = 1;
24477 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
24478 + diepmsk.b.intknepmis = 0;
24479 + diepmsk.b.txfifoundrn = 1; //?????
24480 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24481 + diepmsk.b.nak = 1;
24487 + if (core_if->dma_desc_enable) {
24488 + diepmsk.b.bna = 1;
24492 + if (core_if->dma_enable) {
24493 + doepmsk.b.nak = 1;
24496 + DWC_WRITE_REG32(&dev_if->dev_global_regs->
24497 + diepeachintmsk[ep->num], diepmsk.d32);
24500 + doepmsk_data_t doepmsk = {.d32 = 0 };
24501 + doepmsk.b.xfercompl = 1;
24502 + doepmsk.b.ahberr = 1;
24503 + doepmsk.b.epdisabled = 1;
24504 + if (ep->type == DWC_OTG_EP_TYPE_ISOC)
24505 + doepmsk.b.outtknepdis = 1;
24509 + if (core_if->dma_desc_enable) {
24510 + doepmsk.b.bna = 1;
24514 + doepmsk.b.babble = 1;
24515 + doepmsk.b.nyet = 1;
24516 + doepmsk.b.nak = 1;
24518 + DWC_WRITE_REG32(&dev_if->dev_global_regs->
24519 + doepeachintmsk[ep->num], doepmsk.d32);
24521 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->deachintmsk,
24522 + 0, daintmsk.d32);
24524 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24526 + diepmsk_data_t diepmsk = {.d32 = 0 };
24527 + diepmsk.b.nak = 1;
24528 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32);
24530 + doepmsk_data_t doepmsk = {.d32 = 0 };
24531 + doepmsk.b.outtknepdis = 1;
24532 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->doepmsk, 0, doepmsk.d32);
24535 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->daintmsk,
24536 + 0, daintmsk.d32);
24539 + DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
24540 + DWC_READ_REG32(&dev_if->dev_global_regs->daintmsk));
24542 + ep->stall_clear_flag = 0;
24548 + * This function deactivates an EP. This is done by clearing the USB Active
24549 + * EP bit in the Device EP control register. Note: This function is not used
24550 + * for EP0. EP0 cannot be deactivated.
24552 + * @param core_if Programming view of DWC_otg controller.
24553 + * @param ep The EP to deactivate.
24555 +void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24557 + depctl_data_t depctl = {.d32 = 0 };
24558 + volatile uint32_t *addr;
24559 + daint_data_t daintmsk = {.d32 = 0 };
24560 + dcfg_data_t dcfg;
24563 +#ifdef DWC_UTE_PER_IO
24564 + ep->xiso_frame_num = 0xFFFFFFFF;
24565 + ep->xiso_active_xfers = 0;
24566 + ep->xiso_queued_xfers = 0;
24569 + /* Read DEPCTLn register */
24570 + if (ep->is_in == 1) {
24571 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
24572 + daintmsk.ep.in = 1 << ep->num;
24574 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
24575 + daintmsk.ep.out = 1 << ep->num;
24578 + depctl.d32 = DWC_READ_REG32(addr);
24580 + depctl.b.usbactep = 0;
24582 + /* Update nextep_seq array and EPMSCNT in DCFG*/
24583 + if (!(depctl.b.eptype & 1) && ep->is_in == 1) { // NP EP IN
24584 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
24585 + if (core_if->nextep_seq[i] == ep->num)
24588 + core_if->nextep_seq[i] = core_if->nextep_seq[ep->num];
24589 + if (core_if->first_in_nextep_seq == ep->num)
24590 + core_if->first_in_nextep_seq = i;
24591 + core_if->nextep_seq[ep->num] = 0xff;
24592 + depctl.b.nextep = 0;
24594 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
24595 + dcfg.b.epmscnt--;
24596 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
24599 + DWC_DEBUGPL(DBG_PCDV,
24600 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
24601 + __func__, core_if->first_in_nextep_seq);
24602 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
24603 + DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
24607 + if (ep->is_in == 1)
24608 + depctl.b.txfnum = 0;
24610 + if (core_if->dma_desc_enable)
24611 + depctl.b.epdis = 1;
24613 + DWC_WRITE_REG32(addr, depctl.d32);
24614 + depctl.d32 = DWC_READ_REG32(addr);
24615 + if (core_if->dma_enable && ep->type == DWC_OTG_EP_TYPE_ISOC
24616 + && depctl.b.epena) {
24617 + depctl_data_t depctl = {.d32 = 0};
24619 + diepint_data_t diepint = {.d32 = 0};
24621 + depctl.b.snak = 1;
24622 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24623 + diepctl, depctl.d32);
24627 + DWC_READ_REG32(&core_if->
24628 + dev_if->in_ep_regs[ep->num]->
24630 + } while (!diepint.b.inepnakeff);
24631 + diepint.b.inepnakeff = 1;
24632 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24633 + diepint, diepint.d32);
24635 + depctl.b.epdis = 1;
24636 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24637 + diepctl, depctl.d32);
24641 + DWC_READ_REG32(&core_if->
24642 + dev_if->in_ep_regs[ep->num]->
24644 + } while (!diepint.b.epdisabled);
24645 + diepint.b.epdisabled = 1;
24646 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
24647 + diepint, diepint.d32);
24649 + dctl_data_t dctl = {.d32 = 0};
24650 + gintmsk_data_t gintsts = {.d32 = 0};
24651 + doepint_data_t doepint = {.d32 = 0};
24652 + dctl.b.sgoutnak = 1;
24653 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
24654 + dctl, 0, dctl.d32);
24657 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
24658 + } while (!gintsts.b.goutnakeff);
24660 + gintsts.b.goutnakeff = 1;
24661 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
24664 + depctl.b.epdis = 1;
24665 + depctl.b.snak = 1;
24666 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepctl, depctl.d32);
24670 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
24671 + out_ep_regs[ep->num]->doepint);
24672 + } while (!doepint.b.epdisabled);
24674 + doepint.b.epdisabled = 1;
24675 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepint, doepint.d32);
24678 + dctl.b.cgoutnak = 1;
24679 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
24683 + /* Disable the Interrupt for this EP */
24684 + if (core_if->multiproc_int_enable) {
24685 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
24686 + daintmsk.d32, 0);
24688 + if (ep->is_in == 1) {
24689 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
24690 + diepeachintmsk[ep->num], 0);
24692 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
24693 + doepeachintmsk[ep->num], 0);
24696 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->daintmsk,
24697 + daintmsk.d32, 0);
24703 + * This function initializes dma descriptor chain.
24705 + * @param core_if Programming view of DWC_otg controller.
24706 + * @param ep The EP to start the transfer on.
24708 +static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24710 + dwc_otg_dev_dma_desc_t *dma_desc;
24712 + uint32_t xfer_est;
24714 + unsigned maxxfer_local, total_len;
24716 + if (!ep->is_in && ep->type == DWC_OTG_EP_TYPE_INTR &&
24717 + (ep->maxpacket%4)) {
24718 + maxxfer_local = ep->maxpacket;
24719 + total_len = ep->xfer_len;
24721 + maxxfer_local = ep->maxxfer;
24722 + total_len = ep->total_len;
24725 + ep->desc_cnt = (total_len / maxxfer_local) +
24726 + ((total_len % maxxfer_local) ? 1 : 0);
24728 + if (!ep->desc_cnt)
24729 + ep->desc_cnt = 1;
24731 + if (ep->desc_cnt > MAX_DMA_DESC_CNT)
24732 + ep->desc_cnt = MAX_DMA_DESC_CNT;
24734 + dma_desc = ep->desc_addr;
24735 + if (maxxfer_local == ep->maxpacket) {
24736 + if ((total_len % maxxfer_local) &&
24737 + (total_len/maxxfer_local < MAX_DMA_DESC_CNT)) {
24738 + xfer_est = (ep->desc_cnt - 1) * maxxfer_local +
24739 + (total_len % maxxfer_local);
24741 + xfer_est = ep->desc_cnt * maxxfer_local;
24743 + xfer_est = total_len;
24745 + for (i = 0; i < ep->desc_cnt; ++i) {
24746 + /** DMA Descriptor Setup */
24747 + if (xfer_est > maxxfer_local) {
24748 + dma_desc->status.b.bs = BS_HOST_BUSY;
24749 + dma_desc->status.b.l = 0;
24750 + dma_desc->status.b.ioc = 0;
24751 + dma_desc->status.b.sp = 0;
24752 + dma_desc->status.b.bytes = maxxfer_local;
24753 + dma_desc->buf = ep->dma_addr + offset;
24754 + dma_desc->status.b.sts = 0;
24755 + dma_desc->status.b.bs = BS_HOST_READY;
24757 + xfer_est -= maxxfer_local;
24758 + offset += maxxfer_local;
24760 + dma_desc->status.b.bs = BS_HOST_BUSY;
24761 + dma_desc->status.b.l = 1;
24762 + dma_desc->status.b.ioc = 1;
24764 + dma_desc->status.b.sp =
24766 + ep->maxpacket) ? 1 : ((ep->
24767 + sent_zlp) ? 1 : 0);
24768 + dma_desc->status.b.bytes = xfer_est;
24770 + if (maxxfer_local == ep->maxpacket)
24771 + dma_desc->status.b.bytes = xfer_est;
24773 + dma_desc->status.b.bytes =
24774 + xfer_est + ((4 - (xfer_est & 0x3)) & 0x3);
24777 + dma_desc->buf = ep->dma_addr + offset;
24778 + dma_desc->status.b.sts = 0;
24779 + dma_desc->status.b.bs = BS_HOST_READY;
24785 + * This function is called when to write ISOC data into appropriate dedicated
24788 +static int32_t write_isoc_tx_fifo(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
24790 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
24791 + dwc_otg_dev_in_ep_regs_t *ep_regs;
24792 + dtxfsts_data_t txstatus = {.d32 = 0 };
24793 + uint32_t len = 0;
24794 + int epnum = dwc_ep->num;
24797 + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
24799 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
24801 + len = dwc_ep->xfer_len - dwc_ep->xfer_count;
24803 + if (len > dwc_ep->maxpacket) {
24804 + len = dwc_ep->maxpacket;
24807 + dwords = (len + 3) / 4;
24809 + /* While there is space in the queue and space in the FIFO and
24810 + * More data to tranfer, Write packets to the Tx FIFO */
24811 + txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
24812 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
24814 + while (txstatus.b.txfspcavail > dwords &&
24815 + dwc_ep->xfer_count < dwc_ep->xfer_len && dwc_ep->xfer_len != 0) {
24816 + /* Write the FIFO */
24817 + dwc_otg_ep_write_packet(core_if, dwc_ep, 0);
24819 + len = dwc_ep->xfer_len - dwc_ep->xfer_count;
24820 + if (len > dwc_ep->maxpacket) {
24821 + len = dwc_ep->maxpacket;
24824 + dwords = (len + 3) / 4;
24826 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
24827 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
24831 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
24832 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
24837 + * This function does the setup for a data transfer for an EP and
24838 + * starts the transfer. For an IN transfer, the packets will be
24839 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
24840 + * the packets are unloaded from the Rx FIFO in the ISR. the ISR.
24842 + * @param core_if Programming view of DWC_otg controller.
24843 + * @param ep The EP to start the transfer on.
24846 +void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
24848 + depctl_data_t depctl;
24849 + deptsiz_data_t deptsiz;
24850 + gintmsk_data_t intr_mask = {.d32 = 0 };
24852 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
24853 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
24854 + "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n",
24855 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
24856 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
24858 + /* IN endpoint */
24859 + if (ep->is_in == 1) {
24860 + dwc_otg_dev_in_ep_regs_t *in_regs =
24861 + core_if->dev_if->in_ep_regs[ep->num];
24863 + gnptxsts_data_t gtxstatus;
24866 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
24868 + if (core_if->en_multiple_tx_fifo == 0
24869 + && gtxstatus.b.nptxqspcavail == 0 && !core_if->dma_enable) {
24871 + DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32);
24876 + depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
24877 + deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
24879 + if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
24880 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
24881 + ep->maxxfer : (ep->total_len - ep->xfer_len);
24883 + ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len - ep->xfer_len)) ?
24884 + MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
24887 + /* Zero Length Packet? */
24888 + if ((ep->xfer_len - ep->xfer_count) == 0) {
24889 + deptsiz.b.xfersize = 0;
24890 + deptsiz.b.pktcnt = 1;
24892 + /* Program the transfer size and packet count
24893 + * as follows: xfersize = N * maxpacket +
24894 + * short_packet pktcnt = N + (short_packet
24897 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
24898 + deptsiz.b.pktcnt =
24899 + (ep->xfer_len - ep->xfer_count - 1 +
24900 + ep->maxpacket) / ep->maxpacket;
24901 + if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
24902 + deptsiz.b.pktcnt = MAX_PKT_CNT;
24903 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
24905 + if (ep->type == DWC_OTG_EP_TYPE_ISOC)
24906 + deptsiz.b.mc = deptsiz.b.pktcnt;
24909 + /* Write the DMA register */
24910 + if (core_if->dma_enable) {
24911 + if (core_if->dma_desc_enable == 0) {
24912 + if (ep->type != DWC_OTG_EP_TYPE_ISOC)
24913 + deptsiz.b.mc = 1;
24914 + DWC_WRITE_REG32(&in_regs->dieptsiz,
24916 + DWC_WRITE_REG32(&(in_regs->diepdma),
24917 + (uint32_t) ep->dma_addr);
24919 +#ifdef DWC_UTE_CFI
24920 + /* The descriptor chain should be already initialized by now */
24921 + if (ep->buff_mode != BM_STANDARD) {
24922 + DWC_WRITE_REG32(&in_regs->diepdma,
24923 + ep->descs_dma_addr);
24926 + init_dma_desc_chain(core_if, ep);
24927 + /** DIEPDMAn Register write */
24928 + DWC_WRITE_REG32(&in_regs->diepdma,
24929 + ep->dma_desc_addr);
24930 +#ifdef DWC_UTE_CFI
24935 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
24936 + if (ep->type != DWC_OTG_EP_TYPE_ISOC) {
24938 + * Enable the Non-Periodic Tx FIFO empty interrupt,
24939 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
24940 + * the data will be written into the fifo by the ISR.
24942 + if (core_if->en_multiple_tx_fifo == 0) {
24943 + intr_mask.b.nptxfempty = 1;
24945 + (&core_if->core_global_regs->gintmsk,
24946 + intr_mask.d32, intr_mask.d32);
24948 + /* Enable the Tx FIFO Empty Interrupt for this EP */
24949 + if (ep->xfer_len > 0) {
24950 + uint32_t fifoemptymsk = 0;
24951 + fifoemptymsk = 1 << ep->num;
24953 + (&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
24954 + 0, fifoemptymsk);
24959 + write_isoc_tx_fifo(core_if, ep);
24962 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
24963 + depctl.b.nextep = core_if->nextep_seq[ep->num];
24965 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
24966 + dsts_data_t dsts = {.d32 = 0};
24967 + if (ep->bInterval == 1) {
24969 + DWC_READ_REG32(&core_if->dev_if->
24970 + dev_global_regs->dsts);
24971 + ep->frame_num = dsts.b.soffn + ep->bInterval;
24972 + if (ep->frame_num > 0x3FFF) {
24973 + ep->frm_overrun = 1;
24974 + ep->frame_num &= 0x3FFF;
24976 + ep->frm_overrun = 0;
24977 + if (ep->frame_num & 0x1) {
24978 + depctl.b.setd1pid = 1;
24980 + depctl.b.setd0pid = 1;
24984 + /* EP enable, IN data in FIFO */
24985 + depctl.b.cnak = 1;
24986 + depctl.b.epena = 1;
24987 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
24990 + /* OUT endpoint */
24991 + dwc_otg_dev_out_ep_regs_t *out_regs =
24992 + core_if->dev_if->out_ep_regs[ep->num];
24994 + depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
24995 + deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
24997 + if (!core_if->dma_desc_enable) {
24998 + if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
24999 + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
25000 + ep->maxxfer : (ep->total_len - ep->xfer_len);
25002 + ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len
25003 + - ep->xfer_len)) ? MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
25006 + /* Program the transfer size and packet count as follows:
25009 + * xfersize = N * maxpacket
25011 + if ((ep->xfer_len - ep->xfer_count) == 0) {
25012 + /* Zero Length Packet */
25013 + deptsiz.b.xfersize = ep->maxpacket;
25014 + deptsiz.b.pktcnt = 1;
25016 + deptsiz.b.pktcnt =
25017 + (ep->xfer_len - ep->xfer_count +
25018 + (ep->maxpacket - 1)) / ep->maxpacket;
25019 + if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
25020 + deptsiz.b.pktcnt = MAX_PKT_CNT;
25022 + if (!core_if->dma_desc_enable) {
25024 + deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count;
25026 + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
25029 + DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
25030 + ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
25032 + if (core_if->dma_enable) {
25033 + if (!core_if->dma_desc_enable) {
25034 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25037 + DWC_WRITE_REG32(&(out_regs->doepdma),
25038 + (uint32_t) ep->dma_addr);
25040 +#ifdef DWC_UTE_CFI
25041 + /* The descriptor chain should be already initialized by now */
25042 + if (ep->buff_mode != BM_STANDARD) {
25043 + DWC_WRITE_REG32(&out_regs->doepdma,
25044 + ep->descs_dma_addr);
25047 + /** This is used for interrupt out transfers*/
25048 + if (!ep->xfer_len)
25049 + ep->xfer_len = ep->total_len;
25050 + init_dma_desc_chain(core_if, ep);
25052 + if (core_if->core_params->dev_out_nak) {
25053 + if (ep->type == DWC_OTG_EP_TYPE_BULK) {
25054 + deptsiz.b.pktcnt = (ep->total_len +
25055 + (ep->maxpacket - 1)) / ep->maxpacket;
25056 + deptsiz.b.xfersize = ep->total_len;
25057 + /* Remember initial value of doeptsiz */
25058 + core_if->start_doeptsiz_val[ep->num] = deptsiz.d32;
25059 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25063 + /** DOEPDMAn Register write */
25064 + DWC_WRITE_REG32(&out_regs->doepdma,
25065 + ep->dma_desc_addr);
25066 +#ifdef DWC_UTE_CFI
25071 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25074 + if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
25075 + dsts_data_t dsts = {.d32 = 0};
25076 + if (ep->bInterval == 1) {
25078 + DWC_READ_REG32(&core_if->dev_if->
25079 + dev_global_regs->dsts);
25080 + ep->frame_num = dsts.b.soffn + ep->bInterval;
25081 + if (ep->frame_num > 0x3FFF) {
25082 + ep->frm_overrun = 1;
25083 + ep->frame_num &= 0x3FFF;
25085 + ep->frm_overrun = 0;
25087 + if (ep->frame_num & 0x1) {
25088 + depctl.b.setd1pid = 1;
25090 + depctl.b.setd0pid = 1;
25096 + depctl.b.cnak = 1;
25097 + depctl.b.epena = 1;
25099 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
25101 + DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
25102 + DWC_READ_REG32(&out_regs->doepctl),
25103 + DWC_READ_REG32(&out_regs->doeptsiz));
25104 + DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
25105 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
25107 + DWC_READ_REG32(&core_if->core_global_regs->
25110 + /* Timer is scheduling only for out bulk transfers for
25111 + * "Device DDMA OUT NAK Enhancement" feature to inform user
25112 + * about received data payload in case of timeout
25114 + if (core_if->core_params->dev_out_nak) {
25115 + if (ep->type == DWC_OTG_EP_TYPE_BULK) {
25116 + core_if->ep_xfer_info[ep->num].core_if = core_if;
25117 + core_if->ep_xfer_info[ep->num].ep = ep;
25118 + core_if->ep_xfer_info[ep->num].state = 1;
25120 + /* Start a timer for this transfer. */
25121 + DWC_TIMER_SCHEDULE(core_if->ep_xfer_timer[ep->num], 10000);
25128 + * This function setup a zero length transfer in Buffer DMA and
25129 + * Slave modes for usb requests with zero field set
25131 + * @param core_if Programming view of DWC_otg controller.
25132 + * @param ep The EP to start the transfer on.
25135 +void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25138 + depctl_data_t depctl;
25139 + deptsiz_data_t deptsiz;
25140 + gintmsk_data_t intr_mask = {.d32 = 0 };
25142 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
25143 + DWC_PRINTF("zero length transfer is called\n");
25145 + /* IN endpoint */
25146 + if (ep->is_in == 1) {
25147 + dwc_otg_dev_in_ep_regs_t *in_regs =
25148 + core_if->dev_if->in_ep_regs[ep->num];
25150 + depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
25151 + deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
25153 + deptsiz.b.xfersize = 0;
25154 + deptsiz.b.pktcnt = 1;
25156 + /* Write the DMA register */
25157 + if (core_if->dma_enable) {
25158 + if (core_if->dma_desc_enable == 0) {
25159 + deptsiz.b.mc = 1;
25160 + DWC_WRITE_REG32(&in_regs->dieptsiz,
25162 + DWC_WRITE_REG32(&(in_regs->diepdma),
25163 + (uint32_t) ep->dma_addr);
25166 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25168 + * Enable the Non-Periodic Tx FIFO empty interrupt,
25169 + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
25170 + * the data will be written into the fifo by the ISR.
25172 + if (core_if->en_multiple_tx_fifo == 0) {
25173 + intr_mask.b.nptxfempty = 1;
25174 + DWC_MODIFY_REG32(&core_if->
25175 + core_global_regs->gintmsk,
25176 + intr_mask.d32, intr_mask.d32);
25178 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25179 + if (ep->xfer_len > 0) {
25180 + uint32_t fifoemptymsk = 0;
25181 + fifoemptymsk = 1 << ep->num;
25182 + DWC_MODIFY_REG32(&core_if->
25183 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25184 + 0, fifoemptymsk);
25189 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25190 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25191 + /* EP enable, IN data in FIFO */
25192 + depctl.b.cnak = 1;
25193 + depctl.b.epena = 1;
25194 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25197 + /* OUT endpoint */
25198 + dwc_otg_dev_out_ep_regs_t *out_regs =
25199 + core_if->dev_if->out_ep_regs[ep->num];
25201 + depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
25202 + deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
25204 + /* Zero Length Packet */
25205 + deptsiz.b.xfersize = ep->maxpacket;
25206 + deptsiz.b.pktcnt = 1;
25208 + if (core_if->dma_enable) {
25209 + if (!core_if->dma_desc_enable) {
25210 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25213 + DWC_WRITE_REG32(&(out_regs->doepdma),
25214 + (uint32_t) ep->dma_addr);
25217 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25221 + depctl.b.cnak = 1;
25222 + depctl.b.epena = 1;
25224 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
25230 + * This function does the setup for a data transfer for EP0 and starts
25231 + * the transfer. For an IN transfer, the packets will be loaded into
25232 + * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
25233 + * unloaded from the Rx FIFO in the ISR.
25235 + * @param core_if Programming view of DWC_otg controller.
25236 + * @param ep The EP0 data.
25238 +void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25240 + depctl_data_t depctl;
25241 + deptsiz0_data_t deptsiz;
25242 + gintmsk_data_t intr_mask = {.d32 = 0 };
25243 + dwc_otg_dev_dma_desc_t *dma_desc;
25245 + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
25246 + "xfer_buff=%p start_xfer_buff=%p \n",
25247 + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
25248 + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
25250 + ep->total_len = ep->xfer_len;
25252 + /* IN endpoint */
25253 + if (ep->is_in == 1) {
25254 + dwc_otg_dev_in_ep_regs_t *in_regs =
25255 + core_if->dev_if->in_ep_regs[0];
25257 + gnptxsts_data_t gtxstatus;
25259 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
25260 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25261 + if (depctl.b.epena)
25266 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
25268 + /* If dedicated FIFO every time flush fifo before enable ep*/
25269 + if (core_if->en_multiple_tx_fifo && core_if->snpsid >= OTG_CORE_REV_3_00a)
25270 + dwc_otg_flush_tx_fifo(core_if, ep->tx_fifo_num);
25272 + if (core_if->en_multiple_tx_fifo == 0
25273 + && gtxstatus.b.nptxqspcavail == 0
25274 + && !core_if->dma_enable) {
25276 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25277 + DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
25278 + DWC_READ_REG32(&in_regs->diepctl));
25279 + DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
25281 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
25282 + DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n",
25288 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25289 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25291 + /* Zero Length Packet? */
25292 + if (ep->xfer_len == 0) {
25293 + deptsiz.b.xfersize = 0;
25294 + deptsiz.b.pktcnt = 1;
25296 + /* Program the transfer size and packet count
25297 + * as follows: xfersize = N * maxpacket +
25298 + * short_packet pktcnt = N + (short_packet
25301 + if (ep->xfer_len > ep->maxpacket) {
25302 + ep->xfer_len = ep->maxpacket;
25303 + deptsiz.b.xfersize = ep->maxpacket;
25305 + deptsiz.b.xfersize = ep->xfer_len;
25307 + deptsiz.b.pktcnt = 1;
25310 + DWC_DEBUGPL(DBG_PCDV,
25311 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25312 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25315 + /* Write the DMA register */
25316 + if (core_if->dma_enable) {
25317 + if (core_if->dma_desc_enable == 0) {
25318 + DWC_WRITE_REG32(&in_regs->dieptsiz,
25321 + DWC_WRITE_REG32(&(in_regs->diepdma),
25322 + (uint32_t) ep->dma_addr);
25324 + dma_desc = core_if->dev_if->in_desc_addr;
25326 + /** DMA Descriptor Setup */
25327 + dma_desc->status.b.bs = BS_HOST_BUSY;
25328 + dma_desc->status.b.l = 1;
25329 + dma_desc->status.b.ioc = 1;
25330 + dma_desc->status.b.sp =
25331 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
25332 + dma_desc->status.b.bytes = ep->xfer_len;
25333 + dma_desc->buf = ep->dma_addr;
25334 + dma_desc->status.b.sts = 0;
25335 + dma_desc->status.b.bs = BS_HOST_READY;
25337 + /** DIEPDMA0 Register write */
25338 + DWC_WRITE_REG32(&in_regs->diepdma,
25340 + dev_if->dma_in_desc_addr);
25343 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25346 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25347 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25348 + /* EP enable, IN data in FIFO */
25349 + depctl.b.cnak = 1;
25350 + depctl.b.epena = 1;
25351 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25354 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
25355 + * data will be written into the fifo by the ISR.
25357 + if (!core_if->dma_enable) {
25358 + if (core_if->en_multiple_tx_fifo == 0) {
25359 + intr_mask.b.nptxfempty = 1;
25360 + DWC_MODIFY_REG32(&core_if->
25361 + core_global_regs->gintmsk,
25362 + intr_mask.d32, intr_mask.d32);
25364 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25365 + if (ep->xfer_len > 0) {
25366 + uint32_t fifoemptymsk = 0;
25367 + fifoemptymsk |= 1 << ep->num;
25368 + DWC_MODIFY_REG32(&core_if->
25369 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25370 + 0, fifoemptymsk);
25375 + /* OUT endpoint */
25376 + dwc_otg_dev_out_ep_regs_t *out_regs =
25377 + core_if->dev_if->out_ep_regs[0];
25379 + depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
25380 + deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
25382 + /* Program the transfer size and packet count as follows:
25383 + * xfersize = N * (maxpacket + 4 - (maxpacket % 4))
25385 + /* Zero Length Packet */
25386 + deptsiz.b.xfersize = ep->maxpacket;
25387 + deptsiz.b.pktcnt = 1;
25388 + if (core_if->snpsid >= OTG_CORE_REV_3_00a)
25389 + deptsiz.b.supcnt = 3;
25391 + DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n",
25392 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);
25394 + if (core_if->dma_enable) {
25395 + if (!core_if->dma_desc_enable) {
25396 + DWC_WRITE_REG32(&out_regs->doeptsiz,
25399 + DWC_WRITE_REG32(&(out_regs->doepdma),
25400 + (uint32_t) ep->dma_addr);
25402 + dma_desc = core_if->dev_if->out_desc_addr;
25404 + /** DMA Descriptor Setup */
25405 + dma_desc->status.b.bs = BS_HOST_BUSY;
25406 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
25407 + dma_desc->status.b.mtrf = 0;
25408 + dma_desc->status.b.sr = 0;
25410 + dma_desc->status.b.l = 1;
25411 + dma_desc->status.b.ioc = 1;
25412 + dma_desc->status.b.bytes = ep->maxpacket;
25413 + dma_desc->buf = ep->dma_addr;
25414 + dma_desc->status.b.sts = 0;
25415 + dma_desc->status.b.bs = BS_HOST_READY;
25417 + /** DOEPDMA0 Register write */
25418 + DWC_WRITE_REG32(&out_regs->doepdma,
25419 + core_if->dev_if->
25420 + dma_out_desc_addr);
25423 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25427 + depctl.b.cnak = 1;
25428 + depctl.b.epena = 1;
25429 + DWC_WRITE_REG32(&(out_regs->doepctl), depctl.d32);
25434 + * This function continues control IN transfers started by
25435 + * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
25436 + * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
25437 + * bit for the packet count.
25439 + * @param core_if Programming view of DWC_otg controller.
25440 + * @param ep The EP0 data.
25442 +void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25444 + depctl_data_t depctl;
25445 + deptsiz0_data_t deptsiz;
25446 + gintmsk_data_t intr_mask = {.d32 = 0 };
25447 + dwc_otg_dev_dma_desc_t *dma_desc;
25449 + if (ep->is_in == 1) {
25450 + dwc_otg_dev_in_ep_regs_t *in_regs =
25451 + core_if->dev_if->in_ep_regs[0];
25452 + gnptxsts_data_t tx_status = {.d32 = 0 };
25455 + DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
25456 + /** @todo Should there be check for room in the Tx
25457 + * Status Queue. If not remove the code above this comment. */
25459 + depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
25460 + deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
25462 + /* Program the transfer size and packet count
25463 + * as follows: xfersize = N * maxpacket +
25464 + * short_packet pktcnt = N + (short_packet
25468 + if (core_if->dma_desc_enable == 0) {
25469 + deptsiz.b.xfersize =
25470 + (ep->total_len - ep->xfer_count) >
25471 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
25473 + deptsiz.b.pktcnt = 1;
25474 + if (core_if->dma_enable == 0) {
25475 + ep->xfer_len += deptsiz.b.xfersize;
25477 + ep->xfer_len = deptsiz.b.xfersize;
25479 + DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
25482 + (ep->total_len - ep->xfer_count) >
25483 + ep->maxpacket ? ep->maxpacket : (ep->total_len -
25486 + dma_desc = core_if->dev_if->in_desc_addr;
25488 + /** DMA Descriptor Setup */
25489 + dma_desc->status.b.bs = BS_HOST_BUSY;
25490 + dma_desc->status.b.l = 1;
25491 + dma_desc->status.b.ioc = 1;
25492 + dma_desc->status.b.sp =
25493 + (ep->xfer_len == ep->maxpacket) ? 0 : 1;
25494 + dma_desc->status.b.bytes = ep->xfer_len;
25495 + dma_desc->buf = ep->dma_addr;
25496 + dma_desc->status.b.sts = 0;
25497 + dma_desc->status.b.bs = BS_HOST_READY;
25499 + /** DIEPDMA0 Register write */
25500 + DWC_WRITE_REG32(&in_regs->diepdma,
25501 + core_if->dev_if->dma_in_desc_addr);
25504 + DWC_DEBUGPL(DBG_PCDV,
25505 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25506 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25509 + /* Write the DMA register */
25510 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
25511 + if (core_if->dma_desc_enable == 0)
25512 + DWC_WRITE_REG32(&(in_regs->diepdma),
25513 + (uint32_t) ep->dma_addr);
25515 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
25516 + depctl.b.nextep = core_if->nextep_seq[ep->num];
25517 + /* EP enable, IN data in FIFO */
25518 + depctl.b.cnak = 1;
25519 + depctl.b.epena = 1;
25520 + DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
25523 + * Enable the Non-Periodic Tx FIFO empty interrupt, the
25524 + * data will be written into the fifo by the ISR.
25526 + if (!core_if->dma_enable) {
25527 + if (core_if->en_multiple_tx_fifo == 0) {
25528 + /* First clear it from GINTSTS */
25529 + intr_mask.b.nptxfempty = 1;
25530 + DWC_MODIFY_REG32(&core_if->
25531 + core_global_regs->gintmsk,
25532 + intr_mask.d32, intr_mask.d32);
25535 + /* Enable the Tx FIFO Empty Interrupt for this EP */
25536 + if (ep->xfer_len > 0) {
25537 + uint32_t fifoemptymsk = 0;
25538 + fifoemptymsk |= 1 << ep->num;
25539 + DWC_MODIFY_REG32(&core_if->
25540 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
25541 + 0, fifoemptymsk);
25546 + dwc_otg_dev_out_ep_regs_t *out_regs =
25547 + core_if->dev_if->out_ep_regs[0];
25549 + depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
25550 + deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
25552 + /* Program the transfer size and packet count
25553 + * as follows: xfersize = N * maxpacket +
25554 + * short_packet pktcnt = N + (short_packet
25557 + deptsiz.b.xfersize = ep->maxpacket;
25558 + deptsiz.b.pktcnt = 1;
25560 + if (core_if->dma_desc_enable == 0) {
25561 + DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
25563 + dma_desc = core_if->dev_if->out_desc_addr;
25565 + /** DMA Descriptor Setup */
25566 + dma_desc->status.b.bs = BS_HOST_BUSY;
25567 + dma_desc->status.b.l = 1;
25568 + dma_desc->status.b.ioc = 1;
25569 + dma_desc->status.b.bytes = ep->maxpacket;
25570 + dma_desc->buf = ep->dma_addr;
25571 + dma_desc->status.b.sts = 0;
25572 + dma_desc->status.b.bs = BS_HOST_READY;
25574 + /** DOEPDMA0 Register write */
25575 + DWC_WRITE_REG32(&out_regs->doepdma,
25576 + core_if->dev_if->dma_out_desc_addr);
25579 + DWC_DEBUGPL(DBG_PCDV,
25580 + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
25581 + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
25584 + /* Write the DMA register */
25585 + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
25586 + if (core_if->dma_desc_enable == 0)
25587 + DWC_WRITE_REG32(&(out_regs->doepdma),
25588 + (uint32_t) ep->dma_addr);
25592 + /* EP enable, IN data in FIFO */
25593 + depctl.b.cnak = 1;
25594 + depctl.b.epena = 1;
25595 + DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
25601 +void dump_msg(const u8 * buf, unsigned int length)
25603 + unsigned int start, num, i;
25604 + char line[52], *p;
25606 + if (length >= 512)
25609 + while (length > 0) {
25610 + num = length < 16u ? length : 16u;
25612 + for (i = 0; i < num; ++i) {
25615 + DWC_SPRINTF(p, " %02x", buf[i]);
25619 + DWC_PRINTF("%6x: %s\n", start, line);
25626 +static inline void dump_msg(const u8 * buf, unsigned int length)
25632 + * This function writes a packet into the Tx FIFO associated with the
25633 + * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For
25634 + * periodic EPs the periodic Tx FIFO associated with the EP is written
25635 + * with all packets for the next micro-frame.
25637 + * @param core_if Programming view of DWC_otg controller.
25638 + * @param ep The EP to write packet for.
25639 + * @param dma Indicates if DMA is being used.
25641 +void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep,
25645 + * The buffer is padded to DWORD on a per packet basis in
25646 + * slave/dma mode if the MPS is not DWORD aligned. The last
25647 + * packet, if short, is also padded to a multiple of DWORD.
25649 + * ep->xfer_buff always starts DWORD aligned in memory and is a
25650 + * multiple of DWORD in length
25652 + * ep->xfer_len can be any number of bytes
25654 + * ep->xfer_count is a multiple of ep->maxpacket until the last
25657 + * FIFO access is DWORD */
25660 + uint32_t byte_count;
25661 + uint32_t dword_count;
25663 + uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
25665 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if,
25667 + if (ep->xfer_count >= ep->xfer_len) {
25668 + DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
25672 + /* Find the byte length of the packet either short packet or MPS */
25673 + if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) {
25674 + byte_count = ep->xfer_len - ep->xfer_count;
25676 + byte_count = ep->maxpacket;
25679 + /* Find the DWORD length, padded by extra bytes as neccessary if MPS
25680 + * is not a multiple of DWORD */
25681 + dword_count = (byte_count + 3) / 4;
25684 + dump_msg(ep->xfer_buff, byte_count);
25687 + /**@todo NGS Where are the Periodic Tx FIFO addresses
25688 + * intialized? What should this be? */
25690 + fifo = core_if->data_fifo[ep->num];
25692 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
25693 + fifo, data_buff, *data_buff, byte_count);
25696 + for (i = 0; i < dword_count; i++, data_buff++) {
25697 + DWC_WRITE_REG32(fifo, *data_buff);
25701 + ep->xfer_count += byte_count;
25702 + ep->xfer_buff += byte_count;
25703 + ep->dma_addr += byte_count;
25707 + * Set the EP STALL.
25709 + * @param core_if Programming view of DWC_otg controller.
25710 + * @param ep The EP to set the stall on.
25712 +void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25714 + depctl_data_t depctl;
25715 + volatile uint32_t *depctl_addr;
25717 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
25718 + (ep->is_in ? "IN" : "OUT"));
25720 + if (ep->is_in == 1) {
25721 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
25722 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25724 + /* set the disable and stall bits */
25725 + if (depctl.b.epena) {
25726 + depctl.b.epdis = 1;
25728 + depctl.b.stall = 1;
25729 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25731 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
25732 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25734 + /* set the stall bit */
25735 + depctl.b.stall = 1;
25736 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25739 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
25745 + * Clear the EP STALL.
25747 + * @param core_if Programming view of DWC_otg controller.
25748 + * @param ep The EP to clear stall from.
25750 +void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
25752 + depctl_data_t depctl;
25753 + volatile uint32_t *depctl_addr;
25755 + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
25756 + (ep->is_in ? "IN" : "OUT"));
25758 + if (ep->is_in == 1) {
25759 + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
25761 + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
25764 + depctl.d32 = DWC_READ_REG32(depctl_addr);
25766 + /* clear the stall bits */
25767 + depctl.b.stall = 0;
25770 + * USB Spec 9.4.5: For endpoints using data toggle, regardless
25771 + * of whether an endpoint has the Halt feature set, a
25772 + * ClearFeature(ENDPOINT_HALT) request always results in the
25773 + * data toggle being reinitialized to DATA0.
25775 + if (ep->type == DWC_OTG_EP_TYPE_INTR ||
25776 + ep->type == DWC_OTG_EP_TYPE_BULK) {
25777 + depctl.b.setd0pid = 1; /* DATA0 */
25780 + DWC_WRITE_REG32(depctl_addr, depctl.d32);
25781 + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
25786 + * This function reads a packet from the Rx FIFO into the destination
25787 + * buffer. To read SETUP data use dwc_otg_read_setup_packet.
25789 + * @param core_if Programming view of DWC_otg controller.
25790 + * @param dest Destination buffer for the packet.
25791 + * @param bytes Number of bytes to copy to the destination.
25793 +void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
25794 + uint8_t * dest, uint16_t bytes)
25797 + int word_count = (bytes + 3) / 4;
25799 + volatile uint32_t *fifo = core_if->data_fifo[0];
25800 + uint32_t *data_buff = (uint32_t *) dest;
25803 + * @todo Account for the case where _dest is not dword aligned. This
25804 + * requires reading data from the FIFO into a uint32_t temp buffer,
25805 + * then moving it into the data buffer.
25808 + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
25809 + core_if, dest, bytes);
25811 + for (i = 0; i < word_count; i++, data_buff++) {
25812 + *data_buff = DWC_READ_REG32(fifo);
25819 + * This functions reads the device registers and prints them
25821 + * @param core_if Programming view of DWC_otg controller.
25823 +void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if)
25826 + volatile uint32_t *addr;
25828 + DWC_PRINTF("Device Global Registers\n");
25829 + addr = &core_if->dev_if->dev_global_regs->dcfg;
25830 + DWC_PRINTF("DCFG @0x%08lX : 0x%08X\n",
25831 + (unsigned long)addr, DWC_READ_REG32(addr));
25832 + addr = &core_if->dev_if->dev_global_regs->dctl;
25833 + DWC_PRINTF("DCTL @0x%08lX : 0x%08X\n",
25834 + (unsigned long)addr, DWC_READ_REG32(addr));
25835 + addr = &core_if->dev_if->dev_global_regs->dsts;
25836 + DWC_PRINTF("DSTS @0x%08lX : 0x%08X\n",
25837 + (unsigned long)addr, DWC_READ_REG32(addr));
25838 + addr = &core_if->dev_if->dev_global_regs->diepmsk;
25839 + DWC_PRINTF("DIEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25840 + DWC_READ_REG32(addr));
25841 + addr = &core_if->dev_if->dev_global_regs->doepmsk;
25842 + DWC_PRINTF("DOEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25843 + DWC_READ_REG32(addr));
25844 + addr = &core_if->dev_if->dev_global_regs->daint;
25845 + DWC_PRINTF("DAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
25846 + DWC_READ_REG32(addr));
25847 + addr = &core_if->dev_if->dev_global_regs->daintmsk;
25848 + DWC_PRINTF("DAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25849 + DWC_READ_REG32(addr));
25850 + addr = &core_if->dev_if->dev_global_regs->dtknqr1;
25851 + DWC_PRINTF("DTKNQR1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
25852 + DWC_READ_REG32(addr));
25853 + if (core_if->hwcfg2.b.dev_token_q_depth > 6) {
25854 + addr = &core_if->dev_if->dev_global_regs->dtknqr2;
25855 + DWC_PRINTF("DTKNQR2 @0x%08lX : 0x%08X\n",
25856 + (unsigned long)addr, DWC_READ_REG32(addr));
25859 + addr = &core_if->dev_if->dev_global_regs->dvbusdis;
25860 + DWC_PRINTF("DVBUSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
25861 + DWC_READ_REG32(addr));
25863 + addr = &core_if->dev_if->dev_global_regs->dvbuspulse;
25864 + DWC_PRINTF("DVBUSPULSE @0x%08lX : 0x%08X\n",
25865 + (unsigned long)addr, DWC_READ_REG32(addr));
25867 + addr = &core_if->dev_if->dev_global_regs->dtknqr3_dthrctl;
25868 + DWC_PRINTF("DTKNQR3_DTHRCTL @0x%08lX : 0x%08X\n",
25869 + (unsigned long)addr, DWC_READ_REG32(addr));
25871 + if (core_if->hwcfg2.b.dev_token_q_depth > 22) {
25872 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
25873 + DWC_PRINTF("DTKNQR4 @0x%08lX : 0x%08X\n",
25874 + (unsigned long)addr, DWC_READ_REG32(addr));
25877 + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
25878 + DWC_PRINTF("FIFOEMPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
25879 + DWC_READ_REG32(addr));
25881 + if (core_if->hwcfg2.b.multi_proc_int) {
25883 + addr = &core_if->dev_if->dev_global_regs->deachint;
25884 + DWC_PRINTF("DEACHINT @0x%08lX : 0x%08X\n",
25885 + (unsigned long)addr, DWC_READ_REG32(addr));
25886 + addr = &core_if->dev_if->dev_global_regs->deachintmsk;
25887 + DWC_PRINTF("DEACHINTMSK @0x%08lX : 0x%08X\n",
25888 + (unsigned long)addr, DWC_READ_REG32(addr));
25890 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
25892 + &core_if->dev_if->
25893 + dev_global_regs->diepeachintmsk[i];
25894 + DWC_PRINTF("DIEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
25895 + i, (unsigned long)addr,
25896 + DWC_READ_REG32(addr));
25899 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
25901 + &core_if->dev_if->
25902 + dev_global_regs->doepeachintmsk[i];
25903 + DWC_PRINTF("DOEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
25904 + i, (unsigned long)addr,
25905 + DWC_READ_REG32(addr));
25909 + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
25910 + DWC_PRINTF("Device IN EP %d Registers\n", i);
25911 + addr = &core_if->dev_if->in_ep_regs[i]->diepctl;
25912 + DWC_PRINTF("DIEPCTL @0x%08lX : 0x%08X\n",
25913 + (unsigned long)addr, DWC_READ_REG32(addr));
25914 + addr = &core_if->dev_if->in_ep_regs[i]->diepint;
25915 + DWC_PRINTF("DIEPINT @0x%08lX : 0x%08X\n",
25916 + (unsigned long)addr, DWC_READ_REG32(addr));
25917 + addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz;
25918 + DWC_PRINTF("DIETSIZ @0x%08lX : 0x%08X\n",
25919 + (unsigned long)addr, DWC_READ_REG32(addr));
25920 + addr = &core_if->dev_if->in_ep_regs[i]->diepdma;
25921 + DWC_PRINTF("DIEPDMA @0x%08lX : 0x%08X\n",
25922 + (unsigned long)addr, DWC_READ_REG32(addr));
25923 + addr = &core_if->dev_if->in_ep_regs[i]->dtxfsts;
25924 + DWC_PRINTF("DTXFSTS @0x%08lX : 0x%08X\n",
25925 + (unsigned long)addr, DWC_READ_REG32(addr));
25926 + addr = &core_if->dev_if->in_ep_regs[i]->diepdmab;
25927 + DWC_PRINTF("DIEPDMAB @0x%08lX : 0x%08X\n",
25928 + (unsigned long)addr, 0 /*DWC_READ_REG32(addr) */ );
25931 + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
25932 + DWC_PRINTF("Device OUT EP %d Registers\n", i);
25933 + addr = &core_if->dev_if->out_ep_regs[i]->doepctl;
25934 + DWC_PRINTF("DOEPCTL @0x%08lX : 0x%08X\n",
25935 + (unsigned long)addr, DWC_READ_REG32(addr));
25936 + addr = &core_if->dev_if->out_ep_regs[i]->doepint;
25937 + DWC_PRINTF("DOEPINT @0x%08lX : 0x%08X\n",
25938 + (unsigned long)addr, DWC_READ_REG32(addr));
25939 + addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz;
25940 + DWC_PRINTF("DOETSIZ @0x%08lX : 0x%08X\n",
25941 + (unsigned long)addr, DWC_READ_REG32(addr));
25942 + addr = &core_if->dev_if->out_ep_regs[i]->doepdma;
25943 + DWC_PRINTF("DOEPDMA @0x%08lX : 0x%08X\n",
25944 + (unsigned long)addr, DWC_READ_REG32(addr));
25945 + if (core_if->dma_enable) { /* Don't access this register in SLAVE mode */
25946 + addr = &core_if->dev_if->out_ep_regs[i]->doepdmab;
25947 + DWC_PRINTF("DOEPDMAB @0x%08lX : 0x%08X\n",
25948 + (unsigned long)addr, DWC_READ_REG32(addr));
25955 + * This functions reads the SPRAM and prints its content
25957 + * @param core_if Programming view of DWC_otg controller.
25959 +void dwc_otg_dump_spram(dwc_otg_core_if_t * core_if)
25961 + volatile uint8_t *addr, *start_addr, *end_addr;
25963 + DWC_PRINTF("SPRAM Data:\n");
25964 + start_addr = (void *)core_if->core_global_regs;
25965 + DWC_PRINTF("Base Address: 0x%8lX\n", (unsigned long)start_addr);
25966 + start_addr += 0x00028000;
25967 + end_addr = (void *)core_if->core_global_regs;
25968 + end_addr += 0x000280e0;
25970 + for (addr = start_addr; addr < end_addr; addr += 16) {
25972 + ("0x%8lX:\t%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n",
25973 + (unsigned long)addr, addr[0], addr[1], addr[2], addr[3],
25974 + addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
25975 + addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]
25983 + * This function reads the host registers and prints them
25985 + * @param core_if Programming view of DWC_otg controller.
25987 +void dwc_otg_dump_host_registers(dwc_otg_core_if_t * core_if)
25990 + volatile uint32_t *addr;
25992 + DWC_PRINTF("Host Global Registers\n");
25993 + addr = &core_if->host_if->host_global_regs->hcfg;
25994 + DWC_PRINTF("HCFG @0x%08lX : 0x%08X\n",
25995 + (unsigned long)addr, DWC_READ_REG32(addr));
25996 + addr = &core_if->host_if->host_global_regs->hfir;
25997 + DWC_PRINTF("HFIR @0x%08lX : 0x%08X\n",
25998 + (unsigned long)addr, DWC_READ_REG32(addr));
25999 + addr = &core_if->host_if->host_global_regs->hfnum;
26000 + DWC_PRINTF("HFNUM @0x%08lX : 0x%08X\n", (unsigned long)addr,
26001 + DWC_READ_REG32(addr));
26002 + addr = &core_if->host_if->host_global_regs->hptxsts;
26003 + DWC_PRINTF("HPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
26004 + DWC_READ_REG32(addr));
26005 + addr = &core_if->host_if->host_global_regs->haint;
26006 + DWC_PRINTF("HAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
26007 + DWC_READ_REG32(addr));
26008 + addr = &core_if->host_if->host_global_regs->haintmsk;
26009 + DWC_PRINTF("HAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
26010 + DWC_READ_REG32(addr));
26011 + if (core_if->dma_desc_enable) {
26012 + addr = &core_if->host_if->host_global_regs->hflbaddr;
26013 + DWC_PRINTF("HFLBADDR @0x%08lX : 0x%08X\n",
26014 + (unsigned long)addr, DWC_READ_REG32(addr));
26017 + addr = core_if->host_if->hprt0;
26018 + DWC_PRINTF("HPRT0 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26019 + DWC_READ_REG32(addr));
26021 + for (i = 0; i < core_if->core_params->host_channels; i++) {
26022 + DWC_PRINTF("Host Channel %d Specific Registers\n", i);
26023 + addr = &core_if->host_if->hc_regs[i]->hcchar;
26024 + DWC_PRINTF("HCCHAR @0x%08lX : 0x%08X\n",
26025 + (unsigned long)addr, DWC_READ_REG32(addr));
26026 + addr = &core_if->host_if->hc_regs[i]->hcsplt;
26027 + DWC_PRINTF("HCSPLT @0x%08lX : 0x%08X\n",
26028 + (unsigned long)addr, DWC_READ_REG32(addr));
26029 + addr = &core_if->host_if->hc_regs[i]->hcint;
26030 + DWC_PRINTF("HCINT @0x%08lX : 0x%08X\n",
26031 + (unsigned long)addr, DWC_READ_REG32(addr));
26032 + addr = &core_if->host_if->hc_regs[i]->hcintmsk;
26033 + DWC_PRINTF("HCINTMSK @0x%08lX : 0x%08X\n",
26034 + (unsigned long)addr, DWC_READ_REG32(addr));
26035 + addr = &core_if->host_if->hc_regs[i]->hctsiz;
26036 + DWC_PRINTF("HCTSIZ @0x%08lX : 0x%08X\n",
26037 + (unsigned long)addr, DWC_READ_REG32(addr));
26038 + addr = &core_if->host_if->hc_regs[i]->hcdma;
26039 + DWC_PRINTF("HCDMA @0x%08lX : 0x%08X\n",
26040 + (unsigned long)addr, DWC_READ_REG32(addr));
26041 + if (core_if->dma_desc_enable) {
26042 + addr = &core_if->host_if->hc_regs[i]->hcdmab;
26043 + DWC_PRINTF("HCDMAB @0x%08lX : 0x%08X\n",
26044 + (unsigned long)addr, DWC_READ_REG32(addr));
26052 + * This function reads the core global registers and prints them
26054 + * @param core_if Programming view of DWC_otg controller.
26056 +void dwc_otg_dump_global_registers(dwc_otg_core_if_t * core_if)
26059 + volatile uint32_t *addr;
26062 + DWC_PRINTF("Core Global Registers\n");
26063 + addr = &core_if->core_global_regs->gotgctl;
26064 + DWC_PRINTF("GOTGCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26065 + DWC_READ_REG32(addr));
26066 + addr = &core_if->core_global_regs->gotgint;
26067 + DWC_PRINTF("GOTGINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
26068 + DWC_READ_REG32(addr));
26069 + addr = &core_if->core_global_regs->gahbcfg;
26070 + DWC_PRINTF("GAHBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
26071 + DWC_READ_REG32(addr));
26072 + addr = &core_if->core_global_regs->gusbcfg;
26073 + DWC_PRINTF("GUSBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
26074 + DWC_READ_REG32(addr));
26075 + addr = &core_if->core_global_regs->grstctl;
26076 + DWC_PRINTF("GRSTCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26077 + DWC_READ_REG32(addr));
26078 + addr = &core_if->core_global_regs->gintsts;
26079 + DWC_PRINTF("GINTSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
26080 + DWC_READ_REG32(addr));
26081 + addr = &core_if->core_global_regs->gintmsk;
26082 + DWC_PRINTF("GINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
26083 + DWC_READ_REG32(addr));
26084 + addr = &core_if->core_global_regs->grxstsr;
26085 + DWC_PRINTF("GRXSTSR @0x%08lX : 0x%08X\n", (unsigned long)addr,
26086 + DWC_READ_REG32(addr));
26087 + addr = &core_if->core_global_regs->grxfsiz;
26088 + DWC_PRINTF("GRXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
26089 + DWC_READ_REG32(addr));
26090 + addr = &core_if->core_global_regs->gnptxfsiz;
26091 + DWC_PRINTF("GNPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
26092 + DWC_READ_REG32(addr));
26093 + addr = &core_if->core_global_regs->gnptxsts;
26094 + DWC_PRINTF("GNPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
26095 + DWC_READ_REG32(addr));
26096 + addr = &core_if->core_global_regs->gi2cctl;
26097 + DWC_PRINTF("GI2CCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26098 + DWC_READ_REG32(addr));
26099 + addr = &core_if->core_global_regs->gpvndctl;
26100 + DWC_PRINTF("GPVNDCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26101 + DWC_READ_REG32(addr));
26102 + addr = &core_if->core_global_regs->ggpio;
26103 + DWC_PRINTF("GGPIO @0x%08lX : 0x%08X\n", (unsigned long)addr,
26104 + DWC_READ_REG32(addr));
26105 + addr = &core_if->core_global_regs->guid;
26106 + DWC_PRINTF("GUID @0x%08lX : 0x%08X\n",
26107 + (unsigned long)addr, DWC_READ_REG32(addr));
26108 + addr = &core_if->core_global_regs->gsnpsid;
26109 + DWC_PRINTF("GSNPSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
26110 + DWC_READ_REG32(addr));
26111 + addr = &core_if->core_global_regs->ghwcfg1;
26112 + DWC_PRINTF("GHWCFG1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26113 + DWC_READ_REG32(addr));
26114 + addr = &core_if->core_global_regs->ghwcfg2;
26115 + DWC_PRINTF("GHWCFG2 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26116 + DWC_READ_REG32(addr));
26117 + addr = &core_if->core_global_regs->ghwcfg3;
26118 + DWC_PRINTF("GHWCFG3 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26119 + DWC_READ_REG32(addr));
26120 + addr = &core_if->core_global_regs->ghwcfg4;
26121 + DWC_PRINTF("GHWCFG4 @0x%08lX : 0x%08X\n", (unsigned long)addr,
26122 + DWC_READ_REG32(addr));
26123 + addr = &core_if->core_global_regs->glpmcfg;
26124 + DWC_PRINTF("GLPMCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
26125 + DWC_READ_REG32(addr));
26126 + addr = &core_if->core_global_regs->gpwrdn;
26127 + DWC_PRINTF("GPWRDN @0x%08lX : 0x%08X\n", (unsigned long)addr,
26128 + DWC_READ_REG32(addr));
26129 + addr = &core_if->core_global_regs->gdfifocfg;
26130 + DWC_PRINTF("GDFIFOCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
26131 + DWC_READ_REG32(addr));
26132 + addr = &core_if->core_global_regs->adpctl;
26133 + DWC_PRINTF("ADPCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26134 + dwc_otg_adp_read_reg(core_if));
26135 + addr = &core_if->core_global_regs->hptxfsiz;
26136 + DWC_PRINTF("HPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
26137 + DWC_READ_REG32(addr));
26139 + if (core_if->en_multiple_tx_fifo == 0) {
26140 + ep_num = core_if->hwcfg4.b.num_dev_perio_in_ep;
26141 + txfsiz = "DPTXFSIZ";
26143 + ep_num = core_if->hwcfg4.b.num_in_eps;
26144 + txfsiz = "DIENPTXF";
26146 + for (i = 0; i < ep_num; i++) {
26147 + addr = &core_if->core_global_regs->dtxfsiz[i];
26148 + DWC_PRINTF("%s[%d] @0x%08lX : 0x%08X\n", txfsiz, i + 1,
26149 + (unsigned long)addr, DWC_READ_REG32(addr));
26151 + addr = core_if->pcgcctl;
26152 + DWC_PRINTF("PCGCCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
26153 + DWC_READ_REG32(addr));
26157 + * Flush a Tx FIFO.
26159 + * @param core_if Programming view of DWC_otg controller.
26160 + * @param num Tx FIFO to flush.
26162 +void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * core_if, const int num)
26164 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26165 + volatile grstctl_t greset = {.d32 = 0 };
26168 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", num);
26170 + greset.b.txfflsh = 1;
26171 + greset.b.txfnum = num;
26172 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26175 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26176 + if (++count > 10000) {
26177 + DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
26178 + __func__, greset.d32,
26179 + DWC_READ_REG32(&global_regs->gnptxsts));
26183 + } while (greset.b.txfflsh == 1);
26185 + /* Wait for 3 PHY Clocks */
26192 + * @param core_if Programming view of DWC_otg controller.
26194 +void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * core_if)
26196 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26197 + volatile grstctl_t greset = {.d32 = 0 };
26200 + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__);
26204 + greset.b.rxfflsh = 1;
26205 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26208 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26209 + if (++count > 10000) {
26210 + DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
26215 + } while (greset.b.rxfflsh == 1);
26217 + /* Wait for 3 PHY Clocks */
26222 + * Do core a soft reset of the core. Be careful with this because it
26223 + * resets all the internal state machines of the core.
26225 +void dwc_otg_core_reset(dwc_otg_core_if_t * core_if)
26227 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
26228 + volatile grstctl_t greset = {.d32 = 0 };
26231 + DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
26232 + /* Wait for AHB master IDLE state. */
26235 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26236 + if (++count > 100000) {
26237 + DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
26242 + while (greset.b.ahbidle == 0);
26244 + /* Core Soft Reset */
26246 + greset.b.csftrst = 1;
26247 + DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
26249 + greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
26250 + if (++count > 10000) {
26251 + DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n",
26252 + __func__, greset.d32);
26257 + while (greset.b.csftrst == 1);
26259 + /* Wait for 3 PHY Clocks */
26263 +uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if)
26265 + return (dwc_otg_mode(_core_if) != DWC_HOST_MODE);
26268 +uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if)
26270 + return (dwc_otg_mode(_core_if) == DWC_HOST_MODE);
26274 + * Register HCD callbacks. The callbacks are used to start and stop
26275 + * the HCD for interrupt processing.
26277 + * @param core_if Programming view of DWC_otg controller.
26278 + * @param cb the HCD callback structure.
26279 + * @param p pointer to be passed to callback function (usb_hcd*).
26281 +void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * core_if,
26282 + dwc_otg_cil_callbacks_t * cb, void *p)
26284 + core_if->hcd_cb = cb;
26289 + * Register PCD callbacks. The callbacks are used to start and stop
26290 + * the PCD for interrupt processing.
26292 + * @param core_if Programming view of DWC_otg controller.
26293 + * @param cb the PCD callback structure.
26294 + * @param p pointer to be passed to callback function (pcd*).
26296 +void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * core_if,
26297 + dwc_otg_cil_callbacks_t * cb, void *p)
26299 + core_if->pcd_cb = cb;
26303 +#ifdef DWC_EN_ISOC
26306 + * This function writes isoc data per 1 (micro)frame into tx fifo
26308 + * @param core_if Programming view of DWC_otg controller.
26309 + * @param ep The EP to start the transfer on.
26312 +void write_isoc_frame_data(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
26314 + dwc_otg_dev_in_ep_regs_t *ep_regs;
26315 + dtxfsts_data_t txstatus = {.d32 = 0 };
26316 + uint32_t len = 0;
26319 + ep->xfer_len = ep->data_per_frame;
26320 + ep->xfer_count = 0;
26322 + ep_regs = core_if->dev_if->in_ep_regs[ep->num];
26324 + len = ep->xfer_len - ep->xfer_count;
26326 + if (len > ep->maxpacket) {
26327 + len = ep->maxpacket;
26330 + dwords = (len + 3) / 4;
26332 + /* While there is space in the queue and space in the FIFO and
26333 + * More data to tranfer, Write packets to the Tx FIFO */
26335 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dtxfsts);
26336 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", ep->num, txstatus.d32);
26338 + while (txstatus.b.txfspcavail > dwords &&
26339 + ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) {
26340 + /* Write the FIFO */
26341 + dwc_otg_ep_write_packet(core_if, ep, 0);
26343 + len = ep->xfer_len - ep->xfer_count;
26344 + if (len > ep->maxpacket) {
26345 + len = ep->maxpacket;
26348 + dwords = (len + 3) / 4;
26350 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
26352 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", ep->num,
26358 + * This function initializes a descriptor chain for Isochronous transfer
26360 + * @param core_if Programming view of DWC_otg controller.
26361 + * @param ep The EP to start the transfer on.
26364 +void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
26367 + deptsiz_data_t deptsiz = {.d32 = 0 };
26368 + depctl_data_t depctl = {.d32 = 0 };
26369 + dsts_data_t dsts = {.d32 = 0 };
26370 + volatile uint32_t *addr;
26373 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
26375 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
26378 + ep->xfer_len = ep->data_per_frame;
26379 + ep->xfer_count = 0;
26380 + ep->xfer_buff = ep->cur_pkt_addr;
26381 + ep->dma_addr = ep->cur_pkt_dma_addr;
26384 + /* Program the transfer size and packet count
26385 + * as follows: xfersize = N * maxpacket +
26386 + * short_packet pktcnt = N + (short_packet
26389 + deptsiz.b.xfersize = ep->xfer_len;
26390 + deptsiz.b.pktcnt =
26391 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
26392 + deptsiz.b.mc = deptsiz.b.pktcnt;
26393 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dieptsiz,
26396 + /* Write the DMA register */
26397 + if (core_if->dma_enable) {
26398 + DWC_WRITE_REG32(&
26399 + (core_if->dev_if->in_ep_regs[ep->num]->
26400 + diepdma), (uint32_t) ep->dma_addr);
26403 + deptsiz.b.pktcnt =
26404 + (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket;
26405 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
26407 + DWC_WRITE_REG32(&core_if->dev_if->
26408 + out_ep_regs[ep->num]->doeptsiz, deptsiz.d32);
26410 + if (core_if->dma_enable) {
26411 + DWC_WRITE_REG32(&
26412 + (core_if->dev_if->
26413 + out_ep_regs[ep->num]->doepdma),
26414 + (uint32_t) ep->dma_addr);
26418 + /** Enable endpoint, clear nak */
26421 + if (ep->bInterval == 1) {
26423 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
26424 + ep->next_frame = dsts.b.soffn + ep->bInterval;
26426 + if (ep->next_frame & 0x1) {
26427 + depctl.b.setd1pid = 1;
26429 + depctl.b.setd0pid = 1;
26432 + ep->next_frame += ep->bInterval;
26434 + if (ep->next_frame & 0x1) {
26435 + depctl.b.setd1pid = 1;
26437 + depctl.b.setd0pid = 1;
26440 + depctl.b.epena = 1;
26441 + depctl.b.cnak = 1;
26443 + DWC_MODIFY_REG32(addr, 0, depctl.d32);
26444 + depctl.d32 = DWC_READ_REG32(addr);
26446 + if (ep->is_in && core_if->dma_enable == 0) {
26447 + write_isoc_frame_data(core_if, ep);
26451 +#endif /* DWC_EN_ISOC */
26453 +static void dwc_otg_set_uninitialized(int32_t * p, int size)
26456 + for (i = 0; i < size; i++) {
26461 +static int dwc_otg_param_initialized(int32_t val)
26463 + return val != -1;
26466 +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if)
26469 + core_if->core_params = DWC_ALLOC(sizeof(*core_if->core_params));
26470 + if (!core_if->core_params) {
26471 + return -DWC_E_NO_MEMORY;
26473 + dwc_otg_set_uninitialized((int32_t *) core_if->core_params,
26474 + sizeof(*core_if->core_params) /
26475 + sizeof(int32_t));
26476 + DWC_PRINTF("Setting default values for core params\n");
26477 + dwc_otg_set_param_otg_cap(core_if, dwc_param_otg_cap_default);
26478 + dwc_otg_set_param_dma_enable(core_if, dwc_param_dma_enable_default);
26479 + dwc_otg_set_param_dma_desc_enable(core_if,
26480 + dwc_param_dma_desc_enable_default);
26481 + dwc_otg_set_param_opt(core_if, dwc_param_opt_default);
26482 + dwc_otg_set_param_dma_burst_size(core_if,
26483 + dwc_param_dma_burst_size_default);
26484 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
26485 + dwc_param_host_support_fs_ls_low_power_default);
26486 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
26487 + dwc_param_enable_dynamic_fifo_default);
26488 + dwc_otg_set_param_data_fifo_size(core_if,
26489 + dwc_param_data_fifo_size_default);
26490 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
26491 + dwc_param_dev_rx_fifo_size_default);
26492 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
26493 + dwc_param_dev_nperio_tx_fifo_size_default);
26494 + dwc_otg_set_param_host_rx_fifo_size(core_if,
26495 + dwc_param_host_rx_fifo_size_default);
26496 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
26497 + dwc_param_host_nperio_tx_fifo_size_default);
26498 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
26499 + dwc_param_host_perio_tx_fifo_size_default);
26500 + dwc_otg_set_param_max_transfer_size(core_if,
26501 + dwc_param_max_transfer_size_default);
26502 + dwc_otg_set_param_max_packet_count(core_if,
26503 + dwc_param_max_packet_count_default);
26504 + dwc_otg_set_param_host_channels(core_if,
26505 + dwc_param_host_channels_default);
26506 + dwc_otg_set_param_dev_endpoints(core_if,
26507 + dwc_param_dev_endpoints_default);
26508 + dwc_otg_set_param_phy_type(core_if, dwc_param_phy_type_default);
26509 + dwc_otg_set_param_speed(core_if, dwc_param_speed_default);
26510 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
26511 + dwc_param_host_ls_low_power_phy_clk_default);
26512 + dwc_otg_set_param_phy_ulpi_ddr(core_if, dwc_param_phy_ulpi_ddr_default);
26513 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
26514 + dwc_param_phy_ulpi_ext_vbus_default);
26515 + dwc_otg_set_param_phy_utmi_width(core_if,
26516 + dwc_param_phy_utmi_width_default);
26517 + dwc_otg_set_param_ts_dline(core_if, dwc_param_ts_dline_default);
26518 + dwc_otg_set_param_i2c_enable(core_if, dwc_param_i2c_enable_default);
26519 + dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_param_ulpi_fs_ls_default);
26520 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
26521 + dwc_param_en_multiple_tx_fifo_default);
26522 + for (i = 0; i < 15; i++) {
26523 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
26524 + dwc_param_dev_perio_tx_fifo_size_default,
26528 + for (i = 0; i < 15; i++) {
26529 + dwc_otg_set_param_dev_tx_fifo_size(core_if,
26530 + dwc_param_dev_tx_fifo_size_default,
26533 + dwc_otg_set_param_thr_ctl(core_if, dwc_param_thr_ctl_default);
26534 + dwc_otg_set_param_mpi_enable(core_if, dwc_param_mpi_enable_default);
26535 + dwc_otg_set_param_pti_enable(core_if, dwc_param_pti_enable_default);
26536 + dwc_otg_set_param_lpm_enable(core_if, dwc_param_lpm_enable_default);
26537 + dwc_otg_set_param_ic_usb_cap(core_if, dwc_param_ic_usb_cap_default);
26538 + dwc_otg_set_param_tx_thr_length(core_if,
26539 + dwc_param_tx_thr_length_default);
26540 + dwc_otg_set_param_rx_thr_length(core_if,
26541 + dwc_param_rx_thr_length_default);
26542 + dwc_otg_set_param_ahb_thr_ratio(core_if,
26543 + dwc_param_ahb_thr_ratio_default);
26544 + dwc_otg_set_param_power_down(core_if, dwc_param_power_down_default);
26545 + dwc_otg_set_param_reload_ctl(core_if, dwc_param_reload_ctl_default);
26546 + dwc_otg_set_param_dev_out_nak(core_if, dwc_param_dev_out_nak_default);
26547 + dwc_otg_set_param_cont_on_bna(core_if, dwc_param_cont_on_bna_default);
26548 + dwc_otg_set_param_ahb_single(core_if, dwc_param_ahb_single_default);
26549 + dwc_otg_set_param_otg_ver(core_if, dwc_param_otg_ver_default);
26550 + dwc_otg_set_param_adp_enable(core_if, dwc_param_adp_enable_default);
26551 + DWC_PRINTF("Finished setting default values for core params\n");
26556 +uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if)
26558 + return core_if->dma_enable;
26561 +/* Checks if the parameter is outside of its valid range of values */
26562 +#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \
26563 + (((_param_) < (_low_)) || \
26564 + ((_param_) > (_high_)))
26566 +/* Parameter access functions */
26567 +int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val)
26571 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
26572 + DWC_WARN("Wrong value for otg_cap parameter\n");
26573 + DWC_WARN("otg_cap parameter must be 0,1 or 2\n");
26574 + retval = -DWC_E_INVALID;
26580 + case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
26581 + if (core_if->hwcfg2.b.op_mode !=
26582 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26585 + case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
26586 + if ((core_if->hwcfg2.b.op_mode !=
26587 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26588 + && (core_if->hwcfg2.b.op_mode !=
26589 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
26590 + && (core_if->hwcfg2.b.op_mode !=
26591 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
26592 + && (core_if->hwcfg2.b.op_mode !=
26593 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) {
26597 + case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
26598 + /* always valid */
26602 + if (dwc_otg_param_initialized(core_if->core_params->otg_cap)) {
26604 + ("%d invalid for otg_cap paremter. Check HW configuration.\n",
26608 + (((core_if->hwcfg2.b.op_mode ==
26609 + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
26610 + || (core_if->hwcfg2.b.op_mode ==
26611 + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
26612 + || (core_if->hwcfg2.b.op_mode ==
26613 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
26614 + || (core_if->hwcfg2.b.op_mode ==
26615 + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ?
26616 + DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE :
26617 + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
26618 + retval = -DWC_E_INVALID;
26621 + core_if->core_params->otg_cap = val;
26626 +int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if)
26628 + return core_if->core_params->otg_cap;
26631 +int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val)
26633 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26634 + DWC_WARN("Wrong value for opt parameter\n");
26635 + return -DWC_E_INVALID;
26637 + core_if->core_params->opt = val;
26641 +int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if)
26643 + return core_if->core_params->opt;
26646 +int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, int32_t val)
26649 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26650 + DWC_WARN("Wrong value for dma enable\n");
26651 + return -DWC_E_INVALID;
26654 + if ((val == 1) && (core_if->hwcfg2.b.architecture == 0)) {
26655 + if (dwc_otg_param_initialized(core_if->core_params->dma_enable)) {
26657 + ("%d invalid for dma_enable paremter. Check HW configuration.\n",
26661 + retval = -DWC_E_INVALID;
26664 + core_if->core_params->dma_enable = val;
26666 + dwc_otg_set_param_dma_desc_enable(core_if, 0);
26671 +int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if)
26673 + return core_if->core_params->dma_enable;
26676 +int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, int32_t val)
26679 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26680 + DWC_WARN("Wrong value for dma_enable\n");
26681 + DWC_WARN("dma_desc_enable must be 0 or 1\n");
26682 + return -DWC_E_INVALID;
26686 + && ((dwc_otg_get_param_dma_enable(core_if) == 0)
26687 + || (core_if->hwcfg4.b.desc_dma == 0))) {
26688 + if (dwc_otg_param_initialized
26689 + (core_if->core_params->dma_desc_enable)) {
26691 + ("%d invalid for dma_desc_enable paremter. Check HW configuration.\n",
26695 + retval = -DWC_E_INVALID;
26697 + core_if->core_params->dma_desc_enable = val;
26701 +int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if)
26703 + return core_if->core_params->dma_desc_enable;
26706 +int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * core_if,
26709 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26710 + DWC_WARN("Wrong value for host_support_fs_low_power\n");
26711 + DWC_WARN("host_support_fs_low_power must be 0 or 1\n");
26712 + return -DWC_E_INVALID;
26714 + core_if->core_params->host_support_fs_ls_low_power = val;
26718 +int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
26721 + return core_if->core_params->host_support_fs_ls_low_power;
26724 +int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
26728 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
26729 + DWC_WARN("Wrong value for enable_dynamic_fifo\n");
26730 + DWC_WARN("enable_dynamic_fifo must be 0 or 1\n");
26731 + return -DWC_E_INVALID;
26734 + if ((val == 1) && (core_if->hwcfg2.b.dynamic_fifo == 0)) {
26735 + if (dwc_otg_param_initialized
26736 + (core_if->core_params->enable_dynamic_fifo)) {
26738 + ("%d invalid for enable_dynamic_fifo paremter. Check HW configuration.\n",
26742 + retval = -DWC_E_INVALID;
26744 + core_if->core_params->enable_dynamic_fifo = val;
26748 +int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if)
26750 + return core_if->core_params->enable_dynamic_fifo;
26753 +int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
26756 + if (DWC_OTG_PARAM_TEST(val, 32, 32768)) {
26757 + DWC_WARN("Wrong value for data_fifo_size\n");
26758 + DWC_WARN("data_fifo_size must be 32-32768\n");
26759 + return -DWC_E_INVALID;
26762 + if (val > core_if->hwcfg3.b.dfifo_depth) {
26763 + if (dwc_otg_param_initialized
26764 + (core_if->core_params->data_fifo_size)) {
26766 + ("%d invalid for data_fifo_size parameter. Check HW configuration.\n",
26769 + val = core_if->hwcfg3.b.dfifo_depth;
26770 + retval = -DWC_E_INVALID;
26773 + core_if->core_params->data_fifo_size = val;
26777 +int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if)
26779 + return core_if->core_params->data_fifo_size;
26782 +int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
26785 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26786 + DWC_WARN("Wrong value for dev_rx_fifo_size\n");
26787 + DWC_WARN("dev_rx_fifo_size must be 16-32768\n");
26788 + return -DWC_E_INVALID;
26791 + if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
26792 + if (dwc_otg_param_initialized(core_if->core_params->dev_rx_fifo_size)) {
26793 + DWC_WARN("%d invalid for dev_rx_fifo_size parameter\n", val);
26795 + val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
26796 + retval = -DWC_E_INVALID;
26799 + core_if->core_params->dev_rx_fifo_size = val;
26803 +int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if)
26805 + return core_if->core_params->dev_rx_fifo_size;
26808 +int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26813 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26814 + DWC_WARN("Wrong value for dev_nperio_tx_fifo\n");
26815 + DWC_WARN("dev_nperio_tx_fifo must be 16-32768\n");
26816 + return -DWC_E_INVALID;
26819 + if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
26820 + if (dwc_otg_param_initialized
26821 + (core_if->core_params->dev_nperio_tx_fifo_size)) {
26823 + ("%d invalid for dev_nperio_tx_fifo_size. Check HW configuration.\n",
26827 + (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
26829 + retval = -DWC_E_INVALID;
26832 + core_if->core_params->dev_nperio_tx_fifo_size = val;
26836 +int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26838 + return core_if->core_params->dev_nperio_tx_fifo_size;
26841 +int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
26846 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26847 + DWC_WARN("Wrong value for host_rx_fifo_size\n");
26848 + DWC_WARN("host_rx_fifo_size must be 16-32768\n");
26849 + return -DWC_E_INVALID;
26852 + if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
26853 + if (dwc_otg_param_initialized
26854 + (core_if->core_params->host_rx_fifo_size)) {
26856 + ("%d invalid for host_rx_fifo_size. Check HW configuration.\n",
26859 + val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
26860 + retval = -DWC_E_INVALID;
26863 + core_if->core_params->host_rx_fifo_size = val;
26868 +int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if)
26870 + return core_if->core_params->host_rx_fifo_size;
26873 +int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26878 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26879 + DWC_WARN("Wrong value for host_nperio_tx_fifo_size\n");
26880 + DWC_WARN("host_nperio_tx_fifo_size must be 16-32768\n");
26881 + return -DWC_E_INVALID;
26884 + if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
26885 + if (dwc_otg_param_initialized
26886 + (core_if->core_params->host_nperio_tx_fifo_size)) {
26888 + ("%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
26892 + (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
26894 + retval = -DWC_E_INVALID;
26897 + core_if->core_params->host_nperio_tx_fifo_size = val;
26901 +int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26903 + return core_if->core_params->host_nperio_tx_fifo_size;
26906 +int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
26910 + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
26911 + DWC_WARN("Wrong value for host_perio_tx_fifo_size\n");
26912 + DWC_WARN("host_perio_tx_fifo_size must be 16-32768\n");
26913 + return -DWC_E_INVALID;
26916 + if (val > ((core_if->hptxfsiz.d32) >> 16)) {
26917 + if (dwc_otg_param_initialized
26918 + (core_if->core_params->host_perio_tx_fifo_size)) {
26920 + ("%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
26923 + val = (core_if->hptxfsiz.d32) >> 16;
26924 + retval = -DWC_E_INVALID;
26927 + core_if->core_params->host_perio_tx_fifo_size = val;
26931 +int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if)
26933 + return core_if->core_params->host_perio_tx_fifo_size;
26936 +int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
26941 + if (DWC_OTG_PARAM_TEST(val, 2047, 524288)) {
26942 + DWC_WARN("Wrong value for max_transfer_size\n");
26943 + DWC_WARN("max_transfer_size must be 2047-524288\n");
26944 + return -DWC_E_INVALID;
26947 + if (val >= (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))) {
26948 + if (dwc_otg_param_initialized
26949 + (core_if->core_params->max_transfer_size)) {
26951 + ("%d invalid for max_transfer_size. Check HW configuration.\n",
26955 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 11)) -
26957 + retval = -DWC_E_INVALID;
26960 + core_if->core_params->max_transfer_size = val;
26964 +int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if)
26966 + return core_if->core_params->max_transfer_size;
26969 +int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, int32_t val)
26973 + if (DWC_OTG_PARAM_TEST(val, 15, 511)) {
26974 + DWC_WARN("Wrong value for max_packet_count\n");
26975 + DWC_WARN("max_packet_count must be 15-511\n");
26976 + return -DWC_E_INVALID;
26979 + if (val > (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))) {
26980 + if (dwc_otg_param_initialized
26981 + (core_if->core_params->max_packet_count)) {
26983 + ("%d invalid for max_packet_count. Check HW configuration.\n",
26987 + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1);
26988 + retval = -DWC_E_INVALID;
26991 + core_if->core_params->max_packet_count = val;
26995 +int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if)
26997 + return core_if->core_params->max_packet_count;
27000 +int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, int32_t val)
27004 + if (DWC_OTG_PARAM_TEST(val, 1, 16)) {
27005 + DWC_WARN("Wrong value for host_channels\n");
27006 + DWC_WARN("host_channels must be 1-16\n");
27007 + return -DWC_E_INVALID;
27010 + if (val > (core_if->hwcfg2.b.num_host_chan + 1)) {
27011 + if (dwc_otg_param_initialized
27012 + (core_if->core_params->host_channels)) {
27014 + ("%d invalid for host_channels. Check HW configurations.\n",
27017 + val = (core_if->hwcfg2.b.num_host_chan + 1);
27018 + retval = -DWC_E_INVALID;
27021 + core_if->core_params->host_channels = val;
27025 +int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if)
27027 + return core_if->core_params->host_channels;
27030 +int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, int32_t val)
27034 + if (DWC_OTG_PARAM_TEST(val, 1, 15)) {
27035 + DWC_WARN("Wrong value for dev_endpoints\n");
27036 + DWC_WARN("dev_endpoints must be 1-15\n");
27037 + return -DWC_E_INVALID;
27040 + if (val > (core_if->hwcfg2.b.num_dev_ep)) {
27041 + if (dwc_otg_param_initialized
27042 + (core_if->core_params->dev_endpoints)) {
27044 + ("%d invalid for dev_endpoints. Check HW configurations.\n",
27047 + val = core_if->hwcfg2.b.num_dev_ep;
27048 + retval = -DWC_E_INVALID;
27051 + core_if->core_params->dev_endpoints = val;
27055 +int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if)
27057 + return core_if->core_params->dev_endpoints;
27060 +int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val)
27065 + if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
27066 + DWC_WARN("Wrong value for phy_type\n");
27067 + DWC_WARN("phy_type must be 0,1 or 2\n");
27068 + return -DWC_E_INVALID;
27070 +#ifndef NO_FS_PHY_HW_CHECKS
27071 + if ((val == DWC_PHY_TYPE_PARAM_UTMI) &&
27072 + ((core_if->hwcfg2.b.hs_phy_type == 1) ||
27073 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
27075 + } else if ((val == DWC_PHY_TYPE_PARAM_ULPI) &&
27076 + ((core_if->hwcfg2.b.hs_phy_type == 2) ||
27077 + (core_if->hwcfg2.b.hs_phy_type == 3))) {
27079 + } else if ((val == DWC_PHY_TYPE_PARAM_FS) &&
27080 + (core_if->hwcfg2.b.fs_phy_type == 1)) {
27084 + if (dwc_otg_param_initialized(core_if->core_params->phy_type)) {
27086 + ("%d invalid for phy_type. Check HW configurations.\n",
27089 + if (core_if->hwcfg2.b.hs_phy_type) {
27090 + if ((core_if->hwcfg2.b.hs_phy_type == 3) ||
27091 + (core_if->hwcfg2.b.hs_phy_type == 1)) {
27092 + val = DWC_PHY_TYPE_PARAM_UTMI;
27094 + val = DWC_PHY_TYPE_PARAM_ULPI;
27097 + retval = -DWC_E_INVALID;
27100 + core_if->core_params->phy_type = val;
27104 +int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if)
27106 + return core_if->core_params->phy_type;
27109 +int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val)
27112 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27113 + DWC_WARN("Wrong value for speed parameter\n");
27114 + DWC_WARN("max_speed parameter must be 0 or 1\n");
27115 + return -DWC_E_INVALID;
27118 + && dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS) {
27119 + if (dwc_otg_param_initialized(core_if->core_params->speed)) {
27121 + ("%d invalid for speed paremter. Check HW configuration.\n",
27125 + (dwc_otg_get_param_phy_type(core_if) ==
27126 + DWC_PHY_TYPE_PARAM_FS ? 1 : 0);
27127 + retval = -DWC_E_INVALID;
27129 + core_if->core_params->speed = val;
27133 +int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if)
27135 + return core_if->core_params->speed;
27138 +int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if,
27143 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27145 + ("Wrong value for host_ls_low_power_phy_clk parameter\n");
27146 + DWC_WARN("host_ls_low_power_phy_clk must be 0 or 1\n");
27147 + return -DWC_E_INVALID;
27150 + if ((val == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)
27151 + && (dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS)) {
27152 + if (dwc_otg_param_initialized
27153 + (core_if->core_params->host_ls_low_power_phy_clk)) {
27155 + ("%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
27159 + (dwc_otg_get_param_phy_type(core_if) ==
27160 + DWC_PHY_TYPE_PARAM_FS) ?
27161 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ :
27162 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
27163 + retval = -DWC_E_INVALID;
27166 + core_if->core_params->host_ls_low_power_phy_clk = val;
27170 +int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if)
27172 + return core_if->core_params->host_ls_low_power_phy_clk;
27175 +int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, int32_t val)
27177 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27178 + DWC_WARN("Wrong value for phy_ulpi_ddr\n");
27179 + DWC_WARN("phy_upli_ddr must be 0 or 1\n");
27180 + return -DWC_E_INVALID;
27183 + core_if->core_params->phy_ulpi_ddr = val;
27187 +int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if)
27189 + return core_if->core_params->phy_ulpi_ddr;
27192 +int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
27195 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27196 + DWC_WARN("Wrong valaue for phy_ulpi_ext_vbus\n");
27197 + DWC_WARN("phy_ulpi_ext_vbus must be 0 or 1\n");
27198 + return -DWC_E_INVALID;
27201 + core_if->core_params->phy_ulpi_ext_vbus = val;
27205 +int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if)
27207 + return core_if->core_params->phy_ulpi_ext_vbus;
27210 +int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, int32_t val)
27212 + if (DWC_OTG_PARAM_TEST(val, 8, 8) && DWC_OTG_PARAM_TEST(val, 16, 16)) {
27213 + DWC_WARN("Wrong valaue for phy_utmi_width\n");
27214 + DWC_WARN("phy_utmi_width must be 8 or 16\n");
27215 + return -DWC_E_INVALID;
27218 + core_if->core_params->phy_utmi_width = val;
27222 +int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if)
27224 + return core_if->core_params->phy_utmi_width;
27227 +int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, int32_t val)
27229 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27230 + DWC_WARN("Wrong valaue for ulpi_fs_ls\n");
27231 + DWC_WARN("ulpi_fs_ls must be 0 or 1\n");
27232 + return -DWC_E_INVALID;
27235 + core_if->core_params->ulpi_fs_ls = val;
27239 +int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if)
27241 + return core_if->core_params->ulpi_fs_ls;
27244 +int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val)
27246 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27247 + DWC_WARN("Wrong valaue for ts_dline\n");
27248 + DWC_WARN("ts_dline must be 0 or 1\n");
27249 + return -DWC_E_INVALID;
27252 + core_if->core_params->ts_dline = val;
27256 +int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if)
27258 + return core_if->core_params->ts_dline;
27261 +int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, int32_t val)
27264 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27265 + DWC_WARN("Wrong valaue for i2c_enable\n");
27266 + DWC_WARN("i2c_enable must be 0 or 1\n");
27267 + return -DWC_E_INVALID;
27269 +#ifndef NO_FS_PHY_HW_CHECK
27270 + if (val == 1 && core_if->hwcfg3.b.i2c == 0) {
27271 + if (dwc_otg_param_initialized(core_if->core_params->i2c_enable)) {
27273 + ("%d invalid for i2c_enable. Check HW configuration.\n",
27277 + retval = -DWC_E_INVALID;
27281 + core_if->core_params->i2c_enable = val;
27285 +int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if)
27287 + return core_if->core_params->i2c_enable;
27290 +int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
27291 + int32_t val, int fifo_num)
27295 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
27296 + DWC_WARN("Wrong value for dev_perio_tx_fifo_size\n");
27297 + DWC_WARN("dev_perio_tx_fifo_size must be 4-768\n");
27298 + return -DWC_E_INVALID;
27302 + (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
27303 + if (dwc_otg_param_initialized
27304 + (core_if->core_params->dev_perio_tx_fifo_size[fifo_num])) {
27306 + ("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n",
27309 + val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
27310 + retval = -DWC_E_INVALID;
27313 + core_if->core_params->dev_perio_tx_fifo_size[fifo_num] = val;
27317 +int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
27320 + return core_if->core_params->dev_perio_tx_fifo_size[fifo_num];
27323 +int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
27327 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27328 + DWC_WARN("Wrong valaue for en_multiple_tx_fifo,\n");
27329 + DWC_WARN("en_multiple_tx_fifo must be 0 or 1\n");
27330 + return -DWC_E_INVALID;
27333 + if (val == 1 && core_if->hwcfg4.b.ded_fifo_en == 0) {
27334 + if (dwc_otg_param_initialized
27335 + (core_if->core_params->en_multiple_tx_fifo)) {
27337 + ("%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
27341 + retval = -DWC_E_INVALID;
27344 + core_if->core_params->en_multiple_tx_fifo = val;
27348 +int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if)
27350 + return core_if->core_params->en_multiple_tx_fifo;
27353 +int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val,
27358 + if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
27359 + DWC_WARN("Wrong value for dev_tx_fifo_size\n");
27360 + DWC_WARN("dev_tx_fifo_size must be 4-768\n");
27361 + return -DWC_E_INVALID;
27365 + (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
27366 + if (dwc_otg_param_initialized
27367 + (core_if->core_params->dev_tx_fifo_size[fifo_num])) {
27369 + ("`%d' invalid for parameter `dev_tx_fifo_size_%d'. Check HW configuration.\n",
27372 + val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
27373 + retval = -DWC_E_INVALID;
27376 + core_if->core_params->dev_tx_fifo_size[fifo_num] = val;
27380 +int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
27383 + return core_if->core_params->dev_tx_fifo_size[fifo_num];
27386 +int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val)
27390 + if (DWC_OTG_PARAM_TEST(val, 0, 7)) {
27391 + DWC_WARN("Wrong value for thr_ctl\n");
27392 + DWC_WARN("thr_ctl must be 0-7\n");
27393 + return -DWC_E_INVALID;
27396 + if ((val != 0) &&
27397 + (!dwc_otg_get_param_dma_enable(core_if) ||
27398 + !core_if->hwcfg4.b.ded_fifo_en)) {
27399 + if (dwc_otg_param_initialized(core_if->core_params->thr_ctl)) {
27401 + ("%d invalid for parameter thr_ctl. Check HW configuration.\n",
27405 + retval = -DWC_E_INVALID;
27408 + core_if->core_params->thr_ctl = val;
27412 +int32_t dwc_otg_get_param_thr_ctl(dwc_otg_core_if_t * core_if)
27414 + return core_if->core_params->thr_ctl;
27417 +int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, int32_t val)
27421 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27422 + DWC_WARN("Wrong value for lpm_enable\n");
27423 + DWC_WARN("lpm_enable must be 0 or 1\n");
27424 + return -DWC_E_INVALID;
27427 + if (val && !core_if->hwcfg3.b.otg_lpm_en) {
27428 + if (dwc_otg_param_initialized(core_if->core_params->lpm_enable)) {
27430 + ("%d invalid for parameter lpm_enable. Check HW configuration.\n",
27434 + retval = -DWC_E_INVALID;
27437 + core_if->core_params->lpm_enable = val;
27441 +int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if)
27443 + return core_if->core_params->lpm_enable;
27446 +int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
27448 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
27449 + DWC_WARN("Wrong valaue for tx_thr_length\n");
27450 + DWC_WARN("tx_thr_length must be 8 - 128\n");
27451 + return -DWC_E_INVALID;
27454 + core_if->core_params->tx_thr_length = val;
27458 +int32_t dwc_otg_get_param_tx_thr_length(dwc_otg_core_if_t * core_if)
27460 + return core_if->core_params->tx_thr_length;
27463 +int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
27465 + if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
27466 + DWC_WARN("Wrong valaue for rx_thr_length\n");
27467 + DWC_WARN("rx_thr_length must be 8 - 128\n");
27468 + return -DWC_E_INVALID;
27471 + core_if->core_params->rx_thr_length = val;
27475 +int32_t dwc_otg_get_param_rx_thr_length(dwc_otg_core_if_t * core_if)
27477 + return core_if->core_params->rx_thr_length;
27480 +int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, int32_t val)
27482 + if (DWC_OTG_PARAM_TEST(val, 1, 1) &&
27483 + DWC_OTG_PARAM_TEST(val, 4, 4) &&
27484 + DWC_OTG_PARAM_TEST(val, 8, 8) &&
27485 + DWC_OTG_PARAM_TEST(val, 16, 16) &&
27486 + DWC_OTG_PARAM_TEST(val, 32, 32) &&
27487 + DWC_OTG_PARAM_TEST(val, 64, 64) &&
27488 + DWC_OTG_PARAM_TEST(val, 128, 128) &&
27489 + DWC_OTG_PARAM_TEST(val, 256, 256)) {
27490 + DWC_WARN("`%d' invalid for parameter `dma_burst_size'\n", val);
27491 + return -DWC_E_INVALID;
27493 + core_if->core_params->dma_burst_size = val;
27497 +int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if)
27499 + return core_if->core_params->dma_burst_size;
27502 +int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, int32_t val)
27505 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27506 + DWC_WARN("`%d' invalid for parameter `pti_enable'\n", val);
27507 + return -DWC_E_INVALID;
27509 + if (val && (core_if->snpsid < OTG_CORE_REV_2_72a)) {
27510 + if (dwc_otg_param_initialized(core_if->core_params->pti_enable)) {
27512 + ("%d invalid for parameter pti_enable. Check HW configuration.\n",
27515 + retval = -DWC_E_INVALID;
27518 + core_if->core_params->pti_enable = val;
27522 +int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if)
27524 + return core_if->core_params->pti_enable;
27527 +int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, int32_t val)
27530 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27531 + DWC_WARN("`%d' invalid for parameter `mpi_enable'\n", val);
27532 + return -DWC_E_INVALID;
27534 + if (val && (core_if->hwcfg2.b.multi_proc_int == 0)) {
27535 + if (dwc_otg_param_initialized(core_if->core_params->mpi_enable)) {
27537 + ("%d invalid for parameter mpi_enable. Check HW configuration.\n",
27540 + retval = -DWC_E_INVALID;
27543 + core_if->core_params->mpi_enable = val;
27547 +int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if)
27549 + return core_if->core_params->mpi_enable;
27552 +int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if, int32_t val)
27555 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27556 + DWC_WARN("`%d' invalid for parameter `adp_enable'\n", val);
27557 + return -DWC_E_INVALID;
27559 + if (val && (core_if->hwcfg3.b.adp_supp == 0)) {
27560 + if (dwc_otg_param_initialized
27561 + (core_if->core_params->adp_supp_enable)) {
27563 + ("%d invalid for parameter adp_enable. Check HW configuration.\n",
27566 + retval = -DWC_E_INVALID;
27569 + core_if->core_params->adp_supp_enable = val;
27570 + /*Set OTG version 2.0 in case of enabling ADP*/
27572 + dwc_otg_set_param_otg_ver(core_if, 1);
27577 +int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if)
27579 + return core_if->core_params->adp_supp_enable;
27582 +int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if, int32_t val)
27585 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27586 + DWC_WARN("`%d' invalid for parameter `ic_usb_cap'\n", val);
27587 + DWC_WARN("ic_usb_cap must be 0 or 1\n");
27588 + return -DWC_E_INVALID;
27591 + if (val && (core_if->hwcfg2.b.otg_enable_ic_usb == 0)) {
27592 + if (dwc_otg_param_initialized(core_if->core_params->ic_usb_cap)) {
27594 + ("%d invalid for parameter ic_usb_cap. Check HW configuration.\n",
27597 + retval = -DWC_E_INVALID;
27600 + core_if->core_params->ic_usb_cap = val;
27604 +int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if)
27606 + return core_if->core_params->ic_usb_cap;
27609 +int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val)
27614 + if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
27615 + DWC_WARN("`%d' invalid for parameter `ahb_thr_ratio'\n", val);
27616 + DWC_WARN("ahb_thr_ratio must be 0 - 3\n");
27617 + return -DWC_E_INVALID;
27621 + && (core_if->snpsid < OTG_CORE_REV_2_81a
27622 + || !dwc_otg_get_param_thr_ctl(core_if))) {
27625 + && ((dwc_otg_get_param_tx_thr_length(core_if) / (1 << val)) <
27629 + if (valid == 0) {
27630 + if (dwc_otg_param_initialized
27631 + (core_if->core_params->ahb_thr_ratio)) {
27633 + ("%d invalid for parameter ahb_thr_ratio. Check HW configuration.\n",
27636 + retval = -DWC_E_INVALID;
27640 + core_if->core_params->ahb_thr_ratio = val;
27644 +int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if)
27646 + return core_if->core_params->ahb_thr_ratio;
27649 +int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if, int32_t val)
27653 + hwcfg4_data_t hwcfg4 = {.d32 = 0 };
27654 + hwcfg4.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
27656 + if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
27657 + DWC_WARN("`%d' invalid for parameter `power_down'\n", val);
27658 + DWC_WARN("power_down must be 0 - 2\n");
27659 + return -DWC_E_INVALID;
27662 + if ((val == 2) && (core_if->snpsid < OTG_CORE_REV_2_91a)) {
27666 + && ((core_if->snpsid < OTG_CORE_REV_3_00a)
27667 + || (hwcfg4.b.xhiber == 0))) {
27670 + if (valid == 0) {
27671 + if (dwc_otg_param_initialized(core_if->core_params->power_down)) {
27673 + ("%d invalid for parameter power_down. Check HW configuration.\n",
27676 + retval = -DWC_E_INVALID;
27679 + core_if->core_params->power_down = val;
27683 +int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if)
27685 + return core_if->core_params->power_down;
27688 +int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if, int32_t val)
27693 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27694 + DWC_WARN("`%d' invalid for parameter `reload_ctl'\n", val);
27695 + DWC_WARN("reload_ctl must be 0 or 1\n");
27696 + return -DWC_E_INVALID;
27699 + if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_92a)) {
27702 + if (valid == 0) {
27703 + if (dwc_otg_param_initialized(core_if->core_params->reload_ctl)) {
27704 + DWC_ERROR("%d invalid for parameter reload_ctl."
27705 + "Check HW configuration.\n", val);
27707 + retval = -DWC_E_INVALID;
27710 + core_if->core_params->reload_ctl = val;
27714 +int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if)
27716 + return core_if->core_params->reload_ctl;
27719 +int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if, int32_t val)
27724 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27725 + DWC_WARN("`%d' invalid for parameter `dev_out_nak'\n", val);
27726 + DWC_WARN("dev_out_nak must be 0 or 1\n");
27727 + return -DWC_E_INVALID;
27730 + if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_93a) ||
27731 + !(core_if->core_params->dma_desc_enable))) {
27734 + if (valid == 0) {
27735 + if (dwc_otg_param_initialized(core_if->core_params->dev_out_nak)) {
27736 + DWC_ERROR("%d invalid for parameter dev_out_nak."
27737 + "Check HW configuration.\n", val);
27739 + retval = -DWC_E_INVALID;
27742 + core_if->core_params->dev_out_nak = val;
27746 +int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if)
27748 + return core_if->core_params->dev_out_nak;
27751 +int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if, int32_t val)
27756 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27757 + DWC_WARN("`%d' invalid for parameter `cont_on_bna'\n", val);
27758 + DWC_WARN("cont_on_bna must be 0 or 1\n");
27759 + return -DWC_E_INVALID;
27762 + if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_94a) ||
27763 + !(core_if->core_params->dma_desc_enable))) {
27766 + if (valid == 0) {
27767 + if (dwc_otg_param_initialized(core_if->core_params->cont_on_bna)) {
27768 + DWC_ERROR("%d invalid for parameter cont_on_bna."
27769 + "Check HW configuration.\n", val);
27771 + retval = -DWC_E_INVALID;
27774 + core_if->core_params->cont_on_bna = val;
27778 +int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if)
27780 + return core_if->core_params->cont_on_bna;
27783 +int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if, int32_t val)
27788 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27789 + DWC_WARN("`%d' invalid for parameter `ahb_single'\n", val);
27790 + DWC_WARN("ahb_single must be 0 or 1\n");
27791 + return -DWC_E_INVALID;
27794 + if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
27797 + if (valid == 0) {
27798 + if (dwc_otg_param_initialized(core_if->core_params->ahb_single)) {
27799 + DWC_ERROR("%d invalid for parameter ahb_single."
27800 + "Check HW configuration.\n", val);
27802 + retval = -DWC_E_INVALID;
27805 + core_if->core_params->ahb_single = val;
27809 +int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if)
27811 + return core_if->core_params->ahb_single;
27814 +int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val)
27818 + if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
27819 + DWC_WARN("`%d' invalid for parameter `otg_ver'\n", val);
27821 + ("otg_ver must be 0(for OTG 1.3 support) or 1(for OTG 2.0 support)\n");
27822 + return -DWC_E_INVALID;
27825 + core_if->core_params->otg_ver = val;
27829 +int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if)
27831 + return core_if->core_params->otg_ver;
27834 +uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if)
27836 + gotgctl_data_t otgctl;
27837 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27838 + return otgctl.b.hstnegscs;
27841 +uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if)
27843 + gotgctl_data_t otgctl;
27844 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27845 + return otgctl.b.sesreqscs;
27848 +void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val)
27850 + if(core_if->otg_ver == 0) {
27851 + gotgctl_data_t otgctl;
27852 + otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
27853 + otgctl.b.hnpreq = val;
27854 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, otgctl.d32);
27856 + core_if->otg_sts = val;
27860 +uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if)
27862 + return core_if->snpsid;
27865 +uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if)
27867 + gintsts_data_t gintsts;
27868 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
27869 + return gintsts.b.curmode;
27872 +uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if)
27874 + gusbcfg_data_t usbcfg;
27875 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27876 + return usbcfg.b.hnpcap;
27879 +void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
27881 + gusbcfg_data_t usbcfg;
27882 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27883 + usbcfg.b.hnpcap = val;
27884 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
27887 +uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if)
27889 + gusbcfg_data_t usbcfg;
27890 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27891 + return usbcfg.b.srpcap;
27894 +void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
27896 + gusbcfg_data_t usbcfg;
27897 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
27898 + usbcfg.b.srpcap = val;
27899 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
27902 +uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if)
27904 + dcfg_data_t dcfg;
27905 + /* originally: dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg); */
27907 + dcfg.d32 = -1; //GRAYG
27908 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)\n", __func__, core_if);
27909 + if (NULL == core_if)
27910 + DWC_ERROR("reg request with NULL core_if\n");
27911 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)\n", __func__,
27912 + core_if, core_if->dev_if);
27913 + if (NULL == core_if->dev_if)
27914 + DWC_ERROR("reg request with NULL dev_if\n");
27915 + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)->"
27916 + "dev_global_regs(%p)\n", __func__,
27917 + core_if, core_if->dev_if,
27918 + core_if->dev_if->dev_global_regs);
27919 + if (NULL == core_if->dev_if->dev_global_regs)
27920 + DWC_ERROR("reg request with NULL dev_global_regs\n");
27922 + DWC_DEBUGPL(DBG_CILV, "%s - &core_if(%p)->dev_if(%p)->"
27923 + "dev_global_regs(%p)->dcfg = %p\n", __func__,
27924 + core_if, core_if->dev_if,
27925 + core_if->dev_if->dev_global_regs,
27926 + &core_if->dev_if->dev_global_regs->dcfg);
27927 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
27929 + return dcfg.b.devspd;
27932 +void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val)
27934 + dcfg_data_t dcfg;
27935 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
27936 + dcfg.b.devspd = val;
27937 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
27940 +uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if)
27942 + hprt0_data_t hprt0;
27943 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27944 + return hprt0.b.prtconnsts;
27947 +uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if)
27949 + dsts_data_t dsts;
27950 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
27951 + return dsts.b.enumspd;
27954 +uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if)
27956 + hprt0_data_t hprt0;
27957 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27958 + return hprt0.b.prtpwr;
27962 +uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if)
27964 + return core_if->hibernation_suspend;
27967 +void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val)
27969 + hprt0_data_t hprt0;
27970 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27971 + hprt0.b.prtpwr = val;
27972 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27975 +uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if)
27977 + hprt0_data_t hprt0;
27978 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
27979 + return hprt0.b.prtsusp;
27983 +void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val)
27985 + hprt0_data_t hprt0;
27986 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
27987 + hprt0.b.prtsusp = val;
27988 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
27991 +uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if)
27993 + hfir_data_t hfir;
27994 + hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
27995 + return hfir.b.frint;
27999 +void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val)
28001 + hfir_data_t hfir;
28002 + uint32_t fram_int;
28003 + fram_int = calc_frame_interval(core_if);
28004 + hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
28005 + if (!core_if->core_params->reload_ctl) {
28006 + DWC_WARN("\nCannot reload HFIR register.HFIR.HFIRRldCtrl bit is"
28007 + "not set to 1.\nShould load driver with reload_ctl=1"
28008 + " module parameter\n");
28011 + switch (fram_int) {
28013 + if ((val < 3350) || (val > 4150)) {
28014 + DWC_WARN("HFIR interval for HS core and 30 MHz"
28015 + "clock freq should be from 3350 to 4150\n");
28020 + if ((val < 26820) || (val > 33180)) {
28021 + DWC_WARN("HFIR interval for FS/LS core and 30 MHz"
28022 + "clock freq should be from 26820 to 33180\n");
28027 + if ((val < 5360) || (val > 6640)) {
28028 + DWC_WARN("HFIR interval for HS core and 48 MHz"
28029 + "clock freq should be from 5360 to 6640\n");
28034 + if ((val < 42912) || (val > 53088)) {
28035 + DWC_WARN("HFIR interval for FS/LS core and 48 MHz"
28036 + "clock freq should be from 42912 to 53088\n");
28041 + if ((val < 6700) || (val > 8300)) {
28042 + DWC_WARN("HFIR interval for HS core and 60 MHz"
28043 + "clock freq should be from 6700 to 8300\n");
28048 + if ((val < 53640) || (val > 65536)) {
28049 + DWC_WARN("HFIR interval for FS/LS core and 60 MHz"
28050 + "clock freq should be from 53640 to 65536\n");
28055 + DWC_WARN("Unknown frame interval\n");
28060 + hfir.b.frint = val;
28061 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hfir.d32);
28064 +uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if)
28066 + hcfg_data_t hcfg;
28067 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
28068 + return hcfg.b.modechtimen;
28072 +void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val)
28074 + hcfg_data_t hcfg;
28075 + hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
28076 + hcfg.b.modechtimen = val;
28077 + DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
28080 +void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val)
28082 + hprt0_data_t hprt0;
28083 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
28084 + hprt0.b.prtres = val;
28085 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
28088 +uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if)
28090 + dctl_data_t dctl;
28091 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
28092 + return dctl.b.rmtwkupsig;
28095 +uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if)
28097 + glpmcfg_data_t lpmcfg;
28098 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28101 + ((core_if->lx_state == DWC_OTG_L1) ^ lpmcfg.b.prt_sleep_sts),
28102 + "lx_state = %d, lmpcfg.prt_sleep_sts = %d\n",
28103 + core_if->lx_state, lpmcfg.b.prt_sleep_sts);
28105 + return lpmcfg.b.prt_sleep_sts;
28108 +uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if)
28110 + glpmcfg_data_t lpmcfg;
28111 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28112 + return lpmcfg.b.rem_wkup_en;
28115 +uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if)
28117 + glpmcfg_data_t lpmcfg;
28118 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28119 + return lpmcfg.b.appl_resp;
28122 +void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val)
28124 + glpmcfg_data_t lpmcfg;
28125 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28126 + lpmcfg.b.appl_resp = val;
28127 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
28130 +uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if)
28132 + glpmcfg_data_t lpmcfg;
28133 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28134 + return lpmcfg.b.hsic_connect;
28137 +void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val)
28139 + glpmcfg_data_t lpmcfg;
28140 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28141 + lpmcfg.b.hsic_connect = val;
28142 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
28145 +uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if)
28147 + glpmcfg_data_t lpmcfg;
28148 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28149 + return lpmcfg.b.inv_sel_hsic;
28153 +void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val)
28155 + glpmcfg_data_t lpmcfg;
28156 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
28157 + lpmcfg.b.inv_sel_hsic = val;
28158 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
28161 +uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if)
28163 + return DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
28166 +void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val)
28168 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, val);
28171 +uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if)
28173 + return DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
28176 +void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val)
28178 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, val);
28181 +uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if)
28183 + return DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
28186 +void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
28188 + DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, val);
28191 +uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if)
28193 + return DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
28196 +void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
28198 + DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz, val);
28201 +uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if)
28203 + return DWC_READ_REG32(&core_if->core_global_regs->gpvndctl);
28206 +void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val)
28208 + DWC_WRITE_REG32(&core_if->core_global_regs->gpvndctl, val);
28211 +uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if)
28213 + return DWC_READ_REG32(&core_if->core_global_regs->ggpio);
28216 +void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val)
28218 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, val);
28221 +uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if)
28223 + return DWC_READ_REG32(core_if->host_if->hprt0);
28227 +void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val)
28229 + DWC_WRITE_REG32(core_if->host_if->hprt0, val);
28232 +uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if)
28234 + return DWC_READ_REG32(&core_if->core_global_regs->guid);
28237 +void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val)
28239 + DWC_WRITE_REG32(&core_if->core_global_regs->guid, val);
28242 +uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if)
28244 + return DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
28247 +uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if)
28249 + return ((core_if->otg_ver == 1) ? (uint16_t)0x0200 : (uint16_t)0x0103);
28253 + * Start the SRP timer to detect when the SRP does not complete within
28256 + * @param core_if the pointer to core_if strucure.
28258 +void dwc_otg_pcd_start_srp_timer(dwc_otg_core_if_t * core_if)
28260 + core_if->srp_timer_started = 1;
28261 + DWC_TIMER_SCHEDULE(core_if->srp_timer, 6000 /* 6 secs */ );
28264 +void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if)
28266 + uint32_t *addr = (uint32_t *) & (core_if->core_global_regs->gotgctl);
28267 + gotgctl_data_t mem;
28268 + gotgctl_data_t val;
28270 + val.d32 = DWC_READ_REG32(addr);
28271 + if (val.b.sesreq) {
28272 + DWC_ERROR("Session Request Already active!\n");
28276 + DWC_INFO("Session Request Initated\n"); //NOTICE
28277 + mem.d32 = DWC_READ_REG32(addr);
28278 + mem.b.sesreq = 1;
28279 + DWC_WRITE_REG32(addr, mem.d32);
28281 + /* Start the SRP timer */
28282 + dwc_otg_pcd_start_srp_timer(core_if);
28285 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil.h b/drivers/usb/host/dwc_otg/dwc_otg_cil.h
28286 new file mode 100644
28287 index 0000000..d367cd1
28289 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.h
28291 +/* ==========================================================================
28292 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.h $
28293 + * $Revision: #123 $
28294 + * $Date: 2012/08/10 $
28295 + * $Change: 2047372 $
28297 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
28298 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
28299 + * otherwise expressly agreed to in writing between Synopsys and you.
28301 + * The Software IS NOT an item of Licensed Software or Licensed Product under
28302 + * any End User Software License Agreement or Agreement for Licensed Product
28303 + * with Synopsys or any supplement thereto. You are permitted to use and
28304 + * redistribute this Software in source and binary forms, with or without
28305 + * modification, provided that redistributions of source code must retain this
28306 + * notice. You may not view, use, disclose, copy or distribute this file or
28307 + * any information contained herein except pursuant to this license grant from
28308 + * Synopsys. If you do not agree with this notice, including the disclaimer
28309 + * below, then you are not authorized to use the Software.
28311 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
28312 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28313 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28314 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
28315 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28316 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28317 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28318 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28319 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28320 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28322 + * ========================================================================== */
28324 +#if !defined(__DWC_CIL_H__)
28325 +#define __DWC_CIL_H__
28327 +#include "dwc_list.h"
28328 +#include "dwc_otg_dbg.h"
28329 +#include "dwc_otg_regs.h"
28331 +#include "dwc_otg_core_if.h"
28332 +#include "dwc_otg_adp.h"
28336 + * This file contains the interface to the Core Interface Layer.
28339 +#ifdef DWC_UTE_CFI
28341 +#define MAX_DMA_DESCS_PER_EP 256
28344 + * Enumeration for the data buffer mode
28346 +typedef enum _data_buffer_mode {
28347 + BM_STANDARD = 0, /* data buffer is in normal mode */
28348 + BM_SG = 1, /* data buffer uses the scatter/gather mode */
28349 + BM_CONCAT = 2, /* data buffer uses the concatenation mode */
28350 + BM_CIRCULAR = 3, /* data buffer uses the circular DMA mode */
28351 + BM_ALIGN = 4 /* data buffer is in buffer alignment mode */
28352 +} data_buffer_mode_e;
28353 +#endif //DWC_UTE_CFI
28355 +/** Macros defined for DWC OTG HW Release version */
28357 +#define OTG_CORE_REV_2_60a 0x4F54260A
28358 +#define OTG_CORE_REV_2_71a 0x4F54271A
28359 +#define OTG_CORE_REV_2_72a 0x4F54272A
28360 +#define OTG_CORE_REV_2_80a 0x4F54280A
28361 +#define OTG_CORE_REV_2_81a 0x4F54281A
28362 +#define OTG_CORE_REV_2_90a 0x4F54290A
28363 +#define OTG_CORE_REV_2_91a 0x4F54291A
28364 +#define OTG_CORE_REV_2_92a 0x4F54292A
28365 +#define OTG_CORE_REV_2_93a 0x4F54293A
28366 +#define OTG_CORE_REV_2_94a 0x4F54294A
28367 +#define OTG_CORE_REV_3_00a 0x4F54300A
28370 + * Information for each ISOC packet.
28372 +typedef struct iso_pkt_info {
28379 + * The <code>dwc_ep</code> structure represents the state of a single
28380 + * endpoint when acting in device mode. It contains the data items
28381 + * needed for an endpoint to be activated and transfer packets.
28383 +typedef struct dwc_ep {
28384 + /** EP number used for register address lookup */
28386 + /** EP direction 0 = OUT */
28387 + unsigned is_in:1;
28388 + /** EP active. */
28389 + unsigned active:1;
28392 + * Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic
28393 + * Tx FIFO. If dedicated Tx FIFOs are enabled Tx FIFO # FOR IN EPs*/
28394 + unsigned tx_fifo_num:4;
28395 + /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */
28397 +#define DWC_OTG_EP_TYPE_CONTROL 0
28398 +#define DWC_OTG_EP_TYPE_ISOC 1
28399 +#define DWC_OTG_EP_TYPE_BULK 2
28400 +#define DWC_OTG_EP_TYPE_INTR 3
28402 + /** DATA start PID for INTR and BULK EP */
28403 + unsigned data_pid_start:1;
28404 + /** Frame (even/odd) for ISOC EP */
28405 + unsigned even_odd_frame:1;
28406 + /** Max Packet bytes */
28407 + unsigned maxpacket:11;
28409 + /** Max Transfer size */
28410 + uint32_t maxxfer;
28412 + /** @name Transfer state */
28416 + * Pointer to the beginning of the transfer buffer -- do not modify
28417 + * during transfer.
28420 + dwc_dma_t dma_addr;
28422 + dwc_dma_t dma_desc_addr;
28423 + dwc_otg_dev_dma_desc_t *desc_addr;
28425 + uint8_t *start_xfer_buff;
28426 + /** pointer to the transfer buffer */
28427 + uint8_t *xfer_buff;
28428 + /** Number of bytes to transfer */
28429 + unsigned xfer_len:19;
28430 + /** Number of bytes transferred. */
28431 + unsigned xfer_count:19;
28433 + unsigned sent_zlp:1;
28434 + /** Total len for control transfer */
28435 + unsigned total_len:19;
28437 + /** stall clear flag */
28438 + unsigned stall_clear_flag:1;
28440 + /** SETUP pkt cnt rollover flag for EP0 out*/
28441 + unsigned stp_rollover;
28443 +#ifdef DWC_UTE_CFI
28444 + /* The buffer mode */
28445 + data_buffer_mode_e buff_mode;
28447 + /* The chain of DMA descriptors.
28448 + * MAX_DMA_DESCS_PER_EP will be allocated for each active EP.
28450 + dwc_otg_dma_desc_t *descs;
28452 + /* The DMA address of the descriptors chain start */
28453 + dma_addr_t descs_dma_addr;
28454 + /** This variable stores the length of the last enqueued request */
28455 + uint32_t cfi_req_len;
28456 +#endif //DWC_UTE_CFI
28458 +/** Max DMA Descriptor count for any EP */
28459 +#define MAX_DMA_DESC_CNT 256
28460 + /** Allocated DMA Desc count */
28461 + uint32_t desc_cnt;
28464 + uint32_t bInterval;
28465 + /** Next frame num to setup next ISOC transfer */
28466 + uint32_t frame_num;
28467 + /** Indicates SOF number overrun in DSTS */
28468 + uint8_t frm_overrun;
28470 +#ifdef DWC_UTE_PER_IO
28471 + /** Next frame num for which will be setup DMA Desc */
28472 + uint32_t xiso_frame_num;
28474 + uint32_t xiso_bInterval;
28475 + /** Count of currently active transfers - shall be either 0 or 1 */
28476 + int xiso_active_xfers;
28477 + int xiso_queued_xfers;
28479 +#ifdef DWC_EN_ISOC
28481 + * Variables specific for ISOC EPs
28484 + /** DMA addresses of ISOC buffers */
28485 + dwc_dma_t dma_addr0;
28486 + dwc_dma_t dma_addr1;
28488 + dwc_dma_t iso_dma_desc_addr;
28489 + dwc_otg_dev_dma_desc_t *iso_desc_addr;
28491 + /** pointer to the transfer buffers */
28492 + uint8_t *xfer_buff0;
28493 + uint8_t *xfer_buff1;
28495 + /** number of ISOC Buffer is processing */
28496 + uint32_t proc_buf_num;
28497 + /** Interval of ISOC Buffer processing */
28498 + uint32_t buf_proc_intrvl;
28499 + /** Data size for regular frame */
28500 + uint32_t data_per_frame;
28502 + /* todo - pattern data support is to be implemented in the future */
28503 + /** Data size for pattern frame */
28504 + uint32_t data_pattern_frame;
28505 + /** Frame number of pattern data */
28506 + uint32_t sync_frame;
28509 + uint32_t bInterval;
28510 + /** ISO Packet number per frame */
28511 + uint32_t pkt_per_frm;
28512 + /** Next frame num for which will be setup DMA Desc */
28513 + uint32_t next_frame;
28514 + /** Number of packets per buffer processing */
28515 + uint32_t pkt_cnt;
28516 + /** Info for all isoc packets */
28517 + iso_pkt_info_t *pkt_info;
28518 + /** current pkt number */
28519 + uint32_t cur_pkt;
28520 + /** current pkt number */
28521 + uint8_t *cur_pkt_addr;
28522 + /** current pkt number */
28523 + uint32_t cur_pkt_dma_addr;
28524 +#endif /* DWC_EN_ISOC */
28530 + * Reasons for halting a host channel.
28532 +typedef enum dwc_otg_halt_status {
28533 + DWC_OTG_HC_XFER_NO_HALT_STATUS,
28534 + DWC_OTG_HC_XFER_COMPLETE,
28535 + DWC_OTG_HC_XFER_URB_COMPLETE,
28536 + DWC_OTG_HC_XFER_ACK,
28537 + DWC_OTG_HC_XFER_NAK,
28538 + DWC_OTG_HC_XFER_NYET,
28539 + DWC_OTG_HC_XFER_STALL,
28540 + DWC_OTG_HC_XFER_XACT_ERR,
28541 + DWC_OTG_HC_XFER_FRAME_OVERRUN,
28542 + DWC_OTG_HC_XFER_BABBLE_ERR,
28543 + DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
28544 + DWC_OTG_HC_XFER_AHB_ERR,
28545 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
28546 + DWC_OTG_HC_XFER_URB_DEQUEUE
28547 +} dwc_otg_halt_status_e;
28550 + * Host channel descriptor. This structure represents the state of a single
28551 + * host channel when acting in host mode. It contains the data items needed to
28552 + * transfer packets to an endpoint via a host channel.
28554 +typedef struct dwc_hc {
28555 + /** Host channel number used for register address lookup */
28558 + /** Device to access */
28559 + unsigned dev_addr:7;
28561 + /** EP to access */
28562 + unsigned ep_num:4;
28564 + /** EP direction. 0: OUT, 1: IN */
28565 + unsigned ep_is_in:1;
28569 + * One of the following values:
28570 + * - DWC_OTG_EP_SPEED_LOW
28571 + * - DWC_OTG_EP_SPEED_FULL
28572 + * - DWC_OTG_EP_SPEED_HIGH
28574 + unsigned speed:2;
28575 +#define DWC_OTG_EP_SPEED_LOW 0
28576 +#define DWC_OTG_EP_SPEED_FULL 1
28577 +#define DWC_OTG_EP_SPEED_HIGH 2
28581 + * One of the following values:
28582 + * - DWC_OTG_EP_TYPE_CONTROL: 0
28583 + * - DWC_OTG_EP_TYPE_ISOC: 1
28584 + * - DWC_OTG_EP_TYPE_BULK: 2
28585 + * - DWC_OTG_EP_TYPE_INTR: 3
28587 + unsigned ep_type:2;
28589 + /** Max packet size in bytes */
28590 + unsigned max_packet:11;
28593 + * PID for initial transaction.
28597 + * 3: MDATA (non-Control EP),
28598 + * SETUP (Control EP)
28600 + unsigned data_pid_start:2;
28601 +#define DWC_OTG_HC_PID_DATA0 0
28602 +#define DWC_OTG_HC_PID_DATA2 1
28603 +#define DWC_OTG_HC_PID_DATA1 2
28604 +#define DWC_OTG_HC_PID_MDATA 3
28605 +#define DWC_OTG_HC_PID_SETUP 3
28607 + /** Number of periodic transactions per (micro)frame */
28608 + unsigned multi_count:2;
28610 + /** @name Transfer State */
28613 + /** Pointer to the current transfer buffer position. */
28614 + uint8_t *xfer_buff;
28616 + * In Buffer DMA mode this buffer will be used
28617 + * if xfer_buff is not DWORD aligned.
28619 + dwc_dma_t align_buff;
28620 + /** Total number of bytes to transfer. */
28621 + uint32_t xfer_len;
28622 + /** Number of bytes transferred so far. */
28623 + uint32_t xfer_count;
28624 + /** Packet count at start of transfer.*/
28625 + uint16_t start_pkt_count;
28628 + * Flag to indicate whether the transfer has been started. Set to 1 if
28629 + * it has been started, 0 otherwise.
28631 + uint8_t xfer_started;
28634 + * Set to 1 to indicate that a PING request should be issued on this
28635 + * channel. If 0, process normally.
28640 + * Set to 1 to indicate that the error count for this transaction is
28641 + * non-zero. Set to 0 if the error count is 0.
28643 + uint8_t error_state;
28646 + * Set to 1 to indicate that this channel should be halted the next
28647 + * time a request is queued for the channel. This is necessary in
28648 + * slave mode if no request queue space is available when an attempt
28649 + * is made to halt the channel.
28651 + uint8_t halt_on_queue;
28654 + * Set to 1 if the host channel has been halted, but the core is not
28655 + * finished flushing queued requests. Otherwise 0.
28657 + uint8_t halt_pending;
28660 + * Reason for halting the host channel.
28662 + dwc_otg_halt_status_e halt_status;
28665 + * Split settings for the host channel
28667 + uint8_t do_split; /**< Enable split for the channel */
28668 + uint8_t complete_split; /**< Enable complete split */
28669 + uint8_t hub_addr; /**< Address of high speed hub */
28671 + uint8_t port_addr; /**< Port of the low/full speed device */
28672 + /** Split transaction position
28673 + * One of the following values:
28674 + * - DWC_HCSPLIT_XACTPOS_MID
28675 + * - DWC_HCSPLIT_XACTPOS_BEGIN
28676 + * - DWC_HCSPLIT_XACTPOS_END
28677 + * - DWC_HCSPLIT_XACTPOS_ALL */
28678 + uint8_t xact_pos;
28680 + /** Set when the host channel does a short read. */
28681 + uint8_t short_read;
28684 + * Number of requests issued for this channel since it was assigned to
28685 + * the current transfer (not counting PINGs).
28687 + uint8_t requests;
28690 + * Queue Head for the transfer being processed by this channel.
28692 + struct dwc_otg_qh *qh;
28696 + /** Entry in list of host channels. */
28697 + DWC_CIRCLEQ_ENTRY(dwc_hc) hc_list_entry;
28699 + /** @name Descriptor DMA support */
28702 + /** Number of Transfer Descriptors */
28705 + /** Descriptor List DMA address */
28706 + dwc_dma_t desc_list_addr;
28708 + /** Scheduling micro-frame bitmap. */
28715 + * The following parameters may be specified when starting the module. These
28716 + * parameters define how the DWC_otg controller should be configured.
28718 +typedef struct dwc_otg_core_params {
28722 + * Specifies the OTG capabilities. The driver will automatically
28723 + * detect the value for this parameter if none is specified.
28724 + * 0 - HNP and SRP capable (default)
28725 + * 1 - SRP Only capable
28726 + * 2 - No HNP/SRP capable
28731 + * Specifies whether to use slave or DMA mode for accessing the data
28732 + * FIFOs. The driver will automatically detect the value for this
28733 + * parameter if none is specified.
28735 + * 1 - DMA (default, if available)
28737 + int32_t dma_enable;
28740 + * When DMA mode is enabled specifies whether to use address DMA or DMA
28741 + * Descriptor mode for accessing the data FIFOs in device mode. The driver
28742 + * will automatically detect the value for this if none is specified.
28743 + * 0 - address DMA
28744 + * 1 - DMA Descriptor(default, if available)
28746 + int32_t dma_desc_enable;
28747 + /** The DMA Burst size (applicable only for External DMA
28748 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
28750 + int32_t dma_burst_size; /* Translate this to GAHBCFG values */
28753 + * Specifies the maximum speed of operation in host and device mode.
28754 + * The actual speed depends on the speed of the attached device and
28755 + * the value of phy_type. The actual speed depends on the speed of the
28756 + * attached device.
28757 + * 0 - High Speed (default)
28761 + /** Specifies whether low power mode is supported when attached
28762 + * to a Full Speed or Low Speed device in host mode.
28763 + * 0 - Don't support low power mode (default)
28764 + * 1 - Support low power mode
28766 + int32_t host_support_fs_ls_low_power;
28768 + /** Specifies the PHY clock rate in low power mode when connected to a
28769 + * Low Speed device in host mode. This parameter is applicable only if
28770 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
28771 + * then defaults to 6 MHZ otherwise 48 MHZ.
28776 + int32_t host_ls_low_power_phy_clk;
28779 + * 0 - Use cC FIFO size parameters
28780 + * 1 - Allow dynamic FIFO sizing (default)
28782 + int32_t enable_dynamic_fifo;
28784 + /** Total number of 4-byte words in the data FIFO memory. This
28785 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
28787 + * 32 to 32768 (default 8192)
28788 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
28790 + int32_t data_fifo_size;
28792 + /** Number of 4-byte words in the Rx FIFO in device mode when dynamic
28793 + * FIFO sizing is enabled.
28794 + * 16 to 32768 (default 1064)
28796 + int32_t dev_rx_fifo_size;
28798 + /** Number of 4-byte words in the non-periodic Tx FIFO in device mode
28799 + * when dynamic FIFO sizing is enabled.
28800 + * 16 to 32768 (default 1024)
28802 + int32_t dev_nperio_tx_fifo_size;
28804 + /** Number of 4-byte words in each of the periodic Tx FIFOs in device
28805 + * mode when dynamic FIFO sizing is enabled.
28806 + * 4 to 768 (default 256)
28808 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
28810 + /** Number of 4-byte words in the Rx FIFO in host mode when dynamic
28811 + * FIFO sizing is enabled.
28812 + * 16 to 32768 (default 1024)
28814 + int32_t host_rx_fifo_size;
28816 + /** Number of 4-byte words in the non-periodic Tx FIFO in host mode
28817 + * when Dynamic FIFO sizing is enabled in the core.
28818 + * 16 to 32768 (default 1024)
28820 + int32_t host_nperio_tx_fifo_size;
28822 + /** Number of 4-byte words in the host periodic Tx FIFO when dynamic
28823 + * FIFO sizing is enabled.
28824 + * 16 to 32768 (default 1024)
28826 + int32_t host_perio_tx_fifo_size;
28828 + /** The maximum transfer size supported in bytes.
28829 + * 2047 to 65,535 (default 65,535)
28831 + int32_t max_transfer_size;
28833 + /** The maximum number of packets in a transfer.
28834 + * 15 to 511 (default 511)
28836 + int32_t max_packet_count;
28838 + /** The number of host channel registers to use.
28839 + * 1 to 16 (default 12)
28840 + * Note: The FPGA configuration supports a maximum of 12 host channels.
28842 + int32_t host_channels;
28844 + /** The number of endpoints in addition to EP0 available for device
28845 + * mode operations.
28846 + * 1 to 15 (default 6 IN and OUT)
28847 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
28848 + * endpoints in addition to EP0.
28850 + int32_t dev_endpoints;
28853 + * Specifies the type of PHY interface to use. By default, the driver
28854 + * will automatically detect the phy_type.
28856 + * 0 - Full Speed PHY
28857 + * 1 - UTMI+ (default)
28860 + int32_t phy_type;
28863 + * Specifies the UTMI+ Data Width. This parameter is
28864 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
28865 + * PHY_TYPE, this parameter indicates the data width between
28866 + * the MAC and the ULPI Wrapper.) Also, this parameter is
28867 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
28868 + * to "8 and 16 bits", meaning that the core has been
28869 + * configured to work at either data path width.
28871 + * 8 or 16 bits (default 16)
28873 + int32_t phy_utmi_width;
28876 + * Specifies whether the ULPI operates at double or single
28877 + * data rate. This parameter is only applicable if PHY_TYPE is
28880 + * 0 - single data rate ULPI interface with 8 bit wide data
28882 + * 1 - double data rate ULPI interface with 4 bit wide data
28885 + int32_t phy_ulpi_ddr;
28888 + * Specifies whether to use the internal or external supply to
28889 + * drive the vbus with a ULPI phy.
28891 + int32_t phy_ulpi_ext_vbus;
28894 + * Specifies whether to use the I2Cinterface for full speed PHY. This
28895 + * parameter is only applicable if PHY_TYPE is FS.
28896 + * 0 - No (default)
28899 + int32_t i2c_enable;
28901 + int32_t ulpi_fs_ls;
28903 + int32_t ts_dline;
28906 + * Specifies whether dedicated transmit FIFOs are
28907 + * enabled for non periodic IN endpoints in device mode
28911 + int32_t en_multiple_tx_fifo;
28913 + /** Number of 4-byte words in each of the Tx FIFOs in device
28914 + * mode when dynamic FIFO sizing is enabled.
28915 + * 4 to 768 (default 256)
28917 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
28919 + /** Thresholding enable flag-
28920 + * bit 0 - enable non-ISO Tx thresholding
28921 + * bit 1 - enable ISO Tx thresholding
28922 + * bit 2 - enable Rx thresholding
28924 + uint32_t thr_ctl;
28926 + /** Thresholding length for Tx
28927 + * FIFOs in 32 bit DWORDs
28929 + uint32_t tx_thr_length;
28931 + /** Thresholding length for Rx
28932 + * FIFOs in 32 bit DWORDs
28934 + uint32_t rx_thr_length;
28937 + * Specifies whether LPM (Link Power Management) support is enabled
28939 + int32_t lpm_enable;
28941 + /** Per Transfer Interrupt
28942 + * mode enable flag
28946 + int32_t pti_enable;
28948 + /** Multi Processor Interrupt
28949 + * mode enable flag
28953 + int32_t mpi_enable;
28955 + /** IS_USB Capability
28959 + int32_t ic_usb_cap;
28961 + /** AHB Threshold Ratio
28962 + * 2'b00 AHB Threshold = MAC Threshold
28963 + * 2'b01 AHB Threshold = 1/2 MAC Threshold
28964 + * 2'b10 AHB Threshold = 1/4 MAC Threshold
28965 + * 2'b11 AHB Threshold = 1/8 MAC Threshold
28967 + int32_t ahb_thr_ratio;
28973 + int32_t adp_supp_enable;
28975 + /** HFIR Reload Control
28976 + * 0 - The HFIR cannot be reloaded dynamically.
28977 + * 1 - Allow dynamic reloading of the HFIR register during runtime.
28979 + int32_t reload_ctl;
28981 + /** DCFG: Enable device Out NAK
28982 + * 0 - The core does not set NAK after Bulk Out transfer complete.
28983 + * 1 - The core sets NAK after Bulk OUT transfer complete.
28985 + int32_t dev_out_nak;
28987 + /** DCFG: Enable Continue on BNA
28988 + * After receiving BNA interrupt the core disables the endpoint,when the
28989 + * endpoint is re-enabled by the application the core starts processing
28990 + * 0 - from the DOEPDMA descriptor
28991 + * 1 - from the descriptor which received the BNA.
28993 + int32_t cont_on_bna;
28995 + /** GAHBCFG: AHB Single Support
28996 + * This bit when programmed supports SINGLE transfers for remainder
28997 + * data in a transfer for DMA mode of operation.
28998 + * 0 - in this case the remainder data will be sent using INCR burst size.
28999 + * 1 - in this case the remainder data will be sent using SINGLE burst size.
29001 + int32_t ahb_single;
29003 + /** Core Power down mode
29004 + * 0 - No Power Down is enabled
29006 + * 2 - Complete Power Down (Hibernation)
29008 + int32_t power_down;
29010 + /** OTG revision supported
29011 + * 0 - OTG 1.3 revision
29012 + * 1 - OTG 2.0 revision
29016 +} dwc_otg_core_params_t;
29019 +struct dwc_otg_core_if;
29020 +typedef struct hc_xfer_info {
29021 + struct dwc_otg_core_if *core_if;
29026 +typedef struct ep_xfer_info {
29027 + struct dwc_otg_core_if *core_if;
29034 +typedef enum dwc_otg_lx_state {
29037 + /** LPM sleep state*/
29039 + /** USB suspend state*/
29043 +} dwc_otg_lx_state_e;
29045 +struct dwc_otg_global_regs_backup {
29046 + uint32_t gotgctl_local;
29047 + uint32_t gintmsk_local;
29048 + uint32_t gahbcfg_local;
29049 + uint32_t gusbcfg_local;
29050 + uint32_t grxfsiz_local;
29051 + uint32_t gnptxfsiz_local;
29052 +#ifdef CONFIG_USB_DWC_OTG_LPM
29053 + uint32_t glpmcfg_local;
29055 + uint32_t gi2cctl_local;
29056 + uint32_t hptxfsiz_local;
29057 + uint32_t pcgcctl_local;
29058 + uint32_t gdfifocfg_local;
29059 + uint32_t dtxfsiz_local[MAX_EPS_CHANNELS];
29060 + uint32_t gpwrdn_local;
29061 + uint32_t xhib_pcgcctl;
29062 + uint32_t xhib_gpwrdn;
29065 +struct dwc_otg_host_regs_backup {
29066 + uint32_t hcfg_local;
29067 + uint32_t haintmsk_local;
29068 + uint32_t hcintmsk_local[MAX_EPS_CHANNELS];
29069 + uint32_t hprt0_local;
29070 + uint32_t hfir_local;
29073 +struct dwc_otg_dev_regs_backup {
29076 + uint32_t daintmsk;
29077 + uint32_t diepmsk;
29078 + uint32_t doepmsk;
29079 + uint32_t diepctl[MAX_EPS_CHANNELS];
29080 + uint32_t dieptsiz[MAX_EPS_CHANNELS];
29081 + uint32_t diepdma[MAX_EPS_CHANNELS];
29084 + * The <code>dwc_otg_core_if</code> structure contains information needed to manage
29085 + * the DWC_otg controller acting in either host or device mode. It
29086 + * represents the programming view of the controller as a whole.
29088 +struct dwc_otg_core_if {
29089 + /** Parameters that define how the core should be configured.*/
29090 + dwc_otg_core_params_t *core_params;
29092 + /** Core Global registers starting at offset 000h. */
29093 + dwc_otg_core_global_regs_t *core_global_regs;
29095 + /** Device-specific information */
29096 + dwc_otg_dev_if_t *dev_if;
29097 + /** Host-specific information */
29098 + dwc_otg_host_if_t *host_if;
29100 + /** Value from SNPSID register */
29104 + * Set to 1 if the core PHY interface bits in USBCFG have been
29107 + uint8_t phy_init_done;
29110 + * SRP Success flag, set by srp success interrupt in FS I2C mode
29112 + uint8_t srp_success;
29113 + uint8_t srp_timer_started;
29114 + /** Timer for SRP. If it expires before SRP is successful
29115 + * clear the SRP. */
29116 + dwc_timer_t *srp_timer;
29118 +#ifdef DWC_DEV_SRPCAP
29119 + /* This timer is needed to power on the hibernated host core if SRP is not
29120 + * initiated on connected SRP capable device for limited period of time
29122 + uint8_t pwron_timer_started;
29123 + dwc_timer_t *pwron_timer;
29125 + /* Common configuration information */
29126 + /** Power and Clock Gating Control Register */
29127 + volatile uint32_t *pcgcctl;
29128 +#define DWC_OTG_PCGCCTL_OFFSET 0xE00
29130 + /** Push/pop addresses for endpoints or host channels.*/
29131 + uint32_t *data_fifo[MAX_EPS_CHANNELS];
29132 +#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
29133 +#define DWC_OTG_DATA_FIFO_SIZE 0x1000
29135 + /** Total RAM for FIFOs (Bytes) */
29136 + uint16_t total_fifo_size;
29137 + /** Size of Rx FIFO (Bytes) */
29138 + uint16_t rx_fifo_size;
29139 + /** Size of Non-periodic Tx FIFO (Bytes) */
29140 + uint16_t nperio_tx_fifo_size;
29142 + /** 1 if DMA is enabled, 0 otherwise. */
29143 + uint8_t dma_enable;
29145 + /** 1 if DMA descriptor is enabled, 0 otherwise. */
29146 + uint8_t dma_desc_enable;
29148 + /** 1 if PTI Enhancement mode is enabled, 0 otherwise. */
29149 + uint8_t pti_enh_enable;
29151 + /** 1 if MPI Enhancement mode is enabled, 0 otherwise. */
29152 + uint8_t multiproc_int_enable;
29154 + /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */
29155 + uint8_t en_multiple_tx_fifo;
29157 + /** Set to 1 if multiple packets of a high-bandwidth transfer is in
29158 + * process of being queued */
29159 + uint8_t queuing_high_bandwidth;
29161 + /** Hardware Configuration -- stored here for convenience.*/
29162 + hwcfg1_data_t hwcfg1;
29163 + hwcfg2_data_t hwcfg2;
29164 + hwcfg3_data_t hwcfg3;
29165 + hwcfg4_data_t hwcfg4;
29166 + fifosize_data_t hptxfsiz;
29168 + /** Host and Device Configuration -- stored here for convenience.*/
29169 + hcfg_data_t hcfg;
29170 + dcfg_data_t dcfg;
29172 + /** The operational State, during transations
29173 + * (a_host>>a_peripherial and b_device=>b_host) this may not
29174 + * match the core but allows the software to determine
29177 + uint8_t op_state;
29180 + * Set to 1 if the HCD needs to be restarted on a session request
29181 + * interrupt. This is required if no connector ID status change has
29182 + * occurred since the HCD was last disconnected.
29184 + uint8_t restart_hcd_on_session_req;
29186 + /** HCD callbacks */
29187 + /** A-Device is a_host */
29188 +#define A_HOST (1)
29189 + /** A-Device is a_suspend */
29190 +#define A_SUSPEND (2)
29191 + /** A-Device is a_peripherial */
29192 +#define A_PERIPHERAL (3)
29193 + /** B-Device is operating as a Peripheral. */
29194 +#define B_PERIPHERAL (4)
29195 + /** B-Device is operating as a Host. */
29196 +#define B_HOST (5)
29198 + /** HCD callbacks */
29199 + struct dwc_otg_cil_callbacks *hcd_cb;
29200 + /** PCD callbacks */
29201 + struct dwc_otg_cil_callbacks *pcd_cb;
29203 + /** Device mode Periodic Tx FIFO Mask */
29204 + uint32_t p_tx_msk;
29205 + /** Device mode Periodic Tx FIFO Mask */
29208 + /** Workqueue object used for handling several interrupts */
29209 + dwc_workq_t *wq_otg;
29211 + /** Timer object used for handling "Wakeup Detected" Interrupt */
29212 + dwc_timer_t *wkp_timer;
29213 + /** This arrays used for debug purposes for DEV OUT NAK enhancement */
29214 + uint32_t start_doeptsiz_val[MAX_EPS_CHANNELS];
29215 + ep_xfer_info_t ep_xfer_info[MAX_EPS_CHANNELS];
29216 + dwc_timer_t *ep_xfer_timer[MAX_EPS_CHANNELS];
29218 + uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
29220 + hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS];
29221 + dwc_timer_t *hc_xfer_timer[MAX_EPS_CHANNELS];
29223 + uint32_t hfnum_7_samples;
29224 + uint64_t hfnum_7_frrem_accum;
29225 + uint32_t hfnum_0_samples;
29226 + uint64_t hfnum_0_frrem_accum;
29227 + uint32_t hfnum_other_samples;
29228 + uint64_t hfnum_other_frrem_accum;
29231 +#ifdef DWC_UTE_CFI
29232 + uint16_t pwron_rxfsiz;
29233 + uint16_t pwron_gnptxfsiz;
29234 + uint16_t pwron_txfsiz[15];
29236 + uint16_t init_rxfsiz;
29237 + uint16_t init_gnptxfsiz;
29238 + uint16_t init_txfsiz[15];
29241 + /** Lx state of device */
29242 + dwc_otg_lx_state_e lx_state;
29244 + /** Saved Core Global registers */
29245 + struct dwc_otg_global_regs_backup *gr_backup;
29246 + /** Saved Host registers */
29247 + struct dwc_otg_host_regs_backup *hr_backup;
29248 + /** Saved Device registers */
29249 + struct dwc_otg_dev_regs_backup *dr_backup;
29251 + /** Power Down Enable */
29252 + uint32_t power_down;
29254 + /** ADP support Enable */
29255 + uint32_t adp_enable;
29257 + /** ADP structure object */
29258 + dwc_otg_adp_t adp;
29260 + /** hibernation/suspend flag */
29261 + int hibernation_suspend;
29263 + /** Device mode extended hibernation flag */
29266 + /** OTG revision supported */
29267 + uint32_t otg_ver;
29269 + /** OTG status flag used for HNP polling */
29272 + /** Pointer to either hcd->lock or pcd->lock */
29273 + dwc_spinlock_t *lock;
29275 + /** Start predict NextEP based on Learning Queue if equal 1,
29276 + * also used as counter of disabled NP IN EP's */
29277 + uint8_t start_predict;
29279 + /** NextEp sequence, including EP0: nextep_seq[] = EP if non-periodic and
29280 + * active, 0xff otherwise */
29281 + uint8_t nextep_seq[MAX_EPS_CHANNELS];
29283 + /** Index of fisrt EP in nextep_seq array which should be re-enabled **/
29284 + uint8_t first_in_nextep_seq;
29286 + /** Frame number while entering to ISR - needed for ISOCs **/
29287 + uint32_t frame_num;
29293 + * This function is called when transfer is timed out.
29295 +extern void hc_xfer_timeout(void *ptr);
29299 + * This function is called when transfer is timed out on endpoint.
29301 +extern void ep_xfer_timeout(void *ptr);
29304 + * The following functions are functions for works
29305 + * using during handling some interrupts
29307 +extern void w_conn_id_status_change(void *p);
29309 +extern void w_wakeup_detected(void *p);
29311 +/** Saves global register values into system memory. */
29312 +extern int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if);
29313 +/** Saves device register values into system memory. */
29314 +extern int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if);
29315 +/** Saves host register values into system memory. */
29316 +extern int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if);
29317 +/** Restore global register values. */
29318 +extern int dwc_otg_restore_global_regs(dwc_otg_core_if_t * core_if);
29319 +/** Restore host register values. */
29320 +extern int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset);
29321 +/** Restore device register values. */
29322 +extern int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if,
29324 +extern int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if);
29325 +extern int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode,
29328 +extern int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
29329 + int restore_mode, int reset);
29330 +extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
29331 + int rem_wakeup, int reset);
29334 + * The following functions support initialization of the CIL driver component
29335 + * and the DWC_otg controller.
29337 +extern void dwc_otg_core_host_init(dwc_otg_core_if_t * _core_if);
29338 +extern void dwc_otg_core_dev_init(dwc_otg_core_if_t * _core_if);
29340 +/** @name Device CIL Functions
29341 + * The following functions support managing the DWC_otg controller in device
29345 +extern void dwc_otg_wakeup(dwc_otg_core_if_t * _core_if);
29346 +extern void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if,
29347 + uint32_t * _dest);
29348 +extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if);
29349 +extern void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29350 +extern void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29351 +extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29352 +extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if,
29354 +extern void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * _core_if,
29356 +extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * _core_if,
29358 +extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * _core_if,
29360 +extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t * _core_if,
29361 + dwc_ep_t * _ep, int _dma);
29362 +extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
29363 +extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * _core_if,
29365 +extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * _core_if);
29367 +#ifdef DWC_EN_ISOC
29368 +extern void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
29370 +extern void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
29372 +#endif /* DWC_EN_ISOC */
29375 +/** @name Host CIL Functions
29376 + * The following functions support managing the DWC_otg controller in host
29380 +extern void dwc_otg_hc_init(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29381 +extern void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if,
29382 + dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status);
29383 +extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29384 +extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if,
29386 +extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if,
29388 +extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
29389 +extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if,
29391 +extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * _core_if);
29392 +extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * _core_if);
29394 +extern void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if,
29397 +extern uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if);
29399 +/* Macro used to clear one channel interrupt */
29400 +#define clear_hc_int(_hc_regs_, _intr_) \
29402 + hcint_data_t hcint_clear = {.d32 = 0}; \
29403 + hcint_clear.b._intr_ = 1; \
29404 + DWC_WRITE_REG32(&(_hc_regs_)->hcint, hcint_clear.d32); \
29408 + * Macro used to disable one channel interrupt. Channel interrupts are
29409 + * disabled when the channel is halted or released by the interrupt handler.
29410 + * There is no need to handle further interrupts of that type until the
29411 + * channel is re-assigned. In fact, subsequent handling may cause crashes
29412 + * because the channel structures are cleaned up when the channel is released.
29414 +#define disable_hc_int(_hc_regs_, _intr_) \
29416 + hcintmsk_data_t hcintmsk = {.d32 = 0}; \
29417 + hcintmsk.b._intr_ = 1; \
29418 + DWC_MODIFY_REG32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \
29422 + * This function Reads HPRT0 in preparation to modify. It keeps the
29423 + * WC bits 0 so that if they are read as 1, they won't clear when you
29426 +static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t * _core_if)
29428 + hprt0_data_t hprt0;
29429 + hprt0.d32 = DWC_READ_REG32(_core_if->host_if->hprt0);
29430 + hprt0.b.prtena = 0;
29431 + hprt0.b.prtconndet = 0;
29432 + hprt0.b.prtenchng = 0;
29433 + hprt0.b.prtovrcurrchng = 0;
29434 + return hprt0.d32;
29439 +/** @name Common CIL Functions
29440 + * The following functions support managing the DWC_otg controller in either
29441 + * device or host mode.
29445 +extern void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
29446 + uint8_t * dest, uint16_t bytes);
29448 +extern void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * _core_if, const int _num);
29449 +extern void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * _core_if);
29450 +extern void dwc_otg_core_reset(dwc_otg_core_if_t * _core_if);
29453 + * This function returns the Core Interrupt register.
29455 +static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t * core_if)
29457 + return (DWC_READ_REG32(&core_if->core_global_regs->gintsts) &
29458 + DWC_READ_REG32(&core_if->core_global_regs->gintmsk));
29462 + * This function returns the OTG Interrupt register.
29464 +static inline uint32_t dwc_otg_read_otg_intr(dwc_otg_core_if_t * core_if)
29466 + return (DWC_READ_REG32(&core_if->core_global_regs->gotgint));
29470 + * This function reads the Device All Endpoints Interrupt register and
29471 + * returns the IN endpoint interrupt bits.
29473 +static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *
29479 + if (core_if->multiproc_int_enable) {
29480 + v = DWC_READ_REG32(&core_if->dev_if->
29481 + dev_global_regs->deachint) &
29482 + DWC_READ_REG32(&core_if->
29483 + dev_if->dev_global_regs->deachintmsk);
29485 + v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
29486 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
29488 + return (v & 0xffff);
29492 + * This function reads the Device All Endpoints Interrupt register and
29493 + * returns the OUT endpoint interrupt bits.
29495 +static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *
29500 + if (core_if->multiproc_int_enable) {
29501 + v = DWC_READ_REG32(&core_if->dev_if->
29502 + dev_global_regs->deachint) &
29503 + DWC_READ_REG32(&core_if->
29504 + dev_if->dev_global_regs->deachintmsk);
29506 + v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
29507 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
29510 + return ((v & 0xffff0000) >> 16);
29514 + * This function returns the Device IN EP Interrupt register
29516 +static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t * core_if,
29519 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
29520 + uint32_t v, msk, emp;
29522 + if (core_if->multiproc_int_enable) {
29524 + DWC_READ_REG32(&dev_if->
29525 + dev_global_regs->diepeachintmsk[ep->num]);
29527 + DWC_READ_REG32(&dev_if->
29528 + dev_global_regs->dtknqr4_fifoemptymsk);
29529 + msk |= ((emp >> ep->num) & 0x1) << 7;
29530 + v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
29532 + msk = DWC_READ_REG32(&dev_if->dev_global_regs->diepmsk);
29534 + DWC_READ_REG32(&dev_if->
29535 + dev_global_regs->dtknqr4_fifoemptymsk);
29536 + msk |= ((emp >> ep->num) & 0x1) << 7;
29537 + v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
29544 + * This function returns the Device OUT EP Interrupt register
29546 +static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *
29547 + _core_if, dwc_ep_t * _ep)
29549 + dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
29551 + doepmsk_data_t msk = {.d32 = 0 };
29553 + if (_core_if->multiproc_int_enable) {
29555 + DWC_READ_REG32(&dev_if->
29556 + dev_global_regs->doepeachintmsk[_ep->num]);
29557 + if (_core_if->pti_enh_enable) {
29558 + msk.b.pktdrpsts = 1;
29560 + v = DWC_READ_REG32(&dev_if->
29561 + out_ep_regs[_ep->num]->doepint) & msk.d32;
29563 + msk.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->doepmsk);
29564 + if (_core_if->pti_enh_enable) {
29565 + msk.b.pktdrpsts = 1;
29567 + v = DWC_READ_REG32(&dev_if->
29568 + out_ep_regs[_ep->num]->doepint) & msk.d32;
29574 + * This function returns the Host All Channel Interrupt register
29576 +static inline uint32_t dwc_otg_read_host_all_channels_intr(dwc_otg_core_if_t *
29579 + return (DWC_READ_REG32(&_core_if->host_if->host_global_regs->haint));
29582 +static inline uint32_t dwc_otg_read_host_channel_intr(dwc_otg_core_if_t *
29583 + _core_if, dwc_hc_t * _hc)
29585 + return (DWC_READ_REG32
29586 + (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint));
29590 + * This function returns the mode of the operation, host or device.
29592 + * @return 0 - Device Mode, 1 - Host Mode
29594 +static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t * _core_if)
29596 + return (DWC_READ_REG32(&_core_if->core_global_regs->gintsts) & 0x1);
29602 + * DWC_otg CIL callback structure. This structure allows the HCD and
29603 + * PCD to register functions used for starting and stopping the PCD
29604 + * and HCD for role change on for a DRD.
29606 +typedef struct dwc_otg_cil_callbacks {
29607 + /** Start function for role change */
29608 + int (*start) (void *_p);
29609 + /** Stop Function for role change */
29610 + int (*stop) (void *_p);
29611 + /** Disconnect Function for role change */
29612 + int (*disconnect) (void *_p);
29613 + /** Resume/Remote wakeup Function */
29614 + int (*resume_wakeup) (void *_p);
29615 + /** Suspend function */
29616 + int (*suspend) (void *_p);
29617 + /** Session Start (SRP) */
29618 + int (*session_start) (void *_p);
29619 +#ifdef CONFIG_USB_DWC_OTG_LPM
29620 + /** Sleep (switch to L0 state) */
29621 + int (*sleep) (void *_p);
29623 + /** Pointer passed to start() and stop() */
29625 +} dwc_otg_cil_callbacks_t;
29627 +extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if,
29628 + dwc_otg_cil_callbacks_t * _cb,
29630 +extern void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * _core_if,
29631 + dwc_otg_cil_callbacks_t * _cb,
29634 +void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if);
29636 +//////////////////////////////////////////////////////////////////////
29637 +/** Start the HCD. Helper function for using the HCD callbacks.
29639 + * @param core_if Programming view of DWC_otg controller.
29641 +static inline void cil_hcd_start(dwc_otg_core_if_t * core_if)
29643 + if (core_if->hcd_cb && core_if->hcd_cb->start) {
29644 + core_if->hcd_cb->start(core_if->hcd_cb->p);
29648 +/** Stop the HCD. Helper function for using the HCD callbacks.
29650 + * @param core_if Programming view of DWC_otg controller.
29652 +static inline void cil_hcd_stop(dwc_otg_core_if_t * core_if)
29654 + if (core_if->hcd_cb && core_if->hcd_cb->stop) {
29655 + core_if->hcd_cb->stop(core_if->hcd_cb->p);
29659 +/** Disconnect the HCD. Helper function for using the HCD callbacks.
29661 + * @param core_if Programming view of DWC_otg controller.
29663 +static inline void cil_hcd_disconnect(dwc_otg_core_if_t * core_if)
29665 + if (core_if->hcd_cb && core_if->hcd_cb->disconnect) {
29666 + core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
29670 +/** Inform the HCD the a New Session has begun. Helper function for
29671 + * using the HCD callbacks.
29673 + * @param core_if Programming view of DWC_otg controller.
29675 +static inline void cil_hcd_session_start(dwc_otg_core_if_t * core_if)
29677 + if (core_if->hcd_cb && core_if->hcd_cb->session_start) {
29678 + core_if->hcd_cb->session_start(core_if->hcd_cb->p);
29682 +#ifdef CONFIG_USB_DWC_OTG_LPM
29684 + * Inform the HCD about LPM sleep.
29685 + * Helper function for using the HCD callbacks.
29687 + * @param core_if Programming view of DWC_otg controller.
29689 +static inline void cil_hcd_sleep(dwc_otg_core_if_t * core_if)
29691 + if (core_if->hcd_cb && core_if->hcd_cb->sleep) {
29692 + core_if->hcd_cb->sleep(core_if->hcd_cb->p);
29697 +/** Resume the HCD. Helper function for using the HCD callbacks.
29699 + * @param core_if Programming view of DWC_otg controller.
29701 +static inline void cil_hcd_resume(dwc_otg_core_if_t * core_if)
29703 + if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) {
29704 + core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p);
29708 +/** Start the PCD. Helper function for using the PCD callbacks.
29710 + * @param core_if Programming view of DWC_otg controller.
29712 +static inline void cil_pcd_start(dwc_otg_core_if_t * core_if)
29714 + if (core_if->pcd_cb && core_if->pcd_cb->start) {
29715 + core_if->pcd_cb->start(core_if->pcd_cb->p);
29719 +/** Stop the PCD. Helper function for using the PCD callbacks.
29721 + * @param core_if Programming view of DWC_otg controller.
29723 +static inline void cil_pcd_stop(dwc_otg_core_if_t * core_if)
29725 + if (core_if->pcd_cb && core_if->pcd_cb->stop) {
29726 + core_if->pcd_cb->stop(core_if->pcd_cb->p);
29730 +/** Suspend the PCD. Helper function for using the PCD callbacks.
29732 + * @param core_if Programming view of DWC_otg controller.
29734 +static inline void cil_pcd_suspend(dwc_otg_core_if_t * core_if)
29736 + if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
29737 + core_if->pcd_cb->suspend(core_if->pcd_cb->p);
29741 +/** Resume the PCD. Helper function for using the PCD callbacks.
29743 + * @param core_if Programming view of DWC_otg controller.
29745 +static inline void cil_pcd_resume(dwc_otg_core_if_t * core_if)
29747 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
29748 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
29752 +//////////////////////////////////////////////////////////////////////
29755 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
29756 new file mode 100644
29757 index 0000000..21804c4
29759 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
29761 +/* ==========================================================================
29762 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
29763 + * $Revision: #32 $
29764 + * $Date: 2012/08/10 $
29765 + * $Change: 2047372 $
29767 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
29768 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
29769 + * otherwise expressly agreed to in writing between Synopsys and you.
29771 + * The Software IS NOT an item of Licensed Software or Licensed Product under
29772 + * any End User Software License Agreement or Agreement for Licensed Product
29773 + * with Synopsys or any supplement thereto. You are permitted to use and
29774 + * redistribute this Software in source and binary forms, with or without
29775 + * modification, provided that redistributions of source code must retain this
29776 + * notice. You may not view, use, disclose, copy or distribute this file or
29777 + * any information contained herein except pursuant to this license grant from
29778 + * Synopsys. If you do not agree with this notice, including the disclaimer
29779 + * below, then you are not authorized to use the Software.
29781 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
29782 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29783 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29784 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
29785 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29786 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29787 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29788 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29789 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29790 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29792 + * ========================================================================== */
29796 + * The Core Interface Layer provides basic services for accessing and
29797 + * managing the DWC_otg hardware. These services are used by both the
29798 + * Host Controller Driver and the Peripheral Controller Driver.
29800 + * This file contains the Common Interrupt handlers.
29802 +#include "dwc_os.h"
29803 +#include "dwc_otg_regs.h"
29804 +#include "dwc_otg_cil.h"
29805 +#include "dwc_otg_driver.h"
29806 +#include "dwc_otg_pcd.h"
29807 +#include "dwc_otg_hcd.h"
29810 +inline const char *op_state_str(dwc_otg_core_if_t * core_if)
29812 + return (core_if->op_state == A_HOST ? "a_host" :
29813 + (core_if->op_state == A_SUSPEND ? "a_suspend" :
29814 + (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
29815 + (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
29816 + (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
29820 +/** This function will log a debug message
29822 + * @param core_if Programming view of DWC_otg controller.
29824 +int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if)
29826 + gintsts_data_t gintsts;
29827 + DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
29828 + dwc_otg_mode(core_if) ? "Host" : "Device");
29830 + /* Clear interrupt */
29832 + gintsts.b.modemismatch = 1;
29833 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
29838 + * This function handles the OTG Interrupts. It reads the OTG
29839 + * Interrupt Register (GOTGINT) to determine what interrupt has
29842 + * @param core_if Programming view of DWC_otg controller.
29844 +int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if)
29846 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
29847 + gotgint_data_t gotgint;
29848 + gotgctl_data_t gotgctl;
29849 + gintmsk_data_t gintmsk;
29850 + gpwrdn_data_t gpwrdn;
29852 + gotgint.d32 = DWC_READ_REG32(&global_regs->gotgint);
29853 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29854 + DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
29855 + op_state_str(core_if));
29857 + if (gotgint.b.sesenddet) {
29858 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29859 + "Session End Detected++ (%s)\n",
29860 + op_state_str(core_if));
29861 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29863 + if (core_if->op_state == B_HOST) {
29864 + cil_pcd_start(core_if);
29865 + core_if->op_state = B_PERIPHERAL;
29867 + /* If not B_HOST and Device HNP still set. HNP
29868 + * Did not succeed!*/
29869 + if (gotgctl.b.devhnpen) {
29870 + DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
29871 + __DWC_ERROR("Device Not Connected/Responding!\n");
29874 + /* If Session End Detected the B-Cable has
29875 + * been disconnected. */
29876 + /* Reset PCD and Gadget driver to a
29877 + * clean state. */
29878 + core_if->lx_state = DWC_OTG_L0;
29879 + DWC_SPINUNLOCK(core_if->lock);
29880 + cil_pcd_stop(core_if);
29881 + DWC_SPINLOCK(core_if->lock);
29883 + if (core_if->adp_enable) {
29884 + if (core_if->power_down == 2) {
29886 + gpwrdn.b.pwrdnswtch = 1;
29887 + DWC_MODIFY_REG32(&core_if->
29888 + core_global_regs->
29889 + gpwrdn, gpwrdn.d32, 0);
29893 + gpwrdn.b.pmuintsel = 1;
29894 + gpwrdn.b.pmuactv = 1;
29895 + DWC_MODIFY_REG32(&core_if->core_global_regs->
29896 + gpwrdn, 0, gpwrdn.d32);
29898 + dwc_otg_adp_sense_start(core_if);
29903 + gotgctl.b.devhnpen = 1;
29904 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
29906 + if (gotgint.b.sesreqsucstschng) {
29907 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29908 + "Session Reqeust Success Status Change++\n");
29909 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29910 + if (gotgctl.b.sesreqscs) {
29912 + if ((core_if->core_params->phy_type ==
29913 + DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) {
29914 + core_if->srp_success = 1;
29916 + DWC_SPINUNLOCK(core_if->lock);
29917 + cil_pcd_resume(core_if);
29918 + DWC_SPINLOCK(core_if->lock);
29919 + /* Clear Session Request */
29921 + gotgctl.b.sesreq = 1;
29922 + DWC_MODIFY_REG32(&global_regs->gotgctl,
29927 + if (gotgint.b.hstnegsucstschng) {
29928 + /* Print statements during the HNP interrupt handling
29929 + * can cause it to fail.*/
29930 + gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
29931 + /* WA for 3.00a- HW is not setting cur_mode, even sometimes
29932 + * this does not help*/
29933 + if (core_if->snpsid >= OTG_CORE_REV_3_00a)
29935 + if (gotgctl.b.hstnegscs) {
29936 + if (dwc_otg_is_host_mode(core_if)) {
29937 + core_if->op_state = B_HOST;
29939 + * Need to disable SOF interrupt immediately.
29940 + * When switching from device to host, the PCD
29941 + * interrupt handler won't handle the
29942 + * interrupt if host mode is already set. The
29943 + * HCD interrupt handler won't get called if
29944 + * the HCD state is HALT. This means that the
29945 + * interrupt does not get handled and Linux
29946 + * complains loudly.
29949 + gintmsk.b.sofintr = 1;
29950 + DWC_MODIFY_REG32(&global_regs->gintmsk,
29952 + /* Call callback function with spin lock released */
29953 + DWC_SPINUNLOCK(core_if->lock);
29954 + cil_pcd_stop(core_if);
29956 + * Initialize the Core for Host mode.
29958 + cil_hcd_start(core_if);
29959 + DWC_SPINLOCK(core_if->lock);
29960 + core_if->op_state = B_HOST;
29964 + gotgctl.b.hnpreq = 1;
29965 + gotgctl.b.devhnpen = 1;
29966 + DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
29967 + DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
29968 + __DWC_ERROR("Device Not Connected/Responding\n");
29971 + if (gotgint.b.hstnegdet) {
29972 + /* The disconnect interrupt is set at the same time as
29973 + * Host Negotiation Detected. During the mode
29974 + * switch all interrupts are cleared so the disconnect
29975 + * interrupt handler will not get executed.
29977 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
29978 + "Host Negotiation Detected++ (%s)\n",
29979 + (dwc_otg_is_host_mode(core_if) ? "Host" :
29981 + if (dwc_otg_is_device_mode(core_if)) {
29982 + DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
29983 + core_if->op_state);
29984 + DWC_SPINUNLOCK(core_if->lock);
29985 + cil_hcd_disconnect(core_if);
29986 + cil_pcd_start(core_if);
29987 + DWC_SPINLOCK(core_if->lock);
29988 + core_if->op_state = A_PERIPHERAL;
29991 + * Need to disable SOF interrupt immediately. When
29992 + * switching from device to host, the PCD interrupt
29993 + * handler won't handle the interrupt if host mode is
29994 + * already set. The HCD interrupt handler won't get
29995 + * called if the HCD state is HALT. This means that
29996 + * the interrupt does not get handled and Linux
29997 + * complains loudly.
30000 + gintmsk.b.sofintr = 1;
30001 + DWC_MODIFY_REG32(&global_regs->gintmsk, gintmsk.d32, 0);
30002 + DWC_SPINUNLOCK(core_if->lock);
30003 + cil_pcd_stop(core_if);
30004 + cil_hcd_start(core_if);
30005 + DWC_SPINLOCK(core_if->lock);
30006 + core_if->op_state = A_HOST;
30009 + if (gotgint.b.adevtoutchng) {
30010 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
30011 + "A-Device Timeout Change++\n");
30013 + if (gotgint.b.debdone) {
30014 + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
30017 + /* Clear GOTGINT */
30018 + DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, gotgint.d32);
30023 +void w_conn_id_status_change(void *p)
30025 + dwc_otg_core_if_t *core_if = p;
30026 + uint32_t count = 0;
30027 + gotgctl_data_t gotgctl = {.d32 = 0 };
30029 + gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
30030 + DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
30031 + DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
30033 + /* B-Device connector (Device Mode) */
30034 + if (gotgctl.b.conidsts) {
30035 + /* Wait for switch to device mode. */
30036 + while (!dwc_otg_is_device_mode(core_if)) {
30037 + DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
30038 + (dwc_otg_is_host_mode(core_if) ? "Host" :
30041 + if (++count > 10000)
30044 + DWC_ASSERT(++count < 10000,
30045 + "Connection id status change timed out");
30046 + core_if->op_state = B_PERIPHERAL;
30047 + dwc_otg_core_init(core_if);
30048 + dwc_otg_enable_global_interrupts(core_if);
30049 + cil_pcd_start(core_if);
30051 + /* A-Device connector (Host Mode) */
30052 + while (!dwc_otg_is_host_mode(core_if)) {
30053 + DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
30054 + (dwc_otg_is_host_mode(core_if) ? "Host" :
30057 + if (++count > 10000)
30060 + DWC_ASSERT(++count < 10000,
30061 + "Connection id status change timed out");
30062 + core_if->op_state = A_HOST;
30064 + * Initialize the Core for Host mode.
30066 + dwc_otg_core_init(core_if);
30067 + dwc_otg_enable_global_interrupts(core_if);
30068 + cil_hcd_start(core_if);
30073 + * This function handles the Connector ID Status Change Interrupt. It
30074 + * reads the OTG Interrupt Register (GOTCTL) to determine whether this
30075 + * is a Device to Host Mode transition or a Host Mode to Device
30078 + * This only occurs when the cable is connected/removed from the PHY
30081 + * @param core_if Programming view of DWC_otg controller.
30083 +int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
30087 + * Need to disable SOF interrupt immediately. If switching from device
30088 + * to host, the PCD interrupt handler won't handle the interrupt if
30089 + * host mode is already set. The HCD interrupt handler won't get
30090 + * called if the HCD state is HALT. This means that the interrupt does
30091 + * not get handled and Linux complains loudly.
30093 + gintmsk_data_t gintmsk = {.d32 = 0 };
30094 + gintsts_data_t gintsts = {.d32 = 0 };
30096 + gintmsk.b.sofintr = 1;
30097 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
30099 + DWC_DEBUGPL(DBG_CIL,
30100 + " ++Connector ID Status Change Interrupt++ (%s)\n",
30101 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
30103 + DWC_SPINUNLOCK(core_if->lock);
30106 + * Need to schedule a work, as there are possible DELAY function calls
30107 + * Release lock before scheduling workq as it holds spinlock during scheduling
30110 + DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
30111 + core_if, "connection id status change");
30112 + DWC_SPINLOCK(core_if->lock);
30114 + /* Set flag and clear interrupt */
30115 + gintsts.b.conidstschng = 1;
30116 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30122 + * This interrupt indicates that a device is initiating the Session
30123 + * Request Protocol to request the host to turn on bus power so a new
30124 + * session can begin. The handler responds by turning on bus power. If
30125 + * the DWC_otg controller is in low power mode, the handler brings the
30126 + * controller out of low power mode before turning on bus power.
30128 + * @param core_if Programming view of DWC_otg controller.
30130 +int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
30132 + gintsts_data_t gintsts;
30134 +#ifndef DWC_HOST_ONLY
30135 + DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
30137 + if (dwc_otg_is_device_mode(core_if)) {
30138 + DWC_PRINTF("SRP: Device mode\n");
30140 + hprt0_data_t hprt0;
30141 + DWC_PRINTF("SRP: Host mode\n");
30143 + /* Turn on the port power bit. */
30144 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
30145 + hprt0.b.prtpwr = 1;
30146 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
30148 + /* Start the Connection timer. So a message can be displayed
30149 + * if connect does not occur within 10 seconds. */
30150 + cil_hcd_session_start(core_if);
30154 + /* Clear interrupt */
30156 + gintsts.b.sessreqintr = 1;
30157 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30162 +void w_wakeup_detected(void *p)
30164 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
30166 + * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
30167 + * so that OPT tests pass with all PHYs).
30169 + hprt0_data_t hprt0 = {.d32 = 0 };
30171 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30172 + /* Restart the Phy Clock */
30173 + pcgcctl.b.stoppclk = 1;
30174 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
30177 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
30178 + DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
30179 +// dwc_mdelay(70);
30180 + hprt0.b.prtres = 0; /* Resume */
30181 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
30182 + DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
30183 + DWC_READ_REG32(core_if->host_if->hprt0));
30185 + cil_hcd_resume(core_if);
30187 + /** Change to L0 state*/
30188 + core_if->lx_state = DWC_OTG_L0;
30192 + * This interrupt indicates that the DWC_otg controller has detected a
30193 + * resume or remote wakeup sequence. If the DWC_otg controller is in
30194 + * low power mode, the handler must brings the controller out of low
30195 + * power mode. The controller automatically begins resume
30196 + * signaling. The handler schedules a time to stop resume signaling.
30198 +int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
30200 + gintsts_data_t gintsts;
30202 + DWC_DEBUGPL(DBG_ANY,
30203 + "++Resume and Remote Wakeup Detected Interrupt++\n");
30205 + DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
30207 + if (dwc_otg_is_device_mode(core_if)) {
30208 + dctl_data_t dctl = {.d32 = 0 };
30209 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
30210 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
30212 + if (core_if->lx_state == DWC_OTG_L2) {
30213 +#ifdef PARTIAL_POWER_DOWN
30214 + if (core_if->hwcfg4.b.power_optimiz) {
30215 + pcgcctl_data_t power = {.d32 = 0 };
30217 + power.d32 = DWC_READ_REG32(core_if->pcgcctl);
30218 + DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
30221 + power.b.stoppclk = 0;
30222 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30224 + power.b.pwrclmp = 0;
30225 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30227 + power.b.rstpdwnmodule = 0;
30228 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30231 + /* Clear the Remote Wakeup Signaling */
30232 + dctl.b.rmtwkupsig = 1;
30233 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
30234 + dctl, dctl.d32, 0);
30236 + DWC_SPINUNLOCK(core_if->lock);
30237 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
30238 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
30240 + DWC_SPINLOCK(core_if->lock);
30242 + glpmcfg_data_t lpmcfg;
30244 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
30245 + lpmcfg.b.hird_thres &= (~(1 << 4));
30246 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
30249 + /** Change to L0 state*/
30250 + core_if->lx_state = DWC_OTG_L0;
30252 + if (core_if->lx_state != DWC_OTG_L1) {
30253 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30255 + /* Restart the Phy Clock */
30256 + pcgcctl.b.stoppclk = 1;
30257 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
30258 + DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
30260 + /** Change to L0 state*/
30261 + core_if->lx_state = DWC_OTG_L0;
30265 + /* Clear interrupt */
30267 + gintsts.b.wkupintr = 1;
30268 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30274 + * This interrupt indicates that the Wakeup Logic has detected a
30275 + * Device disconnect.
30277 +static int32_t dwc_otg_handle_pwrdn_disconnect_intr(dwc_otg_core_if_t *core_if)
30279 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
30280 + gpwrdn_data_t gpwrdn_temp = { .d32 = 0 };
30281 + gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30283 + DWC_PRINTF("%s called\n", __FUNCTION__);
30285 + if (!core_if->hibernation_suspend) {
30286 + DWC_PRINTF("Already exited from Hibernation\n");
30290 + /* Switch on the voltage to the core */
30291 + gpwrdn.b.pwrdnswtch = 1;
30292 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30295 + /* Reset the core */
30297 + gpwrdn.b.pwrdnrstn = 1;
30298 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30301 + /* Disable power clamps*/
30303 + gpwrdn.b.pwrdnclmp = 1;
30304 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30306 + /* Remove reset the core signal */
30308 + gpwrdn.b.pwrdnrstn = 1;
30309 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30312 + /* Disable PMU interrupt */
30314 + gpwrdn.b.pmuintsel = 1;
30315 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30317 + core_if->hibernation_suspend = 0;
30319 + /* Disable PMU */
30321 + gpwrdn.b.pmuactv = 1;
30322 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30325 + if (gpwrdn_temp.b.idsts) {
30326 + core_if->op_state = B_PERIPHERAL;
30327 + dwc_otg_core_init(core_if);
30328 + dwc_otg_enable_global_interrupts(core_if);
30329 + cil_pcd_start(core_if);
30331 + core_if->op_state = A_HOST;
30332 + dwc_otg_core_init(core_if);
30333 + dwc_otg_enable_global_interrupts(core_if);
30334 + cil_hcd_start(core_if);
30341 + * This interrupt indicates that the Wakeup Logic has detected a
30342 + * remote wakeup sequence.
30344 +static int32_t dwc_otg_handle_pwrdn_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
30346 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30347 + DWC_DEBUGPL(DBG_ANY,
30348 + "++Powerdown Remote Wakeup Detected Interrupt++\n");
30350 + if (!core_if->hibernation_suspend) {
30351 + DWC_PRINTF("Already exited from Hibernation\n");
30355 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30356 + if (gpwrdn.b.idsts) { // Device Mode
30357 + if ((core_if->power_down == 2)
30358 + && (core_if->hibernation_suspend == 1)) {
30359 + dwc_otg_device_hibernation_restore(core_if, 0, 0);
30362 + if ((core_if->power_down == 2)
30363 + && (core_if->hibernation_suspend == 1)) {
30364 + dwc_otg_host_hibernation_restore(core_if, 1, 0);
30370 +static int32_t dwc_otg_handle_pwrdn_idsts_change(dwc_otg_device_t *otg_dev)
30372 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30373 + gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
30374 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30376 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30377 + gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30378 + if (core_if->power_down == 2) {
30379 + if (!core_if->hibernation_suspend) {
30380 + DWC_PRINTF("Already exited from Hibernation\n");
30383 + DWC_DEBUGPL(DBG_ANY, "Exit from hibernation on ID sts change\n");
30384 + /* Switch on the voltage to the core */
30385 + gpwrdn.b.pwrdnswtch = 1;
30386 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30389 + /* Reset the core */
30391 + gpwrdn.b.pwrdnrstn = 1;
30392 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30395 + /* Disable power clamps */
30397 + gpwrdn.b.pwrdnclmp = 1;
30398 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30400 + /* Remove reset the core signal */
30402 + gpwrdn.b.pwrdnrstn = 1;
30403 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30406 + /* Disable PMU interrupt */
30408 + gpwrdn.b.pmuintsel = 1;
30409 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30411 + /*Indicates that we are exiting from hibernation */
30412 + core_if->hibernation_suspend = 0;
30414 + /* Disable PMU */
30416 + gpwrdn.b.pmuactv = 1;
30417 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30420 + gpwrdn.d32 = core_if->gr_backup->gpwrdn_local;
30421 + if (gpwrdn.b.dis_vbus == 1) {
30423 + gpwrdn.b.dis_vbus = 1;
30424 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30427 + if (gpwrdn_temp.b.idsts) {
30428 + core_if->op_state = B_PERIPHERAL;
30429 + dwc_otg_core_init(core_if);
30430 + dwc_otg_enable_global_interrupts(core_if);
30431 + cil_pcd_start(core_if);
30433 + core_if->op_state = A_HOST;
30434 + dwc_otg_core_init(core_if);
30435 + dwc_otg_enable_global_interrupts(core_if);
30436 + cil_hcd_start(core_if);
30440 + if (core_if->adp_enable) {
30441 + uint8_t is_host = 0;
30442 + DWC_SPINUNLOCK(core_if->lock);
30443 + /* Change the core_if's lock to hcd/pcd lock depend on mode? */
30444 +#ifndef DWC_HOST_ONLY
30445 + if (gpwrdn_temp.b.idsts)
30446 + core_if->lock = otg_dev->pcd->lock;
30448 +#ifndef DWC_DEVICE_ONLY
30449 + if (!gpwrdn_temp.b.idsts) {
30450 + core_if->lock = otg_dev->hcd->lock;
30454 + DWC_PRINTF("RESTART ADP\n");
30455 + if (core_if->adp.probe_enabled)
30456 + dwc_otg_adp_probe_stop(core_if);
30457 + if (core_if->adp.sense_enabled)
30458 + dwc_otg_adp_sense_stop(core_if);
30459 + if (core_if->adp.sense_timer_started)
30460 + DWC_TIMER_CANCEL(core_if->adp.sense_timer);
30461 + if (core_if->adp.vbuson_timer_started)
30462 + DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
30463 + core_if->adp.probe_timer_values[0] = -1;
30464 + core_if->adp.probe_timer_values[1] = -1;
30465 + core_if->adp.sense_timer_started = 0;
30466 + core_if->adp.vbuson_timer_started = 0;
30467 + core_if->adp.probe_counter = 0;
30468 + core_if->adp.gpwrdn = 0;
30470 + /* Disable PMU and restart ADP */
30471 + gpwrdn_temp.d32 = 0;
30472 + gpwrdn_temp.b.pmuactv = 1;
30473 + gpwrdn_temp.b.pmuintsel = 1;
30474 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30475 + DWC_PRINTF("Check point 1\n");
30477 + dwc_otg_adp_start(core_if, is_host);
30478 + DWC_SPINLOCK(core_if->lock);
30485 +static int32_t dwc_otg_handle_pwrdn_session_change(dwc_otg_core_if_t * core_if)
30487 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30488 + int32_t otg_cap_param = core_if->core_params->otg_cap;
30489 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
30491 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30492 + if (core_if->power_down == 2) {
30493 + if (!core_if->hibernation_suspend) {
30494 + DWC_PRINTF("Already exited from Hibernation\n");
30498 + if ((otg_cap_param != DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
30499 + otg_cap_param != DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) &&
30500 + gpwrdn.b.bsessvld == 0) {
30501 + /* Save gpwrdn register for further usage if stschng interrupt */
30502 + core_if->gr_backup->gpwrdn_local =
30503 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30504 + /*Exit from ISR and wait for stschng interrupt with bsessvld = 1 */
30508 + /* Switch on the voltage to the core */
30510 + gpwrdn.b.pwrdnswtch = 1;
30511 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30514 + /* Reset the core */
30516 + gpwrdn.b.pwrdnrstn = 1;
30517 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30520 + /* Disable power clamps */
30522 + gpwrdn.b.pwrdnclmp = 1;
30523 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30525 + /* Remove reset the core signal */
30527 + gpwrdn.b.pwrdnrstn = 1;
30528 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30531 + /* Disable PMU interrupt */
30533 + gpwrdn.b.pmuintsel = 1;
30534 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30537 + /*Indicates that we are exiting from hibernation */
30538 + core_if->hibernation_suspend = 0;
30540 + /* Disable PMU */
30542 + gpwrdn.b.pmuactv = 1;
30543 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30546 + core_if->op_state = B_PERIPHERAL;
30547 + dwc_otg_core_init(core_if);
30548 + dwc_otg_enable_global_interrupts(core_if);
30549 + cil_pcd_start(core_if);
30551 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
30552 + otg_cap_param == DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) {
30554 + * Initiate SRP after initial ADP probe.
30556 + dwc_otg_initiate_srp(core_if);
30563 + * This interrupt indicates that the Wakeup Logic has detected a
30564 + * status change either on IDDIG or BSessVld.
30566 +static uint32_t dwc_otg_handle_pwrdn_stschng_intr(dwc_otg_device_t *otg_dev)
30569 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30570 + gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
30571 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
30573 + DWC_PRINTF("%s called\n", __FUNCTION__);
30575 + if (core_if->power_down == 2) {
30576 + if (core_if->hibernation_suspend <= 0) {
30577 + DWC_PRINTF("Already exited from Hibernation\n");
30580 + gpwrdn_temp.d32 = core_if->gr_backup->gpwrdn_local;
30583 + gpwrdn_temp.d32 = core_if->adp.gpwrdn;
30586 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30588 + if (gpwrdn.b.idsts ^ gpwrdn_temp.b.idsts) {
30589 + retval = dwc_otg_handle_pwrdn_idsts_change(otg_dev);
30590 + } else if (gpwrdn.b.bsessvld ^ gpwrdn_temp.b.bsessvld) {
30591 + retval = dwc_otg_handle_pwrdn_session_change(core_if);
30598 + * This interrupt indicates that the Wakeup Logic has detected a
30601 +static int32_t dwc_otg_handle_pwrdn_srp_intr(dwc_otg_core_if_t * core_if)
30603 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30605 + DWC_PRINTF("%s called\n", __FUNCTION__);
30607 + if (!core_if->hibernation_suspend) {
30608 + DWC_PRINTF("Already exited from Hibernation\n");
30611 +#ifdef DWC_DEV_SRPCAP
30612 + if (core_if->pwron_timer_started) {
30613 + core_if->pwron_timer_started = 0;
30614 + DWC_TIMER_CANCEL(core_if->pwron_timer);
30618 + /* Switch on the voltage to the core */
30619 + gpwrdn.b.pwrdnswtch = 1;
30620 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30623 + /* Reset the core */
30625 + gpwrdn.b.pwrdnrstn = 1;
30626 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30629 + /* Disable power clamps */
30631 + gpwrdn.b.pwrdnclmp = 1;
30632 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30634 + /* Remove reset the core signal */
30636 + gpwrdn.b.pwrdnrstn = 1;
30637 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
30640 + /* Disable PMU interrupt */
30642 + gpwrdn.b.pmuintsel = 1;
30643 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30645 + /* Indicates that we are exiting from hibernation */
30646 + core_if->hibernation_suspend = 0;
30648 + /* Disable PMU */
30650 + gpwrdn.b.pmuactv = 1;
30651 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30654 + /* Programm Disable VBUS to 0 */
30656 + gpwrdn.b.dis_vbus = 1;
30657 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
30659 + /*Initialize the core as Host */
30660 + core_if->op_state = A_HOST;
30661 + dwc_otg_core_init(core_if);
30662 + dwc_otg_enable_global_interrupts(core_if);
30663 + cil_hcd_start(core_if);
30668 +/** This interrupt indicates that restore command after Hibernation
30669 + * was completed by the core. */
30670 +int32_t dwc_otg_handle_restore_done_intr(dwc_otg_core_if_t * core_if)
30672 + pcgcctl_data_t pcgcctl;
30673 + DWC_DEBUGPL(DBG_ANY, "++Restore Done Interrupt++\n");
30675 + //TODO De-assert restore signal. 8.a
30676 + pcgcctl.d32 = DWC_READ_REG32(core_if->pcgcctl);
30677 + if (pcgcctl.b.restoremode == 1) {
30678 + gintmsk_data_t gintmsk = {.d32 = 0 };
30680 + * If restore mode is Remote Wakeup,
30681 + * unmask Remote Wakeup interrupt.
30683 + gintmsk.b.wkupintr = 1;
30684 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
30692 + * This interrupt indicates that a device has been disconnected from
30695 +int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if)
30697 + gintsts_data_t gintsts;
30699 + DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
30700 + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
30701 + op_state_str(core_if));
30703 +/** @todo Consolidate this if statement. */
30704 +#ifndef DWC_HOST_ONLY
30705 + if (core_if->op_state == B_HOST) {
30706 + /* If in device mode Disconnect and stop the HCD, then
30707 + * start the PCD. */
30708 + DWC_SPINUNLOCK(core_if->lock);
30709 + cil_hcd_disconnect(core_if);
30710 + cil_pcd_start(core_if);
30711 + DWC_SPINLOCK(core_if->lock);
30712 + core_if->op_state = B_PERIPHERAL;
30713 + } else if (dwc_otg_is_device_mode(core_if)) {
30714 + gotgctl_data_t gotgctl = {.d32 = 0 };
30716 + DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
30717 + if (gotgctl.b.hstsethnpen == 1) {
30718 + /* Do nothing, if HNP in process the OTG
30719 + * interrupt "Host Negotiation Detected"
30720 + * interrupt will do the mode switch.
30722 + } else if (gotgctl.b.devhnpen == 0) {
30723 + /* If in device mode Disconnect and stop the HCD, then
30724 + * start the PCD. */
30725 + DWC_SPINUNLOCK(core_if->lock);
30726 + cil_hcd_disconnect(core_if);
30727 + cil_pcd_start(core_if);
30728 + DWC_SPINLOCK(core_if->lock);
30729 + core_if->op_state = B_PERIPHERAL;
30731 + DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
30734 + if (core_if->op_state == A_HOST) {
30735 + /* A-Cable still connected but device disconnected. */
30736 + cil_hcd_disconnect(core_if);
30737 + if (core_if->adp_enable) {
30738 + gpwrdn_data_t gpwrdn = { .d32 = 0 };
30739 + cil_hcd_stop(core_if);
30740 + /* Enable Power Down Logic */
30741 + gpwrdn.b.pmuintsel = 1;
30742 + gpwrdn.b.pmuactv = 1;
30743 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30744 + gpwrdn, 0, gpwrdn.d32);
30745 + dwc_otg_adp_probe_start(core_if);
30747 + /* Power off the core */
30748 + if (core_if->power_down == 2) {
30750 + gpwrdn.b.pwrdnswtch = 1;
30752 + (&core_if->core_global_regs->gpwrdn,
30759 + /* Change to L3(OFF) state */
30760 + core_if->lx_state = DWC_OTG_L3;
30763 + gintsts.b.disconnect = 1;
30764 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30769 + * This interrupt indicates that SUSPEND state has been detected on
30772 + * For HNP the USB Suspend interrupt signals the change from
30773 + * "a_peripheral" to "a_host".
30775 + * When power management is enabled the core will be put in low power
30778 +int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if)
30780 + dsts_data_t dsts;
30781 + gintsts_data_t gintsts;
30782 + dcfg_data_t dcfg;
30784 + DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
30786 + if (dwc_otg_is_device_mode(core_if)) {
30787 + /* Check the Device status register to determine if the Suspend
30788 + * state is active. */
30790 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
30791 + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
30792 + DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
30793 + "HWCFG4.power Optimize=%d\n",
30794 + dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
30796 +#ifdef PARTIAL_POWER_DOWN
30797 +/** @todo Add a module parameter for power management. */
30799 + if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
30800 + pcgcctl_data_t power = {.d32 = 0 };
30801 + DWC_DEBUGPL(DBG_CIL, "suspend\n");
30803 + power.b.pwrclmp = 1;
30804 + DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
30806 + power.b.rstpdwnmodule = 1;
30807 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
30809 + power.b.stoppclk = 1;
30810 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
30813 + DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
30816 + /* PCD callback for suspend. Release the lock inside of callback function */
30817 + cil_pcd_suspend(core_if);
30818 + if (core_if->power_down == 2)
30820 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
30821 + DWC_DEBUGPL(DBG_ANY,"lx_state = %08x\n",core_if->lx_state);
30822 + DWC_DEBUGPL(DBG_ANY," device address = %08d\n",dcfg.b.devaddr);
30824 + if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
30825 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30826 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30827 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
30829 + /* Change to L2(suspend) state */
30830 + core_if->lx_state = DWC_OTG_L2;
30832 + /* Clear interrupt in gintsts */
30834 + gintsts.b.usbsuspend = 1;
30835 + DWC_WRITE_REG32(&core_if->core_global_regs->
30836 + gintsts, gintsts.d32);
30837 + DWC_PRINTF("Start of hibernation completed\n");
30838 + dwc_otg_save_global_regs(core_if);
30839 + dwc_otg_save_dev_regs(core_if);
30842 + DWC_READ_REG32(&core_if->core_global_regs->
30844 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
30845 + /* ULPI interface */
30846 + /* Suspend the Phy Clock */
30848 + pcgcctl.b.stoppclk = 1;
30849 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
30852 + gpwrdn.b.pmuactv = 1;
30853 + DWC_MODIFY_REG32(&core_if->
30854 + core_global_regs->
30855 + gpwrdn, 0, gpwrdn.d32);
30857 + /* UTMI+ Interface */
30858 + gpwrdn.b.pmuactv = 1;
30859 + DWC_MODIFY_REG32(&core_if->
30860 + core_global_regs->
30861 + gpwrdn, 0, gpwrdn.d32);
30863 + pcgcctl.b.stoppclk = 1;
30864 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
30869 + /* Set flag to indicate that we are in hibernation */
30870 + core_if->hibernation_suspend = 1;
30871 + /* Enable interrupts from wake up logic */
30873 + gpwrdn.b.pmuintsel = 1;
30874 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30875 + gpwrdn, 0, gpwrdn.d32);
30878 + /* Unmask device mode interrupts in GPWRDN */
30880 + gpwrdn.b.rst_det_msk = 1;
30881 + gpwrdn.b.lnstchng_msk = 1;
30882 + gpwrdn.b.sts_chngint_msk = 1;
30883 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30884 + gpwrdn, 0, gpwrdn.d32);
30887 + /* Enable Power Down Clamp */
30889 + gpwrdn.b.pwrdnclmp = 1;
30890 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30891 + gpwrdn, 0, gpwrdn.d32);
30894 + /* Switch off VDD */
30896 + gpwrdn.b.pwrdnswtch = 1;
30897 + DWC_MODIFY_REG32(&core_if->core_global_regs->
30898 + gpwrdn, 0, gpwrdn.d32);
30900 + /* Save gpwrdn register for further usage if stschng interrupt */
30901 + core_if->gr_backup->gpwrdn_local =
30902 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30903 + DWC_PRINTF("Hibernation completed\n");
30907 + } else if (core_if->power_down == 3) {
30908 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30909 + dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
30910 + DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",core_if->lx_state);
30911 + DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",dcfg.b.devaddr);
30913 + if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
30914 + DWC_DEBUGPL(DBG_ANY, "Start entering to extended hibernation\n");
30915 + core_if->xhib = 1;
30917 + /* Clear interrupt in gintsts */
30919 + gintsts.b.usbsuspend = 1;
30920 + DWC_WRITE_REG32(&core_if->core_global_regs->
30921 + gintsts, gintsts.d32);
30923 + dwc_otg_save_global_regs(core_if);
30924 + dwc_otg_save_dev_regs(core_if);
30926 + /* Wait for 10 PHY clocks */
30929 + /* Program GPIO register while entering to xHib */
30930 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x1);
30932 + pcgcctl.b.enbl_extnd_hiber = 1;
30933 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30934 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30937 + pcgcctl.b.extnd_hiber_pwrclmp = 1;
30938 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30941 + pcgcctl.b.extnd_hiber_switch = 1;
30942 + core_if->gr_backup->xhib_gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
30943 + core_if->gr_backup->xhib_pcgcctl = DWC_READ_REG32(core_if->pcgcctl) | pcgcctl.d32;
30944 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
30946 + DWC_DEBUGPL(DBG_ANY, "Finished entering to extended hibernation\n");
30952 + if (core_if->op_state == A_PERIPHERAL) {
30953 + DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
30954 + /* Clear the a_peripheral flag, back to a_host. */
30955 + DWC_SPINUNLOCK(core_if->lock);
30956 + cil_pcd_stop(core_if);
30957 + cil_hcd_start(core_if);
30958 + DWC_SPINLOCK(core_if->lock);
30959 + core_if->op_state = A_HOST;
30963 + /* Change to L2(suspend) state */
30964 + core_if->lx_state = DWC_OTG_L2;
30966 + /* Clear interrupt */
30968 + gintsts.b.usbsuspend = 1;
30969 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
30974 +static int32_t dwc_otg_handle_xhib_exit_intr(dwc_otg_core_if_t * core_if)
30976 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
30977 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
30978 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
30982 + /* Program GPIO register while entering to xHib */
30983 + DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x0);
30985 + pcgcctl.d32 = core_if->gr_backup->xhib_pcgcctl;
30986 + pcgcctl.b.extnd_hiber_pwrclmp = 0;
30987 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
30990 + gpwrdn.d32 = core_if->gr_backup->xhib_gpwrdn;
30991 + gpwrdn.b.restore = 1;
30992 + DWC_WRITE_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32);
30995 + restore_lpm_i2c_regs(core_if);
30997 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
30998 + pcgcctl.b.max_xcvrselect = 1;
30999 + pcgcctl.b.ess_reg_restored = 0;
31000 + pcgcctl.b.extnd_hiber_switch = 0;
31001 + pcgcctl.b.extnd_hiber_pwrclmp = 0;
31002 + pcgcctl.b.enbl_extnd_hiber = 1;
31003 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
31005 + gahbcfg.d32 = core_if->gr_backup->gahbcfg_local;
31006 + gahbcfg.b.glblintrmsk = 1;
31007 + DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
31009 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
31010 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0x1 << 16);
31012 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
31013 + core_if->gr_backup->gusbcfg_local);
31014 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
31015 + core_if->dr_backup->dcfg);
31018 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
31019 + pcgcctl.b.max_xcvrselect = 1;
31020 + pcgcctl.d32 |= 0x608;
31021 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
31025 + pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
31026 + pcgcctl.b.max_xcvrselect = 1;
31027 + pcgcctl.b.ess_reg_restored = 1;
31028 + pcgcctl.b.enbl_extnd_hiber = 1;
31029 + pcgcctl.b.rstpdwnmodule = 1;
31030 + pcgcctl.b.restoremode = 1;
31031 + DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
31033 + DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
31038 +#ifdef CONFIG_USB_DWC_OTG_LPM
31040 + * This function hadles LPM transaction received interrupt.
31042 +static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
31044 + glpmcfg_data_t lpmcfg;
31045 + gintsts_data_t gintsts;
31047 + if (!core_if->core_params->lpm_enable) {
31048 + DWC_PRINTF("Unexpected LPM interrupt\n");
31051 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
31052 + DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
31054 + if (dwc_otg_is_host_mode(core_if)) {
31055 + cil_hcd_sleep(core_if);
31057 + lpmcfg.b.hird_thres |= (1 << 4);
31058 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
31062 + /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
31064 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
31065 + if (lpmcfg.b.prt_sleep_sts) {
31066 + /* Save the current state */
31067 + core_if->lx_state = DWC_OTG_L1;
31070 + /* Clear interrupt */
31072 + gintsts.b.lpmtranrcvd = 1;
31073 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
31076 +#endif /* CONFIG_USB_DWC_OTG_LPM */
31079 + * This function returns the Core Interrupt register.
31081 +static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
31083 + gahbcfg_data_t gahbcfg = {.d32 = 0 };
31084 + gintsts_data_t gintsts;
31085 + gintmsk_data_t gintmsk;
31086 + gintmsk_data_t gintmsk_common = {.d32 = 0 };
31087 + gintmsk_common.b.wkupintr = 1;
31088 + gintmsk_common.b.sessreqintr = 1;
31089 + gintmsk_common.b.conidstschng = 1;
31090 + gintmsk_common.b.otgintr = 1;
31091 + gintmsk_common.b.modemismatch = 1;
31092 + gintmsk_common.b.disconnect = 1;
31093 + gintmsk_common.b.usbsuspend = 1;
31094 +#ifdef CONFIG_USB_DWC_OTG_LPM
31095 + gintmsk_common.b.lpmtranrcvd = 1;
31097 + gintmsk_common.b.restoredone = 1;
31098 + /** @todo: The port interrupt occurs while in device
31099 + * mode. Added code to CIL to clear the interrupt for now!
31101 + gintmsk_common.b.portintr = 1;
31103 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
31104 + gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
31105 + gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
31108 + /* if any common interrupts set */
31109 + if (gintsts.d32 & gintmsk_common.d32) {
31110 + DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
31111 + gintsts.d32, gintmsk.d32);
31114 + if (gahbcfg.b.glblintrmsk)
31115 + return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
31121 +/* MACRO for clearing interupt bits in GPWRDN register */
31122 +#define CLEAR_GPWRDN_INTR(__core_if,__intr) \
31124 + gpwrdn_data_t gpwrdn = {.d32=0}; \
31125 + gpwrdn.b.__intr = 1; \
31126 + DWC_MODIFY_REG32(&__core_if->core_global_regs->gpwrdn, \
31127 + 0, gpwrdn.d32); \
31131 + * Common interrupt handler.
31133 + * The common interrupts are those that occur in both Host and Device mode.
31134 + * This handler handles the following interrupts:
31135 + * - Mode Mismatch Interrupt
31136 + * - Disconnect Interrupt
31137 + * - OTG Interrupt
31138 + * - Connector ID Status Change Interrupt
31139 + * - Session Request Interrupt.
31140 + * - Resume / Remote Wakeup Detected Interrupt.
31141 + * - LPM Transaction Received Interrupt
31142 + * - ADP Transaction Received Interrupt
31145 +int32_t dwc_otg_handle_common_intr(void *dev)
31148 + gintsts_data_t gintsts;
31149 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
31150 + dwc_otg_device_t *otg_dev = dev;
31151 + dwc_otg_core_if_t *core_if = otg_dev->core_if;
31152 + gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
31153 + if (dwc_otg_is_device_mode(core_if))
31154 + core_if->frame_num = dwc_otg_get_frame_number(core_if);
31156 + if (core_if->lock)
31157 + DWC_SPINLOCK(core_if->lock);
31159 + if (core_if->power_down == 3 && core_if->xhib == 1) {
31160 + DWC_DEBUGPL(DBG_ANY, "Exiting from xHIB state\n");
31161 + retval |= dwc_otg_handle_xhib_exit_intr(core_if);
31162 + core_if->xhib = 2;
31163 + if (core_if->lock)
31164 + DWC_SPINUNLOCK(core_if->lock);
31169 + if (core_if->hibernation_suspend <= 0) {
31170 + gintsts.d32 = dwc_otg_read_common_intr(core_if);
31172 + if (gintsts.b.modemismatch) {
31173 + retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
31175 + if (gintsts.b.otgintr) {
31176 + retval |= dwc_otg_handle_otg_intr(core_if);
31178 + if (gintsts.b.conidstschng) {
31180 + dwc_otg_handle_conn_id_status_change_intr(core_if);
31182 + if (gintsts.b.disconnect) {
31183 + retval |= dwc_otg_handle_disconnect_intr(core_if);
31185 + if (gintsts.b.sessreqintr) {
31186 + retval |= dwc_otg_handle_session_req_intr(core_if);
31188 + if (gintsts.b.wkupintr) {
31189 + retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
31191 + if (gintsts.b.usbsuspend) {
31192 + retval |= dwc_otg_handle_usb_suspend_intr(core_if);
31194 +#ifdef CONFIG_USB_DWC_OTG_LPM
31195 + if (gintsts.b.lpmtranrcvd) {
31196 + retval |= dwc_otg_handle_lpm_intr(core_if);
31199 + if (gintsts.b.restoredone) {
31201 + if (core_if->power_down == 2)
31202 + core_if->hibernation_suspend = -1;
31203 + else if (core_if->power_down == 3 && core_if->xhib == 2) {
31204 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
31205 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
31206 + dctl_data_t dctl = {.d32 = 0 };
31208 + DWC_WRITE_REG32(&core_if->core_global_regs->
31209 + gintsts, 0xFFFFFFFF);
31211 + DWC_DEBUGPL(DBG_ANY,
31212 + "RESTORE DONE generated\n");
31214 + gpwrdn.b.restore = 1;
31215 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
31218 + pcgcctl.b.rstpdwnmodule = 1;
31219 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
31221 + DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, core_if->gr_backup->gusbcfg_local);
31222 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, core_if->dr_backup->dcfg);
31223 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, core_if->dr_backup->dctl);
31226 + dctl.b.pwronprgdone = 1;
31227 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
31230 + dwc_otg_restore_global_regs(core_if);
31231 + dwc_otg_restore_dev_regs(core_if, 0);
31234 + dctl.b.pwronprgdone = 1;
31235 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
31239 + pcgcctl.b.enbl_extnd_hiber = 1;
31240 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
31242 + /* The core will be in ON STATE */
31243 + core_if->lx_state = DWC_OTG_L0;
31244 + core_if->xhib = 0;
31246 + DWC_SPINUNLOCK(core_if->lock);
31247 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
31248 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
31250 + DWC_SPINLOCK(core_if->lock);
31254 + gintsts.b.restoredone = 1;
31255 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
31256 + DWC_PRINTF(" --Restore done interrupt received-- \n");
31259 + if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
31260 + /* The port interrupt occurs while in device mode with HPRT0
31261 + * Port Enable/Disable.
31264 + gintsts.b.portintr = 1;
31265 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
31270 + DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
31272 + if (gpwrdn.b.disconn_det && gpwrdn.b.disconn_det_msk) {
31273 + CLEAR_GPWRDN_INTR(core_if, disconn_det);
31274 + if (gpwrdn.b.linestate == 0) {
31275 + dwc_otg_handle_pwrdn_disconnect_intr(core_if);
31277 + DWC_PRINTF("Disconnect detected while linestate is not 0\n");
31282 + if (gpwrdn.b.lnstschng && gpwrdn.b.lnstchng_msk) {
31283 + CLEAR_GPWRDN_INTR(core_if, lnstschng);
31284 + /* remote wakeup from hibernation */
31285 + if (gpwrdn.b.linestate == 2 || gpwrdn.b.linestate == 1) {
31286 + dwc_otg_handle_pwrdn_wakeup_detected_intr(core_if);
31288 + DWC_PRINTF("gpwrdn.linestate = %d\n", gpwrdn.b.linestate);
31292 + if (gpwrdn.b.rst_det && gpwrdn.b.rst_det_msk) {
31293 + CLEAR_GPWRDN_INTR(core_if, rst_det);
31294 + if (gpwrdn.b.linestate == 0) {
31295 + DWC_PRINTF("Reset detected\n");
31296 + retval |= dwc_otg_device_hibernation_restore(core_if, 0, 1);
31299 + if (gpwrdn.b.srp_det && gpwrdn.b.srp_det_msk) {
31300 + CLEAR_GPWRDN_INTR(core_if, srp_det);
31301 + dwc_otg_handle_pwrdn_srp_intr(core_if);
31305 + /* Handle ADP interrupt here */
31306 + if (gpwrdn.b.adp_int) {
31307 + DWC_PRINTF("ADP interrupt\n");
31308 + CLEAR_GPWRDN_INTR(core_if, adp_int);
31309 + dwc_otg_adp_handle_intr(core_if);
31312 + if (gpwrdn.b.sts_chngint && gpwrdn.b.sts_chngint_msk) {
31313 + DWC_PRINTF("STS CHNG interrupt asserted\n");
31314 + CLEAR_GPWRDN_INTR(core_if, sts_chngint);
31315 + dwc_otg_handle_pwrdn_stschng_intr(otg_dev);
31319 + if (core_if->lock)
31320 + DWC_SPINUNLOCK(core_if->lock);
31324 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_core_if.h b/drivers/usb/host/dwc_otg/dwc_otg_core_if.h
31325 new file mode 100644
31326 index 0000000..10b68c4
31328 +++ b/drivers/usb/host/dwc_otg/dwc_otg_core_if.h
31330 +/* ==========================================================================
31331 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $
31332 + * $Revision: #13 $
31333 + * $Date: 2012/08/10 $
31334 + * $Change: 2047372 $
31336 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
31337 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
31338 + * otherwise expressly agreed to in writing between Synopsys and you.
31340 + * The Software IS NOT an item of Licensed Software or Licensed Product under
31341 + * any End User Software License Agreement or Agreement for Licensed Product
31342 + * with Synopsys or any supplement thereto. You are permitted to use and
31343 + * redistribute this Software in source and binary forms, with or without
31344 + * modification, provided that redistributions of source code must retain this
31345 + * notice. You may not view, use, disclose, copy or distribute this file or
31346 + * any information contained herein except pursuant to this license grant from
31347 + * Synopsys. If you do not agree with this notice, including the disclaimer
31348 + * below, then you are not authorized to use the Software.
31350 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
31351 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31352 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31353 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
31354 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31355 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31356 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31357 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31358 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31359 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31361 + * ========================================================================== */
31362 +#if !defined(__DWC_CORE_IF_H__)
31363 +#define __DWC_CORE_IF_H__
31365 +#include "dwc_os.h"
31368 + * This file defines DWC_OTG Core API
31371 +struct dwc_otg_core_if;
31372 +typedef struct dwc_otg_core_if dwc_otg_core_if_t;
31374 +/** Maximum number of Periodic FIFOs */
31375 +#define MAX_PERIO_FIFOS 15
31376 +/** Maximum number of Periodic FIFOs */
31377 +#define MAX_TX_FIFOS 15
31379 +/** Maximum number of Endpoints/HostChannels */
31380 +#define MAX_EPS_CHANNELS 16
31382 +extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr);
31383 +extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if);
31384 +extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if);
31386 +extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if);
31387 +extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if);
31389 +extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if);
31390 +extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if);
31392 +extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if);
31394 +/** This function should be called on every hardware interrupt. */
31395 +extern int32_t dwc_otg_handle_common_intr(void *otg_dev);
31397 +/** @name OTG Core Parameters */
31401 + * Specifies the OTG capabilities. The driver will automatically
31402 + * detect the value for this parameter if none is specified.
31403 + * 0 - HNP and SRP capable (default)
31404 + * 1 - SRP Only capable
31405 + * 2 - No HNP/SRP capable
31407 +extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val);
31408 +extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if);
31409 +#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
31410 +#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
31411 +#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
31412 +#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
31414 +extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val);
31415 +extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if);
31416 +#define dwc_param_opt_default 1
31419 + * Specifies whether to use slave or DMA mode for accessing the data
31420 + * FIFOs. The driver will automatically detect the value for this
31421 + * parameter if none is specified.
31423 + * 1 - DMA (default, if available)
31425 +extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if,
31427 +extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if);
31428 +#define dwc_param_dma_enable_default 1
31431 + * When DMA mode is enabled specifies whether to use
31432 + * address DMA or DMA Descritor mode for accessing the data
31433 + * FIFOs in device mode. The driver will automatically detect
31434 + * the value for this parameter if none is specified.
31435 + * 0 - address DMA
31436 + * 1 - DMA Descriptor(default, if available)
31438 +extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if,
31440 +extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if);
31441 +//#define dwc_param_dma_desc_enable_default 1
31442 +#define dwc_param_dma_desc_enable_default 0 // Broadcom BCM2708
31444 +/** The DMA Burst size (applicable only for External DMA
31445 + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
31447 +extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if,
31449 +extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if);
31450 +#define dwc_param_dma_burst_size_default 32
31453 + * Specifies the maximum speed of operation in host and device mode.
31454 + * The actual speed depends on the speed of the attached device and
31455 + * the value of phy_type. The actual speed depends on the speed of the
31456 + * attached device.
31457 + * 0 - High Speed (default)
31460 +extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val);
31461 +extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if);
31462 +#define dwc_param_speed_default 0
31463 +#define DWC_SPEED_PARAM_HIGH 0
31464 +#define DWC_SPEED_PARAM_FULL 1
31466 +/** Specifies whether low power mode is supported when attached
31467 + * to a Full Speed or Low Speed device in host mode.
31468 + * 0 - Don't support low power mode (default)
31469 + * 1 - Support low power mode
31471 +extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
31472 + core_if, int32_t val);
31473 +extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t
31475 +#define dwc_param_host_support_fs_ls_low_power_default 0
31477 +/** Specifies the PHY clock rate in low power mode when connected to a
31478 + * Low Speed device in host mode. This parameter is applicable only if
31479 + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
31480 + * then defaults to 6 MHZ otherwise 48 MHZ.
31485 +extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
31486 + core_if, int32_t val);
31487 +extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
31489 +#define dwc_param_host_ls_low_power_phy_clk_default 0
31490 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
31491 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
31494 + * 0 - Use cC FIFO size parameters
31495 + * 1 - Allow dynamic FIFO sizing (default)
31497 +extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
31499 +extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t *
31501 +#define dwc_param_enable_dynamic_fifo_default 1
31503 +/** Total number of 4-byte words in the data FIFO memory. This
31504 + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
31506 + * 32 to 32768 (default 8192)
31507 + * Note: The total FIFO memory depth in the FPGA configuration is 8192.
31509 +extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if,
31511 +extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if);
31512 +//#define dwc_param_data_fifo_size_default 8192
31513 +#define dwc_param_data_fifo_size_default 0xFF0 // Broadcom BCM2708
31515 +/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
31516 + * FIFO sizing is enabled.
31517 + * 16 to 32768 (default 1064)
31519 +extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if,
31521 +extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if);
31522 +#define dwc_param_dev_rx_fifo_size_default 1064
31524 +/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
31525 + * when dynamic FIFO sizing is enabled.
31526 + * 16 to 32768 (default 1024)
31528 +extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
31529 + core_if, int32_t val);
31530 +extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
31532 +#define dwc_param_dev_nperio_tx_fifo_size_default 1024
31534 +/** Number of 4-byte words in each of the periodic Tx FIFOs in device
31535 + * mode when dynamic FIFO sizing is enabled.
31536 + * 4 to 768 (default 256)
31538 +extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
31539 + int32_t val, int fifo_num);
31540 +extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t *
31541 + core_if, int fifo_num);
31542 +#define dwc_param_dev_perio_tx_fifo_size_default 256
31544 +/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
31545 + * FIFO sizing is enabled.
31546 + * 16 to 32768 (default 1024)
31548 +extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
31550 +extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if);
31551 +//#define dwc_param_host_rx_fifo_size_default 1024
31552 +#define dwc_param_host_rx_fifo_size_default 774 // Broadcom BCM2708
31554 +/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
31555 + * when Dynamic FIFO sizing is enabled in the core.
31556 + * 16 to 32768 (default 1024)
31558 +extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
31559 + core_if, int32_t val);
31560 +extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
31562 +//#define dwc_param_host_nperio_tx_fifo_size_default 1024
31563 +#define dwc_param_host_nperio_tx_fifo_size_default 0x100 // Broadcom BCM2708
31565 +/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
31566 + * FIFO sizing is enabled.
31567 + * 16 to 32768 (default 1024)
31569 +extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
31570 + core_if, int32_t val);
31571 +extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
31573 +//#define dwc_param_host_perio_tx_fifo_size_default 1024
31574 +#define dwc_param_host_perio_tx_fifo_size_default 0x200 // Broadcom BCM2708
31576 +/** The maximum transfer size supported in bytes.
31577 + * 2047 to 65,535 (default 65,535)
31579 +extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
31581 +extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if);
31582 +#define dwc_param_max_transfer_size_default 65535
31584 +/** The maximum number of packets in a transfer.
31585 + * 15 to 511 (default 511)
31587 +extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if,
31589 +extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if);
31590 +#define dwc_param_max_packet_count_default 511
31592 +/** The number of host channel registers to use.
31593 + * 1 to 16 (default 12)
31594 + * Note: The FPGA configuration supports a maximum of 12 host channels.
31596 +extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if,
31598 +extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if);
31599 +//#define dwc_param_host_channels_default 12
31600 +#define dwc_param_host_channels_default 8 // Broadcom BCM2708
31602 +/** The number of endpoints in addition to EP0 available for device
31603 + * mode operations.
31604 + * 1 to 15 (default 6 IN and OUT)
31605 + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
31606 + * endpoints in addition to EP0.
31608 +extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if,
31610 +extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if);
31611 +#define dwc_param_dev_endpoints_default 6
31614 + * Specifies the type of PHY interface to use. By default, the driver
31615 + * will automatically detect the phy_type.
31617 + * 0 - Full Speed PHY
31618 + * 1 - UTMI+ (default)
31621 +extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val);
31622 +extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if);
31623 +#define DWC_PHY_TYPE_PARAM_FS 0
31624 +#define DWC_PHY_TYPE_PARAM_UTMI 1
31625 +#define DWC_PHY_TYPE_PARAM_ULPI 2
31626 +#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
31629 + * Specifies the UTMI+ Data Width. This parameter is
31630 + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
31631 + * PHY_TYPE, this parameter indicates the data width between
31632 + * the MAC and the ULPI Wrapper.) Also, this parameter is
31633 + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
31634 + * to "8 and 16 bits", meaning that the core has been
31635 + * configured to work at either data path width.
31637 + * 8 or 16 bits (default 16)
31639 +extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if,
31641 +extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if);
31642 +//#define dwc_param_phy_utmi_width_default 16
31643 +#define dwc_param_phy_utmi_width_default 8 // Broadcom BCM2708
31646 + * Specifies whether the ULPI operates at double or single
31647 + * data rate. This parameter is only applicable if PHY_TYPE is
31650 + * 0 - single data rate ULPI interface with 8 bit wide data
31652 + * 1 - double data rate ULPI interface with 4 bit wide data
31655 +extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if,
31657 +extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if);
31658 +#define dwc_param_phy_ulpi_ddr_default 0
31661 + * Specifies whether to use the internal or external supply to
31662 + * drive the vbus with a ULPI phy.
31664 +extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
31666 +extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if);
31667 +#define DWC_PHY_ULPI_INTERNAL_VBUS 0
31668 +#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
31669 +#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
31672 + * Specifies whether to use the I2Cinterface for full speed PHY. This
31673 + * parameter is only applicable if PHY_TYPE is FS.
31674 + * 0 - No (default)
31677 +extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if,
31679 +extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if);
31680 +#define dwc_param_i2c_enable_default 0
31682 +extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if,
31684 +extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if);
31685 +#define dwc_param_ulpi_fs_ls_default 0
31687 +extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val);
31688 +extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if);
31689 +#define dwc_param_ts_dline_default 0
31692 + * Specifies whether dedicated transmit FIFOs are
31693 + * enabled for non periodic IN endpoints in device mode
31697 +extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
31699 +extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t *
31701 +#define dwc_param_en_multiple_tx_fifo_default 1
31703 +/** Number of 4-byte words in each of the Tx FIFOs in device
31704 + * mode when dynamic FIFO sizing is enabled.
31705 + * 4 to 768 (default 256)
31707 +extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
31708 + int fifo_num, int32_t val);
31709 +extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
31711 +#define dwc_param_dev_tx_fifo_size_default 768
31713 +/** Thresholding enable flag-
31714 + * bit 0 - enable non-ISO Tx thresholding
31715 + * bit 1 - enable ISO Tx thresholding
31716 + * bit 2 - enable Rx thresholding
31718 +extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val);
31719 +extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num);
31720 +#define dwc_param_thr_ctl_default 0
31722 +/** Thresholding length for Tx
31723 + * FIFOs in 32 bit DWORDs
31725 +extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if,
31727 +extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if);
31728 +#define dwc_param_tx_thr_length_default 64
31730 +/** Thresholding length for Rx
31731 + * FIFOs in 32 bit DWORDs
31733 +extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if,
31735 +extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if);
31736 +#define dwc_param_rx_thr_length_default 64
31739 + * Specifies whether LPM (Link Power Management) support is enabled
31741 +extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if,
31743 +extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if);
31744 +#define dwc_param_lpm_enable_default 1
31747 + * Specifies whether PTI enhancement is enabled
31749 +extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if,
31751 +extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if);
31752 +#define dwc_param_pti_enable_default 0
31755 + * Specifies whether MPI enhancement is enabled
31757 +extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if,
31759 +extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if);
31760 +#define dwc_param_mpi_enable_default 0
31763 + * Specifies whether ADP capability is enabled
31765 +extern int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if,
31767 +extern int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if);
31768 +#define dwc_param_adp_enable_default 0
31771 + * Specifies whether IC_USB capability is enabled
31774 +extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
31776 +extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if);
31777 +#define dwc_param_ic_usb_cap_default 0
31779 +extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if,
31781 +extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if);
31782 +#define dwc_param_ahb_thr_ratio_default 0
31784 +extern int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if,
31786 +extern int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if);
31787 +#define dwc_param_power_down_default 0
31789 +extern int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if,
31791 +extern int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if);
31792 +#define dwc_param_reload_ctl_default 0
31794 +extern int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if,
31796 +extern int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if);
31797 +#define dwc_param_dev_out_nak_default 0
31799 +extern int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if,
31801 +extern int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if);
31802 +#define dwc_param_cont_on_bna_default 0
31804 +extern int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if,
31806 +extern int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if);
31807 +#define dwc_param_ahb_single_default 0
31809 +extern int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val);
31810 +extern int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if);
31811 +#define dwc_param_otg_ver_default 0
31815 +/** @name Access to registers and bit-fields */
31818 + * Dump core registers and SPRAM
31820 +extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if);
31821 +extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if);
31822 +extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if);
31823 +extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if);
31826 + * Get host negotiation status.
31828 +extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if);
31833 +extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if);
31836 + * Set hnpreq bit in the GOTGCTL register.
31838 +extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val);
31841 + * Get Content of SNPSID register.
31843 +extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if);
31846 + * Get current mode.
31847 + * Returns 0 if in device mode, and 1 if in host mode.
31849 +extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if);
31852 + * Get value of hnpcapable field in the GUSBCFG register
31854 +extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if);
31856 + * Set value of hnpcapable field in the GUSBCFG register
31858 +extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
31861 + * Get value of srpcapable field in the GUSBCFG register
31863 +extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if);
31865 + * Set value of srpcapable field in the GUSBCFG register
31867 +extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
31870 + * Get value of devspeed field in the DCFG register
31872 +extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if);
31874 + * Set value of devspeed field in the DCFG register
31876 +extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val);
31879 + * Get the value of busconnected field from the HPRT0 register
31881 +extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if);
31884 + * Gets the device enumeration Speed.
31886 +extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if);
31889 + * Get value of prtpwr field from the HPRT0 register
31891 +extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if);
31894 + * Get value of flag indicating core state - hibernated or not
31896 +extern uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if);
31899 + * Set value of prtpwr field from the HPRT0 register
31901 +extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val);
31904 + * Get value of prtsusp field from the HPRT0 regsiter
31906 +extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if);
31908 + * Set value of prtpwr field from the HPRT0 register
31910 +extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val);
31913 + * Get value of ModeChTimEn field from the HCFG regsiter
31915 +extern uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if);
31917 + * Set value of ModeChTimEn field from the HCFG regsiter
31919 +extern void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val);
31922 + * Get value of Fram Interval field from the HFIR regsiter
31924 +extern uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if);
31926 + * Set value of Frame Interval field from the HFIR regsiter
31928 +extern void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val);
31931 + * Set value of prtres field from the HPRT0 register
31934 +extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val);
31937 + * Get value of rmtwkupsig bit in DCTL register
31939 +extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if);
31942 + * Get value of prt_sleep_sts field from the GLPMCFG register
31944 +extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if);
31947 + * Get value of rem_wkup_en field from the GLPMCFG register
31949 +extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if);
31952 + * Get value of appl_resp field from the GLPMCFG register
31954 +extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if);
31956 + * Set value of appl_resp field from the GLPMCFG register
31958 +extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val);
31961 + * Get value of hsic_connect field from the GLPMCFG register
31963 +extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if);
31965 + * Set value of hsic_connect field from the GLPMCFG register
31967 +extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val);
31970 + * Get value of inv_sel_hsic field from the GLPMCFG register.
31972 +extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if);
31974 + * Set value of inv_sel_hsic field from the GLPMFG register.
31976 +extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val);
31979 + * Some functions for accessing registers
31983 + * GOTGCTL register
31985 +extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if);
31986 +extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val);
31989 + * GUSBCFG register
31991 +extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if);
31992 +extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val);
31995 + * GRXFSIZ register
31997 +extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if);
31998 +extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
32001 + * GNPTXFSIZ register
32003 +extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if);
32004 +extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
32006 +extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if);
32007 +extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val);
32012 +extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if);
32013 +extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val);
32018 +extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if);
32019 +extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val);
32024 +extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if);
32025 +extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val);
32030 +extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if);
32034 +#endif /* __DWC_CORE_IF_H__ */
32035 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_dbg.h b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h
32036 new file mode 100644
32037 index 0000000..8681aa9
32039 +++ b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h
32041 +/* ==========================================================================
32043 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
32044 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
32045 + * otherwise expressly agreed to in writing between Synopsys and you.
32047 + * The Software IS NOT an item of Licensed Software or Licensed Product under
32048 + * any End User Software License Agreement or Agreement for Licensed Product
32049 + * with Synopsys or any supplement thereto. You are permitted to use and
32050 + * redistribute this Software in source and binary forms, with or without
32051 + * modification, provided that redistributions of source code must retain this
32052 + * notice. You may not view, use, disclose, copy or distribute this file or
32053 + * any information contained herein except pursuant to this license grant from
32054 + * Synopsys. If you do not agree with this notice, including the disclaimer
32055 + * below, then you are not authorized to use the Software.
32057 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
32058 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32059 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32060 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
32061 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32062 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32063 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32064 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32065 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32066 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32068 + * ========================================================================== */
32070 +#ifndef __DWC_OTG_DBG_H__
32071 +#define __DWC_OTG_DBG_H__
32074 + * This file defines debug levels.
32075 + * Debugging support vanishes in non-debug builds.
32079 + * The Debug Level bit-mask variable.
32081 +extern uint32_t g_dbg_lvl;
32083 + * Set the Debug Level variable.
32085 +static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new)
32087 + uint32_t old = g_dbg_lvl;
32092 +/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
32093 +#define DBG_CIL (0x2)
32094 +/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
32096 +#define DBG_CILV (0x20)
32097 +/** When debug level has the DBG_PCD bit set, display PCD (Device) debug
32099 +#define DBG_PCD (0x4)
32100 +/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
32102 +#define DBG_PCDV (0x40)
32103 +/** When debug level has the DBG_HCD bit set, display Host debug messages */
32104 +#define DBG_HCD (0x8)
32105 +/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
32107 +#define DBG_HCDV (0x80)
32108 +/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
32110 +#define DBG_HCD_URB (0x800)
32111 +/** When debug level has the DBG_HCDI bit set, display host interrupt
32113 +#define DBG_HCDI (0x1000)
32115 +/** When debug level has any bit set, display debug messages */
32116 +#define DBG_ANY (0xFF)
32118 +/** All debug messages off */
32121 +/** Prefix string for DWC_DEBUG print macros. */
32122 +#define USB_DWC "DWC_otg: "
32125 + * Print a debug message when the Global debug level variable contains
32126 + * the bit defined in <code>lvl</code>.
32128 + * @param[in] lvl - Debug level, use one of the DBG_ constants above.
32129 + * @param[in] x - like printf
32133 + * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
32136 + * results in:<br>
32138 + * usb-DWC_otg: dwc_otg_cil_init(ca867000)
32143 +# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0)
32144 +# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x )
32146 +# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
32150 +# define DWC_DEBUGPL(lvl, x...) do{}while(0)
32151 +# define DWC_DEBUGP(x...)
32153 +# define CHK_DEBUG_LEVEL(level) (0)
32157 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
32158 new file mode 100644
32159 index 0000000..e7f99e1
32161 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
32163 +/* ==========================================================================
32164 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $
32165 + * $Revision: #92 $
32166 + * $Date: 2012/08/10 $
32167 + * $Change: 2047372 $
32169 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
32170 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
32171 + * otherwise expressly agreed to in writing between Synopsys and you.
32173 + * The Software IS NOT an item of Licensed Software or Licensed Product under
32174 + * any End User Software License Agreement or Agreement for Licensed Product
32175 + * with Synopsys or any supplement thereto. You are permitted to use and
32176 + * redistribute this Software in source and binary forms, with or without
32177 + * modification, provided that redistributions of source code must retain this
32178 + * notice. You may not view, use, disclose, copy or distribute this file or
32179 + * any information contained herein except pursuant to this license grant from
32180 + * Synopsys. If you do not agree with this notice, including the disclaimer
32181 + * below, then you are not authorized to use the Software.
32183 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
32184 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32185 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32186 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
32187 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32188 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32189 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32190 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32191 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32192 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32194 + * ========================================================================== */
32197 + * The dwc_otg_driver module provides the initialization and cleanup entry
32198 + * points for the DWC_otg driver. This module will be dynamically installed
32199 + * after Linux is booted using the insmod command. When the module is
32200 + * installed, the dwc_otg_driver_init function is called. When the module is
32201 + * removed (using rmmod), the dwc_otg_driver_cleanup function is called.
32203 + * This module also defines a data structure for the dwc_otg_driver, which is
32204 + * used in conjunction with the standard ARM lm_device structure. These
32205 + * structures allow the OTG driver to comply with the standard Linux driver
32206 + * model in which devices and drivers are registered with a bus driver. This
32207 + * has the benefit that Linux can expose attributes of the driver and device
32208 + * in its special sysfs file system. Users can then read or write files in
32209 + * this file system to perform diagnostics on the driver components or the
32213 +#include "dwc_otg_os_dep.h"
32214 +#include "dwc_os.h"
32215 +#include "dwc_otg_dbg.h"
32216 +#include "dwc_otg_driver.h"
32217 +#include "dwc_otg_attr.h"
32218 +#include "dwc_otg_core_if.h"
32219 +#include "dwc_otg_pcd_if.h"
32220 +#include "dwc_otg_hcd_if.h"
32222 +#define DWC_DRIVER_VERSION "3.00a 10-AUG-2012"
32223 +#define DWC_DRIVER_DESC "HS OTG USB Controller driver"
32225 +bool microframe_schedule=true;
32227 +static const char dwc_driver_name[] = "dwc_otg";
32229 +extern int pcd_init(
32230 +#ifdef LM_INTERFACE
32231 + struct lm_device *_dev
32232 +#elif defined(PCI_INTERFACE)
32233 + struct pci_dev *_dev
32234 +#elif defined(PLATFORM_INTERFACE)
32235 + struct platform_device *dev
32238 +extern int hcd_init(
32239 +#ifdef LM_INTERFACE
32240 + struct lm_device *_dev
32241 +#elif defined(PCI_INTERFACE)
32242 + struct pci_dev *_dev
32243 +#elif defined(PLATFORM_INTERFACE)
32244 + struct platform_device *dev
32248 +extern int pcd_remove(
32249 +#ifdef LM_INTERFACE
32250 + struct lm_device *_dev
32251 +#elif defined(PCI_INTERFACE)
32252 + struct pci_dev *_dev
32253 +#elif defined(PLATFORM_INTERFACE)
32254 + struct platform_device *_dev
32258 +extern void hcd_remove(
32259 +#ifdef LM_INTERFACE
32260 + struct lm_device *_dev
32261 +#elif defined(PCI_INTERFACE)
32262 + struct pci_dev *_dev
32263 +#elif defined(PLATFORM_INTERFACE)
32264 + struct platform_device *_dev
32268 +extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
32270 +/*-------------------------------------------------------------------------*/
32271 +/* Encapsulate the module parameter settings */
32273 +struct dwc_otg_driver_module_params {
32276 + int32_t dma_enable;
32277 + int32_t dma_desc_enable;
32278 + int32_t dma_burst_size;
32280 + int32_t host_support_fs_ls_low_power;
32281 + int32_t host_ls_low_power_phy_clk;
32282 + int32_t enable_dynamic_fifo;
32283 + int32_t data_fifo_size;
32284 + int32_t dev_rx_fifo_size;
32285 + int32_t dev_nperio_tx_fifo_size;
32286 + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
32287 + int32_t host_rx_fifo_size;
32288 + int32_t host_nperio_tx_fifo_size;
32289 + int32_t host_perio_tx_fifo_size;
32290 + int32_t max_transfer_size;
32291 + int32_t max_packet_count;
32292 + int32_t host_channels;
32293 + int32_t dev_endpoints;
32294 + int32_t phy_type;
32295 + int32_t phy_utmi_width;
32296 + int32_t phy_ulpi_ddr;
32297 + int32_t phy_ulpi_ext_vbus;
32298 + int32_t i2c_enable;
32299 + int32_t ulpi_fs_ls;
32300 + int32_t ts_dline;
32301 + int32_t en_multiple_tx_fifo;
32302 + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
32303 + uint32_t thr_ctl;
32304 + uint32_t tx_thr_length;
32305 + uint32_t rx_thr_length;
32306 + int32_t pti_enable;
32307 + int32_t mpi_enable;
32308 + int32_t lpm_enable;
32309 + int32_t ic_usb_cap;
32310 + int32_t ahb_thr_ratio;
32311 + int32_t power_down;
32312 + int32_t reload_ctl;
32313 + int32_t dev_out_nak;
32314 + int32_t cont_on_bna;
32315 + int32_t ahb_single;
32317 + int32_t adp_enable;
32320 +static struct dwc_otg_driver_module_params dwc_otg_module_params = {
32323 + .dma_enable = -1,
32324 + .dma_desc_enable = -1,
32325 + .dma_burst_size = -1,
32327 + .host_support_fs_ls_low_power = -1,
32328 + .host_ls_low_power_phy_clk = -1,
32329 + .enable_dynamic_fifo = -1,
32330 + .data_fifo_size = -1,
32331 + .dev_rx_fifo_size = -1,
32332 + .dev_nperio_tx_fifo_size = -1,
32333 + .dev_perio_tx_fifo_size = {
32334 + /* dev_perio_tx_fifo_size_1 */
32352 + .host_rx_fifo_size = -1,
32353 + .host_nperio_tx_fifo_size = -1,
32354 + .host_perio_tx_fifo_size = -1,
32355 + .max_transfer_size = -1,
32356 + .max_packet_count = -1,
32357 + .host_channels = -1,
32358 + .dev_endpoints = -1,
32360 + .phy_utmi_width = -1,
32361 + .phy_ulpi_ddr = -1,
32362 + .phy_ulpi_ext_vbus = -1,
32363 + .i2c_enable = -1,
32364 + .ulpi_fs_ls = -1,
32366 + .en_multiple_tx_fifo = -1,
32367 + .dev_tx_fifo_size = {
32368 + /* dev_tx_fifo_size */
32387 + .tx_thr_length = -1,
32388 + .rx_thr_length = -1,
32389 + .pti_enable = -1,
32390 + .mpi_enable = -1,
32391 + .lpm_enable = -1,
32392 + .ic_usb_cap = -1,
32393 + .ahb_thr_ratio = -1,
32394 + .power_down = -1,
32395 + .reload_ctl = -1,
32396 + .dev_out_nak = -1,
32397 + .cont_on_bna = -1,
32398 + .ahb_single = -1,
32400 + .adp_enable = -1,
32404 + * This function shows the Driver Version.
32406 +static ssize_t version_show(struct device_driver *dev, char *buf)
32408 + return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n",
32409 + DWC_DRIVER_VERSION);
32412 +static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
32415 + * Global Debug Level Mask.
32417 +uint32_t g_dbg_lvl = 0; /* OFF */
32420 + * This function shows the driver Debug Level.
32422 +static ssize_t dbg_level_show(struct device_driver *drv, char *buf)
32424 + return sprintf(buf, "0x%0x\n", g_dbg_lvl);
32428 + * This function stores the driver Debug Level.
32430 +static ssize_t dbg_level_store(struct device_driver *drv, const char *buf,
32433 + g_dbg_lvl = simple_strtoul(buf, NULL, 16);
32437 +static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show,
32438 + dbg_level_store);
32441 + * This function is called during module intialization
32442 + * to pass module parameters to the DWC_OTG CORE.
32444 +static int set_parameters(dwc_otg_core_if_t * core_if)
32449 + if (dwc_otg_module_params.otg_cap != -1) {
32451 + dwc_otg_set_param_otg_cap(core_if,
32452 + dwc_otg_module_params.otg_cap);
32454 + if (dwc_otg_module_params.dma_enable != -1) {
32456 + dwc_otg_set_param_dma_enable(core_if,
32457 + dwc_otg_module_params.
32460 + if (dwc_otg_module_params.dma_desc_enable != -1) {
32462 + dwc_otg_set_param_dma_desc_enable(core_if,
32463 + dwc_otg_module_params.
32464 + dma_desc_enable);
32466 + if (dwc_otg_module_params.opt != -1) {
32468 + dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt);
32470 + if (dwc_otg_module_params.dma_burst_size != -1) {
32472 + dwc_otg_set_param_dma_burst_size(core_if,
32473 + dwc_otg_module_params.
32476 + if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) {
32478 + dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
32479 + dwc_otg_module_params.
32480 + host_support_fs_ls_low_power);
32482 + if (dwc_otg_module_params.enable_dynamic_fifo != -1) {
32484 + dwc_otg_set_param_enable_dynamic_fifo(core_if,
32485 + dwc_otg_module_params.
32486 + enable_dynamic_fifo);
32488 + if (dwc_otg_module_params.data_fifo_size != -1) {
32490 + dwc_otg_set_param_data_fifo_size(core_if,
32491 + dwc_otg_module_params.
32494 + if (dwc_otg_module_params.dev_rx_fifo_size != -1) {
32496 + dwc_otg_set_param_dev_rx_fifo_size(core_if,
32497 + dwc_otg_module_params.
32498 + dev_rx_fifo_size);
32500 + if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) {
32502 + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
32503 + dwc_otg_module_params.
32504 + dev_nperio_tx_fifo_size);
32506 + if (dwc_otg_module_params.host_rx_fifo_size != -1) {
32508 + dwc_otg_set_param_host_rx_fifo_size(core_if,
32509 + dwc_otg_module_params.host_rx_fifo_size);
32511 + if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) {
32513 + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
32514 + dwc_otg_module_params.
32515 + host_nperio_tx_fifo_size);
32517 + if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) {
32519 + dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
32520 + dwc_otg_module_params.
32521 + host_perio_tx_fifo_size);
32523 + if (dwc_otg_module_params.max_transfer_size != -1) {
32525 + dwc_otg_set_param_max_transfer_size(core_if,
32526 + dwc_otg_module_params.
32527 + max_transfer_size);
32529 + if (dwc_otg_module_params.max_packet_count != -1) {
32531 + dwc_otg_set_param_max_packet_count(core_if,
32532 + dwc_otg_module_params.
32533 + max_packet_count);
32535 + if (dwc_otg_module_params.host_channels != -1) {
32537 + dwc_otg_set_param_host_channels(core_if,
32538 + dwc_otg_module_params.
32541 + if (dwc_otg_module_params.dev_endpoints != -1) {
32543 + dwc_otg_set_param_dev_endpoints(core_if,
32544 + dwc_otg_module_params.
32547 + if (dwc_otg_module_params.phy_type != -1) {
32549 + dwc_otg_set_param_phy_type(core_if,
32550 + dwc_otg_module_params.phy_type);
32552 + if (dwc_otg_module_params.speed != -1) {
32554 + dwc_otg_set_param_speed(core_if,
32555 + dwc_otg_module_params.speed);
32557 + if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) {
32559 + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
32560 + dwc_otg_module_params.
32561 + host_ls_low_power_phy_clk);
32563 + if (dwc_otg_module_params.phy_ulpi_ddr != -1) {
32565 + dwc_otg_set_param_phy_ulpi_ddr(core_if,
32566 + dwc_otg_module_params.
32569 + if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) {
32571 + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
32572 + dwc_otg_module_params.
32573 + phy_ulpi_ext_vbus);
32575 + if (dwc_otg_module_params.phy_utmi_width != -1) {
32577 + dwc_otg_set_param_phy_utmi_width(core_if,
32578 + dwc_otg_module_params.
32581 + if (dwc_otg_module_params.ulpi_fs_ls != -1) {
32583 + dwc_otg_set_param_ulpi_fs_ls(core_if,
32584 + dwc_otg_module_params.ulpi_fs_ls);
32586 + if (dwc_otg_module_params.ts_dline != -1) {
32588 + dwc_otg_set_param_ts_dline(core_if,
32589 + dwc_otg_module_params.ts_dline);
32591 + if (dwc_otg_module_params.i2c_enable != -1) {
32593 + dwc_otg_set_param_i2c_enable(core_if,
32594 + dwc_otg_module_params.
32597 + if (dwc_otg_module_params.en_multiple_tx_fifo != -1) {
32599 + dwc_otg_set_param_en_multiple_tx_fifo(core_if,
32600 + dwc_otg_module_params.
32601 + en_multiple_tx_fifo);
32603 + for (i = 0; i < 15; i++) {
32604 + if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) {
32606 + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
32607 + dwc_otg_module_params.
32608 + dev_perio_tx_fifo_size
32613 + for (i = 0; i < 15; i++) {
32614 + if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) {
32615 + retval += dwc_otg_set_param_dev_tx_fifo_size(core_if,
32616 + dwc_otg_module_params.
32621 + if (dwc_otg_module_params.thr_ctl != -1) {
32623 + dwc_otg_set_param_thr_ctl(core_if,
32624 + dwc_otg_module_params.thr_ctl);
32626 + if (dwc_otg_module_params.mpi_enable != -1) {
32628 + dwc_otg_set_param_mpi_enable(core_if,
32629 + dwc_otg_module_params.
32632 + if (dwc_otg_module_params.pti_enable != -1) {
32634 + dwc_otg_set_param_pti_enable(core_if,
32635 + dwc_otg_module_params.
32638 + if (dwc_otg_module_params.lpm_enable != -1) {
32640 + dwc_otg_set_param_lpm_enable(core_if,
32641 + dwc_otg_module_params.
32644 + if (dwc_otg_module_params.ic_usb_cap != -1) {
32646 + dwc_otg_set_param_ic_usb_cap(core_if,
32647 + dwc_otg_module_params.
32650 + if (dwc_otg_module_params.tx_thr_length != -1) {
32652 + dwc_otg_set_param_tx_thr_length(core_if,
32653 + dwc_otg_module_params.tx_thr_length);
32655 + if (dwc_otg_module_params.rx_thr_length != -1) {
32657 + dwc_otg_set_param_rx_thr_length(core_if,
32658 + dwc_otg_module_params.
32661 + if (dwc_otg_module_params.ahb_thr_ratio != -1) {
32663 + dwc_otg_set_param_ahb_thr_ratio(core_if,
32664 + dwc_otg_module_params.ahb_thr_ratio);
32666 + if (dwc_otg_module_params.power_down != -1) {
32668 + dwc_otg_set_param_power_down(core_if,
32669 + dwc_otg_module_params.power_down);
32671 + if (dwc_otg_module_params.reload_ctl != -1) {
32673 + dwc_otg_set_param_reload_ctl(core_if,
32674 + dwc_otg_module_params.reload_ctl);
32677 + if (dwc_otg_module_params.dev_out_nak != -1) {
32679 + dwc_otg_set_param_dev_out_nak(core_if,
32680 + dwc_otg_module_params.dev_out_nak);
32683 + if (dwc_otg_module_params.cont_on_bna != -1) {
32685 + dwc_otg_set_param_cont_on_bna(core_if,
32686 + dwc_otg_module_params.cont_on_bna);
32689 + if (dwc_otg_module_params.ahb_single != -1) {
32691 + dwc_otg_set_param_ahb_single(core_if,
32692 + dwc_otg_module_params.ahb_single);
32695 + if (dwc_otg_module_params.otg_ver != -1) {
32697 + dwc_otg_set_param_otg_ver(core_if,
32698 + dwc_otg_module_params.otg_ver);
32700 + if (dwc_otg_module_params.adp_enable != -1) {
32702 + dwc_otg_set_param_adp_enable(core_if,
32703 + dwc_otg_module_params.
32710 + * This function is the top level interrupt handler for the Common
32711 + * (Device and host modes) interrupts.
32713 +static irqreturn_t dwc_otg_common_irq(int irq, void *dev)
32715 + int32_t retval = IRQ_NONE;
32717 + retval = dwc_otg_handle_common_intr(dev);
32718 + if (retval != 0) {
32719 + S3C2410X_CLEAR_EINTPEND();
32721 + return IRQ_RETVAL(retval);
32725 + * This function is called when a lm_device is unregistered with the
32726 + * dwc_otg_driver. This happens, for example, when the rmmod command is
32727 + * executed. The device may or may not be electrically present. If it is
32728 + * present, the driver stops device processing. Any resources used on behalf
32729 + * of this device are freed.
32733 +#ifdef LM_INTERFACE
32734 +#define REM_RETVAL(n)
32735 +static void dwc_otg_driver_remove( struct lm_device *_dev )
32736 +{ dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
32737 +#elif defined(PCI_INTERFACE)
32738 +#define REM_RETVAL(n)
32739 +static void dwc_otg_driver_remove( struct pci_dev *_dev )
32740 +{ dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
32741 +#elif defined(PLATFORM_INTERFACE)
32742 +#define REM_RETVAL(n) n
32743 +static int dwc_otg_driver_remove( struct platform_device *_dev )
32744 +{ dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
32747 + DWC_DEBUGPL(DBG_ANY, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
32750 + /* Memory allocation for the dwc_otg_device failed. */
32751 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
32752 + return REM_RETVAL(-ENOMEM);
32754 +#ifndef DWC_DEVICE_ONLY
32755 + if (otg_dev->hcd) {
32756 + hcd_remove(_dev);
32758 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
32759 + return REM_RETVAL(-EINVAL);
32763 +#ifndef DWC_HOST_ONLY
32764 + if (otg_dev->pcd) {
32765 + pcd_remove(_dev);
32767 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->pcd NULL!\n", __func__);
32768 + return REM_RETVAL(-EINVAL);
32774 + if (otg_dev->common_irq_installed) {
32775 +#ifdef PLATFORM_INTERFACE
32776 + free_irq(platform_get_irq(_dev, 0), otg_dev);
32778 + free_irq(_dev->irq, otg_dev);
32781 + DWC_DEBUGPL(DBG_ANY, "%s: There is no installed irq!\n", __func__);
32782 + return REM_RETVAL(-ENXIO);
32785 + if (otg_dev->core_if) {
32786 + dwc_otg_cil_remove(otg_dev->core_if);
32788 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->core_if NULL!\n", __func__);
32789 + return REM_RETVAL(-ENXIO);
32793 + * Remove the device attributes
32795 + dwc_otg_attr_remove(_dev);
32798 + * Return the memory.
32800 + if (otg_dev->os_dep.base) {
32801 + iounmap(otg_dev->os_dep.base);
32803 + DWC_FREE(otg_dev);
32806 + * Clear the drvdata pointer.
32808 +#ifdef LM_INTERFACE
32809 + lm_set_drvdata(_dev, 0);
32810 +#elif defined(PCI_INTERFACE)
32811 + release_mem_region(otg_dev->os_dep.rsrc_start,
32812 + otg_dev->os_dep.rsrc_len);
32813 + pci_set_drvdata(_dev, 0);
32814 +#elif defined(PLATFORM_INTERFACE)
32815 + platform_set_drvdata(_dev, 0);
32817 + return REM_RETVAL(0);
32821 + * This function is called when an lm_device is bound to a
32822 + * dwc_otg_driver. It creates the driver components required to
32823 + * control the device (CIL, HCD, and PCD) and it initializes the
32824 + * device. The driver components are stored in a dwc_otg_device
32825 + * structure. A reference to the dwc_otg_device is saved in the
32826 + * lm_device. This allows the driver to access the dwc_otg_device
32827 + * structure on subsequent calls to driver methods for this device.
32829 + * @param _dev Bus device
32831 +static int dwc_otg_driver_probe(
32832 +#ifdef LM_INTERFACE
32833 + struct lm_device *_dev
32834 +#elif defined(PCI_INTERFACE)
32835 + struct pci_dev *_dev,
32836 + const struct pci_device_id *id
32837 +#elif defined(PLATFORM_INTERFACE)
32838 + struct platform_device *_dev
32843 + dwc_otg_device_t *dwc_otg_device;
32846 + dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev);
32847 +#ifdef LM_INTERFACE
32848 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource.start);
32849 +#elif defined(PCI_INTERFACE)
32851 + DWC_ERROR("Invalid pci_device_id %p", id);
32855 + if (!_dev || (pci_enable_device(_dev) < 0)) {
32856 + DWC_ERROR("Invalid pci_device %p", _dev);
32859 + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(_dev,0));
32860 + /* other stuff needed as well? */
32862 +#elif defined(PLATFORM_INTERFACE)
32863 + dev_dbg(&_dev->dev, "start=0x%08x (len 0x%x)\n",
32864 + (unsigned)_dev->resource->start,
32865 + (unsigned)(_dev->resource->end - _dev->resource->start));
32868 + dwc_otg_device = DWC_ALLOC(sizeof(dwc_otg_device_t));
32870 + if (!dwc_otg_device) {
32871 + dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n");
32875 + memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
32876 + dwc_otg_device->os_dep.reg_offset = 0xFFFFFFFF;
32879 + * Map the DWC_otg Core memory into virtual address space.
32881 +#ifdef LM_INTERFACE
32882 + dwc_otg_device->os_dep.base = ioremap(_dev->resource.start, SZ_256K);
32884 + if (!dwc_otg_device->os_dep.base) {
32885 + dev_err(&_dev->dev, "ioremap() failed\n");
32886 + DWC_FREE(dwc_otg_device);
32889 + dev_dbg(&_dev->dev, "base=0x%08x\n",
32890 + (unsigned)dwc_otg_device->os_dep.base);
32891 +#elif defined(PCI_INTERFACE)
32892 + _dev->current_state = PCI_D0;
32893 + _dev->dev.power.power_state = PMSG_ON;
32895 + if (!_dev->irq) {
32896 + DWC_ERROR("Found HC with no IRQ. Check BIOS/PCI %s setup!",
32898 + iounmap(dwc_otg_device->os_dep.base);
32899 + DWC_FREE(dwc_otg_device);
32903 + dwc_otg_device->os_dep.rsrc_start = pci_resource_start(_dev, 0);
32904 + dwc_otg_device->os_dep.rsrc_len = pci_resource_len(_dev, 0);
32905 + DWC_DEBUGPL(DBG_ANY, "PCI resource: start=%08x, len=%08x\n",
32906 + (unsigned)dwc_otg_device->os_dep.rsrc_start,
32907 + (unsigned)dwc_otg_device->os_dep.rsrc_len);
32908 + if (!request_mem_region
32909 + (dwc_otg_device->os_dep.rsrc_start, dwc_otg_device->os_dep.rsrc_len,
32911 + dev_dbg(&_dev->dev, "error requesting memory\n");
32912 + iounmap(dwc_otg_device->os_dep.base);
32913 + DWC_FREE(dwc_otg_device);
32917 + dwc_otg_device->os_dep.base =
32918 + ioremap_nocache(dwc_otg_device->os_dep.rsrc_start,
32919 + dwc_otg_device->os_dep.rsrc_len);
32920 + if (dwc_otg_device->os_dep.base == NULL) {
32921 + dev_dbg(&_dev->dev, "error mapping memory\n");
32922 + release_mem_region(dwc_otg_device->os_dep.rsrc_start,
32923 + dwc_otg_device->os_dep.rsrc_len);
32924 + iounmap(dwc_otg_device->os_dep.base);
32925 + DWC_FREE(dwc_otg_device);
32928 + dev_dbg(&_dev->dev, "base=0x%p (before adjust) \n",
32929 + dwc_otg_device->os_dep.base);
32930 + dwc_otg_device->os_dep.base = (char *)dwc_otg_device->os_dep.base;
32931 + dev_dbg(&_dev->dev, "base=0x%p (after adjust) \n",
32932 + dwc_otg_device->os_dep.base);
32933 + dev_dbg(&_dev->dev, "%s: mapped PA 0x%x to VA 0x%p\n", __func__,
32934 + (unsigned)dwc_otg_device->os_dep.rsrc_start,
32935 + dwc_otg_device->os_dep.base);
32937 + pci_set_master(_dev);
32938 + pci_set_drvdata(_dev, dwc_otg_device);
32939 +#elif defined(PLATFORM_INTERFACE)
32940 + DWC_DEBUGPL(DBG_ANY,"Platform resource: start=%08x, len=%08x\n",
32941 + _dev->resource->start,
32942 + _dev->resource->end - _dev->resource->start + 1);
32944 + if (!request_mem_region(_dev->resource->start,
32945 + _dev->resource->end - _dev->resource->start + 1,
32947 + dev_dbg(&_dev->dev, "error reserving mapped memory\n");
32948 + retval = -EFAULT;
32952 + dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource->start,
32953 + _dev->resource->end -
32954 + _dev->resource->start+1);
32957 + struct map_desc desc = {
32958 + .virtual = IO_ADDRESS((unsigned)_dev->resource->start),
32959 + .pfn = __phys_to_pfn((unsigned)_dev->resource->start),
32960 + .length = SZ_128K,
32961 + .type = MT_DEVICE
32963 + iotable_init(&desc, 1);
32964 + dwc_otg_device->os_dep.base = (void *)desc.virtual;
32967 + if (!dwc_otg_device->os_dep.base) {
32968 + dev_err(&_dev->dev, "ioremap() failed\n");
32969 + retval = -ENOMEM;
32972 + dev_dbg(&_dev->dev, "base=0x%08x\n",
32973 + (unsigned)dwc_otg_device->os_dep.base);
32977 + * Initialize driver data to point to the global DWC_otg
32978 + * Device structure.
32980 +#ifdef LM_INTERFACE
32981 + lm_set_drvdata(_dev, dwc_otg_device);
32982 +#elif defined(PLATFORM_INTERFACE)
32983 + platform_set_drvdata(_dev, dwc_otg_device);
32985 + dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device);
32987 + dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->os_dep.base);
32988 + DWC_DEBUGPL(DBG_HCDV, "probe of device %p given core_if %p\n",
32989 + dwc_otg_device, dwc_otg_device->core_if);//GRAYG
32991 + if (!dwc_otg_device->core_if) {
32992 + dev_err(&_dev->dev, "CIL initialization failed!\n");
32993 + retval = -ENOMEM;
32997 + dev_dbg(&_dev->dev, "Calling get_gsnpsid\n");
32999 + * Attempt to ensure this device is really a DWC_otg Controller.
33000 + * Read and verify the SNPSID register contents. The value should be
33001 + * 0x45F42XXX or 0x45F42XXX, which corresponds to either "OT2" or "OTG3",
33002 + * as in "OTG version 2.XX" or "OTG version 3.XX".
33005 + if (((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F542000) &&
33006 + ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F543000)) {
33007 + dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n",
33008 + dwc_otg_get_gsnpsid(dwc_otg_device->core_if));
33009 + retval = -EINVAL;
33014 + * Validate parameter values.
33016 + dev_dbg(&_dev->dev, "Calling set_parameters\n");
33017 + if (set_parameters(dwc_otg_device->core_if)) {
33018 + retval = -EINVAL;
33023 + * Create Device Attributes in sysfs
33025 + dev_dbg(&_dev->dev, "Calling attr_create\n");
33026 + dwc_otg_attr_create(_dev);
33029 + * Disable the global interrupt until all the interrupt
33030 + * handlers are installed.
33032 + dev_dbg(&_dev->dev, "Calling disable_global_interrupts\n");
33033 + dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
33036 + * Install the interrupt handler for the common interrupts before
33037 + * enabling common interrupts in core_init below.
33040 +#if defined(PLATFORM_INTERFACE)
33041 + devirq = platform_get_irq(_dev, 0);
33043 + devirq = _dev->irq;
33045 + DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n",
33047 + dev_dbg(&_dev->dev, "Calling request_irq(%d)\n", devirq);
33048 + retval = request_irq(devirq, dwc_otg_common_irq,
33050 + "dwc_otg", dwc_otg_device);
33052 + DWC_ERROR("request of irq%d failed\n", devirq);
33056 + dwc_otg_device->common_irq_installed = 1;
33059 +#ifndef IRQF_TRIGGER_LOW
33060 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
33061 + dev_dbg(&_dev->dev, "Calling set_irq_type\n");
33062 + set_irq_type(devirq,
33063 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
33066 + IRQ_TYPE_LEVEL_LOW
33070 +#endif /*IRQF_TRIGGER_LOW*/
33073 + * Initialize the DWC_otg core.
33075 + dev_dbg(&_dev->dev, "Calling dwc_otg_core_init\n");
33076 + dwc_otg_core_init(dwc_otg_device->core_if);
33078 +#ifndef DWC_HOST_ONLY
33080 + * Initialize the PCD
33082 + dev_dbg(&_dev->dev, "Calling pcd_init\n");
33083 + retval = pcd_init(_dev);
33084 + if (retval != 0) {
33085 + DWC_ERROR("pcd_init failed\n");
33086 + dwc_otg_device->pcd = NULL;
33090 +#ifndef DWC_DEVICE_ONLY
33092 + * Initialize the HCD
33094 + dev_dbg(&_dev->dev, "Calling hcd_init\n");
33095 + retval = hcd_init(_dev);
33096 + if (retval != 0) {
33097 + DWC_ERROR("hcd_init failed\n");
33098 + dwc_otg_device->hcd = NULL;
33102 + /* Recover from drvdata having been overwritten by hcd_init() */
33103 +#ifdef LM_INTERFACE
33104 + lm_set_drvdata(_dev, dwc_otg_device);
33105 +#elif defined(PLATFORM_INTERFACE)
33106 + platform_set_drvdata(_dev, dwc_otg_device);
33107 +#elif defined(PCI_INTERFACE)
33108 + pci_set_drvdata(_dev, dwc_otg_device);
33109 + dwc_otg_device->os_dep.pcidev = _dev;
33113 + * Enable the global interrupt after all the interrupt
33114 + * handlers are installed if there is no ADP support else
33115 + * perform initial actions required for Internal ADP logic.
33117 + if (!dwc_otg_get_param_adp_enable(dwc_otg_device->core_if)) {
33118 + dev_dbg(&_dev->dev, "Calling enable_global_interrupts\n");
33119 + dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);
33120 + dev_dbg(&_dev->dev, "Done\n");
33122 + dwc_otg_adp_start(dwc_otg_device->core_if,
33123 + dwc_otg_is_host_mode(dwc_otg_device->core_if));
33128 + dwc_otg_driver_remove(_dev);
33133 + * This structure defines the methods to be called by a bus driver
33134 + * during the lifecycle of a device on that bus. Both drivers and
33135 + * devices are registered with a bus driver. The bus driver matches
33136 + * devices to drivers based on information in the device and driver
33139 + * The probe function is called when the bus driver matches a device
33140 + * to this driver. The remove function is called when a device is
33141 + * unregistered with the bus driver.
33143 +#ifdef LM_INTERFACE
33144 +static struct lm_driver dwc_otg_driver = {
33145 + .drv = {.name = (char *)dwc_driver_name,},
33146 + .probe = dwc_otg_driver_probe,
33147 + .remove = dwc_otg_driver_remove,
33148 + // 'suspend' and 'resume' absent
33150 +#elif defined(PCI_INTERFACE)
33151 +static const struct pci_device_id pci_ids[] = { {
33152 + PCI_DEVICE(0x16c3, 0xabcd),
33154 + (unsigned long)0xdeadbeef,
33155 + }, { /* end: all zeroes */ }
33158 +MODULE_DEVICE_TABLE(pci, pci_ids);
33160 +/* pci driver glue; this is a "new style" PCI driver module */
33161 +static struct pci_driver dwc_otg_driver = {
33162 + .name = "dwc_otg",
33163 + .id_table = pci_ids,
33165 + .probe = dwc_otg_driver_probe,
33166 + .remove = dwc_otg_driver_remove,
33169 + .name = (char *)dwc_driver_name,
33172 +#elif defined(PLATFORM_INTERFACE)
33173 +static struct platform_device_id platform_ids[] = {
33175 + .name = "bcm2708_usb",
33176 + .driver_data = (kernel_ulong_t) 0xdeadbeef,
33178 + { /* end: all zeroes */ }
33180 +MODULE_DEVICE_TABLE(platform, platform_ids);
33182 +static struct platform_driver dwc_otg_driver = {
33184 + .name = (char *)dwc_driver_name,
33186 + .id_table = platform_ids,
33188 + .probe = dwc_otg_driver_probe,
33189 + .remove = dwc_otg_driver_remove,
33190 + // no 'shutdown', 'suspend', 'resume', 'suspend_late' or 'resume_early'
33195 + * This function is called when the dwc_otg_driver is installed with the
33196 + * insmod command. It registers the dwc_otg_driver structure with the
33197 + * appropriate bus driver. This will cause the dwc_otg_driver_probe function
33198 + * to be called. In addition, the bus driver will automatically expose
33199 + * attributes defined for the device and driver in the special sysfs file
33204 +static int __init dwc_otg_driver_init(void)
33208 + struct device_driver *drv;
33209 + printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name,
33210 + DWC_DRIVER_VERSION,
33211 +#ifdef LM_INTERFACE
33213 + retval = lm_driver_register(&dwc_otg_driver);
33214 + drv = &dwc_otg_driver.drv;
33215 +#elif defined(PCI_INTERFACE)
33217 + retval = pci_register_driver(&dwc_otg_driver);
33218 + drv = &dwc_otg_driver.driver;
33219 +#elif defined(PLATFORM_INTERFACE)
33221 + retval = platform_driver_register(&dwc_otg_driver);
33222 + drv = &dwc_otg_driver.driver;
33224 + if (retval < 0) {
33225 + printk(KERN_ERR "%s retval=%d\n", __func__, retval);
33229 + error = driver_create_file(drv, &driver_attr_version);
33231 + error = driver_create_file(drv, &driver_attr_debuglevel);
33236 +module_init(dwc_otg_driver_init);
33239 + * This function is called when the driver is removed from the kernel
33240 + * with the rmmod command. The driver unregisters itself with its bus
33244 +static void __exit dwc_otg_driver_cleanup(void)
33246 + printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n");
33248 +#ifdef LM_INTERFACE
33249 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
33250 + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_version);
33251 + lm_driver_unregister(&dwc_otg_driver);
33252 +#elif defined(PCI_INTERFACE)
33253 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
33254 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
33255 + pci_unregister_driver(&dwc_otg_driver);
33256 +#elif defined(PLATFORM_INTERFACE)
33257 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
33258 + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
33259 + platform_driver_unregister(&dwc_otg_driver);
33262 + printk(KERN_INFO "%s module removed\n", dwc_driver_name);
33265 +module_exit(dwc_otg_driver_cleanup);
33267 +MODULE_DESCRIPTION(DWC_DRIVER_DESC);
33268 +MODULE_AUTHOR("Synopsys Inc.");
33269 +MODULE_LICENSE("GPL");
33271 +module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444);
33272 +MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None");
33273 +module_param_named(opt, dwc_otg_module_params.opt, int, 0444);
33274 +MODULE_PARM_DESC(opt, "OPT Mode");
33275 +module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444);
33276 +MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled");
33278 +module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int,
33280 +MODULE_PARM_DESC(dma_desc_enable,
33281 + "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled");
33283 +module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int,
33285 +MODULE_PARM_DESC(dma_burst_size,
33286 + "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256");
33287 +module_param_named(speed, dwc_otg_module_params.speed, int, 0444);
33288 +MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed");
33289 +module_param_named(host_support_fs_ls_low_power,
33290 + dwc_otg_module_params.host_support_fs_ls_low_power, int,
33292 +MODULE_PARM_DESC(host_support_fs_ls_low_power,
33293 + "Support Low Power w/FS or LS 0=Support 1=Don't Support");
33294 +module_param_named(host_ls_low_power_phy_clk,
33295 + dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444);
33296 +MODULE_PARM_DESC(host_ls_low_power_phy_clk,
33297 + "Low Speed Low Power Clock 0=48Mhz 1=6Mhz");
33298 +module_param_named(enable_dynamic_fifo,
33299 + dwc_otg_module_params.enable_dynamic_fifo, int, 0444);
33300 +MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing");
33301 +module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int,
33303 +MODULE_PARM_DESC(data_fifo_size,
33304 + "Total number of words in the data FIFO memory 32-32768");
33305 +module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size,
33307 +MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
33308 +module_param_named(dev_nperio_tx_fifo_size,
33309 + dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444);
33310 +MODULE_PARM_DESC(dev_nperio_tx_fifo_size,
33311 + "Number of words in the non-periodic Tx FIFO 16-32768");
33312 +module_param_named(dev_perio_tx_fifo_size_1,
33313 + dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444);
33314 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_1,
33315 + "Number of words in the periodic Tx FIFO 4-768");
33316 +module_param_named(dev_perio_tx_fifo_size_2,
33317 + dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444);
33318 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_2,
33319 + "Number of words in the periodic Tx FIFO 4-768");
33320 +module_param_named(dev_perio_tx_fifo_size_3,
33321 + dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444);
33322 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_3,
33323 + "Number of words in the periodic Tx FIFO 4-768");
33324 +module_param_named(dev_perio_tx_fifo_size_4,
33325 + dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444);
33326 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_4,
33327 + "Number of words in the periodic Tx FIFO 4-768");
33328 +module_param_named(dev_perio_tx_fifo_size_5,
33329 + dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444);
33330 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_5,
33331 + "Number of words in the periodic Tx FIFO 4-768");
33332 +module_param_named(dev_perio_tx_fifo_size_6,
33333 + dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444);
33334 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_6,
33335 + "Number of words in the periodic Tx FIFO 4-768");
33336 +module_param_named(dev_perio_tx_fifo_size_7,
33337 + dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444);
33338 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_7,
33339 + "Number of words in the periodic Tx FIFO 4-768");
33340 +module_param_named(dev_perio_tx_fifo_size_8,
33341 + dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444);
33342 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_8,
33343 + "Number of words in the periodic Tx FIFO 4-768");
33344 +module_param_named(dev_perio_tx_fifo_size_9,
33345 + dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444);
33346 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_9,
33347 + "Number of words in the periodic Tx FIFO 4-768");
33348 +module_param_named(dev_perio_tx_fifo_size_10,
33349 + dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444);
33350 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_10,
33351 + "Number of words in the periodic Tx FIFO 4-768");
33352 +module_param_named(dev_perio_tx_fifo_size_11,
33353 + dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444);
33354 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_11,
33355 + "Number of words in the periodic Tx FIFO 4-768");
33356 +module_param_named(dev_perio_tx_fifo_size_12,
33357 + dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444);
33358 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_12,
33359 + "Number of words in the periodic Tx FIFO 4-768");
33360 +module_param_named(dev_perio_tx_fifo_size_13,
33361 + dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444);
33362 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_13,
33363 + "Number of words in the periodic Tx FIFO 4-768");
33364 +module_param_named(dev_perio_tx_fifo_size_14,
33365 + dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444);
33366 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_14,
33367 + "Number of words in the periodic Tx FIFO 4-768");
33368 +module_param_named(dev_perio_tx_fifo_size_15,
33369 + dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444);
33370 +MODULE_PARM_DESC(dev_perio_tx_fifo_size_15,
33371 + "Number of words in the periodic Tx FIFO 4-768");
33372 +module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size,
33374 +MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
33375 +module_param_named(host_nperio_tx_fifo_size,
33376 + dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444);
33377 +MODULE_PARM_DESC(host_nperio_tx_fifo_size,
33378 + "Number of words in the non-periodic Tx FIFO 16-32768");
33379 +module_param_named(host_perio_tx_fifo_size,
33380 + dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444);
33381 +MODULE_PARM_DESC(host_perio_tx_fifo_size,
33382 + "Number of words in the host periodic Tx FIFO 16-32768");
33383 +module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size,
33385 +/** @todo Set the max to 512K, modify checks */
33386 +MODULE_PARM_DESC(max_transfer_size,
33387 + "The maximum transfer size supported in bytes 2047-65535");
33388 +module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count,
33390 +MODULE_PARM_DESC(max_packet_count,
33391 + "The maximum number of packets in a transfer 15-511");
33392 +module_param_named(host_channels, dwc_otg_module_params.host_channels, int,
33394 +MODULE_PARM_DESC(host_channels,
33395 + "The number of host channel registers to use 1-16");
33396 +module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int,
33398 +MODULE_PARM_DESC(dev_endpoints,
33399 + "The number of endpoints in addition to EP0 available for device mode 1-15");
33400 +module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444);
33401 +MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI");
33402 +module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int,
33404 +MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits");
33405 +module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444);
33406 +MODULE_PARM_DESC(phy_ulpi_ddr,
33407 + "ULPI at double or single data rate 0=Single 1=Double");
33408 +module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus,
33410 +MODULE_PARM_DESC(phy_ulpi_ext_vbus,
33411 + "ULPI PHY using internal or external vbus 0=Internal");
33412 +module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444);
33413 +MODULE_PARM_DESC(i2c_enable, "FS PHY Interface");
33414 +module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444);
33415 +MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only");
33416 +module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444);
33417 +MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs");
33418 +module_param_named(debug, g_dbg_lvl, int, 0444);
33419 +MODULE_PARM_DESC(debug, "");
33421 +module_param_named(en_multiple_tx_fifo,
33422 + dwc_otg_module_params.en_multiple_tx_fifo, int, 0444);
33423 +MODULE_PARM_DESC(en_multiple_tx_fifo,
33424 + "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled");
33425 +module_param_named(dev_tx_fifo_size_1,
33426 + dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444);
33427 +MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768");
33428 +module_param_named(dev_tx_fifo_size_2,
33429 + dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444);
33430 +MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768");
33431 +module_param_named(dev_tx_fifo_size_3,
33432 + dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444);
33433 +MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768");
33434 +module_param_named(dev_tx_fifo_size_4,
33435 + dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444);
33436 +MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768");
33437 +module_param_named(dev_tx_fifo_size_5,
33438 + dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444);
33439 +MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768");
33440 +module_param_named(dev_tx_fifo_size_6,
33441 + dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444);
33442 +MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768");
33443 +module_param_named(dev_tx_fifo_size_7,
33444 + dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444);
33445 +MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768");
33446 +module_param_named(dev_tx_fifo_size_8,
33447 + dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444);
33448 +MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768");
33449 +module_param_named(dev_tx_fifo_size_9,
33450 + dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444);
33451 +MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768");
33452 +module_param_named(dev_tx_fifo_size_10,
33453 + dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444);
33454 +MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768");
33455 +module_param_named(dev_tx_fifo_size_11,
33456 + dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444);
33457 +MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768");
33458 +module_param_named(dev_tx_fifo_size_12,
33459 + dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444);
33460 +MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768");
33461 +module_param_named(dev_tx_fifo_size_13,
33462 + dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444);
33463 +MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768");
33464 +module_param_named(dev_tx_fifo_size_14,
33465 + dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444);
33466 +MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768");
33467 +module_param_named(dev_tx_fifo_size_15,
33468 + dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444);
33469 +MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768");
33471 +module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444);
33472 +MODULE_PARM_DESC(thr_ctl,
33473 + "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled");
33474 +module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int,
33476 +MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs");
33477 +module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int,
33479 +MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs");
33481 +module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444);
33482 +module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444);
33483 +module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444);
33484 +MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled");
33485 +module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444);
33486 +MODULE_PARM_DESC(ic_usb_cap,
33487 + "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled");
33488 +module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int,
33490 +MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio");
33491 +module_param_named(power_down, dwc_otg_module_params.power_down, int, 0444);
33492 +MODULE_PARM_DESC(power_down, "Power Down Mode");
33493 +module_param_named(reload_ctl, dwc_otg_module_params.reload_ctl, int, 0444);
33494 +MODULE_PARM_DESC(reload_ctl, "HFIR Reload Control");
33495 +module_param_named(dev_out_nak, dwc_otg_module_params.dev_out_nak, int, 0444);
33496 +MODULE_PARM_DESC(dev_out_nak, "Enable Device OUT NAK");
33497 +module_param_named(cont_on_bna, dwc_otg_module_params.cont_on_bna, int, 0444);
33498 +MODULE_PARM_DESC(cont_on_bna, "Enable Enable Continue on BNA");
33499 +module_param_named(ahb_single, dwc_otg_module_params.ahb_single, int, 0444);
33500 +MODULE_PARM_DESC(ahb_single, "Enable AHB Single Support");
33501 +module_param_named(adp_enable, dwc_otg_module_params.adp_enable, int, 0444);
33502 +MODULE_PARM_DESC(adp_enable, "ADP Enable 0=ADP Disabled 1=ADP Enabled");
33503 +module_param_named(otg_ver, dwc_otg_module_params.otg_ver, int, 0444);
33504 +MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0");
33505 +module_param(microframe_schedule, bool, 0444);
33506 +MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");
33508 +/** @page "Module Parameters"
33510 + * The following parameters may be specified when starting the module.
33511 + * These parameters define how the DWC_otg controller should be
33512 + * configured. Parameter values are passed to the CIL initialization
33513 + * function dwc_otg_cil_init
33515 + * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code>
33519 + <tr><td>Parameter Name</td><td>Meaning</td></tr>
33523 + <td>Specifies the OTG capabilities. The driver will automatically detect the
33524 + value for this parameter if none is specified.
33525 + - 0: HNP and SRP capable (default, if available)
33526 + - 1: SRP Only capable
33527 + - 2: No HNP/SRP capable
33531 + <td>dma_enable</td>
33532 + <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs.
33533 + The driver will automatically detect the value for this parameter if none is
33536 + - 1: DMA (default, if available)
33540 + <td>dma_burst_size</td>
33541 + <td>The DMA Burst size (applicable only for External DMA Mode).
33542 + - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32)
33547 + <td>Specifies the maximum speed of operation in host and device mode. The
33548 + actual speed depends on the speed of the attached device and the value of
33550 + - 0: High Speed (default)
33555 + <td>host_support_fs_ls_low_power</td>
33556 + <td>Specifies whether low power mode is supported when attached to a Full
33557 + Speed or Low Speed device in host mode.
33558 + - 0: Don't support low power mode (default)
33559 + - 1: Support low power mode
33563 + <td>host_ls_low_power_phy_clk</td>
33564 + <td>Specifies the PHY clock rate in low power mode when connected to a Low
33565 + Speed device in host mode. This parameter is applicable only if
33566 + HOST_SUPPORT_FS_LS_LOW_POWER is enabled.
33567 + - 0: 48 MHz (default)
33572 + <td>enable_dynamic_fifo</td>
33573 + <td> Specifies whether FIFOs may be resized by the driver software.
33574 + - 0: Use cC FIFO size parameters
33575 + - 1: Allow dynamic FIFO sizing (default)
33579 + <td>data_fifo_size</td>
33580 + <td>Total number of 4-byte words in the data FIFO memory. This memory
33581 + includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs.
33582 + - Values: 32 to 32768 (default 8192)
33584 + Note: The total FIFO memory depth in the FPGA configuration is 8192.
33588 + <td>dev_rx_fifo_size</td>
33589 + <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic
33590 + FIFO sizing is enabled.
33591 + - Values: 16 to 32768 (default 1064)
33595 + <td>dev_nperio_tx_fifo_size</td>
33596 + <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when
33597 + dynamic FIFO sizing is enabled.
33598 + - Values: 16 to 32768 (default 1024)
33602 + <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td>
33603 + <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode
33604 + when dynamic FIFO sizing is enabled.
33605 + - Values: 4 to 768 (default 256)
33609 + <td>host_rx_fifo_size</td>
33610 + <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO
33611 + sizing is enabled.
33612 + - Values: 16 to 32768 (default 1024)
33616 + <td>host_nperio_tx_fifo_size</td>
33617 + <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when
33618 + dynamic FIFO sizing is enabled in the core.
33619 + - Values: 16 to 32768 (default 1024)
33623 + <td>host_perio_tx_fifo_size</td>
33624 + <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO
33625 + sizing is enabled.
33626 + - Values: 16 to 32768 (default 1024)
33630 + <td>max_transfer_size</td>
33631 + <td>The maximum transfer size supported in bytes.
33632 + - Values: 2047 to 65,535 (default 65,535)
33636 + <td>max_packet_count</td>
33637 + <td>The maximum number of packets in a transfer.
33638 + - Values: 15 to 511 (default 511)
33642 + <td>host_channels</td>
33643 + <td>The number of host channel registers to use.
33644 + - Values: 1 to 16 (default 12)
33646 + Note: The FPGA configuration supports a maximum of 12 host channels.
33650 + <td>dev_endpoints</td>
33651 + <td>The number of endpoints in addition to EP0 available for device mode
33653 + - Values: 1 to 15 (default 6 IN and OUT)
33655 + Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in
33660 + <td>phy_type</td>
33661 + <td>Specifies the type of PHY interface to use. By default, the driver will
33662 + automatically detect the phy_type.
33664 + - 1: UTMI+ (default, if available)
33669 + <td>phy_utmi_width</td>
33670 + <td>Specifies the UTMI+ Data Width. This parameter is applicable for a
33671 + phy_type of UTMI+. Also, this parameter is applicable only if the
33672 + OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the
33673 + core has been configured to work at either data path width.
33674 + - Values: 8 or 16 bits (default 16)
33678 + <td>phy_ulpi_ddr</td>
33679 + <td>Specifies whether the ULPI operates at double or single data rate. This
33680 + parameter is only applicable if phy_type is ULPI.
33681 + - 0: single data rate ULPI interface with 8 bit wide data bus (default)
33682 + - 1: double data rate ULPI interface with 4 bit wide data bus
33686 + <td>i2c_enable</td>
33687 + <td>Specifies whether to use the I2C interface for full speed PHY. This
33688 + parameter is only applicable if PHY_TYPE is FS.
33689 + - 0: Disabled (default)
33694 + <td>ulpi_fs_ls</td>
33695 + <td>Specifies whether to use ULPI FS/LS mode only.
33696 + - 0: Disabled (default)
33701 + <td>ts_dline</td>
33702 + <td>Specifies whether term select D-Line pulsing for all PHYs is enabled.
33703 + - 0: Disabled (default)
33708 + <td>en_multiple_tx_fifo</td>
33709 + <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs.
33710 + The driver will automatically detect the value for this parameter if none is
33713 + - 1: Enabled (default, if available)
33717 + <td>dev_tx_fifo_size_n (n = 1 to 15)</td>
33718 + <td>Number of 4-byte words in each of the Tx FIFOs in device mode
33719 + when dynamic FIFO sizing is enabled.
33720 + - Values: 4 to 768 (default 256)
33724 + <td>tx_thr_length</td>
33725 + <td>Transmit Threshold length in 32 bit double words
33726 + - Values: 8 to 128 (default 64)
33730 + <td>rx_thr_length</td>
33731 + <td>Receive Threshold length in 32 bit double words
33732 + - Values: 8 to 128 (default 64)
33737 + <td>Specifies whether to enable Thresholding for Device mode. Bits 0, 1, 2 of
33738 + this parmater specifies if thresholding is enabled for non-Iso Tx, Iso Tx and
33739 + Rx transfers accordingly.
33740 + The driver will automatically detect the value for this parameter if none is
33742 + - Values: 0 to 7 (default 0)
33743 + Bit values indicate:
33744 + - 0: Thresholding disabled
33745 + - 1: Thresholding enabled
33749 + <td>dma_desc_enable</td>
33750 + <td>Specifies whether to enable Descriptor DMA mode.
33751 + The driver will automatically detect the value for this parameter if none is
33753 + - 0: Descriptor DMA disabled
33754 + - 1: Descriptor DMA (default, if available)
33758 + <td>mpi_enable</td>
33759 + <td>Specifies whether to enable MPI enhancement mode.
33760 + The driver will automatically detect the value for this parameter if none is
33762 + - 0: MPI disabled (default)
33767 + <td>pti_enable</td>
33768 + <td>Specifies whether to enable PTI enhancement support.
33769 + The driver will automatically detect the value for this parameter if none is
33771 + - 0: PTI disabled (default)
33776 + <td>lpm_enable</td>
33777 + <td>Specifies whether to enable LPM support.
33778 + The driver will automatically detect the value for this parameter if none is
33780 + - 0: LPM disabled
33781 + - 1: LPM enable (default, if available)
33785 + <td>ic_usb_cap</td>
33786 + <td>Specifies whether to enable IC_USB capability.
33787 + The driver will automatically detect the value for this parameter if none is
33789 + - 0: IC_USB disabled (default, if available)
33790 + - 1: IC_USB enable
33794 + <td>ahb_thr_ratio</td>
33795 + <td>Specifies AHB Threshold ratio.
33796 + - Values: 0 to 3 (default 0)
33800 + <td>power_down</td>
33801 + <td>Specifies Power Down(Hibernation) Mode.
33802 + The driver will automatically detect the value for this parameter if none is
33804 + - 0: Power Down disabled (default)
33805 + - 2: Power Down enabled
33809 + <td>reload_ctl</td>
33810 + <td>Specifies whether dynamic reloading of the HFIR register is allowed during
33811 + run time. The driver will automatically detect the value for this parameter if
33812 + none is specified. In case the HFIR value is reloaded when HFIR.RldCtrl == 1'b0
33813 + the core might misbehave.
33814 + - 0: Reload Control disabled (default)
33815 + - 1: Reload Control enabled
33819 + <td>dev_out_nak</td>
33820 + <td>Specifies whether Device OUT NAK enhancement enabled or no.
33821 + The driver will automatically detect the value for this parameter if
33822 + none is specified. This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
33823 + - 0: The core does not set NAK after Bulk OUT transfer complete (default)
33824 + - 1: The core sets NAK after Bulk OUT transfer complete
33828 + <td>cont_on_bna</td>
33829 + <td>Specifies whether Enable Continue on BNA enabled or no.
33830 + After receiving BNA interrupt the core disables the endpoint,when the
33831 + endpoint is re-enabled by the application the
33832 + - 0: Core starts processing from the DOEPDMA descriptor (default)
33833 + - 1: Core starts processing from the descriptor which received the BNA.
33834 + This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
33838 + <td>ahb_single</td>
33839 + <td>This bit when programmed supports SINGLE transfers for remainder data
33840 + in a transfer for DMA mode of operation.
33841 + - 0: The remainder data will be sent using INCR burst size (default)
33842 + - 1: The remainder data will be sent using SINGLE burst size.
33846 + <td>adp_enable</td>
33847 + <td>Specifies whether ADP feature is enabled.
33848 + The driver will automatically detect the value for this parameter if none is
33850 + - 0: ADP feature disabled (default)
33851 + - 1: ADP feature enabled
33856 + <td>Specifies whether OTG is performing as USB OTG Revision 2.0 or Revision 1.3
33858 + - 0: OTG 2.0 support disabled (default)
33859 + - 1: OTG 2.0 support enabled
33863 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.h b/drivers/usb/host/dwc_otg/dwc_otg_driver.h
33864 new file mode 100644
33865 index 0000000..8a0e41b
33867 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.h
33869 +/* ==========================================================================
33870 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $
33871 + * $Revision: #19 $
33872 + * $Date: 2010/11/15 $
33873 + * $Change: 1627671 $
33875 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
33876 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
33877 + * otherwise expressly agreed to in writing between Synopsys and you.
33879 + * The Software IS NOT an item of Licensed Software or Licensed Product under
33880 + * any End User Software License Agreement or Agreement for Licensed Product
33881 + * with Synopsys or any supplement thereto. You are permitted to use and
33882 + * redistribute this Software in source and binary forms, with or without
33883 + * modification, provided that redistributions of source code must retain this
33884 + * notice. You may not view, use, disclose, copy or distribute this file or
33885 + * any information contained herein except pursuant to this license grant from
33886 + * Synopsys. If you do not agree with this notice, including the disclaimer
33887 + * below, then you are not authorized to use the Software.
33889 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
33890 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33891 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33892 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
33893 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33894 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33895 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33896 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33897 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33898 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33900 + * ========================================================================== */
33902 +#ifndef __DWC_OTG_DRIVER_H__
33903 +#define __DWC_OTG_DRIVER_H__
33906 + * This file contains the interface to the Linux driver.
33908 +#include "dwc_otg_os_dep.h"
33909 +#include "dwc_otg_core_if.h"
33911 +/* Type declarations */
33912 +struct dwc_otg_pcd;
33913 +struct dwc_otg_hcd;
33916 + * This structure is a wrapper that encapsulates the driver components used to
33917 + * manage a single DWC_otg controller.
33919 +typedef struct dwc_otg_device {
33920 + /** Structure containing OS-dependent stuff. KEEP THIS STRUCT AT THE
33921 + * VERY BEGINNING OF THE DEVICE STRUCT. OSes such as FreeBSD and NetBSD
33922 + * require this. */
33923 + struct os_dependent os_dep;
33925 + /** Pointer to the core interface structure. */
33926 + dwc_otg_core_if_t *core_if;
33928 + /** Pointer to the PCD structure. */
33929 + struct dwc_otg_pcd *pcd;
33931 + /** Pointer to the HCD structure. */
33932 + struct dwc_otg_hcd *hcd;
33934 + /** Flag to indicate whether the common IRQ handler is installed. */
33935 + uint8_t common_irq_installed;
33937 +} dwc_otg_device_t;
33939 +/*We must clear S3C24XX_EINTPEND external interrupt register
33940 + * because after clearing in this register trigerred IRQ from
33941 + * H/W core in kernel interrupt can be occured again before OTG
33942 + * handlers clear all IRQ sources of Core registers because of
33943 + * timing latencies and Low Level IRQ Type.
33945 +#ifdef CONFIG_MACH_IPMATE
33946 +#define S3C2410X_CLEAR_EINTPEND() \
33948 + __raw_writel(1UL << 11,S3C24XX_EINTPEND); \
33951 +#define S3C2410X_CLEAR_EINTPEND() do { } while (0)
33955 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
33956 new file mode 100644
33957 index 0000000..434d0c4
33959 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
33962 +/* ==========================================================================
33963 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
33964 + * $Revision: #104 $
33965 + * $Date: 2011/10/24 $
33966 + * $Change: 1871159 $
33968 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
33969 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
33970 + * otherwise expressly agreed to in writing between Synopsys and you.
33972 + * The Software IS NOT an item of Licensed Software or Licensed Product under
33973 + * any End User Software License Agreement or Agreement for Licensed Product
33974 + * with Synopsys or any supplement thereto. You are permitted to use and
33975 + * redistribute this Software in source and binary forms, with or without
33976 + * modification, provided that redistributions of source code must retain this
33977 + * notice. You may not view, use, disclose, copy or distribute this file or
33978 + * any information contained herein except pursuant to this license grant from
33979 + * Synopsys. If you do not agree with this notice, including the disclaimer
33980 + * below, then you are not authorized to use the Software.
33982 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
33983 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33984 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33985 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
33986 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33987 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33988 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33989 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33990 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33991 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33993 + * ========================================================================== */
33994 +#ifndef DWC_DEVICE_ONLY
33997 + * This file implements HCD Core. All code in this file is portable and doesn't
33998 + * use any OS specific functions.
33999 + * Interface provided by HCD Core is defined in <code><hcd_if.h></code>
34003 +#include "dwc_otg_hcd.h"
34004 +#include "dwc_otg_regs.h"
34006 +extern bool microframe_schedule;
34008 +//#define DEBUG_HOST_CHANNELS
34009 +#ifdef DEBUG_HOST_CHANNELS
34010 +static int last_sel_trans_num_per_scheduled = 0;
34011 +static int last_sel_trans_num_nonper_scheduled = 0;
34012 +static int last_sel_trans_num_avail_hc_at_start = 0;
34013 +static int last_sel_trans_num_avail_hc_at_end = 0;
34014 +#endif /* DEBUG_HOST_CHANNELS */
34016 +dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
34018 + return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
34022 + * Connection timeout function. An OTG host is required to display a
34023 + * message if the device does not connect within 10 seconds.
34025 +void dwc_otg_hcd_connect_timeout(void *ptr)
34027 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
34028 + DWC_PRINTF("Connect Timeout\n");
34029 + __DWC_ERROR("Device Not Connected/Responding\n");
34032 +#if defined(DEBUG)
34033 +static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
34035 + if (qh->channel != NULL) {
34036 + dwc_hc_t *hc = qh->channel;
34037 + dwc_list_link_t *item;
34038 + dwc_otg_qh_t *qh_item;
34039 + int num_channels = hcd->core_if->core_params->host_channels;
34042 + dwc_otg_hc_regs_t *hc_regs;
34043 + hcchar_data_t hcchar;
34044 + hcsplt_data_t hcsplt;
34045 + hctsiz_data_t hctsiz;
34048 + hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
34049 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
34050 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
34051 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
34052 + hcdma = DWC_READ_REG32(&hc_regs->hcdma);
34054 + DWC_PRINTF(" Assigned to channel %p:\n", hc);
34055 + DWC_PRINTF(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
34057 + DWC_PRINTF(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
34059 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
34060 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
34061 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
34062 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
34063 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
34064 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
34065 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
34066 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
34067 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
34068 + DWC_PRINTF(" qh: %p\n", hc->qh);
34069 + DWC_PRINTF(" NP inactive sched:\n");
34070 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
34072 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
34073 + DWC_PRINTF(" %p\n", qh_item);
34075 + DWC_PRINTF(" NP active sched:\n");
34076 + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
34078 + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
34079 + DWC_PRINTF(" %p\n", qh_item);
34081 + DWC_PRINTF(" Channels: \n");
34082 + for (i = 0; i < num_channels; i++) {
34083 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
34084 + DWC_PRINTF(" %2d: %p\n", i, hc);
34089 +#define dump_channel_info(hcd, qh)
34090 +#endif /* DEBUG */
34093 + * Work queue function for starting the HCD when A-Cable is connected.
34094 + * The hcd_start() must be called in a process context.
34096 +static void hcd_start_func(void *_vp)
34098 + dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
34100 + DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
34102 + hcd->fops->start(hcd);
34106 +static void del_xfer_timers(dwc_otg_hcd_t * hcd)
34110 + int num_channels = hcd->core_if->core_params->host_channels;
34111 + for (i = 0; i < num_channels; i++) {
34112 + DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
34117 +static void del_timers(dwc_otg_hcd_t * hcd)
34119 + del_xfer_timers(hcd);
34120 + DWC_TIMER_CANCEL(hcd->conn_timer);
34124 + * Processes all the URBs in a single list of QHs. Completes them with
34125 + * -ETIMEDOUT and frees the QTD.
34127 +static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
34129 + dwc_list_link_t *qh_item;
34130 + dwc_otg_qh_t *qh;
34131 + dwc_otg_qtd_t *qtd, *qtd_tmp;
34133 + DWC_LIST_FOREACH(qh_item, qh_list) {
34134 + qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
34135 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
34136 + &qh->qtd_list, qtd_list_entry) {
34137 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
34138 + if (qtd->urb != NULL) {
34139 + hcd->fops->complete(hcd, qtd->urb->priv,
34140 + qtd->urb, -DWC_E_TIMEOUT);
34141 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
34149 + * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
34150 + * and periodic schedules. The QTD associated with each URB is removed from
34151 + * the schedule and freed. This function may be called when a disconnect is
34152 + * detected or when the HCD is being stopped.
34154 +static void kill_all_urbs(dwc_otg_hcd_t * hcd)
34156 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
34157 + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
34158 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
34159 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
34160 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
34161 + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
34165 + * Start the connection timer. An OTG host is required to display a
34166 + * message if the device does not connect within 10 seconds. The
34167 + * timer is deleted if a port connect interrupt occurs before the
34170 +static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
34172 + DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
34176 + * HCD Callback function for disconnect of the HCD.
34178 + * @param p void pointer to the <code>struct usb_hcd</code>
34180 +static int32_t dwc_otg_hcd_session_start_cb(void *p)
34182 + dwc_otg_hcd_t *dwc_otg_hcd;
34183 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
34185 + dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
34190 + * HCD Callback function for starting the HCD when A-Cable is
34193 + * @param p void pointer to the <code>struct usb_hcd</code>
34195 +static int32_t dwc_otg_hcd_start_cb(void *p)
34197 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34198 + dwc_otg_core_if_t *core_if;
34199 + hprt0_data_t hprt0;
34201 + core_if = dwc_otg_hcd->core_if;
34203 + if (core_if->op_state == B_HOST) {
34205 + * Reset the port. During a HNP mode switch the reset
34206 + * needs to occur within 1ms and have a duration of at
34209 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
34210 + hprt0.b.prtrst = 1;
34211 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34213 + DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
34214 + hcd_start_func, dwc_otg_hcd, 50,
34221 + * HCD Callback function for disconnect of the HCD.
34223 + * @param p void pointer to the <code>struct usb_hcd</code>
34225 +static int32_t dwc_otg_hcd_disconnect_cb(void *p)
34227 + gintsts_data_t intr;
34228 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34231 + * Set status flags for the hub driver.
34233 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
34234 + dwc_otg_hcd->flags.b.port_connect_status = 0;
34237 + * Shutdown any transfers in process by clearing the Tx FIFO Empty
34238 + * interrupt mask and status bits and disabling subsequent host
34239 + * channel interrupts.
34242 + intr.b.nptxfempty = 1;
34243 + intr.b.ptxfempty = 1;
34244 + intr.b.hcintr = 1;
34245 + DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
34247 + DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
34250 + del_timers(dwc_otg_hcd);
34253 + * Turn off the vbus power only if the core has transitioned to device
34254 + * mode. If still in host mode, need to keep power on to detect a
34257 + if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
34258 + if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
34259 + hprt0_data_t hprt0 = {.d32 = 0 };
34260 + DWC_PRINTF("Disconnect: PortPower off\n");
34261 + hprt0.b.prtpwr = 0;
34262 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0,
34266 + dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
34269 + /* Respond with an error status to all URBs in the schedule. */
34270 + kill_all_urbs(dwc_otg_hcd);
34272 + if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
34273 + /* Clean up any host channels that were in use. */
34274 + int num_channels;
34276 + dwc_hc_t *channel;
34277 + dwc_otg_hc_regs_t *hc_regs;
34278 + hcchar_data_t hcchar;
34280 + num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
34282 + if (!dwc_otg_hcd->core_if->dma_enable) {
34283 + /* Flush out any channel requests in slave mode. */
34284 + for (i = 0; i < num_channels; i++) {
34285 + channel = dwc_otg_hcd->hc_ptr_array[i];
34286 + if (DWC_CIRCLEQ_EMPTY_ENTRY
34287 + (channel, hc_list_entry)) {
34289 + dwc_otg_hcd->core_if->
34290 + host_if->hc_regs[i];
34292 + DWC_READ_REG32(&hc_regs->hcchar);
34293 + if (hcchar.b.chen) {
34294 + hcchar.b.chen = 0;
34295 + hcchar.b.chdis = 1;
34296 + hcchar.b.epdir = 0;
34298 + (&hc_regs->hcchar,
34305 + for (i = 0; i < num_channels; i++) {
34306 + channel = dwc_otg_hcd->hc_ptr_array[i];
34307 + if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
34309 + dwc_otg_hcd->core_if->host_if->hc_regs[i];
34310 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
34311 + if (hcchar.b.chen) {
34312 + /* Halt the channel. */
34313 + hcchar.b.chdis = 1;
34314 + DWC_WRITE_REG32(&hc_regs->hcchar,
34318 + dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
34320 + DWC_CIRCLEQ_INSERT_TAIL
34321 + (&dwc_otg_hcd->free_hc_list, channel,
34324 + * Added for Descriptor DMA to prevent channel double cleanup
34325 + * in release_channel_ddma(). Which called from ep_disable
34326 + * when device disconnect.
34328 + channel->qh = NULL;
34333 + if (dwc_otg_hcd->fops->disconnect) {
34334 + dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
34341 + * HCD Callback function for stopping the HCD.
34343 + * @param p void pointer to the <code>struct usb_hcd</code>
34345 +static int32_t dwc_otg_hcd_stop_cb(void *p)
34347 + dwc_otg_hcd_t *dwc_otg_hcd = p;
34349 + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
34350 + dwc_otg_hcd_stop(dwc_otg_hcd);
34354 +#ifdef CONFIG_USB_DWC_OTG_LPM
34356 + * HCD Callback function for sleep of HCD.
34358 + * @param p void pointer to the <code>struct usb_hcd</code>
34360 +static int dwc_otg_hcd_sleep_cb(void *p)
34362 + dwc_otg_hcd_t *hcd = p;
34364 + dwc_otg_hcd_free_hc_from_lpm(hcd);
34371 + * HCD Callback function for Remote Wakeup.
34373 + * @param p void pointer to the <code>struct usb_hcd</code>
34375 +static int dwc_otg_hcd_rem_wakeup_cb(void *p)
34377 + dwc_otg_hcd_t *hcd = p;
34379 + if (hcd->core_if->lx_state == DWC_OTG_L2) {
34380 + hcd->flags.b.port_suspend_change = 1;
34382 +#ifdef CONFIG_USB_DWC_OTG_LPM
34384 + hcd->flags.b.port_l1_change = 1;
34391 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
34394 +void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
34396 + hprt0_data_t hprt0 = {.d32 = 0 };
34398 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
34401 + * The root hub should be disconnected before this function is called.
34402 + * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
34403 + * and the QH lists (via ..._hcd_endpoint_disable).
34406 + /* Turn off all host-specific interrupts. */
34407 + dwc_otg_disable_host_interrupts(hcd->core_if);
34409 + /* Turn off the vbus power */
34410 + DWC_PRINTF("PortPower off\n");
34411 + hprt0.b.prtpwr = 0;
34412 + DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
34416 +int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
34417 + dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
34418 + int atomic_alloc)
34420 + dwc_irqflags_t flags;
34422 + dwc_otg_qtd_t *qtd;
34423 + gintmsk_data_t intr_mask = {.d32 = 0 };
34425 +#ifdef DEBUG /* integrity checks (Broadcom) */
34426 + if (NULL == hcd->core_if) {
34427 + DWC_ERROR("**** DWC OTG HCD URB Enqueue - HCD has NULL core_if\n");
34428 + /* No longer connected. */
34429 + return -DWC_E_INVALID;
34432 + if (!hcd->flags.b.port_connect_status) {
34433 + /* No longer connected. */
34434 + DWC_ERROR("Not connected\n");
34435 + return -DWC_E_NO_DEVICE;
34438 + qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
34439 + if (qtd == NULL) {
34440 + DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
34441 + return -DWC_E_NO_MEMORY;
34443 +#ifdef DEBUG /* integrity checks (Broadcom) */
34444 + if (qtd->urb == NULL) {
34445 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD with no URBs\n");
34446 + return -DWC_E_NO_MEMORY;
34448 + if (qtd->urb->priv == NULL) {
34449 + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD URB with no URB handle\n");
34450 + return -DWC_E_NO_MEMORY;
34454 + dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
34455 + // creates a new queue in ep_handle if it doesn't exist already
34456 + if (retval < 0) {
34457 + DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
34458 + "Error status %d\n", retval);
34459 + dwc_otg_hcd_qtd_free(qtd);
34461 + qtd->qh = *ep_handle;
34463 + intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
34464 + if (!intr_mask.b.sofintr && retval == 0) {
34465 + dwc_otg_transaction_type_e tr_type;
34466 + if ((qtd->qh->ep_type == UE_BULK)
34467 + && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
34468 + /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
34471 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34472 + tr_type = dwc_otg_hcd_select_transactions(hcd);
34473 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
34474 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
34476 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34482 +int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
34483 + dwc_otg_hcd_urb_t * dwc_otg_urb)
34485 + dwc_otg_qh_t *qh;
34486 + dwc_otg_qtd_t *urb_qtd;
34488 +#ifdef DEBUG /* integrity checks (Broadcom) */
34490 + if (hcd == NULL) {
34491 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL HCD\n");
34492 + return -DWC_E_INVALID;
34494 + if (dwc_otg_urb == NULL) {
34495 + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL URB\n");
34496 + return -DWC_E_INVALID;
34498 + if (dwc_otg_urb->qtd == NULL) {
34499 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with NULL QTD\n");
34500 + return -DWC_E_INVALID;
34502 + urb_qtd = dwc_otg_urb->qtd;
34503 + if (urb_qtd->qh == NULL) {
34504 + DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
34505 + return -DWC_E_INVALID;
34508 + urb_qtd = dwc_otg_urb->qtd;
34510 + qh = urb_qtd->qh;
34511 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
34512 + if (urb_qtd->in_process) {
34513 + dump_channel_info(hcd, qh);
34516 +#ifdef DEBUG /* integrity checks (Broadcom) */
34517 + if (hcd->core_if == NULL) {
34518 + DWC_ERROR("**** DWC OTG HCD URB Dequeue HCD has NULL core_if\n");
34519 + return -DWC_E_INVALID;
34522 + if (urb_qtd->in_process && qh->channel) {
34523 + /* The QTD is in process (it has been assigned to a channel). */
34524 + if (hcd->flags.b.port_connect_status) {
34526 + * If still connected (i.e. in host mode), halt the
34527 + * channel so it can be used for other transfers. If
34528 + * no longer connected, the host registers can't be
34529 + * written to halt the channel since the core is in
34532 + dwc_otg_hc_halt(hcd->core_if, qh->channel,
34533 + DWC_OTG_HC_XFER_URB_DEQUEUE);
34538 + * Free the QTD and clean up the associated QH. Leave the QH in the
34539 + * schedule if it has any remaining QTDs.
34542 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue - "
34543 + "delete %sQueue handler\n",
34544 + hcd->core_if->dma_desc_enable?"DMA ":"");
34545 + if (!hcd->core_if->dma_desc_enable) {
34546 + uint8_t b = urb_qtd->in_process;
34547 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
34549 + dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
34550 + qh->channel = NULL;
34551 + } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
34552 + dwc_otg_hcd_qh_remove(hcd, qh);
34555 + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
34560 +int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
34563 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
34565 + dwc_irqflags_t flags;
34568 + retval = -DWC_E_INVALID;
34573 + retval = -DWC_E_INVALID;
34577 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34579 + while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
34580 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34583 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34586 + dwc_otg_hcd_qh_remove(hcd, qh);
34588 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34590 + * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
34591 + * and qh_free to prevent stack dump on DWC_DMA_FREE() with
34592 + * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
34593 + * and dwc_otg_hcd_frame_list_alloc().
34595 + dwc_otg_hcd_qh_free(hcd, qh);
34601 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
34602 +int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle)
34605 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
34607 + return -DWC_E_INVALID;
34609 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
34615 + * HCD Callback structure for handling mode switching.
34617 +static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
34618 + .start = dwc_otg_hcd_start_cb,
34619 + .stop = dwc_otg_hcd_stop_cb,
34620 + .disconnect = dwc_otg_hcd_disconnect_cb,
34621 + .session_start = dwc_otg_hcd_session_start_cb,
34622 + .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
34623 +#ifdef CONFIG_USB_DWC_OTG_LPM
34624 + .sleep = dwc_otg_hcd_sleep_cb,
34630 + * Reset tasklet function
34632 +static void reset_tasklet_func(void *data)
34634 + dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
34635 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
34636 + hprt0_data_t hprt0;
34638 + DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
34640 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
34641 + hprt0.b.prtrst = 1;
34642 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34645 + hprt0.b.prtrst = 0;
34646 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
34647 + dwc_otg_hcd->flags.b.port_reset_change = 1;
34650 +static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
34652 + dwc_list_link_t *item;
34653 + dwc_otg_qh_t *qh;
34654 + dwc_irqflags_t flags;
34656 + if (!qh_list->next) {
34657 + /* The list hasn't been initialized yet. */
34661 + * Hold spinlock here. Not needed in that case if bellow
34662 + * function is being called from ISR
34664 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
34665 + /* Ensure there are no QTDs or URBs left. */
34666 + kill_urbs_in_qh_list(hcd, qh_list);
34667 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
34669 + DWC_LIST_FOREACH(item, qh_list) {
34670 + qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
34671 + dwc_otg_hcd_qh_remove_and_free(hcd, qh);
34676 + * Exit from Hibernation if Host did not detect SRP from connected SRP capable
34677 + * Device during SRP time by host power up.
34679 +void dwc_otg_hcd_power_up(void *ptr)
34681 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
34682 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
34684 + DWC_PRINTF("%s called\n", __FUNCTION__);
34686 + if (!core_if->hibernation_suspend) {
34687 + DWC_PRINTF("Already exited from Hibernation\n");
34691 + /* Switch on the voltage to the core */
34692 + gpwrdn.b.pwrdnswtch = 1;
34693 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34696 + /* Reset the core */
34698 + gpwrdn.b.pwrdnrstn = 1;
34699 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34702 + /* Disable power clamps */
34704 + gpwrdn.b.pwrdnclmp = 1;
34705 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34707 + /* Remove reset the core signal */
34709 + gpwrdn.b.pwrdnrstn = 1;
34710 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
34713 + /* Disable PMU interrupt */
34715 + gpwrdn.b.pmuintsel = 1;
34716 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34718 + core_if->hibernation_suspend = 0;
34720 + /* Disable PMU */
34722 + gpwrdn.b.pmuactv = 1;
34723 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34726 + /* Enable VBUS */
34728 + gpwrdn.b.dis_vbus = 1;
34729 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
34731 + core_if->op_state = A_HOST;
34732 + dwc_otg_core_init(core_if);
34733 + dwc_otg_enable_global_interrupts(core_if);
34734 + cil_hcd_start(core_if);
34738 + * Frees secondary storage associated with the dwc_otg_hcd structure contained
34739 + * in the struct usb_hcd field.
34741 +static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
34745 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
34747 + del_timers(dwc_otg_hcd);
34749 + /* Free memory for QH/QTD lists */
34750 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
34751 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
34752 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
34753 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
34754 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
34755 + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
34757 + /* Free memory for the host channels. */
34758 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
34759 + dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
34762 + if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
34763 + DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
34766 + if (hc != NULL) {
34767 + DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
34773 + if (dwc_otg_hcd->core_if->dma_enable) {
34774 + if (dwc_otg_hcd->status_buf_dma) {
34775 + DWC_DMA_FREE(DWC_OTG_HCD_STATUS_BUF_SIZE,
34776 + dwc_otg_hcd->status_buf,
34777 + dwc_otg_hcd->status_buf_dma);
34779 + } else if (dwc_otg_hcd->status_buf != NULL) {
34780 + DWC_FREE(dwc_otg_hcd->status_buf);
34782 + DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
34783 + /* Set core_if's lock pointer to NULL */
34784 + dwc_otg_hcd->core_if->lock = NULL;
34786 + DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
34787 + DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
34789 +#ifdef DWC_DEV_SRPCAP
34790 + if (dwc_otg_hcd->core_if->power_down == 2 &&
34791 + dwc_otg_hcd->core_if->pwron_timer) {
34792 + DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer);
34795 + DWC_FREE(dwc_otg_hcd);
34798 +int init_hcd_usecs(dwc_otg_hcd_t *_hcd);
34800 +int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
34803 + int num_channels;
34805 + dwc_hc_t *channel;
34807 + hcd->lock = DWC_SPINLOCK_ALLOC();
34808 + DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n",
34810 + if (!hcd->lock) {
34811 + DWC_ERROR("Could not allocate lock for pcd");
34813 + retval = -DWC_E_NO_MEMORY;
34816 + hcd->core_if = core_if;
34818 + /* Register the HCD CIL Callbacks */
34819 + dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
34820 + &hcd_cil_callbacks, hcd);
34822 + /* Initialize the non-periodic schedule. */
34823 + DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
34824 + DWC_LIST_INIT(&hcd->non_periodic_sched_active);
34826 + /* Initialize the periodic schedule. */
34827 + DWC_LIST_INIT(&hcd->periodic_sched_inactive);
34828 + DWC_LIST_INIT(&hcd->periodic_sched_ready);
34829 + DWC_LIST_INIT(&hcd->periodic_sched_assigned);
34830 + DWC_LIST_INIT(&hcd->periodic_sched_queued);
34833 + * Create a host channel descriptor for each host channel implemented
34834 + * in the controller. Initialize the channel descriptor array.
34836 + DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
34837 + num_channels = hcd->core_if->core_params->host_channels;
34838 + DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
34839 + for (i = 0; i < num_channels; i++) {
34840 + channel = DWC_ALLOC(sizeof(dwc_hc_t));
34841 + if (channel == NULL) {
34842 + retval = -DWC_E_NO_MEMORY;
34843 + DWC_ERROR("%s: host channel allocation failed\n",
34845 + dwc_otg_hcd_free(hcd);
34848 + channel->hc_num = i;
34849 + hcd->hc_ptr_array[i] = channel;
34851 + hcd->core_if->hc_xfer_timer[i] =
34852 + DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
34853 + &hcd->core_if->hc_xfer_info[i]);
34855 + DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
34859 + /* Initialize the Connection timeout timer. */
34860 + hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
34861 + dwc_otg_hcd_connect_timeout, 0);
34863 + printk(KERN_DEBUG "dwc_otg: Microframe scheduler %s\n", microframe_schedule ? "enabled":"disabled");
34864 + if (microframe_schedule)
34865 + init_hcd_usecs(hcd);
34867 + /* Initialize reset tasklet. */
34868 + hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
34869 +#ifdef DWC_DEV_SRPCAP
34870 + if (hcd->core_if->power_down == 2) {
34871 + /* Initialize Power on timer for Host power up in case hibernation */
34872 + hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER",
34873 + dwc_otg_hcd_power_up, core_if);
34878 + * Allocate space for storing data on status transactions. Normally no
34879 + * data is sent, but this space acts as a bit bucket. This must be
34880 + * done after usb_add_hcd since that function allocates the DMA buffer
34883 + if (hcd->core_if->dma_enable) {
34884 + hcd->status_buf =
34885 + DWC_DMA_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE,
34886 + &hcd->status_buf_dma);
34888 + hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE);
34890 + if (!hcd->status_buf) {
34891 + retval = -DWC_E_NO_MEMORY;
34892 + DWC_ERROR("%s: status_buf allocation failed\n", __func__);
34893 + dwc_otg_hcd_free(hcd);
34897 + hcd->otg_port = 1;
34898 + hcd->frame_list = NULL;
34899 + hcd->frame_list_dma = 0;
34900 + hcd->periodic_qh_count = 0;
34905 +void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
34907 + /* Turn off all host-specific interrupts. */
34908 + dwc_otg_disable_host_interrupts(hcd->core_if);
34910 + dwc_otg_hcd_free(hcd);
34914 + * Initializes dynamic portions of the DWC_otg HCD state.
34916 +static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
34918 + int num_channels;
34920 + dwc_hc_t *channel;
34921 + dwc_hc_t *channel_tmp;
34923 + hcd->flags.d32 = 0;
34925 + hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
34926 + if (!microframe_schedule) {
34927 + hcd->non_periodic_channels = 0;
34928 + hcd->periodic_channels = 0;
34930 + hcd->available_host_channels = hcd->core_if->core_params->host_channels;
34933 + * Put all channels in the free channel list and clean up channel
34936 + DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
34937 + &hcd->free_hc_list, hc_list_entry) {
34938 + DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
34941 + num_channels = hcd->core_if->core_params->host_channels;
34942 + for (i = 0; i < num_channels; i++) {
34943 + channel = hcd->hc_ptr_array[i];
34944 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
34946 + dwc_otg_hc_cleanup(hcd->core_if, channel);
34949 + /* Initialize the DWC core for host mode operation. */
34950 + dwc_otg_core_host_init(hcd->core_if);
34952 + /* Set core_if's lock pointer to the hcd->lock */
34953 + hcd->core_if->lock = hcd->lock;
34957 + * Assigns transactions from a QTD to a free host channel and initializes the
34958 + * host channel to perform the transactions. The host channel is removed from
34961 + * @param hcd The HCD state structure.
34962 + * @param qh Transactions from the first QTD for this QH are selected and
34963 + * assigned to a free host channel.
34965 +static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
34968 + dwc_otg_qtd_t *qtd;
34969 + dwc_otg_hcd_urb_t *urb;
34970 + void* ptr = NULL;
34972 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
34976 + DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p) - urb %x, actual_length %d\n", __func__, hcd, qh, (unsigned int)urb, urb->actual_length);
34978 + if (((urb->actual_length < 0) || (urb->actual_length > urb->length)) && !dwc_otg_hcd_is_pipe_in(&urb->pipe_info))
34979 + urb->actual_length = urb->length;
34982 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
34984 + /* Remove the host channel from the free list. */
34985 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
34987 + qh->channel = hc;
34989 + qtd->in_process = 1;
34992 + * Use usb_pipedevice to determine device address. This address is
34993 + * 0 before the SET_ADDRESS command and the correct address afterward.
34995 + hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
34996 + hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
34997 + hc->speed = qh->dev_speed;
34998 + hc->max_packet = dwc_max_packet(qh->maxp);
35000 + hc->xfer_started = 0;
35001 + hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
35002 + hc->error_state = (qtd->error_count > 0);
35003 + hc->halt_on_queue = 0;
35004 + hc->halt_pending = 0;
35005 + hc->requests = 0;
35008 + * The following values may be modified in the transfer type section
35009 + * below. The xfer_len value may be reduced when the transfer is
35010 + * started to accommodate the max widths of the XferSize and PktCnt
35011 + * fields in the HCTSIZn register.
35014 + hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
35015 + if (hc->ep_is_in) {
35018 + hc->do_ping = qh->ping_state;
35021 + hc->data_pid_start = qh->data_toggle;
35022 + hc->multi_count = 1;
35024 + if (hcd->core_if->dma_enable) {
35025 + hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
35027 + /* For non-dword aligned case */
35028 + if (((unsigned long)hc->xfer_buff & 0x3)
35029 + && !hcd->core_if->dma_desc_enable) {
35030 + ptr = (uint8_t *) urb->buf + urb->actual_length;
35033 + hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
35035 + hc->xfer_len = urb->length - urb->actual_length;
35036 + hc->xfer_count = 0;
35039 + * Set the split attributes
35041 + hc->do_split = 0;
35042 + if (qh->do_split) {
35043 + uint32_t hub_addr, port_addr;
35044 + hc->do_split = 1;
35045 + hc->xact_pos = qtd->isoc_split_pos;
35046 + hc->complete_split = qtd->complete_split;
35047 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
35048 + hc->hub_addr = (uint8_t) hub_addr;
35049 + hc->port_addr = (uint8_t) port_addr;
35052 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
35054 + hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
35055 + switch (qtd->control_phase) {
35056 + case DWC_OTG_CONTROL_SETUP:
35057 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n");
35059 + hc->ep_is_in = 0;
35060 + hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
35061 + if (hcd->core_if->dma_enable) {
35062 + hc->xfer_buff = (uint8_t *) urb->setup_dma;
35064 + hc->xfer_buff = (uint8_t *) urb->setup_packet;
35066 + hc->xfer_len = 8;
35069 + case DWC_OTG_CONTROL_DATA:
35070 + DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
35071 + hc->data_pid_start = qtd->data_toggle;
35073 + case DWC_OTG_CONTROL_STATUS:
35075 + * Direction is opposite of data direction or IN if no
35078 + DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n");
35079 + if (urb->length == 0) {
35080 + hc->ep_is_in = 1;
35083 + dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
35085 + if (hc->ep_is_in) {
35089 + hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
35091 + hc->xfer_len = 0;
35092 + if (hcd->core_if->dma_enable) {
35093 + hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
35095 + hc->xfer_buff = (uint8_t *) hcd->status_buf;
35102 + hc->ep_type = DWC_OTG_EP_TYPE_BULK;
35104 + case UE_INTERRUPT:
35105 + hc->ep_type = DWC_OTG_EP_TYPE_INTR;
35107 + case UE_ISOCHRONOUS:
35109 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
35111 + hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
35113 + if (hcd->core_if->dma_desc_enable)
35116 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
35118 + frame_desc->status = 0;
35120 + if (hcd->core_if->dma_enable) {
35121 + hc->xfer_buff = (uint8_t *) urb->dma;
35123 + hc->xfer_buff = (uint8_t *) urb->buf;
35126 + frame_desc->offset + qtd->isoc_split_offset;
35128 + frame_desc->length - qtd->isoc_split_offset;
35130 + /* For non-dword aligned buffers */
35131 + if (((unsigned long)hc->xfer_buff & 0x3)
35132 + && hcd->core_if->dma_enable) {
35134 + (uint8_t *) urb->buf + frame_desc->offset +
35135 + qtd->isoc_split_offset;
35139 + if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
35140 + if (hc->xfer_len <= 188) {
35141 + hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
35144 + DWC_HCSPLIT_XACTPOS_BEGIN;
35150 + /* non DWORD-aligned buffer case */
35152 + uint32_t buf_size;
35153 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
35154 + buf_size = hcd->core_if->core_params->max_transfer_size;
35158 + if (!qh->dw_align_buf) {
35159 + qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(buf_size,
35160 + &qh->dw_align_buf_dma);
35161 + if (!qh->dw_align_buf) {
35163 + ("%s: Failed to allocate memory to handle "
35164 + "non-dword aligned buffer case\n",
35169 + if (!hc->ep_is_in) {
35170 + dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
35172 + hc->align_buff = qh->dw_align_buf_dma;
35174 + hc->align_buff = 0;
35177 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
35178 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
35180 + * This value may be modified when the transfer is started to
35181 + * reflect the actual transfer length.
35183 + hc->multi_count = dwc_hb_mult(qh->maxp);
35186 + if (hcd->core_if->dma_desc_enable)
35187 + hc->desc_list_addr = qh->desc_list_dma;
35189 + dwc_otg_hc_init(hcd->core_if, hc);
35194 + * This function selects transactions from the HCD transfer schedule and
35195 + * assigns them to available host channels. It is called from HCD interrupt
35196 + * handler functions.
35198 + * @param hcd The HCD state structure.
35200 + * @return The types of new transactions that were assigned to host channels.
35202 +dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
35204 + dwc_list_link_t *qh_ptr;
35205 + dwc_otg_qh_t *qh;
35206 + int num_channels;
35207 + dwc_irqflags_t flags;
35208 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
35209 + dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
35212 + DWC_DEBUGPL(DBG_HCD, " Select Transactions\n");
35215 +#ifdef DEBUG_HOST_CHANNELS
35216 + last_sel_trans_num_per_scheduled = 0;
35217 + last_sel_trans_num_nonper_scheduled = 0;
35218 + last_sel_trans_num_avail_hc_at_start = hcd->available_host_channels;
35219 +#endif /* DEBUG_HOST_CHANNELS */
35221 + /* Process entries in the periodic ready list. */
35222 + qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
35224 + while (qh_ptr != &hcd->periodic_sched_ready &&
35225 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
35226 + if (microframe_schedule) {
35227 + // Make sure we leave one channel for non periodic transactions.
35228 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35229 + if (hcd->available_host_channels <= 1) {
35230 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35233 + hcd->available_host_channels--;
35234 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35235 +#ifdef DEBUG_HOST_CHANNELS
35236 + last_sel_trans_num_per_scheduled++;
35237 +#endif /* DEBUG_HOST_CHANNELS */
35239 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35240 + assign_and_init_hc(hcd, qh);
35243 + * Move the QH from the periodic ready schedule to the
35244 + * periodic assigned schedule.
35246 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
35247 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35248 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
35249 + &qh->qh_list_entry);
35250 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35252 + ret_val = DWC_OTG_TRANSACTION_PERIODIC;
35256 + * Process entries in the inactive portion of the non-periodic
35257 + * schedule. Some free host channels may not be used if they are
35258 + * reserved for periodic transfers.
35260 + qh_ptr = hcd->non_periodic_sched_inactive.next;
35261 + num_channels = hcd->core_if->core_params->host_channels;
35262 + while (qh_ptr != &hcd->non_periodic_sched_inactive &&
35263 + (microframe_schedule || hcd->non_periodic_channels <
35264 + num_channels - hcd->periodic_channels) &&
35265 + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
35267 + if (microframe_schedule) {
35268 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35269 + if (hcd->available_host_channels < 1) {
35270 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35273 + hcd->available_host_channels--;
35274 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35275 +#ifdef DEBUG_HOST_CHANNELS
35276 + last_sel_trans_num_nonper_scheduled++;
35277 +#endif /* DEBUG_HOST_CHANNELS */
35279 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35281 + assign_and_init_hc(hcd, qh);
35284 + * Move the QH from the non-periodic inactive schedule to the
35285 + * non-periodic active schedule.
35287 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
35288 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
35289 + DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
35290 + &qh->qh_list_entry);
35291 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
35293 + if (ret_val == DWC_OTG_TRANSACTION_NONE) {
35294 + ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
35296 + ret_val = DWC_OTG_TRANSACTION_ALL;
35299 + if (!microframe_schedule)
35300 + hcd->non_periodic_channels++;
35303 +#ifdef DEBUG_HOST_CHANNELS
35304 + last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels;
35305 +#endif /* DEBUG_HOST_CHANNELS */
35307 + DWC_SPINLOCK_FREE(channel_lock);
35312 + * Attempts to queue a single transaction request for a host channel
35313 + * associated with either a periodic or non-periodic transfer. This function
35314 + * assumes that there is space available in the appropriate request queue. For
35315 + * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
35316 + * is available in the appropriate Tx FIFO.
35318 + * @param hcd The HCD state structure.
35319 + * @param hc Host channel descriptor associated with either a periodic or
35320 + * non-periodic transfer.
35321 + * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx
35322 + * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
35325 + * @return 1 if a request is queued and more requests may be needed to
35326 + * complete the transfer, 0 if no more requests are required for this
35327 + * transfer, -1 if there is insufficient space in the Tx FIFO.
35329 +static int queue_transaction(dwc_otg_hcd_t * hcd,
35330 + dwc_hc_t * hc, uint16_t fifo_dwords_avail)
35334 + if (hcd->core_if->dma_enable) {
35335 + if (hcd->core_if->dma_desc_enable) {
35336 + if (!hc->xfer_started
35337 + || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
35338 + dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
35339 + hc->qh->ping_state = 0;
35341 + } else if (!hc->xfer_started) {
35342 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35343 + hc->qh->ping_state = 0;
35346 + } else if (hc->halt_pending) {
35347 + /* Don't queue a request if the channel has been halted. */
35349 + } else if (hc->halt_on_queue) {
35350 + dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
35352 + } else if (hc->do_ping) {
35353 + if (!hc->xfer_started) {
35354 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35357 + } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
35358 + if ((fifo_dwords_avail * 4) >= hc->max_packet) {
35359 + if (!hc->xfer_started) {
35360 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35364 + dwc_otg_hc_continue_transfer(hcd->core_if,
35371 + if (!hc->xfer_started) {
35372 + dwc_otg_hc_start_transfer(hcd->core_if, hc);
35375 + retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
35383 + * Processes periodic channels for the next frame and queues transactions for
35384 + * these channels to the DWC_otg controller. After queueing transactions, the
35385 + * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
35386 + * to queue as Periodic Tx FIFO or request queue space becomes available.
35387 + * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
35389 +static void process_periodic_channels(dwc_otg_hcd_t * hcd)
35391 + hptxsts_data_t tx_status;
35392 + dwc_list_link_t *qh_ptr;
35393 + dwc_otg_qh_t *qh;
35395 + int no_queue_space = 0;
35396 + int no_fifo_space = 0;
35398 + dwc_otg_host_global_regs_t *host_regs;
35399 + host_regs = hcd->core_if->host_if->host_global_regs;
35401 + DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
35403 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35404 + DWC_DEBUGPL(DBG_HCDV,
35405 + " P Tx Req Queue Space Avail (before queue): %d\n",
35406 + tx_status.b.ptxqspcavail);
35407 + DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n",
35408 + tx_status.b.ptxfspcavail);
35411 + qh_ptr = hcd->periodic_sched_assigned.next;
35412 + while (qh_ptr != &hcd->periodic_sched_assigned) {
35413 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35414 + if (tx_status.b.ptxqspcavail == 0) {
35415 + no_queue_space = 1;
35419 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
35422 + * Set a flag if we're queuing high-bandwidth in slave mode.
35423 + * The flag prevents any halts to get into the request queue in
35424 + * the middle of multiple high-bandwidth packets getting queued.
35426 + if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
35427 + hcd->core_if->queuing_high_bandwidth = 1;
35430 + queue_transaction(hcd, qh->channel,
35431 + tx_status.b.ptxfspcavail);
35432 + if (status < 0) {
35433 + no_fifo_space = 1;
35438 + * In Slave mode, stay on the current transfer until there is
35439 + * nothing more to do or the high-bandwidth request count is
35440 + * reached. In DMA mode, only need to queue one request. The
35441 + * controller automatically handles multiple packets for
35442 + * high-bandwidth transfers.
35444 + if (hcd->core_if->dma_enable || status == 0 ||
35445 + qh->channel->requests == qh->channel->multi_count) {
35446 + qh_ptr = qh_ptr->next;
35448 + * Move the QH from the periodic assigned schedule to
35449 + * the periodic queued schedule.
35451 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
35452 + &qh->qh_list_entry);
35454 + /* done queuing high bandwidth */
35455 + hcd->core_if->queuing_high_bandwidth = 0;
35459 + if (!hcd->core_if->dma_enable) {
35460 + dwc_otg_core_global_regs_t *global_regs;
35461 + gintmsk_data_t intr_mask = {.d32 = 0 };
35463 + global_regs = hcd->core_if->core_global_regs;
35464 + intr_mask.b.ptxfempty = 1;
35466 + tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
35467 + DWC_DEBUGPL(DBG_HCDV,
35468 + " P Tx Req Queue Space Avail (after queue): %d\n",
35469 + tx_status.b.ptxqspcavail);
35470 + DWC_DEBUGPL(DBG_HCDV,
35471 + " P Tx FIFO Space Avail (after queue): %d\n",
35472 + tx_status.b.ptxfspcavail);
35474 + if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
35475 + no_queue_space || no_fifo_space) {
35477 + * May need to queue more transactions as the request
35478 + * queue or Tx FIFO empties. Enable the periodic Tx
35479 + * FIFO empty interrupt. (Always use the half-empty
35480 + * level to ensure that new requests are loaded as
35481 + * soon as possible.)
35483 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
35487 + * Disable the Tx FIFO empty interrupt since there are
35488 + * no more transactions that need to be queued right
35489 + * now. This function is called from interrupt
35490 + * handlers to queue more transactions as transfer
35493 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
35500 + * Processes active non-periodic channels and queues transactions for these
35501 + * channels to the DWC_otg controller. After queueing transactions, the NP Tx
35502 + * FIFO Empty interrupt is enabled if there are more transactions to queue as
35503 + * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
35504 + * FIFO Empty interrupt is disabled.
35506 +static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
35508 + gnptxsts_data_t tx_status;
35509 + dwc_list_link_t *orig_qh_ptr;
35510 + dwc_otg_qh_t *qh;
35512 + int no_queue_space = 0;
35513 + int no_fifo_space = 0;
35514 + int more_to_do = 0;
35516 + dwc_otg_core_global_regs_t *global_regs =
35517 + hcd->core_if->core_global_regs;
35519 + DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
35521 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35522 + DWC_DEBUGPL(DBG_HCDV,
35523 + " NP Tx Req Queue Space Avail (before queue): %d\n",
35524 + tx_status.b.nptxqspcavail);
35525 + DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n",
35526 + tx_status.b.nptxfspcavail);
35529 + * Keep track of the starting point. Skip over the start-of-list
35532 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
35533 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
35535 + orig_qh_ptr = hcd->non_periodic_qh_ptr;
35538 + * Process once through the active list or until no more space is
35539 + * available in the request queue or the Tx FIFO.
35542 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35543 + if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
35544 + no_queue_space = 1;
35548 + qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
35551 + queue_transaction(hcd, qh->channel,
35552 + tx_status.b.nptxfspcavail);
35554 + if (status > 0) {
35556 + } else if (status < 0) {
35557 + no_fifo_space = 1;
35561 + /* Advance to next QH, skipping start-of-list entry. */
35562 + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
35563 + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
35564 + hcd->non_periodic_qh_ptr =
35565 + hcd->non_periodic_qh_ptr->next;
35568 + } while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
35570 + if (!hcd->core_if->dma_enable) {
35571 + gintmsk_data_t intr_mask = {.d32 = 0 };
35572 + intr_mask.b.nptxfempty = 1;
35575 + tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
35576 + DWC_DEBUGPL(DBG_HCDV,
35577 + " NP Tx Req Queue Space Avail (after queue): %d\n",
35578 + tx_status.b.nptxqspcavail);
35579 + DWC_DEBUGPL(DBG_HCDV,
35580 + " NP Tx FIFO Space Avail (after queue): %d\n",
35581 + tx_status.b.nptxfspcavail);
35583 + if (more_to_do || no_queue_space || no_fifo_space) {
35585 + * May need to queue more transactions as the request
35586 + * queue or Tx FIFO empties. Enable the non-periodic
35587 + * Tx FIFO empty interrupt. (Always use the half-empty
35588 + * level to ensure that new requests are loaded as
35589 + * soon as possible.)
35591 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
35595 + * Disable the Tx FIFO empty interrupt since there are
35596 + * no more transactions that need to be queued right
35597 + * now. This function is called from interrupt
35598 + * handlers to queue more transactions as transfer
35601 + DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
35608 + * This function processes the currently active host channels and queues
35609 + * transactions for these channels to the DWC_otg controller. It is called
35610 + * from HCD interrupt handler functions.
35612 + * @param hcd The HCD state structure.
35613 + * @param tr_type The type(s) of transactions to queue (non-periodic,
35614 + * periodic, or both).
35616 +void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
35617 + dwc_otg_transaction_type_e tr_type)
35620 + DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
35622 + /* Process host channels associated with periodic transfers. */
35623 + if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
35624 + tr_type == DWC_OTG_TRANSACTION_ALL) &&
35625 + !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
35627 + process_periodic_channels(hcd);
35630 + /* Process host channels associated with non-periodic transfers. */
35631 + if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
35632 + tr_type == DWC_OTG_TRANSACTION_ALL) {
35633 + if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
35634 + process_non_periodic_channels(hcd);
35637 + * Ensure NP Tx FIFO empty interrupt is disabled when
35638 + * there are no non-periodic transfers to process.
35640 + gintmsk_data_t gintmsk = {.d32 = 0 };
35641 + gintmsk.b.nptxfempty = 1;
35642 + DWC_MODIFY_REG32(&hcd->core_if->
35643 + core_global_regs->gintmsk, gintmsk.d32,
35649 +#ifdef DWC_HS_ELECT_TST
35651 + * Quick and dirty hack to implement the HS Electrical Test
35652 + * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
35654 + * This code was copied from our userspace app "hset". It sends a
35655 + * Get Device Descriptor control sequence in two parts, first the
35656 + * Setup packet by itself, followed some time later by the In and
35657 + * Ack packets. Rather than trying to figure out how to add this
35658 + * functionality to the normal driver code, we just hijack the
35659 + * hardware, using these two function to drive the hardware
35663 +static dwc_otg_core_global_regs_t *global_regs;
35664 +static dwc_otg_host_global_regs_t *hc_global_regs;
35665 +static dwc_otg_hc_regs_t *hc_regs;
35666 +static uint32_t *data_fifo;
35668 +static void do_setup(void)
35670 + gintsts_data_t gintsts;
35671 + hctsiz_data_t hctsiz;
35672 + hcchar_data_t hcchar;
35673 + haint_data_t haint;
35674 + hcint_data_t hcint;
35676 + /* Enable HAINTs */
35677 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
35679 + /* Enable HCINTs */
35680 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
35682 + /* Read GINTSTS */
35683 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35686 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35689 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35691 + /* Read HCCHAR */
35692 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35694 + /* Clear HCINT */
35695 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35697 + /* Clear HAINT */
35698 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35700 + /* Clear GINTSTS */
35701 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35703 + /* Read GINTSTS */
35704 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35707 + * Send Setup packet (Get Device Descriptor)
35710 + /* Make sure channel is disabled */
35711 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35712 + if (hcchar.b.chen) {
35713 + hcchar.b.chdis = 1;
35714 +// hcchar.b.chen = 1;
35715 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35717 + dwc_mdelay(1000);
35719 + /* Read GINTSTS */
35720 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35723 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35726 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35728 + /* Read HCCHAR */
35729 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35731 + /* Clear HCINT */
35732 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35734 + /* Clear HAINT */
35735 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35737 + /* Clear GINTSTS */
35738 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35740 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35745 + hctsiz.b.xfersize = 8;
35746 + hctsiz.b.pktcnt = 1;
35747 + hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
35748 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
35751 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35752 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
35753 + hcchar.b.epdir = 0;
35754 + hcchar.b.epnum = 0;
35755 + hcchar.b.mps = 8;
35756 + hcchar.b.chen = 1;
35757 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
35759 + /* Fill FIFO with Setup data for Get Device Descriptor */
35760 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
35761 + DWC_WRITE_REG32(data_fifo++, 0x01000680);
35762 + DWC_WRITE_REG32(data_fifo++, 0x00080000);
35764 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35766 + /* Wait for host channel interrupt */
35768 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35769 + } while (gintsts.b.hcintr == 0);
35771 + /* Disable HCINTs */
35772 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
35774 + /* Disable HAINTs */
35775 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
35778 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35781 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35783 + /* Read HCCHAR */
35784 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35786 + /* Clear HCINT */
35787 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35789 + /* Clear HAINT */
35790 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35792 + /* Clear GINTSTS */
35793 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35795 + /* Read GINTSTS */
35796 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35799 +static void do_in_ack(void)
35801 + gintsts_data_t gintsts;
35802 + hctsiz_data_t hctsiz;
35803 + hcchar_data_t hcchar;
35804 + haint_data_t haint;
35805 + hcint_data_t hcint;
35806 + host_grxsts_data_t grxsts;
35808 + /* Enable HAINTs */
35809 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
35811 + /* Enable HCINTs */
35812 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
35814 + /* Read GINTSTS */
35815 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35818 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35821 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35823 + /* Read HCCHAR */
35824 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35826 + /* Clear HCINT */
35827 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35829 + /* Clear HAINT */
35830 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35832 + /* Clear GINTSTS */
35833 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35835 + /* Read GINTSTS */
35836 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35839 + * Receive Control In packet
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 = 8;
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 = 1;
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 receive status queue interrupt */
35895 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35896 + } while (gintsts.b.rxstsqlvl == 0);
35899 + grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
35901 + /* Clear RXSTSQLVL in GINTSTS */
35903 + gintsts.b.rxstsqlvl = 1;
35904 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35906 + switch (grxsts.b.pktsts) {
35907 + case DWC_GRXSTS_PKTSTS_IN:
35908 + /* Read the data into the host buffer */
35909 + if (grxsts.b.bcnt > 0) {
35911 + int word_count = (grxsts.b.bcnt + 3) / 4;
35913 + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
35915 + for (i = 0; i < word_count; i++) {
35916 + (void)DWC_READ_REG32(data_fifo++);
35925 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35927 + /* Wait for receive status queue interrupt */
35929 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35930 + } while (gintsts.b.rxstsqlvl == 0);
35933 + grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
35935 + /* Clear RXSTSQLVL in GINTSTS */
35937 + gintsts.b.rxstsqlvl = 1;
35938 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35940 + switch (grxsts.b.pktsts) {
35941 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
35948 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35950 + /* Wait for host channel interrupt */
35952 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35953 + } while (gintsts.b.hcintr == 0);
35956 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35959 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35961 + /* Read HCCHAR */
35962 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35964 + /* Clear HCINT */
35965 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35967 + /* Clear HAINT */
35968 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35970 + /* Clear GINTSTS */
35971 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
35973 + /* Read GINTSTS */
35974 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
35976 +// usleep(100000);
35981 + * Send handshake packet
35985 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
35988 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
35990 + /* Read HCCHAR */
35991 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
35993 + /* Clear HCINT */
35994 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
35996 + /* Clear HAINT */
35997 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
35999 + /* Clear GINTSTS */
36000 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
36002 + /* Read GINTSTS */
36003 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
36005 + /* Make sure channel is disabled */
36006 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
36007 + if (hcchar.b.chen) {
36008 + hcchar.b.chdis = 1;
36009 + hcchar.b.chen = 1;
36010 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
36012 + dwc_mdelay(1000);
36014 + /* Read GINTSTS */
36015 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
36018 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
36021 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
36023 + /* Read HCCHAR */
36024 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
36026 + /* Clear HCINT */
36027 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
36029 + /* Clear HAINT */
36030 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
36032 + /* Clear GINTSTS */
36033 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
36035 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
36040 + hctsiz.b.xfersize = 0;
36041 + hctsiz.b.pktcnt = 1;
36042 + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
36043 + DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
36046 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
36047 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
36048 + hcchar.b.epdir = 0;
36049 + hcchar.b.epnum = 0;
36050 + hcchar.b.mps = 8;
36051 + hcchar.b.chen = 1;
36052 + DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
36054 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
36056 + /* Wait for host channel interrupt */
36058 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
36059 + } while (gintsts.b.hcintr == 0);
36061 + /* Disable HCINTs */
36062 + DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
36064 + /* Disable HAINTs */
36065 + DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
36068 + haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
36071 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
36073 + /* Read HCCHAR */
36074 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
36076 + /* Clear HCINT */
36077 + DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
36079 + /* Clear HAINT */
36080 + DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
36082 + /* Clear GINTSTS */
36083 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
36085 + /* Read GINTSTS */
36086 + gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
36090 +/** Handles hub class-specific requests. */
36091 +int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
36092 + uint16_t typeReq,
36094 + uint16_t wIndex, uint8_t * buf, uint16_t wLength)
36098 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
36099 + usb_hub_descriptor_t *hub_desc;
36100 + hprt0_data_t hprt0 = {.d32 = 0 };
36102 + uint32_t port_status;
36104 + switch (typeReq) {
36105 + case UCR_CLEAR_HUB_FEATURE:
36106 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36107 + "ClearHubFeature 0x%x\n", wValue);
36108 + switch (wValue) {
36109 + case UHF_C_HUB_LOCAL_POWER:
36110 + case UHF_C_HUB_OVER_CURRENT:
36111 + /* Nothing required here */
36114 + retval = -DWC_E_INVALID;
36115 + DWC_ERROR("DWC OTG HCD - "
36116 + "ClearHubFeature request %xh unknown\n",
36120 + case UCR_CLEAR_PORT_FEATURE:
36121 +#ifdef CONFIG_USB_DWC_OTG_LPM
36122 + if (wValue != UHF_PORT_L1)
36124 + if (!wIndex || wIndex > 1)
36127 + switch (wValue) {
36128 + case UHF_PORT_ENABLE:
36129 + DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
36130 + "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
36131 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36132 + hprt0.b.prtena = 1;
36133 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36135 + case UHF_PORT_SUSPEND:
36136 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36137 + "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
36139 + if (core_if->power_down == 2) {
36140 + dwc_otg_host_hibernation_restore(core_if, 0, 0);
36142 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
36145 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36146 + hprt0.b.prtres = 1;
36147 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36148 + hprt0.b.prtsusp = 0;
36149 + /* Clear Resume bit */
36151 + hprt0.b.prtres = 0;
36152 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36155 +#ifdef CONFIG_USB_DWC_OTG_LPM
36156 + case UHF_PORT_L1:
36158 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36159 + glpmcfg_data_t lpmcfg = {.d32 = 0 };
36162 + DWC_READ_REG32(&core_if->
36163 + core_global_regs->glpmcfg);
36164 + lpmcfg.b.en_utmi_sleep = 0;
36165 + lpmcfg.b.hird_thres &= (~(1 << 4));
36166 + lpmcfg.b.prt_sleep_sts = 1;
36167 + DWC_WRITE_REG32(&core_if->
36168 + core_global_regs->glpmcfg,
36171 + /* Clear Enbl_L1Gating bit. */
36172 + pcgcctl.b.enbl_sleep_gating = 1;
36173 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
36178 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36179 + hprt0.b.prtres = 1;
36180 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36182 + /* This bit will be cleared in wakeup interrupt handle */
36186 + case UHF_PORT_POWER:
36187 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36188 + "ClearPortFeature USB_PORT_FEAT_POWER\n");
36189 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36190 + hprt0.b.prtpwr = 0;
36191 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36193 + case UHF_PORT_INDICATOR:
36194 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36195 + "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
36196 + /* Port inidicator not supported */
36198 + case UHF_C_PORT_CONNECTION:
36199 + /* Clears drivers internal connect status change
36201 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36202 + "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
36203 + dwc_otg_hcd->flags.b.port_connect_status_change = 0;
36205 + case UHF_C_PORT_RESET:
36206 + /* Clears the driver's internal Port Reset Change
36208 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36209 + "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
36210 + dwc_otg_hcd->flags.b.port_reset_change = 0;
36212 + case UHF_C_PORT_ENABLE:
36213 + /* Clears the driver's internal Port
36214 + * Enable/Disable Change flag */
36215 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36216 + "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
36217 + dwc_otg_hcd->flags.b.port_enable_change = 0;
36219 + case UHF_C_PORT_SUSPEND:
36220 + /* Clears the driver's internal Port Suspend
36221 + * Change flag, which is set when resume signaling on
36222 + * the host port is complete */
36223 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36224 + "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
36225 + dwc_otg_hcd->flags.b.port_suspend_change = 0;
36227 +#ifdef CONFIG_USB_DWC_OTG_LPM
36228 + case UHF_C_PORT_L1:
36229 + dwc_otg_hcd->flags.b.port_l1_change = 0;
36232 + case UHF_C_PORT_OVER_CURRENT:
36233 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36234 + "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
36235 + dwc_otg_hcd->flags.b.port_over_current_change = 0;
36238 + retval = -DWC_E_INVALID;
36239 + DWC_ERROR("DWC OTG HCD - "
36240 + "ClearPortFeature request %xh "
36241 + "unknown or unsupported\n", wValue);
36244 + case UCR_GET_HUB_DESCRIPTOR:
36245 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36246 + "GetHubDescriptor\n");
36247 + hub_desc = (usb_hub_descriptor_t *) buf;
36248 + hub_desc->bDescLength = 9;
36249 + hub_desc->bDescriptorType = 0x29;
36250 + hub_desc->bNbrPorts = 1;
36251 + USETW(hub_desc->wHubCharacteristics, 0x08);
36252 + hub_desc->bPwrOn2PwrGood = 1;
36253 + hub_desc->bHubContrCurrent = 0;
36254 + hub_desc->DeviceRemovable[0] = 0;
36255 + hub_desc->DeviceRemovable[1] = 0xff;
36257 + case UCR_GET_HUB_STATUS:
36258 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36259 + "GetHubStatus\n");
36260 + DWC_MEMSET(buf, 0, 4);
36262 + case UCR_GET_PORT_STATUS:
36263 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36264 + "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n",
36265 + wIndex, dwc_otg_hcd->flags.d32);
36266 + if (!wIndex || wIndex > 1)
36271 + if (dwc_otg_hcd->flags.b.port_connect_status_change)
36272 + port_status |= (1 << UHF_C_PORT_CONNECTION);
36274 + if (dwc_otg_hcd->flags.b.port_enable_change)
36275 + port_status |= (1 << UHF_C_PORT_ENABLE);
36277 + if (dwc_otg_hcd->flags.b.port_suspend_change)
36278 + port_status |= (1 << UHF_C_PORT_SUSPEND);
36280 + if (dwc_otg_hcd->flags.b.port_l1_change)
36281 + port_status |= (1 << UHF_C_PORT_L1);
36283 + if (dwc_otg_hcd->flags.b.port_reset_change) {
36284 + port_status |= (1 << UHF_C_PORT_RESET);
36287 + if (dwc_otg_hcd->flags.b.port_over_current_change) {
36288 + DWC_WARN("Overcurrent change detected\n");
36289 + port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
36292 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
36294 + * The port is disconnected, which means the core is
36295 + * either in device mode or it soon will be. Just
36296 + * return 0's for the remainder of the port status
36297 + * since the port register can't be read if the core
36298 + * is in device mode.
36300 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
36304 + hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
36305 + DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32);
36307 + if (hprt0.b.prtconnsts)
36308 + port_status |= (1 << UHF_PORT_CONNECTION);
36310 + if (hprt0.b.prtena)
36311 + port_status |= (1 << UHF_PORT_ENABLE);
36313 + if (hprt0.b.prtsusp)
36314 + port_status |= (1 << UHF_PORT_SUSPEND);
36316 + if (hprt0.b.prtovrcurract)
36317 + port_status |= (1 << UHF_PORT_OVER_CURRENT);
36319 + if (hprt0.b.prtrst)
36320 + port_status |= (1 << UHF_PORT_RESET);
36322 + if (hprt0.b.prtpwr)
36323 + port_status |= (1 << UHF_PORT_POWER);
36325 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
36326 + port_status |= (1 << UHF_PORT_HIGH_SPEED);
36327 + else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
36328 + port_status |= (1 << UHF_PORT_LOW_SPEED);
36330 + if (hprt0.b.prttstctl)
36331 + port_status |= (1 << UHF_PORT_TEST);
36332 + if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
36333 + port_status |= (1 << UHF_PORT_L1);
36336 + For Synopsys HW emulation of Power down wkup_control asserts the
36337 + hreset_n and prst_n on suspned. This causes the HPRT0 to be zero.
36338 + We intentionally tell the software that port is in L2Suspend state.
36341 + if ((core_if->power_down == 2)
36342 + && (core_if->hibernation_suspend == 1)) {
36343 + port_status |= (1 << UHF_PORT_SUSPEND);
36345 + /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
36347 + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
36350 + case UCR_SET_HUB_FEATURE:
36351 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36352 + "SetHubFeature\n");
36353 + /* No HUB features supported */
36355 + case UCR_SET_PORT_FEATURE:
36356 + if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
36359 + if (!dwc_otg_hcd->flags.b.port_connect_status) {
36361 + * The port is disconnected, which means the core is
36362 + * either in device mode or it soon will be. Just
36363 + * return without doing anything since the port
36364 + * register can't be written if the core is in device
36370 + switch (wValue) {
36371 + case UHF_PORT_SUSPEND:
36372 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36373 + "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
36374 + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) {
36377 + if (core_if->power_down == 2) {
36378 + int timeout = 300;
36379 + dwc_irqflags_t flags;
36380 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36381 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
36382 + gusbcfg_data_t gusbcfg = {.d32 = 0 };
36383 +#ifdef DWC_DEV_SRPCAP
36384 + int32_t otg_cap_param = core_if->core_params->otg_cap;
36386 + DWC_PRINTF("Preparing for complete power-off\n");
36388 + /* Save registers before hibernation */
36389 + dwc_otg_save_global_regs(core_if);
36390 + dwc_otg_save_host_regs(core_if);
36392 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36393 + hprt0.b.prtsusp = 1;
36394 + hprt0.b.prtena = 0;
36395 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36396 + /* Spin hprt0.b.prtsusp to became 1 */
36398 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36399 + if (hprt0.b.prtsusp) {
36403 + } while (--timeout);
36405 + DWC_WARN("Suspend wasn't genereted\n");
36410 + * We need to disable interrupts to prevent servicing of any IRQ
36411 + * during going to hibernation
36413 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
36414 + core_if->lx_state = DWC_OTG_L2;
36415 +#ifdef DWC_DEV_SRPCAP
36416 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36417 + hprt0.b.prtpwr = 0;
36418 + hprt0.b.prtena = 0;
36419 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36423 + DWC_READ_REG32(&core_if->core_global_regs->
36425 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
36426 + /* ULPI interface */
36427 + /* Suspend the Phy Clock */
36429 + pcgcctl.b.stoppclk = 1;
36430 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
36433 + gpwrdn.b.pmuactv = 1;
36434 + DWC_MODIFY_REG32(&core_if->
36435 + core_global_regs->
36436 + gpwrdn, 0, gpwrdn.d32);
36438 + /* UTMI+ Interface */
36439 + gpwrdn.b.pmuactv = 1;
36440 + DWC_MODIFY_REG32(&core_if->
36441 + core_global_regs->
36442 + gpwrdn, 0, gpwrdn.d32);
36444 + pcgcctl.b.stoppclk = 1;
36445 + DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
36448 +#ifdef DWC_DEV_SRPCAP
36450 + gpwrdn.b.dis_vbus = 1;
36451 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36452 + gpwrdn, 0, gpwrdn.d32);
36455 + gpwrdn.b.pmuintsel = 1;
36456 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36457 + gpwrdn, 0, gpwrdn.d32);
36461 +#ifdef DWC_DEV_SRPCAP
36462 + gpwrdn.b.srp_det_msk = 1;
36464 + gpwrdn.b.disconn_det_msk = 1;
36465 + gpwrdn.b.lnstchng_msk = 1;
36466 + gpwrdn.b.sts_chngint_msk = 1;
36467 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36468 + gpwrdn, 0, gpwrdn.d32);
36471 + /* Enable Power Down Clamp and all interrupts in GPWRDN */
36473 + gpwrdn.b.pwrdnclmp = 1;
36474 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36475 + gpwrdn, 0, gpwrdn.d32);
36478 + /* Switch off VDD */
36480 + gpwrdn.b.pwrdnswtch = 1;
36481 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36482 + gpwrdn, 0, gpwrdn.d32);
36484 +#ifdef DWC_DEV_SRPCAP
36485 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
36487 + core_if->pwron_timer_started = 1;
36488 + DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ );
36491 + /* Save gpwrdn register for further usage if stschng interrupt */
36492 + core_if->gr_backup->gpwrdn_local =
36493 + DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
36495 + /* Set flag to indicate that we are in hibernation */
36496 + core_if->hibernation_suspend = 1;
36497 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags);
36499 + DWC_PRINTF("Host hibernation completed\n");
36500 + // Exit from case statement
36504 + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
36505 + dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
36506 + gotgctl_data_t gotgctl = {.d32 = 0 };
36507 + gotgctl.b.hstsethnpen = 1;
36508 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36509 + gotgctl, 0, gotgctl.d32);
36510 + core_if->op_state = A_SUSPEND;
36512 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36513 + hprt0.b.prtsusp = 1;
36514 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36516 + dwc_irqflags_t flags;
36517 + /* Update lx_state */
36518 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
36519 + core_if->lx_state = DWC_OTG_L2;
36520 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
36522 + /* Suspend the Phy Clock */
36524 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36525 + pcgcctl.b.stoppclk = 1;
36526 + DWC_MODIFY_REG32(core_if->pcgcctl, 0,
36531 + /* For HNP the bus must be suspended for at least 200ms. */
36532 + if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
36533 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36534 + pcgcctl.b.stoppclk = 1;
36535 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
36539 + /** @todo - check how sw can wait for 1 sec to check asesvld??? */
36540 +#if 0 //vahrama !!!!!!!!!!!!!!!!!!
36541 + if (core_if->adp_enable) {
36542 + gotgctl_data_t gotgctl = {.d32 = 0 };
36543 + gpwrdn_data_t gpwrdn;
36545 + while (gotgctl.b.asesvld == 1) {
36547 + DWC_READ_REG32(&core_if->
36548 + core_global_regs->
36553 + /* Enable Power Down Logic */
36555 + gpwrdn.b.pmuactv = 1;
36556 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36557 + gpwrdn, 0, gpwrdn.d32);
36559 + /* Unmask SRP detected interrupt from Power Down Logic */
36561 + gpwrdn.b.srp_det_msk = 1;
36562 + DWC_MODIFY_REG32(&core_if->core_global_regs->
36563 + gpwrdn, 0, gpwrdn.d32);
36565 + dwc_otg_adp_probe_start(core_if);
36569 + case UHF_PORT_POWER:
36570 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36571 + "SetPortFeature - USB_PORT_FEAT_POWER\n");
36572 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36573 + hprt0.b.prtpwr = 1;
36574 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36576 + case UHF_PORT_RESET:
36577 + if ((core_if->power_down == 2)
36578 + && (core_if->hibernation_suspend == 1)) {
36579 + /* If we are going to exit from Hibernated
36580 + * state via USB RESET.
36582 + dwc_otg_host_hibernation_restore(core_if, 0, 1);
36584 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36586 + DWC_DEBUGPL(DBG_HCD,
36587 + "DWC OTG HCD HUB CONTROL - "
36588 + "SetPortFeature - USB_PORT_FEAT_RESET\n");
36590 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36591 + pcgcctl.b.enbl_sleep_gating = 1;
36592 + pcgcctl.b.stoppclk = 1;
36593 + DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
36594 + DWC_WRITE_REG32(core_if->pcgcctl, 0);
36596 +#ifdef CONFIG_USB_DWC_OTG_LPM
36598 + glpmcfg_data_t lpmcfg;
36600 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36601 + if (lpmcfg.b.prt_sleep_sts) {
36602 + lpmcfg.b.en_utmi_sleep = 0;
36603 + lpmcfg.b.hird_thres &= (~(1 << 4));
36605 + (&core_if->core_global_regs->glpmcfg,
36611 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36612 + /* Clear suspend bit if resetting from suspended state. */
36613 + hprt0.b.prtsusp = 0;
36614 + /* When B-Host the Port reset bit is set in
36615 + * the Start HCD Callback function, so that
36616 + * the reset is started within 1ms of the HNP
36617 + * success interrupt. */
36618 + if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
36619 + hprt0.b.prtpwr = 1;
36620 + hprt0.b.prtrst = 1;
36621 + DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32);
36622 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36625 + /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
36627 + hprt0.b.prtrst = 0;
36628 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36629 + core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */
36632 +#ifdef DWC_HS_ELECT_TST
36633 + case UHF_PORT_TEST:
36636 + gintmsk_data_t gintmsk;
36638 + t = (wIndex >> 8); /* MSB wIndex USB */
36639 + DWC_DEBUGPL(DBG_HCD,
36640 + "DWC OTG HCD HUB CONTROL - "
36641 + "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
36643 + DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
36645 + hprt0.d32 = dwc_otg_read_hprt0(core_if);
36646 + hprt0.b.prttstctl = t;
36647 + DWC_WRITE_REG32(core_if->host_if->hprt0,
36650 + /* Setup global vars with reg addresses (quick and
36651 + * dirty hack, should be cleaned up)
36653 + global_regs = core_if->core_global_regs;
36655 + core_if->host_if->host_global_regs;
36657 + (dwc_otg_hc_regs_t *) ((char *)
36661 + (uint32_t *) ((char *)global_regs +
36664 + if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */
36665 + /* Save current interrupt mask */
36668 + (&global_regs->gintmsk);
36670 + /* Disable all interrupts while we muck with
36671 + * the hardware directly
36673 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36675 + /* 15 second delay per the test spec */
36676 + dwc_mdelay(15000);
36678 + /* Drive suspend on the root port */
36680 + dwc_otg_read_hprt0(core_if);
36681 + hprt0.b.prtsusp = 1;
36682 + hprt0.b.prtres = 0;
36683 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36685 + /* 15 second delay per the test spec */
36686 + dwc_mdelay(15000);
36688 + /* Drive resume on the root port */
36690 + dwc_otg_read_hprt0(core_if);
36691 + hprt0.b.prtsusp = 0;
36692 + hprt0.b.prtres = 1;
36693 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36696 + /* Clear the resume bit */
36697 + hprt0.b.prtres = 0;
36698 + DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
36700 + /* Restore interrupts */
36701 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36702 + } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
36703 + /* Save current interrupt mask */
36706 + (&global_regs->gintmsk);
36708 + /* Disable all interrupts while we muck with
36709 + * the hardware directly
36711 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36713 + /* 15 second delay per the test spec */
36714 + dwc_mdelay(15000);
36716 + /* Send the Setup packet */
36719 + /* 15 second delay so nothing else happens for awhile */
36720 + dwc_mdelay(15000);
36722 + /* Restore interrupts */
36723 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36724 + } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
36725 + /* Save current interrupt mask */
36728 + (&global_regs->gintmsk);
36730 + /* Disable all interrupts while we muck with
36731 + * the hardware directly
36733 + DWC_WRITE_REG32(&global_regs->gintmsk, 0);
36735 + /* Send the Setup packet */
36738 + /* 15 second delay so nothing else happens for awhile */
36739 + dwc_mdelay(15000);
36741 + /* Send the In and Ack packets */
36744 + /* 15 second delay so nothing else happens for awhile */
36745 + dwc_mdelay(15000);
36747 + /* Restore interrupts */
36748 + DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
36753 +#endif /* DWC_HS_ELECT_TST */
36755 + case UHF_PORT_INDICATOR:
36756 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
36757 + "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
36758 + /* Not supported */
36761 + retval = -DWC_E_INVALID;
36762 + DWC_ERROR("DWC OTG HCD - "
36763 + "SetPortFeature request %xh "
36764 + "unknown or unsupported\n", wValue);
36768 +#ifdef CONFIG_USB_DWC_OTG_LPM
36769 + case UCR_SET_AND_TEST_PORT_FEATURE:
36770 + if (wValue != UHF_PORT_L1) {
36774 + int portnum, hird, devaddr, remwake;
36775 + glpmcfg_data_t lpmcfg;
36776 + uint32_t time_usecs;
36777 + gintsts_data_t gintsts;
36778 + gintmsk_data_t gintmsk;
36780 + if (!dwc_otg_get_param_lpm_enable(core_if)) {
36783 + if (wValue != UHF_PORT_L1 || wLength != 1) {
36786 + /* Check if the port currently is in SLEEP state */
36788 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36789 + if (lpmcfg.b.prt_sleep_sts) {
36790 + DWC_INFO("Port is already in sleep mode\n");
36791 + buf[0] = 0; /* Return success */
36795 + portnum = wIndex & 0xf;
36796 + hird = (wIndex >> 4) & 0xf;
36797 + devaddr = (wIndex >> 8) & 0x7f;
36798 + remwake = (wIndex >> 15);
36800 + if (portnum != 1) {
36801 + retval = -DWC_E_INVALID;
36803 + ("Wrong port number(%d) in SetandTestPortFeature request\n",
36809 + ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
36810 + portnum, hird, devaddr, remwake);
36811 + /* Disable LPM interrupt */
36813 + gintmsk.b.lpmtranrcvd = 1;
36814 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
36817 + if (dwc_otg_hcd_send_lpm
36818 + (dwc_otg_hcd, devaddr, hird, remwake)) {
36819 + retval = -DWC_E_INVALID;
36823 + time_usecs = 10 * (lpmcfg.b.retry_count + 1);
36824 + /* We will consider timeout if time_usecs microseconds pass,
36825 + * and we don't receive LPM transaction status.
36826 + * After receiving non-error responce(ACK/NYET/STALL) from device,
36827 + * core will set lpmtranrcvd bit.
36831 + DWC_READ_REG32(&core_if->core_global_regs->gintsts);
36832 + if (gintsts.b.lpmtranrcvd) {
36836 + } while (--time_usecs);
36837 + /* lpm_int bit will be cleared in LPM interrupt handler */
36839 + /* Now fill status
36844 + if (!gintsts.b.lpmtranrcvd) {
36845 + buf[0] = 0x3; /* Completion code is Timeout */
36846 + dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
36849 + DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
36850 + if (lpmcfg.b.lpm_resp == 0x3) {
36851 + /* ACK responce from the device */
36852 + buf[0] = 0x00; /* Success */
36853 + } else if (lpmcfg.b.lpm_resp == 0x2) {
36854 + /* NYET responce from the device */
36857 + /* Otherwise responce with Timeout */
36861 + DWC_PRINTF("Device responce to LPM trans is %x\n",
36862 + lpmcfg.b.lpm_resp);
36863 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0,
36868 +#endif /* CONFIG_USB_DWC_OTG_LPM */
36871 + retval = -DWC_E_INVALID;
36872 + DWC_WARN("DWC OTG HCD - "
36873 + "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
36874 + typeReq, wIndex, wValue);
36881 +#ifdef CONFIG_USB_DWC_OTG_LPM
36882 +/** Returns index of host channel to perform LPM transaction. */
36883 +int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
36885 + dwc_otg_core_if_t *core_if = hcd->core_if;
36887 + hcchar_data_t hcchar;
36888 + gintmsk_data_t gintmsk = {.d32 = 0 };
36890 + if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
36891 + DWC_PRINTF("No free channel to select for LPM transaction\n");
36895 + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
36897 + /* Mask host channel interrupts. */
36898 + gintmsk.b.hcintr = 1;
36899 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
36901 + /* Fill fields that core needs for LPM transaction */
36902 + hcchar.b.devaddr = devaddr;
36903 + hcchar.b.epnum = 0;
36904 + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
36905 + hcchar.b.mps = 64;
36906 + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
36907 + hcchar.b.epdir = 0; /* OUT */
36908 + DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
36911 + /* Remove the host channel from the free list. */
36912 + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
36914 + DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
36916 + return hc->hc_num;
36919 +/** Release hc after performing LPM transaction */
36920 +void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
36923 + glpmcfg_data_t lpmcfg;
36926 + lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
36927 + hc_num = lpmcfg.b.lpm_chan_index;
36929 + hc = hcd->hc_ptr_array[hc_num];
36931 + DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
36932 + /* Return host channel to free list */
36933 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
36936 +int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
36937 + uint8_t bRemoteWake)
36939 + glpmcfg_data_t lpmcfg;
36940 + pcgcctl_data_t pcgcctl = {.d32 = 0 };
36943 + channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
36944 + if (channel < 0) {
36948 + pcgcctl.b.enbl_sleep_gating = 1;
36949 + DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
36951 + /* Read LPM config register */
36952 + lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
36954 + /* Program LPM transaction fields */
36955 + lpmcfg.b.rem_wkup_en = bRemoteWake;
36956 + lpmcfg.b.hird = hird;
36957 + lpmcfg.b.hird_thres = 0x1c;
36958 + lpmcfg.b.lpm_chan_index = channel;
36959 + lpmcfg.b.en_utmi_sleep = 1;
36960 + /* Program LPM config register */
36961 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
36963 + /* Send LPM transaction */
36964 + lpmcfg.b.send_lpm = 1;
36965 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
36970 +#endif /* CONFIG_USB_DWC_OTG_LPM */
36972 +int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
36977 + return -DWC_E_INVALID;
36980 + retval = (hcd->flags.b.port_connect_status_change ||
36981 + hcd->flags.b.port_reset_change ||
36982 + hcd->flags.b.port_enable_change ||
36983 + hcd->flags.b.port_suspend_change ||
36984 + hcd->flags.b.port_over_current_change);
36987 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
36988 + " Root port status changed\n");
36989 + DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n",
36990 + hcd->flags.b.port_connect_status_change);
36991 + DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n",
36992 + hcd->flags.b.port_reset_change);
36993 + DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n",
36994 + hcd->flags.b.port_enable_change);
36995 + DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n",
36996 + hcd->flags.b.port_suspend_change);
36997 + DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n",
36998 + hcd->flags.b.port_over_current_change);
37004 +int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
37006 + hfnum_data_t hfnum;
37008 + DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
37012 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
37015 + return hfnum.b.frnum;
37018 +int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
37019 + struct dwc_otg_hcd_function_ops *fops)
37023 + hcd->fops = fops;
37024 + if (!dwc_otg_is_device_mode(hcd->core_if) &&
37025 + (!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) {
37026 + dwc_otg_hcd_reinit(hcd);
37028 + retval = -DWC_E_NO_DEVICE;
37034 +void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
37036 + return hcd->priv;
37039 +void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
37041 + hcd->priv = priv_data;
37044 +uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
37046 + return hcd->otg_port;
37049 +uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
37051 + uint32_t is_b_host;
37052 + if (hcd->core_if->op_state == B_HOST) {
37058 + return is_b_host;
37061 +dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
37062 + int iso_desc_count, int atomic_alloc)
37064 + dwc_otg_hcd_urb_t *dwc_otg_urb;
37068 + sizeof(*dwc_otg_urb) +
37069 + iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
37070 + if (atomic_alloc)
37071 + dwc_otg_urb = DWC_ALLOC_ATOMIC(size);
37073 + dwc_otg_urb = DWC_ALLOC(size);
37075 + if (NULL != dwc_otg_urb)
37076 + dwc_otg_urb->packet_count = iso_desc_count;
37078 + dwc_otg_urb->packet_count = 0;
37080 + DWC_ERROR("**** DWC OTG HCD URB alloc - "
37081 + "%salloc of %db failed\n",
37082 + atomic_alloc?"atomic ":"", size);
37086 + return dwc_otg_urb;
37089 +void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
37090 + uint8_t dev_addr, uint8_t ep_num,
37091 + uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
37093 + dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
37094 + ep_type, ep_dir, mps);
37097 + ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
37098 + dev_addr, ep_num, ep_dir, ep_type, mps);
37102 +void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
37103 + void *urb_handle, void *buf, dwc_dma_t dma,
37104 + uint32_t buflen, void *setup_packet,
37105 + dwc_dma_t setup_dma, uint32_t flags,
37106 + uint16_t interval)
37108 + dwc_otg_urb->priv = urb_handle;
37109 + dwc_otg_urb->buf = buf;
37110 + dwc_otg_urb->dma = dma;
37111 + dwc_otg_urb->length = buflen;
37112 + dwc_otg_urb->setup_packet = setup_packet;
37113 + dwc_otg_urb->setup_dma = setup_dma;
37114 + dwc_otg_urb->flags = flags;
37115 + dwc_otg_urb->interval = interval;
37116 + dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
37119 +uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
37121 + return dwc_otg_urb->status;
37124 +uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
37126 + return dwc_otg_urb->actual_length;
37129 +uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
37131 + return dwc_otg_urb->error_count;
37134 +void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
37135 + int desc_num, uint32_t offset,
37138 + dwc_otg_urb->iso_descs[desc_num].offset = offset;
37139 + dwc_otg_urb->iso_descs[desc_num].length = length;
37142 +uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
37145 + return dwc_otg_urb->iso_descs[desc_num].status;
37148 +uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
37149 + dwc_otg_urb, int desc_num)
37151 + return dwc_otg_urb->iso_descs[desc_num].actual_length;
37154 +int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
37156 + int allocated = 0;
37157 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
37160 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
37164 + return allocated;
37167 +int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
37169 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
37171 + DWC_ASSERT(qh, "qh is not allocated\n");
37173 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
37180 +uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
37182 + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
37183 + DWC_ASSERT(qh, "qh is not allocated\n");
37184 + return qh->usecs;
37187 +void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
37190 + int num_channels;
37192 + gnptxsts_data_t np_tx_status;
37193 + hptxsts_data_t p_tx_status;
37195 + num_channels = hcd->core_if->core_params->host_channels;
37196 + DWC_PRINTF("\n");
37198 + ("************************************************************\n");
37199 + DWC_PRINTF("HCD State:\n");
37200 + DWC_PRINTF(" Num channels: %d\n", num_channels);
37201 + for (i = 0; i < num_channels; i++) {
37202 + dwc_hc_t *hc = hcd->hc_ptr_array[i];
37203 + DWC_PRINTF(" Channel %d:\n", i);
37204 + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
37205 + hc->dev_addr, hc->ep_num, hc->ep_is_in);
37206 + DWC_PRINTF(" speed: %d\n", hc->speed);
37207 + DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
37208 + DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
37209 + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
37210 + DWC_PRINTF(" multi_count: %d\n", hc->multi_count);
37211 + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
37212 + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
37213 + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
37214 + DWC_PRINTF(" xfer_count: %d\n", hc->xfer_count);
37215 + DWC_PRINTF(" halt_on_queue: %d\n", hc->halt_on_queue);
37216 + DWC_PRINTF(" halt_pending: %d\n", hc->halt_pending);
37217 + DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
37218 + DWC_PRINTF(" do_split: %d\n", hc->do_split);
37219 + DWC_PRINTF(" complete_split: %d\n", hc->complete_split);
37220 + DWC_PRINTF(" hub_addr: %d\n", hc->hub_addr);
37221 + DWC_PRINTF(" port_addr: %d\n", hc->port_addr);
37222 + DWC_PRINTF(" xact_pos: %d\n", hc->xact_pos);
37223 + DWC_PRINTF(" requests: %d\n", hc->requests);
37224 + DWC_PRINTF(" qh: %p\n", hc->qh);
37225 + if (hc->xfer_started) {
37226 + hfnum_data_t hfnum;
37227 + hcchar_data_t hcchar;
37228 + hctsiz_data_t hctsiz;
37229 + hcint_data_t hcint;
37230 + hcintmsk_data_t hcintmsk;
37232 + DWC_READ_REG32(&hcd->core_if->
37233 + host_if->host_global_regs->hfnum);
37235 + DWC_READ_REG32(&hcd->core_if->host_if->
37236 + hc_regs[i]->hcchar);
37238 + DWC_READ_REG32(&hcd->core_if->host_if->
37239 + hc_regs[i]->hctsiz);
37241 + DWC_READ_REG32(&hcd->core_if->host_if->
37242 + hc_regs[i]->hcint);
37244 + DWC_READ_REG32(&hcd->core_if->host_if->
37245 + hc_regs[i]->hcintmsk);
37246 + DWC_PRINTF(" hfnum: 0x%08x\n", hfnum.d32);
37247 + DWC_PRINTF(" hcchar: 0x%08x\n", hcchar.d32);
37248 + DWC_PRINTF(" hctsiz: 0x%08x\n", hctsiz.d32);
37249 + DWC_PRINTF(" hcint: 0x%08x\n", hcint.d32);
37250 + DWC_PRINTF(" hcintmsk: 0x%08x\n", hcintmsk.d32);
37252 + if (hc->xfer_started && hc->qh) {
37253 + dwc_otg_qtd_t *qtd;
37254 + dwc_otg_hcd_urb_t *urb;
37256 + DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
37257 + if (!qtd->in_process)
37261 + DWC_PRINTF(" URB Info:\n");
37262 + DWC_PRINTF(" qtd: %p, urb: %p\n", qtd, urb);
37264 + DWC_PRINTF(" Dev: %d, EP: %d %s\n",
37265 + dwc_otg_hcd_get_dev_addr(&urb->
37267 + dwc_otg_hcd_get_ep_num(&urb->
37269 + dwc_otg_hcd_is_pipe_in(&urb->
37272 + DWC_PRINTF(" Max packet size: %d\n",
37273 + dwc_otg_hcd_get_mps(&urb->
37275 + DWC_PRINTF(" transfer_buffer: %p\n",
37277 + DWC_PRINTF(" transfer_dma: %p\n",
37278 + (void *)urb->dma);
37279 + DWC_PRINTF(" transfer_buffer_length: %d\n",
37281 + DWC_PRINTF(" actual_length: %d\n",
37282 + urb->actual_length);
37287 + DWC_PRINTF(" non_periodic_channels: %d\n", hcd->non_periodic_channels);
37288 + DWC_PRINTF(" periodic_channels: %d\n", hcd->periodic_channels);
37289 + DWC_PRINTF(" periodic_usecs: %d\n", hcd->periodic_usecs);
37290 + np_tx_status.d32 =
37291 + DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts);
37292 + DWC_PRINTF(" NP Tx Req Queue Space Avail: %d\n",
37293 + np_tx_status.b.nptxqspcavail);
37294 + DWC_PRINTF(" NP Tx FIFO Space Avail: %d\n",
37295 + np_tx_status.b.nptxfspcavail);
37296 + p_tx_status.d32 =
37297 + DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts);
37298 + DWC_PRINTF(" P Tx Req Queue Space Avail: %d\n",
37299 + p_tx_status.b.ptxqspcavail);
37300 + DWC_PRINTF(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
37301 + dwc_otg_hcd_dump_frrem(hcd);
37302 + dwc_otg_dump_global_registers(hcd->core_if);
37303 + dwc_otg_dump_host_registers(hcd->core_if);
37305 + ("************************************************************\n");
37306 + DWC_PRINTF("\n");
37311 +void dwc_print_setup_data(uint8_t * setup)
37314 + if (CHK_DEBUG_LEVEL(DBG_HCD)) {
37315 + DWC_PRINTF("Setup Data = MSB ");
37316 + for (i = 7; i >= 0; i--)
37317 + DWC_PRINTF("%02x ", setup[i]);
37318 + DWC_PRINTF("\n");
37319 + DWC_PRINTF(" bmRequestType Tranfer = %s\n",
37320 + (setup[0] & 0x80) ? "Device-to-Host" :
37321 + "Host-to-Device");
37322 + DWC_PRINTF(" bmRequestType Type = ");
37323 + switch ((setup[0] & 0x60) >> 5) {
37325 + DWC_PRINTF("Standard\n");
37328 + DWC_PRINTF("Class\n");
37331 + DWC_PRINTF("Vendor\n");
37334 + DWC_PRINTF("Reserved\n");
37337 + DWC_PRINTF(" bmRequestType Recipient = ");
37338 + switch (setup[0] & 0x1f) {
37340 + DWC_PRINTF("Device\n");
37343 + DWC_PRINTF("Interface\n");
37346 + DWC_PRINTF("Endpoint\n");
37349 + DWC_PRINTF("Other\n");
37352 + DWC_PRINTF("Reserved\n");
37355 + DWC_PRINTF(" bRequest = 0x%0x\n", setup[1]);
37356 + DWC_PRINTF(" wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
37357 + DWC_PRINTF(" wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
37358 + DWC_PRINTF(" wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
37363 +void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
37366 + DWC_PRINTF("Frame remaining at SOF:\n");
37367 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37368 + hcd->frrem_samples, hcd->frrem_accum,
37369 + (hcd->frrem_samples > 0) ?
37370 + hcd->frrem_accum / hcd->frrem_samples : 0);
37372 + DWC_PRINTF("\n");
37373 + DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
37374 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37375 + hcd->core_if->hfnum_7_samples,
37376 + hcd->core_if->hfnum_7_frrem_accum,
37377 + (hcd->core_if->hfnum_7_samples >
37378 + 0) ? hcd->core_if->hfnum_7_frrem_accum /
37379 + hcd->core_if->hfnum_7_samples : 0);
37380 + DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
37381 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37382 + hcd->core_if->hfnum_0_samples,
37383 + hcd->core_if->hfnum_0_frrem_accum,
37384 + (hcd->core_if->hfnum_0_samples >
37385 + 0) ? hcd->core_if->hfnum_0_frrem_accum /
37386 + hcd->core_if->hfnum_0_samples : 0);
37387 + DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
37388 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37389 + hcd->core_if->hfnum_other_samples,
37390 + hcd->core_if->hfnum_other_frrem_accum,
37391 + (hcd->core_if->hfnum_other_samples >
37392 + 0) ? hcd->core_if->hfnum_other_frrem_accum /
37393 + hcd->core_if->hfnum_other_samples : 0);
37395 + DWC_PRINTF("\n");
37396 + DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
37397 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37398 + hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
37399 + (hcd->hfnum_7_samples_a > 0) ?
37400 + hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
37401 + DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
37402 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37403 + hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
37404 + (hcd->hfnum_0_samples_a > 0) ?
37405 + hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
37406 + DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
37407 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37408 + hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
37409 + (hcd->hfnum_other_samples_a > 0) ?
37410 + hcd->hfnum_other_frrem_accum_a /
37411 + hcd->hfnum_other_samples_a : 0);
37413 + DWC_PRINTF("\n");
37414 + DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
37415 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37416 + hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
37417 + (hcd->hfnum_7_samples_b > 0) ?
37418 + hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
37419 + DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
37420 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37421 + hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
37422 + (hcd->hfnum_0_samples_b > 0) ?
37423 + hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
37424 + DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
37425 + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
37426 + hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
37427 + (hcd->hfnum_other_samples_b > 0) ?
37428 + hcd->hfnum_other_frrem_accum_b /
37429 + hcd->hfnum_other_samples_b : 0);
37433 +#endif /* DWC_DEVICE_ONLY */
37434 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
37435 new file mode 100644
37436 index 0000000..8075595
37438 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
37440 +/* ==========================================================================
37441 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $
37442 + * $Revision: #58 $
37443 + * $Date: 2011/09/15 $
37444 + * $Change: 1846647 $
37446 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
37447 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
37448 + * otherwise expressly agreed to in writing between Synopsys and you.
37450 + * The Software IS NOT an item of Licensed Software or Licensed Product under
37451 + * any End User Software License Agreement or Agreement for Licensed Product
37452 + * with Synopsys or any supplement thereto. You are permitted to use and
37453 + * redistribute this Software in source and binary forms, with or without
37454 + * modification, provided that redistributions of source code must retain this
37455 + * notice. You may not view, use, disclose, copy or distribute this file or
37456 + * any information contained herein except pursuant to this license grant from
37457 + * Synopsys. If you do not agree with this notice, including the disclaimer
37458 + * below, then you are not authorized to use the Software.
37460 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
37461 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37462 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37463 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
37464 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37465 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37466 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37467 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37468 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37469 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
37471 + * ========================================================================== */
37472 +#ifndef DWC_DEVICE_ONLY
37473 +#ifndef __DWC_HCD_H__
37474 +#define __DWC_HCD_H__
37476 +#include "dwc_otg_os_dep.h"
37478 +#include "dwc_otg_hcd_if.h"
37479 +#include "dwc_otg_core_if.h"
37480 +#include "dwc_list.h"
37481 +#include "dwc_otg_cil.h"
37486 + * This file contains the structures, constants, and interfaces for
37487 + * the Host Contoller Driver (HCD).
37489 + * The Host Controller Driver (HCD) is responsible for translating requests
37490 + * from the USB Driver into the appropriate actions on the DWC_otg controller.
37491 + * It isolates the USBD from the specifics of the controller by providing an
37492 + * API to the USBD.
37495 +struct dwc_otg_hcd_pipe_info {
37496 + uint8_t dev_addr;
37498 + uint8_t pipe_type;
37499 + uint8_t pipe_dir;
37503 +struct dwc_otg_hcd_iso_packet_desc {
37506 + uint32_t actual_length;
37510 +struct dwc_otg_qtd;
37512 +struct dwc_otg_hcd_urb {
37514 + struct dwc_otg_qtd *qtd;
37517 + void *setup_packet;
37518 + dwc_dma_t setup_dma;
37520 + uint32_t actual_length;
37522 + uint32_t error_count;
37523 + uint32_t packet_count;
37525 + uint16_t interval;
37526 + struct dwc_otg_hcd_pipe_info pipe_info;
37527 + struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
37530 +static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
37532 + return pipe->ep_num;
37535 +static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info
37538 + return pipe->pipe_type;
37541 +static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe)
37543 + return pipe->mps;
37546 +static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info
37549 + return pipe->dev_addr;
37552 +static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info
37555 + return (pipe->pipe_type == UE_ISOCHRONOUS);
37558 +static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info
37561 + return (pipe->pipe_type == UE_INTERRUPT);
37564 +static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info
37567 + return (pipe->pipe_type == UE_BULK);
37570 +static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info
37573 + return (pipe->pipe_type == UE_CONTROL);
37576 +static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe)
37578 + return (pipe->pipe_dir == UE_DIR_IN);
37581 +static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info
37584 + return (!dwc_otg_hcd_is_pipe_in(pipe));
37587 +static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe,
37588 + uint8_t devaddr, uint8_t ep_num,
37589 + uint8_t pipe_type, uint8_t pipe_dir,
37592 + pipe->dev_addr = devaddr;
37593 + pipe->ep_num = ep_num;
37594 + pipe->pipe_type = pipe_type;
37595 + pipe->pipe_dir = pipe_dir;
37600 + * Phases for control transfers.
37602 +typedef enum dwc_otg_control_phase {
37603 + DWC_OTG_CONTROL_SETUP,
37604 + DWC_OTG_CONTROL_DATA,
37605 + DWC_OTG_CONTROL_STATUS
37606 +} dwc_otg_control_phase_e;
37608 +/** Transaction types. */
37609 +typedef enum dwc_otg_transaction_type {
37610 + DWC_OTG_TRANSACTION_NONE,
37611 + DWC_OTG_TRANSACTION_PERIODIC,
37612 + DWC_OTG_TRANSACTION_NON_PERIODIC,
37613 + DWC_OTG_TRANSACTION_ALL
37614 +} dwc_otg_transaction_type_e;
37616 +struct dwc_otg_qh;
37619 + * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
37620 + * interrupt, or isochronous transfer. A single QTD is created for each URB
37621 + * (of one of these types) submitted to the HCD. The transfer associated with
37622 + * a QTD may require one or multiple transactions.
37624 + * A QTD is linked to a Queue Head, which is entered in either the
37625 + * non-periodic or periodic schedule for execution. When a QTD is chosen for
37626 + * execution, some or all of its transactions may be executed. After
37627 + * execution, the state of the QTD is updated. The QTD may be retired if all
37628 + * its transactions are complete or if an error occurred. Otherwise, it
37629 + * remains in the schedule so more transactions can be executed later.
37631 +typedef struct dwc_otg_qtd {
37633 + * Determines the PID of the next data packet for the data phase of
37634 + * control transfers. Ignored for other transfer types.<br>
37635 + * One of the following values:
37636 + * - DWC_OTG_HC_PID_DATA0
37637 + * - DWC_OTG_HC_PID_DATA1
37639 + uint8_t data_toggle;
37641 + /** Current phase for control transfers (Setup, Data, or Status). */
37642 + dwc_otg_control_phase_e control_phase;
37644 + /** Keep track of the current split type
37645 + * for FS/LS endpoints on a HS Hub */
37646 + uint8_t complete_split;
37648 + /** How many bytes transferred during SSPLIT OUT */
37649 + uint32_t ssplit_out_xfer_count;
37652 + * Holds the number of bus errors that have occurred for a transaction
37653 + * within this transfer.
37655 + uint8_t error_count;
37658 + * Index of the next frame descriptor for an isochronous transfer. A
37659 + * frame descriptor describes the buffer position and length of the
37660 + * data to be transferred in the next scheduled (micro)frame of an
37661 + * isochronous transfer. It also holds status for that transaction.
37662 + * The frame index starts at 0.
37664 + uint16_t isoc_frame_index;
37666 + /** Position of the ISOC split on full/low speed */
37667 + uint8_t isoc_split_pos;
37669 + /** Position of the ISOC split in the buffer for the current frame */
37670 + uint16_t isoc_split_offset;
37672 + /** URB for this transfer */
37673 + struct dwc_otg_hcd_urb *urb;
37675 + struct dwc_otg_qh *qh;
37677 + /** This list of QTDs */
37678 + DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry;
37680 + /** Indicates if this QTD is currently processed by HW. */
37681 + uint8_t in_process;
37683 + /** Number of DMA descriptors for this QTD */
37687 + * Last activated frame(packet) index.
37688 + * Used in Descriptor DMA mode only.
37690 + uint16_t isoc_frame_index_last;
37694 +DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd);
37697 + * A Queue Head (QH) holds the static characteristics of an endpoint and
37698 + * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
37699 + * be entered in either the non-periodic or periodic schedule.
37701 +typedef struct dwc_otg_qh {
37704 + * One of the following values:
37708 + * - UE_ISOCHRONOUS
37711 + uint8_t ep_is_in;
37713 + /** wMaxPacketSize Field of Endpoint Descriptor. */
37718 + * One of the following values:
37719 + * - DWC_OTG_EP_SPEED_LOW
37720 + * - DWC_OTG_EP_SPEED_FULL
37721 + * - DWC_OTG_EP_SPEED_HIGH
37723 + uint8_t dev_speed;
37726 + * Determines the PID of the next data packet for non-control
37727 + * transfers. Ignored for control transfers.<br>
37728 + * One of the following values:
37729 + * - DWC_OTG_HC_PID_DATA0
37730 + * - DWC_OTG_HC_PID_DATA1
37732 + uint8_t data_toggle;
37734 + /** Ping state if 1. */
37735 + uint8_t ping_state;
37738 + * List of QTDs for this QH.
37740 + struct dwc_otg_qtd_list qtd_list;
37742 + /** Host channel currently processing transfers for this QH. */
37743 + struct dwc_hc *channel;
37745 + /** Full/low speed endpoint on high-speed hub requires split. */
37746 + uint8_t do_split;
37748 + /** @name Periodic schedule information */
37751 + /** Bandwidth in microseconds per (micro)frame. */
37754 + /** Interval between transfers in (micro)frames. */
37755 + uint16_t interval;
37758 + * (micro)frame to initialize a periodic transfer. The transfer
37759 + * executes in the following (micro)frame.
37761 + uint16_t sched_frame;
37763 + /** (micro)frame at which last start split was initialized. */
37764 + uint16_t start_split_frame;
37769 + * Used instead of original buffer if
37770 + * it(physical address) is not dword-aligned.
37772 + uint8_t *dw_align_buf;
37773 + dwc_dma_t dw_align_buf_dma;
37775 + /** Entry for QH in either the periodic or non-periodic schedule. */
37776 + dwc_list_link_t qh_list_entry;
37778 + /** @name Descriptor DMA support */
37781 + /** Descriptor List. */
37782 + dwc_otg_host_dma_desc_t *desc_list;
37784 + /** Descriptor List physical address. */
37785 + dwc_dma_t desc_list_dma;
37788 + * Xfer Bytes array.
37789 + * Each element corresponds to a descriptor and indicates
37790 + * original XferSize size value for the descriptor.
37792 + uint32_t *n_bytes;
37794 + /** Actual number of transfer descriptors in a list. */
37797 + /** First activated isochronous transfer descriptor index. */
37798 + uint8_t td_first;
37799 + /** Last activated isochronous transfer descriptor index. */
37806 + uint16_t frame_usecs[8];
37809 +DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
37812 + * This structure holds the state of the HCD, including the non-periodic and
37813 + * periodic schedules.
37815 +struct dwc_otg_hcd {
37816 + /** The DWC otg device pointer */
37817 + struct dwc_otg_device *otg_dev;
37818 + /** DWC OTG Core Interface Layer */
37819 + dwc_otg_core_if_t *core_if;
37821 + /** Function HCD driver callbacks */
37822 + struct dwc_otg_hcd_function_ops *fops;
37824 + /** Internal DWC HCD Flags */
37825 + volatile union dwc_otg_hcd_internal_flags {
37828 + unsigned port_connect_status_change:1;
37829 + unsigned port_connect_status:1;
37830 + unsigned port_reset_change:1;
37831 + unsigned port_enable_change:1;
37832 + unsigned port_suspend_change:1;
37833 + unsigned port_over_current_change:1;
37834 + unsigned port_l1_change:1;
37835 + unsigned reserved:26;
37840 + * Inactive items in the non-periodic schedule. This is a list of
37841 + * Queue Heads. Transfers associated with these Queue Heads are not
37842 + * currently assigned to a host channel.
37844 + dwc_list_link_t non_periodic_sched_inactive;
37847 + * Active items in the non-periodic schedule. This is a list of
37848 + * Queue Heads. Transfers associated with these Queue Heads are
37849 + * currently assigned to a host channel.
37851 + dwc_list_link_t non_periodic_sched_active;
37854 + * Pointer to the next Queue Head to process in the active
37855 + * non-periodic schedule.
37857 + dwc_list_link_t *non_periodic_qh_ptr;
37860 + * Inactive items in the periodic schedule. This is a list of QHs for
37861 + * periodic transfers that are _not_ scheduled for the next frame.
37862 + * Each QH in the list has an interval counter that determines when it
37863 + * needs to be scheduled for execution. This scheduling mechanism
37864 + * allows only a simple calculation for periodic bandwidth used (i.e.
37865 + * must assume that all periodic transfers may need to execute in the
37866 + * same frame). However, it greatly simplifies scheduling and should
37867 + * be sufficient for the vast majority of OTG hosts, which need to
37868 + * connect to a small number of peripherals at one time.
37870 + * Items move from this list to periodic_sched_ready when the QH
37871 + * interval counter is 0 at SOF.
37873 + dwc_list_link_t periodic_sched_inactive;
37876 + * List of periodic QHs that are ready for execution in the next
37877 + * frame, but have not yet been assigned to host channels.
37879 + * Items move from this list to periodic_sched_assigned as host
37880 + * channels become available during the current frame.
37882 + dwc_list_link_t periodic_sched_ready;
37885 + * List of periodic QHs to be executed in the next frame that are
37886 + * assigned to host channels.
37888 + * Items move from this list to periodic_sched_queued as the
37889 + * transactions for the QH are queued to the DWC_otg controller.
37891 + dwc_list_link_t periodic_sched_assigned;
37894 + * List of periodic QHs that have been queued for execution.
37896 + * Items move from this list to either periodic_sched_inactive or
37897 + * periodic_sched_ready when the channel associated with the transfer
37898 + * is released. If the interval for the QH is 1, the item moves to
37899 + * periodic_sched_ready because it must be rescheduled for the next
37900 + * frame. Otherwise, the item moves to periodic_sched_inactive.
37902 + dwc_list_link_t periodic_sched_queued;
37905 + * Total bandwidth claimed so far for periodic transfers. This value
37906 + * is in microseconds per (micro)frame. The assumption is that all
37907 + * periodic transfers may occur in the same (micro)frame.
37909 + uint16_t periodic_usecs;
37912 + * Total bandwidth claimed so far for all periodic transfers
37914 + * This will include a mixture of HS and FS transfers.
37915 + * Units are microseconds per (micro)frame.
37916 + * We have a budget per frame and have to schedule
37917 + * transactions accordingly.
37918 + * Watch out for the fact that things are actually scheduled for the
37921 + uint16_t frame_usecs[8];
37925 + * Frame number read from the core at SOF. The value ranges from 0 to
37926 + * DWC_HFNUM_MAX_FRNUM.
37928 + uint16_t frame_number;
37931 + * Count of periodic QHs, if using several eps. For SOF enable/disable.
37933 + uint16_t periodic_qh_count;
37936 + * Free host channels in the controller. This is a list of
37937 + * dwc_hc_t items.
37939 + struct hc_list free_hc_list;
37941 + * Number of host channels assigned to periodic transfers. Currently
37942 + * assuming that there is a dedicated host channel for each periodic
37943 + * transaction and at least one host channel available for
37944 + * non-periodic transactions.
37946 + int periodic_channels; /* microframe_schedule==0 */
37949 + * Number of host channels assigned to non-periodic transfers.
37951 + int non_periodic_channels; /* microframe_schedule==0 */
37954 + * Number of host channels assigned to non-periodic transfers.
37956 + int available_host_channels;
37959 + * Array of pointers to the host channel descriptors. Allows accessing
37960 + * a host channel descriptor given the host channel number. This is
37961 + * useful in interrupt handlers.
37963 + struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
37966 + * Buffer to use for any data received during the status phase of a
37967 + * control transfer. Normally no data is transferred during the status
37968 + * phase. This buffer is used as a bit bucket.
37970 + uint8_t *status_buf;
37973 + * DMA address for status_buf.
37975 + dma_addr_t status_buf_dma;
37976 +#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
37979 + * Connection timer. An OTG host must display a message if the device
37980 + * does not connect. Started when the VBus power is turned on via
37981 + * sysfs attribute "buspower".
37983 + dwc_timer_t *conn_timer;
37985 + /* Tasket to do a reset */
37986 + dwc_tasklet_t *reset_tasklet;
37989 + dwc_spinlock_t *lock;
37992 + * Private data that could be used by OS wrapper.
37996 + uint8_t otg_port;
37998 + /** Frame List */
37999 + uint32_t *frame_list;
38001 + /** Frame List DMA address */
38002 + dma_addr_t frame_list_dma;
38005 + uint32_t frrem_samples;
38006 + uint64_t frrem_accum;
38008 + uint32_t hfnum_7_samples_a;
38009 + uint64_t hfnum_7_frrem_accum_a;
38010 + uint32_t hfnum_0_samples_a;
38011 + uint64_t hfnum_0_frrem_accum_a;
38012 + uint32_t hfnum_other_samples_a;
38013 + uint64_t hfnum_other_frrem_accum_a;
38015 + uint32_t hfnum_7_samples_b;
38016 + uint64_t hfnum_7_frrem_accum_b;
38017 + uint32_t hfnum_0_samples_b;
38018 + uint64_t hfnum_0_frrem_accum_b;
38019 + uint32_t hfnum_other_samples_b;
38020 + uint64_t hfnum_other_frrem_accum_b;
38024 +/** @name Transaction Execution Functions */
38026 +extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
38028 +extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
38029 + dwc_otg_transaction_type_e tr_type);
38033 +/** @name Interrupt Handler Functions */
38035 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38036 +extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38037 +extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t *
38039 +extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t *
38041 +extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t *
38043 +extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *
38045 +extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38046 +extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t *
38048 +extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38049 +extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38050 +extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd,
38052 +extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd);
38053 +extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t *
38057 +/** @name Schedule Queue Functions */
38060 +/* Implemented in dwc_otg_hcd_queue.c */
38061 +extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
38062 + dwc_otg_hcd_urb_t * urb, int atomic_alloc);
38063 +extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38064 +extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38065 +extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38066 +extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
38067 + int sched_csplit);
38069 +/** Remove and free a QH */
38070 +static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd,
38071 + dwc_otg_qh_t * qh)
38073 + dwc_irqflags_t flags;
38074 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
38075 + dwc_otg_hcd_qh_remove(hcd, qh);
38076 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
38077 + dwc_otg_hcd_qh_free(hcd, qh);
38080 +/** Allocates memory for a QH structure.
38081 + * @return Returns the memory allocate or NULL on error. */
38082 +static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(int atomic_alloc)
38084 + if (atomic_alloc)
38085 + return (dwc_otg_qh_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qh_t));
38087 + return (dwc_otg_qh_t *) DWC_ALLOC(sizeof(dwc_otg_qh_t));
38090 +extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb,
38091 + int atomic_alloc);
38092 +extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb);
38093 +extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd,
38094 + dwc_otg_qh_t ** qh, int atomic_alloc);
38096 +/** Allocates memory for a QTD structure.
38097 + * @return Returns the memory allocate or NULL on error. */
38098 +static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(int atomic_alloc)
38100 + if (atomic_alloc)
38101 + return (dwc_otg_qtd_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qtd_t));
38103 + return (dwc_otg_qtd_t *) DWC_ALLOC(sizeof(dwc_otg_qtd_t));
38106 +/** Frees the memory for a QTD structure. QTD should already be removed from
38108 + * @param qtd QTD to free.*/
38109 +static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd)
38114 +/** Removes a QTD from list.
38115 + * @param hcd HCD instance.
38116 + * @param qtd QTD to remove from list.
38117 + * @param qh QTD belongs to.
38119 +static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd,
38120 + dwc_otg_qtd_t * qtd,
38121 + dwc_otg_qh_t * qh)
38123 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
38126 +/** Remove and free a QTD
38127 + * Need to disable IRQ and hold hcd lock while calling this function out of
38128 + * interrupt servicing chain */
38129 +static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd,
38130 + dwc_otg_qtd_t * qtd,
38131 + dwc_otg_qh_t * qh)
38133 + dwc_otg_hcd_qtd_remove(hcd, qtd, qh);
38134 + dwc_otg_hcd_qtd_free(qtd);
38139 +/** @name Descriptor DMA Supporting Functions */
38142 +extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38143 +extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
38145 + dwc_otg_hc_regs_t * hc_regs,
38146 + dwc_otg_halt_status_e halt_status);
38148 +extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38149 +extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
38153 +/** @name Internal Functions */
38155 +dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb);
38158 +#ifdef CONFIG_USB_DWC_OTG_LPM
38159 +extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd,
38160 + uint8_t devaddr);
38161 +extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd);
38164 +/** Gets the QH that contains the list_head */
38165 +#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
38167 +/** Gets the QTD that contains the list_head */
38168 +#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
38170 +/** Check if QH is non-periodic */
38171 +#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \
38172 + (_qh_ptr_->ep_type == UE_CONTROL))
38174 +/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
38175 +#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
38177 +/** Packet size for any kind of endpoint descriptor */
38178 +#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
38181 + * Returns true if _frame1 is less than or equal to _frame2. The comparison is
38182 + * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
38183 + * frame number when the max frame number is reached.
38185 +static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
38187 + return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
38188 + (DWC_HFNUM_MAX_FRNUM >> 1);
38192 + * Returns true if _frame1 is greater than _frame2. The comparison is done
38193 + * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
38194 + * number when the max frame number is reached.
38196 +static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
38198 + return (frame1 != frame2) &&
38199 + (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
38200 + (DWC_HFNUM_MAX_FRNUM >> 1));
38204 + * Increments _frame by the amount specified by _inc. The addition is done
38205 + * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
38207 +static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
38209 + return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
38212 +static inline uint16_t dwc_full_frame_num(uint16_t frame)
38214 + return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
38217 +static inline uint16_t dwc_micro_frame_num(uint16_t frame)
38219 + return frame & 0x7;
38222 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
38223 + dwc_otg_hc_regs_t * hc_regs,
38224 + dwc_otg_qtd_t * qtd);
38228 + * Macro to sample the remaining PHY clocks left in the current frame. This
38229 + * may be used during debugging to determine the average time it takes to
38230 + * execute sections of code. There are two possible sample points, "a" and
38231 + * "b", so the _letter argument must be one of these values.
38233 + * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
38234 + * example, "cat /sys/devices/lm0/hcd_frrem".
38236 +#define dwc_sample_frrem(_hcd, _qh, _letter) \
38238 + hfnum_data_t hfnum; \
38239 + dwc_otg_qtd_t *qtd; \
38240 + qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
38241 + if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
38242 + hfnum.d32 = DWC_READ_REG32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
38243 + switch (hfnum.b.frnum & 0x7) { \
38245 + _hcd->hfnum_7_samples_##_letter++; \
38246 + _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
38249 + _hcd->hfnum_0_samples_##_letter++; \
38250 + _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
38253 + _hcd->hfnum_other_samples_##_letter++; \
38254 + _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
38260 +#define dwc_sample_frrem(_hcd, _qh, _letter)
38263 +#endif /* DWC_DEVICE_ONLY */
38264 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
38265 new file mode 100644
38266 index 0000000..d0d5fa1
38268 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
38270 +/*==========================================================================
38271 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
38272 + * $Revision: #10 $
38273 + * $Date: 2011/10/20 $
38274 + * $Change: 1869464 $
38276 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
38277 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
38278 + * otherwise expressly agreed to in writing between Synopsys and you.
38280 + * The Software IS NOT an item of Licensed Software or Licensed Product under
38281 + * any End User Software License Agreement or Agreement for Licensed Product
38282 + * with Synopsys or any supplement thereto. You are permitted to use and
38283 + * redistribute this Software in source and binary forms, with or without
38284 + * modification, provided that redistributions of source code must retain this
38285 + * notice. You may not view, use, disclose, copy or distribute this file or
38286 + * any information contained herein except pursuant to this license grant from
38287 + * Synopsys. If you do not agree with this notice, including the disclaimer
38288 + * below, then you are not authorized to use the Software.
38290 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
38291 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38292 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38293 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
38294 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38295 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
38296 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38297 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38298 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38299 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38301 + * ========================================================================== */
38302 +#ifndef DWC_DEVICE_ONLY
38305 + * This file contains Descriptor DMA support implementation for host mode.
38308 +#include "dwc_otg_hcd.h"
38309 +#include "dwc_otg_regs.h"
38311 +extern bool microframe_schedule;
38313 +static inline uint8_t frame_list_idx(uint16_t frame)
38315 + return (frame & (MAX_FRLIST_EN_NUM - 1));
38318 +static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
38320 + return (idx + inc) &
38322 + DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
38323 + MAX_DMA_DESC_NUM_GENERIC) - 1);
38326 +static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
38328 + return (idx - inc) &
38330 + DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
38331 + MAX_DMA_DESC_NUM_GENERIC) - 1);
38334 +static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
38336 + return (((qh->ep_type == UE_ISOCHRONOUS)
38337 + && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH))
38338 + ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC);
38340 +static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
38342 + return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)
38343 + ? ((qh->interval + 8 - 1) / 8)
38347 +static int desc_list_alloc(dwc_otg_qh_t * qh)
38351 + qh->desc_list = (dwc_otg_host_dma_desc_t *)
38352 + DWC_DMA_ALLOC(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
38353 + &qh->desc_list_dma);
38355 + if (!qh->desc_list) {
38356 + retval = -DWC_E_NO_MEMORY;
38357 + DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
38361 + dwc_memset(qh->desc_list, 0x00,
38362 + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
38365 + (uint32_t *) DWC_ALLOC(sizeof(uint32_t) * max_desc_num(qh));
38367 + if (!qh->n_bytes) {
38368 + retval = -DWC_E_NO_MEMORY;
38370 + ("%s: Failed to allocate array for descriptors' size actual values\n",
38378 +static void desc_list_free(dwc_otg_qh_t * qh)
38380 + if (qh->desc_list) {
38381 + DWC_DMA_FREE(max_desc_num(qh), qh->desc_list,
38382 + qh->desc_list_dma);
38383 + qh->desc_list = NULL;
38386 + if (qh->n_bytes) {
38387 + DWC_FREE(qh->n_bytes);
38388 + qh->n_bytes = NULL;
38392 +static int frame_list_alloc(dwc_otg_hcd_t * hcd)
38395 + if (hcd->frame_list)
38398 + hcd->frame_list = DWC_DMA_ALLOC(4 * MAX_FRLIST_EN_NUM,
38399 + &hcd->frame_list_dma);
38400 + if (!hcd->frame_list) {
38401 + retval = -DWC_E_NO_MEMORY;
38402 + DWC_ERROR("%s: Frame List allocation failed\n", __func__);
38405 + dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
38410 +static void frame_list_free(dwc_otg_hcd_t * hcd)
38412 + if (!hcd->frame_list)
38415 + DWC_DMA_FREE(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
38416 + hcd->frame_list = NULL;
38419 +static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
38422 + hcfg_data_t hcfg;
38424 + hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
38426 + if (hcfg.b.perschedena) {
38427 + /* already enabled */
38431 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hflbaddr,
38432 + hcd->frame_list_dma);
38434 + switch (fr_list_en) {
38436 + hcfg.b.frlisten = 3;
38439 + hcfg.b.frlisten = 2;
38442 + hcfg.b.frlisten = 1;
38445 + hcfg.b.frlisten = 0;
38451 + hcfg.b.perschedena = 1;
38453 + DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
38454 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
38458 +static void per_sched_disable(dwc_otg_hcd_t * hcd)
38460 + hcfg_data_t hcfg;
38462 + hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
38464 + if (!hcfg.b.perschedena) {
38465 + /* already disabled */
38468 + hcfg.b.perschedena = 0;
38470 + DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
38471 + DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
38475 + * Activates/Deactivates FrameList entries for the channel
38476 + * based on endpoint servicing period.
38478 +void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
38480 + uint16_t i, j, inc;
38481 + dwc_hc_t *hc = NULL;
38483 + if (!qh->channel) {
38484 + DWC_ERROR("qh->channel = %p", qh->channel);
38489 + DWC_ERROR("------hcd = %p", hcd);
38493 + if (!hcd->frame_list) {
38494 + DWC_ERROR("-------hcd->frame_list = %p", hcd->frame_list);
38498 + hc = qh->channel;
38499 + inc = frame_incr_val(qh);
38500 + if (qh->ep_type == UE_ISOCHRONOUS)
38501 + i = frame_list_idx(qh->sched_frame);
38508 + hcd->frame_list[j] |= (1 << hc->hc_num);
38510 + hcd->frame_list[j] &= ~(1 << hc->hc_num);
38511 + j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
38517 + if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
38519 + /* TODO - check this */
38520 + inc = (8 + qh->interval - 1) / qh->interval;
38521 + for (i = 0; i < inc; i++) {
38522 + hc->schinfo |= j;
38523 + j = j << qh->interval;
38526 + hc->schinfo = 0xff;
38531 +void dump_frame_list(dwc_otg_hcd_t * hcd)
38534 + DWC_PRINTF("--FRAME LIST (hex) --\n");
38535 + for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
38536 + DWC_PRINTF("%x\t", hcd->frame_list[i]);
38537 + if (!(i % 8) && i)
38538 + DWC_PRINTF("\n");
38540 + DWC_PRINTF("\n----\n");
38545 +static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38547 + dwc_irqflags_t flags;
38548 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
38550 + dwc_hc_t *hc = qh->channel;
38551 + if (dwc_qh_is_non_per(qh)) {
38552 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
38553 + if (!microframe_schedule)
38554 + hcd->non_periodic_channels--;
38556 + hcd->available_host_channels++;
38557 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
38559 + update_frame_list(hcd, qh, 0);
38562 + * The condition is added to prevent double cleanup try in case of device
38563 + * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
38566 + dwc_otg_hc_cleanup(hcd->core_if, hc);
38567 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
38571 + qh->channel = NULL;
38574 + if (qh->desc_list) {
38575 + dwc_memset(qh->desc_list, 0x00,
38576 + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
38578 + DWC_SPINLOCK_FREE(channel_lock);
38582 + * Initializes a QH structure's Descriptor DMA related members.
38583 + * Allocates memory for descriptor list.
38584 + * On first periodic QH, allocates memory for FrameList
38585 + * and enables periodic scheduling.
38587 + * @param hcd The HCD state structure for the DWC OTG controller.
38588 + * @param qh The QH to init.
38590 + * @return 0 if successful, negative error code otherwise.
38592 +int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38596 + if (qh->do_split) {
38597 + DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
38601 + retval = desc_list_alloc(qh);
38603 + if ((retval == 0)
38604 + && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
38605 + if (!hcd->frame_list) {
38606 + retval = frame_list_alloc(hcd);
38607 + /* Enable periodic schedule on first periodic QH */
38609 + per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
38619 + * Frees descriptor list memory associated with the QH.
38620 + * If QH is periodic and the last, frees FrameList memory
38621 + * and disables periodic scheduling.
38623 + * @param hcd The HCD state structure for the DWC OTG controller.
38624 + * @param qh The QH to init.
38626 +void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38628 + desc_list_free(qh);
38631 + * Channel still assigned due to some reasons.
38632 + * Seen on Isoc URB dequeue. Channel halted but no subsequent
38633 + * ChHalted interrupt to release the channel. Afterwards
38634 + * when it comes here from endpoint disable routine
38635 + * channel remains assigned.
38638 + release_channel_ddma(hcd, qh);
38640 + if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
38641 + && (microframe_schedule || !hcd->periodic_channels) && hcd->frame_list) {
38643 + per_sched_disable(hcd);
38644 + frame_list_free(hcd);
38648 +static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
38650 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
38652 + * Descriptor set(8 descriptors) index
38653 + * which is 8-aligned.
38655 + return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
38657 + return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
38662 + * Determine starting frame for Isochronous transfer.
38663 + * Few frames skipped to prevent race condition with HC.
38665 +static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
38666 + uint8_t * skip_frames)
38668 + uint16_t frame = 0;
38669 + hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
38671 + /* sched_frame is always frame number(not uFrame) both in FS and HS !! */
38674 + * skip_frames is used to limit activated descriptors number
38675 + * to avoid the situation when HC services the last activated
38676 + * descriptor firstly.
38677 + * Example for FS:
38678 + * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
38679 + * corresponding to curr_frame+1, the descriptor corresponding to frame 2
38680 + * will be fetched. If the number of descriptors is max=64 (or greather) the
38681 + * list will be fully programmed with Active descriptors and it is possible
38682 + * case(rare) that the latest descriptor(considering rollback) corresponding
38683 + * to frame 2 will be serviced first. HS case is more probable because, in fact,
38684 + * up to 11 uframes(16 in the code) may be skipped.
38686 + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
38688 + * Consider uframe counter also, to start xfer asap.
38689 + * If half of the frame elapsed skip 2 frames otherwise
38691 + * Starting descriptor index must be 8-aligned, so
38692 + * if the current frame is near to complete the next one
38693 + * is skipped as well.
38696 + if (dwc_micro_frame_num(hcd->frame_number) >= 5) {
38697 + *skip_frames = 2 * 8;
38698 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
38700 + *skip_frames = 1 * 8;
38701 + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
38704 + frame = dwc_full_frame_num(frame);
38707 + * Two frames are skipped for FS - the current and the next.
38708 + * But for descriptor programming, 1 frame(descriptor) is enough,
38709 + * see example above.
38711 + *skip_frames = 1;
38712 + frame = dwc_frame_num_inc(hcd->frame_number, 2);
38719 + * Calculate initial descriptor index for isochronous transfer
38720 + * based on scheduled frame.
38722 +static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38724 + uint16_t frame = 0, fr_idx, fr_idx_tmp;
38725 + uint8_t skip_frames = 0;
38727 + * With current ISOC processing algorithm the channel is being
38728 + * released when no more QTDs in the list(qh->ntd == 0).
38729 + * Thus this function is called only when qh->ntd == 0 and qh->channel == 0.
38731 + * So qh->channel != NULL branch is not used and just not removed from the
38732 + * source file. It is required for another possible approach which is,
38733 + * do not disable and release the channel when ISOC session completed,
38734 + * just move QH to inactive schedule until new QTD arrives.
38735 + * On new QTD, the QH moved back to 'ready' schedule,
38736 + * starting frame and therefore starting desc_index are recalculated.
38737 + * In this case channel is released only on ep_disable.
38740 + /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
38741 + if (qh->channel) {
38742 + frame = calc_starting_frame(hcd, qh, &skip_frames);
38744 + * Calculate initial descriptor index based on FrameList current bitmap
38745 + * and servicing period.
38747 + fr_idx_tmp = frame_list_idx(frame);
38749 + (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) -
38751 + % frame_incr_val(qh);
38752 + fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
38754 + qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);
38755 + fr_idx = frame_list_idx(qh->sched_frame);
38758 + qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx);
38760 + return skip_frames;
38763 +#define ISOC_URB_GIVEBACK_ASAP
38765 +#define MAX_ISOC_XFER_SIZE_FS 1023
38766 +#define MAX_ISOC_XFER_SIZE_HS 3072
38767 +#define DESCNUM_THRESHOLD 4
38769 +static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
38770 + uint8_t skip_frames)
38772 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
38773 + dwc_otg_qtd_t *qtd;
38774 + dwc_otg_host_dma_desc_t *dma_desc;
38775 + uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
38777 + idx = qh->td_last;
38778 + inc = qh->interval;
38781 + ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
38782 + if (skip_frames && !qh->channel)
38783 + ntd_max = ntd_max - skip_frames / qh->interval;
38786 + (qh->dev_speed ==
38787 + DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS :
38788 + MAX_ISOC_XFER_SIZE_FS;
38790 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
38791 + while ((qh->ntd < ntd_max)
38792 + && (qtd->isoc_frame_index_last <
38793 + qtd->urb->packet_count)) {
38795 + dma_desc = &qh->desc_list[idx];
38796 + dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
38798 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
38800 + if (frame_desc->length > max_xfer_size)
38801 + qh->n_bytes[idx] = max_xfer_size;
38803 + qh->n_bytes[idx] = frame_desc->length;
38804 + dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
38805 + dma_desc->status.b_isoc.a = 1;
38806 + dma_desc->status.b_isoc.sts = 0;
38808 + dma_desc->buf = qtd->urb->dma + frame_desc->offset;
38812 + qtd->isoc_frame_index_last++;
38814 +#ifdef ISOC_URB_GIVEBACK_ASAP
38816 + * Set IOC for each descriptor corresponding to the
38817 + * last frame of the URB.
38819 + if (qtd->isoc_frame_index_last ==
38820 + qtd->urb->packet_count)
38821 + dma_desc->status.b_isoc.ioc = 1;
38824 + idx = desclist_idx_inc(idx, inc, qh->dev_speed);
38828 + qtd->in_process = 1;
38831 + qh->td_last = idx;
38833 +#ifdef ISOC_URB_GIVEBACK_ASAP
38834 + /* Set IOC for the last descriptor if descriptor list is full */
38835 + if (qh->ntd == ntd_max) {
38836 + idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
38837 + qh->desc_list[idx].status.b_isoc.ioc = 1;
38841 + * Set IOC bit only for one descriptor.
38842 + * Always try to be ahead of HW processing,
38843 + * i.e. on IOC generation driver activates next descriptors but
38844 + * core continues to process descriptors followed the one with IOC set.
38847 + if (n_desc > DESCNUM_THRESHOLD) {
38849 + * Move IOC "up". Required even if there is only one QTD
38850 + * in the list, cause QTDs migth continue to be queued,
38851 + * but during the activation it was only one queued.
38852 + * Actually more than one QTD might be in the list if this function called
38853 + * from XferCompletion - QTDs was queued during HW processing of the previous
38854 + * descriptor chunk.
38856 + idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
38859 + * Set the IOC for the latest descriptor
38860 + * if either number of descriptor is not greather than threshold
38861 + * or no more new descriptors activated.
38863 + idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
38866 + qh->desc_list[idx].status.b_isoc.ioc = 1;
38870 +static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38874 + dwc_otg_host_dma_desc_t *dma_desc;
38875 + dwc_otg_qtd_t *qtd;
38876 + int num_packets, len, n_desc = 0;
38878 + hc = qh->channel;
38881 + * Start with hc->xfer_buff initialized in
38882 + * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
38883 + * this pointer re-assigned to the buffer of the currently processed QTD.
38884 + * For non-SG request there is always one QTD active.
38887 + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
38890 + /* SG request - more than 1 QTDs */
38891 + hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
38892 + hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
38898 + dma_desc = &qh->desc_list[n_desc];
38899 + len = hc->xfer_len;
38901 + if (len > MAX_DMA_DESC_SIZE)
38902 + len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
38904 + if (hc->ep_is_in) {
38906 + num_packets = (len + hc->max_packet - 1) / hc->max_packet;
38908 + /* Need 1 packet for transfer length of 0. */
38911 + /* Always program an integral # of max packets for IN transfers. */
38912 + len = num_packets * hc->max_packet;
38915 + dma_desc->status.b.n_bytes = len;
38917 + qh->n_bytes[n_desc] = len;
38919 + if ((qh->ep_type == UE_CONTROL)
38920 + && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
38921 + dma_desc->status.b.sup = 1; /* Setup Packet */
38923 + dma_desc->status.b.a = 1; /* Active descriptor */
38924 + dma_desc->status.b.sts = 0;
38927 + ((unsigned long)hc->xfer_buff & 0xffffffff);
38930 + * Last descriptor(or single) of IN transfer
38931 + * with actual size less than MaxPacket.
38933 + if (len > hc->xfer_len) {
38934 + hc->xfer_len = 0;
38936 + hc->xfer_buff += len;
38937 + hc->xfer_len -= len;
38943 + while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
38946 + qtd->in_process = 1;
38948 + if (qh->ep_type == UE_CONTROL)
38951 + if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
38956 + /* Request Transfer Complete interrupt for the last descriptor */
38957 + qh->desc_list[n_desc - 1].status.b.ioc = 1;
38958 + /* End of List indicator */
38959 + qh->desc_list[n_desc - 1].status.b.eol = 1;
38961 + hc->ntd = n_desc;
38966 + * For Control and Bulk endpoints initializes descriptor list
38967 + * and starts the transfer.
38969 + * For Interrupt and Isochronous endpoints initializes descriptor list
38970 + * then updates FrameList, marking appropriate entries as active.
38971 + * In case of Isochronous, the starting descriptor index is calculated based
38972 + * on the scheduled frame, but only on the first transfer descriptor within a session.
38973 + * Then starts the transfer via enabling the channel.
38974 + * For Isochronous endpoint the channel is not halted on XferComplete
38975 + * interrupt so remains assigned to the endpoint(QH) until session is done.
38977 + * @param hcd The HCD state structure for the DWC OTG controller.
38978 + * @param qh The QH to init.
38980 + * @return 0 if successful, negative error code otherwise.
38982 +void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
38984 + /* Channel is already assigned */
38985 + dwc_hc_t *hc = qh->channel;
38986 + uint8_t skip_frames = 0;
38988 + switch (hc->ep_type) {
38989 + case DWC_OTG_EP_TYPE_CONTROL:
38990 + case DWC_OTG_EP_TYPE_BULK:
38991 + init_non_isoc_dma_desc(hcd, qh);
38993 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
38995 + case DWC_OTG_EP_TYPE_INTR:
38996 + init_non_isoc_dma_desc(hcd, qh);
38998 + update_frame_list(hcd, qh, 1);
39000 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
39002 + case DWC_OTG_EP_TYPE_ISOC:
39005 + skip_frames = recalc_initial_desc_idx(hcd, qh);
39007 + init_isoc_dma_desc(hcd, qh, skip_frames);
39009 + if (!hc->xfer_started) {
39011 + update_frame_list(hcd, qh, 1);
39014 + * Always set to max, instead of actual size.
39015 + * Otherwise ntd will be changed with
39016 + * channel being enabled. Not recommended.
39019 + hc->ntd = max_desc_num(qh);
39020 + /* Enable channel only once for ISOC */
39021 + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
39031 +static void complete_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
39033 + dwc_otg_hc_regs_t * hc_regs,
39034 + dwc_otg_halt_status_e halt_status)
39036 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
39037 + dwc_otg_qtd_t *qtd, *qtd_tmp;
39038 + dwc_otg_qh_t *qh;
39039 + dwc_otg_host_dma_desc_t *dma_desc;
39040 + uint16_t idx, remain;
39041 + uint8_t urb_compl;
39044 + idx = qh->td_first;
39046 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
39047 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
39048 + qtd->in_process = 0;
39050 + } else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) ||
39051 + (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
39053 + * Channel is halted in these error cases.
39054 + * Considered as serious issues.
39055 + * Complete all URBs marking all frames as failed,
39056 + * irrespective whether some of the descriptors(frames) succeeded or no.
39057 + * Pass error code to completion routine as well, to
39058 + * update urb->status, some of class drivers might use it to stop
39059 + * queing transfer requests.
39061 + int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR)
39063 + : (-DWC_E_OVERFLOW);
39065 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
39066 + for (idx = 0; idx < qtd->urb->packet_count; idx++) {
39067 + frame_desc = &qtd->urb->iso_descs[idx];
39068 + frame_desc->status = err;
39070 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
39071 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
39076 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
39078 + if (!qtd->in_process)
39085 + dma_desc = &qh->desc_list[idx];
39087 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
39088 + remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
39090 + if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
39092 + * XactError or, unable to complete all the transactions
39093 + * in the scheduled micro-frame/frame,
39094 + * both indicated by DMA_DESC_STS_PKTERR.
39096 + qtd->urb->error_count++;
39097 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
39098 + frame_desc->status = -DWC_E_PROTOCOL;
39102 + frame_desc->actual_length = qh->n_bytes[idx] - remain;
39103 + frame_desc->status = 0;
39106 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
39108 + * urb->status is not used for isoc transfers here.
39109 + * The individual frame_desc status are used instead.
39112 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
39113 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
39116 + * This check is necessary because urb_dequeue can be called
39117 + * from urb complete callback(sound driver example).
39118 + * All pending URBs are dequeued there, so no need for
39119 + * further processing.
39121 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
39131 + /* Stop if IOC requested descriptor reached */
39132 + if (dma_desc->status.b_isoc.ioc) {
39133 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
39137 + idx = desclist_idx_inc(idx, qh->interval, hc->speed);
39142 + while (idx != qh->td_first);
39145 + qh->td_first = idx;
39148 +uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
39150 + dwc_otg_qtd_t * qtd,
39151 + dwc_otg_host_dma_desc_t * dma_desc,
39152 + dwc_otg_halt_status_e halt_status,
39153 + uint32_t n_bytes, uint8_t * xfer_done)
39156 + uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
39157 + dwc_otg_hcd_urb_t *urb = qtd->urb;
39159 + if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
39160 + urb->status = -DWC_E_IO;
39163 + if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
39164 + switch (halt_status) {
39165 + case DWC_OTG_HC_XFER_STALL:
39166 + urb->status = -DWC_E_PIPE;
39168 + case DWC_OTG_HC_XFER_BABBLE_ERR:
39169 + urb->status = -DWC_E_OVERFLOW;
39171 + case DWC_OTG_HC_XFER_XACT_ERR:
39172 + urb->status = -DWC_E_PROTOCOL;
39175 + DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
39182 + if (dma_desc->status.b.a == 1) {
39183 + DWC_DEBUGPL(DBG_HCDV,
39184 + "Active descriptor encountered on channel %d\n",
39189 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
39190 + if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
39191 + urb->actual_length += n_bytes - remain;
39192 + if (remain || urb->actual_length == urb->length) {
39194 + * For Control Data stage do not set urb->status=0 to prevent
39195 + * URB callback. Set it when Status phase done. See below.
39200 + } else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
39204 + /* No handling for SETUP stage */
39206 + /* BULK and INTR */
39207 + urb->actual_length += n_bytes - remain;
39208 + if (remain || urb->actual_length == urb->length) {
39217 +static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
39219 + dwc_otg_hc_regs_t * hc_regs,
39220 + dwc_otg_halt_status_e halt_status)
39222 + dwc_otg_hcd_urb_t *urb = NULL;
39223 + dwc_otg_qtd_t *qtd, *qtd_tmp;
39224 + dwc_otg_qh_t *qh;
39225 + dwc_otg_host_dma_desc_t *dma_desc;
39226 + uint32_t n_bytes, n_desc, i;
39227 + uint8_t failed = 0, xfer_done;
39233 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
39234 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
39235 + qtd->in_process = 0;
39240 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
39247 + for (i = 0; i < qtd->n_desc; i++) {
39248 + dma_desc = &qh->desc_list[n_desc];
39250 + n_bytes = qh->n_bytes[n_desc];
39253 + update_non_isoc_urb_state_ddma(hcd, hc, qtd,
39255 + halt_status, n_bytes,
39260 + && (urb->status != -DWC_E_IN_PROGRESS))) {
39262 + hcd->fops->complete(hcd, urb->priv, urb,
39264 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
39268 + } else if (qh->ep_type == UE_CONTROL) {
39269 + if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
39270 + if (urb->length > 0) {
39271 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
39273 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
39275 + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n");
39276 + } else if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
39278 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
39279 + DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n");
39280 + } else if (i + 1 == qtd->n_desc) {
39282 + * Last descriptor for Control data stage which is
39283 + * not completed yet.
39285 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
39297 + if (qh->ep_type != UE_CONTROL) {
39299 + * Resetting the data toggle for bulk
39300 + * and interrupt endpoints in case of stall. See handle_hc_stall_intr()
39302 + if (halt_status == DWC_OTG_HC_XFER_STALL)
39303 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
39305 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
39308 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
39309 + hcint_data_t hcint;
39310 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
39311 + if (hcint.b.nyet) {
39313 + * Got a NYET on the last transaction of the transfer. It
39314 + * means that the endpoint should be in the PING state at the
39315 + * beginning of the next transfer.
39317 + qh->ping_state = 1;
39318 + clear_hc_int(hc_regs, nyet);
39326 + * This function is called from interrupt handlers.
39327 + * Scans the descriptor list, updates URB's status and
39328 + * calls completion routine for the URB if it's done.
39329 + * Releases the channel to be used by other transfers.
39330 + * In case of Isochronous endpoint the channel is not halted until
39331 + * the end of the session, i.e. QTD list is empty.
39332 + * If periodic channel released the FrameList is updated accordingly.
39334 + * Calls transaction selection routines to activate pending transfers.
39336 + * @param hcd The HCD state structure for the DWC OTG controller.
39337 + * @param hc Host channel, the transfer is completed on.
39338 + * @param hc_regs Host channel registers.
39339 + * @param halt_status Reason the channel is being halted,
39340 + * or just XferComplete for isochronous transfer
39342 +void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
39344 + dwc_otg_hc_regs_t * hc_regs,
39345 + dwc_otg_halt_status_e halt_status)
39347 + uint8_t continue_isoc_xfer = 0;
39348 + dwc_otg_transaction_type_e tr_type;
39349 + dwc_otg_qh_t *qh = hc->qh;
39351 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
39353 + complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
39355 + /* Release the channel if halted or session completed */
39356 + if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
39357 + DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
39359 + /* Halt the channel if session completed */
39360 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
39361 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
39364 + release_channel_ddma(hcd, qh);
39365 + dwc_otg_hcd_qh_remove(hcd, qh);
39367 + /* Keep in assigned schedule to continue transfer */
39368 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
39369 + &qh->qh_list_entry);
39370 + continue_isoc_xfer = 1;
39373 + /** @todo Consider the case when period exceeds FrameList size.
39374 + * Frame Rollover interrupt should be used.
39377 + /* Scan descriptor list to complete the URB(s), then release the channel */
39378 + complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
39380 + release_channel_ddma(hcd, qh);
39381 + dwc_otg_hcd_qh_remove(hcd, qh);
39383 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
39384 + /* Add back to inactive non-periodic schedule on normal completion */
39385 + dwc_otg_hcd_qh_add(hcd, qh);
39389 + tr_type = dwc_otg_hcd_select_transactions(hcd);
39390 + if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
39391 + if (continue_isoc_xfer) {
39392 + if (tr_type == DWC_OTG_TRANSACTION_NONE) {
39393 + tr_type = DWC_OTG_TRANSACTION_PERIODIC;
39394 + } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
39395 + tr_type = DWC_OTG_TRANSACTION_ALL;
39398 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
39402 +#endif /* DWC_DEVICE_ONLY */
39403 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
39404 new file mode 100644
39405 index 0000000..b3dc806
39407 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
39409 +/* ==========================================================================
39410 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $
39411 + * $Revision: #12 $
39412 + * $Date: 2011/10/26 $
39413 + * $Change: 1873028 $
39415 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
39416 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
39417 + * otherwise expressly agreed to in writing between Synopsys and you.
39419 + * The Software IS NOT an item of Licensed Software or Licensed Product under
39420 + * any End User Software License Agreement or Agreement for Licensed Product
39421 + * with Synopsys or any supplement thereto. You are permitted to use and
39422 + * redistribute this Software in source and binary forms, with or without
39423 + * modification, provided that redistributions of source code must retain this
39424 + * notice. You may not view, use, disclose, copy or distribute this file or
39425 + * any information contained herein except pursuant to this license grant from
39426 + * Synopsys. If you do not agree with this notice, including the disclaimer
39427 + * below, then you are not authorized to use the Software.
39429 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
39430 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39431 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39432 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
39433 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39434 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39435 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39436 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39437 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39438 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39440 + * ========================================================================== */
39441 +#ifndef DWC_DEVICE_ONLY
39442 +#ifndef __DWC_HCD_IF_H__
39443 +#define __DWC_HCD_IF_H__
39445 +#include "dwc_otg_core_if.h"
39448 + * This file defines DWC_OTG HCD Core API.
39451 +struct dwc_otg_hcd;
39452 +typedef struct dwc_otg_hcd dwc_otg_hcd_t;
39454 +struct dwc_otg_hcd_urb;
39455 +typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t;
39457 +/** @name HCD Function Driver Callbacks */
39460 +/** This function is called whenever core switches to host mode. */
39461 +typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd);
39463 +/** This function is called when device has been disconnected */
39464 +typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd);
39466 +/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */
39467 +typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
39468 + void *urb_handle,
39469 + uint32_t * hub_addr,
39470 + uint32_t * port_addr);
39471 +/** Via this function HCD core gets device speed */
39472 +typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
39473 + void *urb_handle);
39475 +/** This function is called when urb is completed */
39476 +typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd,
39477 + void *urb_handle,
39478 + dwc_otg_hcd_urb_t * dwc_otg_urb,
39481 +/** Via this function HCD core gets b_hnp_enable parameter */
39482 +typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd);
39484 +struct dwc_otg_hcd_function_ops {
39485 + dwc_otg_hcd_start_cb_t start;
39486 + dwc_otg_hcd_disconnect_cb_t disconnect;
39487 + dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
39488 + dwc_otg_hcd_speed_from_urb_cb_t speed;
39489 + dwc_otg_hcd_complete_urb_cb_t complete;
39490 + dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
39494 +/** @name HCD Core API */
39496 +/** This function allocates dwc_otg_hcd structure and returns pointer on it. */
39497 +extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void);
39499 +/** This function should be called to initiate HCD Core.
39501 + * @param hcd The HCD
39502 + * @param core_if The DWC_OTG Core
39504 + * Returns -DWC_E_NO_MEMORY if no enough memory.
39505 + * Returns 0 on success
39507 +extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if);
39511 + * @param hcd The HCD
39513 +extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
39515 +/** This function should be called on every hardware interrupt.
39517 + * @param dwc_otg_hcd The HCD
39519 + * Returns non zero if interrupt is handled
39520 + * Return 0 if interrupt is not handled
39522 +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
39525 + * Returns private data set by
39526 + * dwc_otg_hcd_set_priv_data function.
39528 + * @param hcd The HCD
39530 +extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd);
39533 + * Set private data.
39535 + * @param hcd The HCD
39536 + * @param priv_data pointer to be stored in private data
39538 +extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data);
39541 + * This function initializes the HCD Core.
39543 + * @param hcd The HCD
39544 + * @param fops The Function Driver Operations data structure containing pointers to all callbacks.
39546 + * Returns -DWC_E_NO_DEVICE if Core is currently is in device mode.
39547 + * Returns 0 on success
39549 +extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
39550 + struct dwc_otg_hcd_function_ops *fops);
39553 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
39556 + * @param hcd The HCD
39558 +extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd);
39561 + * Handles hub class-specific requests.
39563 + * @param dwc_otg_hcd The HCD
39564 + * @param typeReq Request Type
39565 + * @param wValue wValue from control request
39566 + * @param wIndex wIndex from control request
39567 + * @param buf data buffer
39568 + * @param wLength data buffer length
39570 + * Returns -DWC_E_INVALID if invalid argument is passed
39571 + * Returns 0 on success
39573 +extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
39574 + uint16_t typeReq, uint16_t wValue,
39575 + uint16_t wIndex, uint8_t * buf,
39576 + uint16_t wLength);
39579 + * Returns otg port number.
39581 + * @param hcd The HCD
39583 +extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd);
39586 + * Returns OTG version - either 1.3 or 2.0.
39588 + * @param core_if The core_if structure pointer
39590 +extern uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if);
39593 + * Returns 1 if currently core is acting as B host, and 0 otherwise.
39595 + * @param hcd The HCD
39597 +extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd);
39600 + * Returns current frame number.
39602 + * @param hcd The HCD
39604 +extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd);
39607 + * Dumps hcd state.
39609 + * @param hcd The HCD
39611 +extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd);
39614 + * Dump the average frame remaining at SOF. This can be used to
39615 + * determine average interrupt latency. Frame remaining is also shown for
39616 + * start transfer and two additional sample points.
39617 + * Currently this function is not implemented.
39619 + * @param hcd The HCD
39621 +extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd);
39624 + * Sends LPM transaction to the local device.
39626 + * @param hcd The HCD
39627 + * @param devaddr Device Address
39628 + * @param hird Host initiated resume duration
39629 + * @param bRemoteWake Value of bRemoteWake field in LPM transaction
39631 + * Returns negative value if sending LPM transaction was not succeeded.
39632 + * Returns 0 on success.
39634 +extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr,
39635 + uint8_t hird, uint8_t bRemoteWake);
39637 +/* URB interface */
39640 + * Allocates memory for dwc_otg_hcd_urb structure.
39641 + * Allocated memory should be freed by call of DWC_FREE.
39643 + * @param hcd The HCD
39644 + * @param iso_desc_count Count of ISOC descriptors
39645 + * @param atomic_alloc Specefies whether to perform atomic allocation.
39647 +extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
39648 + int iso_desc_count,
39649 + int atomic_alloc);
39652 + * Set pipe information in URB.
39654 + * @param hcd_urb DWC_OTG URB
39655 + * @param devaddr Device Address
39656 + * @param ep_num Endpoint Number
39657 + * @param ep_type Endpoint Type
39658 + * @param ep_dir Endpoint Direction
39659 + * @param mps Max Packet Size
39661 +extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb,
39662 + uint8_t devaddr, uint8_t ep_num,
39663 + uint8_t ep_type, uint8_t ep_dir,
39666 +/* Transfer flags */
39667 +#define URB_GIVEBACK_ASAP 0x1
39668 +#define URB_SEND_ZERO_PACKET 0x2
39671 + * Sets dwc_otg_hcd_urb parameters.
39673 + * @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
39674 + * @param urb_handle Unique handle for request, this will be passed back
39675 + * to function driver in completion callback.
39676 + * @param buf The buffer for the data
39677 + * @param dma The DMA buffer for the data
39678 + * @param buflen Transfer length
39679 + * @param sp Buffer for setup data
39680 + * @param sp_dma DMA address of setup data buffer
39681 + * @param flags Transfer flags
39682 + * @param interval Polling interval for interrupt or isochronous transfers.
39684 +extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb,
39685 + void *urb_handle, void *buf,
39686 + dwc_dma_t dma, uint32_t buflen, void *sp,
39687 + dwc_dma_t sp_dma, uint32_t flags,
39688 + uint16_t interval);
39690 +/** Gets status from dwc_otg_hcd_urb
39692 + * @param dwc_otg_urb DWC_OTG URB
39694 +extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb);
39696 +/** Gets actual length from dwc_otg_hcd_urb
39698 + * @param dwc_otg_urb DWC_OTG URB
39700 +extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t *
39703 +/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs
39705 + * @param dwc_otg_urb DWC_OTG URB
39707 +extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t *
39710 +/** Set ISOC descriptor offset and length
39712 + * @param dwc_otg_urb DWC_OTG URB
39713 + * @param desc_num ISOC descriptor number
39714 + * @param offset Offset from beginig of buffer.
39715 + * @param length Transaction length
39717 +extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
39718 + int desc_num, uint32_t offset,
39719 + uint32_t length);
39721 +/** Get status of ISOC descriptor, specified by desc_num
39723 + * @param dwc_otg_urb DWC_OTG URB
39724 + * @param desc_num ISOC descriptor number
39726 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t *
39727 + dwc_otg_urb, int desc_num);
39729 +/** Get actual length of ISOC descriptor, specified by desc_num
39731 + * @param dwc_otg_urb DWC_OTG URB
39732 + * @param desc_num ISOC descriptor number
39734 +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
39738 +/** Queue URB. After transfer is completes, the complete callback will be called with the URB status
39740 + * @param dwc_otg_hcd The HCD
39741 + * @param dwc_otg_urb DWC_OTG URB
39742 + * @param ep_handle Out parameter for returning endpoint handle
39743 + * @param atomic_alloc Flag to do atomic allocation if needed
39745 + * Returns -DWC_E_NO_DEVICE if no device is connected.
39746 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
39747 + * Returns 0 on success.
39749 +extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd,
39750 + dwc_otg_hcd_urb_t * dwc_otg_urb,
39751 + void **ep_handle, int atomic_alloc);
39753 +/** De-queue the specified URB
39755 + * @param dwc_otg_hcd The HCD
39756 + * @param dwc_otg_urb DWC_OTG URB
39758 +extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd,
39759 + dwc_otg_hcd_urb_t * dwc_otg_urb);
39761 +/** Frees resources in the DWC_otg controller related to a given endpoint.
39762 + * Any URBs for the endpoint must already be dequeued.
39764 + * @param hcd The HCD
39765 + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
39766 + * @param retry Number of retries if there are queued transfers.
39768 + * Returns -DWC_E_INVALID if invalid arguments are passed.
39769 + * Returns 0 on success
39771 +extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
39774 +/* Resets the data toggle in qh structure. This function can be called from
39775 + * usb_clear_halt routine.
39777 + * @param hcd The HCD
39778 + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
39780 + * Returns -DWC_E_INVALID if invalid arguments are passed.
39781 + * Returns 0 on success
39783 +extern int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle);
39785 +/** Returns 1 if status of specified port is changed and 0 otherwise.
39787 + * @param hcd The HCD
39788 + * @param port Port number
39790 +extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port);
39792 +/** Call this function to check if bandwidth was allocated for specified endpoint.
39793 + * Only for ISOC and INTERRUPT endpoints.
39795 + * @param hcd The HCD
39796 + * @param ep_handle Endpoint handle
39798 +extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd,
39799 + void *ep_handle);
39801 +/** Call this function to check if bandwidth was freed for specified endpoint.
39803 + * @param hcd The HCD
39804 + * @param ep_handle Endpoint handle
39806 +extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle);
39808 +/** Returns bandwidth allocated for specified endpoint in microseconds.
39809 + * Only for ISOC and INTERRUPT endpoints.
39811 + * @param hcd The HCD
39812 + * @param ep_handle Endpoint handle
39814 +extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd,
39815 + void *ep_handle);
39819 +#endif /* __DWC_HCD_IF_H__ */
39820 +#endif /* DWC_DEVICE_ONLY */
39821 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
39822 new file mode 100644
39823 index 0000000..63c1b55
39825 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
39827 +/* ==========================================================================
39828 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $
39829 + * $Revision: #89 $
39830 + * $Date: 2011/10/20 $
39831 + * $Change: 1869487 $
39833 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
39834 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
39835 + * otherwise expressly agreed to in writing between Synopsys and you.
39837 + * The Software IS NOT an item of Licensed Software or Licensed Product under
39838 + * any End User Software License Agreement or Agreement for Licensed Product
39839 + * with Synopsys or any supplement thereto. You are permitted to use and
39840 + * redistribute this Software in source and binary forms, with or without
39841 + * modification, provided that redistributions of source code must retain this
39842 + * notice. You may not view, use, disclose, copy or distribute this file or
39843 + * any information contained herein except pursuant to this license grant from
39844 + * Synopsys. If you do not agree with this notice, including the disclaimer
39845 + * below, then you are not authorized to use the Software.
39847 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
39848 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39849 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39850 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
39851 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39852 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39853 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39854 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39855 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39856 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39858 + * ========================================================================== */
39859 +#ifndef DWC_DEVICE_ONLY
39861 +#include "dwc_otg_hcd.h"
39862 +#include "dwc_otg_regs.h"
39864 +extern bool microframe_schedule;
39867 + * This file contains the implementation of the HCD Interrupt handlers.
39870 +/** This function handles interrupts for the HCD. */
39871 +int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
39875 + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
39876 + gintsts_data_t gintsts;
39878 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
39880 + //GRAYG: debugging
39881 + if (NULL == global_regs) {
39882 + DWC_DEBUGPL(DBG_HCD, "**** NULL regs: dwc_otg_hcd=%p "
39884 + dwc_otg_hcd, global_regs);
39889 + /* Exit from ISR if core is hibernated */
39890 + if (core_if->hibernation_suspend == 1) {
39893 + DWC_SPINLOCK(dwc_otg_hcd->lock);
39894 + /* Check if HOST Mode */
39895 + if (dwc_otg_is_host_mode(core_if)) {
39896 + gintsts.d32 = dwc_otg_read_core_intr(core_if);
39897 + if (!gintsts.d32) {
39898 + DWC_SPINUNLOCK(dwc_otg_hcd->lock);
39902 + /* Don't print debug message in the interrupt handler on SOF */
39904 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39906 + DWC_DEBUGPL(DBG_HCDI, "\n");
39911 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39913 + DWC_DEBUGPL(DBG_HCDI,
39914 + "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n",
39915 + gintsts.d32, core_if);
39918 + if (gintsts.b.sofintr) {
39919 + retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
39921 + if (gintsts.b.rxstsqlvl) {
39923 + dwc_otg_hcd_handle_rx_status_q_level_intr
39926 + if (gintsts.b.nptxfempty) {
39928 + dwc_otg_hcd_handle_np_tx_fifo_empty_intr
39931 + if (gintsts.b.i2cintr) {
39932 + /** @todo Implement i2cintr handler. */
39934 + if (gintsts.b.portintr) {
39935 + retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
39937 + if (gintsts.b.hcintr) {
39938 + retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
39940 + if (gintsts.b.ptxfempty) {
39942 + dwc_otg_hcd_handle_perio_tx_fifo_empty_intr
39947 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39950 + DWC_DEBUGPL(DBG_HCDI,
39951 + "DWC OTG HCD Finished Servicing Interrupts\n");
39952 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
39953 + DWC_READ_REG32(&global_regs->gintsts));
39954 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
39955 + DWC_READ_REG32(&global_regs->gintmsk));
39961 + if (gintsts.d32 != DWC_SOF_INTR_MASK)
39963 + DWC_DEBUGPL(DBG_HCDI, "\n");
39967 + DWC_SPINUNLOCK(dwc_otg_hcd->lock);
39971 +#ifdef DWC_TRACK_MISSED_SOFS
39972 +#warning Compiling code to track missed SOFs
39973 +#define FRAME_NUM_ARRAY_SIZE 1000
39975 + * This function is for debug only.
39977 +static inline void track_missed_sofs(uint16_t curr_frame_number)
39979 + static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
39980 + static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
39981 + static int frame_num_idx = 0;
39982 + static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
39983 + static int dumped_frame_num_array = 0;
39985 + if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
39986 + if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
39987 + curr_frame_number) {
39988 + frame_num_array[frame_num_idx] = curr_frame_number;
39989 + last_frame_num_array[frame_num_idx++] = last_frame_num;
39991 + } else if (!dumped_frame_num_array) {
39993 + DWC_PRINTF("Frame Last Frame\n");
39994 + DWC_PRINTF("----- ----------\n");
39995 + for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
39996 + DWC_PRINTF("0x%04x 0x%04x\n",
39997 + frame_num_array[i], last_frame_num_array[i]);
39999 + dumped_frame_num_array = 1;
40001 + last_frame_num = curr_frame_number;
40006 + * Handles the start-of-frame interrupt in host mode. Non-periodic
40007 + * transactions may be queued to the DWC_otg controller for the current
40008 + * (micro)frame. Periodic transactions may be queued to the controller for the
40009 + * next (micro)frame.
40011 +int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd)
40013 + hfnum_data_t hfnum;
40014 + dwc_list_link_t *qh_entry;
40015 + dwc_otg_qh_t *qh;
40016 + dwc_otg_transaction_type_e tr_type;
40017 + gintsts_data_t gintsts = {.d32 = 0 };
40020 + DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
40023 + DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
40025 + hcd->frame_number = hfnum.b.frnum;
40028 + hcd->frrem_accum += hfnum.b.frrem;
40029 + hcd->frrem_samples++;
40032 +#ifdef DWC_TRACK_MISSED_SOFS
40033 + track_missed_sofs(hcd->frame_number);
40035 + /* Determine whether any periodic QHs should be executed. */
40036 + qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive);
40037 + while (qh_entry != &hcd->periodic_sched_inactive) {
40038 + qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry);
40039 + qh_entry = qh_entry->next;
40040 + if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
40042 + * Move QH to the ready list to be executed next
40045 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
40046 + &qh->qh_list_entry);
40049 + tr_type = dwc_otg_hcd_select_transactions(hcd);
40050 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
40051 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
40054 + /* Clear interrupt */
40055 + gintsts.b.sofintr = 1;
40056 + DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
40061 +/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at
40062 + * least one packet in the Rx FIFO. The packets are moved from the FIFO to
40063 + * memory if the DWC_otg controller is operating in Slave mode. */
40064 +int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40066 + host_grxsts_data_t grxsts;
40067 + dwc_hc_t *hc = NULL;
40069 + DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
40072 + DWC_READ_REG32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp);
40074 + hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
40076 + DWC_ERROR("Unable to get corresponding channel\n");
40080 + /* Packet Status */
40081 + DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum);
40082 + DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt);
40083 + DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid,
40084 + hc->data_pid_start);
40085 + DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts);
40087 + switch (grxsts.b.pktsts) {
40088 + case DWC_GRXSTS_PKTSTS_IN:
40089 + /* Read the data into the host buffer. */
40090 + if (grxsts.b.bcnt > 0) {
40091 + dwc_otg_read_packet(dwc_otg_hcd->core_if,
40092 + hc->xfer_buff, grxsts.b.bcnt);
40094 + /* Update the HC fields for the next packet received. */
40095 + hc->xfer_count += grxsts.b.bcnt;
40096 + hc->xfer_buff += grxsts.b.bcnt;
40099 + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
40100 + case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
40101 + case DWC_GRXSTS_PKTSTS_CH_HALTED:
40102 + /* Handled in interrupt, just ignore data */
40105 + DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n",
40106 + grxsts.b.pktsts);
40113 +/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
40114 + * data packets may be written to the FIFO for OUT transfers. More requests
40115 + * may be written to the non-periodic request queue for IN transfers. This
40116 + * interrupt is enabled only in Slave mode. */
40117 +int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40119 + DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
40120 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
40121 + DWC_OTG_TRANSACTION_NON_PERIODIC);
40125 +/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data
40126 + * packets may be written to the FIFO for OUT transfers. More requests may be
40127 + * written to the periodic request queue for IN transfers. This interrupt is
40128 + * enabled only in Slave mode. */
40129 +int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40131 + DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
40132 + dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
40133 + DWC_OTG_TRANSACTION_PERIODIC);
40137 +/** There are multiple conditions that can cause a port interrupt. This function
40138 + * determines which interrupt conditions have occurred and handles them
40139 + * appropriately. */
40140 +int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40143 + hprt0_data_t hprt0;
40144 + hprt0_data_t hprt0_modify;
40146 + hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
40147 + hprt0_modify.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
40149 + /* Clear appropriate bits in HPRT0 to clear the interrupt bit in
40152 + hprt0_modify.b.prtena = 0;
40153 + hprt0_modify.b.prtconndet = 0;
40154 + hprt0_modify.b.prtenchng = 0;
40155 + hprt0_modify.b.prtovrcurrchng = 0;
40157 + /* Port Connect Detected
40158 + * Set flag and clear if detected */
40159 + if (dwc_otg_hcd->core_if->hibernation_suspend == 1) {
40160 + // Dont modify port status if we are in hibernation state
40161 + hprt0_modify.b.prtconndet = 1;
40162 + hprt0_modify.b.prtenchng = 1;
40163 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
40164 + hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
40168 + if (hprt0.b.prtconndet) {
40169 + /** @todo - check if steps performed in 'else' block should be perfromed regardles adp */
40170 + if (dwc_otg_hcd->core_if->adp_enable &&
40171 + dwc_otg_hcd->core_if->adp.vbuson_timer_started == 1) {
40172 + DWC_PRINTF("PORT CONNECT DETECTED ----------------\n");
40173 + DWC_TIMER_CANCEL(dwc_otg_hcd->core_if->adp.vbuson_timer);
40174 + dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
40175 + /* TODO - check if this is required, as
40176 + * host initialization was already performed
40177 + * after initial ADP probing
40179 + /*dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
40180 + dwc_otg_core_init(dwc_otg_hcd->core_if);
40181 + dwc_otg_enable_global_interrupts(dwc_otg_hcd->core_if);
40182 + cil_hcd_start(dwc_otg_hcd->core_if);*/
40185 + DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
40186 + "Port Connect Detected--\n", hprt0.d32);
40187 + dwc_otg_hcd->flags.b.port_connect_status_change = 1;
40188 + dwc_otg_hcd->flags.b.port_connect_status = 1;
40189 + hprt0_modify.b.prtconndet = 1;
40191 + /* B-Device has connected, Delete the connection timer. */
40192 + DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer);
40194 + /* The Hub driver asserts a reset when it sees port connect
40195 + * status change flag */
40199 + /* Port Enable Changed
40200 + * Clear if detected - Set internal flag if disabled */
40201 + if (hprt0.b.prtenchng) {
40202 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
40203 + "Port Enable Changed--\n", hprt0.d32);
40204 + hprt0_modify.b.prtenchng = 1;
40205 + if (hprt0.b.prtena == 1) {
40206 + hfir_data_t hfir;
40207 + int do_reset = 0;
40208 + dwc_otg_core_params_t *params =
40209 + dwc_otg_hcd->core_if->core_params;
40210 + dwc_otg_core_global_regs_t *global_regs =
40211 + dwc_otg_hcd->core_if->core_global_regs;
40212 + dwc_otg_host_if_t *host_if =
40213 + dwc_otg_hcd->core_if->host_if;
40215 + /* Every time when port enables calculate
40216 + * HFIR.FrInterval
40218 + hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
40219 + hfir.b.frint = calc_frame_interval(dwc_otg_hcd->core_if);
40220 + DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
40222 + /* Check if we need to adjust the PHY clock speed for
40223 + * low power and adjust it */
40224 + if (params->host_support_fs_ls_low_power) {
40225 + gusbcfg_data_t usbcfg;
40228 + DWC_READ_REG32(&global_regs->gusbcfg);
40230 + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED
40231 + || hprt0.b.prtspd ==
40232 + DWC_HPRT0_PRTSPD_FULL_SPEED) {
40236 + hcfg_data_t hcfg;
40237 + if (usbcfg.b.phylpwrclksel == 0) {
40238 + /* Set PHY low power clock select for FS/LS devices */
40239 + usbcfg.b.phylpwrclksel = 1;
40241 + (&global_regs->gusbcfg,
40248 + (&host_if->host_global_regs->hcfg);
40250 + if (hprt0.b.prtspd ==
40251 + DWC_HPRT0_PRTSPD_LOW_SPEED
40252 + && params->host_ls_low_power_phy_clk
40254 + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)
40257 + DWC_DEBUGPL(DBG_CIL,
40258 + "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
40259 + if (hcfg.b.fslspclksel !=
40260 + DWC_HCFG_6_MHZ) {
40261 + hcfg.b.fslspclksel =
40264 + (&host_if->host_global_regs->hcfg,
40270 + DWC_DEBUGPL(DBG_CIL,
40271 + "FS_PHY programming HCFG to 48 MHz ()\n");
40272 + if (hcfg.b.fslspclksel !=
40273 + DWC_HCFG_48_MHZ) {
40274 + hcfg.b.fslspclksel =
40277 + (&host_if->host_global_regs->hcfg,
40286 + if (usbcfg.b.phylpwrclksel == 1) {
40287 + usbcfg.b.phylpwrclksel = 0;
40289 + (&global_regs->gusbcfg,
40296 + DWC_TASK_SCHEDULE(dwc_otg_hcd->reset_tasklet);
40301 + /* Port has been enabled set the reset change flag */
40302 + dwc_otg_hcd->flags.b.port_reset_change = 1;
40305 + dwc_otg_hcd->flags.b.port_enable_change = 1;
40310 + /** Overcurrent Change Interrupt */
40311 + if (hprt0.b.prtovrcurrchng) {
40312 + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
40313 + "Port Overcurrent Changed--\n", hprt0.d32);
40314 + dwc_otg_hcd->flags.b.port_over_current_change = 1;
40315 + hprt0_modify.b.prtovrcurrchng = 1;
40319 + /* Clear Port Interrupts */
40320 + DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
40325 +/** This interrupt indicates that one or more host channels has a pending
40326 + * interrupt. There are multiple conditions that can cause each host channel
40327 + * interrupt. This function determines which conditions have occurred for each
40328 + * host channel interrupt and handles them appropriately. */
40329 +int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
40333 + haint_data_t haint;
40335 + /* Clear appropriate bits in HCINTn to clear the interrupt bit in
40338 + haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
40340 + for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
40341 + if (haint.b2.chint & (1 << i)) {
40342 + retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
40350 + * Gets the actual length of a transfer after the transfer halts. _halt_status
40351 + * holds the reason for the halt.
40353 + * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE,
40354 + * *short_read is set to 1 upon return if less than the requested
40355 + * number of bytes were transferred. Otherwise, *short_read is set to 0 upon
40356 + * return. short_read may also be NULL on entry, in which case it remains
40359 +static uint32_t get_actual_xfer_length(dwc_hc_t * hc,
40360 + dwc_otg_hc_regs_t * hc_regs,
40361 + dwc_otg_qtd_t * qtd,
40362 + dwc_otg_halt_status_e halt_status,
40365 + hctsiz_data_t hctsiz;
40368 + if (short_read != NULL) {
40371 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40373 + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
40374 + if (hc->ep_is_in) {
40375 + length = hc->xfer_len - hctsiz.b.xfersize;
40376 + if (short_read != NULL) {
40377 + *short_read = (hctsiz.b.xfersize != 0);
40379 + } else if (hc->qh->do_split) {
40380 + length = qtd->ssplit_out_xfer_count;
40382 + length = hc->xfer_len;
40386 + * Must use the hctsiz.pktcnt field to determine how much data
40387 + * has been transferred. This field reflects the number of
40388 + * packets that have been transferred via the USB. This is
40389 + * always an integral number of packets if the transfer was
40390 + * halted before its normal completion. (Can't use the
40391 + * hctsiz.xfersize field because that reflects the number of
40392 + * bytes transferred via the AHB, not the USB).
40395 + (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet;
40402 + * Updates the state of the URB after a Transfer Complete interrupt on the
40403 + * host channel. Updates the actual_length field of the URB based on the
40404 + * number of bytes transferred via the host channel. Sets the URB status
40405 + * if the data transfer is finished.
40407 + * @return 1 if the data transfer specified by the URB is completely finished,
40410 +static int update_urb_state_xfer_comp(dwc_hc_t * hc,
40411 + dwc_otg_hc_regs_t * hc_regs,
40412 + dwc_otg_hcd_urb_t * urb,
40413 + dwc_otg_qtd_t * qtd)
40415 + int xfer_done = 0;
40416 + int short_read = 0;
40420 + xfer_length = get_actual_xfer_length(hc, hc_regs, qtd,
40421 + DWC_OTG_HC_XFER_COMPLETE,
40425 + /* non DWORD-aligned buffer case handling. */
40426 + if (hc->align_buff && xfer_length && hc->ep_is_in) {
40427 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
40431 + urb->actual_length += xfer_length;
40433 + if (xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) &&
40434 + (urb->flags & URB_SEND_ZERO_PACKET)
40435 + && (urb->actual_length == urb->length)
40436 + && !(urb->length % hc->max_packet)) {
40438 + } else if (short_read || urb->actual_length >= urb->length) {
40445 + hctsiz_data_t hctsiz;
40446 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40447 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
40448 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
40450 + DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", hc->xfer_len);
40451 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n",
40452 + hctsiz.b.xfersize);
40453 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
40455 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
40456 + urb->actual_length);
40457 + DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n",
40458 + short_read, xfer_done);
40462 + return xfer_done;
40466 + * Save the starting data toggle for the next transfer. The data toggle is
40467 + * saved in the QH for non-control transfers and it's saved in the QTD for
40468 + * control transfers.
40470 +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
40471 + dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd)
40473 + hctsiz_data_t hctsiz;
40474 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40476 + if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
40477 + dwc_otg_qh_t *qh = hc->qh;
40478 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
40479 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
40481 + qh->data_toggle = DWC_OTG_HC_PID_DATA1;
40484 + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
40485 + qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
40487 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
40493 + * Updates the state of an Isochronous URB when the transfer is stopped for
40494 + * any reason. The fields of the current entry in the frame descriptor array
40495 + * are set based on the transfer state and the input _halt_status. Completes
40496 + * the Isochronous URB if all the URB frames have been completed.
40498 + * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be
40499 + * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
40501 +static dwc_otg_halt_status_e
40502 +update_isoc_urb_state(dwc_otg_hcd_t * hcd,
40504 + dwc_otg_hc_regs_t * hc_regs,
40505 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
40507 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40508 + dwc_otg_halt_status_e ret_val = halt_status;
40509 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
40511 + frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
40512 + switch (halt_status) {
40513 + case DWC_OTG_HC_XFER_COMPLETE:
40514 + frame_desc->status = 0;
40515 + frame_desc->actual_length =
40516 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
40518 + /* non DWORD-aligned buffer case handling. */
40519 + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
40520 + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
40521 + hc->qh->dw_align_buf, frame_desc->actual_length);
40525 + case DWC_OTG_HC_XFER_FRAME_OVERRUN:
40526 + urb->error_count++;
40527 + if (hc->ep_is_in) {
40528 + frame_desc->status = -DWC_E_NO_STREAM_RES;
40530 + frame_desc->status = -DWC_E_COMMUNICATION;
40532 + frame_desc->actual_length = 0;
40534 + case DWC_OTG_HC_XFER_BABBLE_ERR:
40535 + urb->error_count++;
40536 + frame_desc->status = -DWC_E_OVERFLOW;
40537 + /* Don't need to update actual_length in this case. */
40539 + case DWC_OTG_HC_XFER_XACT_ERR:
40540 + urb->error_count++;
40541 + frame_desc->status = -DWC_E_PROTOCOL;
40542 + frame_desc->actual_length =
40543 + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
40545 + /* non DWORD-aligned buffer case handling. */
40546 + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
40547 + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
40548 + hc->qh->dw_align_buf, frame_desc->actual_length);
40550 + /* Skip whole frame */
40551 + if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) &&
40552 + hc->ep_is_in && hcd->core_if->dma_enable) {
40553 + qtd->complete_split = 0;
40554 + qtd->isoc_split_offset = 0;
40559 + DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status);
40562 + if (++qtd->isoc_frame_index == urb->packet_count) {
40564 + * urb->status is not used for isoc transfers.
40565 + * The individual frame_desc statuses are used instead.
40567 + hcd->fops->complete(hcd, urb->priv, urb, 0);
40568 + ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
40570 + ret_val = DWC_OTG_HC_XFER_COMPLETE;
40576 + * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
40577 + * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
40578 + * still linked to the QH, the QH is added to the end of the inactive
40579 + * non-periodic schedule. For periodic QHs, removes the QH from the periodic
40580 + * schedule if no more QTDs are linked to the QH.
40582 +static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd)
40584 + int continue_split = 0;
40585 + dwc_otg_qtd_t *qtd;
40587 + DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd);
40589 + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
40591 + if (qtd->complete_split) {
40592 + continue_split = 1;
40593 + } else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
40594 + qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) {
40595 + continue_split = 1;
40599 + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
40600 + continue_split = 0;
40603 + qh->channel = NULL;
40604 + dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
40608 + * Releases a host channel for use by other transfers. Attempts to select and
40609 + * queue more transactions since at least one host channel is available.
40611 + * @param hcd The HCD state structure.
40612 + * @param hc The host channel to release.
40613 + * @param qtd The QTD associated with the host channel. This QTD may be freed
40614 + * if the transfer is complete or an error has occurred.
40615 + * @param halt_status Reason the channel is being released. This status
40616 + * determines the actions taken by this function.
40618 +static void release_channel(dwc_otg_hcd_t * hcd,
40620 + dwc_otg_qtd_t * qtd,
40621 + dwc_otg_halt_status_e halt_status)
40623 + dwc_otg_transaction_type_e tr_type;
40625 + dwc_irqflags_t flags;
40626 + dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
40628 + DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n",
40629 + __func__, hc->hc_num, halt_status, hc->xfer_len);
40631 + switch (halt_status) {
40632 + case DWC_OTG_HC_XFER_URB_COMPLETE:
40635 + case DWC_OTG_HC_XFER_AHB_ERR:
40636 + case DWC_OTG_HC_XFER_STALL:
40637 + case DWC_OTG_HC_XFER_BABBLE_ERR:
40640 + case DWC_OTG_HC_XFER_XACT_ERR:
40641 + if (qtd->error_count >= 3) {
40642 + DWC_DEBUGPL(DBG_HCDV,
40643 + " Complete URB with transaction error\n");
40645 + qtd->urb->status = -DWC_E_PROTOCOL;
40646 + hcd->fops->complete(hcd, qtd->urb->priv,
40647 + qtd->urb, -DWC_E_PROTOCOL);
40652 + case DWC_OTG_HC_XFER_URB_DEQUEUE:
40654 + * The QTD has already been removed and the QH has been
40655 + * deactivated. Don't want to do anything except release the
40656 + * host channel and try to queue more transfers.
40659 + case DWC_OTG_HC_XFER_NO_HALT_STATUS:
40662 + case DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE:
40663 + DWC_DEBUGPL(DBG_HCDV,
40664 + " Complete URB with I/O error\n");
40666 + qtd->urb->status = -DWC_E_IO;
40667 + hcd->fops->complete(hcd, qtd->urb->priv,
40668 + qtd->urb, -DWC_E_IO);
40675 + deactivate_qh(hcd, hc->qh, free_qtd);
40679 + * Release the host channel for use by other transfers. The cleanup
40680 + * function clears the channel interrupt enables and conditions, so
40681 + * there's no need to clear the Channel Halted interrupt separately.
40683 + dwc_otg_hc_cleanup(hcd->core_if, hc);
40684 + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
40686 + if (!microframe_schedule) {
40687 + switch (hc->ep_type) {
40688 + case DWC_OTG_EP_TYPE_CONTROL:
40689 + case DWC_OTG_EP_TYPE_BULK:
40690 + hcd->non_periodic_channels--;
40695 + * Don't release reservations for periodic channels here.
40696 + * That's done when a periodic transfer is descheduled (i.e.
40697 + * when the QH is removed from the periodic schedule).
40703 + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
40704 + hcd->available_host_channels++;
40705 + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
40708 + /* Try to queue more transfers now that there's a free channel. */
40709 + tr_type = dwc_otg_hcd_select_transactions(hcd);
40710 + if (tr_type != DWC_OTG_TRANSACTION_NONE) {
40711 + dwc_otg_hcd_queue_transactions(hcd, tr_type);
40713 + DWC_SPINLOCK_FREE(channel_lock);
40717 + * Halts a host channel. If the channel cannot be halted immediately because
40718 + * the request queue is full, this function ensures that the FIFO empty
40719 + * interrupt for the appropriate queue is enabled so that the halt request can
40720 + * be queued when there is space in the request queue.
40722 + * This function may also be called in DMA mode. In that case, the channel is
40723 + * simply released since the core always halts the channel automatically in
40726 +static void halt_channel(dwc_otg_hcd_t * hcd,
40728 + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
40730 + if (hcd->core_if->dma_enable) {
40731 + release_channel(hcd, hc, qtd, halt_status);
40735 + /* Slave mode processing... */
40736 + dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
40738 + if (hc->halt_on_queue) {
40739 + gintmsk_data_t gintmsk = {.d32 = 0 };
40740 + dwc_otg_core_global_regs_t *global_regs;
40741 + global_regs = hcd->core_if->core_global_regs;
40743 + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
40744 + hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
40746 + * Make sure the Non-periodic Tx FIFO empty interrupt
40747 + * is enabled so that the non-periodic schedule will
40750 + gintmsk.b.nptxfempty = 1;
40751 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
40754 + * Move the QH from the periodic queued schedule to
40755 + * the periodic assigned schedule. This allows the
40756 + * halt to be queued when the periodic schedule is
40759 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
40760 + &hc->qh->qh_list_entry);
40763 + * Make sure the Periodic Tx FIFO Empty interrupt is
40764 + * enabled so that the periodic schedule will be
40767 + gintmsk.b.ptxfempty = 1;
40768 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
40774 + * Performs common cleanup for non-periodic transfers after a Transfer
40775 + * Complete interrupt. This function should be called after any endpoint type
40776 + * specific handling is finished to release the host channel.
40778 +static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd,
40780 + dwc_otg_hc_regs_t * hc_regs,
40781 + dwc_otg_qtd_t * qtd,
40782 + dwc_otg_halt_status_e halt_status)
40784 + hcint_data_t hcint;
40786 + qtd->error_count = 0;
40788 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
40789 + if (hcint.b.nyet) {
40791 + * Got a NYET on the last transaction of the transfer. This
40792 + * means that the endpoint should be in the PING state at the
40793 + * beginning of the next transfer.
40795 + hc->qh->ping_state = 1;
40796 + clear_hc_int(hc_regs, nyet);
40800 + * Always halt and release the host channel to make it available for
40801 + * more transfers. There may still be more phases for a control
40802 + * transfer or more data packets for a bulk transfer at this point,
40803 + * but the host channel is still halted. A channel will be reassigned
40804 + * to the transfer when the non-periodic schedule is processed after
40805 + * the channel is released. This allows transactions to be queued
40806 + * properly via dwc_otg_hcd_queue_transactions, which also enables the
40807 + * Tx FIFO Empty interrupt if necessary.
40809 + if (hc->ep_is_in) {
40811 + * IN transfers in Slave mode require an explicit disable to
40812 + * halt the channel. (In DMA mode, this call simply releases
40815 + halt_channel(hcd, hc, qtd, halt_status);
40818 + * The channel is automatically disabled by the core for OUT
40819 + * transfers in Slave mode.
40821 + release_channel(hcd, hc, qtd, halt_status);
40826 + * Performs common cleanup for periodic transfers after a Transfer Complete
40827 + * interrupt. This function should be called after any endpoint type specific
40828 + * handling is finished to release the host channel.
40830 +static void complete_periodic_xfer(dwc_otg_hcd_t * hcd,
40832 + dwc_otg_hc_regs_t * hc_regs,
40833 + dwc_otg_qtd_t * qtd,
40834 + dwc_otg_halt_status_e halt_status)
40836 + hctsiz_data_t hctsiz;
40837 + qtd->error_count = 0;
40839 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
40840 + if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) {
40841 + /* Core halts channel in these cases. */
40842 + release_channel(hcd, hc, qtd, halt_status);
40844 + /* Flush any outstanding requests from the Tx queue. */
40845 + halt_channel(hcd, hc, qtd, halt_status);
40849 +static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd,
40851 + dwc_otg_hc_regs_t * hc_regs,
40852 + dwc_otg_qtd_t * qtd)
40855 + struct dwc_otg_hcd_iso_packet_desc *frame_desc;
40856 + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
40858 + len = get_actual_xfer_length(hc, hc_regs, qtd,
40859 + DWC_OTG_HC_XFER_COMPLETE, NULL);
40862 + qtd->complete_split = 0;
40863 + qtd->isoc_split_offset = 0;
40866 + frame_desc->actual_length += len;
40868 + if (hc->align_buff && len)
40869 + dwc_memcpy(qtd->urb->buf + frame_desc->offset +
40870 + qtd->isoc_split_offset, hc->qh->dw_align_buf, len);
40871 + qtd->isoc_split_offset += len;
40873 + if (frame_desc->length == frame_desc->actual_length) {
40874 + frame_desc->status = 0;
40875 + qtd->isoc_frame_index++;
40876 + qtd->complete_split = 0;
40877 + qtd->isoc_split_offset = 0;
40880 + if (qtd->isoc_frame_index == qtd->urb->packet_count) {
40881 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
40882 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
40884 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
40887 + return 1; /* Indicates that channel released */
40891 + * Handles a host channel Transfer Complete interrupt. This handler may be
40892 + * called in either DMA mode or Slave mode.
40894 +static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd,
40896 + dwc_otg_hc_regs_t * hc_regs,
40897 + dwc_otg_qtd_t * qtd)
40899 + int urb_xfer_done;
40900 + dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;
40901 + dwc_otg_hcd_urb_t *urb = qtd->urb;
40902 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
40904 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
40905 + "Transfer Complete--\n", hc->hc_num);
40907 + if (hcd->core_if->dma_desc_enable) {
40908 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status);
40909 + if (pipe_type == UE_ISOCHRONOUS) {
40910 + /* Do not disable the interrupt, just clear it */
40911 + clear_hc_int(hc_regs, xfercomp);
40914 + goto handle_xfercomp_done;
40918 + * Handle xfer complete on CSPLIT.
40921 + if (hc->qh->do_split) {
40922 + if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in
40923 + && hcd->core_if->dma_enable) {
40924 + if (qtd->complete_split
40925 + && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs,
40927 + goto handle_xfercomp_done;
40929 + qtd->complete_split = 0;
40933 + /* Update the QTD and URB states. */
40934 + switch (pipe_type) {
40936 + switch (qtd->control_phase) {
40937 + case DWC_OTG_CONTROL_SETUP:
40938 + if (urb->length > 0) {
40939 + qtd->control_phase = DWC_OTG_CONTROL_DATA;
40941 + qtd->control_phase = DWC_OTG_CONTROL_STATUS;
40943 + DWC_DEBUGPL(DBG_HCDV,
40944 + " Control setup transaction done\n");
40945 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40947 + case DWC_OTG_CONTROL_DATA:{
40949 + update_urb_state_xfer_comp(hc, hc_regs, urb,
40951 + if (urb_xfer_done) {
40952 + qtd->control_phase =
40953 + DWC_OTG_CONTROL_STATUS;
40954 + DWC_DEBUGPL(DBG_HCDV,
40955 + " Control data transfer done\n");
40957 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40959 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40962 + case DWC_OTG_CONTROL_STATUS:
40963 + DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n");
40964 + if (urb->status == -DWC_E_IN_PROGRESS) {
40967 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40968 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40972 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40975 + DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n");
40977 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
40978 + if (urb_xfer_done) {
40979 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40980 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
40982 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
40985 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
40986 + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
40988 + case UE_INTERRUPT:
40989 + DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n");
40991 + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
40994 + * Interrupt URB is done on the first transfer complete
40997 + if (urb_xfer_done) {
40998 + hcd->fops->complete(hcd, urb->priv, urb, urb->status);
40999 + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
41001 + halt_status = DWC_OTG_HC_XFER_COMPLETE;
41004 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41005 + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
41007 + case UE_ISOCHRONOUS:
41008 + DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n");
41009 + if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {
41011 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41012 + DWC_OTG_HC_XFER_COMPLETE);
41014 + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
41018 +handle_xfercomp_done:
41019 + disable_hc_int(hc_regs, xfercompl);
41025 + * Handles a host channel STALL interrupt. This handler may be called in
41026 + * either DMA mode or Slave mode.
41028 +static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd,
41030 + dwc_otg_hc_regs_t * hc_regs,
41031 + dwc_otg_qtd_t * qtd)
41033 + dwc_otg_hcd_urb_t *urb = qtd->urb;
41034 + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
41036 + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
41037 + "STALL Received--\n", hc->hc_num);
41039 + if (hcd->core_if->dma_desc_enable) {
41040 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL);
41041 + goto handle_stall_done;
41044 + if (pipe_type == UE_CONTROL) {
41045 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
41048 + if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) {
41049 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
41051 + * USB protocol requires resetting the data toggle for bulk
41052 + * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
41053 + * setup command is issued to the endpoint. Anticipate the
41054 + * CLEAR_FEATURE command since a STALL has occurred and reset
41055 + * the data toggle now.
41057 + hc->qh->data_toggle = 0;
41060 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL);
41062 +handle_stall_done:
41063 + disable_hc_int(hc_regs, stall);
41069 + * Updates the state of the URB when a transfer has been stopped due to an
41070 + * abnormal condition before the transfer completes. Modifies the
41071 + * actual_length field of the URB to reflect the number of bytes that have
41072 + * actually been transferred via the host channel.
41074 +static void update_urb_state_xfer_intr(dwc_hc_t * hc,
41075 + dwc_otg_hc_regs_t * hc_regs,
41076 + dwc_otg_hcd_urb_t * urb,
41077 + dwc_otg_qtd_t * qtd,
41078 + dwc_otg_halt_status_e halt_status)
41080 + uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
41081 + halt_status, NULL);
41082 + /* non DWORD-aligned buffer case handling. */
41083 + if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
41084 + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
41085 + bytes_transferred);
41088 + urb->actual_length += bytes_transferred;
41092 + hctsiz_data_t hctsiz;
41093 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41094 + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
41095 + __func__, (hc->ep_is_in ? "IN" : "OUT"),
41097 + DWC_DEBUGPL(DBG_HCDV, " hc->start_pkt_count %d\n",
41098 + hc->start_pkt_count);
41099 + DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
41100 + DWC_DEBUGPL(DBG_HCDV, " hc->max_packet %d\n", hc->max_packet);
41101 + DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n",
41102 + bytes_transferred);
41103 + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
41104 + urb->actual_length);
41105 + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
41112 + * Handles a host channel NAK interrupt. This handler may be called in either
41113 + * DMA mode or Slave mode.
41115 +static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
41117 + dwc_otg_hc_regs_t * hc_regs,
41118 + dwc_otg_qtd_t * qtd)
41120 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41121 + "NAK Received--\n", hc->hc_num);
41124 + * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
41125 + * interrupt. Re-start the SSPLIT transfer.
41127 + if (hc->do_split) {
41128 + if (hc->complete_split) {
41129 + qtd->error_count = 0;
41131 + qtd->complete_split = 0;
41132 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
41133 + goto handle_nak_done;
41136 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41139 + if (hcd->core_if->dma_enable && hc->ep_is_in) {
41141 + * NAK interrupts are enabled on bulk/control IN
41142 + * transfers in DMA mode for the sole purpose of
41143 + * resetting the error count after a transaction error
41144 + * occurs. The core will continue transferring data.
41146 + qtd->error_count = 0;
41147 + goto handle_nak_done;
41151 + * NAK interrupts normally occur during OUT transfers in DMA
41152 + * or Slave mode. For IN transfers, more requests will be
41153 + * queued as request queue space is available.
41155 + qtd->error_count = 0;
41157 + if (!hc->qh->ping_state) {
41158 + update_urb_state_xfer_intr(hc, hc_regs,
41160 + DWC_OTG_HC_XFER_NAK);
41161 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41163 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH)
41164 + hc->qh->ping_state = 1;
41168 + * Halt the channel so the transfer can be re-started from
41169 + * the appropriate point or the PING protocol will
41170 + * start/continue.
41172 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
41174 + case UE_INTERRUPT:
41175 + qtd->error_count = 0;
41176 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
41178 + case UE_ISOCHRONOUS:
41179 + /* Should never get called for isochronous transfers. */
41180 + DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n");
41185 + disable_hc_int(hc_regs, nak);
41191 + * Handles a host channel ACK interrupt. This interrupt is enabled when
41192 + * performing the PING protocol in Slave mode, when errors occur during
41193 + * either Slave mode or DMA mode, and during Start Split transactions.
41195 +static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd,
41197 + dwc_otg_hc_regs_t * hc_regs,
41198 + dwc_otg_qtd_t * qtd)
41200 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41201 + "ACK Received--\n", hc->hc_num);
41203 + if (hc->do_split) {
41205 + * Handle ACK on SSPLIT.
41206 + * ACK should not occur in CSPLIT.
41208 + if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) {
41209 + qtd->ssplit_out_xfer_count = hc->xfer_len;
41211 + if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) {
41212 + /* Don't need complete for isochronous out transfers. */
41213 + qtd->complete_split = 1;
41217 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
41218 + switch (hc->xact_pos) {
41219 + case DWC_HCSPLIT_XACTPOS_ALL:
41221 + case DWC_HCSPLIT_XACTPOS_END:
41222 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
41223 + qtd->isoc_split_offset = 0;
41225 + case DWC_HCSPLIT_XACTPOS_BEGIN:
41226 + case DWC_HCSPLIT_XACTPOS_MID:
41228 + * For BEGIN or MID, calculate the length for
41229 + * the next microframe to determine the correct
41230 + * SSPLIT token, either MID or END.
41233 + struct dwc_otg_hcd_iso_packet_desc
41238 + iso_descs[qtd->isoc_frame_index];
41239 + qtd->isoc_split_offset += 188;
41241 + if ((frame_desc->length -
41242 + qtd->isoc_split_offset) <= 188) {
41243 + qtd->isoc_split_pos =
41244 + DWC_HCSPLIT_XACTPOS_END;
41246 + qtd->isoc_split_pos =
41247 + DWC_HCSPLIT_XACTPOS_MID;
41254 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
41257 + qtd->error_count = 0;
41259 + if (hc->qh->ping_state) {
41260 + hc->qh->ping_state = 0;
41262 + * Halt the channel so the transfer can be re-started
41263 + * from the appropriate point. This only happens in
41264 + * Slave mode. In DMA mode, the ping_state is cleared
41265 + * when the transfer is started because the core
41266 + * automatically executes the PING, then the transfer.
41268 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
41273 + * If the ACK occurred when _not_ in the PING state, let the channel
41274 + * continue transferring data after clearing the error count.
41277 + disable_hc_int(hc_regs, ack);
41283 + * Handles a host channel NYET interrupt. This interrupt should only occur on
41284 + * Bulk and Control OUT endpoints and for complete split transactions. If a
41285 + * NYET occurs at the same time as a Transfer Complete interrupt, it is
41286 + * handled in the xfercomp interrupt handler, not here. This handler may be
41287 + * called in either DMA mode or Slave mode.
41289 +static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
41291 + dwc_otg_hc_regs_t * hc_regs,
41292 + dwc_otg_qtd_t * qtd)
41294 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41295 + "NYET Received--\n", hc->hc_num);
41299 + * re-do the CSPLIT immediately on non-periodic
41301 + if (hc->do_split && hc->complete_split) {
41302 + if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
41303 + && hcd->core_if->dma_enable) {
41304 + qtd->complete_split = 0;
41305 + qtd->isoc_split_offset = 0;
41306 + if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
41307 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
41308 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
41311 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
41312 + goto handle_nyet_done;
41315 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
41316 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
41317 + int frnum = dwc_otg_hcd_get_frame_number(hcd);
41319 + if (dwc_full_frame_num(frnum) !=
41320 + dwc_full_frame_num(hc->qh->sched_frame)) {
41322 + * No longer in the same full speed frame.
41323 + * Treat this as a transaction error.
41326 + /** @todo Fix system performance so this can
41327 + * be treated as an error. Right now complete
41328 + * splits cannot be scheduled precisely enough
41329 + * due to other system activity, so this error
41330 + * occurs regularly in Slave mode.
41332 + qtd->error_count++;
41334 + qtd->complete_split = 0;
41335 + halt_channel(hcd, hc, qtd,
41336 + DWC_OTG_HC_XFER_XACT_ERR);
41337 + /** @todo add support for isoc release */
41338 + goto handle_nyet_done;
41342 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
41343 + goto handle_nyet_done;
41346 + hc->qh->ping_state = 1;
41347 + qtd->error_count = 0;
41349 + update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd,
41350 + DWC_OTG_HC_XFER_NYET);
41351 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41354 + * Halt the channel and re-start the transfer so the PING
41355 + * protocol will start.
41357 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
41360 + disable_hc_int(hc_regs, nyet);
41365 + * Handles a host channel babble interrupt. This handler may be called in
41366 + * either DMA mode or Slave mode.
41368 +static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd,
41370 + dwc_otg_hc_regs_t * hc_regs,
41371 + dwc_otg_qtd_t * qtd)
41373 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41374 + "Babble Error--\n", hc->hc_num);
41376 + if (hcd->core_if->dma_desc_enable) {
41377 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41378 + DWC_OTG_HC_XFER_BABBLE_ERR);
41379 + goto handle_babble_done;
41382 + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
41383 + hcd->fops->complete(hcd, qtd->urb->priv,
41384 + qtd->urb, -DWC_E_OVERFLOW);
41385 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
41387 + dwc_otg_halt_status_e halt_status;
41388 + halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41389 + DWC_OTG_HC_XFER_BABBLE_ERR);
41390 + halt_channel(hcd, hc, qtd, halt_status);
41393 +handle_babble_done:
41394 + disable_hc_int(hc_regs, bblerr);
41399 + * Handles a host channel AHB error interrupt. This handler is only called in
41402 +static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd,
41404 + dwc_otg_hc_regs_t * hc_regs,
41405 + dwc_otg_qtd_t * qtd)
41407 + hcchar_data_t hcchar;
41408 + hcsplt_data_t hcsplt;
41409 + hctsiz_data_t hctsiz;
41411 + char *pipetype, *speed;
41413 + dwc_otg_hcd_urb_t *urb = qtd->urb;
41415 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41416 + "AHB Error--\n", hc->hc_num);
41418 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41419 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
41420 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41421 + hcdma = DWC_READ_REG32(&hc_regs->hcdma);
41423 + DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num);
41424 + DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
41425 + DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
41426 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
41427 + DWC_ERROR(" Device address: %d\n",
41428 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
41429 + DWC_ERROR(" Endpoint: %d, %s\n",
41430 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
41431 + (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"));
41433 + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
41435 + pipetype = "CONTROL";
41438 + pipetype = "BULK";
41440 + case UE_INTERRUPT:
41441 + pipetype = "INTERRUPT";
41443 + case UE_ISOCHRONOUS:
41444 + pipetype = "ISOCHRONOUS";
41447 + pipetype = "UNKNOWN";
41451 + DWC_ERROR(" Endpoint type: %s\n", pipetype);
41453 + switch (hc->speed) {
41454 + case DWC_OTG_EP_SPEED_HIGH:
41457 + case DWC_OTG_EP_SPEED_FULL:
41460 + case DWC_OTG_EP_SPEED_LOW:
41464 + speed = "UNKNOWN";
41468 + DWC_ERROR(" Speed: %s\n", speed);
41470 + DWC_ERROR(" Max packet size: %d\n",
41471 + dwc_otg_hcd_get_mps(&urb->pipe_info));
41472 + DWC_ERROR(" Data buffer length: %d\n", urb->length);
41473 + DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n",
41474 + urb->buf, (void *)urb->dma);
41475 + DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n",
41476 + urb->setup_packet, (void *)urb->setup_dma);
41477 + DWC_ERROR(" Interval: %d\n", urb->interval);
41479 + /* Core haltes the channel for Descriptor DMA mode */
41480 + if (hcd->core_if->dma_desc_enable) {
41481 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41482 + DWC_OTG_HC_XFER_AHB_ERR);
41483 + goto handle_ahberr_done;
41486 + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO);
41489 + * Force a channel halt. Don't call halt_channel because that won't
41490 + * write to the HCCHARn register in DMA mode to force the halt.
41492 + dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
41493 +handle_ahberr_done:
41494 + disable_hc_int(hc_regs, ahberr);
41499 + * Handles a host channel transaction error interrupt. This handler may be
41500 + * called in either DMA mode or Slave mode.
41502 +static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd,
41504 + dwc_otg_hc_regs_t * hc_regs,
41505 + dwc_otg_qtd_t * qtd)
41507 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41508 + "Transaction Error--\n", hc->hc_num);
41510 + if (hcd->core_if->dma_desc_enable) {
41511 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41512 + DWC_OTG_HC_XFER_XACT_ERR);
41513 + goto handle_xacterr_done;
41516 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41519 + qtd->error_count++;
41520 + if (!hc->qh->ping_state) {
41522 + update_urb_state_xfer_intr(hc, hc_regs,
41524 + DWC_OTG_HC_XFER_XACT_ERR);
41525 + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
41526 + if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) {
41527 + hc->qh->ping_state = 1;
41532 + * Halt the channel so the transfer can be re-started from
41533 + * the appropriate point or the PING protocol will start.
41535 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41537 + case UE_INTERRUPT:
41538 + qtd->error_count++;
41539 + if (hc->do_split && hc->complete_split) {
41540 + qtd->complete_split = 0;
41542 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
41544 + case UE_ISOCHRONOUS:
41546 + dwc_otg_halt_status_e halt_status;
41548 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41549 + DWC_OTG_HC_XFER_XACT_ERR);
41551 + halt_channel(hcd, hc, qtd, halt_status);
41555 +handle_xacterr_done:
41556 + disable_hc_int(hc_regs, xacterr);
41562 + * Handles a host channel frame overrun interrupt. This handler may be called
41563 + * in either DMA mode or Slave mode.
41565 +static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd,
41567 + dwc_otg_hc_regs_t * hc_regs,
41568 + dwc_otg_qtd_t * qtd)
41570 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41571 + "Frame Overrun--\n", hc->hc_num);
41573 + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
41577 + case UE_INTERRUPT:
41578 + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
41580 + case UE_ISOCHRONOUS:
41582 + dwc_otg_halt_status_e halt_status;
41584 + update_isoc_urb_state(hcd, hc, hc_regs, qtd,
41585 + DWC_OTG_HC_XFER_FRAME_OVERRUN);
41587 + halt_channel(hcd, hc, qtd, halt_status);
41592 + disable_hc_int(hc_regs, frmovrun);
41598 + * Handles a host channel data toggle error interrupt. This handler may be
41599 + * called in either DMA mode or Slave mode.
41601 +static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd,
41603 + dwc_otg_hc_regs_t * hc_regs,
41604 + dwc_otg_qtd_t * qtd)
41606 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41607 + "Data Toggle Error--\n", hc->hc_num);
41609 + if (hc->ep_is_in) {
41610 + qtd->error_count = 0;
41612 + DWC_ERROR("Data Toggle Error on OUT transfer,"
41613 + "channel %d\n", hc->hc_num);
41616 + disable_hc_int(hc_regs, datatglerr);
41623 + * This function is for debug only. It checks that a valid halt status is set
41624 + * and that HCCHARn.chdis is clear. If there's a problem, corrective action is
41625 + * taken and a warning is issued.
41626 + * @return 1 if halt status is ok, 0 otherwise.
41628 +static inline int halt_status_ok(dwc_otg_hcd_t * hcd,
41630 + dwc_otg_hc_regs_t * hc_regs,
41631 + dwc_otg_qtd_t * qtd)
41633 + hcchar_data_t hcchar;
41634 + hctsiz_data_t hctsiz;
41635 + hcint_data_t hcint;
41636 + hcintmsk_data_t hcintmsk;
41637 + hcsplt_data_t hcsplt;
41639 + if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
41641 + * This code is here only as a check. This condition should
41642 + * never happen. Ignore the halt if it does occur.
41644 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41645 + hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
41646 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41647 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41648 + hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
41650 + ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
41651 + "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
41652 + "hcint 0x%08x, hcintmsk 0x%08x, "
41653 + "hcsplt 0x%08x, qtd->complete_split %d\n", __func__,
41654 + hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32,
41655 + hcintmsk.d32, hcsplt.d32, qtd->complete_split);
41657 + DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
41658 + __func__, hc->hc_num);
41660 + clear_hc_int(hc_regs, chhltd);
41665 + * This code is here only as a check. hcchar.chdis should
41666 + * never be set when the halt interrupt occurs. Halt the
41667 + * channel again if it does occur.
41669 + hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
41670 + if (hcchar.b.chdis) {
41671 + DWC_WARN("%s: hcchar.chdis set unexpectedly, "
41672 + "hcchar 0x%08x, trying to halt again\n",
41673 + __func__, hcchar.d32);
41674 + clear_hc_int(hc_regs, chhltd);
41675 + hc->halt_pending = 0;
41676 + halt_channel(hcd, hc, qtd, hc->halt_status);
41685 + * Handles a host Channel Halted interrupt in DMA mode. This handler
41686 + * determines the reason the channel halted and proceeds accordingly.
41688 +static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
41690 + dwc_otg_hc_regs_t * hc_regs,
41691 + dwc_otg_qtd_t * qtd)
41693 + hcint_data_t hcint;
41694 + hcintmsk_data_t hcintmsk;
41695 + int out_nak_enh = 0;
41697 + /* For core with OUT NAK enhancement, the flow for high-
41698 + * speed CONTROL/BULK OUT is handled a little differently.
41700 + if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) {
41701 + if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in &&
41702 + (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
41703 + hc->ep_type == DWC_OTG_EP_TYPE_BULK)) {
41708 + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
41709 + (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR
41710 + && !hcd->core_if->dma_desc_enable)) {
41712 + * Just release the channel. A dequeue can happen on a
41713 + * transfer timeout. In the case of an AHB Error, the channel
41714 + * was forced to halt because there's no way to gracefully
41717 + if (hcd->core_if->dma_desc_enable)
41718 + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
41719 + hc->halt_status);
41721 + release_channel(hcd, hc, qtd, hc->halt_status);
41725 + /* Read the HCINTn register to determine the cause for the halt. */
41726 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41727 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41729 + if (hcint.b.xfercomp) {
41730 + /** @todo This is here because of a possible hardware bug. Spec
41731 + * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
41732 + * interrupt w/ACK bit set should occur, but I only see the
41733 + * XFERCOMP bit, even with it masked out. This is a workaround
41734 + * for that behavior. Should fix this when hardware is fixed.
41736 + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
41737 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
41739 + handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
41740 + } else if (hcint.b.stall) {
41741 + handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
41742 + } else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) {
41743 + if (out_nak_enh) {
41744 + if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) {
41745 + DWC_DEBUGPL(DBG_HCD, "XactErr with NYET/NAK/ACK\n");
41746 + qtd->error_count = 0;
41748 + DWC_DEBUGPL(DBG_HCD, "XactErr without NYET/NAK/ACK\n");
41753 + * Must handle xacterr before nak or ack. Could get a xacterr
41754 + * at the same time as either of these on a BULK/CONTROL OUT
41755 + * that started with a PING. The xacterr takes precedence.
41757 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
41758 + } else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) {
41759 + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
41760 + } else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) {
41761 + handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
41762 + } else if (hcint.b.bblerr) {
41763 + handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
41764 + } else if (hcint.b.frmovrun) {
41765 + handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
41766 + } else if (!out_nak_enh) {
41767 + if (hcint.b.nyet) {
41769 + * Must handle nyet before nak or ack. Could get a nyet at the
41770 + * same time as either of those on a BULK/CONTROL OUT that
41771 + * started with a PING. The nyet takes precedence.
41773 + handle_hc_nyet_intr(hcd, hc, hc_regs, qtd);
41774 + } else if (hcint.b.nak && !hcintmsk.b.nak) {
41776 + * If nak is not masked, it's because a non-split IN transfer
41777 + * is in an error state. In that case, the nak is handled by
41778 + * the nak interrupt handler, not here. Handle nak here for
41779 + * BULK/CONTROL OUT transfers, which halt on a NAK to allow
41780 + * rewinding the buffer pointer.
41782 + handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
41783 + } else if (hcint.b.ack && !hcintmsk.b.ack) {
41785 + * If ack is not masked, it's because a non-split IN transfer
41786 + * is in an error state. In that case, the ack is handled by
41787 + * the ack interrupt handler, not here. Handle ack here for
41788 + * split transfers. Start splits halt on ACK.
41790 + handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
41792 + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
41793 + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
41795 + * A periodic transfer halted with no other channel
41796 + * interrupts set. Assume it was halted by the core
41797 + * because it could not be completed in its scheduled
41802 + ("%s: Halt channel %d (assume incomplete periodic transfer)\n",
41803 + __func__, hc->hc_num);
41805 + halt_channel(hcd, hc, qtd,
41806 + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
41809 + ("%s: Channel %d, DMA Mode -- ChHltd set, but reason "
41810 + "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
41811 + __func__, hc->hc_num, hcint.d32,
41812 + DWC_READ_REG32(&hcd->
41813 + core_if->core_global_regs->
41819 + DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n",
41825 + * Handles a host channel Channel Halted interrupt.
41827 + * In slave mode, this handler is called only when the driver specifically
41828 + * requests a halt. This occurs during handling other host channel interrupts
41829 + * (e.g. nak, xacterr, stall, nyet, etc.).
41831 + * In DMA mode, this is the interrupt that occurs when the core has finished
41832 + * processing a transfer on a channel. Other host channel interrupts (except
41833 + * ahberr) are disabled in DMA mode.
41835 +static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
41837 + dwc_otg_hc_regs_t * hc_regs,
41838 + dwc_otg_qtd_t * qtd)
41840 + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
41841 + "Channel Halted--\n", hc->hc_num);
41843 + if (hcd->core_if->dma_enable) {
41844 + handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd);
41847 + if (!halt_status_ok(hcd, hc, hc_regs, qtd)) {
41851 + release_channel(hcd, hc, qtd, hc->halt_status);
41857 +/** Handles interrupt for a specific Host Channel */
41858 +int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
41861 + hcint_data_t hcint;
41862 + hcintmsk_data_t hcintmsk;
41864 + dwc_otg_hc_regs_t *hc_regs;
41865 + dwc_otg_qtd_t *qtd;
41867 + DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num);
41869 + hc = dwc_otg_hcd->hc_ptr_array[num];
41870 + hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
41871 + qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
41873 + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
41874 + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
41875 + DWC_DEBUGPL(DBG_HCDV,
41876 + " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
41877 + hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
41878 + hcint.d32 = hcint.d32 & hcintmsk.d32;
41880 + if (!dwc_otg_hcd->core_if->dma_enable) {
41881 + if (hcint.b.chhltd && hcint.d32 != 0x2) {
41882 + hcint.b.chhltd = 0;
41886 + if (hcint.b.xfercomp) {
41888 + handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41890 + * If NYET occurred at same time as Xfer Complete, the NYET is
41891 + * handled by the Xfer Complete interrupt handler. Don't want
41892 + * to call the NYET interrupt handler in this case.
41894 + hcint.b.nyet = 0;
41896 + if (hcint.b.chhltd) {
41897 + retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41899 + if (hcint.b.ahberr) {
41900 + retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41902 + if (hcint.b.stall) {
41903 + retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41905 + if (hcint.b.nak) {
41906 + retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41908 + if (hcint.b.ack) {
41909 + retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41911 + if (hcint.b.nyet) {
41912 + retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41914 + if (hcint.b.xacterr) {
41915 + retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41917 + if (hcint.b.bblerr) {
41918 + retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41920 + if (hcint.b.frmovrun) {
41922 + handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41924 + if (hcint.b.datatglerr) {
41926 + handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
41932 +#endif /* DWC_DEVICE_ONLY */
41933 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
41934 new file mode 100644
41935 index 0000000..4a985a6
41937 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
41939 +/* ==========================================================================
41940 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
41941 + * $Revision: #20 $
41942 + * $Date: 2011/10/26 $
41943 + * $Change: 1872981 $
41945 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
41946 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
41947 + * otherwise expressly agreed to in writing between Synopsys and you.
41949 + * The Software IS NOT an item of Licensed Software or Licensed Product under
41950 + * any End User Software License Agreement or Agreement for Licensed Product
41951 + * with Synopsys or any supplement thereto. You are permitted to use and
41952 + * redistribute this Software in source and binary forms, with or without
41953 + * modification, provided that redistributions of source code must retain this
41954 + * notice. You may not view, use, disclose, copy or distribute this file or
41955 + * any information contained herein except pursuant to this license grant from
41956 + * Synopsys. If you do not agree with this notice, including the disclaimer
41957 + * below, then you are not authorized to use the Software.
41959 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
41960 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41961 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41962 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
41963 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41964 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41965 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
41966 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41967 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41968 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
41970 + * ========================================================================== */
41971 +#ifndef DWC_DEVICE_ONLY
41976 + * This file contains the implementation of the HCD. In Linux, the HCD
41977 + * implements the hc_driver API.
41979 +#include <linux/kernel.h>
41980 +#include <linux/module.h>
41981 +#include <linux/moduleparam.h>
41982 +#include <linux/init.h>
41983 +#include <linux/device.h>
41984 +#include <linux/errno.h>
41985 +#include <linux/list.h>
41986 +#include <linux/interrupt.h>
41987 +#include <linux/string.h>
41988 +#include <linux/dma-mapping.h>
41989 +#include <linux/version.h>
41990 +#include <asm/io.h>
41991 +#include <linux/usb.h>
41992 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
41993 +#include <../drivers/usb/core/hcd.h>
41995 +#include <linux/usb/hcd.h>
41998 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
41999 +#define USB_URB_EP_LINKING 1
42001 +#define USB_URB_EP_LINKING 0
42004 +#include "dwc_otg_hcd_if.h"
42005 +#include "dwc_otg_dbg.h"
42006 +#include "dwc_otg_driver.h"
42007 +#include "dwc_otg_hcd.h"
42009 + * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
42010 + * qualified with its direction (possible 32 endpoints per device).
42012 +#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
42013 + ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
42015 +static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
42017 +/** @name Linux HC Driver API Functions */
42019 +/* manage i/o requests, device state */
42020 +static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
42021 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42022 + struct usb_host_endpoint *ep,
42024 + struct urb *urb, gfp_t mem_flags);
42026 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
42027 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42028 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
42030 +#else /* kernels at or post 2.6.30 */
42031 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd,
42032 + struct urb *urb, int status);
42033 +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) */
42035 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
42036 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
42037 +static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
42039 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
42040 +extern int hcd_start(struct usb_hcd *hcd);
42041 +extern void hcd_stop(struct usb_hcd *hcd);
42042 +static int get_frame_number(struct usb_hcd *hcd);
42043 +extern int hub_status_data(struct usb_hcd *hcd, char *buf);
42044 +extern int hub_control(struct usb_hcd *hcd,
42046 + u16 wValue, u16 wIndex, char *buf, u16 wLength);
42048 +struct wrapper_priv_data {
42049 + dwc_otg_hcd_t *dwc_otg_hcd;
42054 +static struct hc_driver dwc_otg_hc_driver = {
42056 + .description = dwc_otg_hcd_name,
42057 + .product_desc = "DWC OTG Controller",
42058 + .hcd_priv_size = sizeof(struct wrapper_priv_data),
42060 + .irq = dwc_otg_hcd_irq,
42062 + .flags = HCD_MEMORY | HCD_USB2,
42065 + .start = hcd_start,
42068 + .stop = hcd_stop,
42070 + .urb_enqueue = dwc_otg_urb_enqueue,
42071 + .urb_dequeue = dwc_otg_urb_dequeue,
42072 + .endpoint_disable = endpoint_disable,
42073 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
42074 + .endpoint_reset = endpoint_reset,
42076 + .get_frame_number = get_frame_number,
42078 + .hub_status_data = hub_status_data,
42079 + .hub_control = hub_control,
42084 +/** Gets the dwc_otg_hcd from a struct usb_hcd */
42085 +static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
42087 + struct wrapper_priv_data *p;
42088 + p = (struct wrapper_priv_data *)(hcd->hcd_priv);
42089 + return p->dwc_otg_hcd;
42092 +/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
42093 +static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
42095 + return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
42098 +/** Gets the usb_host_endpoint associated with an URB. */
42099 +inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
42101 + struct usb_device *dev = urb->dev;
42102 + int ep_num = usb_pipeendpoint(urb->pipe);
42104 + if (usb_pipein(urb->pipe))
42105 + return dev->ep_in[ep_num];
42107 + return dev->ep_out[ep_num];
42110 +static int _disconnect(dwc_otg_hcd_t * hcd)
42112 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
42114 + usb_hcd->self.is_b_host = 0;
42118 +static int _start(dwc_otg_hcd_t * hcd)
42120 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
42122 + usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
42123 + hcd_start(usb_hcd);
42128 +static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
42129 + uint32_t * port_addr)
42131 + struct urb *urb = (struct urb *)urb_handle;
42132 + struct usb_bus *bus;
42133 +#if 1 //GRAYG - temporary
42134 + if (NULL == urb_handle)
42135 + DWC_ERROR("**** %s - NULL URB handle\n", __func__);//GRAYG
42136 + if (NULL == urb->dev)
42137 + DWC_ERROR("**** %s - URB has no device\n", __func__);//GRAYG
42138 + if (NULL == port_addr)
42139 + DWC_ERROR("**** %s - NULL port_address\n", __func__);//GRAYG
42141 + if (urb->dev->tt) {
42142 + if (NULL == urb->dev->tt->hub) {
42143 + DWC_ERROR("**** %s - (URB's transactor has no TT - giving no hub)\n",
42144 + __func__); //GRAYG
42145 + //*hub_addr = (u8)usb_pipedevice(urb->pipe); //GRAYG
42146 + *hub_addr = 0; //GRAYG
42147 + // we probably shouldn't have a transaction translator if
42148 + // there's no associated hub?
42150 + bus = hcd_to_bus(dwc_otg_hcd_to_hcd(hcd));
42151 + if (urb->dev->tt->hub == bus->root_hub)
42154 + *hub_addr = urb->dev->tt->hub->devnum;
42156 + *port_addr = urb->dev->tt->multi ? urb->dev->ttport : 1;
42159 + *port_addr = urb->dev->ttport;
42164 +static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
42166 + struct urb *urb = (struct urb *)urb_handle;
42167 + return urb->dev->speed;
42170 +static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
42172 + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
42173 + return usb_hcd->self.b_hnp_enable;
42176 +static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
42179 + hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
42180 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42181 + hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
42183 + hcd_to_bus(hcd)->bandwidth_int_reqs++;
42187 +static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
42190 + hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
42191 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42192 + hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
42194 + hcd_to_bus(hcd)->bandwidth_int_reqs--;
42199 + * Sets the final status of an URB and returns it to the device driver. Any
42200 + * required cleanup of the URB is performed.
42202 +static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
42203 + dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
42205 + struct urb *urb = (struct urb *)urb_handle;
42207 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42208 + DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
42209 + __func__, urb, usb_pipedevice(urb->pipe),
42210 + usb_pipeendpoint(urb->pipe),
42211 + usb_pipein(urb->pipe) ? "IN" : "OUT", status);
42212 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42214 + for (i = 0; i < urb->number_of_packets; i++) {
42215 + DWC_PRINTF(" ISO Desc %d status: %d\n",
42216 + i, urb->iso_frame_desc[i].status);
42221 + urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
42222 + /* Convert status value. */
42223 + switch (status) {
42224 + case -DWC_E_PROTOCOL:
42225 + status = -EPROTO;
42227 + case -DWC_E_IN_PROGRESS:
42228 + status = -EINPROGRESS;
42230 + case -DWC_E_PIPE:
42236 + case -DWC_E_TIMEOUT:
42237 + status = -ETIMEDOUT;
42239 + case -DWC_E_OVERFLOW:
42240 + status = -EOVERFLOW;
42244 + DWC_PRINTF("Uknown urb status %d\n", status);
42249 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42252 + urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
42253 + for (i = 0; i < urb->number_of_packets; ++i) {
42254 + urb->iso_frame_desc[i].actual_length =
42255 + dwc_otg_hcd_urb_get_iso_desc_actual_length
42256 + (dwc_otg_urb, i);
42257 + urb->iso_frame_desc[i].status =
42258 + dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
42262 + urb->status = status;
42263 + urb->hcpriv = NULL;
42265 + if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
42266 + (urb->actual_length < urb->transfer_buffer_length)) {
42267 + urb->status = -EREMOTEIO;
42271 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
42272 + (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
42273 + struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
42275 + free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
42276 + dwc_otg_hcd_get_ep_bandwidth(hcd,
42282 + DWC_FREE(dwc_otg_urb);
42284 +#if USB_URB_EP_LINKING
42285 + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
42287 + DWC_SPINUNLOCK(hcd->lock);
42288 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42289 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
42291 + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
42293 + DWC_SPINLOCK(hcd->lock);
42298 +static struct dwc_otg_hcd_function_ops hcd_fops = {
42300 + .disconnect = _disconnect,
42301 + .hub_info = _hub_info,
42303 + .complete = _complete,
42304 + .get_b_hnp_enable = _get_b_hnp_enable,
42308 + * Initializes the HCD. This function allocates memory for and initializes the
42309 + * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
42310 + * USB bus with the core and calls the hc_driver->start() function. It returns
42311 + * a negative error on failure.
42313 +int hcd_init(dwc_bus_dev_t *_dev)
42315 + struct usb_hcd *hcd = NULL;
42316 + dwc_otg_hcd_t *dwc_otg_hcd = NULL;
42317 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
42321 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev);
42323 + /* Set device flags indicating whether the HCD supports DMA. */
42324 + if (dwc_otg_is_dma_enable(otg_dev->core_if))
42325 + dmamask = DMA_BIT_MASK(32);
42329 +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
42330 + dma_set_mask(&_dev->dev, dmamask);
42331 + dma_set_coherent_mask(&_dev->dev, dmamask);
42332 +#elif defined(PCI_INTERFACE)
42333 + pci_set_dma_mask(_dev, dmamask);
42334 + pci_set_consistent_dma_mask(_dev, dmamask);
42338 + * Allocate memory for the base HCD plus the DWC OTG HCD.
42339 + * Initialize the base HCD.
42341 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
42342 + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
42344 + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
42346 +// hcd->uses_new_polling = 1;
42347 +// hcd->poll_rh = 0;
42350 + retval = -ENOMEM;
42354 + hcd->regs = otg_dev->os_dep.base;
42356 + /* Initialize the DWC OTG HCD. */
42357 + dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
42358 + if (!dwc_otg_hcd) {
42361 + ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
42363 + otg_dev->hcd = dwc_otg_hcd;
42365 + if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
42369 + otg_dev->hcd->otg_dev = otg_dev;
42370 + hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
42371 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
42372 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) //version field absent later
42373 + hcd->self.otg_version = dwc_otg_get_otg_version(otg_dev->core_if);
42375 + /* Don't support SG list at this point */
42376 + hcd->self.sg_tablesize = 0;
42379 + * Finish generic HCD initialization and start the HCD. This function
42380 + * allocates the DMA buffer pool, registers the USB bus, requests the
42381 + * IRQ line, and calls hcd_start method.
42383 +#ifdef PLATFORM_INTERFACE
42384 + retval = usb_add_hcd(hcd, platform_get_irq(_dev, 0), IRQF_SHARED | IRQF_DISABLED);
42386 + retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED);
42388 + if (retval < 0) {
42392 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
42396 + usb_put_hcd(hcd);
42402 + * Removes the HCD.
42403 + * Frees memory and resources associated with the HCD and deregisters the bus.
42405 +void hcd_remove(dwc_bus_dev_t *_dev)
42407 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
42408 + dwc_otg_hcd_t *dwc_otg_hcd;
42409 + struct usb_hcd *hcd;
42411 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE otg_dev=%p\n", otg_dev);
42414 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
42418 + dwc_otg_hcd = otg_dev->hcd;
42420 + if (!dwc_otg_hcd) {
42421 + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
42425 + hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
42428 + DWC_DEBUGPL(DBG_ANY,
42429 + "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
42433 + usb_remove_hcd(hcd);
42434 + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
42435 + dwc_otg_hcd_remove(dwc_otg_hcd);
42436 + usb_put_hcd(hcd);
42439 +/* =========================================================================
42440 + * Linux HC Driver Functions
42441 + * ========================================================================= */
42443 +/** Initializes the DWC_otg controller and its root hub and prepares it for host
42444 + * mode operation. Activates the root port. Returns 0 on success and a negative
42445 + * error code on failure. */
42446 +int hcd_start(struct usb_hcd *hcd)
42448 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42449 + struct usb_bus *bus;
42451 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
42452 + bus = hcd_to_bus(hcd);
42454 + hcd->state = HC_STATE_RUNNING;
42455 + if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
42459 + /* Initialize and connect root hub if one is not already attached */
42460 + if (bus->root_hub) {
42461 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
42462 + /* Inform the HUB driver to resume. */
42463 + usb_hcd_resume_root_hub(hcd);
42470 + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
42473 +void hcd_stop(struct usb_hcd *hcd)
42475 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42477 + dwc_otg_hcd_stop(dwc_otg_hcd);
42480 +/** Returns the current frame number. */
42481 +static int get_frame_number(struct usb_hcd *hcd)
42483 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42485 + return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
42489 +static void dump_urb_info(struct urb *urb, char *fn_name)
42491 + DWC_PRINTF("%s, urb %p\n", fn_name, urb);
42492 + DWC_PRINTF(" Device address: %d\n", usb_pipedevice(urb->pipe));
42493 + DWC_PRINTF(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
42494 + (usb_pipein(urb->pipe) ? "IN" : "OUT"));
42495 + DWC_PRINTF(" Endpoint type: %s\n", ( {
42497 + switch (usb_pipetype(urb->pipe)) {
42498 +case PIPE_CONTROL:
42499 +pipetype = "CONTROL"; break; case PIPE_BULK:
42500 +pipetype = "BULK"; break; case PIPE_INTERRUPT:
42501 +pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
42502 +pipetype = "ISOCHRONOUS"; break; default:
42503 + pipetype = "UNKNOWN"; break;};
42506 + DWC_PRINTF(" Speed: %s\n", ( {
42507 + char *speed; switch (urb->dev->speed) {
42508 +case USB_SPEED_HIGH:
42509 +speed = "HIGH"; break; case USB_SPEED_FULL:
42510 +speed = "FULL"; break; case USB_SPEED_LOW:
42511 +speed = "LOW"; break; default:
42512 + speed = "UNKNOWN"; break;};
42515 + DWC_PRINTF(" Max packet size: %d\n",
42516 + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
42517 + DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length);
42518 + DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n",
42519 + urb->transfer_buffer, (void *)urb->transfer_dma);
42520 + DWC_PRINTF(" Setup buffer: %p, Setup DMA: %p\n",
42521 + urb->setup_packet, (void *)urb->setup_dma);
42522 + DWC_PRINTF(" Interval: %d\n", urb->interval);
42523 + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
42525 + for (i = 0; i < urb->number_of_packets; i++) {
42526 + DWC_PRINTF(" ISO Desc %d:\n", i);
42527 + DWC_PRINTF(" offset: %d, length %d\n",
42528 + urb->iso_frame_desc[i].offset,
42529 + urb->iso_frame_desc[i].length);
42535 +/** Starts processing a USB transfer request specified by a USB Request Block
42536 + * (URB). mem_flags indicates the type of memory allocation to use while
42537 + * processing this URB. */
42538 +static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
42539 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42540 + struct usb_host_endpoint *ep,
42542 + struct urb *urb, gfp_t mem_flags)
42545 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
42546 + struct usb_host_endpoint *ep = urb->ep;
42548 +#if USB_URB_EP_LINKING
42549 + dwc_irqflags_t irqflags;
42551 + void **ref_ep_hcpriv = &ep->hcpriv;
42552 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42553 + dwc_otg_hcd_urb_t *dwc_otg_urb;
42555 + int alloc_bandwidth = 0;
42556 + uint8_t ep_type = 0;
42557 + uint32_t flags = 0;
42561 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42562 + dump_urb_info(urb, "dwc_otg_urb_enqueue");
42566 + if (!urb->transfer_buffer && urb->transfer_buffer_length)
42569 + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
42570 + || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
42571 + if (!dwc_otg_hcd_is_bandwidth_allocated
42572 + (dwc_otg_hcd, ref_ep_hcpriv)) {
42573 + alloc_bandwidth = 1;
42577 + switch (usb_pipetype(urb->pipe)) {
42578 + case PIPE_CONTROL:
42579 + ep_type = USB_ENDPOINT_XFER_CONTROL;
42581 + case PIPE_ISOCHRONOUS:
42582 + ep_type = USB_ENDPOINT_XFER_ISOC;
42585 + ep_type = USB_ENDPOINT_XFER_BULK;
42587 + case PIPE_INTERRUPT:
42588 + ep_type = USB_ENDPOINT_XFER_INT;
42591 + DWC_WARN("Wrong EP type - %d\n", usb_pipetype(urb->pipe));
42594 + /* # of packets is often 0 - do we really need to call this then? */
42595 + dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
42596 + urb->number_of_packets,
42597 + mem_flags == GFP_ATOMIC ? 1 : 0);
42599 + if(dwc_otg_urb == NULL)
42602 + urb->hcpriv = dwc_otg_urb;
42603 + if (!dwc_otg_urb && urb->number_of_packets)
42606 + dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
42607 + usb_pipeendpoint(urb->pipe), ep_type,
42608 + usb_pipein(urb->pipe),
42609 + usb_maxpacket(urb->dev, urb->pipe,
42610 + !(usb_pipein(urb->pipe))));
42612 + buf = urb->transfer_buffer;
42613 + if (hcd->self.uses_dma) {
42615 + * Calculate virtual address from physical address,
42616 + * because some class driver may not fill transfer_buffer.
42617 + * In Buffer DMA mode virual address is used,
42618 + * when handling non DWORD aligned buffers.
42620 + //buf = phys_to_virt(urb->transfer_dma);
42621 + // DMA addresses are bus addresses not physical addresses!
42622 + buf = dma_to_virt(&urb->dev->dev, urb->transfer_dma);
42625 + if (!(urb->transfer_flags & URB_NO_INTERRUPT))
42626 + flags |= URB_GIVEBACK_ASAP;
42627 + if (urb->transfer_flags & URB_ZERO_PACKET)
42628 + flags |= URB_SEND_ZERO_PACKET;
42630 + dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
42631 + urb->transfer_dma,
42632 + urb->transfer_buffer_length,
42633 + urb->setup_packet,
42634 + urb->setup_dma, flags, urb->interval);
42636 + for (i = 0; i < urb->number_of_packets; ++i) {
42637 + dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
42639 + iso_frame_desc[i].offset,
42641 + iso_frame_desc[i].length);
42644 +#if USB_URB_EP_LINKING
42645 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
42646 + retval = usb_hcd_link_urb_to_ep(hcd, urb);
42647 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
42651 + retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
42652 + /*(dwc_otg_qh_t **)*/
42654 + mem_flags == GFP_ATOMIC ? 1 : 0);
42655 + if (0 == retval) {
42656 + if (alloc_bandwidth) {
42657 + allocate_bus_bandwidth(hcd,
42658 + dwc_otg_hcd_get_ep_bandwidth(
42659 + dwc_otg_hcd, *ref_ep_hcpriv),
42663 +#if USB_URB_EP_LINKING
42664 + dwc_irqflags_t irqflags;
42665 + DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
42666 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
42667 + usb_hcd_unlink_urb_from_ep(hcd, urb);
42668 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
42670 + if (retval == -DWC_E_NO_DEVICE) {
42671 + retval = -ENODEV;
42678 +/** Aborts/cancels a USB transfer request. Always returns 0 to indicate
42680 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42681 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
42683 +static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
42686 + dwc_irqflags_t flags;
42687 + dwc_otg_hcd_t *dwc_otg_hcd;
42690 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
42692 + dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42695 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42696 + dump_urb_info(urb, "dwc_otg_urb_dequeue");
42700 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
42701 + rc = usb_hcd_check_unlink_urb(hcd, urb, status);
42703 + if(urb->hcpriv != NULL) {
42704 + dwc_otg_hcd_urb_dequeue(dwc_otg_hcd,
42705 + (dwc_otg_hcd_urb_t *)urb->hcpriv);
42707 + DWC_FREE(urb->hcpriv);
42708 + urb->hcpriv = NULL;
42713 + /* Higher layer software sets URB status. */
42714 +#if USB_URB_EP_LINKING
42715 + usb_hcd_unlink_urb_from_ep(hcd, urb);
42717 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42718 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
42719 + usb_hcd_giveback_urb(hcd, urb);
42721 + usb_hcd_giveback_urb(hcd, urb, status);
42723 + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
42724 + DWC_PRINTF("Called usb_hcd_giveback_urb() \n");
42725 + DWC_PRINTF(" 1urb->status = %d\n", urb->status);
42727 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue OK\n");
42729 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42730 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue failed - rc %d\n",
42737 +/* Frees resources in the DWC_otg controller related to a given endpoint. Also
42738 + * clears state in the HCD related to the endpoint. Any URBs for the endpoint
42739 + * must already be dequeued. */
42740 +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
42742 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42744 + DWC_DEBUGPL(DBG_HCD,
42745 + "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
42746 + "endpoint=%d\n", ep->desc.bEndpointAddress,
42747 + dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
42748 + dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
42749 + ep->hcpriv = NULL;
42752 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
42753 +/* Resets endpoint specific parameter values, in current version used to reset
42754 + * the data toggle(as a WA). This function can be called from usb_clear_halt routine */
42755 +static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
42757 + dwc_irqflags_t flags;
42758 + struct usb_device *udev = NULL;
42759 + int epnum = usb_endpoint_num(&ep->desc);
42760 + int is_out = usb_endpoint_dir_out(&ep->desc);
42761 + int is_control = usb_endpoint_xfer_control(&ep->desc);
42762 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42763 + struct device *dev = DWC_OTG_OS_GETDEV(dwc_otg_hcd->otg_dev->os_dep);
42766 + udev = to_usb_device(dev);
42770 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum);
42772 + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
42773 + usb_settoggle(udev, epnum, is_out, 0);
42775 + usb_settoggle(udev, epnum, !is_out, 0);
42777 + if (ep->hcpriv) {
42778 + dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
42780 + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
42784 +/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
42785 + * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
42788 + * This function is called by the USB core when an interrupt occurs */
42789 +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
42791 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42792 + int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
42793 + if (retval != 0) {
42794 + S3C2410X_CLEAR_EINTPEND();
42796 + return IRQ_RETVAL(retval);
42799 +/** Creates Status Change bitmap for the root hub and root port. The bitmap is
42800 + * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
42801 + * is the status change indicator for the single root port. Returns 1 if either
42802 + * change indicator is 1, otherwise returns 0. */
42803 +int hub_status_data(struct usb_hcd *hcd, char *buf)
42805 + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
42808 + buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
42810 + return (buf[0] != 0);
42813 +/** Handles hub class-specific requests. */
42814 +int hub_control(struct usb_hcd *hcd,
42815 + u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
42819 + retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
42820 + typeReq, wValue, wIndex, buf, wLength);
42822 + switch (retval) {
42823 + case -DWC_E_INVALID:
42824 + retval = -EINVAL;
42831 +#endif /* DWC_DEVICE_ONLY */
42832 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
42833 new file mode 100644
42834 index 0000000..08c1669
42836 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
42838 +/* ==========================================================================
42839 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
42840 + * $Revision: #44 $
42841 + * $Date: 2011/10/26 $
42842 + * $Change: 1873028 $
42844 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
42845 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
42846 + * otherwise expressly agreed to in writing between Synopsys and you.
42848 + * The Software IS NOT an item of Licensed Software or Licensed Product under
42849 + * any End User Software License Agreement or Agreement for Licensed Product
42850 + * with Synopsys or any supplement thereto. You are permitted to use and
42851 + * redistribute this Software in source and binary forms, with or without
42852 + * modification, provided that redistributions of source code must retain this
42853 + * notice. You may not view, use, disclose, copy or distribute this file or
42854 + * any information contained herein except pursuant to this license grant from
42855 + * Synopsys. If you do not agree with this notice, including the disclaimer
42856 + * below, then you are not authorized to use the Software.
42858 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
42859 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42860 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42861 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
42862 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42863 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
42864 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
42865 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42866 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42867 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
42869 + * ========================================================================== */
42870 +#ifndef DWC_DEVICE_ONLY
42875 + * This file contains the functions to manage Queue Heads and Queue
42876 + * Transfer Descriptors.
42879 +#include "dwc_otg_hcd.h"
42880 +#include "dwc_otg_regs.h"
42882 +extern bool microframe_schedule;
42885 + * Free each QTD in the QH's QTD-list then free the QH. QH should already be
42886 + * removed from a list. QTD list should already be empty if called from URB
42889 + * @param hcd HCD instance.
42890 + * @param qh The QH to free.
42892 +void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
42894 + dwc_otg_qtd_t *qtd, *qtd_tmp;
42896 + /* Free each QTD in the QTD list */
42897 + DWC_SPINLOCK(hcd->lock);
42898 + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
42899 + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
42900 + dwc_otg_hcd_qtd_free(qtd);
42903 + if (hcd->core_if->dma_desc_enable) {
42904 + dwc_otg_hcd_qh_free_ddma(hcd, qh);
42905 + } else if (qh->dw_align_buf) {
42906 + uint32_t buf_size;
42907 + if (qh->ep_type == UE_ISOCHRONOUS) {
42910 + buf_size = hcd->core_if->core_params->max_transfer_size;
42912 + DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
42916 + DWC_SPINUNLOCK(hcd->lock);
42920 +#define BitStuffTime(bytecount) ((8 * 7* bytecount) / 6)
42921 +#define HS_HOST_DELAY 5 /* nanoseconds */
42922 +#define FS_LS_HOST_DELAY 1000 /* nanoseconds */
42923 +#define HUB_LS_SETUP 333 /* nanoseconds */
42924 +#define NS_TO_US(ns) ((ns + 500) / 1000)
42925 + /* convert & round nanoseconds to microseconds */
42927 +static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
42929 + unsigned long retval;
42932 + case USB_SPEED_HIGH:
42935 + ((38 * 8 * 2083) +
42936 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
42940 + ((55 * 8 * 2083) +
42941 + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
42945 + case USB_SPEED_FULL:
42948 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
42950 + retval = 7268 + FS_LS_HOST_DELAY + retval;
42952 + retval = 6265 + FS_LS_HOST_DELAY + retval;
42956 + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
42957 + retval = 9107 + FS_LS_HOST_DELAY + retval;
42960 + case USB_SPEED_LOW:
42963 + (67667 * (31 + 10 * BitStuffTime(bytecount))) /
42966 + 64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
42970 + (66700 * (31 + 10 * BitStuffTime(bytecount))) /
42973 + 64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
42978 + DWC_WARN("Unknown device speed\n");
42982 + return NS_TO_US(retval);
42986 + * Initializes a QH structure.
42988 + * @param hcd The HCD state structure for the DWC OTG controller.
42989 + * @param qh The QH to init.
42990 + * @param urb Holds the information about the device/endpoint that we need
42991 + * to initialize the QH.
42993 +#define SCHEDULE_SLOP 10
42994 +void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
42996 + char *speed, *type;
42998 + uint32_t hub_addr, hub_port;
43000 + dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
43002 + /* Initialize QH */
43003 + qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
43004 + qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
43006 + qh->data_toggle = DWC_OTG_HC_PID_DATA0;
43007 + qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
43008 + DWC_CIRCLEQ_INIT(&qh->qtd_list);
43009 + DWC_LIST_INIT(&qh->qh_list_entry);
43010 + qh->channel = NULL;
43012 + /* FS/LS Enpoint on HS Hub
43013 + * NOT virtual root hub */
43014 + dev_speed = hcd->fops->speed(hcd, urb->priv);
43016 + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
43017 + qh->do_split = 0;
43018 + if (microframe_schedule)
43019 + qh->speed = dev_speed;
43022 + if (((dev_speed == USB_SPEED_LOW) ||
43023 + (dev_speed == USB_SPEED_FULL)) &&
43024 + (hub_addr != 0 && hub_addr != 1)) {
43025 + DWC_DEBUGPL(DBG_HCD,
43026 + "QH init: EP %d: TT found at hub addr %d, for port %d\n",
43027 + dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
43029 + qh->do_split = 1;
43032 + if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
43033 + /* Compute scheduling parameters once and save them. */
43034 + hprt0_data_t hprt;
43036 + /** @todo Account for split transfers in the bus time. */
43038 + dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
43041 + calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
43042 + qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
43044 + /* Start in a slightly future (micro)frame. */
43045 + qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
43047 + qh->interval = urb->interval;
43050 + /* Increase interrupt polling rate for debugging. */
43051 + if (qh->ep_type == UE_INTERRUPT) {
43052 + qh->interval = 8;
43055 + hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
43056 + if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
43057 + ((dev_speed == USB_SPEED_LOW) ||
43058 + (dev_speed == USB_SPEED_FULL))) {
43059 + qh->interval *= 8;
43060 + qh->sched_frame |= 0x7;
43061 + qh->start_split_frame = qh->sched_frame;
43066 + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
43067 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", qh);
43068 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n",
43069 + dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
43070 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n",
43071 + dwc_otg_hcd_get_ep_num(&urb->pipe_info),
43072 + dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
43073 + switch (dev_speed) {
43074 + case USB_SPEED_LOW:
43075 + qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
43078 + case USB_SPEED_FULL:
43079 + qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
43082 + case USB_SPEED_HIGH:
43083 + qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
43090 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", speed);
43092 + switch (qh->ep_type) {
43093 + case UE_ISOCHRONOUS:
43094 + type = "isochronous";
43096 + case UE_INTERRUPT:
43097 + type = "interrupt";
43100 + type = "control";
43110 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", type);
43113 + if (qh->ep_type == UE_INTERRUPT) {
43114 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
43116 + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
43124 + * This function allocates and initializes a QH.
43126 + * @param hcd The HCD state structure for the DWC OTG controller.
43127 + * @param urb Holds the information about the device/endpoint that we need
43128 + * to initialize the QH.
43129 + * @param atomic_alloc Flag to do atomic allocation if needed
43131 + * @return Returns pointer to the newly allocated QH, or NULL on error. */
43132 +dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
43133 + dwc_otg_hcd_urb_t * urb, int atomic_alloc)
43135 + dwc_otg_qh_t *qh;
43137 + /* Allocate memory */
43138 + /** @todo add memflags argument */
43139 + qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
43140 + if (qh == NULL) {
43141 + DWC_ERROR("qh allocation failed");
43145 + qh_init(hcd, qh, urb);
43147 + if (hcd->core_if->dma_desc_enable
43148 + && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
43149 + dwc_otg_hcd_qh_free(hcd, qh);
43156 +/* microframe_schedule=0 start */
43159 + * Checks that a channel is available for a periodic transfer.
43161 + * @return 0 if successful, negative error code otherise.
43163 +static int periodic_channel_available(dwc_otg_hcd_t * hcd)
43166 + * Currently assuming that there is a dedicated host channnel for each
43167 + * periodic transaction plus at least one host channel for
43168 + * non-periodic transactions.
43171 + int num_channels;
43173 + num_channels = hcd->core_if->core_params->host_channels;
43174 + if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
43175 + && (hcd->periodic_channels < num_channels - 1)) {
43178 + DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
43179 + __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels); //NOTICE
43180 + status = -DWC_E_NO_SPACE;
43187 + * Checks that there is sufficient bandwidth for the specified QH in the
43188 + * periodic schedule. For simplicity, this calculation assumes that all the
43189 + * transfers in the periodic schedule may occur in the same (micro)frame.
43191 + * @param hcd The HCD state structure for the DWC OTG controller.
43192 + * @param qh QH containing periodic bandwidth required.
43194 + * @return 0 if successful, negative error code otherwise.
43196 +static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43199 + int16_t max_claimed_usecs;
43203 + if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
43205 + * High speed mode.
43206 + * Max periodic usecs is 80% x 125 usec = 100 usec.
43209 + max_claimed_usecs = 100 - qh->usecs;
43212 + * Full speed mode.
43213 + * Max periodic usecs is 90% x 1000 usec = 900 usec.
43215 + max_claimed_usecs = 900 - qh->usecs;
43218 + if (hcd->periodic_usecs > max_claimed_usecs) {
43219 + DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs); //NOTICE
43220 + status = -DWC_E_NO_SPACE;
43226 +/* microframe_schedule=0 end */
43229 + * Microframe scheduler
43230 + * track the total use in hcd->frame_usecs
43231 + * keep each qh use in qh->frame_usecs
43232 + * when surrendering the qh then donate the time back
43234 +const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 };
43237 + * called from dwc_otg_hcd.c:dwc_otg_hcd_init
43239 +int init_hcd_usecs(dwc_otg_hcd_t *_hcd)
43242 + for (i=0; i<8; i++) {
43243 + _hcd->frame_usecs[i] = max_uframe_usecs[i];
43248 +static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43251 + unsigned short utime;
43257 + utime = _qh->usecs;
43261 + while (done == 0) {
43262 + /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */
43263 + if (utime <= _hcd->frame_usecs[i]) {
43264 + _hcd->frame_usecs[i] -= utime;
43265 + _qh->frame_usecs[i] += utime;
43282 + * use this for FS apps that can span multiple uframes
43284 +static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43288 + unsigned short utime;
43292 + unsigned short xtime;
43295 + utime = _qh->usecs;
43300 + while (done == 0) {
43301 + if(_hcd->frame_usecs[i] <= 0) {
43311 + * we need n consecutive slots
43312 + * so use j as a start slot j plus j+1 must be enough time (for now)
43314 + xtime= _hcd->frame_usecs[i];
43315 + for (j = i+1 ; j < 8 ; j++ ) {
43317 + * if we add this frame remaining time to xtime we may
43318 + * be OK, if not we need to test j for a complete frame
43320 + if ((xtime+_hcd->frame_usecs[j]) < utime) {
43321 + if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) {
43327 + if (xtime >= utime) {
43329 + j = 8; /* stop loop with a good value ret */
43332 + /* add the frame time to x time */
43333 + xtime += _hcd->frame_usecs[j];
43334 + /* we must have a fully available next frame or break */
43335 + if ((xtime < utime)
43336 + && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) {
43338 + j = 8; /* stop loop with a bad value ret */
43344 + for (j = i; (t_left>0) && (j < 8); j++ ) {
43345 + t_left -= _hcd->frame_usecs[j];
43346 + if ( t_left <= 0 ) {
43347 + _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left;
43348 + _hcd->frame_usecs[j]= -t_left;
43352 + _qh->frame_usecs[j] += _hcd->frame_usecs[j];
43353 + _hcd->frame_usecs[j] = 0;
43367 +static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
43372 + if (_qh->speed == USB_SPEED_HIGH) {
43373 + /* if this is a hs transaction we need a full frame */
43374 + ret = find_single_uframe(_hcd, _qh);
43376 + /* if this is a fs transaction we may need a sequence of frames */
43377 + ret = find_multi_uframe(_hcd, _qh);
43383 + * Checks that the max transfer size allowed in a host channel is large enough
43384 + * to handle the maximum data transfer in a single (micro)frame for a periodic
43387 + * @param hcd The HCD state structure for the DWC OTG controller.
43388 + * @param qh QH for a periodic endpoint.
43390 + * @return 0 if successful, negative error code otherwise.
43392 +static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43395 + uint32_t max_xfer_size;
43396 + uint32_t max_channel_xfer_size;
43400 + max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
43401 + max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
43403 + if (max_xfer_size > max_channel_xfer_size) {
43404 + DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
43405 + __func__, max_xfer_size, max_channel_xfer_size); //NOTICE
43406 + status = -DWC_E_NO_SPACE;
43413 + * Schedules an interrupt or isochronous transfer in the periodic schedule.
43415 + * @param hcd The HCD state structure for the DWC OTG controller.
43416 + * @param qh QH for the periodic transfer. The QH should already contain the
43417 + * scheduling information.
43419 + * @return 0 if successful, negative error code otherwise.
43421 +static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43425 + if (microframe_schedule) {
43427 + status = find_uframe(hcd, qh);
43429 + if (status == 0) {
43433 + frame = status-1;
43436 + /* Set the new frame up */
43437 + if (frame > -1) {
43438 + qh->sched_frame &= ~0x7;
43439 + qh->sched_frame |= (frame & 7);
43442 + if (status != -1)
43445 + status = periodic_channel_available(hcd);
43447 + DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE
43451 + status = check_periodic_bandwidth(hcd, qh);
43454 + DWC_INFO("%s: Insufficient periodic bandwidth for "
43455 + "periodic transfer.\n", __func__);
43458 + status = check_max_xfer_size(hcd, qh);
43460 + DWC_INFO("%s: Channel max transfer size too small "
43461 + "for periodic transfer.\n", __func__);
43465 + if (hcd->core_if->dma_desc_enable) {
43466 + /* Don't rely on SOF and start in ready schedule */
43467 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
43470 + /* Always start in the inactive schedule. */
43471 + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
43474 + if (!microframe_schedule) {
43475 + /* Reserve the periodic channel. */
43476 + hcd->periodic_channels++;
43479 + /* Update claimed usecs per (micro)frame. */
43480 + hcd->periodic_usecs += qh->usecs;
43486 + * This function adds a QH to either the non periodic or periodic schedule if
43487 + * it is not already in the schedule. If the QH is already in the schedule, no
43488 + * action is taken.
43490 + * @return 0 if successful, negative error code otherwise.
43492 +int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43495 + gintmsk_data_t intr_mask = {.d32 = 0 };
43497 + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
43498 + /* QH already in a schedule. */
43502 + /* Add the new QH to the appropriate schedule */
43503 + if (dwc_qh_is_non_per(qh)) {
43504 + /* Always start in the inactive schedule. */
43505 + DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
43506 + &qh->qh_list_entry);
43508 + status = schedule_periodic(hcd, qh);
43509 + if ( !hcd->periodic_qh_count ) {
43510 + intr_mask.b.sofintr = 1;
43511 + DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
43512 + intr_mask.d32, intr_mask.d32);
43514 + hcd->periodic_qh_count++;
43521 + * Removes an interrupt or isochronous transfer from the periodic schedule.
43523 + * @param hcd The HCD state structure for the DWC OTG controller.
43524 + * @param qh QH for the periodic transfer.
43526 +static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43529 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
43531 + /* Update claimed usecs per (micro)frame. */
43532 + hcd->periodic_usecs -= qh->usecs;
43534 + if (!microframe_schedule) {
43535 + /* Release the periodic channel reservation. */
43536 + hcd->periodic_channels--;
43538 + for (i = 0; i < 8; i++) {
43539 + hcd->frame_usecs[i] += qh->frame_usecs[i];
43540 + qh->frame_usecs[i] = 0;
43546 + * Removes a QH from either the non-periodic or periodic schedule. Memory is
43549 + * @param hcd The HCD state structure.
43550 + * @param qh QH to remove from schedule. */
43551 +void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
43553 + gintmsk_data_t intr_mask = {.d32 = 0 };
43555 + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
43556 + /* QH is not in a schedule. */
43560 + if (dwc_qh_is_non_per(qh)) {
43561 + if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
43562 + hcd->non_periodic_qh_ptr =
43563 + hcd->non_periodic_qh_ptr->next;
43565 + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
43567 + deschedule_periodic(hcd, qh);
43568 + hcd->periodic_qh_count--;
43569 + if( !hcd->periodic_qh_count ) {
43570 + intr_mask.b.sofintr = 1;
43571 + DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
43572 + intr_mask.d32, 0);
43578 + * Deactivates a QH. For non-periodic QHs, removes the QH from the active
43579 + * non-periodic schedule. The QH is added to the inactive non-periodic
43580 + * schedule if any QTDs are still attached to the QH.
43582 + * For periodic QHs, the QH is removed from the periodic queued schedule. If
43583 + * there are any QTDs still attached to the QH, the QH is added to either the
43584 + * periodic inactive schedule or the periodic ready schedule and its next
43585 + * scheduled frame is calculated. The QH is placed in the ready schedule if
43586 + * the scheduled frame has been reached already. Otherwise it's placed in the
43587 + * inactive schedule. If there are no QTDs attached to the QH, the QH is
43588 + * completely removed from the periodic schedule.
43590 +void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
43591 + int sched_next_periodic_split)
43593 + if (dwc_qh_is_non_per(qh)) {
43594 + dwc_otg_hcd_qh_remove(hcd, qh);
43595 + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
43596 + /* Add back to inactive non-periodic schedule. */
43597 + dwc_otg_hcd_qh_add(hcd, qh);
43600 + uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
43602 + if (qh->do_split) {
43603 + /* Schedule the next continuing periodic split transfer */
43604 + if (sched_next_periodic_split) {
43606 + qh->sched_frame = frame_number;
43607 + if (dwc_frame_num_le(frame_number,
43608 + dwc_frame_num_inc
43609 + (qh->start_split_frame,
43612 + * Allow one frame to elapse after start
43613 + * split microframe before scheduling
43614 + * complete split, but DONT if we are
43615 + * doing the next start split in the
43616 + * same frame for an ISOC out.
43618 + if ((qh->ep_type != UE_ISOCHRONOUS) ||
43619 + (qh->ep_is_in != 0)) {
43620 + qh->sched_frame =
43621 + dwc_frame_num_inc(qh->sched_frame, 1);
43625 + qh->sched_frame =
43626 + dwc_frame_num_inc(qh->start_split_frame,
43628 + if (dwc_frame_num_le
43629 + (qh->sched_frame, frame_number)) {
43630 + qh->sched_frame = frame_number;
43632 + qh->sched_frame |= 0x7;
43633 + qh->start_split_frame = qh->sched_frame;
43636 + qh->sched_frame =
43637 + dwc_frame_num_inc(qh->sched_frame, qh->interval);
43638 + if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
43639 + qh->sched_frame = frame_number;
43643 + if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
43644 + dwc_otg_hcd_qh_remove(hcd, qh);
43647 + * Remove from periodic_sched_queued and move to
43648 + * appropriate queue.
43650 + if ((microframe_schedule && dwc_frame_num_le(qh->sched_frame, frame_number)) ||
43651 + (!microframe_schedule && qh->sched_frame == frame_number)) {
43652 + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
43653 + &qh->qh_list_entry);
43655 + DWC_LIST_MOVE_HEAD
43656 + (&hcd->periodic_sched_inactive,
43657 + &qh->qh_list_entry);
43664 + * This function allocates and initializes a QTD.
43666 + * @param urb The URB to create a QTD from. Each URB-QTD pair will end up
43667 + * pointing to each other so each pair should have a unique correlation.
43668 + * @param atomic_alloc Flag to do atomic alloc if needed
43670 + * @return Returns pointer to the newly allocated QTD, or NULL on error. */
43671 +dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
43673 + dwc_otg_qtd_t *qtd;
43675 + qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
43676 + if (qtd == NULL) {
43680 + dwc_otg_hcd_qtd_init(qtd, urb);
43685 + * Initializes a QTD structure.
43687 + * @param qtd The QTD to initialize.
43688 + * @param urb The URB to use for initialization. */
43689 +void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
43691 + dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
43693 + if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
43695 + * The only time the QTD data toggle is used is on the data
43696 + * phase of control transfers. This phase always starts with
43699 + qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
43700 + qtd->control_phase = DWC_OTG_CONTROL_SETUP;
43703 + /* start split */
43704 + qtd->complete_split = 0;
43705 + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
43706 + qtd->isoc_split_offset = 0;
43707 + qtd->in_process = 0;
43709 + /* Store the qtd ptr in the urb to reference what QTD. */
43715 + * This function adds a QTD to the QTD-list of a QH. It will find the correct
43716 + * QH to place the QTD into. If it does not find a QH, then it will create a
43717 + * new QH. If the QH to which the QTD is added is not currently scheduled, it
43718 + * is placed into the proper schedule based on its EP type.
43720 + * @param[in] qtd The QTD to add
43721 + * @param[in] hcd The DWC HCD structure
43722 + * @param[out] qh out parameter to return queue head
43723 + * @param atomic_alloc Flag to do atomic alloc if needed
43725 + * @return 0 if successful, negative error code otherwise.
43727 +int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
43728 + dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
43731 + dwc_irqflags_t flags;
43733 + dwc_otg_hcd_urb_t *urb = qtd->urb;
43736 + * Get the QH which holds the QTD-list to insert to. Create QH if it
43739 + if (*qh == NULL) {
43740 + *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
43741 + if (*qh == NULL) {
43746 + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
43747 + retval = dwc_otg_hcd_qh_add(hcd, *qh);
43748 + if (retval == 0) {
43749 + DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
43752 + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
43759 +#endif /* DWC_DEVICE_ONLY */
43760 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
43761 new file mode 100644
43762 index 0000000..a7e9076
43764 +++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
43766 +#ifndef _DWC_OS_DEP_H_
43767 +#define _DWC_OS_DEP_H_
43772 + * This file contains OS dependent structures.
43776 +#include <linux/kernel.h>
43777 +#include <linux/module.h>
43778 +#include <linux/moduleparam.h>
43779 +#include <linux/init.h>
43780 +#include <linux/device.h>
43781 +#include <linux/errno.h>
43782 +#include <linux/types.h>
43783 +#include <linux/slab.h>
43784 +#include <linux/list.h>
43785 +#include <linux/interrupt.h>
43786 +#include <linux/ctype.h>
43787 +#include <linux/string.h>
43788 +#include <linux/dma-mapping.h>
43789 +#include <linux/jiffies.h>
43790 +#include <linux/delay.h>
43791 +#include <linux/timer.h>
43792 +#include <linux/workqueue.h>
43793 +#include <linux/stat.h>
43794 +#include <linux/pci.h>
43796 +#include <linux/version.h>
43798 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
43799 +# include <linux/irq.h>
43802 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
43803 +# include <linux/usb/ch9.h>
43805 +# include <linux/usb_ch9.h>
43808 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
43809 +# include <linux/usb/gadget.h>
43811 +# include <linux/usb_gadget.h>
43814 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
43815 +# include <asm/irq.h>
43818 +#ifdef PCI_INTERFACE
43819 +# include <asm/io.h>
43822 +#ifdef LM_INTERFACE
43823 +# include <asm/unaligned.h>
43824 +# include <asm/sizes.h>
43825 +# include <asm/param.h>
43826 +# include <asm/io.h>
43827 +# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
43828 +# include <asm/arch/hardware.h>
43829 +# include <asm/arch/lm.h>
43830 +# include <asm/arch/irqs.h>
43831 +# include <asm/arch/regs-irq.h>
43833 +/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure -
43834 + here we assume that the machine architecture provides definitions
43835 + in its own header
43837 +# include <mach/lm.h>
43838 +# include <mach/hardware.h>
43842 +#ifdef PLATFORM_INTERFACE
43843 +#include <linux/platform_device.h>
43844 +#include <asm/mach/map.h>
43847 +/** The OS page size */
43848 +#define DWC_OS_PAGE_SIZE PAGE_SIZE
43850 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
43851 +typedef int gfp_t;
43854 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
43855 +# define IRQF_SHARED SA_SHIRQ
43858 +typedef struct os_dependent {
43859 + /** Base address returned from ioremap() */
43862 + /** Register offset for Diagnostic API */
43863 + uint32_t reg_offset;
43865 +#ifdef LM_INTERFACE
43866 + struct lm_device *lmdev;
43867 +#elif defined(PCI_INTERFACE)
43868 + struct pci_dev *pcidev;
43870 + /** Start address of a PCI region */
43871 + resource_size_t rsrc_start;
43873 + /** Length address of a PCI region */
43874 + resource_size_t rsrc_len;
43875 +#elif defined(PLATFORM_INTERFACE)
43876 + struct platform_device *platformdev;
43881 +#ifdef __cplusplus
43887 +/* Type for the our device on the chosen bus */
43888 +#if defined(LM_INTERFACE)
43889 +typedef struct lm_device dwc_bus_dev_t;
43890 +#elif defined(PCI_INTERFACE)
43891 +typedef struct pci_dev dwc_bus_dev_t;
43892 +#elif defined(PLATFORM_INTERFACE)
43893 +typedef struct platform_device dwc_bus_dev_t;
43896 +/* Helper macro to retrieve drvdata from the device on the chosen bus */
43897 +#if defined(LM_INTERFACE)
43898 +#define DWC_OTG_BUSDRVDATA(_dev) lm_get_drvdata(_dev)
43899 +#elif defined(PCI_INTERFACE)
43900 +#define DWC_OTG_BUSDRVDATA(_dev) pci_get_drvdata(_dev)
43901 +#elif defined(PLATFORM_INTERFACE)
43902 +#define DWC_OTG_BUSDRVDATA(_dev) platform_get_drvdata(_dev)
43906 + * Helper macro returning the otg_device structure of a given struct device
43908 + * c.f. static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
43910 +#ifdef LM_INTERFACE
43911 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43912 + struct lm_device *lm_dev = \
43913 + container_of(_dev, struct lm_device, dev); \
43914 + _var = lm_get_drvdata(lm_dev); \
43917 +#elif defined(PCI_INTERFACE)
43918 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43919 + _var = dev_get_drvdata(_dev); \
43922 +#elif defined(PLATFORM_INTERFACE)
43923 +#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
43924 + struct platform_device *platform_dev = \
43925 + container_of(_dev, struct platform_device, dev); \
43926 + _var = platform_get_drvdata(platform_dev); \
43932 + * Helper macro returning the struct dev of the given struct os_dependent
43934 + * c.f. static struct device *dwc_otg_getdev(struct os_dependent *osdep)
43936 +#ifdef LM_INTERFACE
43937 +#define DWC_OTG_OS_GETDEV(_osdep) \
43938 + ((_osdep).lmdev == NULL? NULL: &(_osdep).lmdev->dev)
43939 +#elif defined(PCI_INTERFACE)
43940 +#define DWC_OTG_OS_GETDEV(_osdep) \
43941 + ((_osdep).pci_dev == NULL? NULL: &(_osdep).pci_dev->dev)
43942 +#elif defined(PLATFORM_INTERFACE)
43943 +#define DWC_OTG_OS_GETDEV(_osdep) \
43944 + ((_osdep).platformdev == NULL? NULL: &(_osdep).platformdev->dev)
43950 +#endif /* _DWC_OS_DEP_H_ */
43951 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd.c
43952 new file mode 100644
43953 index 0000000..c97d65c
43955 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.c
43957 +/* ==========================================================================
43958 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
43959 + * $Revision: #101 $
43960 + * $Date: 2012/08/10 $
43961 + * $Change: 2047372 $
43963 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
43964 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
43965 + * otherwise expressly agreed to in writing between Synopsys and you.
43967 + * The Software IS NOT an item of Licensed Software or Licensed Product under
43968 + * any End User Software License Agreement or Agreement for Licensed Product
43969 + * with Synopsys or any supplement thereto. You are permitted to use and
43970 + * redistribute this Software in source and binary forms, with or without
43971 + * modification, provided that redistributions of source code must retain this
43972 + * notice. You may not view, use, disclose, copy or distribute this file or
43973 + * any information contained herein except pursuant to this license grant from
43974 + * Synopsys. If you do not agree with this notice, including the disclaimer
43975 + * below, then you are not authorized to use the Software.
43977 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
43978 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43979 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43980 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
43981 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43982 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43983 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
43984 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43985 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43986 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
43988 + * ========================================================================== */
43989 +#ifndef DWC_HOST_ONLY
43992 + * This file implements PCD Core. All code in this file is portable and doesn't
43993 + * use any OS specific functions.
43994 + * PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code>
43995 + * header file, which can be used to implement OS specific PCD interface.
43997 + * An important function of the PCD is managing interrupts generated
43998 + * by the DWC_otg controller. The implementation of the DWC_otg device
43999 + * mode interrupt service routines is in dwc_otg_pcd_intr.c.
44001 + * @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
44002 + * @todo Does it work when the request size is greater than DEPTSIZ
44007 +#include "dwc_otg_pcd.h"
44009 +#ifdef DWC_UTE_CFI
44010 +#include "dwc_otg_cfi.h"
44012 +extern int init_cfi(cfiobject_t * cfiobj);
44016 + * Choose endpoint from ep arrays using usb_ep structure.
44018 +static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
44021 + if (pcd->ep0.priv == handle) {
44022 + return &pcd->ep0;
44024 + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
44025 + if (pcd->in_ep[i].priv == handle)
44026 + return &pcd->in_ep[i];
44027 + if (pcd->out_ep[i].priv == handle)
44028 + return &pcd->out_ep[i];
44035 + * This function completes a request. It call's the request call back.
44037 +void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req,
44040 + unsigned stopped = ep->stopped;
44042 + DWC_DEBUGPL(DBG_PCDV, "%s(ep %p req %p)\n", __func__, ep, req);
44043 + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
44045 + /* don't modify queue heads during completion callback */
44047 + /* spin_unlock/spin_lock now done in fops->complete() */
44048 + ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status,
44051 + if (ep->pcd->request_pending > 0) {
44052 + --ep->pcd->request_pending;
44055 + ep->stopped = stopped;
44060 + * This function terminates all the requsts in the EP request queue.
44062 +void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep)
44064 + dwc_otg_pcd_request_t *req;
44068 + /* called with irqs blocked?? */
44069 + while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
44070 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
44071 + dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN);
44075 +void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
44076 + const struct dwc_otg_pcd_function_ops *fops)
44078 + pcd->fops = fops;
44082 + * PCD Callback function for initializing the PCD when switching to
44085 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44087 +static int32_t dwc_otg_pcd_start_cb(void *p)
44089 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44090 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
44093 + * Initialized the Core for Device mode.
44095 + if (dwc_otg_is_device_mode(core_if)) {
44096 + dwc_otg_core_dev_init(core_if);
44097 + /* Set core_if's lock pointer to the pcd->lock */
44098 + core_if->lock = pcd->lock;
44103 +/** CFI-specific buffer allocation function for EP */
44104 +#ifdef DWC_UTE_CFI
44105 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
44106 + size_t buflen, int flags)
44108 + dwc_otg_pcd_ep_t *ep;
44109 + ep = get_ep_from_handle(pcd, pep);
44111 + DWC_WARN("bad ep\n");
44112 + return -DWC_E_INVALID;
44115 + return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen,
44119 +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
44120 + size_t buflen, int flags);
44124 + * PCD Callback function for notifying the PCD when resuming from
44127 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44129 +static int32_t dwc_otg_pcd_resume_cb(void *p)
44131 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44133 + if (pcd->fops->resume) {
44134 + pcd->fops->resume(pcd);
44137 + /* Stop the SRP timeout timer. */
44138 + if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS)
44139 + || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {
44140 + if (GET_CORE_IF(pcd)->srp_timer_started) {
44141 + GET_CORE_IF(pcd)->srp_timer_started = 0;
44142 + DWC_TIMER_CANCEL(GET_CORE_IF(pcd)->srp_timer);
44149 + * PCD Callback function for notifying the PCD device is suspended.
44151 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44153 +static int32_t dwc_otg_pcd_suspend_cb(void *p)
44155 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44157 + if (pcd->fops->suspend) {
44158 + DWC_SPINUNLOCK(pcd->lock);
44159 + pcd->fops->suspend(pcd);
44160 + DWC_SPINLOCK(pcd->lock);
44167 + * PCD Callback function for stopping the PCD when switching to Host
44170 + * @param p void pointer to the <code>dwc_otg_pcd_t</code>
44172 +static int32_t dwc_otg_pcd_stop_cb(void *p)
44174 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
44175 + extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);
44177 + dwc_otg_pcd_stop(pcd);
44182 + * PCD Callback structure for handling mode switching.
44184 +static dwc_otg_cil_callbacks_t pcd_callbacks = {
44185 + .start = dwc_otg_pcd_start_cb,
44186 + .stop = dwc_otg_pcd_stop_cb,
44187 + .suspend = dwc_otg_pcd_suspend_cb,
44188 + .resume_wakeup = dwc_otg_pcd_resume_cb,
44189 + .p = 0, /* Set at registration */
44193 + * This function allocates a DMA Descriptor chain for the Endpoint
44194 + * buffer to be used for a transfer to/from the specified endpoint.
44196 +dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(dwc_dma_t * dma_desc_addr,
44199 + return DWC_DMA_ALLOC_ATOMIC(count * sizeof(dwc_otg_dev_dma_desc_t),
44204 + * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc.
44206 +void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr,
44207 + uint32_t dma_desc_addr, uint32_t count)
44209 + DWC_DMA_FREE(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr,
44213 +#ifdef DWC_EN_ISOC
44216 + * This function initializes a descriptor chain for Isochronous transfer
44218 + * @param core_if Programming view of DWC_otg controller.
44219 + * @param dwc_ep The EP to start the transfer on.
44222 +void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if,
44223 + dwc_ep_t * dwc_ep)
44226 + dsts_data_t dsts = {.d32 = 0 };
44227 + depctl_data_t depctl = {.d32 = 0 };
44228 + volatile uint32_t *addr;
44232 + if (dwc_ep->is_in)
44233 + dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;
44235 + dwc_ep->desc_cnt =
44236 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44237 + dwc_ep->bInterval;
44239 + /** Allocate descriptors for double buffering */
44240 + dwc_ep->iso_desc_addr =
44241 + dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr,
44242 + dwc_ep->desc_cnt * 2);
44243 + if (dwc_ep->desc_addr) {
44244 + DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__);
44248 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44250 + /** ISO OUT EP */
44251 + if (dwc_ep->is_in == 0) {
44252 + dev_dma_desc_sts_t sts = {.d32 = 0 };
44253 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
44254 + dma_addr_t dma_ad;
44255 + uint32_t data_per_desc;
44256 + dwc_otg_dev_out_ep_regs_t *out_regs =
44257 + core_if->dev_if->out_ep_regs[dwc_ep->num];
44260 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
44261 + dma_ad = (dma_addr_t) DWC_READ_REG32(&(out_regs->doepdma));
44263 + /** Buffer 0 descriptors setup */
44264 + dma_ad = dwc_ep->dma_addr0;
44266 + sts.b_iso_out.bs = BS_HOST_READY;
44267 + sts.b_iso_out.rxsts = 0;
44268 + sts.b_iso_out.l = 0;
44269 + sts.b_iso_out.sp = 0;
44270 + sts.b_iso_out.ioc = 0;
44271 + sts.b_iso_out.pid = 0;
44272 + sts.b_iso_out.framenum = 0;
44275 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44276 + i += dwc_ep->pkt_per_frm) {
44278 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
44279 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44280 + if (len > dwc_ep->data_per_frame)
44282 + dwc_ep->data_per_frame -
44283 + j * dwc_ep->maxpacket;
44285 + data_per_desc = dwc_ep->maxpacket;
44286 + len = data_per_desc % 4;
44288 + data_per_desc += 4 - len;
44290 + sts.b_iso_out.rxbytes = data_per_desc;
44291 + dma_desc->buf = dma_ad;
44292 + dma_desc->status.d32 = sts.d32;
44294 + offset += data_per_desc;
44296 + dma_ad += data_per_desc;
44300 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
44301 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44302 + if (len > dwc_ep->data_per_frame)
44304 + dwc_ep->data_per_frame -
44305 + j * dwc_ep->maxpacket;
44307 + data_per_desc = dwc_ep->maxpacket;
44308 + len = data_per_desc % 4;
44310 + data_per_desc += 4 - len;
44311 + sts.b_iso_out.rxbytes = data_per_desc;
44312 + dma_desc->buf = dma_ad;
44313 + dma_desc->status.d32 = sts.d32;
44315 + offset += data_per_desc;
44317 + dma_ad += data_per_desc;
44320 + sts.b_iso_out.ioc = 1;
44321 + len = (j + 1) * dwc_ep->maxpacket;
44322 + if (len > dwc_ep->data_per_frame)
44324 + dwc_ep->data_per_frame - j * dwc_ep->maxpacket;
44326 + data_per_desc = dwc_ep->maxpacket;
44327 + len = data_per_desc % 4;
44329 + data_per_desc += 4 - len;
44330 + sts.b_iso_out.rxbytes = data_per_desc;
44332 + dma_desc->buf = dma_ad;
44333 + dma_desc->status.d32 = sts.d32;
44336 + /** Buffer 1 descriptors setup */
44337 + sts.b_iso_out.ioc = 0;
44338 + dma_ad = dwc_ep->dma_addr1;
44341 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44342 + i += dwc_ep->pkt_per_frm) {
44343 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
44344 + uint32_t len = (j + 1) * dwc_ep->maxpacket;
44345 + if (len > dwc_ep->data_per_frame)
44347 + dwc_ep->data_per_frame -
44348 + j * dwc_ep->maxpacket;
44350 + data_per_desc = dwc_ep->maxpacket;
44351 + len = data_per_desc % 4;
44353 + data_per_desc += 4 - len;
44356 + sts.b_iso_out.rxbytes = data_per_desc;
44357 + dma_desc->buf = dma_ad;
44358 + dma_desc->status.d32 = sts.d32;
44360 + offset += data_per_desc;
44362 + dma_ad += data_per_desc;
44365 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
44367 + ((j + 1) * dwc_ep->maxpacket >
44368 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
44369 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
44371 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
44372 + sts.b_iso_out.rxbytes = data_per_desc;
44373 + dma_desc->buf = dma_ad;
44374 + dma_desc->status.d32 = sts.d32;
44376 + offset += data_per_desc;
44378 + dma_ad += data_per_desc;
44381 + sts.b_iso_out.ioc = 1;
44382 + sts.b_iso_out.l = 1;
44384 + ((j + 1) * dwc_ep->maxpacket >
44385 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
44386 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
44388 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
44389 + sts.b_iso_out.rxbytes = data_per_desc;
44391 + dma_desc->buf = dma_ad;
44392 + dma_desc->status.d32 = sts.d32;
44394 + dwc_ep->next_frame = 0;
44396 + /** Write dma_ad into DOEPDMA register */
44397 + DWC_WRITE_REG32(&(out_regs->doepdma),
44398 + (uint32_t) dwc_ep->iso_dma_desc_addr);
44403 + dev_dma_desc_sts_t sts = {.d32 = 0 };
44404 + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
44405 + dma_addr_t dma_ad;
44406 + dwc_otg_dev_in_ep_regs_t *in_regs =
44407 + core_if->dev_if->in_ep_regs[dwc_ep->num];
44408 + unsigned int frmnumber;
44409 + fifosize_data_t txfifosize, rxfifosize;
44412 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[dwc_ep->num]->
44415 + DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
44417 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
44419 + dma_ad = dwc_ep->dma_addr0;
44422 + DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44424 + sts.b_iso_in.bs = BS_HOST_READY;
44425 + sts.b_iso_in.txsts = 0;
44426 + sts.b_iso_in.sp =
44427 + (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;
44428 + sts.b_iso_in.ioc = 0;
44429 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
44431 + frmnumber = dwc_ep->next_frame;
44433 + sts.b_iso_in.framenum = frmnumber;
44434 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
44435 + sts.b_iso_in.l = 0;
44437 + /** Buffer 0 descriptors setup */
44438 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
44439 + dma_desc->buf = dma_ad;
44440 + dma_desc->status.d32 = sts.d32;
44443 + dma_ad += dwc_ep->data_per_frame;
44444 + sts.b_iso_in.framenum += dwc_ep->bInterval;
44447 + sts.b_iso_in.ioc = 1;
44448 + dma_desc->buf = dma_ad;
44449 + dma_desc->status.d32 = sts.d32;
44452 + /** Buffer 1 descriptors setup */
44453 + sts.b_iso_in.ioc = 0;
44454 + dma_ad = dwc_ep->dma_addr1;
44456 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
44457 + i += dwc_ep->pkt_per_frm) {
44458 + dma_desc->buf = dma_ad;
44459 + dma_desc->status.d32 = sts.d32;
44462 + dma_ad += dwc_ep->data_per_frame;
44463 + sts.b_iso_in.framenum += dwc_ep->bInterval;
44465 + sts.b_iso_in.ioc = 0;
44467 + sts.b_iso_in.ioc = 1;
44468 + sts.b_iso_in.l = 1;
44470 + dma_desc->buf = dma_ad;
44471 + dma_desc->status.d32 = sts.d32;
44473 + dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval;
44475 + /** Write dma_ad into diepdma register */
44476 + DWC_WRITE_REG32(&(in_regs->diepdma),
44477 + (uint32_t) dwc_ep->iso_dma_desc_addr);
44479 + /** Enable endpoint, clear nak */
44481 + depctl.b.epena = 1;
44482 + depctl.b.usbactep = 1;
44483 + depctl.b.cnak = 1;
44485 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
44486 + depctl.d32 = DWC_READ_REG32(addr);
44490 + * This function initializes a descriptor chain for Isochronous transfer
44492 + * @param core_if Programming view of DWC_otg controller.
44493 + * @param ep The EP to start the transfer on.
44496 +void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
44499 + depctl_data_t depctl = {.d32 = 0 };
44500 + volatile uint32_t *addr;
44503 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
44505 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
44508 + if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) {
44511 + deptsiz_data_t deptsiz = {.d32 = 0 };
44514 + ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval;
44516 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
44517 + ep->xfer_count = 0;
44519 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
44521 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
44524 + /* Program the transfer size and packet count
44525 + * as follows: xfersize = N * maxpacket +
44526 + * short_packet pktcnt = N + (short_packet
44529 + deptsiz.b.mc = ep->pkt_per_frm;
44530 + deptsiz.b.xfersize = ep->xfer_len;
44531 + deptsiz.b.pktcnt =
44532 + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
44533 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
44534 + dieptsiz, deptsiz.d32);
44536 + /* Write the DMA register */
44537 + DWC_WRITE_REG32(&
44538 + (core_if->dev_if->in_ep_regs[ep->num]->
44539 + diepdma), (uint32_t) ep->dma_addr);
44542 + deptsiz.b.pktcnt =
44543 + (ep->xfer_len + (ep->maxpacket - 1)) /
44545 + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
44547 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
44548 + doeptsiz, deptsiz.d32);
44550 + /* Write the DMA register */
44551 + DWC_WRITE_REG32(&
44552 + (core_if->dev_if->out_ep_regs[ep->num]->
44553 + doepdma), (uint32_t) ep->dma_addr);
44556 + /** Enable endpoint, clear nak */
44558 + depctl.b.epena = 1;
44559 + depctl.b.cnak = 1;
44561 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
44566 + * This function does the setup for a data transfer for an EP and
44567 + * starts the transfer. For an IN transfer, the packets will be
44568 + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
44569 + * the packets are unloaded from the Rx FIFO in the ISR.
44571 + * @param core_if Programming view of DWC_otg controller.
44572 + * @param ep The EP to start the transfer on.
44575 +static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if,
44578 + if (core_if->dma_enable) {
44579 + if (core_if->dma_desc_enable) {
44581 + ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm;
44583 + ep->desc_cnt = ep->pkt_cnt;
44585 + dwc_otg_iso_ep_start_ddma_transfer(core_if, ep);
44587 + if (core_if->pti_enh_enable) {
44588 + dwc_otg_iso_ep_start_buf_transfer(core_if, ep);
44590 + ep->cur_pkt_addr =
44591 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->
44593 + ep->cur_pkt_dma_addr =
44594 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->
44596 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
44600 + ep->cur_pkt_addr =
44601 + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
44602 + ep->cur_pkt_dma_addr =
44603 + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
44604 + dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
44609 + * This function stops transfer for an EP and
44610 + * resets the ep's variables.
44612 + * @param core_if Programming view of DWC_otg controller.
44613 + * @param ep The EP to start the transfer on.
44616 +void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
44618 + depctl_data_t depctl = {.d32 = 0 };
44619 + volatile uint32_t *addr;
44621 + if (ep->is_in == 1) {
44622 + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
44624 + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
44627 + /* disable the ep */
44628 + depctl.d32 = DWC_READ_REG32(addr);
44630 + depctl.b.epdis = 1;
44631 + depctl.b.snak = 1;
44633 + DWC_WRITE_REG32(addr, depctl.d32);
44635 + if (core_if->dma_desc_enable &&
44636 + ep->iso_desc_addr && ep->iso_dma_desc_addr) {
44637 + dwc_otg_ep_free_desc_chain(ep->iso_desc_addr,
44638 + ep->iso_dma_desc_addr,
44639 + ep->desc_cnt * 2);
44642 + /* reset varibales */
44643 + ep->dma_addr0 = 0;
44644 + ep->dma_addr1 = 0;
44645 + ep->xfer_buff0 = 0;
44646 + ep->xfer_buff1 = 0;
44647 + ep->data_per_frame = 0;
44648 + ep->data_pattern_frame = 0;
44649 + ep->sync_frame = 0;
44650 + ep->buf_proc_intrvl = 0;
44651 + ep->bInterval = 0;
44652 + ep->proc_buf_num = 0;
44653 + ep->pkt_per_frm = 0;
44654 + ep->pkt_per_frm = 0;
44655 + ep->desc_cnt = 0;
44656 + ep->iso_desc_addr = 0;
44657 + ep->iso_dma_desc_addr = 0;
44660 +int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
44661 + uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0,
44662 + dwc_dma_t dma1, int sync_frame, int dp_frame,
44663 + int data_per_frame, int start_frame,
44664 + int buf_proc_intrvl, void *req_handle,
44665 + int atomic_alloc)
44667 + dwc_otg_pcd_ep_t *ep;
44668 + dwc_irqflags_t flags = 0;
44669 + dwc_ep_t *dwc_ep;
44670 + int32_t frm_data;
44671 + dsts_data_t dsts;
44672 + dwc_otg_core_if_t *core_if;
44674 + ep = get_ep_from_handle(pcd, ep_handle);
44676 + if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
44677 + DWC_WARN("bad ep\n");
44678 + return -DWC_E_INVALID;
44681 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
44682 + core_if = GET_CORE_IF(pcd);
44683 + dwc_ep = &ep->dwc_ep;
44685 + if (ep->iso_req_handle) {
44686 + DWC_WARN("ISO request in progress\n");
44689 + dwc_ep->dma_addr0 = dma0;
44690 + dwc_ep->dma_addr1 = dma1;
44692 + dwc_ep->xfer_buff0 = buf0;
44693 + dwc_ep->xfer_buff1 = buf1;
44695 + dwc_ep->data_per_frame = data_per_frame;
44697 + /** @todo - pattern data support is to be implemented in the future */
44698 + dwc_ep->data_pattern_frame = dp_frame;
44699 + dwc_ep->sync_frame = sync_frame;
44701 + dwc_ep->buf_proc_intrvl = buf_proc_intrvl;
44703 + dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);
44705 + dwc_ep->proc_buf_num = 0;
44707 + dwc_ep->pkt_per_frm = 0;
44708 + frm_data = ep->dwc_ep.data_per_frame;
44709 + while (frm_data > 0) {
44710 + dwc_ep->pkt_per_frm++;
44711 + frm_data -= ep->dwc_ep.maxpacket;
44714 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
44716 + if (start_frame == -1) {
44717 + dwc_ep->next_frame = dsts.b.soffn + 1;
44718 + if (dwc_ep->bInterval != 1) {
44719 + dwc_ep->next_frame =
44720 + dwc_ep->next_frame + (dwc_ep->bInterval - 1 -
44721 + dwc_ep->next_frame %
44722 + dwc_ep->bInterval);
44725 + dwc_ep->next_frame = start_frame;
44728 + if (!core_if->pti_enh_enable) {
44729 + dwc_ep->pkt_cnt =
44730 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44731 + dwc_ep->bInterval;
44733 + dwc_ep->pkt_cnt =
44734 + (dwc_ep->data_per_frame *
44735 + (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval)
44736 + - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket;
44739 + if (core_if->dma_desc_enable) {
44740 + dwc_ep->desc_cnt =
44741 + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
44742 + dwc_ep->bInterval;
44745 + if (atomic_alloc) {
44746 + dwc_ep->pkt_info =
44747 + DWC_ALLOC_ATOMIC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44749 + dwc_ep->pkt_info =
44750 + DWC_ALLOC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44752 + if (!dwc_ep->pkt_info) {
44753 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44754 + return -DWC_E_NO_MEMORY;
44756 + if (core_if->pti_enh_enable) {
44757 + dwc_memset(dwc_ep->pkt_info, 0,
44758 + sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
44761 + dwc_ep->cur_pkt = 0;
44762 + ep->iso_req_handle = req_handle;
44764 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44765 + dwc_otg_iso_ep_start_transfer(core_if, dwc_ep);
44769 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
44770 + void *req_handle)
44772 + dwc_irqflags_t flags = 0;
44773 + dwc_otg_pcd_ep_t *ep;
44774 + dwc_ep_t *dwc_ep;
44776 + ep = get_ep_from_handle(pcd, ep_handle);
44777 + if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
44778 + DWC_WARN("bad ep\n");
44779 + return -DWC_E_INVALID;
44781 + dwc_ep = &ep->dwc_ep;
44783 + dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep);
44785 + DWC_FREE(dwc_ep->pkt_info);
44786 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
44787 + if (ep->iso_req_handle != req_handle) {
44788 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44789 + return -DWC_E_INVALID;
44792 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
44794 + ep->iso_req_handle = 0;
44799 + * This function is used for perodical data exchnage between PCD and gadget drivers.
44800 + * for Isochronous EPs
44802 + * - Every time a sync period completes this function is called to
44803 + * perform data exchange between PCD and gadget
44805 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
44806 + void *req_handle)
44809 + dwc_ep_t *dwc_ep;
44811 + dwc_ep = &ep->dwc_ep;
44813 + DWC_SPINUNLOCK(ep->pcd->lock);
44814 + pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle,
44815 + dwc_ep->proc_buf_num ^ 0x1);
44816 + DWC_SPINLOCK(ep->pcd->lock);
44818 + for (i = 0; i < dwc_ep->pkt_cnt; ++i) {
44819 + dwc_ep->pkt_info[i].status = 0;
44820 + dwc_ep->pkt_info[i].offset = 0;
44821 + dwc_ep->pkt_info[i].length = 0;
44825 +int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle,
44826 + void *iso_req_handle)
44828 + dwc_otg_pcd_ep_t *ep;
44829 + dwc_ep_t *dwc_ep;
44831 + ep = get_ep_from_handle(pcd, ep_handle);
44832 + if (!ep->desc || ep->dwc_ep.num == 0) {
44833 + DWC_WARN("bad ep\n");
44834 + return -DWC_E_INVALID;
44836 + dwc_ep = &ep->dwc_ep;
44838 + return dwc_ep->pkt_cnt;
44841 +void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle,
44842 + void *iso_req_handle, int packet,
44843 + int *status, int *actual, int *offset)
44845 + dwc_otg_pcd_ep_t *ep;
44846 + dwc_ep_t *dwc_ep;
44848 + ep = get_ep_from_handle(pcd, ep_handle);
44850 + DWC_WARN("bad ep\n");
44852 + dwc_ep = &ep->dwc_ep;
44854 + *status = dwc_ep->pkt_info[packet].status;
44855 + *actual = dwc_ep->pkt_info[packet].length;
44856 + *offset = dwc_ep->pkt_info[packet].offset;
44859 +#endif /* DWC_EN_ISOC */
44861 +static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
44862 + uint32_t is_in, uint32_t ep_num)
44864 + /* Init EP structure */
44865 + pcd_ep->desc = 0;
44866 + pcd_ep->pcd = pcd;
44867 + pcd_ep->stopped = 1;
44868 + pcd_ep->queue_sof = 0;
44870 + /* Init DWC ep structure */
44871 + pcd_ep->dwc_ep.is_in = is_in;
44872 + pcd_ep->dwc_ep.num = ep_num;
44873 + pcd_ep->dwc_ep.active = 0;
44874 + pcd_ep->dwc_ep.tx_fifo_num = 0;
44875 + /* Control until ep is actvated */
44876 + pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
44877 + pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
44878 + pcd_ep->dwc_ep.dma_addr = 0;
44879 + pcd_ep->dwc_ep.start_xfer_buff = 0;
44880 + pcd_ep->dwc_ep.xfer_buff = 0;
44881 + pcd_ep->dwc_ep.xfer_len = 0;
44882 + pcd_ep->dwc_ep.xfer_count = 0;
44883 + pcd_ep->dwc_ep.sent_zlp = 0;
44884 + pcd_ep->dwc_ep.total_len = 0;
44885 + pcd_ep->dwc_ep.desc_addr = 0;
44886 + pcd_ep->dwc_ep.dma_desc_addr = 0;
44887 + DWC_CIRCLEQ_INIT(&pcd_ep->queue);
44891 + * Initialize ep's
44893 +static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
44897 + dwc_otg_pcd_ep_t *ep;
44898 + int in_ep_cntr, out_ep_cntr;
44899 + uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
44900 + uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
44903 + * Initialize the EP0 structure.
44906 + dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
44909 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
44910 + for (i = 1; in_ep_cntr < num_in_eps; i++) {
44911 + if ((hwcfg1 & 0x1) == 0) {
44912 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr];
44915 + * @todo NGS: Add direction to EP, based on contents
44916 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
44919 + dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
44921 + DWC_CIRCLEQ_INIT(&ep->queue);
44927 + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
44928 + for (i = 1; out_ep_cntr < num_out_eps; i++) {
44929 + if ((hwcfg1 & 0x1) == 0) {
44930 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr];
44933 + * @todo NGS: Add direction to EP, based on contents
44934 + * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
44937 + dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
44938 + DWC_CIRCLEQ_INIT(&ep->queue);
44943 + pcd->ep0state = EP0_DISCONNECT;
44944 + pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
44945 + pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
44949 + * This function is called when the SRP timer expires. The SRP should
44950 + * complete within 6 seconds.
44952 +static void srp_timeout(void *ptr)
44954 + gotgctl_data_t gotgctl;
44955 + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
44956 + volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
44958 + gotgctl.d32 = DWC_READ_REG32(addr);
44960 + core_if->srp_timer_started = 0;
44962 + if (core_if->adp_enable) {
44963 + if (gotgctl.b.bsesvld == 0) {
44964 + gpwrdn_data_t gpwrdn = {.d32 = 0 };
44965 + DWC_PRINTF("SRP Timeout BSESSVLD = 0\n");
44966 + /* Power off the core */
44967 + if (core_if->power_down == 2) {
44968 + gpwrdn.b.pwrdnswtch = 1;
44969 + DWC_MODIFY_REG32(&core_if->
44970 + core_global_regs->gpwrdn,
44975 + gpwrdn.b.pmuintsel = 1;
44976 + gpwrdn.b.pmuactv = 1;
44977 + DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
44979 + dwc_otg_adp_probe_start(core_if);
44981 + DWC_PRINTF("SRP Timeout BSESSVLD = 1\n");
44982 + core_if->op_state = B_PERIPHERAL;
44983 + dwc_otg_core_init(core_if);
44984 + dwc_otg_enable_global_interrupts(core_if);
44985 + cil_pcd_start(core_if);
44989 + if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
44990 + (core_if->core_params->i2c_enable)) {
44991 + DWC_PRINTF("SRP Timeout\n");
44993 + if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {
44994 + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
44995 + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
44998 + /* Clear Session Request */
45000 + gotgctl.b.sesreq = 1;
45001 + DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
45004 + core_if->srp_success = 0;
45006 + __DWC_ERROR("Device not connected/responding\n");
45007 + gotgctl.b.sesreq = 0;
45008 + DWC_WRITE_REG32(addr, gotgctl.d32);
45010 + } else if (gotgctl.b.sesreq) {
45011 + DWC_PRINTF("SRP Timeout\n");
45013 + __DWC_ERROR("Device not connected/responding\n");
45014 + gotgctl.b.sesreq = 0;
45015 + DWC_WRITE_REG32(addr, gotgctl.d32);
45017 + DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32);
45025 +extern void start_next_request(dwc_otg_pcd_ep_t * ep);
45027 +static void start_xfer_tasklet_func(void *data)
45029 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
45030 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45033 + depctl_data_t diepctl;
45035 + DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
45037 + diepctl.d32 = DWC_READ_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl);
45039 + if (pcd->ep0.queue_sof) {
45040 + pcd->ep0.queue_sof = 0;
45041 + start_next_request(&pcd->ep0);
45045 + for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
45046 + depctl_data_t diepctl;
45048 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
45050 + if (pcd->in_ep[i].queue_sof) {
45051 + pcd->in_ep[i].queue_sof = 0;
45052 + start_next_request(&pcd->in_ep[i]);
45061 + * This function initialized the PCD portion of the driver.
45064 +dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
45066 + dwc_otg_pcd_t *pcd = NULL;
45067 + dwc_otg_dev_if_t *dev_if;
45071 + * Allocate PCD structure
45073 + pcd = DWC_ALLOC(sizeof(dwc_otg_pcd_t));
45075 + if (pcd == NULL) {
45079 + pcd->lock = DWC_SPINLOCK_ALLOC();
45080 + DWC_DEBUGPL(DBG_HCDV, "Init of PCD %p given core_if %p\n",
45081 + pcd, core_if);//GRAYG
45082 + if (!pcd->lock) {
45083 + DWC_ERROR("Could not allocate lock for pcd");
45087 + /* Set core_if's lock pointer to hcd->lock */
45088 + core_if->lock = pcd->lock;
45089 + pcd->core_if = core_if;
45091 + dev_if = core_if->dev_if;
45092 + dev_if->isoc_ep = NULL;
45094 + if (core_if->hwcfg4.b.ded_fifo_en) {
45095 + DWC_PRINTF("Dedicated Tx FIFOs mode\n");
45097 + DWC_PRINTF("Shared Tx FIFO mode\n");
45101 + * Initialized the Core for Device mode here if there is nod ADP support.
45102 + * Otherwise it will be done later in dwc_otg_adp_start routine.
45104 + if (dwc_otg_is_device_mode(core_if) /*&& !core_if->adp_enable*/) {
45105 + dwc_otg_core_dev_init(core_if);
45109 + * Register the PCD Callbacks.
45111 + dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd);
45114 + * Initialize the DMA buffer for SETUP packets
45116 + if (GET_CORE_IF(pcd)->dma_enable) {
45118 + DWC_DMA_ALLOC(sizeof(*pcd->setup_pkt) * 5,
45119 + &pcd->setup_pkt_dma_handle);
45120 + if (pcd->setup_pkt == NULL) {
45125 + pcd->status_buf =
45126 + DWC_DMA_ALLOC(sizeof(uint16_t),
45127 + &pcd->status_buf_dma_handle);
45128 + if (pcd->status_buf == NULL) {
45129 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
45130 + pcd->setup_pkt, pcd->setup_pkt_dma_handle);
45135 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45136 + dev_if->setup_desc_addr[0] =
45137 + dwc_otg_ep_alloc_desc_chain
45138 + (&dev_if->dma_setup_desc_addr[0], 1);
45139 + dev_if->setup_desc_addr[1] =
45140 + dwc_otg_ep_alloc_desc_chain
45141 + (&dev_if->dma_setup_desc_addr[1], 1);
45142 + dev_if->in_desc_addr =
45143 + dwc_otg_ep_alloc_desc_chain
45144 + (&dev_if->dma_in_desc_addr, 1);
45145 + dev_if->out_desc_addr =
45146 + dwc_otg_ep_alloc_desc_chain
45147 + (&dev_if->dma_out_desc_addr, 1);
45148 + pcd->data_terminated = 0;
45150 + if (dev_if->setup_desc_addr[0] == 0
45151 + || dev_if->setup_desc_addr[1] == 0
45152 + || dev_if->in_desc_addr == 0
45153 + || dev_if->out_desc_addr == 0) {
45155 + if (dev_if->out_desc_addr)
45156 + dwc_otg_ep_free_desc_chain
45157 + (dev_if->out_desc_addr,
45158 + dev_if->dma_out_desc_addr, 1);
45159 + if (dev_if->in_desc_addr)
45160 + dwc_otg_ep_free_desc_chain
45161 + (dev_if->in_desc_addr,
45162 + dev_if->dma_in_desc_addr, 1);
45163 + if (dev_if->setup_desc_addr[1])
45164 + dwc_otg_ep_free_desc_chain
45165 + (dev_if->setup_desc_addr[1],
45166 + dev_if->dma_setup_desc_addr[1], 1);
45167 + if (dev_if->setup_desc_addr[0])
45168 + dwc_otg_ep_free_desc_chain
45169 + (dev_if->setup_desc_addr[0],
45170 + dev_if->dma_setup_desc_addr[0], 1);
45172 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
45174 + pcd->setup_pkt_dma_handle);
45175 + DWC_DMA_FREE(sizeof(*pcd->status_buf),
45177 + pcd->status_buf_dma_handle);
45185 + pcd->setup_pkt = DWC_ALLOC(sizeof(*pcd->setup_pkt) * 5);
45186 + if (pcd->setup_pkt == NULL) {
45191 + pcd->status_buf = DWC_ALLOC(sizeof(uint16_t));
45192 + if (pcd->status_buf == NULL) {
45193 + DWC_FREE(pcd->setup_pkt);
45199 + dwc_otg_pcd_reinit(pcd);
45201 + /* Allocate the cfi object for the PCD */
45202 +#ifdef DWC_UTE_CFI
45203 + pcd->cfi = DWC_ALLOC(sizeof(cfiobject_t));
45204 + if (NULL == pcd->cfi)
45206 + if (init_cfi(pcd->cfi)) {
45207 + CFI_INFO("%s: Failed to init the CFI object\n", __func__);
45212 + /* Initialize tasklets */
45213 + pcd->start_xfer_tasklet = DWC_TASK_ALLOC("xfer_tasklet",
45214 + start_xfer_tasklet_func, pcd);
45215 + pcd->test_mode_tasklet = DWC_TASK_ALLOC("test_mode_tasklet",
45216 + do_test_mode, pcd);
45218 + /* Initialize SRP timer */
45219 + core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
45221 + if (core_if->core_params->dev_out_nak) {
45223 + * Initialize xfer timeout timer. Implemented for
45224 + * 2.93a feature "Device DDMA OUT NAK Enhancement"
45226 + for(i = 0; i < MAX_EPS_CHANNELS; i++) {
45227 + pcd->core_if->ep_xfer_timer[i] =
45228 + DWC_TIMER_ALLOC("ep timer", ep_xfer_timeout,
45229 + &pcd->core_if->ep_xfer_info[i]);
45234 +#ifdef DWC_UTE_CFI
45237 + if (pcd->setup_pkt)
45238 + DWC_FREE(pcd->setup_pkt);
45239 + if (pcd->status_buf)
45240 + DWC_FREE(pcd->status_buf);
45241 +#ifdef DWC_UTE_CFI
45243 + DWC_FREE(pcd->cfi);
45252 + * Remove PCD specific data
45254 +void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd)
45256 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
45258 + if (pcd->core_if->core_params->dev_out_nak) {
45259 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
45260 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[i]);
45261 + pcd->core_if->ep_xfer_info[i].state = 0;
45265 + if (GET_CORE_IF(pcd)->dma_enable) {
45266 + DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt,
45267 + pcd->setup_pkt_dma_handle);
45268 + DWC_DMA_FREE(sizeof(uint16_t), pcd->status_buf,
45269 + pcd->status_buf_dma_handle);
45270 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45271 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0],
45272 + dev_if->dma_setup_desc_addr
45274 + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1],
45275 + dev_if->dma_setup_desc_addr
45277 + dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr,
45278 + dev_if->dma_in_desc_addr, 1);
45279 + dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr,
45280 + dev_if->dma_out_desc_addr,
45284 + DWC_FREE(pcd->setup_pkt);
45285 + DWC_FREE(pcd->status_buf);
45287 + DWC_SPINLOCK_FREE(pcd->lock);
45288 + /* Set core_if's lock pointer to NULL */
45289 + pcd->core_if->lock = NULL;
45291 + DWC_TASK_FREE(pcd->start_xfer_tasklet);
45292 + DWC_TASK_FREE(pcd->test_mode_tasklet);
45293 + if (pcd->core_if->core_params->dev_out_nak) {
45294 + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
45295 + if (pcd->core_if->ep_xfer_timer[i]) {
45296 + DWC_TIMER_FREE(pcd->core_if->ep_xfer_timer[i]);
45301 +/* Release the CFI object's dynamic memory */
45302 +#ifdef DWC_UTE_CFI
45303 + if (pcd->cfi->ops.release) {
45304 + pcd->cfi->ops.release(pcd->cfi);
45312 + * Returns whether registered pcd is dual speed or not
45314 +uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd)
45316 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45318 + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) ||
45319 + ((core_if->hwcfg2.b.hs_phy_type == 2) &&
45320 + (core_if->hwcfg2.b.fs_phy_type == 1) &&
45321 + (core_if->core_params->ulpi_fs_ls))) {
45329 + * Returns whether registered pcd is OTG capable or not
45331 +uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd)
45333 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
45334 + gusbcfg_data_t usbcfg = {.d32 = 0 };
45336 + usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
45337 + if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) {
45345 + * This function assigns periodic Tx FIFO to an periodic EP
45346 + * in shared Tx FIFO mode
45348 +static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if)
45350 + uint32_t TxMsk = 1;
45353 + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) {
45354 + if ((TxMsk & core_if->tx_msk) == 0) {
45355 + core_if->tx_msk |= TxMsk;
45364 + * This function assigns periodic Tx FIFO to an periodic EP
45365 + * in shared Tx FIFO mode
45367 +static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if)
45369 + uint32_t PerTxMsk = 1;
45371 + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) {
45372 + if ((PerTxMsk & core_if->p_tx_msk) == 0) {
45373 + core_if->p_tx_msk |= PerTxMsk;
45382 + * This function releases periodic Tx FIFO
45383 + * in shared Tx FIFO mode
45385 +static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if,
45386 + uint32_t fifo_num)
45388 + core_if->p_tx_msk =
45389 + (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
45393 + * This function releases periodic Tx FIFO
45394 + * in shared Tx FIFO mode
45396 +static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num)
45398 + core_if->tx_msk =
45399 + (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
45403 + * This function is being called from gadget
45404 + * to enable PCD endpoint.
45406 +int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
45407 + const uint8_t * ep_desc, void *usb_ep)
45410 + dwc_otg_pcd_ep_t *ep = NULL;
45411 + const usb_endpoint_descriptor_t *desc;
45412 + dwc_irqflags_t flags;
45413 + fifosize_data_t dptxfsiz = {.d32 = 0 };
45414 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
45415 + gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
45419 + desc = (const usb_endpoint_descriptor_t *)ep_desc;
45422 + pcd->ep0.priv = usb_ep;
45424 + retval = -DWC_E_INVALID;
45428 + num = UE_GET_ADDR(desc->bEndpointAddress);
45429 + dir = UE_GET_DIR(desc->bEndpointAddress);
45431 + if (!desc->wMaxPacketSize) {
45432 + DWC_WARN("bad maxpacketsize\n");
45433 + retval = -DWC_E_INVALID;
45437 + if (dir == UE_DIR_IN) {
45438 + epcount = pcd->core_if->dev_if->num_in_eps;
45439 + for (i = 0; i < epcount; i++) {
45440 + if (num == pcd->in_ep[i].dwc_ep.num) {
45441 + ep = &pcd->in_ep[i];
45446 + epcount = pcd->core_if->dev_if->num_out_eps;
45447 + for (i = 0; i < epcount; i++) {
45448 + if (num == pcd->out_ep[i].dwc_ep.num) {
45449 + ep = &pcd->out_ep[i];
45456 + DWC_WARN("bad address\n");
45457 + retval = -DWC_E_INVALID;
45461 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45464 + ep->priv = usb_ep;
45467 + * Activate the EP
45471 + ep->dwc_ep.is_in = (dir == UE_DIR_IN);
45472 + ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize);
45474 + ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE;
45476 + if (ep->dwc_ep.is_in) {
45477 + if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45478 + ep->dwc_ep.tx_fifo_num = 0;
45480 + if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
45482 + * if ISOC EP then assign a Periodic Tx FIFO.
45484 + ep->dwc_ep.tx_fifo_num =
45485 + assign_perio_tx_fifo(GET_CORE_IF(pcd));
45489 + * if Dedicated FIFOs mode is on then assign a Tx FIFO.
45491 + ep->dwc_ep.tx_fifo_num =
45492 + assign_tx_fifo(GET_CORE_IF(pcd));
45495 + /* Calculating EP info controller base address */
45496 + if (ep->dwc_ep.tx_fifo_num
45497 + && GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45499 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
45500 + core_global_regs->gdfifocfg);
45501 + gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
45504 + (&GET_CORE_IF(pcd)->core_global_regs->
45505 + dtxfsiz[ep->dwc_ep.tx_fifo_num - 1]) >> 16);
45506 + gdfifocfg.b.epinfobase =
45507 + gdfifocfgbase.d32 + dptxfsiz.d32;
45508 + if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
45509 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
45510 + core_global_regs->gdfifocfg,
45515 + /* Set initial data PID. */
45516 + if (ep->dwc_ep.type == UE_BULK) {
45517 + ep->dwc_ep.data_pid_start = 0;
45520 + /* Alloc DMA Descriptors */
45521 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45522 +#ifndef DWC_UTE_PER_IO
45523 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
45525 + ep->dwc_ep.desc_addr =
45526 + dwc_otg_ep_alloc_desc_chain(&ep->
45527 + dwc_ep.dma_desc_addr,
45528 + MAX_DMA_DESC_CNT);
45529 + if (!ep->dwc_ep.desc_addr) {
45530 + DWC_WARN("%s, can't allocate DMA descriptor\n",
45532 + retval = -DWC_E_SHUTDOWN;
45533 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45536 +#ifndef DWC_UTE_PER_IO
45541 + DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n",
45542 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
45543 + ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc);
45544 +#ifdef DWC_UTE_PER_IO
45545 + ep->dwc_ep.xiso_bInterval = 1 << (ep->desc->bInterval - 1);
45547 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
45548 + ep->dwc_ep.bInterval = 1 << (ep->desc->bInterval - 1);
45549 + ep->dwc_ep.frame_num = 0xFFFFFFFF;
45552 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
45554 +#ifdef DWC_UTE_CFI
45555 + if (pcd->cfi->ops.ep_enable) {
45556 + pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep);
45560 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45567 + * This function is being called from gadget
45568 + * to disable PCD endpoint.
45570 +int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle)
45572 + dwc_otg_pcd_ep_t *ep;
45573 + dwc_irqflags_t flags;
45574 + dwc_otg_dev_dma_desc_t *desc_addr;
45575 + dwc_dma_t dma_desc_addr;
45576 + gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
45577 + gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
45578 + fifosize_data_t dptxfsiz = {.d32 = 0 };
45580 + ep = get_ep_from_handle(pcd, ep_handle);
45582 + if (!ep || !ep->desc) {
45583 + DWC_DEBUGPL(DBG_PCD, "bad ep address\n");
45584 + return -DWC_E_INVALID;
45587 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45589 + dwc_otg_request_nuke(ep);
45591 + dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep);
45592 + if (pcd->core_if->core_params->dev_out_nak) {
45593 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[ep->dwc_ep.num]);
45594 + pcd->core_if->ep_xfer_info[ep->dwc_ep.num].state = 0;
45600 + DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg);
45601 + gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
45603 + if (ep->dwc_ep.is_in) {
45604 + if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45605 + /* Flush the Tx FIFO */
45606 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd),
45607 + ep->dwc_ep.tx_fifo_num);
45609 + release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
45610 + release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
45611 + if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
45612 + /* Decreasing EPinfo Base Addr */
45615 + (&GET_CORE_IF(pcd)->
45616 + core_global_regs->dtxfsiz[ep->dwc_ep.tx_fifo_num-1]) >> 16);
45617 + gdfifocfg.b.epinfobase = gdfifocfgbase.d32 - dptxfsiz.d32;
45618 + if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
45619 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg,
45625 + /* Free DMA Descriptors */
45626 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
45627 + if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
45628 + desc_addr = ep->dwc_ep.desc_addr;
45629 + dma_desc_addr = ep->dwc_ep.dma_desc_addr;
45631 + /* Cannot call dma_free_coherent() with IRQs disabled */
45632 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45633 + dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
45634 + MAX_DMA_DESC_CNT);
45636 + goto out_unlocked;
45639 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
45642 + DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num,
45643 + ep->dwc_ep.is_in ? "IN" : "OUT");
45648 +/******************************************************************************/
45649 +#ifdef DWC_UTE_PER_IO
45652 + * Free the request and its extended parts
45655 +void dwc_pcd_xiso_ereq_free(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req)
45657 + DWC_FREE(req->ext_req.per_io_frame_descs);
45662 + * Start the next request in the endpoint's queue.
45665 +int dwc_otg_pcd_xiso_start_next_request(dwc_otg_pcd_t * pcd,
45666 + dwc_otg_pcd_ep_t * ep)
45669 + dwc_otg_pcd_request_t *req = NULL;
45670 + dwc_ep_t *dwcep = NULL;
45671 + struct dwc_iso_xreq_port *ereq = NULL;
45672 + struct dwc_iso_pkt_desc_port *ddesc_iso;
45674 + depctl_data_t diepctl;
45676 + dwcep = &ep->dwc_ep;
45678 + if (dwcep->xiso_active_xfers > 0) {
45679 +#if 0 //Disable this to decrease s/w overhead that is crucial for Isoc transfers
45680 + DWC_WARN("There are currently active transfers for EP%d \
45681 + (active=%d; queued=%d)", dwcep->num, dwcep->xiso_active_xfers,
45682 + dwcep->xiso_queued_xfers);
45687 + nat = UGETW(ep->desc->wMaxPacketSize);
45688 + nat = (nat >> 11) & 0x03;
45690 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
45691 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
45692 + ereq = &req->ext_req;
45695 + /* Get the frame number */
45696 + dwcep->xiso_frame_num =
45697 + dwc_otg_get_frame_number(GET_CORE_IF(pcd));
45698 + DWC_DEBUG("FRM_NUM=%d", dwcep->xiso_frame_num);
45700 + ddesc_iso = ereq->per_io_frame_descs;
45702 + if (dwcep->is_in) {
45703 + /* Setup DMA Descriptor chain for IN Isoc request */
45704 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45705 + //if ((i % (nat + 1)) == 0)
45707 + dwcep->xiso_frame_num =
45708 + (dwcep->xiso_bInterval +
45709 + dwcep->xiso_frame_num) & 0x3FFF;
45710 + dwcep->desc_addr[i].buf =
45711 + req->dma + ddesc_iso[i].offset;
45712 + dwcep->desc_addr[i].status.b_iso_in.txbytes =
45713 + ddesc_iso[i].length;
45714 + dwcep->desc_addr[i].status.b_iso_in.framenum =
45715 + dwcep->xiso_frame_num;
45716 + dwcep->desc_addr[i].status.b_iso_in.bs =
45718 + dwcep->desc_addr[i].status.b_iso_in.txsts = 0;
45719 + dwcep->desc_addr[i].status.b_iso_in.sp =
45720 + (ddesc_iso[i].length %
45721 + dwcep->maxpacket) ? 1 : 0;
45722 + dwcep->desc_addr[i].status.b_iso_in.ioc = 0;
45723 + dwcep->desc_addr[i].status.b_iso_in.pid = nat + 1;
45724 + dwcep->desc_addr[i].status.b_iso_in.l = 0;
45726 + /* Process the last descriptor */
45727 + if (i == ereq->pio_pkt_count - 1) {
45728 + dwcep->desc_addr[i].status.b_iso_in.ioc = 1;
45729 + dwcep->desc_addr[i].status.b_iso_in.l = 1;
45733 + /* Setup and start the transfer for this endpoint */
45734 + dwcep->xiso_active_xfers++;
45735 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if->
45736 + in_ep_regs[dwcep->num]->diepdma,
45737 + dwcep->dma_desc_addr);
45739 + diepctl.b.epena = 1;
45740 + diepctl.b.cnak = 1;
45741 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
45742 + in_ep_regs[dwcep->num]->diepctl, 0,
45745 + /* Setup DMA Descriptor chain for OUT Isoc request */
45746 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45747 + //if ((i % (nat + 1)) == 0)
45748 + dwcep->xiso_frame_num = (dwcep->xiso_bInterval +
45749 + dwcep->xiso_frame_num) & 0x3FFF;
45750 + dwcep->desc_addr[i].buf =
45751 + req->dma + ddesc_iso[i].offset;
45752 + dwcep->desc_addr[i].status.b_iso_out.rxbytes =
45753 + ddesc_iso[i].length;
45754 + dwcep->desc_addr[i].status.b_iso_out.framenum =
45755 + dwcep->xiso_frame_num;
45756 + dwcep->desc_addr[i].status.b_iso_out.bs =
45758 + dwcep->desc_addr[i].status.b_iso_out.rxsts = 0;
45759 + dwcep->desc_addr[i].status.b_iso_out.sp =
45760 + (ddesc_iso[i].length %
45761 + dwcep->maxpacket) ? 1 : 0;
45762 + dwcep->desc_addr[i].status.b_iso_out.ioc = 0;
45763 + dwcep->desc_addr[i].status.b_iso_out.pid = nat + 1;
45764 + dwcep->desc_addr[i].status.b_iso_out.l = 0;
45766 + /* Process the last descriptor */
45767 + if (i == ereq->pio_pkt_count - 1) {
45768 + dwcep->desc_addr[i].status.b_iso_out.ioc = 1;
45769 + dwcep->desc_addr[i].status.b_iso_out.l = 1;
45773 + /* Setup and start the transfer for this endpoint */
45774 + dwcep->xiso_active_xfers++;
45775 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
45776 + dev_if->out_ep_regs[dwcep->num]->
45777 + doepdma, dwcep->dma_desc_addr);
45779 + diepctl.b.epena = 1;
45780 + diepctl.b.cnak = 1;
45781 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
45782 + dev_if->out_ep_regs[dwcep->num]->
45783 + doepctl, 0, diepctl.d32);
45794 + * - Remove the request from the queue
45796 +void complete_xiso_ep(dwc_otg_pcd_ep_t * ep)
45798 + dwc_otg_pcd_request_t *req = NULL;
45799 + struct dwc_iso_xreq_port *ereq = NULL;
45800 + struct dwc_iso_pkt_desc_port *ddesc_iso = NULL;
45801 + dwc_ep_t *dwcep = NULL;
45805 + dwcep = &ep->dwc_ep;
45807 + /* Get the first pending request from the queue */
45808 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
45809 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
45811 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
45814 + dwcep->xiso_active_xfers--;
45815 + dwcep->xiso_queued_xfers--;
45816 + /* Remove this request from the queue */
45817 + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
45819 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
45824 + ereq = &req->ext_req;
45825 + ddesc_iso = ereq->per_io_frame_descs;
45827 + if (dwcep->xiso_active_xfers < 0) {
45828 + DWC_WARN("EP#%d (xiso_active_xfers=%d)", dwcep->num,
45829 + dwcep->xiso_active_xfers);
45832 + /* Fill the Isoc descs of portable extended req from dma descriptors */
45833 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45834 + if (dwcep->is_in) { /* IN endpoints */
45835 + ddesc_iso[i].actual_length = ddesc_iso[i].length -
45836 + dwcep->desc_addr[i].status.b_iso_in.txbytes;
45837 + ddesc_iso[i].status =
45838 + dwcep->desc_addr[i].status.b_iso_in.txsts;
45839 + } else { /* OUT endpoints */
45840 + ddesc_iso[i].actual_length = ddesc_iso[i].length -
45841 + dwcep->desc_addr[i].status.b_iso_out.rxbytes;
45842 + ddesc_iso[i].status =
45843 + dwcep->desc_addr[i].status.b_iso_out.rxsts;
45847 + DWC_SPINUNLOCK(ep->pcd->lock);
45849 + /* Call the completion function in the non-portable logic */
45850 + ep->pcd->fops->xisoc_complete(ep->pcd, ep->priv, req->priv, 0,
45853 + DWC_SPINLOCK(ep->pcd->lock);
45855 + /* Free the request - specific freeing needed for extended request object */
45856 + dwc_pcd_xiso_ereq_free(ep, req);
45858 + /* Start the next request */
45859 + dwc_otg_pcd_xiso_start_next_request(ep->pcd, ep);
45865 + * Create and initialize the Isoc pkt descriptors of the extended request.
45868 +static int dwc_otg_pcd_xiso_create_pkt_descs(dwc_otg_pcd_request_t * req,
45869 + void *ereq_nonport,
45870 + int atomic_alloc)
45872 + struct dwc_iso_xreq_port *ereq = NULL;
45873 + struct dwc_iso_xreq_port *req_mapped = NULL;
45874 + struct dwc_iso_pkt_desc_port *ipds = NULL; /* To be created in this function */
45875 + uint32_t pkt_count;
45878 + ereq = &req->ext_req;
45879 + req_mapped = (struct dwc_iso_xreq_port *)ereq_nonport;
45880 + pkt_count = req_mapped->pio_pkt_count;
45882 + /* Create the isoc descs */
45883 + if (atomic_alloc) {
45884 + ipds = DWC_ALLOC_ATOMIC(sizeof(*ipds) * pkt_count);
45886 + ipds = DWC_ALLOC(sizeof(*ipds) * pkt_count);
45890 + DWC_ERROR("Failed to allocate isoc descriptors");
45891 + return -DWC_E_NO_MEMORY;
45894 + /* Initialize the extended request fields */
45895 + ereq->per_io_frame_descs = ipds;
45896 + ereq->error_count = 0;
45897 + ereq->pio_alloc_pkt_count = pkt_count;
45898 + ereq->pio_pkt_count = pkt_count;
45899 + ereq->tr_sub_flags = req_mapped->tr_sub_flags;
45901 + /* Init the Isoc descriptors */
45902 + for (i = 0; i < pkt_count; i++) {
45903 + ipds[i].length = req_mapped->per_io_frame_descs[i].length;
45904 + ipds[i].offset = req_mapped->per_io_frame_descs[i].offset;
45905 + ipds[i].status = req_mapped->per_io_frame_descs[i].status; /* 0 */
45906 + ipds[i].actual_length =
45907 + req_mapped->per_io_frame_descs[i].actual_length;
45913 +static void prn_ext_request(struct dwc_iso_xreq_port *ereq)
45915 + struct dwc_iso_pkt_desc_port *xfd = NULL;
45918 + DWC_DEBUG("per_io_frame_descs=%p", ereq->per_io_frame_descs);
45919 + DWC_DEBUG("tr_sub_flags=%d", ereq->tr_sub_flags);
45920 + DWC_DEBUG("error_count=%d", ereq->error_count);
45921 + DWC_DEBUG("pio_alloc_pkt_count=%d", ereq->pio_alloc_pkt_count);
45922 + DWC_DEBUG("pio_pkt_count=%d", ereq->pio_pkt_count);
45923 + DWC_DEBUG("res=%d", ereq->res);
45925 + for (i = 0; i < ereq->pio_pkt_count; i++) {
45926 + xfd = &ereq->per_io_frame_descs[0];
45927 + DWC_DEBUG("FD #%d", i);
45929 + DWC_DEBUG("xfd->actual_length=%d", xfd->actual_length);
45930 + DWC_DEBUG("xfd->length=%d", xfd->length);
45931 + DWC_DEBUG("xfd->offset=%d", xfd->offset);
45932 + DWC_DEBUG("xfd->status=%d", xfd->status);
45939 +int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
45940 + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
45941 + int zero, void *req_handle, int atomic_alloc,
45942 + void *ereq_nonport)
45944 + dwc_otg_pcd_request_t *req = NULL;
45945 + dwc_otg_pcd_ep_t *ep;
45946 + dwc_irqflags_t flags;
45949 + ep = get_ep_from_handle(pcd, ep_handle);
45951 + DWC_WARN("bad ep\n");
45952 + return -DWC_E_INVALID;
45955 + /* We support this extension only for DDMA mode */
45956 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
45957 + if (!GET_CORE_IF(pcd)->dma_desc_enable)
45958 + return -DWC_E_INVALID;
45960 + /* Create a dwc_otg_pcd_request_t object */
45961 + if (atomic_alloc) {
45962 + req = DWC_ALLOC_ATOMIC(sizeof(*req));
45964 + req = DWC_ALLOC(sizeof(*req));
45968 + return -DWC_E_NO_MEMORY;
45971 + /* Create the Isoc descs for this request which shall be the exact match
45972 + * of the structure sent to us from the non-portable logic */
45974 + dwc_otg_pcd_xiso_create_pkt_descs(req, ereq_nonport, atomic_alloc);
45976 + DWC_WARN("Failed to init the Isoc descriptors");
45981 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45983 + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
45985 + req->dma = dma_buf;
45986 + req->length = buflen;
45987 + req->sent_zlp = zero;
45988 + req->priv = req_handle;
45990 + //DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
45991 + ep->dwc_ep.dma_addr = dma_buf;
45992 + ep->dwc_ep.start_xfer_buff = buf;
45993 + ep->dwc_ep.xfer_buff = buf;
45994 + ep->dwc_ep.xfer_len = 0;
45995 + ep->dwc_ep.xfer_count = 0;
45996 + ep->dwc_ep.sent_zlp = 0;
45997 + ep->dwc_ep.total_len = buflen;
45999 + /* Add this request to the tail */
46000 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
46001 + ep->dwc_ep.xiso_queued_xfers++;
46003 +//DWC_DEBUG("CP_0");
46004 +//DWC_DEBUG("req->ext_req.tr_sub_flags=%d", req->ext_req.tr_sub_flags);
46005 +//prn_ext_request((struct dwc_iso_xreq_port *) ereq_nonport);
46006 +//prn_ext_request(&req->ext_req);
46008 + //DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46010 + /* If the req->status == ASAP then check if there is any active transfer
46011 + * for this endpoint. If no active transfers, then get the first entry
46012 + * from the queue and start that transfer
46014 + if (req->ext_req.tr_sub_flags == DWC_EREQ_TF_ASAP) {
46015 + res = dwc_otg_pcd_xiso_start_next_request(pcd, ep);
46017 + DWC_WARN("Failed to start the next Isoc transfer");
46018 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46024 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46029 +/* END ifdef DWC_UTE_PER_IO ***************************************************/
46030 +int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
46031 + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
46032 + int zero, void *req_handle, int atomic_alloc)
46034 + dwc_irqflags_t flags;
46035 + dwc_otg_pcd_request_t *req;
46036 + dwc_otg_pcd_ep_t *ep;
46037 + uint32_t max_transfer;
46039 + ep = get_ep_from_handle(pcd, ep_handle);
46040 + if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
46041 + DWC_WARN("bad ep\n");
46042 + return -DWC_E_INVALID;
46045 + if (atomic_alloc) {
46046 + req = DWC_ALLOC_ATOMIC(sizeof(*req));
46048 + req = DWC_ALLOC(sizeof(*req));
46052 + return -DWC_E_NO_MEMORY;
46054 + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
46055 + if (!GET_CORE_IF(pcd)->core_params->opt) {
46056 + if (ep->dwc_ep.num != 0) {
46057 + DWC_ERROR("queue req %p, len %d buf %p\n",
46058 + req_handle, buflen, buf);
46063 + req->dma = dma_buf;
46064 + req->length = buflen;
46065 + req->sent_zlp = zero;
46066 + req->priv = req_handle;
46067 + req->dw_align_buf = NULL;
46068 + if ((dma_buf & 0x3) && GET_CORE_IF(pcd)->dma_enable
46069 + && !GET_CORE_IF(pcd)->dma_desc_enable)
46070 + req->dw_align_buf = DWC_DMA_ALLOC(buflen,
46071 + &req->dw_align_buf_dma);
46072 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46075 + * After adding request to the queue for IN ISOC wait for In Token Received
46076 + * when TX FIFO is empty interrupt and for OUT ISOC wait for OUT Token
46077 + * Received when EP is disabled interrupt to obtain starting microframe
46078 + * (odd/even) start transfer
46080 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
46082 + depctl_data_t depctl = {.d32 =
46083 + DWC_READ_REG32(&pcd->core_if->dev_if->
46084 + in_ep_regs[ep->dwc_ep.num]->
46086 + ++pcd->request_pending;
46088 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
46089 + if (ep->dwc_ep.is_in) {
46090 + depctl.b.cnak = 1;
46091 + DWC_WRITE_REG32(&pcd->core_if->dev_if->
46092 + in_ep_regs[ep->dwc_ep.num]->
46093 + diepctl, depctl.d32);
46096 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46102 + * For EP0 IN without premature status, zlp is required?
46104 + if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {
46105 + DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num);
46106 + //_req->zero = 1;
46109 + /* Start the transfer */
46110 + if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) {
46111 + /* EP0 Transfer? */
46112 + if (ep->dwc_ep.num == 0) {
46113 + switch (pcd->ep0state) {
46114 + case EP0_IN_DATA_PHASE:
46115 + DWC_DEBUGPL(DBG_PCD,
46116 + "%s ep0: EP0_IN_DATA_PHASE\n",
46120 + case EP0_OUT_DATA_PHASE:
46121 + DWC_DEBUGPL(DBG_PCD,
46122 + "%s ep0: EP0_OUT_DATA_PHASE\n",
46124 + if (pcd->request_config) {
46125 + /* Complete STATUS PHASE */
46126 + ep->dwc_ep.is_in = 1;
46127 + pcd->ep0state = EP0_IN_STATUS_PHASE;
46131 + case EP0_IN_STATUS_PHASE:
46132 + DWC_DEBUGPL(DBG_PCD,
46133 + "%s ep0: EP0_IN_STATUS_PHASE\n",
46138 + DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
46140 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46141 + return -DWC_E_SHUTDOWN;
46144 + ep->dwc_ep.dma_addr = dma_buf;
46145 + ep->dwc_ep.start_xfer_buff = buf;
46146 + ep->dwc_ep.xfer_buff = buf;
46147 + ep->dwc_ep.xfer_len = buflen;
46148 + ep->dwc_ep.xfer_count = 0;
46149 + ep->dwc_ep.sent_zlp = 0;
46150 + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
46153 + if ((ep->dwc_ep.xfer_len %
46154 + ep->dwc_ep.maxpacket == 0)
46155 + && (ep->dwc_ep.xfer_len != 0)) {
46156 + ep->dwc_ep.sent_zlp = 1;
46161 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
46163 + } // non-ep0 endpoints
46165 +#ifdef DWC_UTE_CFI
46166 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
46167 + /* store the request length */
46168 + ep->dwc_ep.cfi_req_len = buflen;
46169 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd,
46174 + GET_CORE_IF(ep->pcd)->core_params->
46175 + max_transfer_size;
46177 + /* Setup and start the Transfer */
46178 + if (req->dw_align_buf){
46179 + if (ep->dwc_ep.is_in)
46180 + dwc_memcpy(req->dw_align_buf,
46182 + ep->dwc_ep.dma_addr =
46183 + req->dw_align_buf_dma;
46184 + ep->dwc_ep.start_xfer_buff =
46185 + req->dw_align_buf;
46186 + ep->dwc_ep.xfer_buff =
46187 + req->dw_align_buf;
46189 + ep->dwc_ep.dma_addr = dma_buf;
46190 + ep->dwc_ep.start_xfer_buff = buf;
46191 + ep->dwc_ep.xfer_buff = buf;
46193 + ep->dwc_ep.xfer_len = 0;
46194 + ep->dwc_ep.xfer_count = 0;
46195 + ep->dwc_ep.sent_zlp = 0;
46196 + ep->dwc_ep.total_len = buflen;
46198 + ep->dwc_ep.maxxfer = max_transfer;
46199 + if (GET_CORE_IF(pcd)->dma_desc_enable) {
46200 + uint32_t out_max_xfer =
46201 + DDMA_MAX_TRANSFER_SIZE -
46202 + (DDMA_MAX_TRANSFER_SIZE % 4);
46203 + if (ep->dwc_ep.is_in) {
46204 + if (ep->dwc_ep.maxxfer >
46205 + DDMA_MAX_TRANSFER_SIZE) {
46206 + ep->dwc_ep.maxxfer =
46207 + DDMA_MAX_TRANSFER_SIZE;
46210 + if (ep->dwc_ep.maxxfer >
46212 + ep->dwc_ep.maxxfer =
46217 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
46218 + ep->dwc_ep.maxxfer -=
46219 + (ep->dwc_ep.maxxfer %
46220 + ep->dwc_ep.maxpacket);
46224 + if ((ep->dwc_ep.total_len %
46225 + ep->dwc_ep.maxpacket == 0)
46226 + && (ep->dwc_ep.total_len != 0)) {
46227 + ep->dwc_ep.sent_zlp = 1;
46230 +#ifdef DWC_UTE_CFI
46233 + dwc_otg_ep_start_transfer(GET_CORE_IF(pcd),
46239 + ++pcd->request_pending;
46240 + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
46241 + if (ep->dwc_ep.is_in && ep->stopped
46242 + && !(GET_CORE_IF(pcd)->dma_enable)) {
46243 + /** @todo NGS Create a function for this. */
46244 + diepmsk_data_t diepmsk = {.d32 = 0 };
46245 + diepmsk.b.intktxfemp = 1;
46246 + if (GET_CORE_IF(pcd)->multiproc_int_enable) {
46247 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
46248 + dev_if->dev_global_regs->diepeachintmsk
46249 + [ep->dwc_ep.num], 0,
46252 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
46253 + dev_if->dev_global_regs->
46254 + diepmsk, 0, diepmsk.d32);
46259 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46264 +int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
46265 + void *req_handle)
46267 + dwc_irqflags_t flags;
46268 + dwc_otg_pcd_request_t *req;
46269 + dwc_otg_pcd_ep_t *ep;
46271 + ep = get_ep_from_handle(pcd, ep_handle);
46272 + if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
46273 + DWC_WARN("bad argument\n");
46274 + return -DWC_E_INVALID;
46277 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46279 + /* make sure it's actually queued on this endpoint */
46280 + DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
46281 + if (req->priv == (void *)req_handle) {
46286 + if (req->priv != (void *)req_handle) {
46287 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46288 + return -DWC_E_INVALID;
46291 + if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) {
46292 + dwc_otg_request_done(ep, req, -DWC_E_RESTART);
46297 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46299 + return req ? 0 : -DWC_E_SHUTDOWN;
46304 + * dwc_otg_pcd_ep_wedge - sets the halt feature and ignores clear requests
46306 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
46307 + * requests. If the gadget driver clears the halt status, it will
46308 + * automatically unwedge the endpoint.
46310 + * Returns zero on success, else negative DWC error code.
46312 +int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle)
46314 + dwc_otg_pcd_ep_t *ep;
46315 + dwc_irqflags_t flags;
46318 + ep = get_ep_from_handle(pcd, ep_handle);
46320 + if ((!ep->desc && ep != &pcd->ep0) ||
46321 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
46322 + DWC_WARN("%s, bad ep\n", __func__);
46323 + return -DWC_E_INVALID;
46326 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46327 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
46328 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
46329 + ep->dwc_ep.is_in ? "IN" : "OUT");
46330 + retval = -DWC_E_AGAIN;
46332 + /* This code needs to be reviewed */
46333 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
46334 + dtxfsts_data_t txstatus;
46335 + fifosize_data_t txfifosize;
46338 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
46339 + core_global_regs->dtxfsiz[ep->dwc_ep.
46342 + DWC_READ_REG32(&GET_CORE_IF(pcd)->
46343 + dev_if->in_ep_regs[ep->dwc_ep.num]->
46346 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
46347 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
46348 + retval = -DWC_E_AGAIN;
46350 + if (ep->dwc_ep.num == 0) {
46351 + pcd->ep0state = EP0_STALL;
46355 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
46359 + if (ep->dwc_ep.num == 0) {
46360 + pcd->ep0state = EP0_STALL;
46364 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46368 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46373 +int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value)
46375 + dwc_otg_pcd_ep_t *ep;
46376 + dwc_irqflags_t flags;
46379 + ep = get_ep_from_handle(pcd, ep_handle);
46381 + if (!ep || (!ep->desc && ep != &pcd->ep0) ||
46382 + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
46383 + DWC_WARN("%s, bad ep\n", __func__);
46384 + return -DWC_E_INVALID;
46387 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46388 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
46389 + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
46390 + ep->dwc_ep.is_in ? "IN" : "OUT");
46391 + retval = -DWC_E_AGAIN;
46392 + } else if (value == 0) {
46393 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46394 + } else if (value == 1) {
46395 + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
46396 + dtxfsts_data_t txstatus;
46397 + fifosize_data_t txfifosize;
46400 + DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->
46401 + dtxfsiz[ep->dwc_ep.tx_fifo_num]);
46403 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
46404 + in_ep_regs[ep->dwc_ep.num]->dtxfsts);
46406 + if (txstatus.b.txfspcavail < txfifosize.b.depth) {
46407 + DWC_WARN("%s() Data In Tx Fifo\n", __func__);
46408 + retval = -DWC_E_AGAIN;
46410 + if (ep->dwc_ep.num == 0) {
46411 + pcd->ep0state = EP0_STALL;
46415 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
46419 + if (ep->dwc_ep.num == 0) {
46420 + pcd->ep0state = EP0_STALL;
46424 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
46426 + } else if (value == 2) {
46427 + ep->dwc_ep.stall_clear_flag = 0;
46428 + } else if (value == 3) {
46429 + ep->dwc_ep.stall_clear_flag = 1;
46432 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46438 + * This function initiates remote wakeup of the host from suspend state.
46440 +void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set)
46442 + dctl_data_t dctl = { 0 };
46443 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46444 + dsts_data_t dsts;
46446 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
46447 + if (!dsts.b.suspsts) {
46448 + DWC_WARN("Remote wakeup while is not in suspend state\n");
46450 + /* Check if DEVICE_REMOTE_WAKEUP feature enabled */
46451 + if (pcd->remote_wakeup_enable) {
46454 + if (core_if->adp_enable) {
46455 + gpwrdn_data_t gpwrdn;
46457 + dwc_otg_adp_probe_stop(core_if);
46459 + /* Mask SRP detected interrupt from Power Down Logic */
46461 + gpwrdn.b.srp_det_msk = 1;
46462 + DWC_MODIFY_REG32(&core_if->
46463 + core_global_regs->gpwrdn,
46466 + /* Disable Power Down Logic */
46468 + gpwrdn.b.pmuactv = 1;
46469 + DWC_MODIFY_REG32(&core_if->
46470 + core_global_regs->gpwrdn,
46474 + * Initialize the Core for Device mode.
46476 + core_if->op_state = B_PERIPHERAL;
46477 + dwc_otg_core_init(core_if);
46478 + dwc_otg_enable_global_interrupts(core_if);
46479 + cil_pcd_start(core_if);
46481 + dwc_otg_initiate_srp(core_if);
46484 + dctl.b.rmtwkupsig = 1;
46485 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
46486 + dctl, 0, dctl.d32);
46487 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
46490 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
46491 + dctl, dctl.d32, 0);
46492 + DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
46495 + DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
46499 +#ifdef CONFIG_USB_DWC_OTG_LPM
46501 + * This function initiates remote wakeup of the host from L1 sleep state.
46503 +void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set)
46505 + glpmcfg_data_t lpmcfg;
46506 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46508 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
46510 + /* Check if we are in L1 state */
46511 + if (!lpmcfg.b.prt_sleep_sts) {
46512 + DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n");
46516 + /* Check if host allows remote wakeup */
46517 + if (!lpmcfg.b.rem_wkup_en) {
46518 + DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n");
46522 + /* Check if Resume OK */
46523 + if (!lpmcfg.b.sleep_state_resumeok) {
46524 + DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n");
46528 + lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
46529 + lpmcfg.b.en_utmi_sleep = 0;
46530 + lpmcfg.b.hird_thres &= (~(1 << 4));
46531 + DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
46534 + dctl_data_t dctl = {.d32 = 0 };
46535 + dctl.b.rmtwkupsig = 1;
46536 + /* Set RmtWkUpSig bit to start remote wakup signaling.
46537 + * Hardware will automatically clear this bit.
46539 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl,
46541 + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
46548 + * Performs remote wakeup.
46550 +void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set)
46552 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46553 + dwc_irqflags_t flags;
46554 + if (dwc_otg_is_device_mode(core_if)) {
46555 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46556 +#ifdef CONFIG_USB_DWC_OTG_LPM
46557 + if (core_if->lx_state == DWC_OTG_L1) {
46558 + dwc_otg_pcd_rem_wkup_from_sleep(pcd, set);
46561 + dwc_otg_pcd_rem_wkup_from_suspend(pcd, set);
46562 +#ifdef CONFIG_USB_DWC_OTG_LPM
46565 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46570 +void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs)
46572 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
46573 + dctl_data_t dctl = { 0 };
46575 + if (dwc_otg_is_device_mode(core_if)) {
46576 + dctl.b.sftdiscon = 1;
46577 + DWC_PRINTF("Soft disconnect for %d useconds\n",no_of_usecs);
46578 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
46579 + dwc_udelay(no_of_usecs);
46580 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32,0);
46583 + DWC_PRINTF("NOT SUPPORTED IN HOST MODE\n");
46589 +int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd)
46591 + dsts_data_t dsts;
46592 + gotgctl_data_t gotgctl;
46595 + * This function starts the Protocol if no session is in progress. If
46596 + * a session is already in progress, but the device is suspended,
46597 + * remote wakeup signaling is started.
46600 + /* Check if valid session */
46602 + DWC_READ_REG32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
46603 + if (gotgctl.b.bsesvld) {
46604 + /* Check if suspend state */
46607 + (GET_CORE_IF(pcd)->dev_if->
46608 + dev_global_regs->dsts));
46609 + if (dsts.b.suspsts) {
46610 + dwc_otg_pcd_remote_wakeup(pcd, 1);
46613 + dwc_otg_pcd_initiate_srp(pcd);
46621 + * Start the SRP timer to detect when the SRP does not complete within
46624 + * @param pcd the pcd structure.
46626 +void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd)
46628 + dwc_irqflags_t flags;
46629 + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
46630 + dwc_otg_initiate_srp(GET_CORE_IF(pcd));
46631 + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
46634 +int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd)
46636 + return dwc_otg_get_frame_number(GET_CORE_IF(pcd));
46639 +int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd)
46641 + return GET_CORE_IF(pcd)->core_params->lpm_enable;
46644 +uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd)
46646 + return pcd->b_hnp_enable;
46649 +uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd)
46651 + return pcd->a_hnp_support;
46654 +uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd)
46656 + return pcd->a_alt_hnp_support;
46659 +int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd)
46661 + return pcd->remote_wakeup_enable;
46664 +#endif /* DWC_HOST_ONLY */
46665 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd.h b/drivers/usb/host/dwc_otg/dwc_otg_pcd.h
46666 new file mode 100644
46667 index 0000000..8ef7ba6
46669 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.h
46671 +/* ==========================================================================
46672 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $
46673 + * $Revision: #48 $
46674 + * $Date: 2012/08/10 $
46675 + * $Change: 2047372 $
46677 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
46678 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
46679 + * otherwise expressly agreed to in writing between Synopsys and you.
46681 + * The Software IS NOT an item of Licensed Software or Licensed Product under
46682 + * any End User Software License Agreement or Agreement for Licensed Product
46683 + * with Synopsys or any supplement thereto. You are permitted to use and
46684 + * redistribute this Software in source and binary forms, with or without
46685 + * modification, provided that redistributions of source code must retain this
46686 + * notice. You may not view, use, disclose, copy or distribute this file or
46687 + * any information contained herein except pursuant to this license grant from
46688 + * Synopsys. If you do not agree with this notice, including the disclaimer
46689 + * below, then you are not authorized to use the Software.
46691 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
46692 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46693 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46694 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
46695 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46696 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
46697 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
46698 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46699 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46700 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46702 + * ========================================================================== */
46703 +#ifndef DWC_HOST_ONLY
46704 +#if !defined(__DWC_PCD_H__)
46705 +#define __DWC_PCD_H__
46707 +#include "dwc_otg_os_dep.h"
46709 +#include "dwc_otg_cil.h"
46710 +#include "dwc_otg_pcd_if.h"
46716 + * This file contains the structures, constants, and interfaces for
46717 + * the Perpherial Contoller Driver (PCD).
46719 + * The Peripheral Controller Driver (PCD) for Linux will implement the
46720 + * Gadget API, so that the existing Gadget drivers can be used. For
46721 + * the Mass Storage Function driver the File-backed USB Storage Gadget
46722 + * (FBS) driver will be used. The FBS driver supports the
46723 + * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only
46728 +/** Invalid DMA Address */
46729 +#define DWC_DMA_ADDR_INVALID (~(dwc_dma_t)0)
46731 +/** Max Transfer size for any EP */
46732 +#define DDMA_MAX_TRANSFER_SIZE 65535
46735 + * Get the pointer to the core_if from the pcd pointer.
46737 +#define GET_CORE_IF( _pcd ) (_pcd->core_if)
46742 +typedef enum ep0_state {
46743 + EP0_DISCONNECT, /* no host */
46745 + EP0_IN_DATA_PHASE,
46746 + EP0_OUT_DATA_PHASE,
46747 + EP0_IN_STATUS_PHASE,
46748 + EP0_OUT_STATUS_PHASE,
46752 +/** Fordward declaration.*/
46753 +struct dwc_otg_pcd;
46755 +/** DWC_otg iso request structure.
46758 +typedef struct usb_iso_request dwc_otg_pcd_iso_request_t;
46760 +#ifdef DWC_UTE_PER_IO
46763 + * This shall be the exact analogy of the same type structure defined in the
46764 + * usb_gadget.h. Each descriptor contains
46766 +struct dwc_iso_pkt_desc_port {
46768 + uint32_t length; /* expected length */
46769 + uint32_t actual_length;
46773 +struct dwc_iso_xreq_port {
46774 + /** transfer/submission flag */
46775 + uint32_t tr_sub_flags;
46776 + /** Start the request ASAP */
46777 +#define DWC_EREQ_TF_ASAP 0x00000002
46778 + /** Just enqueue the request w/o initiating a transfer */
46779 +#define DWC_EREQ_TF_ENQUEUE 0x00000004
46782 + * count of ISO packets attached to this request - shall
46783 + * not exceed the pio_alloc_pkt_count
46785 + uint32_t pio_pkt_count;
46786 + /** count of ISO packets allocated for this request */
46787 + uint32_t pio_alloc_pkt_count;
46788 + /** number of ISO packet errors */
46789 + uint32_t error_count;
46790 + /** reserved for future extension */
46792 + /** Will be allocated and freed in the UTE gadget and based on the CFC value */
46793 + struct dwc_iso_pkt_desc_port *per_io_frame_descs;
46796 +/** DWC_otg request structure.
46797 + * This structure is a list of requests.
46799 +typedef struct dwc_otg_pcd_request {
46805 + unsigned sent_zlp:1;
46807 + * Used instead of original buffer if
46808 + * it(physical address) is not dword-aligned.
46810 + uint8_t *dw_align_buf;
46811 + dwc_dma_t dw_align_buf_dma;
46813 + DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry;
46814 +#ifdef DWC_UTE_PER_IO
46815 + struct dwc_iso_xreq_port ext_req;
46816 + //void *priv_ereq_nport; /* */
46818 +} dwc_otg_pcd_request_t;
46820 +DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request);
46822 +/** PCD EP structure.
46823 + * This structure describes an EP, there is an array of EPs in the PCD
46826 +typedef struct dwc_otg_pcd_ep {
46827 + /** USB EP Descriptor */
46828 + const usb_endpoint_descriptor_t *desc;
46830 + /** queue of dwc_otg_pcd_requests. */
46831 + struct req_list queue;
46832 + unsigned stopped:1;
46833 + unsigned disabling:1;
46835 + unsigned queue_sof:1;
46837 +#ifdef DWC_EN_ISOC
46838 + /** ISOC req handle passed */
46839 + void *iso_req_handle;
46840 +#endif //_EN_ISOC_
46842 + /** DWC_otg ep data. */
46845 + /** Pointer to PCD */
46846 + struct dwc_otg_pcd *pcd;
46849 +} dwc_otg_pcd_ep_t;
46851 +/** DWC_otg PCD Structure.
46852 + * This structure encapsulates the data for the dwc_otg PCD.
46854 +struct dwc_otg_pcd {
46855 + const struct dwc_otg_pcd_function_ops *fops;
46856 + /** The DWC otg device pointer */
46857 + struct dwc_otg_device *otg_dev;
46858 + /** Core Interface */
46859 + dwc_otg_core_if_t *core_if;
46860 + /** State of EP0 */
46861 + ep0state_e ep0state;
46862 + /** EP0 Request is pending */
46863 + unsigned ep0_pending:1;
46864 + /** Indicates when SET CONFIGURATION Request is in process */
46865 + unsigned request_config:1;
46866 + /** The state of the Remote Wakeup Enable. */
46867 + unsigned remote_wakeup_enable:1;
46868 + /** The state of the B-Device HNP Enable. */
46869 + unsigned b_hnp_enable:1;
46870 + /** The state of A-Device HNP Support. */
46871 + unsigned a_hnp_support:1;
46872 + /** The state of the A-Device Alt HNP support. */
46873 + unsigned a_alt_hnp_support:1;
46874 + /** Count of pending Requests */
46875 + unsigned request_pending;
46877 + /** SETUP packet for EP0
46878 + * This structure is allocated as a DMA buffer on PCD initialization
46879 + * with enough space for up to 3 setup packets.
46882 + usb_device_request_t req;
46886 + dwc_dma_t setup_pkt_dma_handle;
46888 + /* Additional buffer and flag for CTRL_WR premature case */
46889 + uint8_t *backup_buf;
46890 + unsigned data_terminated;
46892 + /** 2-byte dma buffer used to return status from GET_STATUS */
46893 + uint16_t *status_buf;
46894 + dwc_dma_t status_buf_dma_handle;
46897 + dwc_otg_pcd_ep_t ep0;
46899 + /** Array of IN EPs. */
46900 + dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1];
46901 + /** Array of OUT EPs. */
46902 + dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1];
46903 + /** number of valid EPs in the above array. */
46904 +// unsigned num_eps : 4;
46905 + dwc_spinlock_t *lock;
46907 + /** Tasklet to defer starting of TEST mode transmissions until
46908 + * Status Phase has been completed.
46910 + dwc_tasklet_t *test_mode_tasklet;
46912 + /** Tasklet to delay starting of xfer in DMA mode */
46913 + dwc_tasklet_t *start_xfer_tasklet;
46915 + /** The test mode to enter when the tasklet is executed. */
46916 + unsigned test_mode;
46917 + /** The cfi_api structure that implements most of the CFI API
46918 + * and OTG specific core configuration functionality
46920 +#ifdef DWC_UTE_CFI
46921 + struct cfiobject *cfi;
46926 +//FIXME this functions should be static, and this prototypes should be removed
46927 +extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep);
46928 +extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep,
46929 + dwc_otg_pcd_request_t * req, int32_t status);
46931 +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
46932 + void *req_handle);
46934 +extern void do_test_mode(void *data);
46936 +#endif /* DWC_HOST_ONLY */
46937 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h b/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
46938 new file mode 100644
46939 index 0000000..c8d2e0e
46941 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
46943 +/* ==========================================================================
46944 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $
46945 + * $Revision: #11 $
46946 + * $Date: 2011/10/26 $
46947 + * $Change: 1873028 $
46949 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
46950 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
46951 + * otherwise expressly agreed to in writing between Synopsys and you.
46953 + * The Software IS NOT an item of Licensed Software or Licensed Product under
46954 + * any End User Software License Agreement or Agreement for Licensed Product
46955 + * with Synopsys or any supplement thereto. You are permitted to use and
46956 + * redistribute this Software in source and binary forms, with or without
46957 + * modification, provided that redistributions of source code must retain this
46958 + * notice. You may not view, use, disclose, copy or distribute this file or
46959 + * any information contained herein except pursuant to this license grant from
46960 + * Synopsys. If you do not agree with this notice, including the disclaimer
46961 + * below, then you are not authorized to use the Software.
46963 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
46964 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46965 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46966 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
46967 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46968 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
46969 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
46970 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46971 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46972 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46974 + * ========================================================================== */
46975 +#ifndef DWC_HOST_ONLY
46977 +#if !defined(__DWC_PCD_IF_H__)
46978 +#define __DWC_PCD_IF_H__
46980 +//#include "dwc_os.h"
46981 +#include "dwc_otg_core_if.h"
46984 + * This file defines DWC_OTG PCD Core API.
46987 +struct dwc_otg_pcd;
46988 +typedef struct dwc_otg_pcd dwc_otg_pcd_t;
46990 +/** Maxpacket size for EP0 */
46991 +#define MAX_EP0_SIZE 64
46992 +/** Maxpacket size for any EP */
46993 +#define MAX_PACKET_SIZE 1024
46995 +/** @name Function Driver Callbacks */
46998 +/** This function will be called whenever a previously queued request has
46999 + * completed. The status value will be set to -DWC_E_SHUTDOWN to indicated a
47000 + * failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset,
47001 + * or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid
47003 +typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
47004 + void *req_handle, int32_t status,
47005 + uint32_t actual);
47007 + * This function will be called whenever a previousle queued ISOC request has
47008 + * completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count
47010 + * The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_*
47013 +typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
47014 + void *req_handle, int proc_buf_num);
47015 +/** This function should handle any SETUP request that cannot be handled by the
47016 + * PCD Core. This includes most GET_DESCRIPTORs, SET_CONFIGS, Any
47017 + * class-specific requests, etc. The function must non-blocking.
47019 + * Returns 0 on success.
47020 + * Returns -DWC_E_NOT_SUPPORTED if the request is not supported.
47021 + * Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes.
47022 + * Returns -DWC_E_SHUTDOWN on any other error. */
47023 +typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes);
47024 +/** This is called whenever the device has been disconnected. The function
47025 + * driver should take appropriate action to clean up all pending requests in the
47026 + * PCD Core, remove all endpoints (except ep0), and initialize back to reset
47028 +typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd);
47029 +/** This function is called when device has been connected. */
47030 +typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed);
47031 +/** This function is called when device has been suspended */
47032 +typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd);
47033 +/** This function is called when device has received LPM tokens, i.e.
47034 + * device has been sent to sleep state. */
47035 +typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd);
47036 +/** This function is called when device has been resumed
47037 + * from suspend(L2) or L1 sleep state. */
47038 +typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd);
47039 +/** This function is called whenever hnp params has been changed.
47040 + * User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions
47041 + * to get hnp parameters. */
47042 +typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd);
47043 +/** This function is called whenever USB RESET is detected. */
47044 +typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd);
47046 +typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes);
47050 + * @param ep_handle Void pointer to the usb_ep structure
47051 + * @param ereq_port Pointer to the extended request structure created in the
47054 +typedef int (*xiso_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
47055 + void *req_handle, int32_t status,
47056 + void *ereq_port);
47057 +/** Function Driver Ops Data Structure */
47058 +struct dwc_otg_pcd_function_ops {
47059 + dwc_connect_cb_t connect;
47060 + dwc_disconnect_cb_t disconnect;
47061 + dwc_setup_cb_t setup;
47062 + dwc_completion_cb_t complete;
47063 + dwc_isoc_completion_cb_t isoc_complete;
47064 + dwc_suspend_cb_t suspend;
47065 + dwc_sleep_cb_t sleep;
47066 + dwc_resume_cb_t resume;
47067 + dwc_reset_cb_t reset;
47068 + dwc_hnp_params_changed_cb_t hnp_changed;
47069 + cfi_setup_cb_t cfi_setup;
47070 +#ifdef DWC_UTE_PER_IO
47071 + xiso_completion_cb_t xisoc_complete;
47076 +/** @name Function Driver Functions */
47079 +/** Call this function to get pointer on dwc_otg_pcd_t,
47080 + * this pointer will be used for all PCD API functions.
47082 + * @param core_if The DWC_OTG Core
47084 +extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if);
47086 +/** Frees PCD allocated by dwc_otg_pcd_init
47088 + * @param pcd The PCD
47090 +extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd);
47092 +/** Call this to bind the function driver to the PCD Core.
47094 + * @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
47095 + * @param fops The Function Driver Ops data structure containing pointers to all callbacks.
47097 +extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
47098 + const struct dwc_otg_pcd_function_ops *fops);
47100 +/** Enables an endpoint for use. This function enables an endpoint in
47101 + * the PCD. The endpoint is described by the ep_desc which has the
47102 + * same format as a USB ep descriptor. The ep_handle parameter is used to refer
47103 + * to the endpoint from other API functions and in callbacks. Normally this
47104 + * should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the
47105 + * core for that interface.
47107 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47108 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47109 + * Returns 0 on success.
47111 + * @param pcd The PCD
47112 + * @param ep_desc Endpoint descriptor
47113 + * @param usb_ep Handle on endpoint, that will be used to identify endpoint.
47115 +extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
47116 + const uint8_t * ep_desc, void *usb_ep);
47118 +/** Disable the endpoint referenced by ep_handle.
47120 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47121 + * Returns -DWC_E_SHUTDOWN if any other error occurred.
47122 + * Returns 0 on success. */
47123 +extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle);
47125 +/** Queue a data transfer request on the endpoint referenced by ep_handle.
47126 + * After the transfer is completes, the complete callback will be called with
47127 + * the request status.
47129 + * @param pcd The PCD
47130 + * @param ep_handle The handle of the endpoint
47131 + * @param buf The buffer for the data
47132 + * @param dma_buf The DMA buffer for the data
47133 + * @param buflen The length of the data transfer
47134 + * @param zero Specifies whether to send zero length last packet.
47135 + * @param req_handle Set this handle to any value to use to reference this
47136 + * request in the ep_dequeue function or from the complete callback
47137 + * @param atomic_alloc If driver need to perform atomic allocations
47138 + * for internal data structures.
47140 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47141 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47142 + * Returns 0 on success. */
47143 +extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
47144 + uint8_t * buf, dwc_dma_t dma_buf,
47145 + uint32_t buflen, int zero, void *req_handle,
47146 + int atomic_alloc);
47147 +#ifdef DWC_UTE_PER_IO
47150 + * @param ereq_nonport Pointer to the extended request part of the
47151 + * usb_request structure defined in usb_gadget.h file.
47153 +extern int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
47154 + uint8_t * buf, dwc_dma_t dma_buf,
47155 + uint32_t buflen, int zero,
47156 + void *req_handle, int atomic_alloc,
47157 + void *ereq_nonport);
47161 +/** De-queue the specified data transfer that has not yet completed.
47163 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47164 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47165 + * Returns 0 on success. */
47166 +extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
47167 + void *req_handle);
47169 +/** Halt (STALL) an endpoint or clear it.
47171 + * Returns -DWC_E_INVALID if invalid parameters were passed.
47172 + * Returns -DWC_E_SHUTDOWN if any other error ocurred.
47173 + * Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later
47174 + * Returns 0 on success. */
47175 +extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value);
47177 +/** This function */
47178 +extern int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle);
47180 +/** This function should be called on every hardware interrupt */
47181 +extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd);
47183 +/** This function returns current frame number */
47184 +extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd);
47187 + * Start isochronous transfers on the endpoint referenced by ep_handle.
47188 + * For isochronous transfers duble buffering is used.
47189 + * After processing each of buffers comlete callback will be called with
47190 + * status for each transaction.
47192 + * @param pcd The PCD
47193 + * @param ep_handle The handle of the endpoint
47194 + * @param buf0 The virtual address of first data buffer
47195 + * @param buf1 The virtual address of second data buffer
47196 + * @param dma0 The DMA address of first data buffer
47197 + * @param dma1 The DMA address of second data buffer
47198 + * @param sync_frame Data pattern frame number
47199 + * @param dp_frame Data size for pattern frame
47200 + * @param data_per_frame Data size for regular frame
47201 + * @param start_frame Frame number to start transfers, if -1 then start transfers ASAP.
47202 + * @param buf_proc_intrvl Interval of ISOC Buffer processing
47203 + * @param req_handle Handle of ISOC request
47204 + * @param atomic_alloc Specefies whether to perform atomic allocation for
47205 + * internal data structures.
47207 + * Returns -DWC_E_NO_MEMORY if there is no enough memory.
47208 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function.
47209 + * Returns -DW_E_SHUTDOWN for any other error.
47210 + * Returns 0 on success
47212 +extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
47213 + uint8_t * buf0, uint8_t * buf1,
47214 + dwc_dma_t dma0, dwc_dma_t dma1,
47215 + int sync_frame, int dp_frame,
47216 + int data_per_frame, int start_frame,
47217 + int buf_proc_intrvl, void *req_handle,
47218 + int atomic_alloc);
47220 +/** Stop ISOC transfers on endpoint referenced by ep_handle.
47222 + * @param pcd The PCD
47223 + * @param ep_handle The handle of the endpoint
47224 + * @param req_handle Handle of ISOC request
47226 + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function
47227 + * Returns 0 on success
47229 +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
47230 + void *req_handle);
47232 +/** Get ISOC packet status.
47234 + * @param pcd The PCD
47235 + * @param ep_handle The handle of the endpoint
47236 + * @param iso_req_handle Isochronoush request handle
47237 + * @param packet Number of packet
47238 + * @param status Out parameter for returning status
47239 + * @param actual Out parameter for returning actual length
47240 + * @param offset Out parameter for returning offset
47243 +extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd,
47245 + void *iso_req_handle, int packet,
47246 + int *status, int *actual,
47249 +/** Get ISOC packet count.
47251 + * @param pcd The PCD
47252 + * @param ep_handle The handle of the endpoint
47253 + * @param iso_req_handle
47255 +extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd,
47257 + void *iso_req_handle);
47259 +/** This function starts the SRP Protocol if no session is in progress. If
47260 + * a session is already in progress, but the device is suspended,
47261 + * remote wakeup signaling is started.
47263 +extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd);
47265 +/** This function returns 1 if LPM support is enabled, and 0 otherwise. */
47266 +extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd);
47268 +/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */
47269 +extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd);
47271 +/** Initiate SRP */
47272 +extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd);
47274 +/** Starts remote wakeup signaling. */
47275 +extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set);
47277 +/** Starts micorsecond soft disconnect. */
47278 +extern void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs);
47279 +/** This function returns whether device is dualspeed.*/
47280 +extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd);
47282 +/** This function returns whether device is otg. */
47283 +extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd);
47285 +/** These functions allow to get hnp parameters */
47286 +extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd);
47287 +extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd);
47288 +extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd);
47290 +/** CFI specific Interface functions */
47291 +/** Allocate a cfi buffer */
47292 +extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep,
47293 + dwc_dma_t * addr, size_t buflen,
47296 +/******************************************************************************/
47300 +#endif /* __DWC_PCD_IF_H__ */
47302 +#endif /* DWC_HOST_ONLY */
47303 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
47304 new file mode 100644
47305 index 0000000..27061d3
47307 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
47309 +/* ==========================================================================
47310 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $
47311 + * $Revision: #116 $
47312 + * $Date: 2012/08/10 $
47313 + * $Change: 2047372 $
47315 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
47316 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
47317 + * otherwise expressly agreed to in writing between Synopsys and you.
47319 + * The Software IS NOT an item of Licensed Software or Licensed Product under
47320 + * any End User Software License Agreement or Agreement for Licensed Product
47321 + * with Synopsys or any supplement thereto. You are permitted to use and
47322 + * redistribute this Software in source and binary forms, with or without
47323 + * modification, provided that redistributions of source code must retain this
47324 + * notice. You may not view, use, disclose, copy or distribute this file or
47325 + * any information contained herein except pursuant to this license grant from
47326 + * Synopsys. If you do not agree with this notice, including the disclaimer
47327 + * below, then you are not authorized to use the Software.
47329 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
47330 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47331 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47332 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
47333 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
47334 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
47335 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
47336 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47337 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47338 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
47340 + * ========================================================================== */
47341 +#ifndef DWC_HOST_ONLY
47343 +#include "dwc_otg_pcd.h"
47345 +#ifdef DWC_UTE_CFI
47346 +#include "dwc_otg_cfi.h"
47349 +#ifdef DWC_UTE_PER_IO
47350 +extern void complete_xiso_ep(dwc_otg_pcd_ep_t * ep);
47352 +//#define PRINT_CFI_DMA_DESCS
47357 + * This function updates OTG.
47359 +static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset)
47363 + pcd->b_hnp_enable = 0;
47364 + pcd->a_hnp_support = 0;
47365 + pcd->a_alt_hnp_support = 0;
47368 + if (pcd->fops->hnp_changed) {
47369 + pcd->fops->hnp_changed(pcd);
47374 + * This file contains the implementation of the PCD Interrupt handlers.
47376 + * The PCD handles the device interrupts. Many conditions can cause a
47377 + * device interrupt. When an interrupt occurs, the device interrupt
47378 + * service routine determines the cause of the interrupt and
47379 + * dispatches handling to the appropriate function. These interrupt
47380 + * handling functions are described below.
47381 + * All interrupt registers are processed from LSB to MSB.
47385 + * This function prints the ep0 state for debug purposes.
47387 +static inline void print_ep0_state(dwc_otg_pcd_t * pcd)
47392 + switch (pcd->ep0state) {
47393 + case EP0_DISCONNECT:
47394 + dwc_strcpy(str, "EP0_DISCONNECT");
47397 + dwc_strcpy(str, "EP0_IDLE");
47399 + case EP0_IN_DATA_PHASE:
47400 + dwc_strcpy(str, "EP0_IN_DATA_PHASE");
47402 + case EP0_OUT_DATA_PHASE:
47403 + dwc_strcpy(str, "EP0_OUT_DATA_PHASE");
47405 + case EP0_IN_STATUS_PHASE:
47406 + dwc_strcpy(str, "EP0_IN_STATUS_PHASE");
47408 + case EP0_OUT_STATUS_PHASE:
47409 + dwc_strcpy(str, "EP0_OUT_STATUS_PHASE");
47412 + dwc_strcpy(str, "EP0_STALL");
47415 + dwc_strcpy(str, "EP0_INVALID");
47418 + DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state);
47423 + * This function calculate the size of the payload in the memory
47424 + * for out endpoints and prints size for debug purposes(used in
47425 + * 2.93a DevOutNak feature).
47427 +static inline void print_memory_payload(dwc_otg_pcd_t * pcd, dwc_ep_t * ep)
47430 + deptsiz_data_t deptsiz_init = {.d32 = 0 };
47431 + deptsiz_data_t deptsiz_updt = {.d32 = 0 };
47433 + unsigned payload;
47435 + deptsiz_init.d32 = pcd->core_if->start_doeptsiz_val[ep->num];
47436 + deptsiz_updt.d32 =
47437 + DWC_READ_REG32(&pcd->core_if->dev_if->
47438 + out_ep_regs[ep->num]->doeptsiz);
47439 + /* Payload will be */
47440 + payload = deptsiz_init.b.xfersize - deptsiz_updt.b.xfersize;
47441 + /* Packet count is decremented every time a packet
47442 + * is written to the RxFIFO not in to the external memory
47443 + * So, if payload == 0, then it means no packet was sent to ext memory*/
47444 + pack_num = (!payload) ? 0 : (deptsiz_init.b.pktcnt - deptsiz_updt.b.pktcnt);
47445 + DWC_DEBUGPL(DBG_PCDV,
47446 + "Payload for EP%d-%s\n",
47447 + ep->num, (ep->is_in ? "IN" : "OUT"));
47448 + DWC_DEBUGPL(DBG_PCDV,
47449 + "Number of transfered bytes = 0x%08x\n", payload);
47450 + DWC_DEBUGPL(DBG_PCDV,
47451 + "Number of transfered packets = %d\n", pack_num);
47456 +#ifdef DWC_UTE_CFI
47457 +static inline void print_desc(struct dwc_otg_dma_desc *ddesc,
47458 + const uint8_t * epname, int descnum)
47461 + ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n",
47462 + epname, descnum, ddesc->buf, ddesc->status.b.bytes,
47463 + ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts,
47464 + ddesc->status.b.bs);
47469 + * This function returns pointer to in ep struct with number ep_num
47471 +static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
47474 + int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
47475 + if (ep_num == 0) {
47476 + return &pcd->ep0;
47478 + for (i = 0; i < num_in_eps; ++i) {
47479 + if (pcd->in_ep[i].dwc_ep.num == ep_num)
47480 + return &pcd->in_ep[i];
47487 + * This function returns pointer to out ep struct with number ep_num
47489 +static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
47492 + int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
47493 + if (ep_num == 0) {
47494 + return &pcd->ep0;
47496 + for (i = 0; i < num_out_eps; ++i) {
47497 + if (pcd->out_ep[i].dwc_ep.num == ep_num)
47498 + return &pcd->out_ep[i];
47505 + * This functions gets a pointer to an EP from the wIndex address
47506 + * value of the control request.
47508 +dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex)
47510 + dwc_otg_pcd_ep_t *ep;
47511 + uint32_t ep_num = UE_GET_ADDR(wIndex);
47513 + if (ep_num == 0) {
47515 + } else if (UE_GET_DIR(wIndex) == UE_DIR_IN) { /* in ep */
47516 + ep = &pcd->in_ep[ep_num - 1];
47518 + ep = &pcd->out_ep[ep_num - 1];
47525 + * This function checks the EP request queue, if the queue is not
47526 + * empty the next request is started.
47528 +void start_next_request(dwc_otg_pcd_ep_t * ep)
47530 + dwc_otg_pcd_request_t *req = 0;
47531 + uint32_t max_transfer =
47532 + GET_CORE_IF(ep->pcd)->core_params->max_transfer_size;
47534 +#ifdef DWC_UTE_CFI
47535 + struct dwc_otg_pcd *pcd;
47539 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
47540 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
47542 +#ifdef DWC_UTE_CFI
47543 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
47544 + ep->dwc_ep.cfi_req_len = req->length;
47545 + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req);
47548 + /* Setup and start the Transfer */
47549 + if (req->dw_align_buf) {
47550 + ep->dwc_ep.dma_addr = req->dw_align_buf_dma;
47551 + ep->dwc_ep.start_xfer_buff = req->dw_align_buf;
47552 + ep->dwc_ep.xfer_buff = req->dw_align_buf;
47554 + ep->dwc_ep.dma_addr = req->dma;
47555 + ep->dwc_ep.start_xfer_buff = req->buf;
47556 + ep->dwc_ep.xfer_buff = req->buf;
47558 + ep->dwc_ep.sent_zlp = 0;
47559 + ep->dwc_ep.total_len = req->length;
47560 + ep->dwc_ep.xfer_len = 0;
47561 + ep->dwc_ep.xfer_count = 0;
47563 + ep->dwc_ep.maxxfer = max_transfer;
47564 + if (GET_CORE_IF(ep->pcd)->dma_desc_enable) {
47565 + uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE
47566 + - (DDMA_MAX_TRANSFER_SIZE % 4);
47567 + if (ep->dwc_ep.is_in) {
47568 + if (ep->dwc_ep.maxxfer >
47569 + DDMA_MAX_TRANSFER_SIZE) {
47570 + ep->dwc_ep.maxxfer =
47571 + DDMA_MAX_TRANSFER_SIZE;
47574 + if (ep->dwc_ep.maxxfer > out_max_xfer) {
47575 + ep->dwc_ep.maxxfer =
47580 + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
47581 + ep->dwc_ep.maxxfer -=
47582 + (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket);
47584 + if (req->sent_zlp) {
47585 + if ((ep->dwc_ep.total_len %
47586 + ep->dwc_ep.maxpacket == 0)
47587 + && (ep->dwc_ep.total_len != 0)) {
47588 + ep->dwc_ep.sent_zlp = 1;
47592 +#ifdef DWC_UTE_CFI
47595 + dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep);
47596 + } else if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
47597 + DWC_PRINTF("There are no more ISOC requests \n");
47598 + ep->dwc_ep.frame_num = 0xFFFFFFFF;
47603 + * This function handles the SOF Interrupts. At this time the SOF
47604 + * Interrupt is disabled.
47606 +int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd)
47608 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47610 + gintsts_data_t gintsts;
47612 + DWC_DEBUGPL(DBG_PCD, "SOF\n");
47614 + /* Clear interrupt */
47616 + gintsts.b.sofintr = 1;
47617 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
47623 + * This function handles the Rx Status Queue Level Interrupt, which
47624 + * indicates that there is a least one packet in the Rx FIFO. The
47625 + * packets are moved from the FIFO to memory, where they will be
47626 + * processed when the Endpoint Interrupt Register indicates Transfer
47627 + * Complete or SETUP Phase Done.
47629 + * Repeat the following until the Rx Status Queue is empty:
47630 + * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
47632 + * -# If Receive FIFO is empty then skip to step Clear the interrupt
47634 + * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
47635 + * SETUP data to the buffer
47636 + * -# If OUT Data Packet call dwc_otg_read_packet to copy the data
47637 + * to the destination buffer
47639 +int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd)
47641 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47642 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
47643 + gintmsk_data_t gintmask = {.d32 = 0 };
47644 + device_grxsts_data_t status;
47645 + dwc_otg_pcd_ep_t *ep;
47646 + gintsts_data_t gintsts;
47648 + static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" };
47651 + //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
47652 + /* Disable the Rx Status Queue Level interrupt */
47653 + gintmask.b.rxstsqlvl = 1;
47654 + DWC_MODIFY_REG32(&global_regs->gintmsk, gintmask.d32, 0);
47656 + /* Get the Status from the top of the FIFO */
47657 + status.d32 = DWC_READ_REG32(&global_regs->grxstsp);
47659 + DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
47660 + "pktsts:%x Frame:%d(0x%0x)\n",
47661 + status.b.epnum, status.b.bcnt,
47662 + dpid_str[status.b.dpid],
47663 + status.b.pktsts, status.b.fn, status.b.fn);
47664 + /* Get pointer to EP structure */
47665 + ep = get_out_ep(pcd, status.b.epnum);
47667 + switch (status.b.pktsts) {
47668 + case DWC_DSTS_GOUT_NAK:
47669 + DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
47671 + case DWC_STS_DATA_UPDT:
47672 + DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
47673 + if (status.b.bcnt && ep->dwc_ep.xfer_buff) {
47674 + /** @todo NGS Check for buffer overflow? */
47675 + dwc_otg_read_packet(core_if,
47676 + ep->dwc_ep.xfer_buff,
47678 + ep->dwc_ep.xfer_count += status.b.bcnt;
47679 + ep->dwc_ep.xfer_buff += status.b.bcnt;
47682 + case DWC_STS_XFER_COMP:
47683 + DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
47685 + case DWC_DSTS_SETUP_COMP:
47687 + DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
47690 + case DWC_DSTS_SETUP_UPDT:
47691 + dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32);
47693 + DWC_DEBUGPL(DBG_PCD,
47694 + "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
47695 + pcd->setup_pkt->req.bmRequestType,
47696 + pcd->setup_pkt->req.bRequest,
47697 + UGETW(pcd->setup_pkt->req.wValue),
47698 + UGETW(pcd->setup_pkt->req.wIndex),
47699 + UGETW(pcd->setup_pkt->req.wLength));
47701 + ep->dwc_ep.xfer_count += status.b.bcnt;
47704 + DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
47705 + status.b.pktsts);
47709 + /* Enable the Rx Status Queue Level interrupt */
47710 + DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmask.d32);
47711 + /* Clear interrupt */
47713 + gintsts.b.rxstsqlvl = 1;
47714 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
47716 + //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
47721 + * This function examines the Device IN Token Learning Queue to
47722 + * determine the EP number of the last IN token received. This
47723 + * implementation is for the Mass Storage device where there are only
47724 + * 2 IN EPs (Control-IN and BULK-IN).
47726 + * The EP numbers for the first six IN Tokens are in DTKNQR1 and there
47727 + * are 8 EP Numbers in each of the other possible DTKNQ Registers.
47729 + * @param core_if Programming view of DWC_otg controller.
47732 +static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if)
47734 + dwc_otg_device_global_regs_t *dev_global_regs =
47735 + core_if->dev_if->dev_global_regs;
47736 + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
47737 + /* Number of Token Queue Registers */
47738 + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
47739 + dtknq1_data_t dtknqr1;
47740 + uint32_t in_tkn_epnums[4];
47743 + volatile uint32_t *addr = &dev_global_regs->dtknqr1;
47746 + //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
47748 + /* Read the DTKNQ Registers */
47749 + for (i = 0; i < DTKNQ_REG_CNT; i++) {
47750 + in_tkn_epnums[i] = DWC_READ_REG32(addr);
47751 + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
47752 + in_tkn_epnums[i]);
47753 + if (addr == &dev_global_regs->dvbusdis) {
47754 + addr = &dev_global_regs->dtknqr3_dthrctl;
47761 + /* Copy the DTKNQR1 data to the bit field. */
47762 + dtknqr1.d32 = in_tkn_epnums[0];
47763 + /* Get the EP numbers */
47764 + in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
47765 + ndx = dtknqr1.b.intknwptr - 1;
47767 + //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
47769 + /** @todo Find a simpler way to calculate the max
47770 + * queue position.*/
47771 + int cnt = TOKEN_Q_DEPTH;
47772 + if (TOKEN_Q_DEPTH <= 6) {
47773 + cnt = TOKEN_Q_DEPTH - 1;
47774 + } else if (TOKEN_Q_DEPTH <= 14) {
47775 + cnt = TOKEN_Q_DEPTH - 7;
47776 + } else if (TOKEN_Q_DEPTH <= 22) {
47777 + cnt = TOKEN_Q_DEPTH - 15;
47779 + cnt = TOKEN_Q_DEPTH - 23;
47781 + epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF;
47784 + epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
47785 + } else if (ndx <= 13) {
47787 + epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
47788 + } else if (ndx <= 21) {
47790 + epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
47791 + } else if (ndx <= 29) {
47793 + epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
47796 + //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
47801 + * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
47802 + * The active request is checked for the next packet to be loaded into
47803 + * the non-periodic Tx FIFO.
47805 +int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd)
47807 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47808 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
47809 + dwc_otg_dev_in_ep_regs_t *ep_regs;
47810 + gnptxsts_data_t txstatus = {.d32 = 0 };
47811 + gintsts_data_t gintsts;
47814 + dwc_otg_pcd_ep_t *ep = 0;
47815 + uint32_t len = 0;
47818 + /* Get the epnum from the IN Token Learning Queue. */
47819 + epnum = get_ep_of_last_in_token(core_if);
47820 + ep = get_in_ep(pcd, epnum);
47822 + DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum);
47824 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
47826 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47827 + if (len > ep->dwc_ep.maxpacket) {
47828 + len = ep->dwc_ep.maxpacket;
47830 + dwords = (len + 3) / 4;
47832 + /* While there is space in the queue and space in the FIFO and
47833 + * More data to tranfer, Write packets to the Tx FIFO */
47834 + txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
47835 + DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32);
47837 + while (txstatus.b.nptxqspcavail > 0 &&
47838 + txstatus.b.nptxfspcavail > dwords &&
47839 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) {
47840 + /* Write the FIFO */
47841 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
47842 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47844 + if (len > ep->dwc_ep.maxpacket) {
47845 + len = ep->dwc_ep.maxpacket;
47848 + dwords = (len + 3) / 4;
47849 + txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
47850 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32);
47853 + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
47854 + DWC_READ_REG32(&global_regs->gnptxsts));
47856 + /* Clear interrupt */
47858 + gintsts.b.nptxfempty = 1;
47859 + DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
47865 + * This function is called when dedicated Tx FIFO Empty interrupt occurs.
47866 + * The active request is checked for the next packet to be loaded into
47867 + * apropriate Tx FIFO.
47869 +static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum)
47871 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
47872 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
47873 + dwc_otg_dev_in_ep_regs_t *ep_regs;
47874 + dtxfsts_data_t txstatus = {.d32 = 0 };
47875 + dwc_otg_pcd_ep_t *ep = 0;
47876 + uint32_t len = 0;
47879 + ep = get_in_ep(pcd, epnum);
47881 + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
47883 + ep_regs = core_if->dev_if->in_ep_regs[epnum];
47885 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47887 + if (len > ep->dwc_ep.maxpacket) {
47888 + len = ep->dwc_ep.maxpacket;
47891 + dwords = (len + 3) / 4;
47893 + /* While there is space in the queue and space in the FIFO and
47894 + * More data to tranfer, Write packets to the Tx FIFO */
47895 + txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
47896 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
47898 + while (txstatus.b.txfspcavail > dwords &&
47899 + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
47900 + ep->dwc_ep.xfer_len != 0) {
47901 + /* Write the FIFO */
47902 + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
47904 + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
47905 + if (len > ep->dwc_ep.maxpacket) {
47906 + len = ep->dwc_ep.maxpacket;
47909 + dwords = (len + 3) / 4;
47911 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
47912 + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
47916 + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
47917 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
47923 + * This function is called when the Device is disconnected. It stops
47924 + * any active requests and informs the Gadget driver of the
47927 +void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd)
47929 + int i, num_in_eps, num_out_eps;
47930 + dwc_otg_pcd_ep_t *ep;
47932 + gintmsk_data_t intr_mask = {.d32 = 0 };
47934 + DWC_SPINLOCK(pcd->lock);
47936 + num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
47937 + num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
47939 + DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__);
47940 + /* don't disconnect drivers more than once */
47941 + if (pcd->ep0state == EP0_DISCONNECT) {
47942 + DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__);
47943 + DWC_SPINUNLOCK(pcd->lock);
47946 + pcd->ep0state = EP0_DISCONNECT;
47948 + /* Reset the OTG state. */
47949 + dwc_otg_pcd_update_otg(pcd, 1);
47951 + /* Disable the NP Tx Fifo Empty Interrupt. */
47952 + intr_mask.b.nptxfempty = 1;
47953 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
47954 + intr_mask.d32, 0);
47956 + /* Flush the FIFOs */
47957 + /**@todo NGS Flush Periodic FIFOs */
47958 + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10);
47959 + dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd));
47961 + /* prevent new request submissions, kill any outstanding requests */
47963 + dwc_otg_request_nuke(ep);
47964 + /* prevent new request submissions, kill any outstanding requests */
47965 + for (i = 0; i < num_in_eps; i++) {
47966 + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i];
47967 + dwc_otg_request_nuke(ep);
47969 + /* prevent new request submissions, kill any outstanding requests */
47970 + for (i = 0; i < num_out_eps; i++) {
47971 + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i];
47972 + dwc_otg_request_nuke(ep);
47975 + /* report disconnect; the driver is already quiesced */
47976 + if (pcd->fops->disconnect) {
47977 + DWC_SPINUNLOCK(pcd->lock);
47978 + pcd->fops->disconnect(pcd);
47979 + DWC_SPINLOCK(pcd->lock);
47981 + DWC_SPINUNLOCK(pcd->lock);
47985 + * This interrupt indicates that ...
47987 +int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd)
47989 + gintmsk_data_t intr_mask = {.d32 = 0 };
47990 + gintsts_data_t gintsts;
47992 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr");
47993 + intr_mask.b.i2cintr = 1;
47994 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
47995 + intr_mask.d32, 0);
47997 + /* Clear interrupt */
47999 + gintsts.b.i2cintr = 1;
48000 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48006 + * This interrupt indicates that ...
48008 +int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd)
48010 + gintsts_data_t gintsts;
48011 +#if defined(VERBOSE)
48012 + DWC_PRINTF("Early Suspend Detected\n");
48015 + /* Clear interrupt */
48017 + gintsts.b.erlysuspend = 1;
48018 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48024 + * This function configures EPO to receive SETUP packets.
48026 + * @todo NGS: Update the comments from the HW FS.
48028 + * -# Program the following fields in the endpoint specific registers
48029 + * for Control OUT EP 0, in order to receive a setup packet
48030 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
48032 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
48033 + * to back setup packets)
48034 + * - In DMA mode, DOEPDMA0 Register with a memory address to
48035 + * store any setup packets received
48037 + * @param core_if Programming view of DWC_otg controller.
48038 + * @param pcd Programming view of the PCD.
48040 +static inline void ep0_out_start(dwc_otg_core_if_t * core_if,
48041 + dwc_otg_pcd_t * pcd)
48043 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
48044 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
48045 + dwc_otg_dev_dma_desc_t *dma_desc;
48046 + depctl_data_t doepctl = {.d32 = 0 };
48049 + DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__,
48050 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
48052 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
48053 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
48054 + if (doepctl.b.epena) {
48059 + doeptsize0.b.supcnt = 3;
48060 + doeptsize0.b.pktcnt = 1;
48061 + doeptsize0.b.xfersize = 8 * 3;
48063 + if (core_if->dma_enable) {
48064 + if (!core_if->dma_desc_enable) {
48065 + /** put here as for Hermes mode deptisz register should not be written */
48066 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
48069 + /** @todo dma needs to handle multiple setup packets (up to 3) */
48070 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
48071 + pcd->setup_pkt_dma_handle);
48073 + dev_if->setup_desc_index =
48074 + (dev_if->setup_desc_index + 1) & 1;
48076 + dev_if->setup_desc_addr[dev_if->setup_desc_index];
48078 + /** DMA Descriptor Setup */
48079 + dma_desc->status.b.bs = BS_HOST_BUSY;
48080 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
48081 + dma_desc->status.b.sr = 0;
48082 + dma_desc->status.b.mtrf = 0;
48084 + dma_desc->status.b.l = 1;
48085 + dma_desc->status.b.ioc = 1;
48086 + dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket;
48087 + dma_desc->buf = pcd->setup_pkt_dma_handle;
48088 + dma_desc->status.b.sts = 0;
48089 + dma_desc->status.b.bs = BS_HOST_READY;
48091 + /** DOEPDMA0 Register write */
48092 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
48093 + dev_if->dma_setup_desc_addr
48094 + [dev_if->setup_desc_index]);
48098 + /** put here as for Hermes mode deptisz register should not be written */
48099 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
48103 + /** DOEPCTL0 Register write cnak will be set after setup interrupt */
48105 + doepctl.b.epena = 1;
48106 + if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
48107 + doepctl.b.cnak = 1;
48108 + DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
48110 + DWC_MODIFY_REG32(&dev_if->out_ep_regs[0]->doepctl, 0, doepctl.d32);
48114 + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
48115 + DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
48116 + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
48117 + DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
48122 + * This interrupt occurs when a USB Reset is detected. When the USB
48123 + * Reset Interrupt occurs the device state is set to DEFAULT and the
48124 + * EP0 state is set to IDLE.
48125 + * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
48126 + * -# Unmask the following interrupt bits
48127 + * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
48128 + * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
48129 + * - DOEPMSK.SETUP = 1
48130 + * - DOEPMSK.XferCompl = 1
48131 + * - DIEPMSK.XferCompl = 1
48132 + * - DIEPMSK.TimeOut = 1
48133 + * -# Program the following fields in the endpoint specific registers
48134 + * for Control OUT EP 0, in order to receive a setup packet
48135 + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
48137 + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
48138 + * to back setup packets)
48139 + * - In DMA mode, DOEPDMA0 Register with a memory address to
48140 + * store any setup packets received
48141 + * At this point, all the required initialization, except for enabling
48142 + * the control 0 OUT endpoint is done, for receiving SETUP packets.
48144 +int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd)
48146 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48147 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
48148 + depctl_data_t doepctl = {.d32 = 0 };
48149 + depctl_data_t diepctl = {.d32 = 0 };
48150 + daint_data_t daintmsk = {.d32 = 0 };
48151 + doepmsk_data_t doepmsk = {.d32 = 0 };
48152 + diepmsk_data_t diepmsk = {.d32 = 0 };
48153 + dcfg_data_t dcfg = {.d32 = 0 };
48154 + grstctl_t resetctl = {.d32 = 0 };
48155 + dctl_data_t dctl = {.d32 = 0 };
48157 + gintsts_data_t gintsts;
48158 + pcgcctl_data_t power = {.d32 = 0 };
48160 + power.d32 = DWC_READ_REG32(core_if->pcgcctl);
48161 + if (power.b.stoppclk) {
48163 + power.b.stoppclk = 1;
48164 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
48166 + power.b.pwrclmp = 1;
48167 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
48169 + power.b.rstpdwnmodule = 1;
48170 + DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
48173 + core_if->lx_state = DWC_OTG_L0;
48175 + DWC_PRINTF("USB RESET\n");
48176 +#ifdef DWC_EN_ISOC
48177 + for (i = 1; i < 16; ++i) {
48178 + dwc_otg_pcd_ep_t *ep;
48179 + dwc_ep_t *dwc_ep;
48180 + ep = get_in_ep(pcd, i);
48182 + dwc_ep = &ep->dwc_ep;
48183 + dwc_ep->next_frame = 0xffffffff;
48186 +#endif /* DWC_EN_ISOC */
48188 + /* reset the HNP settings */
48189 + dwc_otg_pcd_update_otg(pcd, 1);
48191 + /* Clear the Remote Wakeup Signalling */
48192 + dctl.b.rmtwkupsig = 1;
48193 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
48195 + /* Set NAK for all OUT EPs */
48196 + doepctl.b.snak = 1;
48197 + for (i = 0; i <= dev_if->num_out_eps; i++) {
48198 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
48201 + /* Flush the NP Tx FIFO */
48202 + dwc_otg_flush_tx_fifo(core_if, 0x10);
48203 + /* Flush the Learning Queue */
48204 + resetctl.b.intknqflsh = 1;
48205 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
48207 + if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
48208 + core_if->start_predict = 0;
48209 + for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
48210 + core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
48212 + core_if->nextep_seq[0] = 0;
48213 + core_if->first_in_nextep_seq = 0;
48214 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
48215 + diepctl.b.nextep = 0;
48216 + DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
48218 + /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
48219 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
48220 + dcfg.b.epmscnt = 2;
48221 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
48223 + DWC_DEBUGPL(DBG_PCDV,
48224 + "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
48225 + __func__, core_if->first_in_nextep_seq);
48226 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
48227 + DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
48231 + if (core_if->multiproc_int_enable) {
48232 + daintmsk.b.inep0 = 1;
48233 + daintmsk.b.outep0 = 1;
48234 + DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk,
48237 + doepmsk.b.setup = 1;
48238 + doepmsk.b.xfercompl = 1;
48239 + doepmsk.b.ahberr = 1;
48240 + doepmsk.b.epdisabled = 1;
48242 + if ((core_if->dma_desc_enable) ||
48243 + (core_if->dma_enable
48244 + && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
48245 + doepmsk.b.stsphsercvd = 1;
48247 + if (core_if->dma_desc_enable)
48248 + doepmsk.b.bna = 1;
48250 + doepmsk.b.babble = 1;
48251 + doepmsk.b.nyet = 1;
48253 + if (core_if->dma_enable) {
48254 + doepmsk.b.nak = 1;
48257 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepeachintmsk[0],
48260 + diepmsk.b.xfercompl = 1;
48261 + diepmsk.b.timeout = 1;
48262 + diepmsk.b.epdisabled = 1;
48263 + diepmsk.b.ahberr = 1;
48264 + diepmsk.b.intknepmis = 1;
48265 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
48266 + diepmsk.b.intknepmis = 0;
48268 +/* if (core_if->dma_desc_enable) {
48269 + diepmsk.b.bna = 1;
48273 + if (core_if->dma_enable) {
48274 + diepmsk.b.nak = 1;
48277 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepeachintmsk[0],
48280 + daintmsk.b.inep0 = 1;
48281 + daintmsk.b.outep0 = 1;
48282 + DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk,
48285 + doepmsk.b.setup = 1;
48286 + doepmsk.b.xfercompl = 1;
48287 + doepmsk.b.ahberr = 1;
48288 + doepmsk.b.epdisabled = 1;
48290 + if ((core_if->dma_desc_enable) ||
48291 + (core_if->dma_enable
48292 + && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
48293 + doepmsk.b.stsphsercvd = 1;
48295 + if (core_if->dma_desc_enable)
48296 + doepmsk.b.bna = 1;
48297 + DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32);
48299 + diepmsk.b.xfercompl = 1;
48300 + diepmsk.b.timeout = 1;
48301 + diepmsk.b.epdisabled = 1;
48302 + diepmsk.b.ahberr = 1;
48303 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
48304 + diepmsk.b.intknepmis = 0;
48306 + if (core_if->dma_desc_enable) {
48307 + diepmsk.b.bna = 1;
48311 + DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32);
48314 + /* Reset Device Address */
48315 + dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
48316 + dcfg.b.devaddr = 0;
48317 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
48319 + /* setup EP0 to receive SETUP packets */
48320 + if (core_if->snpsid <= OTG_CORE_REV_2_94a)
48321 + ep0_out_start(core_if, pcd);
48323 + /* Clear interrupt */
48325 + gintsts.b.usbreset = 1;
48326 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48332 + * Get the device speed from the device status register and convert it
48333 + * to USB speed constant.
48335 + * @param core_if Programming view of DWC_otg controller.
48337 +static int get_device_speed(dwc_otg_core_if_t * core_if)
48339 + dsts_data_t dsts;
48341 + dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
48343 + switch (dsts.b.enumspd) {
48344 + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
48345 + speed = USB_SPEED_HIGH;
48347 + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
48348 + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
48349 + speed = USB_SPEED_FULL;
48352 + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
48353 + speed = USB_SPEED_LOW;
48361 + * Read the device status register and set the device speed in the
48362 + * data structure.
48363 + * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
48365 +int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd)
48367 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48368 + gintsts_data_t gintsts;
48369 + gusbcfg_data_t gusbcfg;
48370 + dwc_otg_core_global_regs_t *global_regs =
48371 + GET_CORE_IF(pcd)->core_global_regs;
48372 + uint8_t utmi16b, utmi8b;
48374 + DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
48376 + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
48377 + utmi16b = 6; //vahrama old value was 6;
48383 + dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep);
48384 + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a) {
48385 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48389 + print_ep0_state(pcd);
48392 + if (pcd->ep0state == EP0_DISCONNECT) {
48393 + pcd->ep0state = EP0_IDLE;
48394 + } else if (pcd->ep0state == EP0_STALL) {
48395 + pcd->ep0state = EP0_IDLE;
48398 + pcd->ep0state = EP0_IDLE;
48400 + ep0->stopped = 0;
48402 + speed = get_device_speed(GET_CORE_IF(pcd));
48403 + pcd->fops->connect(pcd, speed);
48405 + /* Set USB turnaround time based on device speed and PHY interface. */
48406 + gusbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
48407 + if (speed == USB_SPEED_HIGH) {
48408 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48409 + DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
48410 + /* ULPI interface */
48411 + gusbcfg.b.usbtrdtim = 9;
48413 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48414 + DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
48415 + /* UTMI+ interface */
48416 + if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) {
48417 + gusbcfg.b.usbtrdtim = utmi8b;
48418 + } else if (GET_CORE_IF(pcd)->hwcfg4.
48419 + b.utmi_phy_data_width == 1) {
48420 + gusbcfg.b.usbtrdtim = utmi16b;
48421 + } else if (GET_CORE_IF(pcd)->
48422 + core_params->phy_utmi_width == 8) {
48423 + gusbcfg.b.usbtrdtim = utmi8b;
48425 + gusbcfg.b.usbtrdtim = utmi16b;
48428 + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
48429 + DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
48430 + /* UTMI+ OR ULPI interface */
48431 + if (gusbcfg.b.ulpi_utmi_sel == 1) {
48432 + /* ULPI interface */
48433 + gusbcfg.b.usbtrdtim = 9;
48435 + /* UTMI+ interface */
48436 + if (GET_CORE_IF(pcd)->
48437 + core_params->phy_utmi_width == 16) {
48438 + gusbcfg.b.usbtrdtim = utmi16b;
48440 + gusbcfg.b.usbtrdtim = utmi8b;
48445 + /* Full or low speed */
48446 + gusbcfg.b.usbtrdtim = 9;
48448 + DWC_WRITE_REG32(&global_regs->gusbcfg, gusbcfg.d32);
48450 + /* Clear interrupt */
48452 + gintsts.b.enumdone = 1;
48453 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48459 + * This interrupt indicates that the ISO OUT Packet was dropped due to
48460 + * Rx FIFO full or Rx Status Queue Full. If this interrupt occurs
48461 + * read all the data from the Rx FIFO.
48463 +int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd)
48465 + gintmsk_data_t intr_mask = {.d32 = 0 };
48466 + gintsts_data_t gintsts;
48468 + DWC_WARN("INTERRUPT Handler not implemented for %s\n",
48469 + "ISOC Out Dropped");
48471 + intr_mask.b.isooutdrop = 1;
48472 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48473 + intr_mask.d32, 0);
48475 + /* Clear interrupt */
48477 + gintsts.b.isooutdrop = 1;
48478 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48485 + * This interrupt indicates the end of the portion of the micro-frame
48486 + * for periodic transactions. If there is a periodic transaction for
48487 + * the next frame, load the packets into the EP periodic Tx FIFO.
48489 +int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd)
48491 + gintmsk_data_t intr_mask = {.d32 = 0 };
48492 + gintsts_data_t gintsts;
48493 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP");
48495 + intr_mask.b.eopframe = 1;
48496 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
48497 + intr_mask.d32, 0);
48499 + /* Clear interrupt */
48501 + gintsts.b.eopframe = 1;
48502 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
48509 + * This interrupt indicates that EP of the packet on the top of the
48510 + * non-periodic Tx FIFO does not match EP of the IN Token received.
48512 + * The "Device IN Token Queue" Registers are read to determine the
48513 + * order the IN Tokens have been received. The non-periodic Tx FIFO
48514 + * is flushed, so it can be reloaded in the order seen in the IN Token
48517 +int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_pcd_t * pcd)
48519 + gintsts_data_t gintsts;
48520 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48521 + dctl_data_t dctl;
48522 + gintmsk_data_t intr_mask = {.d32 = 0 };
48524 + if (!core_if->en_multiple_tx_fifo && core_if->dma_enable) {
48525 + core_if->start_predict = 1;
48527 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
48529 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
48530 + if (!gintsts.b.ginnakeff) {
48531 + /* Disable EP Mismatch interrupt */
48532 + intr_mask.d32 = 0;
48533 + intr_mask.b.epmismatch = 1;
48534 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
48535 + /* Enable the Global IN NAK Effective Interrupt */
48536 + intr_mask.d32 = 0;
48537 + intr_mask.b.ginnakeff = 1;
48538 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
48539 + /* Set the global non-periodic IN NAK handshake */
48540 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
48541 + dctl.b.sgnpinnak = 1;
48542 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
48544 + DWC_PRINTF("gintsts.b.ginnakeff = 1! dctl.b.sgnpinnak not set\n");
48546 + /* Disabling of all EP's will be done in dwc_otg_pcd_handle_in_nak_effective()
48547 + * handler after Global IN NAK Effective interrupt will be asserted */
48549 + /* Clear interrupt */
48551 + gintsts.b.epmismatch = 1;
48552 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48558 + * This interrupt is valid only in DMA mode. This interrupt indicates that the
48559 + * core has stopped fetching data for IN endpoints due to the unavailability of
48560 + * TxFIFO space or Request Queue space. This interrupt is used by the
48561 + * application for an endpoint mismatch algorithm.
48563 + * @param pcd The PCD
48565 +int32_t dwc_otg_pcd_handle_ep_fetsusp_intr(dwc_otg_pcd_t * pcd)
48567 + gintsts_data_t gintsts;
48568 + gintmsk_data_t gintmsk_data;
48569 + dctl_data_t dctl;
48570 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48571 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
48573 + /* Clear the global non-periodic IN NAK handshake */
48575 + dctl.b.cgnpinnak = 1;
48576 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
48578 + /* Mask GINTSTS.FETSUSP interrupt */
48579 + gintmsk_data.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
48580 + gintmsk_data.b.fetsusp = 0;
48581 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_data.d32);
48583 + /* Clear interrupt */
48585 + gintsts.b.fetsusp = 1;
48586 + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
48591 + * This funcion stalls EP0.
48593 +static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val)
48595 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48596 + usb_device_request_t *ctrl = &pcd->setup_pkt->req;
48597 + DWC_WARN("req %02x.%02x protocol STALL; err %d\n",
48598 + ctrl->bmRequestType, ctrl->bRequest, err_val);
48600 + ep0->dwc_ep.is_in = 1;
48601 + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep);
48602 + pcd->ep0.stopped = 1;
48603 + pcd->ep0state = EP0_IDLE;
48604 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48608 + * This functions delegates the setup command to the gadget driver.
48610 +static inline void do_gadget_setup(dwc_otg_pcd_t * pcd,
48611 + usb_device_request_t * ctrl)
48614 + DWC_SPINUNLOCK(pcd->lock);
48615 + ret = pcd->fops->setup(pcd, (uint8_t *) ctrl);
48616 + DWC_SPINLOCK(pcd->lock);
48618 + ep0_do_stall(pcd, ret);
48621 + /** @todo This is a g_file_storage gadget driver specific
48622 + * workaround: a DELAYED_STATUS result from the fsg_setup
48623 + * routine will result in the gadget queueing a EP0 IN status
48624 + * phase for a two-stage control transfer. Exactly the same as
48625 + * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
48626 + * specific request. Need a generic way to know when the gadget
48627 + * driver will queue the status phase. Can we assume when we
48628 + * call the gadget driver setup() function that it will always
48629 + * queue and require the following flag? Need to look into
48633 + if (ret == 256 + 999) {
48634 + pcd->request_config = 1;
48638 +#ifdef DWC_UTE_CFI
48640 + * This functions delegates the CFI setup commands to the gadget driver.
48641 + * This function will return a negative value to indicate a failure.
48643 +static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd,
48644 + struct cfi_usb_ctrlrequest *ctrl_req)
48648 + if (pcd->fops && pcd->fops->cfi_setup) {
48649 + DWC_SPINUNLOCK(pcd->lock);
48650 + ret = pcd->fops->cfi_setup(pcd, ctrl_req);
48651 + DWC_SPINLOCK(pcd->lock);
48653 + ep0_do_stall(pcd, ret);
48663 + * This function starts the Zero-Length Packet for the IN status phase
48664 + * of a 2 stage control transfer.
48666 +static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd)
48668 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48669 + if (pcd->ep0state == EP0_STALL) {
48673 + pcd->ep0state = EP0_IN_STATUS_PHASE;
48675 + /* Prepare for more SETUP Packets */
48676 + DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
48677 + if ((GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a)
48678 + && (pcd->core_if->dma_desc_enable)
48679 + && (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len)) {
48680 + DWC_DEBUGPL(DBG_PCDV,
48681 + "Data terminated wait next packet in out_desc_addr\n");
48682 + pcd->backup_buf = phys_to_virt(ep0->dwc_ep.dma_addr);
48683 + pcd->data_terminated = 1;
48685 + ep0->dwc_ep.xfer_len = 0;
48686 + ep0->dwc_ep.xfer_count = 0;
48687 + ep0->dwc_ep.is_in = 1;
48688 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
48689 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48691 + /* Prepare for more SETUP Packets */
48692 + //ep0_out_start(GET_CORE_IF(pcd), pcd);
48696 + * This function starts the Zero-Length Packet for the OUT status phase
48697 + * of a 2 stage control transfer.
48699 +static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd)
48701 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48702 + if (pcd->ep0state == EP0_STALL) {
48703 + DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
48706 + pcd->ep0state = EP0_OUT_STATUS_PHASE;
48708 + DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
48709 + ep0->dwc_ep.xfer_len = 0;
48710 + ep0->dwc_ep.xfer_count = 0;
48711 + ep0->dwc_ep.is_in = 0;
48712 + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
48713 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48715 + /* Prepare for more SETUP Packets */
48716 + if (GET_CORE_IF(pcd)->dma_enable == 0) {
48717 + ep0_out_start(GET_CORE_IF(pcd), pcd);
48722 + * Clear the EP halt (STALL) and if pending requests start the
48725 +static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
48727 + if (ep->dwc_ep.stall_clear_flag == 0)
48728 + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
48730 + /* Reactive the EP */
48731 + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
48732 + if (ep->stopped) {
48734 + /* If there is a request in the EP queue start it */
48736 + /** @todo FIXME: this causes an EP mismatch in DMA mode.
48737 + * epmismatch not yet implemented. */
48740 + * Above fixme is solved by implmenting a tasklet to call the
48741 + * start_next_request(), outside of interrupt context at some
48742 + * time after the current time, after a clear-halt setup packet.
48743 + * Still need to implement ep mismatch in the future if a gadget
48744 + * ever uses more than one endpoint at once
48746 + ep->queue_sof = 1;
48747 + DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet);
48749 + /* Start Control Status Phase */
48750 + do_setup_in_status_phase(pcd);
48754 + * This function is called when the SET_FEATURE TEST_MODE Setup packet
48755 + * is sent from the host. The Device Control register is written with
48756 + * the Test Mode bits set to the specified Test Mode. This is done as
48757 + * a tasklet so that the "Status" phase of the control transfer
48758 + * completes before transmitting the TEST packets.
48760 + * @todo This has not been tested since the tasklet struct was put
48761 + * into the PCD struct!
48764 +void do_test_mode(void *data)
48766 + dctl_data_t dctl;
48767 + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
48768 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48769 + int test_mode = pcd->test_mode;
48771 +// DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
48773 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
48774 + switch (test_mode) {
48775 + case 1: // TEST_J
48776 + dctl.b.tstctl = 1;
48779 + case 2: // TEST_K
48780 + dctl.b.tstctl = 2;
48783 + case 3: // TEST_SE0_NAK
48784 + dctl.b.tstctl = 3;
48787 + case 4: // TEST_PACKET
48788 + dctl.b.tstctl = 4;
48791 + case 5: // TEST_FORCE_ENABLE
48792 + dctl.b.tstctl = 5;
48795 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
48799 + * This function process the GET_STATUS Setup Commands.
48801 +static inline void do_get_status(dwc_otg_pcd_t * pcd)
48803 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48804 + dwc_otg_pcd_ep_t *ep;
48805 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
48806 + uint16_t *status = pcd->status_buf;
48807 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48810 + DWC_DEBUGPL(DBG_PCD,
48811 + "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
48812 + ctrl.bmRequestType, ctrl.bRequest,
48813 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48814 + UGETW(ctrl.wLength));
48817 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48819 + if(UGETW(ctrl.wIndex) == 0xF000) { /* OTG Status selector */
48820 + DWC_PRINTF("wIndex - %d\n", UGETW(ctrl.wIndex));
48821 + DWC_PRINTF("OTG VERSION - %d\n", core_if->otg_ver);
48822 + DWC_PRINTF("OTG CAP - %d, %d\n",
48823 + core_if->core_params->otg_cap,
48824 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
48825 + if (core_if->otg_ver == 1
48826 + && core_if->core_params->otg_cap ==
48827 + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48828 + uint8_t *otgsts = (uint8_t*)pcd->status_buf;
48829 + *otgsts = (core_if->otg_sts & 0x1);
48830 + pcd->ep0_pending = 1;
48831 + ep0->dwc_ep.start_xfer_buff =
48832 + (uint8_t *) otgsts;
48833 + ep0->dwc_ep.xfer_buff = (uint8_t *) otgsts;
48834 + ep0->dwc_ep.dma_addr =
48835 + pcd->status_buf_dma_handle;
48836 + ep0->dwc_ep.xfer_len = 1;
48837 + ep0->dwc_ep.xfer_count = 0;
48838 + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
48839 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
48843 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48848 + *status = 0x1; /* Self powered */
48849 + *status |= pcd->remote_wakeup_enable << 1;
48852 + case UT_INTERFACE:
48856 + case UT_ENDPOINT:
48857 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
48858 + if (ep == 0 || UGETW(ctrl.wLength) > 2) {
48859 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48862 + /** @todo check for EP stall */
48863 + *status = ep->stopped;
48866 + pcd->ep0_pending = 1;
48867 + ep0->dwc_ep.start_xfer_buff = (uint8_t *) status;
48868 + ep0->dwc_ep.xfer_buff = (uint8_t *) status;
48869 + ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle;
48870 + ep0->dwc_ep.xfer_len = 2;
48871 + ep0->dwc_ep.xfer_count = 0;
48872 + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
48873 + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
48877 + * This function process the SET_FEATURE Setup Commands.
48879 +static inline void do_set_feature(dwc_otg_pcd_t * pcd)
48881 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
48882 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
48883 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48884 + dwc_otg_pcd_ep_t *ep = 0;
48885 + int32_t otg_cap_param = core_if->core_params->otg_cap;
48886 + gotgctl_data_t gotgctl = {.d32 = 0 };
48888 + DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
48889 + ctrl.bmRequestType, ctrl.bRequest,
48890 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48891 + UGETW(ctrl.wLength));
48892 + DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param);
48894 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
48896 + switch (UGETW(ctrl.wValue)) {
48897 + case UF_DEVICE_REMOTE_WAKEUP:
48898 + pcd->remote_wakeup_enable = 1;
48901 + case UF_TEST_MODE:
48902 + /* Setup the Test Mode tasklet to do the Test
48903 + * Packet generation after the SETUP Status
48904 + * phase has completed. */
48906 + /** @todo This has not been tested since the
48907 + * tasklet struct was put into the PCD
48909 + pcd->test_mode = UGETW(ctrl.wIndex) >> 8;
48910 + DWC_TASK_SCHEDULE(pcd->test_mode_tasklet);
48913 + case UF_DEVICE_B_HNP_ENABLE:
48914 + DWC_DEBUGPL(DBG_PCDV,
48915 + "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
48917 + /* dev may initiate HNP */
48918 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48919 + pcd->b_hnp_enable = 1;
48920 + dwc_otg_pcd_update_otg(pcd, 0);
48921 + DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
48922 + /**@todo Is the gotgctl.devhnpen cleared
48923 + * by a USB Reset? */
48924 + gotgctl.b.devhnpen = 1;
48925 + gotgctl.b.hnpreq = 1;
48926 + DWC_WRITE_REG32(&global_regs->gotgctl,
48929 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48934 + case UF_DEVICE_A_HNP_SUPPORT:
48935 + /* RH port supports HNP */
48936 + DWC_DEBUGPL(DBG_PCDV,
48937 + "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
48938 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48939 + pcd->a_hnp_support = 1;
48940 + dwc_otg_pcd_update_otg(pcd, 0);
48942 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48947 + case UF_DEVICE_A_ALT_HNP_SUPPORT:
48948 + /* other RH port does */
48949 + DWC_DEBUGPL(DBG_PCDV,
48950 + "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
48951 + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
48952 + pcd->a_alt_hnp_support = 1;
48953 + dwc_otg_pcd_update_otg(pcd, 0);
48955 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48961 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48965 + do_setup_in_status_phase(pcd);
48968 + case UT_INTERFACE:
48969 + do_gadget_setup(pcd, &ctrl);
48972 + case UT_ENDPOINT:
48973 + if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) {
48974 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
48976 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
48980 + dwc_otg_ep_set_stall(core_if, &ep->dwc_ep);
48982 + do_setup_in_status_phase(pcd);
48988 + * This function process the CLEAR_FEATURE Setup Commands.
48990 +static inline void do_clear_feature(dwc_otg_pcd_t * pcd)
48992 + usb_device_request_t ctrl = pcd->setup_pkt->req;
48993 + dwc_otg_pcd_ep_t *ep = 0;
48995 + DWC_DEBUGPL(DBG_PCD,
48996 + "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
48997 + ctrl.bmRequestType, ctrl.bRequest,
48998 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
48999 + UGETW(ctrl.wLength));
49001 + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
49003 + switch (UGETW(ctrl.wValue)) {
49004 + case UF_DEVICE_REMOTE_WAKEUP:
49005 + pcd->remote_wakeup_enable = 0;
49008 + case UF_TEST_MODE:
49009 + /** @todo Add CLEAR_FEATURE for TEST modes. */
49013 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
49016 + do_setup_in_status_phase(pcd);
49019 + case UT_ENDPOINT:
49020 + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
49022 + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
49026 + pcd_clear_halt(pcd, ep);
49033 + * This function process the SET_ADDRESS Setup Commands.
49035 +static inline void do_set_address(dwc_otg_pcd_t * pcd)
49037 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
49038 + usb_device_request_t ctrl = pcd->setup_pkt->req;
49040 + if (ctrl.bmRequestType == UT_DEVICE) {
49041 + dcfg_data_t dcfg = {.d32 = 0 };
49044 +// DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
49046 + dcfg.b.devaddr = UGETW(ctrl.wValue);
49047 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32);
49048 + do_setup_in_status_phase(pcd);
49053 + * This function processes SETUP commands. In Linux, the USB Command
49054 + * processing is done in two places - the first being the PCD and the
49055 + * second in the Gadget Driver (for example, the File-Backed Storage
49056 + * Gadget Driver).
49059 + * <tr><td>Command </td><td>Driver </td><td>Description</td></tr>
49061 + * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as
49062 + * defined in chapter 9 of the USB 2.0 Specification chapter 9
49065 + * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint
49066 + * requests are the ENDPOINT_HALT feature is procesed, all others the
49067 + * interface requests are ignored.</td></tr>
49069 + * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint
49070 + * requests are processed by the PCD. Interface requests are passed
49071 + * to the Gadget Driver.</td></tr>
49073 + * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg,
49074 + * with device address received </td></tr>
49076 + * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the
49077 + * requested descriptor</td></tr>
49079 + * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional -
49080 + * not implemented by any of the existing Gadget Drivers.</td></tr>
49082 + * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable
49083 + * all EPs and enable EPs for new configuration.</td></tr>
49085 + * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return
49086 + * the current configuration</td></tr>
49088 + * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all
49089 + * EPs and enable EPs for new configuration.</td></tr>
49091 + * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the
49092 + * current interface.</td></tr>
49094 + * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug
49095 + * message.</td></tr>
49098 + * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are
49099 + * processed by pcd_setup. Calling the Function Driver's setup function from
49100 + * pcd_setup processes the gadget SETUP commands.
49102 +static inline void pcd_setup(dwc_otg_pcd_t * pcd)
49104 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
49105 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49106 + usb_device_request_t ctrl = pcd->setup_pkt->req;
49107 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
49109 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
49111 +#ifdef DWC_UTE_CFI
49113 + struct cfi_usb_ctrlrequest cfi_req;
49116 + doeptsize0.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doeptsiz);
49118 + /** In BDMA more then 1 setup packet is not supported till 3.00a */
49119 + if (core_if->dma_enable && core_if->dma_desc_enable == 0
49120 + && (doeptsize0.b.supcnt < 2)
49121 + && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
49123 + ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n");
49125 + if ((core_if->snpsid >= OTG_CORE_REV_3_00a)
49126 + && (core_if->dma_enable == 1) && (core_if->dma_desc_enable == 0)) {
49128 + (pcd->setup_pkt +
49129 + (3 - doeptsize0.b.supcnt - 1 +
49130 + ep0->dwc_ep.stp_rollover))->req;
49133 + DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
49134 + ctrl.bmRequestType, ctrl.bRequest,
49135 + UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
49136 + UGETW(ctrl.wLength));
49139 + /* Clean up the request queue */
49140 + dwc_otg_request_nuke(ep0);
49141 + ep0->stopped = 0;
49143 + if (ctrl.bmRequestType & UE_DIR_IN) {
49144 + ep0->dwc_ep.is_in = 1;
49145 + pcd->ep0state = EP0_IN_DATA_PHASE;
49147 + ep0->dwc_ep.is_in = 0;
49148 + pcd->ep0state = EP0_OUT_DATA_PHASE;
49151 + if (UGETW(ctrl.wLength) == 0) {
49152 + ep0->dwc_ep.is_in = 1;
49153 + pcd->ep0state = EP0_IN_STATUS_PHASE;
49156 + if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) {
49158 +#ifdef DWC_UTE_CFI
49159 + DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t));
49161 + //printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n",
49162 + ctrl.bRequestType, ctrl.bRequest);
49163 + if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) {
49164 + if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) {
49165 + retval = cfi_setup(pcd, &cfi_req);
49166 + if (retval < 0) {
49167 + ep0_do_stall(pcd, retval);
49168 + pcd->ep0_pending = 0;
49172 + /* if need gadget setup then call it and check the retval */
49173 + if (pcd->cfi->need_gadget_att) {
49175 + cfi_gadget_setup(pcd,
49178 + if (retval < 0) {
49179 + pcd->ep0_pending = 0;
49184 + if (pcd->cfi->need_status_in_complete) {
49185 + do_setup_in_status_phase(pcd);
49192 + /* handle non-standard (class/vendor) requests in the gadget driver */
49193 + do_gadget_setup(pcd, &ctrl);
49197 + /** @todo NGS: Handle bad setup packet? */
49199 +///////////////////////////////////////////
49200 +//// --- Standard Request handling --- ////
49202 + switch (ctrl.bRequest) {
49203 + case UR_GET_STATUS:
49204 + do_get_status(pcd);
49207 + case UR_CLEAR_FEATURE:
49208 + do_clear_feature(pcd);
49211 + case UR_SET_FEATURE:
49212 + do_set_feature(pcd);
49215 + case UR_SET_ADDRESS:
49216 + do_set_address(pcd);
49219 + case UR_SET_INTERFACE:
49220 + case UR_SET_CONFIG:
49221 +// _pcd->request_config = 1; /* Configuration changed */
49222 + do_gadget_setup(pcd, &ctrl);
49225 + case UR_SYNCH_FRAME:
49226 + do_gadget_setup(pcd, &ctrl);
49230 + /* Call the Gadget Driver's setup functions */
49231 + do_gadget_setup(pcd, &ctrl);
49237 + * This function completes the ep0 control transfer.
49239 +static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep)
49241 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
49242 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49243 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
49244 + dev_if->in_ep_regs[ep->dwc_ep.num];
49246 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
49247 + dev_if->out_ep_regs[ep->dwc_ep.num];
49249 + deptsiz0_data_t deptsiz;
49250 + dev_dma_desc_sts_t desc_sts;
49251 + dwc_otg_pcd_request_t *req;
49253 + dwc_otg_pcd_t *pcd = ep->pcd;
49255 +#ifdef DWC_UTE_CFI
49256 + struct cfi_usb_ctrlrequest *ctrlreq;
49257 + int retval = -DWC_E_NOT_SUPPORTED;
49260 + desc_sts.b.bytes = 0;
49262 + if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49263 + if (ep->dwc_ep.is_in) {
49265 + DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
49267 + do_setup_out_status_phase(pcd);
49270 + DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
49273 +#ifdef DWC_UTE_CFI
49274 + ctrlreq = &pcd->cfi->ctrl_req;
49276 + if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) {
49277 + if (ctrlreq->bRequest > 0xB0
49278 + && ctrlreq->bRequest < 0xBF) {
49280 + /* Return if the PCD failed to handle the request */
49283 + ctrl_write_complete(pcd->cfi,
49286 + ("ERROR setting a new value in the PCD(%d)\n",
49288 + ep0_do_stall(pcd, retval);
49289 + pcd->ep0_pending = 0;
49293 + /* If the gadget needs to be notified on the request */
49294 + if (pcd->cfi->need_gadget_att == 1) {
49295 + //retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req);
49297 + cfi_gadget_setup(pcd,
49301 + /* Return from the function if the gadget failed to process
49302 + * the request properly - this should never happen !!!
49304 + if (retval < 0) {
49306 + ("ERROR setting a new value in the gadget(%d)\n",
49308 + pcd->ep0_pending = 0;
49313 + CFI_INFO("%s: RETVAL=%d\n", __func__,
49315 + /* If we hit here then the PCD and the gadget has properly
49316 + * handled the request - so send the ZLP IN to the host.
49318 + /* @todo: MAS - decide whether we need to start the setup
49319 + * stage based on the need_setup value of the cfi object
49321 + do_setup_in_status_phase(pcd);
49322 + pcd->ep0_pending = 0;
49328 + do_setup_in_status_phase(pcd);
49330 + pcd->ep0_pending = 0;
49334 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49337 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
49339 + if (pcd->ep0state == EP0_OUT_STATUS_PHASE
49340 + || pcd->ep0state == EP0_IN_STATUS_PHASE) {
49342 + } else if (ep->dwc_ep.is_in) {
49343 + deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
49344 + if (core_if->dma_desc_enable != 0)
49345 + desc_sts = dev_if->in_desc_addr->status;
49347 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xfersize=%d pktcnt=%d\n",
49348 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
49349 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49352 + if (((core_if->dma_desc_enable == 0)
49353 + && (deptsiz.b.xfersize == 0))
49354 + || ((core_if->dma_desc_enable != 0)
49355 + && (desc_sts.b.bytes == 0))) {
49356 + req->actual = ep->dwc_ep.xfer_count;
49357 + /* Is a Zero Len Packet needed? */
49358 + if (req->sent_zlp) {
49360 + DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
49362 + req->sent_zlp = 0;
49364 + do_setup_out_status_phase(pcd);
49369 + deptsiz.d32 = DWC_READ_REG32(&out_ep_regs->doeptsiz);
49370 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n",
49371 + ep->dwc_ep.num, ep->dwc_ep.xfer_len,
49372 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49374 + req->actual = ep->dwc_ep.xfer_count;
49376 + /* Is a Zero Len Packet needed? */
49377 + if (req->sent_zlp) {
49379 + DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
49381 + req->sent_zlp = 0;
49383 + /* For older cores do setup in status phase in Slave/BDMA modes,
49384 + * starting from 3.00 do that only in slave, and for DMA modes
49385 + * just re-enable ep 0 OUT here*/
49386 + if (core_if->dma_enable == 0
49387 + || (core_if->dma_desc_enable == 0
49388 + && core_if->snpsid <= OTG_CORE_REV_2_94a)) {
49389 + do_setup_in_status_phase(pcd);
49390 + } else if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
49391 + DWC_DEBUGPL(DBG_PCDV,
49392 + "Enable out ep before in status phase\n");
49393 + ep0_out_start(core_if, pcd);
49397 + /* Complete the request */
49399 + dwc_otg_request_done(ep, req, 0);
49400 + ep->dwc_ep.start_xfer_buff = 0;
49401 + ep->dwc_ep.xfer_buff = 0;
49402 + ep->dwc_ep.xfer_len = 0;
49408 +#ifdef DWC_UTE_CFI
49410 + * This function calculates traverses all the CFI DMA descriptors and
49411 + * and accumulates the bytes that are left to be transfered.
49413 + * @return The total bytes left to transfered, or a negative value as failure
49415 +static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep)
49419 + struct dwc_otg_dma_desc *ddesc = NULL;
49420 + struct cfi_ep *cfiep;
49422 + /* See if the pcd_ep has its respective cfi_ep mapped */
49423 + cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep);
49425 + CFI_INFO("%s: Failed to find ep\n", __func__);
49429 + ddesc = ep->dwc_ep.descs;
49431 + for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) {
49433 +#if defined(PRINT_CFI_DMA_DESCS)
49434 + print_desc(ddesc, ep->ep.name, i);
49436 + ret += ddesc->status.b.bytes;
49441 + CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__,
49449 + * This function completes the request for the EP. If there are
49450 + * additional requests for the EP in the queue they will be started.
49452 +static void complete_ep(dwc_otg_pcd_ep_t * ep)
49454 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
49455 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
49456 + dwc_otg_dev_in_ep_regs_t *in_ep_regs =
49457 + dev_if->in_ep_regs[ep->dwc_ep.num];
49458 + deptsiz_data_t deptsiz;
49459 + dev_dma_desc_sts_t desc_sts;
49460 + dwc_otg_pcd_request_t *req = 0;
49461 + dwc_otg_dev_dma_desc_t *dma_desc;
49462 + uint32_t byte_count = 0;
49466 + DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num,
49467 + (ep->dwc_ep.is_in ? "IN" : "OUT"));
49469 + /* Get any pending requests */
49470 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
49471 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
49473 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
49477 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
49481 + DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending);
49483 + if (ep->dwc_ep.is_in) {
49484 + deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
49486 + if (core_if->dma_enable) {
49487 + if (core_if->dma_desc_enable == 0) {
49488 + if (deptsiz.b.xfersize == 0
49489 + && deptsiz.b.pktcnt == 0) {
49491 + ep->dwc_ep.xfer_len -
49492 + ep->dwc_ep.xfer_count;
49494 + ep->dwc_ep.xfer_buff += byte_count;
49495 + ep->dwc_ep.dma_addr += byte_count;
49496 + ep->dwc_ep.xfer_count += byte_count;
49498 + DWC_DEBUGPL(DBG_PCDV,
49499 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
49502 + is_in ? "IN" : "OUT"),
49503 + ep->dwc_ep.xfer_len,
49504 + deptsiz.b.xfersize,
49505 + deptsiz.b.pktcnt);
49507 + if (ep->dwc_ep.xfer_len <
49508 + ep->dwc_ep.total_len) {
49509 + dwc_otg_ep_start_transfer
49510 + (core_if, &ep->dwc_ep);
49511 + } else if (ep->dwc_ep.sent_zlp) {
49513 + * This fragment of code should initiate 0
49514 + * length transfer in case if it is queued
49515 + * a transfer with size divisible to EPs max
49516 + * packet size and with usb_request zero field
49517 + * is set, which means that after data is transfered,
49518 + * it is also should be transfered
49519 + * a 0 length packet at the end. For Slave and
49520 + * Buffer DMA modes in this case SW has
49521 + * to initiate 2 transfers one with transfer size,
49522 + * and the second with 0 size. For Descriptor
49523 + * DMA mode SW is able to initiate a transfer,
49524 + * which will handle all the packets including
49525 + * the last 0 length.
49527 + ep->dwc_ep.sent_zlp = 0;
49528 + dwc_otg_ep_start_zl_transfer
49529 + (core_if, &ep->dwc_ep);
49534 + if (ep->dwc_ep.type ==
49535 + DWC_OTG_EP_TYPE_ISOC) {
49537 + dwc_otg_request_done(ep, req, 0);
49539 + ep->dwc_ep.start_xfer_buff = 0;
49540 + ep->dwc_ep.xfer_buff = 0;
49541 + ep->dwc_ep.xfer_len = 0;
49543 + /* If there is a request in the queue start it. */
49544 + start_next_request(ep);
49547 + ("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n",
49549 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
49550 + deptsiz.b.xfersize,
49551 + deptsiz.b.pktcnt);
49554 + dma_desc = ep->dwc_ep.desc_addr;
49556 + ep->dwc_ep.sent_zlp = 0;
49558 +#ifdef DWC_UTE_CFI
49559 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
49560 + ep->dwc_ep.buff_mode);
49561 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49564 + residue = cfi_calc_desc_residue(ep);
49568 + byte_count = residue;
49571 + for (i = 0; i < ep->dwc_ep.desc_cnt;
49573 + desc_sts = dma_desc->status;
49574 + byte_count += desc_sts.b.bytes;
49577 +#ifdef DWC_UTE_CFI
49580 + if (byte_count == 0) {
49581 + ep->dwc_ep.xfer_count =
49582 + ep->dwc_ep.total_len;
49585 + DWC_WARN("Incomplete transfer\n");
49589 + if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) {
49590 + DWC_DEBUGPL(DBG_PCDV,
49591 + "%d-%s len=%d xfersize=%d pktcnt=%d\n",
49593 + ep->dwc_ep.is_in ? "IN" : "OUT",
49594 + ep->dwc_ep.xfer_len,
49595 + deptsiz.b.xfersize,
49596 + deptsiz.b.pktcnt);
49598 + /* Check if the whole transfer was completed,
49599 + * if no, setup transfer for next portion of data
49601 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49602 + dwc_otg_ep_start_transfer(core_if,
49604 + } else if (ep->dwc_ep.sent_zlp) {
49606 + * This fragment of code should initiate 0
49607 + * length trasfer in case if it is queued
49608 + * a trasfer with size divisible to EPs max
49609 + * packet size and with usb_request zero field
49610 + * is set, which means that after data is transfered,
49611 + * it is also should be transfered
49612 + * a 0 length packet at the end. For Slave and
49613 + * Buffer DMA modes in this case SW has
49614 + * to initiate 2 transfers one with transfer size,
49615 + * and the second with 0 size. For Desriptor
49616 + * DMA mode SW is able to initiate a transfer,
49617 + * which will handle all the packets including
49618 + * the last 0 legth.
49620 + ep->dwc_ep.sent_zlp = 0;
49621 + dwc_otg_ep_start_zl_transfer(core_if,
49628 + ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n",
49630 + (ep->dwc_ep.is_in ? "IN" : "OUT"),
49631 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49635 + dwc_otg_dev_out_ep_regs_t *out_ep_regs =
49636 + dev_if->out_ep_regs[ep->dwc_ep.num];
49637 + desc_sts.d32 = 0;
49638 + if (core_if->dma_enable) {
49639 + if (core_if->dma_desc_enable) {
49640 + dma_desc = ep->dwc_ep.desc_addr;
49642 + ep->dwc_ep.sent_zlp = 0;
49644 +#ifdef DWC_UTE_CFI
49645 + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
49646 + ep->dwc_ep.buff_mode);
49647 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49649 + residue = cfi_calc_desc_residue(ep);
49652 + byte_count = residue;
49656 + for (i = 0; i < ep->dwc_ep.desc_cnt;
49658 + desc_sts = dma_desc->status;
49659 + byte_count += desc_sts.b.bytes;
49663 +#ifdef DWC_UTE_CFI
49666 + /* Checking for interrupt Out transfers with not
49667 + * dword aligned mps sizes
49669 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_INTR &&
49670 + (ep->dwc_ep.maxpacket%4)) {
49671 + ep->dwc_ep.xfer_count =
49672 + ep->dwc_ep.total_len - byte_count;
49673 + if ((ep->dwc_ep.xfer_len %
49674 + ep->dwc_ep.maxpacket)
49675 + && (ep->dwc_ep.xfer_len /
49676 + ep->dwc_ep.maxpacket <
49677 + MAX_DMA_DESC_CNT))
49678 + ep->dwc_ep.xfer_len -=
49679 + (ep->dwc_ep.desc_cnt -
49680 + 1) * ep->dwc_ep.maxpacket +
49681 + ep->dwc_ep.xfer_len %
49682 + ep->dwc_ep.maxpacket;
49684 + ep->dwc_ep.xfer_len -=
49685 + ep->dwc_ep.desc_cnt *
49686 + ep->dwc_ep.maxpacket;
49687 + if (ep->dwc_ep.xfer_len > 0) {
49688 + dwc_otg_ep_start_transfer
49689 + (core_if, &ep->dwc_ep);
49694 + ep->dwc_ep.xfer_count =
49695 + ep->dwc_ep.total_len - byte_count +
49698 + total_len & 0x3)) & 0x3);
49704 + DWC_READ_REG32(&out_ep_regs->doeptsiz);
49706 + byte_count = (ep->dwc_ep.xfer_len -
49707 + ep->dwc_ep.xfer_count -
49708 + deptsiz.b.xfersize);
49709 + ep->dwc_ep.xfer_buff += byte_count;
49710 + ep->dwc_ep.dma_addr += byte_count;
49711 + ep->dwc_ep.xfer_count += byte_count;
49713 + /* Check if the whole transfer was completed,
49714 + * if no, setup transfer for next portion of data
49716 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49717 + dwc_otg_ep_start_transfer(core_if,
49719 + } else if (ep->dwc_ep.sent_zlp) {
49721 + * This fragment of code should initiate 0
49722 + * length trasfer in case if it is queued
49723 + * a trasfer with size divisible to EPs max
49724 + * packet size and with usb_request zero field
49725 + * is set, which means that after data is transfered,
49726 + * it is also should be transfered
49727 + * a 0 length packet at the end. For Slave and
49728 + * Buffer DMA modes in this case SW has
49729 + * to initiate 2 transfers one with transfer size,
49730 + * and the second with 0 size. For Desriptor
49731 + * DMA mode SW is able to initiate a transfer,
49732 + * which will handle all the packets including
49733 + * the last 0 legth.
49735 + ep->dwc_ep.sent_zlp = 0;
49736 + dwc_otg_ep_start_zl_transfer(core_if,
49743 + /* Check if the whole transfer was completed,
49744 + * if no, setup transfer for next portion of data
49746 + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
49747 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
49748 + } else if (ep->dwc_ep.sent_zlp) {
49750 + * This fragment of code should initiate 0
49751 + * length transfer in case if it is queued
49752 + * a transfer with size divisible to EPs max
49753 + * packet size and with usb_request zero field
49754 + * is set, which means that after data is transfered,
49755 + * it is also should be transfered
49756 + * a 0 length packet at the end. For Slave and
49757 + * Buffer DMA modes in this case SW has
49758 + * to initiate 2 transfers one with transfer size,
49759 + * and the second with 0 size. For Descriptor
49760 + * DMA mode SW is able to initiate a transfer,
49761 + * which will handle all the packets including
49762 + * the last 0 length.
49764 + ep->dwc_ep.sent_zlp = 0;
49765 + dwc_otg_ep_start_zl_transfer(core_if,
49772 + DWC_DEBUGPL(DBG_PCDV,
49773 + "addr %p, %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n",
49774 + &out_ep_regs->doeptsiz, ep->dwc_ep.num,
49775 + ep->dwc_ep.is_in ? "IN" : "OUT",
49776 + ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count,
49777 + deptsiz.b.xfersize, deptsiz.b.pktcnt);
49780 + /* Complete the request */
49782 +#ifdef DWC_UTE_CFI
49783 + if (ep->dwc_ep.buff_mode != BM_STANDARD) {
49784 + req->actual = ep->dwc_ep.cfi_req_len - byte_count;
49787 + req->actual = ep->dwc_ep.xfer_count;
49788 +#ifdef DWC_UTE_CFI
49791 + if (req->dw_align_buf) {
49792 + if (!ep->dwc_ep.is_in) {
49793 + dwc_memcpy(req->buf, req->dw_align_buf, req->length);
49795 + DWC_DMA_FREE(req->length, req->dw_align_buf,
49796 + req->dw_align_buf_dma);
49799 + dwc_otg_request_done(ep, req, 0);
49801 + ep->dwc_ep.start_xfer_buff = 0;
49802 + ep->dwc_ep.xfer_buff = 0;
49803 + ep->dwc_ep.xfer_len = 0;
49805 + /* If there is a request in the queue start it. */
49806 + start_next_request(ep);
49810 +#ifdef DWC_EN_ISOC
49813 + * This function BNA interrupt for Isochronous EPs
49816 +static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep)
49818 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
49819 + volatile uint32_t *addr;
49820 + depctl_data_t depctl = {.d32 = 0 };
49821 + dwc_otg_pcd_t *pcd = ep->pcd;
49822 + dwc_otg_dev_dma_desc_t *dma_desc;
49826 + dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num);
49828 + if (dwc_ep->is_in) {
49829 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49830 + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
49831 + sts.d32 = dma_desc->status.d32;
49832 + sts.b_iso_in.bs = BS_HOST_READY;
49833 + dma_desc->status.d32 = sts.d32;
49836 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49837 + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
49838 + sts.d32 = dma_desc->status.d32;
49839 + sts.b_iso_out.bs = BS_HOST_READY;
49840 + dma_desc->status.d32 = sts.d32;
49844 + if (dwc_ep->is_in == 0) {
49846 + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->
49850 + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
49852 + depctl.b.epena = 1;
49853 + DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
49857 + * This function sets latest iso packet information(non-PTI mode)
49859 + * @param core_if Programming view of DWC_otg controller.
49860 + * @param ep The EP to start the transfer on.
49863 +void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
49865 + deptsiz_data_t deptsiz = {.d32 = 0 };
49866 + dma_addr_t dma_addr;
49869 + if (ep->proc_buf_num)
49870 + dma_addr = ep->dma_addr1;
49872 + dma_addr = ep->dma_addr0;
49876 + DWC_READ_REG32(&core_if->dev_if->
49877 + in_ep_regs[ep->num]->dieptsiz);
49878 + offset = ep->data_per_frame;
49881 + DWC_READ_REG32(&core_if->dev_if->
49882 + out_ep_regs[ep->num]->doeptsiz);
49884 + ep->data_per_frame +
49885 + (0x4 & (0x4 - (ep->data_per_frame & 0x3)));
49888 + if (!deptsiz.b.xfersize) {
49889 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
49890 + ep->pkt_info[ep->cur_pkt].offset =
49891 + ep->cur_pkt_dma_addr - dma_addr;
49892 + ep->pkt_info[ep->cur_pkt].status = 0;
49894 + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
49895 + ep->pkt_info[ep->cur_pkt].offset =
49896 + ep->cur_pkt_dma_addr - dma_addr;
49897 + ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA;
49899 + ep->cur_pkt_addr += offset;
49900 + ep->cur_pkt_dma_addr += offset;
49905 + * This function sets latest iso packet information(DDMA mode)
49907 + * @param core_if Programming view of DWC_otg controller.
49908 + * @param dwc_ep The EP to start the transfer on.
49911 +static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if,
49912 + dwc_ep_t * dwc_ep)
49914 + dwc_otg_dev_dma_desc_t *dma_desc;
49915 + dev_dma_desc_sts_t sts = {.d32 = 0 };
49916 + iso_pkt_info_t *iso_packet;
49917 + uint32_t data_per_desc;
49921 + iso_packet = dwc_ep->pkt_info;
49923 + /** Reinit closed DMA Descriptors*/
49924 + /** ISO OUT EP */
49925 + if (dwc_ep->is_in == 0) {
49927 + dwc_ep->iso_desc_addr +
49928 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
49931 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
49932 + i += dwc_ep->pkt_per_frm) {
49933 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
49935 + ((j + 1) * dwc_ep->maxpacket >
49937 + data_per_frame) ? dwc_ep->data_per_frame -
49938 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49940 + (data_per_desc % 4) ? (4 -
49944 + sts.d32 = dma_desc->status.d32;
49946 + /* Write status in iso_packet_decsriptor */
49947 + iso_packet->status =
49948 + sts.b_iso_out.rxsts +
49949 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
49950 + if (iso_packet->status) {
49951 + iso_packet->status = -DWC_E_NO_DATA;
49954 + /* Received data length */
49955 + if (!sts.b_iso_out.rxbytes) {
49956 + iso_packet->length =
49958 + sts.b_iso_out.rxbytes;
49960 + iso_packet->length =
49962 + sts.b_iso_out.rxbytes + (4 -
49963 + dwc_ep->data_per_frame
49967 + iso_packet->offset = offset;
49969 + offset += data_per_desc;
49975 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
49977 + ((j + 1) * dwc_ep->maxpacket >
49978 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
49979 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
49981 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
49983 + sts.d32 = dma_desc->status.d32;
49985 + /* Write status in iso_packet_decsriptor */
49986 + iso_packet->status =
49987 + sts.b_iso_out.rxsts +
49988 + (sts.b_iso_out.bs ^ BS_DMA_DONE);
49989 + if (iso_packet->status) {
49990 + iso_packet->status = -DWC_E_NO_DATA;
49993 + /* Received data length */
49994 + iso_packet->length =
49995 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
49997 + iso_packet->offset = offset;
49999 + offset += data_per_desc;
50004 + sts.d32 = dma_desc->status.d32;
50006 + /* Write status in iso_packet_decsriptor */
50007 + iso_packet->status =
50008 + sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE);
50009 + if (iso_packet->status) {
50010 + iso_packet->status = -DWC_E_NO_DATA;
50012 + /* Received data length */
50013 + if (!sts.b_iso_out.rxbytes) {
50014 + iso_packet->length =
50015 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
50017 + iso_packet->length =
50018 + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes +
50019 + (4 - dwc_ep->data_per_frame % 4);
50022 + iso_packet->offset = offset;
50027 + dwc_ep->iso_desc_addr +
50028 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
50030 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
50031 + sts.d32 = dma_desc->status.d32;
50033 + /* Write status in iso packet descriptor */
50034 + iso_packet->status =
50035 + sts.b_iso_in.txsts +
50036 + (sts.b_iso_in.bs ^ BS_DMA_DONE);
50037 + if (iso_packet->status != 0) {
50038 + iso_packet->status = -DWC_E_NO_DATA;
50041 + /* Bytes has been transfered */
50042 + iso_packet->length =
50043 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
50049 + sts.d32 = dma_desc->status.d32;
50050 + while (sts.b_iso_in.bs == BS_DMA_BUSY) {
50051 + sts.d32 = dma_desc->status.d32;
50054 + /* Write status in iso packet descriptor ??? do be done with ERROR codes */
50055 + iso_packet->status =
50056 + sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE);
50057 + if (iso_packet->status != 0) {
50058 + iso_packet->status = -DWC_E_NO_DATA;
50061 + /* Bytes has been transfered */
50062 + iso_packet->length =
50063 + dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
50068 + * This function reinitialize DMA Descriptors for Isochronous transfer
50070 + * @param core_if Programming view of DWC_otg controller.
50071 + * @param dwc_ep The EP to start the transfer on.
50074 +static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
50077 + dwc_otg_dev_dma_desc_t *dma_desc;
50078 + dma_addr_t dma_ad;
50079 + volatile uint32_t *addr;
50080 + dev_dma_desc_sts_t sts = {.d32 = 0 };
50081 + uint32_t data_per_desc;
50083 + if (dwc_ep->is_in == 0) {
50084 + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
50086 + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
50089 + if (dwc_ep->proc_buf_num == 0) {
50090 + /** Buffer 0 descriptors setup */
50091 + dma_ad = dwc_ep->dma_addr0;
50093 + /** Buffer 1 descriptors setup */
50094 + dma_ad = dwc_ep->dma_addr1;
50097 + /** Reinit closed DMA Descriptors*/
50098 + /** ISO OUT EP */
50099 + if (dwc_ep->is_in == 0) {
50101 + dwc_ep->iso_desc_addr +
50102 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
50104 + sts.b_iso_out.bs = BS_HOST_READY;
50105 + sts.b_iso_out.rxsts = 0;
50106 + sts.b_iso_out.l = 0;
50107 + sts.b_iso_out.sp = 0;
50108 + sts.b_iso_out.ioc = 0;
50109 + sts.b_iso_out.pid = 0;
50110 + sts.b_iso_out.framenum = 0;
50112 + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
50113 + i += dwc_ep->pkt_per_frm) {
50114 + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
50116 + ((j + 1) * dwc_ep->maxpacket >
50118 + data_per_frame) ? dwc_ep->data_per_frame -
50119 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
50121 + (data_per_desc % 4) ? (4 -
50124 + sts.b_iso_out.rxbytes = data_per_desc;
50125 + dma_desc->buf = dma_ad;
50126 + dma_desc->status.d32 = sts.d32;
50128 + dma_ad += data_per_desc;
50133 + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
50136 + ((j + 1) * dwc_ep->maxpacket >
50137 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
50138 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
50140 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
50141 + sts.b_iso_out.rxbytes = data_per_desc;
50143 + dma_desc->buf = dma_ad;
50144 + dma_desc->status.d32 = sts.d32;
50147 + dma_ad += data_per_desc;
50150 + sts.b_iso_out.ioc = 1;
50151 + sts.b_iso_out.l = dwc_ep->proc_buf_num;
50154 + ((j + 1) * dwc_ep->maxpacket >
50155 + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
50156 + j * dwc_ep->maxpacket : dwc_ep->maxpacket;
50158 + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
50159 + sts.b_iso_out.rxbytes = data_per_desc;
50161 + dma_desc->buf = dma_ad;
50162 + dma_desc->status.d32 = sts.d32;
50167 + dwc_ep->iso_desc_addr +
50168 + dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
50170 + sts.b_iso_in.bs = BS_HOST_READY;
50171 + sts.b_iso_in.txsts = 0;
50172 + sts.b_iso_in.sp = 0;
50173 + sts.b_iso_in.ioc = 0;
50174 + sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
50175 + sts.b_iso_in.framenum = dwc_ep->next_frame;
50176 + sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
50177 + sts.b_iso_in.l = 0;
50179 + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
50180 + dma_desc->buf = dma_ad;
50181 + dma_desc->status.d32 = sts.d32;
50183 + sts.b_iso_in.framenum += dwc_ep->bInterval;
50184 + dma_ad += dwc_ep->data_per_frame;
50188 + sts.b_iso_in.ioc = 1;
50189 + sts.b_iso_in.l = dwc_ep->proc_buf_num;
50191 + dma_desc->buf = dma_ad;
50192 + dma_desc->status.d32 = sts.d32;
50194 + dwc_ep->next_frame =
50195 + sts.b_iso_in.framenum + dwc_ep->bInterval * 1;
50197 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
50201 + * This function is to handle Iso EP transfer complete interrupt
50202 + * in case Iso out packet was dropped
50204 + * @param core_if Programming view of DWC_otg controller.
50205 + * @param dwc_ep The EP for wihich transfer complete was asserted
50208 +static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if,
50209 + dwc_ep_t * dwc_ep)
50211 + uint32_t dma_addr;
50212 + uint32_t drp_pkt;
50213 + uint32_t drp_pkt_cnt;
50214 + deptsiz_data_t deptsiz = {.d32 = 0 };
50215 + depctl_data_t depctl = {.d32 = 0 };
50219 + DWC_READ_REG32(&core_if->dev_if->
50220 + out_ep_regs[dwc_ep->num]->doeptsiz);
50222 + drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt;
50223 + drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm);
50225 + /* Setting dropped packets status */
50226 + for (i = 0; i < drp_pkt_cnt; ++i) {
50227 + dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA;
50229 + deptsiz.b.pktcnt--;
50232 + if (deptsiz.b.pktcnt > 0) {
50233 + deptsiz.b.xfersize =
50234 + dwc_ep->xfer_len - (dwc_ep->pkt_cnt -
50235 + deptsiz.b.pktcnt) * dwc_ep->maxpacket;
50237 + deptsiz.b.xfersize = 0;
50238 + deptsiz.b.pktcnt = 0;
50241 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz,
50244 + if (deptsiz.b.pktcnt > 0) {
50245 + if (dwc_ep->proc_buf_num) {
50247 + dwc_ep->dma_addr1 + dwc_ep->xfer_len -
50248 + deptsiz.b.xfersize;
50251 + dwc_ep->dma_addr0 + dwc_ep->xfer_len -
50252 + deptsiz.b.xfersize;;
50255 + DWC_WRITE_REG32(&core_if->dev_if->
50256 + out_ep_regs[dwc_ep->num]->doepdma, dma_addr);
50258 + /** Re-enable endpoint, clear nak */
50260 + depctl.b.epena = 1;
50261 + depctl.b.cnak = 1;
50263 + DWC_MODIFY_REG32(&core_if->dev_if->
50264 + out_ep_regs[dwc_ep->num]->doepctl, depctl.d32,
50273 + * This function sets iso packets information(PTI mode)
50275 + * @param core_if Programming view of DWC_otg controller.
50276 + * @param ep The EP to start the transfer on.
50279 +static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
50282 + dma_addr_t dma_ad;
50283 + iso_pkt_info_t *packet_info = ep->pkt_info;
50285 + uint32_t frame_data;
50286 + deptsiz_data_t deptsiz;
50288 + if (ep->proc_buf_num == 0) {
50289 + /** Buffer 0 descriptors setup */
50290 + dma_ad = ep->dma_addr0;
50292 + /** Buffer 1 descriptors setup */
50293 + dma_ad = ep->dma_addr1;
50298 + DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
50302 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
50306 + if (!deptsiz.b.xfersize) {
50308 + for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) {
50309 + frame_data = ep->data_per_frame;
50310 + for (j = 0; j < ep->pkt_per_frm; ++j) {
50312 + /* Packet status - is not set as initially
50313 + * it is set to 0 and if packet was sent
50314 + successfully, status field will remain 0*/
50316 + /* Bytes has been transfered */
50317 + packet_info->length =
50319 + frame_data) ? ep->maxpacket : frame_data;
50321 + /* Received packet offset */
50322 + packet_info->offset = offset;
50323 + offset += packet_info->length;
50324 + frame_data -= packet_info->length;
50331 + /* This is a workaround for in case of Transfer Complete with
50332 + * PktDrpSts interrupts merging - in this case Transfer complete
50333 + * interrupt for Isoc Out Endpoint is asserted without PktDrpSts
50334 + * set and with DOEPTSIZ register non zero. Investigations showed,
50335 + * that this happens when Out packet is dropped, but because of
50336 + * interrupts merging during first interrupt handling PktDrpSts
50337 + * bit is cleared and for next merged interrupts it is not reset.
50338 + * In this case SW hadles the interrupt as if PktDrpSts bit is set.
50343 + return handle_iso_out_pkt_dropped(core_if, ep);
50349 + * This function is to handle Iso EP transfer complete interrupt
50351 + * @param pcd The PCD
50352 + * @param ep The EP for which transfer complete was asserted
50355 +static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
50357 + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
50358 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
50359 + uint8_t is_last = 0;
50361 + if (ep->dwc_ep.next_frame == 0xffffffff) {
50362 + DWC_WARN("Next frame is not set!\n");
50366 + if (core_if->dma_enable) {
50367 + if (core_if->dma_desc_enable) {
50368 + set_ddma_iso_pkts_info(core_if, dwc_ep);
50369 + reinit_ddma_iso_xfer(core_if, dwc_ep);
50372 + if (core_if->pti_enh_enable) {
50373 + if (set_iso_pkts_info(core_if, dwc_ep)) {
50374 + dwc_ep->proc_buf_num =
50375 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
50376 + dwc_otg_iso_ep_start_buf_transfer
50377 + (core_if, dwc_ep);
50381 + set_current_pkt_info(core_if, dwc_ep);
50382 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
50384 + dwc_ep->cur_pkt = 0;
50385 + dwc_ep->proc_buf_num =
50386 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
50387 + if (dwc_ep->proc_buf_num) {
50388 + dwc_ep->cur_pkt_addr =
50389 + dwc_ep->xfer_buff1;
50390 + dwc_ep->cur_pkt_dma_addr =
50391 + dwc_ep->dma_addr1;
50393 + dwc_ep->cur_pkt_addr =
50394 + dwc_ep->xfer_buff0;
50395 + dwc_ep->cur_pkt_dma_addr =
50396 + dwc_ep->dma_addr0;
50400 + dwc_otg_iso_ep_start_frm_transfer(core_if,
50405 + set_current_pkt_info(core_if, dwc_ep);
50406 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
50408 + dwc_ep->cur_pkt = 0;
50409 + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
50410 + if (dwc_ep->proc_buf_num) {
50411 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1;
50412 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1;
50414 + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0;
50415 + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0;
50419 + dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep);
50422 + dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle);
50424 +#endif /* DWC_EN_ISOC */
50427 + * This function handle BNA interrupt for Non Isochronous EPs
50430 +static void dwc_otg_pcd_handle_noniso_bna(dwc_otg_pcd_ep_t * ep)
50432 + dwc_ep_t *dwc_ep = &ep->dwc_ep;
50433 + volatile uint32_t *addr;
50434 + depctl_data_t depctl = {.d32 = 0 };
50435 + dwc_otg_pcd_t *pcd = ep->pcd;
50436 + dwc_otg_dev_dma_desc_t *dma_desc;
50437 + dev_dma_desc_sts_t sts = {.d32 = 0 };
50438 + dwc_otg_core_if_t *core_if = ep->pcd->core_if;
50441 + if (!dwc_ep->desc_cnt)
50442 + DWC_WARN("Ep%d %s Descriptor count = %d \n", dwc_ep->num,
50443 + (dwc_ep->is_in ? "IN" : "OUT"), dwc_ep->desc_cnt);
50445 + if (core_if->core_params->cont_on_bna && !dwc_ep->is_in
50446 + && dwc_ep->type != DWC_OTG_EP_TYPE_CONTROL) {
50447 + uint32_t doepdma;
50448 + dwc_otg_dev_out_ep_regs_t *out_regs =
50449 + core_if->dev_if->out_ep_regs[dwc_ep->num];
50450 + doepdma = DWC_READ_REG32(&(out_regs->doepdma));
50451 + start = (doepdma - dwc_ep->dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t);
50452 + dma_desc = &(dwc_ep->desc_addr[start]);
50455 + dma_desc = dwc_ep->desc_addr;
50459 + for (i = start; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
50460 + sts.d32 = dma_desc->status.d32;
50461 + sts.b.bs = BS_HOST_READY;
50462 + dma_desc->status.d32 = sts.d32;
50465 + if (dwc_ep->is_in == 0) {
50467 + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->
50471 + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
50473 + depctl.b.epena = 1;
50474 + depctl.b.cnak = 1;
50475 + DWC_MODIFY_REG32(addr, 0, depctl.d32);
50479 + * This function handles EP0 Control transfers.
50481 + * The state of the control transfers are tracked in
50482 + * <code>ep0state</code>.
50484 +static void handle_ep0(dwc_otg_pcd_t * pcd)
50486 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50487 + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
50488 + dev_dma_desc_sts_t desc_sts;
50489 + deptsiz0_data_t deptsiz;
50490 + uint32_t byte_count;
50493 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
50494 + print_ep0_state(pcd);
50497 +// DWC_PRINTF("HANDLE EP0\n");
50499 + switch (pcd->ep0state) {
50500 + case EP0_DISCONNECT:
50504 + pcd->request_config = 0;
50509 + case EP0_IN_DATA_PHASE:
50511 + DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
50512 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
50513 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
50516 + if (core_if->dma_enable != 0) {
50518 + * For EP0 we can only program 1 packet at a time so we
50519 + * need to do the make calculations after each complete.
50520 + * Call write_packet to make the calculations, as in
50521 + * slave mode, and use those values to determine if we
50524 + if (core_if->dma_desc_enable == 0) {
50526 + DWC_READ_REG32(&core_if->
50527 + dev_if->in_ep_regs[0]->
50530 + ep0->dwc_ep.xfer_len - deptsiz.b.xfersize;
50533 + core_if->dev_if->in_desc_addr->status;
50535 + ep0->dwc_ep.xfer_len - desc_sts.b.bytes;
50537 + ep0->dwc_ep.xfer_count += byte_count;
50538 + ep0->dwc_ep.xfer_buff += byte_count;
50539 + ep0->dwc_ep.dma_addr += byte_count;
50541 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
50542 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50544 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
50545 + } else if (ep0->dwc_ep.sent_zlp) {
50546 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50548 + ep0->dwc_ep.sent_zlp = 0;
50549 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
50551 + ep0_complete_request(ep0);
50552 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
50555 + case EP0_OUT_DATA_PHASE:
50557 + DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
50558 + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
50559 + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
50561 + if (core_if->dma_enable != 0) {
50562 + if (core_if->dma_desc_enable == 0) {
50564 + DWC_READ_REG32(&core_if->
50565 + dev_if->out_ep_regs[0]->
50568 + ep0->dwc_ep.maxpacket - deptsiz.b.xfersize;
50571 + core_if->dev_if->out_desc_addr->status;
50573 + ep0->dwc_ep.maxpacket - desc_sts.b.bytes;
50575 + ep0->dwc_ep.xfer_count += byte_count;
50576 + ep0->dwc_ep.xfer_buff += byte_count;
50577 + ep0->dwc_ep.dma_addr += byte_count;
50579 + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
50580 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50582 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
50583 + } else if (ep0->dwc_ep.sent_zlp) {
50584 + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
50586 + ep0->dwc_ep.sent_zlp = 0;
50587 + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
50589 + ep0_complete_request(ep0);
50590 + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
50594 + case EP0_IN_STATUS_PHASE:
50595 + case EP0_OUT_STATUS_PHASE:
50596 + DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
50597 + ep0_complete_request(ep0);
50598 + pcd->ep0state = EP0_IDLE;
50599 + ep0->stopped = 1;
50600 + ep0->dwc_ep.is_in = 0; /* OUT for next SETUP */
50602 + /* Prepare for more SETUP Packets */
50603 + if (core_if->dma_enable) {
50604 + ep0_out_start(core_if, pcd);
50609 + DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
50613 + print_ep0_state(pcd);
50618 + * Restart transfer
50620 +static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum)
50622 + dwc_otg_core_if_t *core_if;
50623 + dwc_otg_dev_if_t *dev_if;
50624 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50625 + dwc_otg_pcd_ep_t *ep;
50627 + ep = get_in_ep(pcd, epnum);
50629 +#ifdef DWC_EN_ISOC
50630 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
50633 +#endif /* DWC_EN_ISOC */
50635 + core_if = GET_CORE_IF(pcd);
50636 + dev_if = core_if->dev_if;
50638 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
50640 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x"
50641 + " stopped=%d\n", ep->dwc_ep.xfer_buff,
50642 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped);
50644 + * If xfersize is 0 and pktcnt in not 0, resend the last packet.
50646 + if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
50647 + ep->dwc_ep.start_xfer_buff != 0) {
50648 + if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) {
50649 + ep->dwc_ep.xfer_count = 0;
50650 + ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
50651 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
50653 + ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
50654 + /* convert packet size to dwords. */
50655 + ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
50656 + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
50659 + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x "
50660 + "xfer_len=%0x stopped=%d\n",
50661 + ep->dwc_ep.xfer_buff,
50662 + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len,
50664 + if (epnum == 0) {
50665 + dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
50667 + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
50673 + * This function create new nextep sequnce based on Learn Queue.
50675 + * @param core_if Programming view of DWC_otg controller
50677 +void predict_nextep_seq( dwc_otg_core_if_t * core_if)
50679 + dwc_otg_device_global_regs_t *dev_global_regs =
50680 + core_if->dev_if->dev_global_regs;
50681 + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
50682 + /* Number of Token Queue Registers */
50683 + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
50684 + dtknq1_data_t dtknqr1;
50685 + uint32_t in_tkn_epnums[4];
50686 + uint8_t seqnum[MAX_EPS_CHANNELS];
50687 + uint8_t intkn_seq[TOKEN_Q_DEPTH];
50688 + grstctl_t resetctl = {.d32 = 0 };
50693 + int sort_done = 0;
50695 + volatile uint32_t *addr = &dev_global_regs->dtknqr1;
50698 + DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
50700 + /* Read the DTKNQ Registers */
50701 + for (i = 0; i < DTKNQ_REG_CNT; i++) {
50702 + in_tkn_epnums[i] = DWC_READ_REG32(addr);
50703 + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
50704 + in_tkn_epnums[i]);
50705 + if (addr == &dev_global_regs->dvbusdis) {
50706 + addr = &dev_global_regs->dtknqr3_dthrctl;
50713 + /* Copy the DTKNQR1 data to the bit field. */
50714 + dtknqr1.d32 = in_tkn_epnums[0];
50715 + if (dtknqr1.b.wrap_bit) {
50716 + ndx = dtknqr1.b.intknwptr;
50719 + end = TOKEN_Q_DEPTH -1;
50722 + end = dtknqr1.b.intknwptr -1;
50728 + /* Fill seqnum[] by initial values: EP number + 31 */
50729 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
50730 + seqnum[i] = i +31;
50733 + /* Fill intkn_seq[] from in_tkn_epnums[0] */
50734 + for (i=0; i < 6; i++)
50735 + intkn_seq[i] = (in_tkn_epnums[0] >> ((7-i) * 4)) & 0xf;
50737 + if (TOKEN_Q_DEPTH > 6) {
50738 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50739 + for (i=6; i < 14; i++)
50741 + (in_tkn_epnums[1] >> ((7 - (i - 6)) * 4)) & 0xf;
50744 + if (TOKEN_Q_DEPTH > 14) {
50745 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50746 + for (i=14; i < 22; i++)
50748 + (in_tkn_epnums[2] >> ((7 - (i - 14)) * 4)) & 0xf;
50751 + if (TOKEN_Q_DEPTH > 22) {
50752 + /* Fill intkn_seq[] from in_tkn_epnums[1] */
50753 + for (i=22; i < 30; i++)
50755 + (in_tkn_epnums[3] >> ((7 - (i - 22)) * 4)) & 0xf;
50758 + DWC_DEBUGPL(DBG_PCDV, "%s start=%d end=%d intkn_seq[]:\n", __func__,
50760 + for (i=0; i<TOKEN_Q_DEPTH; i++)
50761 + DWC_DEBUGPL(DBG_PCDV,"%d\n", intkn_seq[i]);
50763 + /* Update seqnum based on intkn_seq[] */
50766 + seqnum[intkn_seq[ndx]] = i;
50769 + if (ndx == TOKEN_Q_DEPTH)
50771 + } while ( i < TOKEN_Q_DEPTH );
50773 + /* Mark non active EP's in seqnum[] by 0xff */
50774 + for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
50775 + if (core_if->nextep_seq[i] == 0xff )
50776 + seqnum[i] = 0xff;
50779 + /* Sort seqnum[] */
50781 + while (!sort_done) {
50783 + for (i=0; i<core_if->dev_if->num_in_eps; i++) {
50784 + if (seqnum[i] > seqnum[i+1]) {
50785 + temp = seqnum[i];
50786 + seqnum[i] = seqnum[i+1];
50787 + seqnum[i+1] = temp;
50793 + ndx = start + seqnum[0];
50794 + if (ndx >= TOKEN_Q_DEPTH)
50795 + ndx = ndx % TOKEN_Q_DEPTH;
50796 + core_if->first_in_nextep_seq = intkn_seq[ndx];
50798 + /* Update seqnum[] by EP numbers */
50799 + for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
50801 + if (seqnum[i] < 31) {
50802 + ndx = start + seqnum[i];
50803 + if (ndx >= TOKEN_Q_DEPTH)
50804 + ndx = ndx % TOKEN_Q_DEPTH;
50805 + seqnum[i] = intkn_seq[ndx];
50807 + if (seqnum[i] < 0xff) {
50808 + seqnum[i] = seqnum[i] - 31;
50815 + /* Update nextep_seq[] based on seqnum[] */
50816 + for (i=0; i<core_if->dev_if->num_in_eps; i++) {
50817 + if (seqnum[i] != 0xff) {
50818 + if (seqnum[i+1] != 0xff) {
50819 + core_if->nextep_seq[seqnum[i]] = seqnum[i+1];
50821 + core_if->nextep_seq[seqnum[i]] = core_if->first_in_nextep_seq;
50829 + DWC_DEBUGPL(DBG_PCDV, "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
50830 + __func__, core_if->first_in_nextep_seq);
50831 + for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
50832 + DWC_DEBUGPL(DBG_PCDV,"%2d\n", core_if->nextep_seq[i]);
50835 + /* Flush the Learning Queue */
50836 + resetctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->grstctl);
50837 + resetctl.b.intknqflsh = 1;
50838 + DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
50844 + * handle the IN EP disable interrupt.
50846 +static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd,
50847 + const uint32_t epnum)
50849 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50850 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
50851 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50852 + dctl_data_t dctl = {.d32 = 0 };
50853 + dwc_otg_pcd_ep_t *ep;
50854 + dwc_ep_t *dwc_ep;
50855 + gintmsk_data_t gintmsk_data;
50856 + depctl_data_t depctl;
50857 + uint32_t diepdma;
50858 + uint32_t remain_to_transfer = 0;
50860 + uint32_t xfer_size;
50862 + ep = get_in_ep(pcd, epnum);
50863 + dwc_ep = &ep->dwc_ep;
50865 + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
50866 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
50871 + DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum,
50872 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl));
50873 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
50874 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
50876 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
50877 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
50879 + if ((core_if->start_predict == 0) || (depctl.b.eptype & 1)) {
50880 + if (ep->stopped) {
50881 + if (core_if->en_multiple_tx_fifo)
50882 + /* Flush the Tx FIFO */
50883 + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
50884 + /* Clear the Global IN NP NAK */
50886 + dctl.b.cgnpinnak = 1;
50887 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
50888 + /* Restart the transaction */
50889 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
50890 + restart_transfer(pcd, epnum);
50893 + /* Restart the transaction */
50894 + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
50895 + restart_transfer(pcd, epnum);
50897 + DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
50902 + if (core_if->start_predict > 2) { // NP IN EP
50903 + core_if->start_predict--;
50907 + core_if->start_predict--;
50909 + if (core_if->start_predict == 1) { // All NP IN Ep's disabled now
50911 + predict_nextep_seq(core_if);
50913 + /* Update all active IN EP's NextEP field based of nextep_seq[] */
50914 + for ( i = 0; i <= core_if->dev_if->num_in_eps; i++) {
50916 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50917 + if (core_if->nextep_seq[i] != 0xff) { // Active NP IN EP
50918 + depctl.b.nextep = core_if->nextep_seq[i];
50919 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
50922 + /* Flush Shared NP TxFIFO */
50923 + dwc_otg_flush_tx_fifo(core_if, 0);
50924 + /* Rewind buffers */
50925 + if (!core_if->dma_desc_enable) {
50926 + i = core_if->first_in_nextep_seq;
50928 + ep = get_in_ep(pcd, i);
50929 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
50930 + xfer_size = ep->dwc_ep.total_len - ep->dwc_ep.xfer_count;
50931 + if (xfer_size > ep->dwc_ep.maxxfer)
50932 + xfer_size = ep->dwc_ep.maxxfer;
50933 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50934 + if (dieptsiz.b.pktcnt != 0) {
50935 + if (xfer_size == 0) {
50936 + remain_to_transfer = 0;
50938 + if ((xfer_size % ep->dwc_ep.maxpacket) == 0) {
50939 + remain_to_transfer =
50940 + dieptsiz.b.pktcnt * ep->dwc_ep.maxpacket;
50942 + remain_to_transfer = ((dieptsiz.b.pktcnt -1) * ep->dwc_ep.maxpacket)
50943 + + (xfer_size % ep->dwc_ep.maxpacket);
50946 + diepdma = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepdma);
50947 + dieptsiz.b.xfersize = remain_to_transfer;
50948 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, dieptsiz.d32);
50949 + diepdma = ep->dwc_ep.dma_addr + (xfer_size - remain_to_transfer);
50950 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, diepdma);
50952 + i = core_if->nextep_seq[i];
50953 + } while (i != core_if->first_in_nextep_seq);
50954 + } else { // dma_desc_enable
50955 + DWC_PRINTF("%s Learning Queue not supported in DDMA\n", __func__);
50958 + /* Restart transfers in predicted sequences */
50959 + i = core_if->first_in_nextep_seq;
50961 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
50962 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50963 + if (dieptsiz.b.pktcnt != 0) {
50964 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
50965 + depctl.b.epena = 1;
50966 + depctl.b.cnak = 1;
50967 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
50969 + i = core_if->nextep_seq[i];
50970 + } while (i != core_if->first_in_nextep_seq);
50972 + /* Clear the global non-periodic IN NAK handshake */
50974 + dctl.b.cgnpinnak = 1;
50975 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
50977 + /* Unmask EP Mismatch interrupt */
50978 + gintmsk_data.d32 = 0;
50979 + gintmsk_data.b.epmismatch = 1;
50980 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk_data.d32);
50982 + core_if->start_predict = 0;
50988 + * Handler for the IN EP timeout handshake interrupt.
50990 +static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd,
50991 + const uint32_t epnum)
50993 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
50994 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
50997 + deptsiz_data_t dieptsiz = {.d32 = 0 };
50998 + uint32_t num = 0;
51000 + dctl_data_t dctl = {.d32 = 0 };
51001 + dwc_otg_pcd_ep_t *ep;
51003 + gintmsk_data_t intr_mask = {.d32 = 0 };
51005 + ep = get_in_ep(pcd, epnum);
51007 + /* Disable the NP Tx Fifo Empty Interrrupt */
51008 + if (!core_if->dma_enable) {
51009 + intr_mask.b.nptxfempty = 1;
51010 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
51011 + intr_mask.d32, 0);
51013 + /** @todo NGS Check EP type.
51014 + * Implement for Periodic EPs */
51016 + * Non-periodic EP
51018 + /* Enable the Global IN NAK Effective Interrupt */
51019 + intr_mask.b.ginnakeff = 1;
51020 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
51022 + /* Set Global IN NAK */
51023 + dctl.b.sgnpinnak = 1;
51024 + DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
51029 + dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[num]->dieptsiz);
51030 + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
51031 + dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
51034 +#ifdef DISABLE_PERIODIC_EP
51036 + * Set the NAK bit for this EP to
51037 + * start the disable process.
51040 + diepctl.b.snak = 1;
51041 + DWC_MODIFY_REG32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32,
51043 + ep->disabling = 1;
51049 + * Handler for the IN EP NAK interrupt.
51051 +static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd,
51052 + const uint32_t epnum)
51054 + /** @todo implement ISR */
51055 + dwc_otg_core_if_t *core_if;
51056 + diepmsk_data_t intr_mask = {.d32 = 0 };
51058 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK");
51059 + core_if = GET_CORE_IF(pcd);
51060 + intr_mask.b.nak = 1;
51062 + if (core_if->multiproc_int_enable) {
51063 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51064 + diepeachintmsk[epnum], intr_mask.d32, 0);
51066 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->diepmsk,
51067 + intr_mask.d32, 0);
51074 + * Handler for the OUT EP Babble interrupt.
51076 +static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd,
51077 + const uint32_t epnum)
51079 + /** @todo implement ISR */
51080 + dwc_otg_core_if_t *core_if;
51081 + doepmsk_data_t intr_mask = {.d32 = 0 };
51083 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
51084 + "OUT EP Babble");
51085 + core_if = GET_CORE_IF(pcd);
51086 + intr_mask.b.babble = 1;
51088 + if (core_if->multiproc_int_enable) {
51089 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51090 + doepeachintmsk[epnum], intr_mask.d32, 0);
51092 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51093 + intr_mask.d32, 0);
51100 + * Handler for the OUT EP NAK interrupt.
51102 +static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd,
51103 + const uint32_t epnum)
51105 + /** @todo implement ISR */
51106 + dwc_otg_core_if_t *core_if;
51107 + doepmsk_data_t intr_mask = {.d32 = 0 };
51109 + DWC_DEBUGPL(DBG_ANY, "INTERRUPT Handler not implemented for %s\n", "OUT EP NAK");
51110 + core_if = GET_CORE_IF(pcd);
51111 + intr_mask.b.nak = 1;
51113 + if (core_if->multiproc_int_enable) {
51114 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51115 + doepeachintmsk[epnum], intr_mask.d32, 0);
51117 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51118 + intr_mask.d32, 0);
51125 + * Handler for the OUT EP NYET interrupt.
51127 +static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd,
51128 + const uint32_t epnum)
51130 + /** @todo implement ISR */
51131 + dwc_otg_core_if_t *core_if;
51132 + doepmsk_data_t intr_mask = {.d32 = 0 };
51134 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET");
51135 + core_if = GET_CORE_IF(pcd);
51136 + intr_mask.b.nyet = 1;
51138 + if (core_if->multiproc_int_enable) {
51139 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
51140 + doepeachintmsk[epnum], intr_mask.d32, 0);
51142 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51143 + intr_mask.d32, 0);
51150 + * This interrupt indicates that an IN EP has a pending Interrupt.
51151 + * The sequence for handling the IN EP interrupt is shown below:
51152 + * -# Read the Device All Endpoint Interrupt register
51153 + * -# Repeat the following for each IN EP interrupt bit set (from
51155 + * -# Read the Device Endpoint Interrupt (DIEPINTn) register
51156 + * -# If "Transfer Complete" call the request complete function
51157 + * -# If "Endpoint Disabled" complete the EP disable procedure.
51158 + * -# If "AHB Error Interrupt" log error
51159 + * -# If "Time-out Handshake" log error
51160 + * -# If "IN Token Received when TxFIFO Empty" write packet to Tx
51162 + * -# If "IN Token EP Mismatch" (disable, this is handled by EP
51163 + * Mismatch Interrupt)
51165 +static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd)
51167 +#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
51169 + diepint_data_t diepint = {.d32=0}; \
51170 + diepint.b.__intr = 1; \
51171 + DWC_WRITE_REG32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
51175 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
51176 + dwc_otg_dev_if_t *dev_if = core_if->dev_if;
51177 + diepint_data_t diepint = {.d32 = 0 };
51178 + depctl_data_t depctl = {.d32 = 0 };
51179 + uint32_t ep_intr;
51180 + uint32_t epnum = 0;
51181 + dwc_otg_pcd_ep_t *ep;
51182 + dwc_ep_t *dwc_ep;
51183 + gintmsk_data_t intr_mask = {.d32 = 0 };
51185 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd);
51187 + /* Read in the device interrupt bits */
51188 + ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if);
51190 + /* Service the Device IN interrupts for each endpoint */
51191 + while (ep_intr) {
51192 + if (ep_intr & 0x1) {
51193 + uint32_t empty_msk;
51194 + /* Get EP pointer */
51195 + ep = get_in_ep(pcd, epnum);
51196 + dwc_ep = &ep->dwc_ep;
51199 + DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
51201 + DWC_READ_REG32(&dev_if->
51202 + dev_global_regs->dtknqr4_fifoemptymsk);
51204 + DWC_DEBUGPL(DBG_PCDV,
51205 + "IN EP INTERRUPT - %d\nepmty_msk - %8x diepctl - %8x\n",
51206 + epnum, empty_msk, depctl.d32);
51208 + DWC_DEBUGPL(DBG_PCD,
51209 + "EP%d-%s: type=%d, mps=%d\n",
51210 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
51211 + dwc_ep->type, dwc_ep->maxpacket);
51214 + dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep);
51216 + DWC_DEBUGPL(DBG_PCDV,
51217 + "EP %d Interrupt Register - 0x%x\n", epnum,
51219 + /* Transfer complete */
51220 + if (diepint.b.xfercompl) {
51221 + /* Disable the NP Tx FIFO Empty
51223 + if (core_if->en_multiple_tx_fifo == 0) {
51224 + intr_mask.b.nptxfempty = 1;
51226 + (&core_if->core_global_regs->gintmsk,
51227 + intr_mask.d32, 0);
51229 + /* Disable the Tx FIFO Empty Interrupt for this EP */
51230 + uint32_t fifoemptymsk =
51231 + 0x1 << dwc_ep->num;
51232 + DWC_MODIFY_REG32(&core_if->
51233 + dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
51234 + fifoemptymsk, 0);
51236 + /* Clear the bit in DIEPINTn for this interrupt */
51237 + CLEAR_IN_EP_INTR(core_if, epnum, xfercompl);
51239 + /* Complete the transfer */
51240 + if (epnum == 0) {
51243 +#ifdef DWC_EN_ISOC
51244 + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51245 + if (!ep->stopped)
51246 + complete_iso_ep(pcd, ep);
51248 +#endif /* DWC_EN_ISOC */
51249 +#ifdef DWC_UTE_PER_IO
51250 + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51251 + if (!ep->stopped)
51252 + complete_xiso_ep(ep);
51254 +#endif /* DWC_UTE_PER_IO */
51256 + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC &&
51257 + dwc_ep->bInterval > 1) {
51258 + dwc_ep->frame_num += dwc_ep->bInterval;
51259 + if (dwc_ep->frame_num > 0x3FFF)
51261 + dwc_ep->frm_overrun = 1;
51262 + dwc_ep->frame_num &= 0x3FFF;
51264 + dwc_ep->frm_overrun = 0;
51267 + if(diepint.b.nak)
51268 + CLEAR_IN_EP_INTR(core_if, epnum, nak);
51271 + /* Endpoint disable */
51272 + if (diepint.b.epdisabled) {
51273 + DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n",
51275 + handle_in_ep_disable_intr(pcd, epnum);
51277 + /* Clear the bit in DIEPINTn for this interrupt */
51278 + CLEAR_IN_EP_INTR(core_if, epnum, epdisabled);
51281 + if (diepint.b.ahberr) {
51282 + DWC_ERROR("EP%d IN AHB Error\n", epnum);
51283 + /* Clear the bit in DIEPINTn for this interrupt */
51284 + CLEAR_IN_EP_INTR(core_if, epnum, ahberr);
51286 + /* TimeOUT Handshake (non-ISOC IN EPs) */
51287 + if (diepint.b.timeout) {
51288 + DWC_ERROR("EP%d IN Time-out\n", epnum);
51289 + handle_in_ep_timeout_intr(pcd, epnum);
51291 + CLEAR_IN_EP_INTR(core_if, epnum, timeout);
51293 + /** IN Token received with TxF Empty */
51294 + if (diepint.b.intktxfemp) {
51295 + DWC_DEBUGPL(DBG_ANY,
51296 + "EP%d IN TKN TxFifo Empty\n",
51298 + if (!ep->stopped && epnum != 0) {
51300 + diepmsk_data_t diepmsk = {.d32 = 0 };
51301 + diepmsk.b.intktxfemp = 1;
51303 + if (core_if->multiproc_int_enable) {
51305 + (&dev_if->dev_global_regs->diepeachintmsk
51306 + [epnum], diepmsk.d32, 0);
51309 + (&dev_if->dev_global_regs->diepmsk,
51312 + } else if (core_if->dma_desc_enable
51314 + && pcd->ep0state ==
51315 + EP0_OUT_STATUS_PHASE) {
51316 + // EP0 IN set STALL
51318 + DWC_READ_REG32(&dev_if->in_ep_regs
51319 + [epnum]->diepctl);
51321 + /* set the disable and stall bits */
51322 + if (depctl.b.epena) {
51323 + depctl.b.epdis = 1;
51325 + depctl.b.stall = 1;
51326 + DWC_WRITE_REG32(&dev_if->in_ep_regs
51327 + [epnum]->diepctl,
51330 + CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp);
51332 + /** IN Token Received with EP mismatch */
51333 + if (diepint.b.intknepmis) {
51334 + DWC_DEBUGPL(DBG_ANY,
51335 + "EP%d IN TKN EP Mismatch\n", epnum);
51336 + CLEAR_IN_EP_INTR(core_if, epnum, intknepmis);
51338 + /** IN Endpoint NAK Effective */
51339 + if (diepint.b.inepnakeff) {
51340 + DWC_DEBUGPL(DBG_ANY,
51341 + "EP%d IN EP NAK Effective\n",
51343 + /* Periodic EP */
51344 + if (ep->disabling) {
51346 + depctl.b.snak = 1;
51347 + depctl.b.epdis = 1;
51348 + DWC_MODIFY_REG32(&dev_if->in_ep_regs
51349 + [epnum]->diepctl,
51353 + CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff);
51357 + /** IN EP Tx FIFO Empty Intr */
51358 + if (diepint.b.emptyintr) {
51359 + DWC_DEBUGPL(DBG_ANY,
51360 + "EP%d Tx FIFO Empty Intr \n",
51362 + write_empty_tx_fifo(pcd, epnum);
51364 + CLEAR_IN_EP_INTR(core_if, epnum, emptyintr);
51368 + /** IN EP BNA Intr */
51369 + if (diepint.b.bna) {
51370 + CLEAR_IN_EP_INTR(core_if, epnum, bna);
51371 + if (core_if->dma_desc_enable) {
51372 +#ifdef DWC_EN_ISOC
51373 + if (dwc_ep->type ==
51374 + DWC_OTG_EP_TYPE_ISOC) {
51376 + * This checking is performed to prevent first "false" BNA
51377 + * handling occuring right after reconnect
51379 + if (dwc_ep->next_frame !=
51381 + dwc_otg_pcd_handle_iso_bna(ep);
51383 +#endif /* DWC_EN_ISOC */
51385 + dwc_otg_pcd_handle_noniso_bna(ep);
51389 + /* NAK Interrutp */
51390 + if (diepint.b.nak) {
51391 + DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n",
51393 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
51394 + depctl_data_t depctl;
51395 + if (ep->dwc_ep.frame_num == 0xFFFFFFFF) {
51396 + ep->dwc_ep.frame_num = core_if->frame_num;
51397 + if (ep->dwc_ep.bInterval > 1) {
51399 + depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
51400 + if (ep->dwc_ep.frame_num & 0x1) {
51401 + depctl.b.setd1pid = 1;
51402 + depctl.b.setd0pid = 0;
51404 + depctl.b.setd0pid = 1;
51405 + depctl.b.setd1pid = 0;
51407 + DWC_WRITE_REG32(&dev_if->in_ep_regs[epnum]->diepctl, depctl.d32);
51409 + start_next_request(ep);
51411 + ep->dwc_ep.frame_num += ep->dwc_ep.bInterval;
51412 + if (dwc_ep->frame_num > 0x3FFF) {
51413 + dwc_ep->frm_overrun = 1;
51414 + dwc_ep->frame_num &= 0x3FFF;
51416 + dwc_ep->frm_overrun = 0;
51419 + CLEAR_IN_EP_INTR(core_if, epnum, nak);
51427 +#undef CLEAR_IN_EP_INTR
51431 + * This interrupt indicates that an OUT EP has a pending Interrupt.
51432 + * The sequence for handling the OUT EP interrupt is shown below:
51433 + * -# Read the Device All Endpoint Interrupt register
51434 + * -# Repeat the following for each OUT EP interrupt bit set (from
51436 + * -# Read the Device Endpoint Interrupt (DOEPINTn) register
51437 + * -# If "Transfer Complete" call the request complete function
51438 + * -# If "Endpoint Disabled" complete the EP disable procedure.
51439 + * -# If "AHB Error Interrupt" log error
51440 + * -# If "Setup Phase Done" process Setup Packet (See Standard USB
51441 + * Command Processing)
51443 +static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd)
51445 +#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
51447 + doepint_data_t doepint = {.d32=0}; \
51448 + doepint.b.__intr = 1; \
51449 + DWC_WRITE_REG32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
51453 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
51454 + uint32_t ep_intr;
51455 + doepint_data_t doepint = {.d32 = 0 };
51456 + uint32_t epnum = 0;
51457 + dwc_otg_pcd_ep_t *ep;
51458 + dwc_ep_t *dwc_ep;
51459 + dctl_data_t dctl = {.d32 = 0 };
51460 + gintmsk_data_t gintmsk = {.d32 = 0 };
51463 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
51465 + /* Read in the device interrupt bits */
51466 + ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if);
51468 + while (ep_intr) {
51469 + if (ep_intr & 0x1) {
51470 + /* Get EP pointer */
51471 + ep = get_out_ep(pcd, epnum);
51472 + dwc_ep = &ep->dwc_ep;
51475 + DWC_DEBUGPL(DBG_PCDV,
51476 + "EP%d-%s: type=%d, mps=%d\n",
51477 + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
51478 + dwc_ep->type, dwc_ep->maxpacket);
51481 + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
51482 + /* Moved this interrupt upper due to core deffect of asserting
51483 + * OUT EP 0 xfercompl along with stsphsrcvd in BDMA */
51484 + if (doepint.b.stsphsercvd) {
51485 + deptsiz0_data_t deptsiz;
51486 + CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd);
51488 + DWC_READ_REG32(&core_if->dev_if->
51489 + out_ep_regs[0]->doeptsiz);
51490 + if (core_if->snpsid >= OTG_CORE_REV_3_00a
51491 + && core_if->dma_enable
51492 + && core_if->dma_desc_enable == 0
51493 + && doepint.b.xfercompl
51494 + && deptsiz.b.xfersize == 24) {
51495 + CLEAR_OUT_EP_INTR(core_if, epnum,
51497 + doepint.b.xfercompl = 0;
51498 + ep0_out_start(core_if, pcd);
51500 + if ((core_if->dma_desc_enable) ||
51501 + (core_if->dma_enable
51502 + && core_if->snpsid >=
51503 + OTG_CORE_REV_3_00a)) {
51504 + do_setup_in_status_phase(pcd);
51507 + /* Transfer complete */
51508 + if (doepint.b.xfercompl) {
51510 + if (epnum == 0) {
51511 + /* Clear the bit in DOEPINTn for this interrupt */
51512 + CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
51513 + if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
51514 + DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
51515 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepint),
51517 + DWC_DEBUGPL(DBG_PCDV, "DOEPCTL=%x \n",
51518 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepctl));
51520 + if (core_if->snpsid >= OTG_CORE_REV_3_00a
51521 + && core_if->dma_enable == 0) {
51522 + doepint_data_t doepint;
51523 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51524 + out_ep_regs[0]->doepint);
51525 + if (pcd->ep0state == EP0_IDLE && doepint.b.sr) {
51526 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51527 + goto exit_xfercompl;
51530 + /* In case of DDMA look at SR bit to go to the Data Stage */
51531 + if (core_if->dma_desc_enable) {
51532 + dev_dma_desc_sts_t status = {.d32 = 0};
51533 + if (pcd->ep0state == EP0_IDLE) {
51534 + status.d32 = core_if->dev_if->setup_desc_addr[core_if->
51535 + dev_if->setup_desc_index]->status.d32;
51536 + if(pcd->data_terminated) {
51537 + pcd->data_terminated = 0;
51538 + status.d32 = core_if->dev_if->out_desc_addr->status.d32;
51539 + dwc_memcpy(&pcd->setup_pkt->req, pcd->backup_buf, 8);
51541 + if (status.b.sr) {
51542 + if (doepint.b.setup) {
51543 + DWC_DEBUGPL(DBG_PCDV, "DMA DESC EP0_IDLE SR=1 setup=1\n");
51544 + /* Already started data stage, clear setup */
51545 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51546 + doepint.b.setup = 0;
51548 + /* Prepare for more setup packets */
51549 + if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
51550 + pcd->ep0state == EP0_IN_DATA_PHASE) {
51551 + ep0_out_start(core_if, pcd);
51554 + goto exit_xfercompl;
51556 + /* Prepare for more setup packets */
51557 + DWC_DEBUGPL(DBG_PCDV,
51558 + "EP0_IDLE SR=1 setup=0 new setup comes\n");
51559 + ep0_out_start(core_if, pcd);
51563 + dwc_otg_pcd_request_t *req;
51564 + dev_dma_desc_sts_t status = {.d32 = 0};
51565 + diepint_data_t diepint0;
51566 + diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
51567 + in_ep_regs[0]->diepint);
51569 + if (pcd->ep0state == EP0_STALL || pcd->ep0state == EP0_DISCONNECT) {
51570 + DWC_ERROR("EP0 is stalled/disconnected\n");
51573 + /* Clear IN xfercompl if set */
51574 + if (diepint0.b.xfercompl && (pcd->ep0state == EP0_IN_STATUS_PHASE
51575 + || pcd->ep0state == EP0_IN_DATA_PHASE)) {
51576 + DWC_WRITE_REG32(&core_if->dev_if->
51577 + in_ep_regs[0]->diepint, diepint0.d32);
51580 + status.d32 = core_if->dev_if->setup_desc_addr[core_if->
51581 + dev_if->setup_desc_index]->status.d32;
51583 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len
51584 + && (pcd->ep0state == EP0_OUT_DATA_PHASE))
51585 + status.d32 = core_if->dev_if->out_desc_addr->status.d32;
51586 + if (pcd->ep0state == EP0_OUT_STATUS_PHASE)
51587 + status.d32 = status.d32 = core_if->dev_if->
51588 + out_desc_addr->status.d32;
51590 + if (status.b.sr) {
51591 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51592 + DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
51594 + DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
51595 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51596 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
51597 + pcd->ep0state == EP0_OUT_DATA_PHASE) {
51598 + /* Read arrived setup packet from req->buf */
51599 + dwc_memcpy(&pcd->setup_pkt->req,
51600 + req->buf + ep->dwc_ep.xfer_count, 8);
51602 + req->actual = ep->dwc_ep.xfer_count;
51603 + dwc_otg_request_done(ep, req, -ECONNRESET);
51604 + ep->dwc_ep.start_xfer_buff = 0;
51605 + ep->dwc_ep.xfer_buff = 0;
51606 + ep->dwc_ep.xfer_len = 0;
51608 + pcd->ep0state = EP0_IDLE;
51609 + if (doepint.b.setup) {
51610 + DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
51611 + /* Data stage started, clear setup */
51612 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51613 + doepint.b.setup = 0;
51615 + /* Prepare for setup packets if ep0in was enabled*/
51616 + if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
51617 + ep0_out_start(core_if, pcd);
51620 + goto exit_xfercompl;
51622 + /* Prepare for more setup packets */
51623 + DWC_DEBUGPL(DBG_PCDV,
51624 + "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
51625 + ep0_out_start(core_if, pcd);
51630 + if (core_if->snpsid >= OTG_CORE_REV_2_94a && core_if->dma_enable
51631 + && core_if->dma_desc_enable == 0) {
51632 + doepint_data_t doepint_temp = {.d32 = 0};
51633 + deptsiz0_data_t doeptsize0 = {.d32 = 0 };
51634 + doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
51635 + out_ep_regs[ep->dwc_ep.num]->doepint);
51636 + doeptsize0.d32 = DWC_READ_REG32(&core_if->dev_if->
51637 + out_ep_regs[ep->dwc_ep.num]->doeptsiz);
51638 + if (pcd->ep0state == EP0_IDLE) {
51639 + if (doepint_temp.b.sr) {
51640 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51642 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51643 + out_ep_regs[0]->doepint);
51644 + if (doeptsize0.b.supcnt == 3) {
51645 + DWC_DEBUGPL(DBG_ANY, "Rolling over!!!!!!!\n");
51646 + ep->dwc_ep.stp_rollover = 1;
51648 + if (doepint.b.setup) {
51650 + /* Already started data stage, clear setup */
51651 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51652 + doepint.b.setup = 0;
51654 + ep->dwc_ep.stp_rollover = 0;
51655 + /* Prepare for more setup packets */
51656 + if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
51657 + pcd->ep0state == EP0_IN_DATA_PHASE) {
51658 + ep0_out_start(core_if, pcd);
51660 + goto exit_xfercompl;
51662 + /* Prepare for more setup packets */
51663 + DWC_DEBUGPL(DBG_ANY,
51664 + "EP0_IDLE SR=1 setup=0 new setup comes\n");
51665 + doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51666 + out_ep_regs[0]->doepint);
51667 + if(doepint.b.setup)
51669 + ep0_out_start(core_if, pcd);
51672 + dwc_otg_pcd_request_t *req;
51673 + diepint_data_t diepint0 = {.d32 = 0};
51674 + doepint_data_t doepint_temp = {.d32 = 0};
51675 + depctl_data_t diepctl0;
51676 + diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
51677 + in_ep_regs[0]->diepint);
51678 + diepctl0.d32 = DWC_READ_REG32(&core_if->dev_if->
51679 + in_ep_regs[0]->diepctl);
51681 + if (pcd->ep0state == EP0_IN_DATA_PHASE
51682 + || pcd->ep0state == EP0_IN_STATUS_PHASE) {
51683 + if (diepint0.b.xfercompl) {
51684 + DWC_WRITE_REG32(&core_if->dev_if->
51685 + in_ep_regs[0]->diepint, diepint0.d32);
51687 + if (diepctl0.b.epena) {
51688 + diepint_data_t diepint = {.d32 = 0};
51689 + diepctl0.b.snak = 1;
51690 + DWC_WRITE_REG32(&core_if->dev_if->
51691 + in_ep_regs[0]->diepctl, diepctl0.d32);
51694 + diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51695 + in_ep_regs[0]->diepint);
51696 + } while (!diepint.b.inepnakeff);
51697 + diepint.b.inepnakeff = 1;
51698 + DWC_WRITE_REG32(&core_if->dev_if->
51699 + in_ep_regs[0]->diepint, diepint.d32);
51700 + diepctl0.d32 = 0;
51701 + diepctl0.b.epdis = 1;
51702 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl,
51706 + diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
51707 + in_ep_regs[0]->diepint);
51708 + } while (!diepint.b.epdisabled);
51709 + diepint.b.epdisabled = 1;
51710 + DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepint,
51714 + doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
51715 + out_ep_regs[ep->dwc_ep.num]->doepint);
51716 + if (doepint_temp.b.sr) {
51717 + CLEAR_OUT_EP_INTR(core_if, epnum, sr);
51718 + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51719 + DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
51721 + DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
51722 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51723 + if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
51724 + pcd->ep0state == EP0_OUT_DATA_PHASE) {
51725 + /* Read arrived setup packet from req->buf */
51726 + dwc_memcpy(&pcd->setup_pkt->req,
51727 + req->buf + ep->dwc_ep.xfer_count, 8);
51729 + req->actual = ep->dwc_ep.xfer_count;
51730 + dwc_otg_request_done(ep, req, -ECONNRESET);
51731 + ep->dwc_ep.start_xfer_buff = 0;
51732 + ep->dwc_ep.xfer_buff = 0;
51733 + ep->dwc_ep.xfer_len = 0;
51735 + pcd->ep0state = EP0_IDLE;
51736 + if (doepint.b.setup) {
51737 + DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
51738 + /* Data stage started, clear setup */
51739 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51740 + doepint.b.setup = 0;
51742 + /* Prepare for setup packets if ep0in was enabled*/
51743 + if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
51744 + ep0_out_start(core_if, pcd);
51746 + goto exit_xfercompl;
51748 + /* Prepare for more setup packets */
51749 + DWC_DEBUGPL(DBG_PCDV,
51750 + "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
51751 + ep0_out_start(core_if, pcd);
51756 + if (core_if->dma_enable == 0 || pcd->ep0state != EP0_IDLE)
51759 + DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
51760 + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep), doepint.d32);
51762 + if (core_if->dma_desc_enable == 0
51763 + || pcd->ep0state != EP0_IDLE)
51766 +#ifdef DWC_EN_ISOC
51767 + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51768 + if (doepint.b.pktdrpsts == 0) {
51769 + /* Clear the bit in DOEPINTn for this interrupt */
51770 + CLEAR_OUT_EP_INTR(core_if,
51773 + complete_iso_ep(pcd, ep);
51776 + doepint_data_t doepint = {.d32 = 0 };
51777 + doepint.b.xfercompl = 1;
51778 + doepint.b.pktdrpsts = 1;
51780 + (&core_if->dev_if->out_ep_regs
51781 + [epnum]->doepint,
51783 + if (handle_iso_out_pkt_dropped
51784 + (core_if, dwc_ep)) {
51785 + complete_iso_ep(pcd,
51789 +#endif /* DWC_EN_ISOC */
51790 +#ifdef DWC_UTE_PER_IO
51791 + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
51792 + CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
51793 + if (!ep->stopped)
51794 + complete_xiso_ep(ep);
51795 +#endif /* DWC_UTE_PER_IO */
51797 + /* Clear the bit in DOEPINTn for this interrupt */
51798 + CLEAR_OUT_EP_INTR(core_if, epnum,
51801 + if (core_if->core_params->dev_out_nak) {
51802 + DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[epnum]);
51803 + pcd->core_if->ep_xfer_info[epnum].state = 0;
51805 + print_memory_payload(pcd, dwc_ep);
51813 + /* Endpoint disable */
51814 + if (doepint.b.epdisabled) {
51816 + /* Clear the bit in DOEPINTn for this interrupt */
51817 + CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled);
51818 + if (core_if->core_params->dev_out_nak) {
51820 + print_memory_payload(pcd, dwc_ep);
51822 + /* In case of timeout condition */
51823 + if (core_if->ep_xfer_info[epnum].state == 2) {
51824 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51825 + dev_global_regs->dctl);
51826 + dctl.b.cgoutnak = 1;
51827 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
51829 + /* Unmask goutnakeff interrupt which was masked
51830 + * during handle nak out interrupt */
51831 + gintmsk.b.goutnakeff = 1;
51832 + DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
51838 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
51840 + dctl_data_t dctl;
51841 + gintmsk_data_t intr_mask = {.d32 = 0};
51842 + dwc_otg_pcd_request_t *req = 0;
51844 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51845 + dev_global_regs->dctl);
51846 + dctl.b.cgoutnak = 1;
51847 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
51850 + intr_mask.d32 = 0;
51851 + intr_mask.b.incomplisoout = 1;
51853 + /* Get any pending requests */
51854 + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
51855 + req = DWC_CIRCLEQ_FIRST(&ep->queue);
51857 + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
51859 + dwc_otg_request_done(ep, req, 0);
51860 + start_next_request(ep);
51863 + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
51868 + if (doepint.b.ahberr) {
51869 + DWC_ERROR("EP%d OUT AHB Error\n", epnum);
51870 + DWC_ERROR("EP%d DEPDMA=0x%08x \n",
51871 + epnum, core_if->dev_if->out_ep_regs[epnum]->doepdma);
51872 + CLEAR_OUT_EP_INTR(core_if, epnum, ahberr);
51874 + /* Setup Phase Done (contorl EPs) */
51875 + if (doepint.b.setup) {
51877 + DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n", epnum);
51879 + CLEAR_OUT_EP_INTR(core_if, epnum, setup);
51884 + /** OUT EP BNA Intr */
51885 + if (doepint.b.bna) {
51886 + CLEAR_OUT_EP_INTR(core_if, epnum, bna);
51887 + if (core_if->dma_desc_enable) {
51888 +#ifdef DWC_EN_ISOC
51889 + if (dwc_ep->type ==
51890 + DWC_OTG_EP_TYPE_ISOC) {
51892 + * This checking is performed to prevent first "false" BNA
51893 + * handling occuring right after reconnect
51895 + if (dwc_ep->next_frame !=
51897 + dwc_otg_pcd_handle_iso_bna(ep);
51899 +#endif /* DWC_EN_ISOC */
51901 + dwc_otg_pcd_handle_noniso_bna(ep);
51905 + /* Babble Interrupt */
51906 + if (doepint.b.babble) {
51907 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n",
51909 + handle_out_ep_babble_intr(pcd, epnum);
51911 + CLEAR_OUT_EP_INTR(core_if, epnum, babble);
51913 + if (doepint.b.outtknepdis) {
51914 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Token received when EP is \
51915 + disabled\n",epnum);
51916 + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
51917 + doepmsk_data_t doepmsk = {.d32 = 0};
51918 + ep->dwc_ep.frame_num = core_if->frame_num;
51919 + if (ep->dwc_ep.bInterval > 1) {
51920 + depctl_data_t depctl;
51921 + depctl.d32 = DWC_READ_REG32(&core_if->dev_if->
51922 + out_ep_regs[epnum]->doepctl);
51923 + if (ep->dwc_ep.frame_num & 0x1) {
51924 + depctl.b.setd1pid = 1;
51925 + depctl.b.setd0pid = 0;
51927 + depctl.b.setd0pid = 1;
51928 + depctl.b.setd1pid = 0;
51930 + DWC_WRITE_REG32(&core_if->dev_if->
51931 + out_ep_regs[epnum]->doepctl, depctl.d32);
51933 + start_next_request(ep);
51934 + doepmsk.b.outtknepdis = 1;
51935 + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
51938 + CLEAR_OUT_EP_INTR(core_if, epnum, outtknepdis);
51941 + /* NAK Interrutp */
51942 + if (doepint.b.nak) {
51943 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum);
51944 + handle_out_ep_nak_intr(pcd, epnum);
51946 + CLEAR_OUT_EP_INTR(core_if, epnum, nak);
51948 + /* NYET Interrutp */
51949 + if (doepint.b.nyet) {
51950 + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum);
51951 + handle_out_ep_nyet_intr(pcd, epnum);
51953 + CLEAR_OUT_EP_INTR(core_if, epnum, nyet);
51963 +#undef CLEAR_OUT_EP_INTR
51965 +static int drop_transfer(uint32_t trgt_fr, uint32_t curr_fr, uint8_t frm_overrun)
51968 + if(!frm_overrun && curr_fr >= trgt_fr)
51970 + else if (frm_overrun
51971 + && (curr_fr >= trgt_fr && ((curr_fr - trgt_fr) < 0x3FFF / 2)))
51976 + * Incomplete ISO IN Transfer Interrupt.
51977 + * This interrupt indicates one of the following conditions occurred
51978 + * while transmitting an ISOC transaction.
51979 + * - Corrupted IN Token for ISOC EP.
51980 + * - Packet not complete in FIFO.
51981 + * The follow actions will be taken:
51982 + * -# Determine the EP
51983 + * -# Set incomplete flag in dwc_ep structure
51984 + * -# Disable EP; when "Endpoint Disabled" interrupt is received
51987 +int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd)
51989 + gintsts_data_t gintsts;
51991 +#ifdef DWC_EN_ISOC
51992 + dwc_otg_dev_if_t *dev_if;
51993 + deptsiz_data_t deptsiz = {.d32 = 0 };
51994 + depctl_data_t depctl = {.d32 = 0 };
51995 + dsts_data_t dsts = {.d32 = 0 };
51996 + dwc_ep_t *dwc_ep;
51999 + dev_if = GET_CORE_IF(pcd)->dev_if;
52001 + for (i = 1; i <= dev_if->num_in_eps; ++i) {
52002 + dwc_ep = &pcd->in_ep[i].dwc_ep;
52003 + if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
52005 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
52007 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52009 + if (depctl.b.epdis && deptsiz.d32) {
52010 + set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep);
52011 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
52012 + dwc_ep->cur_pkt = 0;
52013 + dwc_ep->proc_buf_num =
52014 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
52016 + if (dwc_ep->proc_buf_num) {
52017 + dwc_ep->cur_pkt_addr =
52018 + dwc_ep->xfer_buff1;
52019 + dwc_ep->cur_pkt_dma_addr =
52020 + dwc_ep->dma_addr1;
52022 + dwc_ep->cur_pkt_addr =
52023 + dwc_ep->xfer_buff0;
52024 + dwc_ep->cur_pkt_dma_addr =
52025 + dwc_ep->dma_addr0;
52031 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
52032 + dev_global_regs->dsts);
52033 + dwc_ep->next_frame = dsts.b.soffn;
52035 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
52043 + depctl_data_t depctl = {.d32 = 0 };
52044 + dwc_ep_t *dwc_ep;
52045 + dwc_otg_dev_if_t *dev_if;
52047 + dev_if = GET_CORE_IF(pcd)->dev_if;
52049 + DWC_DEBUGPL(DBG_PCD,"Incomplete ISO IN \n");
52051 + for (i = 1; i <= dev_if->num_in_eps; ++i) {
52052 + dwc_ep = &pcd->in_ep[i-1].dwc_ep;
52054 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52055 + if (depctl.b.epena && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
52056 + if (drop_transfer(dwc_ep->frame_num, GET_CORE_IF(pcd)->frame_num,
52057 + dwc_ep->frm_overrun))
52060 + DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52061 + depctl.b.snak = 1;
52062 + depctl.b.epdis = 1;
52063 + DWC_MODIFY_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32, depctl.d32);
52068 + /*intr_mask.b.incomplisoin = 1;
52069 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52070 + intr_mask.d32, 0); */
52071 +#endif //DWC_EN_ISOC
52073 + /* Clear interrupt */
52075 + gintsts.b.incomplisoin = 1;
52076 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52083 + * Incomplete ISO OUT Transfer Interrupt.
52085 + * This interrupt indicates that the core has dropped an ISO OUT
52086 + * packet. The following conditions can be the cause:
52087 + * - FIFO Full, the entire packet would not fit in the FIFO.
52089 + * - Corrupted Token
52090 + * The follow actions will be taken:
52091 + * -# Determine the EP
52092 + * -# Set incomplete flag in dwc_ep structure
52093 + * -# Read any data from the FIFO
52094 + * -# Disable EP. When "Endpoint Disabled" interrupt is received
52097 +int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd)
52100 + gintsts_data_t gintsts;
52102 +#ifdef DWC_EN_ISOC
52103 + dwc_otg_dev_if_t *dev_if;
52104 + deptsiz_data_t deptsiz = {.d32 = 0 };
52105 + depctl_data_t depctl = {.d32 = 0 };
52106 + dsts_data_t dsts = {.d32 = 0 };
52107 + dwc_ep_t *dwc_ep;
52110 + dev_if = GET_CORE_IF(pcd)->dev_if;
52112 + for (i = 1; i <= dev_if->num_out_eps; ++i) {
52113 + dwc_ep = &pcd->in_ep[i].dwc_ep;
52114 + if (pcd->out_ep[i].dwc_ep.active &&
52115 + pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
52117 + DWC_READ_REG32(&dev_if->out_ep_regs[i]->doeptsiz);
52119 + DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
52121 + if (depctl.b.epdis && deptsiz.d32) {
52122 + set_current_pkt_info(GET_CORE_IF(pcd),
52123 + &pcd->out_ep[i].dwc_ep);
52124 + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
52125 + dwc_ep->cur_pkt = 0;
52126 + dwc_ep->proc_buf_num =
52127 + (dwc_ep->proc_buf_num ^ 1) & 0x1;
52129 + if (dwc_ep->proc_buf_num) {
52130 + dwc_ep->cur_pkt_addr =
52131 + dwc_ep->xfer_buff1;
52132 + dwc_ep->cur_pkt_dma_addr =
52133 + dwc_ep->dma_addr1;
52135 + dwc_ep->cur_pkt_addr =
52136 + dwc_ep->xfer_buff0;
52137 + dwc_ep->cur_pkt_dma_addr =
52138 + dwc_ep->dma_addr0;
52144 + DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
52145 + dev_global_regs->dsts);
52146 + dwc_ep->next_frame = dsts.b.soffn;
52148 + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
52155 + /** @todo implement ISR */
52156 + gintmsk_data_t intr_mask = {.d32 = 0 };
52157 + dwc_otg_core_if_t *core_if;
52158 + deptsiz_data_t deptsiz = {.d32 = 0 };
52159 + depctl_data_t depctl = {.d32 = 0 };
52160 + dctl_data_t dctl = {.d32 = 0 };
52161 + dwc_ep_t *dwc_ep = NULL;
52163 + core_if = GET_CORE_IF(pcd);
52165 + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
52166 + dwc_ep = &pcd->out_ep[i].dwc_ep;
52168 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
52169 + if (depctl.b.epena && depctl.b.dpid == (core_if->frame_num & 0x1)) {
52170 + core_if->dev_if->isoc_ep = dwc_ep;
52172 + DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz);
52176 + dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
52177 + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
52178 + intr_mask.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
52180 + if (!intr_mask.b.goutnakeff) {
52182 + intr_mask.b.goutnakeff = 1;
52183 + DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32);
52185 + if (!gintsts.b.goutnakeff) {
52186 + dctl.b.sgoutnak = 1;
52188 + DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
52190 + depctl.d32 = DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
52191 + if (depctl.b.epena) {
52192 + depctl.b.epdis = 1;
52193 + depctl.b.snak = 1;
52195 + DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl, depctl.d32);
52197 + intr_mask.d32 = 0;
52198 + intr_mask.b.incomplisoout = 1;
52200 +#endif /* DWC_EN_ISOC */
52202 + /* Clear interrupt */
52204 + gintsts.b.incomplisoout = 1;
52205 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52212 + * This function handles the Global IN NAK Effective interrupt.
52215 +int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd)
52217 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
52218 + depctl_data_t diepctl = {.d32 = 0 };
52219 + gintmsk_data_t intr_mask = {.d32 = 0 };
52220 + gintsts_data_t gintsts;
52221 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
52224 + DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
52226 + /* Disable all active IN EPs */
52227 + for (i = 0; i <= dev_if->num_in_eps; i++) {
52228 + diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
52229 + if (!(diepctl.b.eptype & 1) && diepctl.b.epena) {
52230 + if (core_if->start_predict > 0)
52231 + core_if->start_predict++;
52232 + diepctl.b.epdis = 1;
52233 + diepctl.b.snak = 1;
52234 + DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, diepctl.d32);
52239 + /* Disable the Global IN NAK Effective Interrupt */
52240 + intr_mask.b.ginnakeff = 1;
52241 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52242 + intr_mask.d32, 0);
52244 + /* Clear interrupt */
52246 + gintsts.b.ginnakeff = 1;
52247 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52254 + * OUT NAK Effective.
52257 +int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd)
52259 + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
52260 + gintmsk_data_t intr_mask = {.d32 = 0 };
52261 + gintsts_data_t gintsts;
52262 + depctl_data_t doepctl;
52265 + /* Disable the Global OUT NAK Effective Interrupt */
52266 + intr_mask.b.goutnakeff = 1;
52267 + DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
52268 + intr_mask.d32, 0);
52270 + /* If DEV OUT NAK enabled*/
52271 + if (pcd->core_if->core_params->dev_out_nak) {
52272 + /* Run over all out endpoints to determine the ep number on
52273 + * which the timeout has happened
52275 + for (i = 0; i <= dev_if->num_out_eps; i++) {
52276 + if ( pcd->core_if->ep_xfer_info[i].state == 2 )
52279 + if (i > dev_if->num_out_eps) {
52280 + dctl_data_t dctl;
52282 + DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
52283 + dctl.b.cgoutnak = 1;
52284 + DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl,
52289 + /* Disable the endpoint */
52290 + doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
52291 + if (doepctl.b.epena) {
52292 + doepctl.b.epdis = 1;
52293 + doepctl.b.snak = 1;
52295 + DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
52298 + /* We come here from Incomplete ISO OUT handler */
52299 + if (dev_if->isoc_ep) {
52300 + dwc_ep_t *dwc_ep = (dwc_ep_t *)dev_if->isoc_ep;
52301 + uint32_t epnum = dwc_ep->num;
52302 + doepint_data_t doepint;
52304 + DWC_READ_REG32(&dev_if->out_ep_regs[dwc_ep->num]->doepint);
52305 + dev_if->isoc_ep = NULL;
52307 + DWC_READ_REG32(&dev_if->out_ep_regs[epnum]->doepctl);
52308 + DWC_PRINTF("Before disable DOEPCTL = %08x\n", doepctl.d32);
52309 + if (doepctl.b.epena) {
52310 + doepctl.b.epdis = 1;
52311 + doepctl.b.snak = 1;
52313 + DWC_WRITE_REG32(&dev_if->out_ep_regs[epnum]->doepctl,
52317 + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
52318 + "Global OUT NAK Effective\n");
52321 + /* Clear interrupt */
52323 + gintsts.b.goutnakeff = 1;
52324 + DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
52331 + * PCD interrupt handler.
52333 + * The PCD handles the device interrupts. Many conditions can cause a
52334 + * device interrupt. When an interrupt occurs, the device interrupt
52335 + * service routine determines the cause of the interrupt and
52336 + * dispatches handling to the appropriate function. These interrupt
52337 + * handling functions are described below.
52339 + * All interrupt registers are processed from LSB to MSB.
52342 +int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd)
52344 + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
52346 + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
52348 + gintsts_data_t gintr_status;
52349 + int32_t retval = 0;
52351 + /* Exit from ISR if core is hibernated */
52352 + if (core_if->hibernation_suspend == 1) {
52356 + DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x gintmsk=%08x\n",
52358 + DWC_READ_REG32(&global_regs->gintsts),
52359 + DWC_READ_REG32(&global_regs->gintmsk));
52362 + if (dwc_otg_is_device_mode(core_if)) {
52363 + DWC_SPINLOCK(pcd->lock);
52365 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x gintmsk=%08x\n",
52367 + DWC_READ_REG32(&global_regs->gintsts),
52368 + DWC_READ_REG32(&global_regs->gintmsk));
52371 + gintr_status.d32 = dwc_otg_read_core_intr(core_if);
52373 + DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
52374 + __func__, gintr_status.d32);
52376 + if (gintr_status.b.sofintr) {
52377 + retval |= dwc_otg_pcd_handle_sof_intr(pcd);
52379 + if (gintr_status.b.rxstsqlvl) {
52381 + dwc_otg_pcd_handle_rx_status_q_level_intr(pcd);
52383 + if (gintr_status.b.nptxfempty) {
52384 + retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd);
52386 + if (gintr_status.b.goutnakeff) {
52387 + retval |= dwc_otg_pcd_handle_out_nak_effective(pcd);
52389 + if (gintr_status.b.i2cintr) {
52390 + retval |= dwc_otg_pcd_handle_i2c_intr(pcd);
52392 + if (gintr_status.b.erlysuspend) {
52393 + retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd);
52395 + if (gintr_status.b.usbreset) {
52396 + retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd);
52398 + if (gintr_status.b.enumdone) {
52399 + retval |= dwc_otg_pcd_handle_enum_done_intr(pcd);
52401 + if (gintr_status.b.isooutdrop) {
52403 + dwc_otg_pcd_handle_isoc_out_packet_dropped_intr
52406 + if (gintr_status.b.eopframe) {
52408 + dwc_otg_pcd_handle_end_periodic_frame_intr(pcd);
52410 + if (gintr_status.b.inepint) {
52411 + if (!core_if->multiproc_int_enable) {
52412 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
52415 + if (gintr_status.b.outepintr) {
52416 + if (!core_if->multiproc_int_enable) {
52417 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
52420 + if (gintr_status.b.epmismatch) {
52421 + retval |= dwc_otg_pcd_handle_ep_mismatch_intr(pcd);
52423 + if (gintr_status.b.fetsusp) {
52424 + retval |= dwc_otg_pcd_handle_ep_fetsusp_intr(pcd);
52426 + if (gintr_status.b.ginnakeff) {
52427 + retval |= dwc_otg_pcd_handle_in_nak_effective(pcd);
52429 + if (gintr_status.b.incomplisoin) {
52431 + dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd);
52433 + if (gintr_status.b.incomplisoout) {
52435 + dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd);
52438 + /* In MPI mode Device Endpoints interrupts are asserted
52439 + * without setting outepintr and inepint bits set, so these
52440 + * Interrupt handlers are called without checking these bit-fields
52442 + if (core_if->multiproc_int_enable) {
52443 + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
52444 + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
52447 + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
52448 + DWC_READ_REG32(&global_regs->gintsts));
52450 + DWC_SPINUNLOCK(pcd->lock);
52455 +#endif /* DWC_HOST_ONLY */
52456 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
52457 new file mode 100644
52458 index 0000000..a591d89
52460 +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
52462 + /* ==========================================================================
52463 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
52464 + * $Revision: #21 $
52465 + * $Date: 2012/08/10 $
52466 + * $Change: 2047372 $
52468 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
52469 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
52470 + * otherwise expressly agreed to in writing between Synopsys and you.
52472 + * The Software IS NOT an item of Licensed Software or Licensed Product under
52473 + * any End User Software License Agreement or Agreement for Licensed Product
52474 + * with Synopsys or any supplement thereto. You are permitted to use and
52475 + * redistribute this Software in source and binary forms, with or without
52476 + * modification, provided that redistributions of source code must retain this
52477 + * notice. You may not view, use, disclose, copy or distribute this file or
52478 + * any information contained herein except pursuant to this license grant from
52479 + * Synopsys. If you do not agree with this notice, including the disclaimer
52480 + * below, then you are not authorized to use the Software.
52482 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
52483 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52484 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52485 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
52486 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
52487 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
52488 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
52489 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52490 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52491 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
52493 + * ========================================================================== */
52494 +#ifndef DWC_HOST_ONLY
52497 + * This file implements the Peripheral Controller Driver.
52499 + * The Peripheral Controller Driver (PCD) is responsible for
52500 + * translating requests from the Function Driver into the appropriate
52501 + * actions on the DWC_otg controller. It isolates the Function Driver
52502 + * from the specifics of the controller by providing an API to the
52503 + * Function Driver.
52505 + * The Peripheral Controller Driver for Linux will implement the
52506 + * Gadget API, so that the existing Gadget drivers can be used.
52507 + * (Gadget Driver is the Linux terminology for a Function Driver.)
52509 + * The Linux Gadget API is defined in the header file
52510 + * <code><linux/usb_gadget.h></code>. The USB EP operations API is
52511 + * defined in the structure <code>usb_ep_ops</code> and the USB
52512 + * Controller API is defined in the structure
52513 + * <code>usb_gadget_ops</code>.
52517 +#include "dwc_otg_os_dep.h"
52518 +#include "dwc_otg_pcd_if.h"
52519 +#include "dwc_otg_pcd.h"
52520 +#include "dwc_otg_driver.h"
52521 +#include "dwc_otg_dbg.h"
52523 +static struct gadget_wrapper {
52524 + dwc_otg_pcd_t *pcd;
52526 + struct usb_gadget gadget;
52527 + struct usb_gadget_driver *driver;
52529 + struct usb_ep ep0;
52530 + struct usb_ep in_ep[16];
52531 + struct usb_ep out_ep[16];
52533 +} *gadget_wrapper;
52535 +/* Display the contents of the buffer */
52536 +extern void dump_msg(const u8 * buf, unsigned int length);
52538 + * Get the dwc_otg_pcd_ep_t* from usb_ep* pointer - NULL in case
52539 + * if the endpoint is not found
52541 +static struct dwc_otg_pcd_ep *ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
52544 + if (pcd->ep0.priv == handle) {
52545 + return &pcd->ep0;
52548 + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
52549 + if (pcd->in_ep[i].priv == handle)
52550 + return &pcd->in_ep[i];
52551 + if (pcd->out_ep[i].priv == handle)
52552 + return &pcd->out_ep[i];
52558 +/* USB Endpoint Operations */
52560 + * The following sections briefly describe the behavior of the Gadget
52561 + * API endpoint operations implemented in the DWC_otg driver
52562 + * software. Detailed descriptions of the generic behavior of each of
52563 + * these functions can be found in the Linux header file
52564 + * include/linux/usb_gadget.h.
52566 + * The Gadget API provides wrapper functions for each of the function
52567 + * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
52568 + * function, which then calls the underlying PCD function. The
52569 + * following sections are named according to the wrapper
52570 + * functions. Within each section, the corresponding DWC_otg PCD
52571 + * function name is specified.
52576 + * This function is called by the Gadget Driver for each EP to be
52577 + * configured for the current configuration (SET_CONFIGURATION).
52579 + * This function initializes the dwc_otg_ep_t data structure, and then
52580 + * calls dwc_otg_ep_activate.
52582 +static int ep_enable(struct usb_ep *usb_ep,
52583 + const struct usb_endpoint_descriptor *ep_desc)
52587 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
52589 + if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
52590 + DWC_WARN("%s, bad ep or descriptor\n", __func__);
52593 + if (usb_ep == &gadget_wrapper->ep0) {
52594 + DWC_WARN("%s, bad ep(0)\n", __func__);
52598 + /* Check FIFO size? */
52599 + if (!ep_desc->wMaxPacketSize) {
52600 + DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
52604 + if (!gadget_wrapper->driver ||
52605 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52606 + DWC_WARN("%s, bogus device state\n", __func__);
52607 + return -ESHUTDOWN;
52610 + /* Delete after check - MAS */
52612 + nat = (uint32_t) ep_desc->wMaxPacketSize;
52613 + printk(KERN_ALERT "%s: nat (before) =%d\n", __func__, nat);
52614 + nat = (nat >> 11) & 0x03;
52615 + printk(KERN_ALERT "%s: nat (after) =%d\n", __func__, nat);
52617 + retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
52618 + (const uint8_t *)ep_desc,
52621 + DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
52625 + usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
52631 + * This function is called when an EP is disabled due to disconnect or
52632 + * change in configuration. Any pending requests will terminate with a
52633 + * status of -ESHUTDOWN.
52635 + * This function modifies the dwc_otg_ep_t data structure for this EP,
52636 + * and then calls dwc_otg_ep_deactivate.
52638 +static int ep_disable(struct usb_ep *usb_ep)
52642 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
52644 + DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
52645 + usb_ep ? usb_ep->name : NULL);
52649 + retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
52651 + retval = -EINVAL;
52658 + * This function allocates a request object to use with the specified
52661 + * @param ep The endpoint to be used with with the request
52662 + * @param gfp_flags the GFP_* flags to use.
52664 +static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
52667 + struct usb_request *usb_req;
52669 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
52671 + DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
52674 + usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
52675 + if (0 == usb_req) {
52676 + DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
52679 + memset(usb_req, 0, sizeof(*usb_req));
52680 + usb_req->dma = DWC_DMA_ADDR_INVALID;
52686 + * This function frees a request object.
52688 + * @param ep The endpoint associated with the request
52689 + * @param req The request being freed
52691 +static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
52693 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
52695 + if (0 == ep || 0 == req) {
52696 + DWC_WARN("%s() %s\n", __func__,
52697 + "Invalid ep or req argument!\n");
52704 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52706 + * This function allocates an I/O buffer to be used for a transfer
52707 + * to/from the specified endpoint.
52709 + * @param usb_ep The endpoint to be used with with the request
52710 + * @param bytes The desired number of bytes for the buffer
52711 + * @param dma Pointer to the buffer's DMA address; must be valid
52712 + * @param gfp_flags the GFP_* flags to use.
52713 + * @return address of a new buffer or null is buffer could not be allocated.
52715 +static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
52716 + dma_addr_t * dma, gfp_t gfp_flags)
52719 + dwc_otg_pcd_t *pcd = 0;
52721 + pcd = gadget_wrapper->pcd;
52723 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
52726 + /* Check dword alignment */
52727 + if ((bytes & 0x3UL) != 0) {
52728 + DWC_WARN("%s() Buffer size is not a multiple of"
52729 + "DWORD size (%d)", __func__, bytes);
52732 + buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
52734 + /* Check dword alignment */
52735 + if (((int)buf & 0x3UL) != 0) {
52736 + DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
52744 + * This function frees an I/O buffer that was allocated by alloc_buffer.
52746 + * @param usb_ep the endpoint associated with the buffer
52747 + * @param buf address of the buffer
52748 + * @param dma The buffer's DMA address
52749 + * @param bytes The number of bytes of the buffer
52751 +static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
52752 + dma_addr_t dma, unsigned bytes)
52754 + dwc_otg_pcd_t *pcd = 0;
52756 + pcd = gadget_wrapper->pcd;
52758 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
52760 + dma_free_coherent(NULL, bytes, buf, dma);
52765 + * This function is used to submit an I/O Request to an EP.
52767 + * - When the request completes the request's completion callback
52768 + * is called to return the request to the driver.
52769 + * - An EP, except control EPs, may have multiple requests
52771 + * - Once submitted the request cannot be examined or modified.
52772 + * - Each request is turned into one or more packets.
52773 + * - A BULK EP can queue any amount of data; the transfer is
52775 + * - Zero length Packets are specified with the request 'zero'
52778 +static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
52781 + dwc_otg_pcd_t *pcd;
52782 + struct dwc_otg_pcd_ep *ep = NULL;
52783 + int retval = 0, is_isoc_ep = 0;
52784 + dma_addr_t dma_addr = DWC_DMA_ADDR_INVALID;
52786 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
52787 + __func__, usb_ep, usb_req, gfp_flags);
52789 + if (!usb_req || !usb_req->complete || !usb_req->buf) {
52790 + DWC_WARN("bad params\n");
52795 + DWC_WARN("bad ep\n");
52799 + pcd = gadget_wrapper->pcd;
52800 + if (!gadget_wrapper->driver ||
52801 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52802 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
52803 + gadget_wrapper->gadget.speed);
52804 + DWC_WARN("bogus device state\n");
52805 + return -ESHUTDOWN;
52808 + DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
52809 + usb_ep->name, usb_req, usb_req->length, usb_req->buf);
52811 + usb_req->status = -EINPROGRESS;
52812 + usb_req->actual = 0;
52814 + ep = ep_from_handle(pcd, usb_ep);
52818 + is_isoc_ep = (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ? 1 : 0;
52819 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
52820 + dma_addr = usb_req->dma;
52822 + if (GET_CORE_IF(pcd)->dma_enable) {
52823 + dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
52824 + struct device *dev = NULL;
52826 + if (otg_dev != NULL)
52827 + dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
52829 + if (usb_req->length != 0 &&
52830 + usb_req->dma == DWC_DMA_ADDR_INVALID) {
52831 + dma_addr = dma_map_single(dev, usb_req->buf,
52833 + ep->dwc_ep.is_in ?
52835 + DMA_FROM_DEVICE);
52840 +#ifdef DWC_UTE_PER_IO
52841 + if (is_isoc_ep == 1) {
52842 + retval = dwc_otg_pcd_xiso_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
52843 + usb_req->length, usb_req->zero, usb_req,
52844 + gfp_flags == GFP_ATOMIC ? 1 : 0, &usb_req->ext_req);
52851 + retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
52852 + usb_req->length, usb_req->zero, usb_req,
52853 + gfp_flags == GFP_ATOMIC ? 1 : 0);
52862 + * This function cancels an I/O request from an EP.
52864 +static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
52866 + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
52868 + if (!usb_ep || !usb_req) {
52869 + DWC_WARN("bad argument\n");
52872 + if (!gadget_wrapper->driver ||
52873 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
52874 + DWC_WARN("bogus device state\n");
52875 + return -ESHUTDOWN;
52877 + if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
52885 + * usb_ep_set_halt stalls an endpoint.
52887 + * usb_ep_clear_halt clears an endpoint halt and resets its data
52890 + * Both of these functions are implemented with the same underlying
52891 + * function. The behavior depends on the value argument.
52893 + * @param[in] usb_ep the Endpoint to halt or clear halt.
52894 + * @param[in] value
52895 + * - 0 means clear_halt.
52896 + * - 1 means set_halt,
52897 + * - 2 means clear stall lock flag.
52898 + * - 3 means set stall lock flag.
52900 +static int ep_halt(struct usb_ep *usb_ep, int value)
52904 + DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
52907 + DWC_WARN("bad ep\n");
52911 + retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
52912 + if (retval == -DWC_E_AGAIN) {
52914 + } else if (retval) {
52915 + retval = -EINVAL;
52921 +//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
52924 + * ep_wedge: sets the halt feature and ignores clear requests
52926 + * @usb_ep: the endpoint being wedged
52928 + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
52929 + * requests. If the gadget driver clears the halt status, it will
52930 + * automatically unwedge the endpoint.
52932 + * Returns zero on success, else negative errno. *
52933 + * Check usb_ep_set_wedge() at "usb_gadget.h" for details
52935 +static int ep_wedge(struct usb_ep *usb_ep)
52939 + DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name);
52942 + DWC_WARN("bad ep\n");
52946 + retval = dwc_otg_pcd_ep_wedge(gadget_wrapper->pcd, usb_ep);
52947 + if (retval == -DWC_E_AGAIN) {
52948 + retval = -EAGAIN;
52949 + } else if (retval) {
52950 + retval = -EINVAL;
52957 +#ifdef DWC_EN_ISOC
52959 + * This function is used to submit an ISOC Transfer Request to an EP.
52961 + * - Every time a sync period completes the request's completion callback
52962 + * is called to provide data to the gadget driver.
52963 + * - Once submitted the request cannot be modified.
52964 + * - Each request is turned into periodic data packets untill ISO
52965 + * Transfer is stopped..
52967 +static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
52972 + if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
52973 + DWC_WARN("bad params\n");
52978 + DWC_PRINTF("bad params\n");
52982 + req->status = -EINPROGRESS;
52985 + dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
52986 + req->buf1, req->dma0, req->dma1,
52987 + req->sync_frame, req->data_pattern_frame,
52988 + req->data_per_frame,
52990 + flags & USB_REQ_ISO_ASAP ? -1 :
52991 + req->start_frame, req->buf_proc_intrvl,
52992 + req, gfp_flags == GFP_ATOMIC ? 1 : 0);
53002 + * This function stops ISO EP Periodic Data Transfer.
53004 +static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
53008 + DWC_WARN("bad ep\n");
53011 + if (!gadget_wrapper->driver ||
53012 + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
53013 + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
53014 + gadget_wrapper->gadget.speed);
53015 + DWC_WARN("bogus device state\n");
53018 + dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
53020 + retval = -EINVAL;
53026 +static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
53027 + int packets, gfp_t gfp_flags)
53029 + struct usb_iso_request *pReq = NULL;
53030 + uint32_t req_size;
53032 + req_size = sizeof(struct usb_iso_request);
53034 + (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
53036 + pReq = kmalloc(req_size, gfp_flags);
53038 + DWC_WARN("Can't allocate Iso Request\n");
53041 + pReq->iso_packet_desc0 = (void *)(pReq + 1);
53043 + pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
53048 +static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
53053 +static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
53055 + .enable = ep_enable,
53056 + .disable = ep_disable,
53058 + .alloc_request = dwc_otg_pcd_alloc_request,
53059 + .free_request = dwc_otg_pcd_free_request,
53061 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
53062 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
53063 + .free_buffer = dwc_otg_pcd_free_buffer,
53066 + .queue = ep_queue,
53067 + .dequeue = ep_dequeue,
53069 + .set_halt = ep_halt,
53070 + .fifo_status = 0,
53073 + .iso_ep_start = iso_ep_start,
53074 + .iso_ep_stop = iso_ep_stop,
53075 + .alloc_iso_request = alloc_iso_request,
53076 + .free_iso_request = free_iso_request,
53081 + int (*enable) (struct usb_ep *ep,
53082 + const struct usb_endpoint_descriptor *desc);
53083 + int (*disable) (struct usb_ep *ep);
53085 + struct usb_request *(*alloc_request) (struct usb_ep *ep,
53086 + gfp_t gfp_flags);
53087 + void (*free_request) (struct usb_ep *ep, struct usb_request *req);
53089 + int (*queue) (struct usb_ep *ep, struct usb_request *req,
53090 + gfp_t gfp_flags);
53091 + int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
53093 + int (*set_halt) (struct usb_ep *ep, int value);
53094 + int (*set_wedge) (struct usb_ep *ep);
53096 + int (*fifo_status) (struct usb_ep *ep);
53097 + void (*fifo_flush) (struct usb_ep *ep);
53098 +static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
53099 + .enable = ep_enable,
53100 + .disable = ep_disable,
53102 + .alloc_request = dwc_otg_pcd_alloc_request,
53103 + .free_request = dwc_otg_pcd_free_request,
53105 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
53106 + .alloc_buffer = dwc_otg_pcd_alloc_buffer,
53107 + .free_buffer = dwc_otg_pcd_free_buffer,
53109 + /* .set_wedge = ep_wedge, */
53110 + .set_wedge = NULL, /* uses set_halt instead */
53113 + .queue = ep_queue,
53114 + .dequeue = ep_dequeue,
53116 + .set_halt = ep_halt,
53117 + .fifo_status = 0,
53122 +#endif /* _EN_ISOC_ */
53123 +/* Gadget Operations */
53125 + * The following gadget operations will be implemented in the DWC_otg
53126 + * PCD. Functions in the API that are not described below are not
53129 + * The Gadget API provides wrapper functions for each of the function
53130 + * pointers defined in usb_gadget_ops. The Gadget Driver calls the
53131 + * wrapper function, which then calls the underlying PCD function. The
53132 + * following sections are named according to the wrapper functions
53133 + * (except for ioctl, which doesn't have a wrapper function). Within
53134 + * each section, the corresponding DWC_otg PCD function name is
53140 + *Gets the USB Frame number of the last SOF.
53142 +static int get_frame_number(struct usb_gadget *gadget)
53144 + struct gadget_wrapper *d;
53146 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
53148 + if (gadget == 0) {
53152 + d = container_of(gadget, struct gadget_wrapper, gadget);
53153 + return dwc_otg_pcd_get_frame_number(d->pcd);
53156 +#ifdef CONFIG_USB_DWC_OTG_LPM
53157 +static int test_lpm_enabled(struct usb_gadget *gadget)
53159 + struct gadget_wrapper *d;
53161 + d = container_of(gadget, struct gadget_wrapper, gadget);
53163 + return dwc_otg_pcd_is_lpm_enabled(d->pcd);
53168 + * Initiates Session Request Protocol (SRP) to wakeup the host if no
53169 + * session is in progress. If a session is already in progress, but
53170 + * the device is suspended, remote wakeup signaling is started.
53173 +static int wakeup(struct usb_gadget *gadget)
53175 + struct gadget_wrapper *d;
53177 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
53179 + if (gadget == 0) {
53182 + d = container_of(gadget, struct gadget_wrapper, gadget);
53184 + dwc_otg_pcd_wakeup(d->pcd);
53188 +static const struct usb_gadget_ops dwc_otg_pcd_ops = {
53189 + .get_frame = get_frame_number,
53190 + .wakeup = wakeup,
53191 +#ifdef CONFIG_USB_DWC_OTG_LPM
53192 + .lpm_support = test_lpm_enabled,
53194 + // current versions must always be self-powered
53197 +static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
53199 + int retval = -DWC_E_NOT_SUPPORTED;
53200 + if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
53201 + retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
53202 + (struct usb_ctrlrequest
53206 + if (retval == -ENOTSUPP) {
53207 + retval = -DWC_E_NOT_SUPPORTED;
53208 + } else if (retval < 0) {
53209 + retval = -DWC_E_INVALID;
53215 +#ifdef DWC_EN_ISOC
53216 +static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53217 + void *req_handle, int proc_buf_num)
53219 + int i, packet_count;
53220 + struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
53221 + struct usb_iso_request *iso_req = req_handle;
53223 + if (proc_buf_num) {
53224 + iso_packet = iso_req->iso_packet_desc1;
53226 + iso_packet = iso_req->iso_packet_desc0;
53229 + dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
53230 + for (i = 0; i < packet_count; ++i) {
53234 + dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
53235 + i, &status, &actual, &offset);
53236 + switch (status) {
53237 + case -DWC_E_NO_DATA:
53238 + status = -ENODATA;
53242 + DWC_PRINTF("unknown status in isoc packet\n");
53246 + iso_packet[i].status = status;
53247 + iso_packet[i].offset = offset;
53248 + iso_packet[i].actual_length = actual;
53251 + iso_req->status = 0;
53252 + iso_req->process_buffer(ep_handle, iso_req);
53256 +#endif /* DWC_EN_ISOC */
53258 +#ifdef DWC_UTE_PER_IO
53260 + * Copy the contents of the extended request to the Linux usb_request's
53261 + * extended part and call the gadget's completion.
53263 + * @param pcd Pointer to the pcd structure
53264 + * @param ep_handle Void pointer to the usb_ep structure
53265 + * @param req_handle Void pointer to the usb_request structure
53266 + * @param status Request status returned from the portable logic
53267 + * @param ereq_port Void pointer to the extended request structure
53268 + * created in the the portable part that contains the
53269 + * results of the processed iso packets.
53271 +static int _xisoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53272 + void *req_handle, int32_t status, void *ereq_port)
53274 + struct dwc_ute_iso_req_ext *ereqorg = NULL;
53275 + struct dwc_iso_xreq_port *ereqport = NULL;
53276 + struct dwc_ute_iso_packet_descriptor *desc_org = NULL;
53278 + struct usb_request *req;
53279 + //struct dwc_ute_iso_packet_descriptor *
53280 + //int status = 0;
53282 + req = (struct usb_request *)req_handle;
53283 + ereqorg = &req->ext_req;
53284 + ereqport = (struct dwc_iso_xreq_port *)ereq_port;
53285 + desc_org = ereqorg->per_io_frame_descs;
53287 + if (req && req->complete) {
53288 + /* Copy the request data from the portable logic to our request */
53289 + for (i = 0; i < ereqport->pio_pkt_count; i++) {
53290 + desc_org[i].actual_length =
53291 + ereqport->per_io_frame_descs[i].actual_length;
53292 + desc_org[i].status =
53293 + ereqport->per_io_frame_descs[i].status;
53296 + switch (status) {
53297 + case -DWC_E_SHUTDOWN:
53298 + req->status = -ESHUTDOWN;
53300 + case -DWC_E_RESTART:
53301 + req->status = -ECONNRESET;
53303 + case -DWC_E_INVALID:
53304 + req->status = -EINVAL;
53306 + case -DWC_E_TIMEOUT:
53307 + req->status = -ETIMEDOUT;
53310 + req->status = status;
53313 + /* And call the gadget's completion */
53314 + req->complete(ep_handle, req);
53319 +#endif /* DWC_UTE_PER_IO */
53321 +static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
53322 + void *req_handle, int32_t status, uint32_t actual)
53324 + struct usb_request *req = (struct usb_request *)req_handle;
53325 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
53326 + struct dwc_otg_pcd_ep *ep = NULL;
53329 + if (req && req->complete) {
53330 + switch (status) {
53331 + case -DWC_E_SHUTDOWN:
53332 + req->status = -ESHUTDOWN;
53334 + case -DWC_E_RESTART:
53335 + req->status = -ECONNRESET;
53337 + case -DWC_E_INVALID:
53338 + req->status = -EINVAL;
53340 + case -DWC_E_TIMEOUT:
53341 + req->status = -ETIMEDOUT;
53344 + req->status = status;
53348 + req->actual = actual;
53349 + DWC_SPINUNLOCK(pcd->lock);
53350 + req->complete(ep_handle, req);
53351 + DWC_SPINLOCK(pcd->lock);
53353 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
53354 + ep = ep_from_handle(pcd, ep_handle);
53355 + if (GET_CORE_IF(pcd)->dma_enable) {
53356 + if (req->length != 0) {
53357 + dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
53358 + struct device *dev = NULL;
53360 + if (otg_dev != NULL)
53361 + dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
53363 + dma_unmap_single(dev, req->dma, req->length,
53364 + ep->dwc_ep.is_in ?
53365 + DMA_TO_DEVICE: DMA_FROM_DEVICE);
53373 +static int _connect(dwc_otg_pcd_t * pcd, int speed)
53375 + gadget_wrapper->gadget.speed = speed;
53379 +static int _disconnect(dwc_otg_pcd_t * pcd)
53381 + if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
53382 + gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
53387 +static int _resume(dwc_otg_pcd_t * pcd)
53389 + if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
53390 + gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
53396 +static int _suspend(dwc_otg_pcd_t * pcd)
53398 + if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
53399 + gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
53405 + * This function updates the otg values in the gadget structure.
53407 +static int _hnp_changed(dwc_otg_pcd_t * pcd)
53410 + if (!gadget_wrapper->gadget.is_otg)
53413 + gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
53414 + gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
53415 + gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
53419 +static int _reset(dwc_otg_pcd_t * pcd)
53424 +#ifdef DWC_UTE_CFI
53425 +static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
53427 + int retval = -DWC_E_INVALID;
53428 + if (gadget_wrapper->driver->cfi_feature_setup) {
53430 + gadget_wrapper->driver->
53431 + cfi_feature_setup(&gadget_wrapper->gadget,
53432 + (struct cfi_usb_ctrlrequest *)cfi_req);
53439 +static const struct dwc_otg_pcd_function_ops fops = {
53440 + .complete = _complete,
53441 +#ifdef DWC_EN_ISOC
53442 + .isoc_complete = _isoc_complete,
53445 + .disconnect = _disconnect,
53446 + .connect = _connect,
53447 + .resume = _resume,
53448 + .suspend = _suspend,
53449 + .hnp_changed = _hnp_changed,
53451 +#ifdef DWC_UTE_CFI
53452 + .cfi_setup = _cfi_setup,
53454 +#ifdef DWC_UTE_PER_IO
53455 + .xisoc_complete = _xisoc_complete,
53460 + * This function is the top level PCD interrupt handler.
53462 +static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
53464 + dwc_otg_pcd_t *pcd = dev;
53465 + int32_t retval = IRQ_NONE;
53467 + retval = dwc_otg_pcd_handle_intr(pcd);
53468 + if (retval != 0) {
53469 + S3C2410X_CLEAR_EINTPEND();
53471 + return IRQ_RETVAL(retval);
53475 + * This function initialized the usb_ep structures to there default
53478 + * @param d Pointer on gadget_wrapper.
53480 +void gadget_add_eps(struct gadget_wrapper *d)
53482 + static const char *names[] = {
53518 + struct usb_ep *ep;
53519 + int8_t dev_endpoints;
53521 + DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
53523 + INIT_LIST_HEAD(&d->gadget.ep_list);
53524 + d->gadget.ep0 = &d->ep0;
53525 + d->gadget.speed = USB_SPEED_UNKNOWN;
53527 + INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
53530 + * Initialize the EP0 structure.
53534 + /* Init the usb_ep structure. */
53535 + ep->name = names[0];
53536 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53539 + * @todo NGS: What should the max packet size be set to
53540 + * here? Before EP type is set?
53542 + ep->maxpacket = MAX_PACKET_SIZE;
53543 + dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
53545 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53548 + * Initialize the EP structures.
53550 + dev_endpoints = d->pcd->core_if->dev_if->num_in_eps;
53552 + for (i = 0; i < dev_endpoints; i++) {
53553 + ep = &d->in_ep[i];
53555 + /* Init the usb_ep structure. */
53556 + ep->name = names[d->pcd->in_ep[i].dwc_ep.num];
53557 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53560 + * @todo NGS: What should the max packet size be set to
53561 + * here? Before EP type is set?
53563 + ep->maxpacket = MAX_PACKET_SIZE;
53564 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53567 + dev_endpoints = d->pcd->core_if->dev_if->num_out_eps;
53569 + for (i = 0; i < dev_endpoints; i++) {
53570 + ep = &d->out_ep[i];
53572 + /* Init the usb_ep structure. */
53573 + ep->name = names[15 + d->pcd->out_ep[i].dwc_ep.num];
53574 + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
53577 + * @todo NGS: What should the max packet size be set to
53578 + * here? Before EP type is set?
53580 + ep->maxpacket = MAX_PACKET_SIZE;
53582 + list_add_tail(&ep->ep_list, &d->gadget.ep_list);
53585 + /* remove ep0 from the list. There is a ep0 pointer. */
53586 + list_del_init(&d->ep0.ep_list);
53588 + d->ep0.maxpacket = MAX_EP0_SIZE;
53592 + * This function releases the Gadget device.
53593 + * required by device_unregister().
53595 + * @todo Should this do something? Should it free the PCD?
53597 +static void dwc_otg_pcd_gadget_release(struct device *dev)
53599 + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
53602 +static struct gadget_wrapper *alloc_wrapper(dwc_bus_dev_t *_dev)
53604 + static char pcd_name[] = "dwc_otg_pcd";
53605 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53606 + struct gadget_wrapper *d;
53609 + d = DWC_ALLOC(sizeof(*d));
53614 + memset(d, 0, sizeof(*d));
53616 + d->gadget.name = pcd_name;
53617 + d->pcd = otg_dev->pcd;
53619 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
53620 + strcpy(d->gadget.dev.bus_id, "gadget");
53622 + dev_set_name(&d->gadget.dev, "%s", "gadget");
53625 + d->gadget.dev.parent = &_dev->dev;
53626 + d->gadget.dev.release = dwc_otg_pcd_gadget_release;
53627 + d->gadget.ops = &dwc_otg_pcd_ops;
53628 + d->gadget.max_speed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd) ? USB_SPEED_HIGH:USB_SPEED_FULL;
53629 + d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
53632 + /* Register the gadget device */
53633 + retval = device_register(&d->gadget.dev);
53634 + if (retval != 0) {
53635 + DWC_ERROR("device_register failed\n");
53643 +static void free_wrapper(struct gadget_wrapper *d)
53646 + /* should have been done already by driver model core */
53647 + DWC_WARN("driver '%s' is still registered\n",
53648 + d->driver->driver.name);
53649 + usb_gadget_unregister_driver(d->driver);
53652 + device_unregister(&d->gadget.dev);
53657 + * This function initialized the PCD portion of the driver.
53660 +int pcd_init(dwc_bus_dev_t *_dev)
53662 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53665 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev=%p\n", __func__, _dev, otg_dev);
53667 + otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
53669 + if (!otg_dev->pcd) {
53670 + DWC_ERROR("dwc_otg_pcd_init failed\n");
53674 + otg_dev->pcd->otg_dev = otg_dev;
53675 + gadget_wrapper = alloc_wrapper(_dev);
53678 + * Initialize EP structures
53680 + gadget_add_eps(gadget_wrapper);
53682 + * Setup interupt handler
53684 +#ifdef PLATFORM_INTERFACE
53685 + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
53686 + platform_get_irq(_dev, 0));
53687 + retval = request_irq(platform_get_irq(_dev, 0), dwc_otg_pcd_irq,
53688 + IRQF_SHARED, gadget_wrapper->gadget.name,
53690 + if (retval != 0) {
53691 + DWC_ERROR("request of irq%d failed\n",
53692 + platform_get_irq(_dev, 0));
53693 + free_wrapper(gadget_wrapper);
53697 + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
53699 + retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
53700 + IRQF_SHARED | IRQF_DISABLED,
53701 + gadget_wrapper->gadget.name, otg_dev->pcd);
53702 + if (retval != 0) {
53703 + DWC_ERROR("request of irq%d failed\n", _dev->irq);
53704 + free_wrapper(gadget_wrapper);
53709 + dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
53715 + * Cleanup the PCD.
53717 +void pcd_remove(dwc_bus_dev_t *_dev)
53719 + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
53720 + dwc_otg_pcd_t *pcd = otg_dev->pcd;
53722 + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
53727 +#ifdef PLATFORM_INTERFACE
53728 + free_irq(platform_get_irq(_dev, 0), pcd);
53730 + free_irq(_dev->irq, pcd);
53732 + dwc_otg_pcd_remove(otg_dev->pcd);
53733 + free_wrapper(gadget_wrapper);
53734 + otg_dev->pcd = 0;
53738 + * This function registers a gadget driver with the PCD.
53740 + * When a driver is successfully registered, it will receive control
53741 + * requests including set_configuration(), which enables non-control
53742 + * requests. then usb traffic follows until a disconnect is reported.
53743 + * then a host may connect again, or the driver might get unbound.
53745 + * @param driver The driver being registered
53746 + * @param bind The bind function of gadget driver
53749 +int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
53753 + DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
53754 + driver->driver.name);
53756 + if (!driver || driver->max_speed == USB_SPEED_UNKNOWN ||
53758 + !driver->unbind || !driver->disconnect || !driver->setup) {
53759 + DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
53762 + if (gadget_wrapper == 0) {
53763 + DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
53766 + if (gadget_wrapper->driver != 0) {
53767 + DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
53771 + /* hook up the driver */
53772 + gadget_wrapper->driver = driver;
53773 + gadget_wrapper->gadget.dev.driver = &driver->driver;
53775 + DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
53776 + retval = driver->bind(&gadget_wrapper->gadget, gadget_wrapper->driver);
53778 + DWC_ERROR("bind to driver %s --> error %d\n",
53779 + driver->driver.name, retval);
53780 + gadget_wrapper->driver = 0;
53781 + gadget_wrapper->gadget.dev.driver = 0;
53784 + DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
53785 + driver->driver.name);
53788 +EXPORT_SYMBOL(usb_gadget_probe_driver);
53791 + * This function unregisters a gadget driver
53793 + * @param driver The driver being unregistered
53795 +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
53797 + //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
53799 + if (gadget_wrapper == 0) {
53800 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
53804 + if (driver == 0 || driver != gadget_wrapper->driver) {
53805 + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
53810 + driver->unbind(&gadget_wrapper->gadget);
53811 + gadget_wrapper->driver = 0;
53813 + DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
53817 +EXPORT_SYMBOL(usb_gadget_unregister_driver);
53819 +#endif /* DWC_HOST_ONLY */
53820 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_regs.h b/drivers/usb/host/dwc_otg/dwc_otg_regs.h
53821 new file mode 100644
53822 index 0000000..0572642
53824 +++ b/drivers/usb/host/dwc_otg/dwc_otg_regs.h
53826 +/* ==========================================================================
53827 + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $
53828 + * $Revision: #98 $
53829 + * $Date: 2012/08/10 $
53830 + * $Change: 2047372 $
53832 + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
53833 + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
53834 + * otherwise expressly agreed to in writing between Synopsys and you.
53836 + * The Software IS NOT an item of Licensed Software or Licensed Product under
53837 + * any End User Software License Agreement or Agreement for Licensed Product
53838 + * with Synopsys or any supplement thereto. You are permitted to use and
53839 + * redistribute this Software in source and binary forms, with or without
53840 + * modification, provided that redistributions of source code must retain this
53841 + * notice. You may not view, use, disclose, copy or distribute this file or
53842 + * any information contained herein except pursuant to this license grant from
53843 + * Synopsys. If you do not agree with this notice, including the disclaimer
53844 + * below, then you are not authorized to use the Software.
53846 + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
53847 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53848 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53849 + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
53850 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53851 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53852 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
53853 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53854 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53855 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
53857 + * ========================================================================== */
53859 +#ifndef __DWC_OTG_REGS_H__
53860 +#define __DWC_OTG_REGS_H__
53862 +#include "dwc_otg_core_if.h"
53867 + * This file contains the data structures for accessing the DWC_otg core registers.
53869 + * The application interfaces with the HS OTG core by reading from and
53870 + * writing to the Control and Status Register (CSR) space through the
53871 + * AHB Slave interface. These registers are 32 bits wide, and the
53872 + * addresses are 32-bit-block aligned.
53873 + * CSRs are classified as follows:
53874 + * - Core Global Registers
53875 + * - Device Mode Registers
53876 + * - Device Global Registers
53877 + * - Device Endpoint Specific Registers
53878 + * - Host Mode Registers
53879 + * - Host Global Registers
53880 + * - Host Port CSRs
53881 + * - Host Channel Specific Registers
53883 + * Only the Core Global registers can be accessed in both Device and
53884 + * Host modes. When the HS OTG core is operating in one mode, either
53885 + * Device or Host, the application must not access registers from the
53886 + * other mode. When the core switches from one mode to another, the
53887 + * registers in the new mode of operation must be reprogrammed as they
53888 + * would be after a power-on reset.
53891 +/****************************************************************************/
53892 +/** DWC_otg Core registers .
53893 + * The dwc_otg_core_global_regs structure defines the size
53894 + * and relative field offsets for the Core Global registers.
53896 +typedef struct dwc_otg_core_global_regs {
53897 + /** OTG Control and Status Register. <i>Offset: 000h</i> */
53898 + volatile uint32_t gotgctl;
53899 + /** OTG Interrupt Register. <i>Offset: 004h</i> */
53900 + volatile uint32_t gotgint;
53901 + /**Core AHB Configuration Register. <i>Offset: 008h</i> */
53902 + volatile uint32_t gahbcfg;
53904 +#define DWC_GLBINTRMASK 0x0001
53905 +#define DWC_DMAENABLE 0x0020
53906 +#define DWC_NPTXEMPTYLVL_EMPTY 0x0080
53907 +#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000
53908 +#define DWC_PTXEMPTYLVL_EMPTY 0x0100
53909 +#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000
53911 + /**Core USB Configuration Register. <i>Offset: 00Ch</i> */
53912 + volatile uint32_t gusbcfg;
53913 + /**Core Reset Register. <i>Offset: 010h</i> */
53914 + volatile uint32_t grstctl;
53915 + /**Core Interrupt Register. <i>Offset: 014h</i> */
53916 + volatile uint32_t gintsts;
53917 + /**Core Interrupt Mask Register. <i>Offset: 018h</i> */
53918 + volatile uint32_t gintmsk;
53919 + /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */
53920 + volatile uint32_t grxstsr;
53921 + /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/
53922 + volatile uint32_t grxstsp;
53923 + /**Receive FIFO Size Register. <i>Offset: 024h</i> */
53924 + volatile uint32_t grxfsiz;
53925 + /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */
53926 + volatile uint32_t gnptxfsiz;
53927 + /**Non Periodic Transmit FIFO/Queue Status Register (Read
53928 + * Only). <i>Offset: 02Ch</i> */
53929 + volatile uint32_t gnptxsts;
53930 + /**I2C Access Register. <i>Offset: 030h</i> */
53931 + volatile uint32_t gi2cctl;
53932 + /**PHY Vendor Control Register. <i>Offset: 034h</i> */
53933 + volatile uint32_t gpvndctl;
53934 + /**General Purpose Input/Output Register. <i>Offset: 038h</i> */
53935 + volatile uint32_t ggpio;
53936 + /**User ID Register. <i>Offset: 03Ch</i> */
53937 + volatile uint32_t guid;
53938 + /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */
53939 + volatile uint32_t gsnpsid;
53940 + /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */
53941 + volatile uint32_t ghwcfg1;
53942 + /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */
53943 + volatile uint32_t ghwcfg2;
53944 +#define DWC_SLAVE_ONLY_ARCH 0
53945 +#define DWC_EXT_DMA_ARCH 1
53946 +#define DWC_INT_DMA_ARCH 2
53948 +#define DWC_MODE_HNP_SRP_CAPABLE 0
53949 +#define DWC_MODE_SRP_ONLY_CAPABLE 1
53950 +#define DWC_MODE_NO_HNP_SRP_CAPABLE 2
53951 +#define DWC_MODE_SRP_CAPABLE_DEVICE 3
53952 +#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4
53953 +#define DWC_MODE_SRP_CAPABLE_HOST 5
53954 +#define DWC_MODE_NO_SRP_CAPABLE_HOST 6
53956 + /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */
53957 + volatile uint32_t ghwcfg3;
53958 + /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/
53959 + volatile uint32_t ghwcfg4;
53960 + /** Core LPM Configuration register <i>Offset: 054h</i>*/
53961 + volatile uint32_t glpmcfg;
53962 + /** Global PowerDn Register <i>Offset: 058h</i> */
53963 + volatile uint32_t gpwrdn;
53964 + /** Global DFIFO SW Config Register <i>Offset: 05Ch</i> */
53965 + volatile uint32_t gdfifocfg;
53966 + /** ADP Control Register <i>Offset: 060h</i> */
53967 + volatile uint32_t adpctl;
53968 + /** Reserved <i>Offset: 064h-0FFh</i> */
53969 + volatile uint32_t reserved39[39];
53970 + /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */
53971 + volatile uint32_t hptxfsiz;
53972 + /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled,
53973 + otherwise Device Transmit FIFO#n Register.
53974 + * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */
53975 + volatile uint32_t dtxfsiz[15];
53976 +} dwc_otg_core_global_regs_t;
53979 + * This union represents the bit fields of the Core OTG Control
53980 + * and Status Register (GOTGCTL). Set the bits using the bit
53981 + * fields then write the <i>d32</i> value to the register.
53983 +typedef union gotgctl_data {
53984 + /** raw register data */
53986 + /** register bits */
53988 + unsigned sesreqscs:1;
53989 + unsigned sesreq:1;
53990 + unsigned vbvalidoven:1;
53991 + unsigned vbvalidovval:1;
53992 + unsigned avalidoven:1;
53993 + unsigned avalidovval:1;
53994 + unsigned bvalidoven:1;
53995 + unsigned bvalidovval:1;
53996 + unsigned hstnegscs:1;
53997 + unsigned hnpreq:1;
53998 + unsigned hstsethnpen:1;
53999 + unsigned devhnpen:1;
54000 + unsigned reserved12_15:4;
54001 + unsigned conidsts:1;
54002 + unsigned dbnctime:1;
54003 + unsigned asesvld:1;
54004 + unsigned bsesvld:1;
54005 + unsigned otgver:1;
54006 + unsigned reserved1:1;
54007 + unsigned multvalidbc:5;
54008 + unsigned chirpen:1;
54009 + unsigned reserved28_31:4;
54014 + * This union represents the bit fields of the Core OTG Interrupt Register
54015 + * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i>
54016 + * value to the register.
54018 +typedef union gotgint_data {
54019 + /** raw register data */
54021 + /** register bits */
54023 + /** Current Mode */
54024 + unsigned reserved0_1:2;
54026 + /** Session End Detected */
54027 + unsigned sesenddet:1;
54029 + unsigned reserved3_7:5;
54031 + /** Session Request Success Status Change */
54032 + unsigned sesreqsucstschng:1;
54033 + /** Host Negotiation Success Status Change */
54034 + unsigned hstnegsucstschng:1;
54036 + unsigned reserved10_16:7;
54038 + /** Host Negotiation Detected */
54039 + unsigned hstnegdet:1;
54040 + /** A-Device Timeout Change */
54041 + unsigned adevtoutchng:1;
54042 + /** Debounce Done */
54043 + unsigned debdone:1;
54044 + /** Multi-Valued input changed */
54047 + unsigned reserved31_21:11;
54053 + * This union represents the bit fields of the Core AHB Configuration
54054 + * Register (GAHBCFG). Set/clear the bits using the bit fields then
54055 + * write the <i>d32</i> value to the register.
54057 +typedef union gahbcfg_data {
54058 + /** raw register data */
54060 + /** register bits */
54062 + unsigned glblintrmsk:1;
54063 +#define DWC_GAHBCFG_GLBINT_ENABLE 1
54065 + unsigned hburstlen:4;
54066 +#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0
54067 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1
54068 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3
54069 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5
54070 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7
54072 + unsigned dmaenable:1;
54073 +#define DWC_GAHBCFG_DMAENABLE 1
54074 + unsigned reserved:1;
54075 + unsigned nptxfemplvl_txfemplvl:1;
54076 + unsigned ptxfemplvl:1;
54077 +#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1
54078 +#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0
54079 + unsigned reserved9_20:12;
54080 + unsigned remmemsupp:1;
54081 + unsigned notialldmawrit:1;
54082 + unsigned ahbsingle:1;
54083 + unsigned reserved24_31:8;
54088 + * This union represents the bit fields of the Core USB Configuration
54089 + * Register (GUSBCFG). Set the bits using the bit fields then write
54090 + * the <i>d32</i> value to the register.
54092 +typedef union gusbcfg_data {
54093 + /** raw register data */
54095 + /** register bits */
54097 + unsigned toutcal:3;
54098 + unsigned phyif:1;
54099 + unsigned ulpi_utmi_sel:1;
54100 + unsigned fsintf:1;
54101 + unsigned physel:1;
54102 + unsigned ddrsel:1;
54103 + unsigned srpcap:1;
54104 + unsigned hnpcap:1;
54105 + unsigned usbtrdtim:4;
54106 + unsigned reserved1:1;
54107 + unsigned phylpwrclksel:1;
54108 + unsigned otgutmifssel:1;
54109 + unsigned ulpi_fsls:1;
54110 + unsigned ulpi_auto_res:1;
54111 + unsigned ulpi_clk_sus_m:1;
54112 + unsigned ulpi_ext_vbus_drv:1;
54113 + unsigned ulpi_int_vbus_indicator:1;
54114 + unsigned term_sel_dl_pulse:1;
54115 + unsigned indicator_complement:1;
54116 + unsigned indicator_pass_through:1;
54117 + unsigned ulpi_int_prot_dis:1;
54118 + unsigned ic_usb_cap:1;
54119 + unsigned ic_traffic_pull_remove:1;
54120 + unsigned tx_end_delay:1;
54121 + unsigned force_host_mode:1;
54122 + unsigned force_dev_mode:1;
54123 + unsigned reserved31:1;
54128 + * This union represents the bit fields of the Core Reset Register
54129 + * (GRSTCTL). Set/clear the bits using the bit fields then write the
54130 + * <i>d32</i> value to the register.
54132 +typedef union grstctl_data {
54133 + /** raw register data */
54135 + /** register bits */
54137 + /** Core Soft Reset (CSftRst) (Device and Host)
54139 + * The application can flush the control logic in the
54140 + * entire core using this bit. This bit resets the
54141 + * pipelines in the AHB Clock domain as well as the
54142 + * PHY Clock domain.
54144 + * The state machines are reset to an IDLE state, the
54145 + * control bits in the CSRs are cleared, all the
54146 + * transmit FIFOs and the receive FIFO are flushed.
54148 + * The status mask bits that control the generation of
54149 + * the interrupt, are cleared, to clear the
54150 + * interrupt. The interrupt status bits are not
54151 + * cleared, so the application can get the status of
54152 + * any events that occurred in the core after it has
54155 + * Any transactions on the AHB are terminated as soon
54156 + * as possible following the protocol. Any
54157 + * transactions on the USB are terminated immediately.
54159 + * The configuration settings in the CSRs are
54160 + * unchanged, so the software doesn't have to
54161 + * reprogram these registers (Device
54162 + * Configuration/Host Configuration/Core System
54163 + * Configuration/Core PHY Configuration).
54165 + * The application can write to this bit, any time it
54166 + * wants to reset the core. This is a self clearing
54167 + * bit and the core clears this bit after all the
54168 + * necessary logic is reset in the core, which may
54169 + * take several clocks, depending on the current state
54172 + unsigned csftrst:1;
54173 + /** Hclk Soft Reset
54175 + * The application uses this bit to reset the control logic in
54176 + * the AHB clock domain. Only AHB clock domain pipelines are
54179 + unsigned hsftrst:1;
54180 + /** Host Frame Counter Reset (Host Only)<br>
54182 + * The application can reset the (micro)frame number
54183 + * counter inside the core, using this bit. When the
54184 + * (micro)frame counter is reset, the subsequent SOF
54185 + * sent out by the core, will have a (micro)frame
54188 + unsigned hstfrm:1;
54189 + /** In Token Sequence Learning Queue Flush
54190 + * (INTknQFlsh) (Device Only)
54192 + unsigned intknqflsh:1;
54193 + /** RxFIFO Flush (RxFFlsh) (Device and Host)
54195 + * The application can flush the entire Receive FIFO
54196 + * using this bit. The application must first
54197 + * ensure that the core is not in the middle of a
54198 + * transaction. The application should write into
54199 + * this bit, only after making sure that neither the
54200 + * DMA engine is reading from the RxFIFO nor the MAC
54201 + * is writing the data in to the FIFO. The
54202 + * application should wait until the bit is cleared
54203 + * before performing any other operations. This bit
54204 + * will takes 8 clocks (slowest of PHY or AHB clock)
54207 + unsigned rxfflsh:1;
54208 + /** TxFIFO Flush (TxFFlsh) (Device and Host).
54210 + * This bit is used to selectively flush a single or
54211 + * all transmit FIFOs. The application must first
54212 + * ensure that the core is not in the middle of a
54213 + * transaction. The application should write into
54214 + * this bit, only after making sure that neither the
54215 + * DMA engine is writing into the TxFIFO nor the MAC
54216 + * is reading the data out of the FIFO. The
54217 + * application should wait until the core clears this
54218 + * bit, before performing any operations. This bit
54219 + * will takes 8 clocks (slowest of PHY or AHB clock)
54222 + unsigned txfflsh:1;
54224 + /** TxFIFO Number (TxFNum) (Device and Host).
54226 + * This is the FIFO number which needs to be flushed,
54227 + * using the TxFIFO Flush bit. This field should not
54228 + * be changed until the TxFIFO Flush bit is cleared by
54230 + * - 0x0 : Non Periodic TxFIFO Flush
54231 + * - 0x1 : Periodic TxFIFO #1 Flush in device mode
54232 + * or Periodic TxFIFO in host mode
54233 + * - 0x2 : Periodic TxFIFO #2 Flush in device mode.
54235 + * - 0xF : Periodic TxFIFO #15 Flush in device mode
54236 + * - 0x10: Flush all the Transmit NonPeriodic and
54237 + * Transmit Periodic FIFOs in the core
54239 + unsigned txfnum:5;
54241 + unsigned reserved11_29:19;
54242 + /** DMA Request Signal. Indicated DMA request is in
54243 + * probress. Used for debug purpose. */
54244 + unsigned dmareq:1;
54245 + /** AHB Master Idle. Indicates the AHB Master State
54246 + * Machine is in IDLE condition. */
54247 + unsigned ahbidle:1;
54252 + * This union represents the bit fields of the Core Interrupt Mask
54253 + * Register (GINTMSK). Set/clear the bits using the bit fields then
54254 + * write the <i>d32</i> value to the register.
54256 +typedef union gintmsk_data {
54257 + /** raw register data */
54259 + /** register bits */
54261 + unsigned reserved0:1;
54262 + unsigned modemismatch:1;
54263 + unsigned otgintr:1;
54264 + unsigned sofintr:1;
54265 + unsigned rxstsqlvl:1;
54266 + unsigned nptxfempty:1;
54267 + unsigned ginnakeff:1;
54268 + unsigned goutnakeff:1;
54269 + unsigned ulpickint:1;
54270 + unsigned i2cintr:1;
54271 + unsigned erlysuspend:1;
54272 + unsigned usbsuspend:1;
54273 + unsigned usbreset:1;
54274 + unsigned enumdone:1;
54275 + unsigned isooutdrop:1;
54276 + unsigned eopframe:1;
54277 + unsigned restoredone:1;
54278 + unsigned epmismatch:1;
54279 + unsigned inepintr:1;
54280 + unsigned outepintr:1;
54281 + unsigned incomplisoin:1;
54282 + unsigned incomplisoout:1;
54283 + unsigned fetsusp:1;
54284 + unsigned resetdet:1;
54285 + unsigned portintr:1;
54286 + unsigned hcintr:1;
54287 + unsigned ptxfempty:1;
54288 + unsigned lpmtranrcvd:1;
54289 + unsigned conidstschng:1;
54290 + unsigned disconnect:1;
54291 + unsigned sessreqintr:1;
54292 + unsigned wkupintr:1;
54296 + * This union represents the bit fields of the Core Interrupt Register
54297 + * (GINTSTS). Set/clear the bits using the bit fields then write the
54298 + * <i>d32</i> value to the register.
54300 +typedef union gintsts_data {
54301 + /** raw register data */
54303 +#define DWC_SOF_INTR_MASK 0x0008
54304 + /** register bits */
54306 +#define DWC_HOST_MODE 1
54307 + unsigned curmode:1;
54308 + unsigned modemismatch:1;
54309 + unsigned otgintr:1;
54310 + unsigned sofintr:1;
54311 + unsigned rxstsqlvl:1;
54312 + unsigned nptxfempty:1;
54313 + unsigned ginnakeff:1;
54314 + unsigned goutnakeff:1;
54315 + unsigned ulpickint:1;
54316 + unsigned i2cintr:1;
54317 + unsigned erlysuspend:1;
54318 + unsigned usbsuspend:1;
54319 + unsigned usbreset:1;
54320 + unsigned enumdone:1;
54321 + unsigned isooutdrop:1;
54322 + unsigned eopframe:1;
54323 + unsigned restoredone:1;
54324 + unsigned epmismatch:1;
54325 + unsigned inepint:1;
54326 + unsigned outepintr:1;
54327 + unsigned incomplisoin:1;
54328 + unsigned incomplisoout:1;
54329 + unsigned fetsusp:1;
54330 + unsigned resetdet:1;
54331 + unsigned portintr:1;
54332 + unsigned hcintr:1;
54333 + unsigned ptxfempty:1;
54334 + unsigned lpmtranrcvd:1;
54335 + unsigned conidstschng:1;
54336 + unsigned disconnect:1;
54337 + unsigned sessreqintr:1;
54338 + unsigned wkupintr:1;
54343 + * This union represents the bit fields in the Device Receive Status Read and
54344 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
54345 + * element then read out the bits using the <i>b</i>it elements.
54347 +typedef union device_grxsts_data {
54348 + /** raw register data */
54350 + /** register bits */
54352 + unsigned epnum:4;
54353 + unsigned bcnt:11;
54356 +#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet
54357 +#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete
54359 +#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK
54360 +#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete
54361 +#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet
54362 + unsigned pktsts:4;
54364 + unsigned reserved25_31:7;
54366 +} device_grxsts_data_t;
54369 + * This union represents the bit fields in the Host Receive Status Read and
54370 + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
54371 + * element then read out the bits using the <i>b</i>it elements.
54373 +typedef union host_grxsts_data {
54374 + /** raw register data */
54376 + /** register bits */
54378 + unsigned chnum:4;
54379 + unsigned bcnt:11;
54382 + unsigned pktsts:4;
54383 +#define DWC_GRXSTS_PKTSTS_IN 0x2
54384 +#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3
54385 +#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
54386 +#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7
54388 + unsigned reserved21_31:11;
54390 +} host_grxsts_data_t;
54393 + * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ,
54394 + * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the <i>d32</i> element
54395 + * then read out the bits using the <i>b</i>it elements.
54397 +typedef union fifosize_data {
54398 + /** raw register data */
54400 + /** register bits */
54402 + unsigned startaddr:16;
54403 + unsigned depth:16;
54405 +} fifosize_data_t;
54408 + * This union represents the bit fields in the Non-Periodic Transmit
54409 + * FIFO/Queue Status Register (GNPTXSTS). Read the register into the
54410 + * <i>d32</i> element then read out the bits using the <i>b</i>it
54413 +typedef union gnptxsts_data {
54414 + /** raw register data */
54416 + /** register bits */
54418 + unsigned nptxfspcavail:16;
54419 + unsigned nptxqspcavail:8;
54420 + /** Top of the Non-Periodic Transmit Request Queue
54421 + * - bit 24 - Terminate (Last entry for the selected
54423 + * - bits 26:25 - Token Type
54424 + * - 2'b00 - IN/OUT
54425 + * - 2'b01 - Zero Length OUT
54426 + * - 2'b10 - PING/Complete Split
54427 + * - 2'b11 - Channel Halt
54428 + * - bits 30:27 - Channel/EP Number
54430 + unsigned nptxqtop_terminate:1;
54431 + unsigned nptxqtop_token:2;
54432 + unsigned nptxqtop_chnep:4;
54433 + unsigned reserved:1;
54435 +} gnptxsts_data_t;
54438 + * This union represents the bit fields in the Transmit
54439 + * FIFO Status Register (DTXFSTS). Read the register into the
54440 + * <i>d32</i> element then read out the bits using the <i>b</i>it
54443 +typedef union dtxfsts_data {
54444 + /** raw register data */
54446 + /** register bits */
54448 + unsigned txfspcavail:16;
54449 + unsigned reserved:16;
54454 + * This union represents the bit fields in the I2C Control Register
54455 + * (I2CCTL). Read the register into the <i>d32</i> element then read out the
54456 + * bits using the <i>b</i>it elements.
54458 +typedef union gi2cctl_data {
54459 + /** raw register data */
54461 + /** register bits */
54463 + unsigned rwdata:8;
54464 + unsigned regaddr:8;
54466 + unsigned i2cen:1;
54468 + unsigned i2csuspctl:1;
54469 + unsigned i2cdevaddr:2;
54470 + unsigned i2cdatse0:1;
54471 + unsigned reserved:1;
54473 + unsigned bsydne:1;
54478 + * This union represents the bit fields in the PHY Vendor Control Register
54479 + * (GPVNDCTL). Read the register into the <i>d32</i> element then read out the
54480 + * bits using the <i>b</i>it elements.
54482 +typedef union gpvndctl_data {
54483 + /** raw register data */
54485 + /** register bits */
54487 + unsigned regdata:8;
54488 + unsigned vctrl:8;
54489 + unsigned regaddr16_21:6;
54490 + unsigned regwr:1;
54491 + unsigned reserved23_24:2;
54492 + unsigned newregreq:1;
54493 + unsigned vstsbsy:1;
54494 + unsigned vstsdone:1;
54495 + unsigned reserved28_30:3;
54496 + unsigned disulpidrvr:1;
54498 +} gpvndctl_data_t;
54501 + * This union represents the bit fields in the General Purpose
54502 + * Input/Output Register (GGPIO).
54503 + * Read the register into the <i>d32</i> element then read out the
54504 + * bits using the <i>b</i>it elements.
54506 +typedef union ggpio_data {
54507 + /** raw register data */
54509 + /** register bits */
54517 + * This union represents the bit fields in the User ID Register
54518 + * (GUID). Read the register into the <i>d32</i> element then read out the
54519 + * bits using the <i>b</i>it elements.
54521 +typedef union guid_data {
54522 + /** raw register data */
54524 + /** register bits */
54526 + unsigned rwdata:32;
54531 + * This union represents the bit fields in the Synopsys ID Register
54532 + * (GSNPSID). Read the register into the <i>d32</i> element then read out the
54533 + * bits using the <i>b</i>it elements.
54535 +typedef union gsnpsid_data {
54536 + /** raw register data */
54538 + /** register bits */
54540 + unsigned rwdata:32;
54545 + * This union represents the bit fields in the User HW Config1
54546 + * Register. Read the register into the <i>d32</i> element then read
54547 + * out the bits using the <i>b</i>it elements.
54549 +typedef union hwcfg1_data {
54550 + /** raw register data */
54552 + /** register bits */
54554 + unsigned ep_dir0:2;
54555 + unsigned ep_dir1:2;
54556 + unsigned ep_dir2:2;
54557 + unsigned ep_dir3:2;
54558 + unsigned ep_dir4:2;
54559 + unsigned ep_dir5:2;
54560 + unsigned ep_dir6:2;
54561 + unsigned ep_dir7:2;
54562 + unsigned ep_dir8:2;
54563 + unsigned ep_dir9:2;
54564 + unsigned ep_dir10:2;
54565 + unsigned ep_dir11:2;
54566 + unsigned ep_dir12:2;
54567 + unsigned ep_dir13:2;
54568 + unsigned ep_dir14:2;
54569 + unsigned ep_dir15:2;
54574 + * This union represents the bit fields in the User HW Config2
54575 + * Register. Read the register into the <i>d32</i> element then read
54576 + * out the bits using the <i>b</i>it elements.
54578 +typedef union hwcfg2_data {
54579 + /** raw register data */
54581 + /** register bits */
54584 + unsigned op_mode:3;
54585 +#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
54586 +#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
54587 +#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
54588 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
54589 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
54590 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
54591 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
54593 + unsigned architecture:2;
54594 + unsigned point2point:1;
54595 + unsigned hs_phy_type:2;
54596 +#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
54597 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
54598 +#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
54599 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
54601 + unsigned fs_phy_type:2;
54602 + unsigned num_dev_ep:4;
54603 + unsigned num_host_chan:4;
54604 + unsigned perio_ep_supported:1;
54605 + unsigned dynamic_fifo:1;
54606 + unsigned multi_proc_int:1;
54607 + unsigned reserved21:1;
54608 + unsigned nonperio_tx_q_depth:2;
54609 + unsigned host_perio_tx_q_depth:2;
54610 + unsigned dev_token_q_depth:5;
54611 + unsigned otg_enable_ic_usb:1;
54616 + * This union represents the bit fields in the User HW Config3
54617 + * Register. Read the register into the <i>d32</i> element then read
54618 + * out the bits using the <i>b</i>it elements.
54620 +typedef union hwcfg3_data {
54621 + /** raw register data */
54623 + /** register bits */
54626 + unsigned xfer_size_cntr_width:4;
54627 + unsigned packet_size_cntr_width:3;
54628 + unsigned otg_func:1;
54630 + unsigned vendor_ctrl_if:1;
54631 + unsigned optional_features:1;
54632 + unsigned synch_reset_type:1;
54633 + unsigned adp_supp:1;
54634 + unsigned otg_enable_hsic:1;
54635 + unsigned bc_support:1;
54636 + unsigned otg_lpm_en:1;
54637 + unsigned dfifo_depth:16;
54642 + * This union represents the bit fields in the User HW Config4
54643 + * Register. Read the register into the <i>d32</i> element then read
54644 + * out the bits using the <i>b</i>it elements.
54646 +typedef union hwcfg4_data {
54647 + /** raw register data */
54649 + /** register bits */
54651 + unsigned num_dev_perio_in_ep:4;
54652 + unsigned power_optimiz:1;
54653 + unsigned min_ahb_freq:1;
54654 + unsigned hiber:1;
54655 + unsigned xhiber:1;
54656 + unsigned reserved:6;
54657 + unsigned utmi_phy_data_width:2;
54658 + unsigned num_dev_mode_ctrl_ep:4;
54659 + unsigned iddig_filt_en:1;
54660 + unsigned vbus_valid_filt_en:1;
54661 + unsigned a_valid_filt_en:1;
54662 + unsigned b_valid_filt_en:1;
54663 + unsigned session_end_filt_en:1;
54664 + unsigned ded_fifo_en:1;
54665 + unsigned num_in_eps:4;
54666 + unsigned desc_dma:1;
54667 + unsigned desc_dma_dyn:1;
54672 + * This union represents the bit fields of the Core LPM Configuration
54673 + * Register (GLPMCFG). Set the bits using bit fields then write
54674 + * the <i>d32</i> value to the register.
54676 +typedef union glpmctl_data {
54677 + /** raw register data */
54679 + /** register bits */
54681 + /** LPM-Capable (LPMCap) (Device and Host)
54682 + * The application uses this bit to control
54683 + * the DWC_otg core LPM capabilities.
54685 + unsigned lpm_cap_en:1;
54686 + /** LPM response programmed by application (AppL1Res) (Device)
54687 + * Handshake response to LPM token pre-programmed
54688 + * by device application software.
54690 + unsigned appl_resp:1;
54691 + /** Host Initiated Resume Duration (HIRD) (Device and Host)
54692 + * In Host mode this field indicates the value of HIRD
54693 + * to be sent in an LPM transaction.
54694 + * In Device mode this field is updated with the
54695 + * Received LPM Token HIRD bmAttribute
54696 + * when an ACK/NYET/STALL response is sent
54697 + * to an LPM transaction.
54700 + /** RemoteWakeEnable (bRemoteWake) (Device and Host)
54701 + * In Host mode this bit indicates the value of remote
54702 + * wake up to be sent in wIndex field of LPM transaction.
54703 + * In Device mode this field is updated with the
54704 + * Received LPM Token bRemoteWake bmAttribute
54705 + * when an ACK/NYET/STALL response is sent
54706 + * to an LPM transaction.
54708 + unsigned rem_wkup_en:1;
54709 + /** Enable utmi_sleep_n (EnblSlpM) (Device and Host)
54710 + * The application uses this bit to control
54711 + * the utmi_sleep_n assertion to the PHY when in L1 state.
54713 + unsigned en_utmi_sleep:1;
54714 + /** HIRD Threshold (HIRD_Thres) (Device and Host)
54716 + unsigned hird_thres:5;
54717 + /** LPM Response (CoreL1Res) (Device and Host)
54718 + * In Host mode this bit contains handsake response to
54719 + * LPM transaction.
54720 + * In Device mode the response of the core to
54721 + * LPM transaction received is reflected in these two bits.
54722 + - 0x0 : ERROR (No handshake response)
54727 + unsigned lpm_resp:2;
54728 + /** Port Sleep Status (SlpSts) (Device and Host)
54729 + * This bit is set as long as a Sleep condition
54730 + * is present on the USB bus.
54732 + unsigned prt_sleep_sts:1;
54733 + /** Sleep State Resume OK (L1ResumeOK) (Device and Host)
54734 + * Indicates that the application or host
54735 + * can start resume from Sleep state.
54737 + unsigned sleep_state_resumeok:1;
54738 + /** LPM channel Index (LPM_Chnl_Indx) (Host)
54739 + * The channel number on which the LPM transaction
54740 + * has to be applied while sending
54741 + * an LPM transaction to the local device.
54743 + unsigned lpm_chan_index:4;
54744 + /** LPM Retry Count (LPM_Retry_Cnt) (Host)
54745 + * Number host retries that would be performed
54746 + * if the device response was not valid response.
54748 + unsigned retry_count:3;
54749 + /** Send LPM Transaction (SndLPM) (Host)
54750 + * When set by application software,
54751 + * an LPM transaction containing two tokens
54754 + unsigned send_lpm:1;
54755 + /** LPM Retry status (LPM_RetryCnt_Sts) (Host)
54756 + * Number of LPM Host Retries still remaining
54757 + * to be transmitted for the current LPM sequence
54759 + unsigned retry_count_sts:3;
54760 + unsigned reserved28_29:2;
54761 + /** In host mode once this bit is set, the host
54762 + * configures to drive the HSIC Idle state on the bus.
54763 + * It then waits for the device to initiate the Connect sequence.
54764 + * In device mode once this bit is set, the device waits for
54765 + * the HSIC Idle line state on the bus. Upon receving the Idle
54766 + * line state, it initiates the HSIC Connect sequence.
54768 + unsigned hsic_connect:1;
54769 + /** This bit overrides and functionally inverts
54770 + * the if_select_hsic input port signal.
54772 + unsigned inv_sel_hsic:1;
54777 + * This union represents the bit fields of the Core ADP Timer, Control and
54778 + * Status Register (ADPTIMCTLSTS). Set the bits using bit fields then write
54779 + * the <i>d32</i> value to the register.
54781 +typedef union adpctl_data {
54782 + /** raw register data */
54784 + /** register bits */
54786 + /** Probe Discharge (PRB_DSCHG)
54787 + * These bits set the times for TADP_DSCHG.
54788 + * These bits are defined as follows:
54791 + * 2'b10 - 16 msec
54792 + * 2'b11 - 32 msec
54794 + unsigned prb_dschg:2;
54795 + /** Probe Delta (PRB_DELTA)
54796 + * These bits set the resolution for RTIM value.
54797 + * The bits are defined in units of 32 kHz clock cycles as follows:
54798 + * 2'b00 - 1 cycles
54799 + * 2'b01 - 2 cycles
54800 + * 2'b10 - 3 cycles
54801 + * 2'b11 - 4 cycles
54802 + * For example if this value is chosen to 2'b01, it means that RTIM
54803 + * increments for every 3(three) 32Khz clock cycles.
54805 + unsigned prb_delta:2;
54806 + /** Probe Period (PRB_PER)
54807 + * These bits sets the TADP_PRD as shown in Figure 4 as follows:
54808 + * 2'b00 - 0.625 to 0.925 sec (typical 0.775 sec)
54809 + * 2'b01 - 1.25 to 1.85 sec (typical 1.55 sec)
54810 + * 2'b10 - 1.9 to 2.6 sec (typical 2.275 sec)
54811 + * 2'b11 - Reserved
54813 + unsigned prb_per:2;
54814 + /** These bits capture the latest time it took for VBUS to ramp from
54815 + * VADP_SINK to VADP_PRB.
54816 + * 0x000 - 1 cycles
54817 + * 0x001 - 2 cycles
54818 + * 0x002 - 3 cycles
54820 + * 0x7FF - 2048 cycles
54821 + * A time of 1024 cycles at 32 kHz corresponds to a time of 32 msec.
54823 + unsigned rtim:11;
54824 + /** Enable Probe (EnaPrb)
54825 + * When programmed to 1'b1, the core performs a probe operation.
54826 + * This bit is valid only if OTG_Ver = 1'b1.
54828 + unsigned enaprb:1;
54829 + /** Enable Sense (EnaSns)
54830 + * When programmed to 1'b1, the core performs a Sense operation.
54831 + * This bit is valid only if OTG_Ver = 1'b1.
54833 + unsigned enasns:1;
54834 + /** ADP Reset (ADPRes)
54835 + * When set, ADP controller is reset.
54836 + * This bit is valid only if OTG_Ver = 1'b1.
54838 + unsigned adpres:1;
54839 + /** ADP Enable (ADPEn)
54840 + * When set, the core performs either ADP probing or sensing
54841 + * based on EnaPrb or EnaSns.
54842 + * This bit is valid only if OTG_Ver = 1'b1.
54844 + unsigned adpen:1;
54845 + /** ADP Probe Interrupt (ADP_PRB_INT)
54846 + * When this bit is set, it means that the VBUS
54847 + * voltage is greater than VADP_PRB or VADP_PRB is reached.
54848 + * This bit is valid only if OTG_Ver = 1'b1.
54850 + unsigned adp_prb_int:1;
54852 + * ADP Sense Interrupt (ADP_SNS_INT)
54853 + * When this bit is set, it means that the VBUS voltage is greater than
54854 + * VADP_SNS value or VADP_SNS is reached.
54855 + * This bit is valid only if OTG_Ver = 1'b1.
54857 + unsigned adp_sns_int:1;
54858 + /** ADP Tomeout Interrupt (ADP_TMOUT_INT)
54859 + * This bit is relevant only for an ADP probe.
54860 + * When this bit is set, it means that the ramp time has
54861 + * completed ie ADPCTL.RTIM has reached its terminal value
54862 + * of 0x7FF. This is a debug feature that allows software
54863 + * to read the ramp time after each cycle.
54864 + * This bit is valid only if OTG_Ver = 1'b1.
54866 + unsigned adp_tmout_int:1;
54867 + /** ADP Probe Interrupt Mask (ADP_PRB_INT_MSK)
54868 + * When this bit is set, it unmasks the interrupt due to ADP_PRB_INT.
54869 + * This bit is valid only if OTG_Ver = 1'b1.
54871 + unsigned adp_prb_int_msk:1;
54872 + /** ADP Sense Interrupt Mask (ADP_SNS_INT_MSK)
54873 + * When this bit is set, it unmasks the interrupt due to ADP_SNS_INT.
54874 + * This bit is valid only if OTG_Ver = 1'b1.
54876 + unsigned adp_sns_int_msk:1;
54877 + /** ADP Timoeout Interrupt Mask (ADP_TMOUT_MSK)
54878 + * When this bit is set, it unmasks the interrupt due to ADP_TMOUT_INT.
54879 + * This bit is valid only if OTG_Ver = 1'b1.
54881 + unsigned adp_tmout_int_msk:1;
54882 + /** Access Request
54883 + * 2'b00 - Read/Write Valid (updated by the core)
54886 + * 2'b00 - Reserved
54890 + unsigned reserved29_31:3;
54894 +////////////////////////////////////////////
54895 +// Device Registers
54897 + * Device Global Registers. <i>Offsets 800h-BFFh</i>
54899 + * The following structures define the size and relative field offsets
54900 + * for the Device Mode Registers.
54902 + * <i>These registers are visible only in Device mode and must not be
54903 + * accessed in Host mode, as the results are unknown.</i>
54905 +typedef struct dwc_otg_dev_global_regs {
54906 + /** Device Configuration Register. <i>Offset 800h</i> */
54907 + volatile uint32_t dcfg;
54908 + /** Device Control Register. <i>Offset: 804h</i> */
54909 + volatile uint32_t dctl;
54910 + /** Device Status Register (Read Only). <i>Offset: 808h</i> */
54911 + volatile uint32_t dsts;
54912 + /** Reserved. <i>Offset: 80Ch</i> */
54914 + /** Device IN Endpoint Common Interrupt Mask
54915 + * Register. <i>Offset: 810h</i> */
54916 + volatile uint32_t diepmsk;
54917 + /** Device OUT Endpoint Common Interrupt Mask
54918 + * Register. <i>Offset: 814h</i> */
54919 + volatile uint32_t doepmsk;
54920 + /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */
54921 + volatile uint32_t daint;
54922 + /** Device All Endpoints Interrupt Mask Register. <i>Offset:
54924 + volatile uint32_t daintmsk;
54925 + /** Device IN Token Queue Read Register-1 (Read Only).
54926 + * <i>Offset: 820h</i> */
54927 + volatile uint32_t dtknqr1;
54928 + /** Device IN Token Queue Read Register-2 (Read Only).
54929 + * <i>Offset: 824h</i> */
54930 + volatile uint32_t dtknqr2;
54931 + /** Device VBUS discharge Register. <i>Offset: 828h</i> */
54932 + volatile uint32_t dvbusdis;
54933 + /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */
54934 + volatile uint32_t dvbuspulse;
54935 + /** Device IN Token Queue Read Register-3 (Read Only). /
54936 + * Device Thresholding control register (Read/Write)
54937 + * <i>Offset: 830h</i> */
54938 + volatile uint32_t dtknqr3_dthrctl;
54939 + /** Device IN Token Queue Read Register-4 (Read Only). /
54940 + * Device IN EPs empty Inr. Mask Register (Read/Write)
54941 + * <i>Offset: 834h</i> */
54942 + volatile uint32_t dtknqr4_fifoemptymsk;
54943 + /** Device Each Endpoint Interrupt Register (Read Only). /
54944 + * <i>Offset: 838h</i> */
54945 + volatile uint32_t deachint;
54946 + /** Device Each Endpoint Interrupt mask Register (Read/Write). /
54947 + * <i>Offset: 83Ch</i> */
54948 + volatile uint32_t deachintmsk;
54949 + /** Device Each In Endpoint Interrupt mask Register (Read/Write). /
54950 + * <i>Offset: 840h</i> */
54951 + volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS];
54952 + /** Device Each Out Endpoint Interrupt mask Register (Read/Write). /
54953 + * <i>Offset: 880h</i> */
54954 + volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS];
54955 +} dwc_otg_device_global_regs_t;
54958 + * This union represents the bit fields in the Device Configuration
54959 + * Register. Read the register into the <i>d32</i> member then
54960 + * set/clear the bits using the <i>b</i>it elements. Write the
54961 + * <i>d32</i> member to the dcfg register.
54963 +typedef union dcfg_data {
54964 + /** raw register data */
54966 + /** register bits */
54968 + /** Device Speed */
54969 + unsigned devspd:2;
54970 + /** Non Zero Length Status OUT Handshake */
54971 + unsigned nzstsouthshk:1;
54972 +#define DWC_DCFG_SEND_STALL 1
54974 + unsigned ena32khzs:1;
54975 + /** Device Addresses */
54976 + unsigned devaddr:7;
54977 + /** Periodic Frame Interval */
54978 + unsigned perfrint:2;
54979 +#define DWC_DCFG_FRAME_INTERVAL_80 0
54980 +#define DWC_DCFG_FRAME_INTERVAL_85 1
54981 +#define DWC_DCFG_FRAME_INTERVAL_90 2
54982 +#define DWC_DCFG_FRAME_INTERVAL_95 3
54984 + /** Enable Device OUT NAK for bulk in DDMA mode */
54985 + unsigned endevoutnak:1;
54987 + unsigned reserved14_17:4;
54988 + /** In Endpoint Mis-match count */
54989 + unsigned epmscnt:5;
54990 + /** Enable Descriptor DMA in Device mode */
54991 + unsigned descdma:1;
54992 + unsigned perschintvl:2;
54993 + unsigned resvalid:6;
54998 + * This union represents the bit fields in the Device Control
54999 + * Register. Read the register into the <i>d32</i> member then
55000 + * set/clear the bits using the <i>b</i>it elements.
55002 +typedef union dctl_data {
55003 + /** raw register data */
55005 + /** register bits */
55007 + /** Remote Wakeup */
55008 + unsigned rmtwkupsig:1;
55009 + /** Soft Disconnect */
55010 + unsigned sftdiscon:1;
55011 + /** Global Non-Periodic IN NAK Status */
55012 + unsigned gnpinnaksts:1;
55013 + /** Global OUT NAK Status */
55014 + unsigned goutnaksts:1;
55015 + /** Test Control */
55016 + unsigned tstctl:3;
55017 + /** Set Global Non-Periodic IN NAK */
55018 + unsigned sgnpinnak:1;
55019 + /** Clear Global Non-Periodic IN NAK */
55020 + unsigned cgnpinnak:1;
55021 + /** Set Global OUT NAK */
55022 + unsigned sgoutnak:1;
55023 + /** Clear Global OUT NAK */
55024 + unsigned cgoutnak:1;
55025 + /** Power-On Programming Done */
55026 + unsigned pwronprgdone:1;
55028 + unsigned reserved:1;
55029 + /** Global Multi Count */
55031 + /** Ignore Frame Number for ISOC EPs */
55032 + unsigned ifrmnum:1;
55033 + /** NAK on Babble */
55034 + unsigned nakonbble:1;
55035 + /** Enable Continue on BNA */
55036 + unsigned encontonbna:1;
55038 + unsigned reserved18_31:14;
55043 + * This union represents the bit fields in the Device Status
55044 + * Register. Read the register into the <i>d32</i> member then
55045 + * set/clear the bits using the <i>b</i>it elements.
55047 +typedef union dsts_data {
55048 + /** raw register data */
55050 + /** register bits */
55052 + /** Suspend Status */
55053 + unsigned suspsts:1;
55054 + /** Enumerated Speed */
55055 + unsigned enumspd:2;
55056 +#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
55057 +#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
55058 +#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2
55059 +#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3
55060 + /** Erratic Error */
55061 + unsigned errticerr:1;
55062 + unsigned reserved4_7:4;
55063 + /** Frame or Microframe Number of the received SOF */
55064 + unsigned soffn:14;
55065 + unsigned reserved22_31:10;
55070 + * This union represents the bit fields in the Device IN EP Interrupt
55071 + * Register and the Device IN EP Common Mask Register.
55073 + * - Read the register into the <i>d32</i> member then set/clear the
55074 + * bits using the <i>b</i>it elements.
55076 +typedef union diepint_data {
55077 + /** raw register data */
55079 + /** register bits */
55081 + /** Transfer complete mask */
55082 + unsigned xfercompl:1;
55083 + /** Endpoint disable mask */
55084 + unsigned epdisabled:1;
55085 + /** AHB Error mask */
55086 + unsigned ahberr:1;
55087 + /** TimeOUT Handshake mask (non-ISOC EPs) */
55088 + unsigned timeout:1;
55089 + /** IN Token received with TxF Empty mask */
55090 + unsigned intktxfemp:1;
55091 + /** IN Token Received with EP mismatch mask */
55092 + unsigned intknepmis:1;
55093 + /** IN Endpoint NAK Effective mask */
55094 + unsigned inepnakeff:1;
55096 + unsigned emptyintr:1;
55098 + unsigned txfifoundrn:1;
55100 + /** BNA Interrupt mask */
55103 + unsigned reserved10_12:3;
55104 + /** BNA Interrupt mask */
55107 + unsigned reserved14_31:18;
55112 + * This union represents the bit fields in the Device IN EP
55113 + * Common/Dedicated Interrupt Mask Register.
55115 +typedef union diepint_data diepmsk_data_t;
55118 + * This union represents the bit fields in the Device OUT EP Interrupt
55119 + * Registerand Device OUT EP Common Interrupt Mask Register.
55121 + * - Read the register into the <i>d32</i> member then set/clear the
55122 + * bits using the <i>b</i>it elements.
55124 +typedef union doepint_data {
55125 + /** raw register data */
55127 + /** register bits */
55129 + /** Transfer complete */
55130 + unsigned xfercompl:1;
55131 + /** Endpoint disable */
55132 + unsigned epdisabled:1;
55134 + unsigned ahberr:1;
55135 + /** Setup Phase Done (contorl EPs) */
55136 + unsigned setup:1;
55137 + /** OUT Token Received when Endpoint Disabled */
55138 + unsigned outtknepdis:1;
55140 + unsigned stsphsercvd:1;
55141 + /** Back-to-Back SETUP Packets Received */
55142 + unsigned back2backsetup:1;
55144 + unsigned reserved7:1;
55145 + /** OUT packet Error */
55146 + unsigned outpkterr:1;
55147 + /** BNA Interrupt */
55150 + unsigned reserved10:1;
55151 + /** Packet Drop Status */
55152 + unsigned pktdrpsts:1;
55153 + /** Babble Interrupt */
55154 + unsigned babble:1;
55155 + /** NAK Interrupt */
55157 + /** NYET Interrupt */
55159 + /** Bit indicating setup packet received */
55162 + unsigned reserved16_31:16;
55167 + * This union represents the bit fields in the Device OUT EP
55168 + * Common/Dedicated Interrupt Mask Register.
55170 +typedef union doepint_data doepmsk_data_t;
55173 + * This union represents the bit fields in the Device All EP Interrupt
55174 + * and Mask Registers.
55175 + * - Read the register into the <i>d32</i> member then set/clear the
55176 + * bits using the <i>b</i>it elements.
55178 +typedef union daint_data {
55179 + /** raw register data */
55181 + /** register bits */
55183 + /** IN Endpoint bits */
55185 + /** OUT Endpoint bits */
55189 + /** IN Endpoint bits */
55190 + unsigned inep0:1;
55191 + unsigned inep1:1;
55192 + unsigned inep2:1;
55193 + unsigned inep3:1;
55194 + unsigned inep4:1;
55195 + unsigned inep5:1;
55196 + unsigned inep6:1;
55197 + unsigned inep7:1;
55198 + unsigned inep8:1;
55199 + unsigned inep9:1;
55200 + unsigned inep10:1;
55201 + unsigned inep11:1;
55202 + unsigned inep12:1;
55203 + unsigned inep13:1;
55204 + unsigned inep14:1;
55205 + unsigned inep15:1;
55206 + /** OUT Endpoint bits */
55207 + unsigned outep0:1;
55208 + unsigned outep1:1;
55209 + unsigned outep2:1;
55210 + unsigned outep3:1;
55211 + unsigned outep4:1;
55212 + unsigned outep5:1;
55213 + unsigned outep6:1;
55214 + unsigned outep7:1;
55215 + unsigned outep8:1;
55216 + unsigned outep9:1;
55217 + unsigned outep10:1;
55218 + unsigned outep11:1;
55219 + unsigned outep12:1;
55220 + unsigned outep13:1;
55221 + unsigned outep14:1;
55222 + unsigned outep15:1;
55227 + * This union represents the bit fields in the Device IN Token Queue
55228 + * Read Registers.
55229 + * - Read the register into the <i>d32</i> member.
55230 + * - READ-ONLY Register
55232 +typedef union dtknq1_data {
55233 + /** raw register data */
55235 + /** register bits */
55237 + /** In Token Queue Write Pointer */
55238 + unsigned intknwptr:5;
55240 + unsigned reserved05_06:2;
55241 + /** write pointer has wrapped. */
55242 + unsigned wrap_bit:1;
55243 + /** EP Numbers of IN Tokens 0 ... 4 */
55244 + unsigned epnums0_5:24;
55249 + * This union represents Threshold control Register
55250 + * - Read and write the register into the <i>d32</i> member.
55251 + * - READ-WRITABLE Register
55253 +typedef union dthrctl_data {
55254 + /** raw register data */
55256 + /** register bits */
55258 + /** non ISO Tx Thr. Enable */
55259 + unsigned non_iso_thr_en:1;
55260 + /** ISO Tx Thr. Enable */
55261 + unsigned iso_thr_en:1;
55262 + /** Tx Thr. Length */
55263 + unsigned tx_thr_len:9;
55264 + /** AHB Threshold ratio */
55265 + unsigned ahb_thr_ratio:2;
55267 + unsigned reserved13_15:3;
55268 + /** Rx Thr. Enable */
55269 + unsigned rx_thr_en:1;
55270 + /** Rx Thr. Length */
55271 + unsigned rx_thr_len:9;
55272 + unsigned reserved26:1;
55273 + /** Arbiter Parking Enable*/
55274 + unsigned arbprken:1;
55276 + unsigned reserved28_31:4;
55281 + * Device Logical IN Endpoint-Specific Registers. <i>Offsets
55284 + * There will be one set of endpoint registers per logical endpoint
55287 + * <i>These registers are visible only in Device mode and must not be
55288 + * accessed in Host mode, as the results are unknown.</i>
55290 +typedef struct dwc_otg_dev_in_ep_regs {
55291 + /** Device IN Endpoint Control Register. <i>Offset:900h +
55292 + * (ep_num * 20h) + 00h</i> */
55293 + volatile uint32_t diepctl;
55294 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */
55295 + uint32_t reserved04;
55296 + /** Device IN Endpoint Interrupt Register. <i>Offset:900h +
55297 + * (ep_num * 20h) + 08h</i> */
55298 + volatile uint32_t diepint;
55299 + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */
55300 + uint32_t reserved0C;
55301 + /** Device IN Endpoint Transfer Size
55302 + * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */
55303 + volatile uint32_t dieptsiz;
55304 + /** Device IN Endpoint DMA Address Register. <i>Offset:900h +
55305 + * (ep_num * 20h) + 14h</i> */
55306 + volatile uint32_t diepdma;
55307 + /** Device IN Endpoint Transmit FIFO Status Register. <i>Offset:900h +
55308 + * (ep_num * 20h) + 18h</i> */
55309 + volatile uint32_t dtxfsts;
55310 + /** Device IN Endpoint DMA Buffer Register. <i>Offset:900h +
55311 + * (ep_num * 20h) + 1Ch</i> */
55312 + volatile uint32_t diepdmab;
55313 +} dwc_otg_dev_in_ep_regs_t;
55316 + * Device Logical OUT Endpoint-Specific Registers. <i>Offsets:
55319 + * There will be one set of endpoint registers per logical endpoint
55322 + * <i>These registers are visible only in Device mode and must not be
55323 + * accessed in Host mode, as the results are unknown.</i>
55325 +typedef struct dwc_otg_dev_out_ep_regs {
55326 + /** Device OUT Endpoint Control Register. <i>Offset:B00h +
55327 + * (ep_num * 20h) + 00h</i> */
55328 + volatile uint32_t doepctl;
55329 + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 04h</i> */
55330 + uint32_t reserved04;
55331 + /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h +
55332 + * (ep_num * 20h) + 08h</i> */
55333 + volatile uint32_t doepint;
55334 + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */
55335 + uint32_t reserved0C;
55336 + /** Device OUT Endpoint Transfer Size Register. <i>Offset:
55337 + * B00h + (ep_num * 20h) + 10h</i> */
55338 + volatile uint32_t doeptsiz;
55339 + /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h
55340 + * + (ep_num * 20h) + 14h</i> */
55341 + volatile uint32_t doepdma;
55342 + /** Reserved. <i>Offset:B00h + * (ep_num * 20h) + 18h</i> */
55344 + /** Device OUT Endpoint DMA Buffer Register. <i>Offset:B00h
55345 + * + (ep_num * 20h) + 1Ch</i> */
55346 + uint32_t doepdmab;
55347 +} dwc_otg_dev_out_ep_regs_t;
55350 + * This union represents the bit fields in the Device EP Control
55351 + * Register. Read the register into the <i>d32</i> member then
55352 + * set/clear the bits using the <i>b</i>it elements.
55354 +typedef union depctl_data {
55355 + /** raw register data */
55357 + /** register bits */
55359 + /** Maximum Packet Size
55361 + * IN/OUT EP0 - 2 bits
55362 + * 2'b00: 64 Bytes
55367 +#define DWC_DEP0CTL_MPS_64 0
55368 +#define DWC_DEP0CTL_MPS_32 1
55369 +#define DWC_DEP0CTL_MPS_16 2
55370 +#define DWC_DEP0CTL_MPS_8 3
55372 + /** Next Endpoint
55374 + * OUT EPn/OUT EP0 - reserved */
55375 + unsigned nextep:4;
55377 + /** USB Active Endpoint */
55378 + unsigned usbactep:1;
55380 + /** Endpoint DPID (INTR/Bulk IN and OUT endpoints)
55381 + * This field contains the PID of the packet going to
55382 + * be received or transmitted on this endpoint. The
55383 + * application should program the PID of the first
55384 + * packet going to be received or transmitted on this
55385 + * endpoint , after the endpoint is
55386 + * activated. Application use the SetD1PID and
55387 + * SetD0PID fields of this register to program either
55390 + * The encoding for this field is
55396 + /** NAK Status */
55397 + unsigned naksts:1;
55399 + /** Endpoint Type
55401 + * 2'b01: Isochronous
55403 + * 2'b11: Interrupt */
55404 + unsigned eptype:2;
55407 + * OUT EPn/OUT EP0
55408 + * IN EPn/IN EP0 - reserved */
55411 + /** Stall Handshake */
55412 + unsigned stall:1;
55414 + /** Tx Fifo Number
55416 + * OUT EPn/OUT EP0 - reserved */
55417 + unsigned txfnum:4;
55423 + /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints)
55424 + * Writing to this field sets the Endpoint DPID (DPID)
55425 + * field in this register to DATA0. Set Even
55426 + * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints)
55427 + * Writing to this field sets the Even/Odd
55428 + * (micro)frame (EO_FrNum) field to even (micro)
55431 + unsigned setd0pid:1;
55432 + /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints)
55433 + * Writing to this field sets the Endpoint DPID (DPID)
55434 + * field in this register to DATA1 Set Odd
55435 + * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints)
55436 + * Writing to this field sets the Even/Odd
55437 + * (micro)frame (EO_FrNum) field to odd (micro) frame.
55439 + unsigned setd1pid:1;
55441 + /** Endpoint Disable */
55442 + unsigned epdis:1;
55443 + /** Endpoint Enable */
55444 + unsigned epena:1;
55449 + * This union represents the bit fields in the Device EP Transfer
55450 + * Size Register. Read the register into the <i>d32</i> member then
55451 + * set/clear the bits using the <i>b</i>it elements.
55453 +typedef union deptsiz_data {
55454 + /** raw register data */
55456 + /** register bits */
55458 + /** Transfer size */
55459 + unsigned xfersize:19;
55460 +/** Max packet count for EP (pow(2,10)-1) */
55461 +#define MAX_PKT_CNT 1023
55462 + /** Packet Count */
55463 + unsigned pktcnt:10;
55464 + /** Multi Count - Periodic IN endpoints */
55466 + unsigned reserved:1;
55471 + * This union represents the bit fields in the Device EP 0 Transfer
55472 + * Size Register. Read the register into the <i>d32</i> member then
55473 + * set/clear the bits using the <i>b</i>it elements.
55475 +typedef union deptsiz0_data {
55476 + /** raw register data */
55478 + /** register bits */
55480 + /** Transfer size */
55481 + unsigned xfersize:7;
55483 + unsigned reserved7_18:12;
55484 + /** Packet Count */
55485 + unsigned pktcnt:2;
55487 + unsigned reserved21_28:8;
55488 + /**Setup Packet Count (DOEPTSIZ0 Only) */
55489 + unsigned supcnt:2;
55490 + unsigned reserved31;
55492 +} deptsiz0_data_t;
55494 +/////////////////////////////////////////////////
55495 +// DMA Descriptor Specific Structures
55498 +/** Buffer status definitions */
55500 +#define BS_HOST_READY 0x0
55501 +#define BS_DMA_BUSY 0x1
55502 +#define BS_DMA_DONE 0x2
55503 +#define BS_HOST_BUSY 0x3
55505 +/** Receive/Transmit status definitions */
55507 +#define RTS_SUCCESS 0x0
55508 +#define RTS_BUFFLUSH 0x1
55509 +#define RTS_RESERVED 0x2
55510 +#define RTS_BUFERR 0x3
55513 + * This union represents the bit fields in the DMA Descriptor
55514 + * status quadlet. Read the quadlet into the <i>d32</i> member then
55515 + * set/clear the bits using the <i>b</i>it, <i>b_iso_out</i> and
55516 + * <i>b_iso_in</i> elements.
55518 +typedef union dev_dma_desc_sts {
55519 + /** raw register data */
55521 + /** quadlet bits */
55523 + /** Received number of bytes */
55524 + unsigned bytes:16;
55525 + /** NAK bit - only for OUT EPs */
55527 + unsigned reserved17_22:6;
55528 + /** Multiple Transfer - only for OUT EPs */
55530 + /** Setup Packet received - only for OUT EPs */
55532 + /** Interrupt On Complete */
55534 + /** Short Packet */
55538 + /** Receive Status */
55540 + /** Buffer Status */
55544 +//#ifdef DWC_EN_ISOC
55545 + /** iso out quadlet bits */
55547 + /** Received number of bytes */
55548 + unsigned rxbytes:11;
55550 + unsigned reserved11:1;
55551 + /** Frame Number */
55552 + unsigned framenum:11;
55553 + /** Received ISO Data PID */
55555 + /** Interrupt On Complete */
55557 + /** Short Packet */
55561 + /** Receive Status */
55562 + unsigned rxsts:2;
55563 + /** Buffer Status */
55567 + /** iso in quadlet bits */
55569 + /** Transmited number of bytes */
55570 + unsigned txbytes:12;
55571 + /** Frame Number */
55572 + unsigned framenum:11;
55573 + /** Transmited ISO Data PID */
55575 + /** Interrupt On Complete */
55577 + /** Short Packet */
55581 + /** Transmit Status */
55582 + unsigned txsts:2;
55583 + /** Buffer Status */
55586 +//#endif /* DWC_EN_ISOC */
55587 +} dev_dma_desc_sts_t;
55590 + * DMA Descriptor structure
55592 + * DMA Descriptor structure contains two quadlets:
55593 + * Status quadlet and Data buffer pointer.
55595 +typedef struct dwc_otg_dev_dma_desc {
55596 + /** DMA Descriptor status quadlet */
55597 + dev_dma_desc_sts_t status;
55598 + /** DMA Descriptor data buffer pointer */
55600 +} dwc_otg_dev_dma_desc_t;
55603 + * The dwc_otg_dev_if structure contains information needed to manage
55604 + * the DWC_otg controller acting in device mode. It represents the
55605 + * programming view of the device-specific aspects of the controller.
55607 +typedef struct dwc_otg_dev_if {
55608 + /** Pointer to device Global registers.
55609 + * Device Global Registers starting at offset 800h
55611 + dwc_otg_device_global_regs_t *dev_global_regs;
55612 +#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
55615 + * Device Logical IN Endpoint-Specific Registers 900h-AFCh
55617 + dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS];
55618 +#define DWC_DEV_IN_EP_REG_OFFSET 0x900
55619 +#define DWC_EP_REG_OFFSET 0x20
55621 + /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
55622 + dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];
55623 +#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
55625 + /* Device configuration information */
55626 + uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */
55627 + uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */
55628 + uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/
55630 + /** Size of periodic FIFOs (Bytes) */
55631 + uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS];
55633 + /** Size of Tx FIFOs (Bytes) */
55634 + uint16_t tx_fifo_size[MAX_TX_FIFOS];
55636 + /** Thresholding enable flags and length varaiables **/
55637 + uint16_t rx_thr_en;
55638 + uint16_t iso_tx_thr_en;
55639 + uint16_t non_iso_tx_thr_en;
55641 + uint16_t rx_thr_length;
55642 + uint16_t tx_thr_length;
55645 + * Pointers to the DMA Descriptors for EP0 Control
55646 + * transfers (virtual and physical)
55649 + /** 2 descriptors for SETUP packets */
55650 + dwc_dma_t dma_setup_desc_addr[2];
55651 + dwc_otg_dev_dma_desc_t *setup_desc_addr[2];
55653 + /** Pointer to Descriptor with latest SETUP packet */
55654 + dwc_otg_dev_dma_desc_t *psetup;
55656 + /** Index of current SETUP handler descriptor */
55657 + uint32_t setup_desc_index;
55659 + /** Descriptor for Data In or Status In phases */
55660 + dwc_dma_t dma_in_desc_addr;
55661 + dwc_otg_dev_dma_desc_t *in_desc_addr;
55663 + /** Descriptor for Data Out or Status Out phases */
55664 + dwc_dma_t dma_out_desc_addr;
55665 + dwc_otg_dev_dma_desc_t *out_desc_addr;
55667 + /** Setup Packet Detected - if set clear NAK when queueing */
55669 + /** Isoc ep pointer on which incomplete happens */
55672 +} dwc_otg_dev_if_t;
55674 +/////////////////////////////////////////////////
55675 +// Host Mode Register Structures
55678 + * The Host Global Registers structure defines the size and relative
55679 + * field offsets for the Host Mode Global Registers. Host Global
55680 + * Registers offsets 400h-7FFh.
55682 +typedef struct dwc_otg_host_global_regs {
55683 + /** Host Configuration Register. <i>Offset: 400h</i> */
55684 + volatile uint32_t hcfg;
55685 + /** Host Frame Interval Register. <i>Offset: 404h</i> */
55686 + volatile uint32_t hfir;
55687 + /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */
55688 + volatile uint32_t hfnum;
55689 + /** Reserved. <i>Offset: 40Ch</i> */
55690 + uint32_t reserved40C;
55691 + /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */
55692 + volatile uint32_t hptxsts;
55693 + /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */
55694 + volatile uint32_t haint;
55695 + /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */
55696 + volatile uint32_t haintmsk;
55697 + /** Host Frame List Base Address Register . <i>Offset: 41Ch</i> */
55698 + volatile uint32_t hflbaddr;
55699 +} dwc_otg_host_global_regs_t;
55702 + * This union represents the bit fields in the Host Configuration Register.
55703 + * Read the register into the <i>d32</i> member then set/clear the bits using
55704 + * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register.
55706 +typedef union hcfg_data {
55707 + /** raw register data */
55710 + /** register bits */
55712 + /** FS/LS Phy Clock Select */
55713 + unsigned fslspclksel:2;
55714 +#define DWC_HCFG_30_60_MHZ 0
55715 +#define DWC_HCFG_48_MHZ 1
55716 +#define DWC_HCFG_6_MHZ 2
55718 + /** FS/LS Only Support */
55719 + unsigned fslssupp:1;
55720 + unsigned reserved3_6:4;
55721 + /** Enable 32-KHz Suspend Mode */
55722 + unsigned ena32khzs:1;
55723 + /** Resume Validation Periiod */
55724 + unsigned resvalid:8;
55725 + unsigned reserved16_22:7;
55726 + /** Enable Scatter/gather DMA in Host mode */
55727 + unsigned descdma:1;
55728 + /** Frame List Entries */
55729 + unsigned frlisten:2;
55730 + /** Enable Periodic Scheduling */
55731 + unsigned perschedena:1;
55732 + unsigned reserved27_30:4;
55733 + unsigned modechtimen:1;
55738 + * This union represents the bit fields in the Host Frame Remaing/Number
55741 +typedef union hfir_data {
55742 + /** raw register data */
55745 + /** register bits */
55747 + unsigned frint:16;
55748 + unsigned hfirrldctrl:1;
55749 + unsigned reserved:15;
55754 + * This union represents the bit fields in the Host Frame Remaing/Number
55757 +typedef union hfnum_data {
55758 + /** raw register data */
55761 + /** register bits */
55763 + unsigned frnum:16;
55764 +#define DWC_HFNUM_MAX_FRNUM 0x3FFF
55765 + unsigned frrem:16;
55769 +typedef union hptxsts_data {
55770 + /** raw register data */
55773 + /** register bits */
55775 + unsigned ptxfspcavail:16;
55776 + unsigned ptxqspcavail:8;
55777 + /** Top of the Periodic Transmit Request Queue
55778 + * - bit 24 - Terminate (last entry for the selected channel)
55779 + * - bits 26:25 - Token Type
55780 + * - 2'b00 - Zero length
55782 + * - 2'b10 - Disable
55783 + * - bits 30:27 - Channel Number
55784 + * - bit 31 - Odd/even microframe
55786 + unsigned ptxqtop_terminate:1;
55787 + unsigned ptxqtop_token:2;
55788 + unsigned ptxqtop_chnum:4;
55789 + unsigned ptxqtop_odd:1;
55794 + * This union represents the bit fields in the Host Port Control and Status
55795 + * Register. Read the register into the <i>d32</i> member then set/clear the
55796 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55797 + * hprt0 register.
55799 +typedef union hprt0_data {
55800 + /** raw register data */
55802 + /** register bits */
55804 + unsigned prtconnsts:1;
55805 + unsigned prtconndet:1;
55806 + unsigned prtena:1;
55807 + unsigned prtenchng:1;
55808 + unsigned prtovrcurract:1;
55809 + unsigned prtovrcurrchng:1;
55810 + unsigned prtres:1;
55811 + unsigned prtsusp:1;
55812 + unsigned prtrst:1;
55813 + unsigned reserved9:1;
55814 + unsigned prtlnsts:2;
55815 + unsigned prtpwr:1;
55816 + unsigned prttstctl:4;
55817 + unsigned prtspd:2;
55818 +#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
55819 +#define DWC_HPRT0_PRTSPD_FULL_SPEED 1
55820 +#define DWC_HPRT0_PRTSPD_LOW_SPEED 2
55821 + unsigned reserved19_31:13;
55826 + * This union represents the bit fields in the Host All Interrupt
55829 +typedef union haint_data {
55830 + /** raw register data */
55832 + /** register bits */
55850 + unsigned reserved:16;
55854 + unsigned chint:16;
55855 + unsigned reserved:16;
55860 + * This union represents the bit fields in the Host All Interrupt
55863 +typedef union haintmsk_data {
55864 + /** raw register data */
55866 + /** register bits */
55884 + unsigned reserved:16;
55888 + unsigned chint:16;
55889 + unsigned reserved:16;
55891 +} haintmsk_data_t;
55894 + * Host Channel Specific Registers. <i>500h-5FCh</i>
55896 +typedef struct dwc_otg_hc_regs {
55897 + /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */
55898 + volatile uint32_t hcchar;
55899 + /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */
55900 + volatile uint32_t hcsplt;
55901 + /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */
55902 + volatile uint32_t hcint;
55903 + /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */
55904 + volatile uint32_t hcintmsk;
55905 + /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */
55906 + volatile uint32_t hctsiz;
55907 + /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */
55908 + volatile uint32_t hcdma;
55909 + volatile uint32_t reserved;
55910 + /** Host Channel 0 DMA Buffer Address Register. <i>Offset: 500h + (chan_num * 20h) + 1Ch</i> */
55911 + volatile uint32_t hcdmab;
55912 +} dwc_otg_hc_regs_t;
55915 + * This union represents the bit fields in the Host Channel Characteristics
55916 + * Register. Read the register into the <i>d32</i> member then set/clear the
55917 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
55918 + * hcchar register.
55920 +typedef union hcchar_data {
55921 + /** raw register data */
55924 + /** register bits */
55926 + /** Maximum packet size in bytes */
55929 + /** Endpoint number */
55930 + unsigned epnum:4;
55932 + /** 0: OUT, 1: IN */
55933 + unsigned epdir:1;
55935 + unsigned reserved:1;
55937 + /** 0: Full/high speed device, 1: Low speed device */
55938 + unsigned lspddev:1;
55940 + /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
55941 + unsigned eptype:2;
55943 + /** Packets per frame for periodic transfers. 0 is reserved. */
55944 + unsigned multicnt:2;
55946 + /** Device address */
55947 + unsigned devaddr:7;
55950 + * Frame to transmit periodic transaction.
55951 + * 0: even, 1: odd
55953 + unsigned oddfrm:1;
55955 + /** Channel disable */
55956 + unsigned chdis:1;
55958 + /** Channel enable */
55963 +typedef union hcsplt_data {
55964 + /** raw register data */
55967 + /** register bits */
55969 + /** Port Address */
55970 + unsigned prtaddr:7;
55972 + /** Hub Address */
55973 + unsigned hubaddr:7;
55975 + /** Transaction Position */
55976 + unsigned xactpos:2;
55977 +#define DWC_HCSPLIT_XACTPOS_MID 0
55978 +#define DWC_HCSPLIT_XACTPOS_END 1
55979 +#define DWC_HCSPLIT_XACTPOS_BEGIN 2
55980 +#define DWC_HCSPLIT_XACTPOS_ALL 3
55982 + /** Do Complete Split */
55983 + unsigned compsplt:1;
55986 + unsigned reserved:14;
55988 + /** Split Enble */
55989 + unsigned spltena:1;
55994 + * This union represents the bit fields in the Host All Interrupt
55997 +typedef union hcint_data {
55998 + /** raw register data */
56000 + /** register bits */
56002 + /** Transfer Complete */
56003 + unsigned xfercomp:1;
56004 + /** Channel Halted */
56005 + unsigned chhltd:1;
56007 + unsigned ahberr:1;
56008 + /** STALL Response Received */
56009 + unsigned stall:1;
56010 + /** NAK Response Received */
56012 + /** ACK Response Received */
56014 + /** NYET Response Received */
56016 + /** Transaction Err */
56017 + unsigned xacterr:1;
56018 + /** Babble Error */
56019 + unsigned bblerr:1;
56020 + /** Frame Overrun */
56021 + unsigned frmovrun:1;
56022 + /** Data Toggle Error */
56023 + unsigned datatglerr:1;
56024 + /** Buffer Not Available (only for DDMA mode) */
56026 + /** Exessive transaction error (only for DDMA mode) */
56027 + unsigned xcs_xact:1;
56028 + /** Frame List Rollover interrupt */
56029 + unsigned frm_list_roll:1;
56031 + unsigned reserved14_31:18;
56036 + * This union represents the bit fields in the Host Channel Interrupt Mask
56037 + * Register. Read the register into the <i>d32</i> member then set/clear the
56038 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
56039 + * hcintmsk register.
56041 +typedef union hcintmsk_data {
56042 + /** raw register data */
56045 + /** register bits */
56047 + unsigned xfercompl:1;
56048 + unsigned chhltd:1;
56049 + unsigned ahberr:1;
56050 + unsigned stall:1;
56054 + unsigned xacterr:1;
56055 + unsigned bblerr:1;
56056 + unsigned frmovrun:1;
56057 + unsigned datatglerr:1;
56059 + unsigned xcs_xact:1;
56060 + unsigned frm_list_roll:1;
56061 + unsigned reserved14_31:18;
56063 +} hcintmsk_data_t;
56066 + * This union represents the bit fields in the Host Channel Transfer Size
56067 + * Register. Read the register into the <i>d32</i> member then set/clear the
56068 + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
56069 + * hcchar register.
56072 +typedef union hctsiz_data {
56073 + /** raw register data */
56076 + /** register bits */
56078 + /** Total transfer size in bytes */
56079 + unsigned xfersize:19;
56081 + /** Data packets to transfer */
56082 + unsigned pktcnt:10;
56085 + * Packet ID for next data packet
56089 + * 3: MDATA (non-Control), SETUP (Control)
56092 +#define DWC_HCTSIZ_DATA0 0
56093 +#define DWC_HCTSIZ_DATA1 2
56094 +#define DWC_HCTSIZ_DATA2 1
56095 +#define DWC_HCTSIZ_MDATA 3
56096 +#define DWC_HCTSIZ_SETUP 3
56098 + /** Do PING protocol when 1 */
56099 + unsigned dopng:1;
56102 + /** register bits */
56104 + /** Scheduling information */
56105 + unsigned schinfo:8;
56107 + /** Number of transfer descriptors.
56110 + * 256 only for HS isochronous endpoint.
56114 + /** Data packets to transfer */
56115 + unsigned reserved16_28:13;
56118 + * Packet ID for next data packet
56122 + * 3: MDATA (non-Control)
56126 + /** Do PING protocol when 1 */
56127 + unsigned dopng:1;
56132 + * This union represents the bit fields in the Host DMA Address
56133 + * Register used in Descriptor DMA mode.
56135 +typedef union hcdma_data {
56136 + /** raw register data */
56138 + /** register bits */
56140 + unsigned reserved0_2:3;
56141 + /** Current Transfer Descriptor. Not used for ISOC */
56143 + /** Start Address of Descriptor List */
56144 + unsigned dma_addr:21;
56149 + * This union represents the bit fields in the DMA Descriptor
56150 + * status quadlet for host mode. Read the quadlet into the <i>d32</i> member then
56151 + * set/clear the bits using the <i>b</i>it elements.
56153 +typedef union host_dma_desc_sts {
56154 + /** raw register data */
56156 + /** quadlet bits */
56158 + /* for non-isochronous */
56160 + /** Number of bytes */
56161 + unsigned n_bytes:17;
56162 + /** QTD offset to jump when Short Packet received - only for IN EPs */
56163 + unsigned qtd_offset:6;
56165 + * Set to request the core to jump to alternate QTD if
56166 + * Short Packet received - only for IN EPs
56168 + unsigned a_qtd:1;
56170 + * Setup Packet bit. When set indicates that buffer contains
56174 + /** Interrupt On Complete */
56176 + /** End of List */
56178 + unsigned reserved27:1;
56179 + /** Rx/Tx Status */
56181 +#define DMA_DESC_STS_PKTERR 1
56182 + unsigned reserved30:1;
56183 + /** Active Bit */
56186 + /* for isochronous */
56188 + /** Number of bytes */
56189 + unsigned n_bytes:12;
56190 + unsigned reserved12_24:13;
56191 + /** Interrupt On Complete */
56193 + unsigned reserved26_27:2;
56194 + /** Rx/Tx Status */
56196 + unsigned reserved30:1;
56197 + /** Active Bit */
56200 +} host_dma_desc_sts_t;
56202 +#define MAX_DMA_DESC_SIZE 131071
56203 +#define MAX_DMA_DESC_NUM_GENERIC 64
56204 +#define MAX_DMA_DESC_NUM_HS_ISOC 256
56205 +#define MAX_FRLIST_EN_NUM 64
56207 + * Host-mode DMA Descriptor structure
56209 + * DMA Descriptor structure contains two quadlets:
56210 + * Status quadlet and Data buffer pointer.
56212 +typedef struct dwc_otg_host_dma_desc {
56213 + /** DMA Descriptor status quadlet */
56214 + host_dma_desc_sts_t status;
56215 + /** DMA Descriptor data buffer pointer */
56217 +} dwc_otg_host_dma_desc_t;
56219 +/** OTG Host Interface Structure.
56221 + * The OTG Host Interface Structure structure contains information
56222 + * needed to manage the DWC_otg controller acting in host mode. It
56223 + * represents the programming view of the host-specific aspects of the
56226 +typedef struct dwc_otg_host_if {
56227 + /** Host Global Registers starting at offset 400h.*/
56228 + dwc_otg_host_global_regs_t *host_global_regs;
56229 +#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
56231 + /** Host Port 0 Control and Status Register */
56232 + volatile uint32_t *hprt0;
56233 +#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
56235 + /** Host Channel Specific Registers at offsets 500h-5FCh. */
56236 + dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS];
56237 +#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
56238 +#define DWC_OTG_CHAN_REGS_OFFSET 0x20
56240 + /* Host configuration information */
56241 + /** Number of Host Channels (range: 1-16) */
56242 + uint8_t num_host_channels;
56243 + /** Periodic EPs supported (0: no, 1: yes) */
56244 + uint8_t perio_eps_supported;
56245 + /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */
56246 + uint16_t perio_tx_fifo_size;
56248 +} dwc_otg_host_if_t;
56251 + * This union represents the bit fields in the Power and Clock Gating Control
56252 + * Register. Read the register into the <i>d32</i> member then set/clear the
56253 + * bits using the <i>b</i>it elements.
56255 +typedef union pcgcctl_data {
56256 + /** raw register data */
56259 + /** register bits */
56262 + unsigned stoppclk:1;
56264 + unsigned gatehclk:1;
56265 + /** Power Clamp */
56266 + unsigned pwrclmp:1;
56267 + /** Reset Power Down Modules */
56268 + unsigned rstpdwnmodule:1;
56270 + unsigned reserved:1;
56271 + /** Enable Sleep Clock Gating (Enbl_L1Gating) */
56272 + unsigned enbl_sleep_gating:1;
56273 + /** PHY In Sleep (PhySleep) */
56274 + unsigned phy_in_sleep:1;
56276 + unsigned deep_sleep:1;
56277 + unsigned resetaftsusp:1;
56278 + unsigned restoremode:1;
56279 + unsigned enbl_extnd_hiber:1;
56280 + unsigned extnd_hiber_pwrclmp:1;
56281 + unsigned extnd_hiber_switch:1;
56282 + unsigned ess_reg_restored:1;
56283 + unsigned prt_clk_sel:2;
56284 + unsigned port_power:1;
56285 + unsigned max_xcvrselect:2;
56286 + unsigned max_termsel:1;
56287 + unsigned mac_dev_addr:7;
56288 + unsigned p2hd_dev_enum_spd:2;
56289 + unsigned p2hd_prt_spd:2;
56290 + unsigned if_dev_mode:1;
56295 + * This union represents the bit fields in the Global Data FIFO Software
56296 + * Configuration Register. Read the register into the <i>d32</i> member then
56297 + * set/clear the bits using the <i>b</i>it elements.
56299 +typedef union gdfifocfg_data {
56300 + /* raw register data */
56302 + /** register bits */
56304 + /** OTG Data FIFO depth */
56305 + unsigned gdfifocfg:16;
56306 + /** Start address of EP info controller */
56307 + unsigned epinfobase:16;
56309 +} gdfifocfg_data_t;
56312 + * This union represents the bit fields in the Global Power Down Register
56313 + * Register. Read the register into the <i>d32</i> member then set/clear the
56314 + * bits using the <i>b</i>it elements.
56316 +typedef union gpwrdn_data {
56317 + /* raw register data */
56320 + /** register bits */
56322 + /** PMU Interrupt Select */
56323 + unsigned pmuintsel:1;
56324 + /** PMU Active */
56325 + unsigned pmuactv:1;
56327 + unsigned restore:1;
56328 + /** Power Down Clamp */
56329 + unsigned pwrdnclmp:1;
56330 + /** Power Down Reset */
56331 + unsigned pwrdnrstn:1;
56332 + /** Power Down Switch */
56333 + unsigned pwrdnswtch:1;
56334 + /** Disable VBUS */
56335 + unsigned dis_vbus:1;
56336 + /** Line State Change */
56337 + unsigned lnstschng:1;
56338 + /** Line state change mask */
56339 + unsigned lnstchng_msk:1;
56340 + /** Reset Detected */
56341 + unsigned rst_det:1;
56342 + /** Reset Detect mask */
56343 + unsigned rst_det_msk:1;
56344 + /** Disconnect Detected */
56345 + unsigned disconn_det:1;
56346 + /** Disconnect Detect mask */
56347 + unsigned disconn_det_msk:1;
56348 + /** Connect Detected*/
56349 + unsigned connect_det:1;
56350 + /** Connect Detected Mask*/
56351 + unsigned connect_det_msk:1;
56352 + /** SRP Detected */
56353 + unsigned srp_det:1;
56354 + /** SRP Detect mask */
56355 + unsigned srp_det_msk:1;
56356 + /** Status Change Interrupt */
56357 + unsigned sts_chngint:1;
56358 + /** Status Change Interrupt Mask */
56359 + unsigned sts_chngint_msk:1;
56360 + /** Line State */
56361 + unsigned linestate:2;
56362 + /** Indicates current mode(status of IDDIG signal) */
56363 + unsigned idsts:1;
56364 + /** B Session Valid signal status*/
56365 + unsigned bsessvld:1;
56366 + /** ADP Event Detected */
56367 + unsigned adp_int:1;
56368 + /** Multi Valued ID pin */
56369 + unsigned mult_val_id_bc:5;
56370 + /** Reserved 24_31 */
56371 + unsigned reserved29_31:3;
56376 diff --git a/drivers/usb/host/dwc_otg/test/Makefile b/drivers/usb/host/dwc_otg/test/Makefile
56377 new file mode 100644
56378 index 0000000..fc45375
56380 +++ b/drivers/usb/host/dwc_otg/test/Makefile
56383 +PERL=/usr/bin/perl
56384 +PL_TESTS=test_sysfs.pl test_mod_param.pl
56391 + @echo Running perl tests
56392 + @for test in $(PL_TESTS); do \
56393 + if $(PERL) ./$$test ; then \
56394 + echo "=======> $$test, PASSED" ; \
56395 + else echo "=======> $$test, FAILED" ; \
56398 diff --git a/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm b/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
56399 new file mode 100644
56400 index 0000000..233b04a
56402 +++ b/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
56404 +package dwc_otg_test;
56409 +use vars qw(@ISA @EXPORT
56410 +$sysfsdir $paramdir $errors $params
56413 +@ISA = qw(Exporter);
56418 +$sysfsdir = "/sys/devices/lm0";
56419 +$paramdir = "/sys/module/dwc_otg";
56424 + NAME => "otg_cap",
56431 + NAME => "dma_enable",
56438 + NAME => "dma_burst_size",
56440 + ENUM => [1, 4, 8, 16, 32, 64, 128, 256],
56445 + NAME => "host_speed",
56452 + NAME => "host_support_fs_ls_low_power",
56459 + NAME => "host_ls_low_power_phy_clk",
56466 + NAME => "dev_speed",
56473 + NAME => "enable_dynamic_fifo",
56480 + NAME => "data_fifo_size",
56487 + NAME => "dev_rx_fifo_size",
56494 + NAME => "dev_nperio_tx_fifo_size",
56501 + NAME => "dev_perio_tx_fifo_size_1",
56508 + NAME => "dev_perio_tx_fifo_size_2",
56515 + NAME => "dev_perio_tx_fifo_size_3",
56522 + NAME => "dev_perio_tx_fifo_size_4",
56529 + NAME => "dev_perio_tx_fifo_size_5",
56536 + NAME => "dev_perio_tx_fifo_size_6",
56543 + NAME => "dev_perio_tx_fifo_size_7",
56550 + NAME => "dev_perio_tx_fifo_size_8",
56557 + NAME => "dev_perio_tx_fifo_size_9",
56564 + NAME => "dev_perio_tx_fifo_size_10",
56571 + NAME => "dev_perio_tx_fifo_size_11",
56578 + NAME => "dev_perio_tx_fifo_size_12",
56585 + NAME => "dev_perio_tx_fifo_size_13",
56592 + NAME => "dev_perio_tx_fifo_size_14",
56599 + NAME => "dev_perio_tx_fifo_size_15",
56606 + NAME => "host_rx_fifo_size",
56613 + NAME => "host_nperio_tx_fifo_size",
56620 + NAME => "host_perio_tx_fifo_size",
56627 + NAME => "max_transfer_size",
56628 + DEFAULT => 65535,
56634 + NAME => "max_packet_count",
56641 + NAME => "host_channels",
56648 + NAME => "dev_endpoints",
56655 + NAME => "phy_type",
56662 + NAME => "phy_utmi_width",
56669 + NAME => "phy_ulpi_ddr",
56683 + unless (m/armv4tl/) {
56684 + warn "# \n# Can't execute on $_. Run on integrator platform.\n# \n";
56693 + my $params = shift;
56694 + print "\nRemoving Module\n";
56695 + system "rmmod dwc_otg";
56696 + print "Loading Module\n";
56697 + if ($params ne "") {
56698 + print "Module Parameters: $params\n";
56700 + if (system("modprobe dwc_otg $params")) {
56701 + warn "Unable to load module\n";
56714 + if (defined $arg) {
56715 + warn "WARNING: $arg\n";
56718 + if ($errors > 0) {
56719 + warn "TEST FAILED with $errors errors\n";
56722 + print "TEST PASSED\n";
56723 + return 0 if (defined $arg);
56741 diff --git a/drivers/usb/host/dwc_otg/test/test_mod_param.pl b/drivers/usb/host/dwc_otg/test/test_mod_param.pl
56742 new file mode 100644
56743 index 0000000..e887dce
56745 +++ b/drivers/usb/host/dwc_otg/test/test_mod_param.pl
56747 +#!/usr/bin/perl -w
56749 +# Run this program on the integrator.
56751 +# - Tests module parameter default values.
56752 +# - Tests setting of valid module parameter values via modprobe.
56753 +# - Tests invalid module parameter values.
56754 +# -----------------------------------------------------------------------------
56758 +check_arch() or die;
56763 + my ($param,$expected) = @_;
56764 + my $value = get($param);
56766 + if ($value == $expected) {
56767 + print "$param = $value, okay\n";
56771 + warn "ERROR: value of $param != $expected, $value\n";
56779 + my $param = shift;
56780 + my $tmp = `cat $paramdir/$param`;
56789 + print "\nTesting Module Parameters\n";
56791 + load_module("") or die;
56793 + # Test initial values
56794 + print "\nTesting Default Values\n";
56795 + foreach (@{$params}) {
56796 + test ($_->{NAME}, $_->{DEFAULT});
56800 + print "\nTesting Low Value\n";
56801 + my $cmd_params = "";
56802 + foreach (@{$params}) {
56803 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{LOW} ";
56805 + load_module($cmd_params) or die;
56807 + foreach (@{$params}) {
56808 + test ($_->{NAME}, $_->{LOW});
56811 + # Test high value
56812 + print "\nTesting High Value\n";
56813 + $cmd_params = "";
56814 + foreach (@{$params}) {
56815 + $cmd_params = $cmd_params . "$_->{NAME}=$_->{HIGH} ";
56817 + load_module($cmd_params) or die;
56819 + foreach (@{$params}) {
56820 + test ($_->{NAME}, $_->{HIGH});
56824 + print "\nTesting Enumerated\n";
56825 + foreach (@{$params}) {
56826 + if (defined $_->{ENUM}) {
56828 + foreach $value (@{$_->{ENUM}}) {
56829 + $cmd_params = "$_->{NAME}=$value";
56830 + load_module($cmd_params) or die;
56831 + test ($_->{NAME}, $value);
56836 + # Test Invalid Values
56837 + print "\nTesting Invalid Values\n";
56838 + $cmd_params = "";
56839 + foreach (@{$params}) {
56840 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{LOW}-1;
56842 + load_module($cmd_params) or die;
56844 + foreach (@{$params}) {
56845 + test ($_->{NAME}, $_->{DEFAULT});
56848 + $cmd_params = "";
56849 + foreach (@{$params}) {
56850 + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{HIGH}+1;
56852 + load_module($cmd_params) or die;
56854 + foreach (@{$params}) {
56855 + test ($_->{NAME}, $_->{DEFAULT});
56858 + print "\nTesting Enumerated\n";
56859 + foreach (@{$params}) {
56860 + if (defined $_->{ENUM}) {
56862 + foreach $value (@{$_->{ENUM}}) {
56863 + $value = $value + 1;
56864 + $cmd_params = "$_->{NAME}=$value";
56865 + load_module($cmd_params) or die;
56866 + test ($_->{NAME}, $_->{DEFAULT});
56867 + $value = $value - 2;
56868 + $cmd_params = "$_->{NAME}=$value";
56869 + load_module($cmd_params) or die;
56870 + test ($_->{NAME}, $_->{DEFAULT});
56875 + test_status() or die;
56880 diff --git a/drivers/usb/host/dwc_otg/test/test_sysfs.pl b/drivers/usb/host/dwc_otg/test/test_sysfs.pl
56881 new file mode 100644
56882 index 0000000..abcf284
56884 +++ b/drivers/usb/host/dwc_otg/test/test_sysfs.pl
56886 +#!/usr/bin/perl -w
56888 +# Run this program on the integrator
56889 +# - Tests select sysfs attributes.
56890 +# - Todo ... test more attributes, hnp/srp, buspower/bussuspend, etc.
56891 +# -----------------------------------------------------------------------------
56895 +check_arch() or die;
56900 + my ($attr,$expected) = @_;
56901 + my $string = get($attr);
56903 + if ($string eq $expected) {
56904 + printf("$attr = $string, okay\n");
56907 + warn "ERROR: value of $attr != $expected, $string\n";
56915 + my ($reg, $value) = @_;
56916 + system "echo $value > $sysfsdir/$reg";
56922 + my $attr = shift;
56923 + my $string = `cat $sysfsdir/$attr`;
56925 + if ($string =~ m/\s\=\s/) {
56927 + ($tmp, $string) = split /\s=\s/, $string;
56935 + print("\nTesting Sysfs Attributes\n");
56937 + load_module("") or die;
56939 + # Test initial values of regoffset/regvalue/guid/gsnpsid
56940 + print("\nTesting Default Values\n");
56942 + test("regoffset", "0xffffffff");
56943 + test("regvalue", "invalid offset");
56944 + test("guid", "0x12345678"); # this will fail if it has been changed
56945 + test("gsnpsid", "0x4f54200a");
56947 + # Test operation of regoffset/regvalue
56948 + print("\nTesting regoffset\n");
56949 + set('regoffset', '5a5a5a5a');
56950 + test("regoffset", "0xffffffff");
56952 + set('regoffset', '0');
56953 + test("regoffset", "0x00000000");
56955 + set('regoffset', '40000');
56956 + test("regoffset", "0x00000000");
56958 + set('regoffset', '3ffff');
56959 + test("regoffset", "0x0003ffff");
56961 + set('regoffset', '1');
56962 + test("regoffset", "0x00000001");
56964 + print("\nTesting regvalue\n");
56965 + set('regoffset', '3c');
56966 + test("regvalue", "0x12345678");
56967 + set('regvalue', '5a5a5a5a');
56968 + test("regvalue", "0x5a5a5a5a");
56969 + set('regvalue','a5a5a5a5');
56970 + test("regvalue", "0xa5a5a5a5");
56971 + set('guid','12345678');
56973 + # Test HNP Capable
56974 + print("\nTesting HNP Capable bit\n");
56975 + set('hnpcapable', '1');
56976 + test("hnpcapable", "0x1");
56977 + set('hnpcapable','0');
56978 + test("hnpcapable", "0x0");
56980 + set('regoffset','0c');
56982 + my $old = get('gusbcfg');
56983 + print("setting hnpcapable\n");
56984 + set('hnpcapable', '1');
56985 + test("hnpcapable", "0x1");
56986 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<9)));
56987 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<9)));
56989 + $old = get('gusbcfg');
56990 + print("clearing hnpcapable\n");
56991 + set('hnpcapable', '0');
56992 + test("hnpcapable", "0x0");
56993 + test ('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<9)));
56994 + test ('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<9)));
56996 + # Test SRP Capable
56997 + print("\nTesting SRP Capable bit\n");
56998 + set('srpcapable', '1');
56999 + test("srpcapable", "0x1");
57000 + set('srpcapable','0');
57001 + test("srpcapable", "0x0");
57003 + set('regoffset','0c');
57005 + $old = get('gusbcfg');
57006 + print("setting srpcapable\n");
57007 + set('srpcapable', '1');
57008 + test("srpcapable", "0x1");
57009 + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<8)));
57010 + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<8)));
57012 + $old = get('gusbcfg');
57013 + print("clearing srpcapable\n");
57014 + set('srpcapable', '0');
57015 + test("srpcapable", "0x0");
57016 + test('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<8)));
57017 + test('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<8)));
57020 + print("\nTesting GGPIO\n");
57021 + set('ggpio','5a5a5a5a');
57022 + test('ggpio','0x5a5a0000');
57023 + set('ggpio','a5a5a5a5');
57024 + test('ggpio','0xa5a50000');
57025 + set('ggpio','11110000');
57026 + test('ggpio','0x11110000');
57027 + set('ggpio','00001111');
57028 + test('ggpio','0x00000000');
57031 + print("\nTesting DEVSPEED\n");
57032 + set('regoffset','800');
57033 + $old = get('regvalue');
57034 + set('devspeed','0');
57035 + test('devspeed','0x0');
57036 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
57037 + set('devspeed','1');
57038 + test('devspeed','0x1');
57039 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
57040 + set('devspeed','2');
57041 + test('devspeed','0x2');
57042 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 2));
57043 + set('devspeed','3');
57044 + test('devspeed','0x3');
57045 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 3));
57046 + set('devspeed','4');
57047 + test('devspeed','0x0');
57048 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
57049 + set('devspeed','5');
57050 + test('devspeed','0x1');
57051 + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
57054 + # mode Returns the current mode:0 for device mode1 for host mode Read
57055 + # hnp Initiate the Host Negotiation Protocol. Read returns the status. Read/Write
57056 + # srp Initiate the Session Request Protocol. Read returns the status. Read/Write
57057 + # buspower Get or Set the Power State of the bus (0 - Off or 1 - On) Read/Write
57058 + # bussuspend Suspend the USB bus. Read/Write
57059 + # busconnected Get the connection status of the bus Read
57061 + # gotgctl Get or set the Core Control Status Register. Read/Write
57062 + ## gusbcfg Get or set the Core USB Configuration Register Read/Write
57063 + # grxfsiz Get or set the Receive FIFO Size Register Read/Write
57064 + # gnptxfsiz Get or set the non-periodic Transmit Size Register Read/Write
57065 + # gpvndctl Get or set the PHY Vendor Control Register Read/Write
57066 + ## ggpio Get the value in the lower 16-bits of the General Purpose IO Register or Set the upper 16 bits. Read/Write
57067 + ## guid Get or set the value of the User ID Register Read/Write
57068 + ## gsnpsid Get the value of the Synopsys ID Regester Read
57069 + ## devspeed Get or set the device speed setting in the DCFG register Read/Write
57070 + # enumspeed Gets the device enumeration Speed. Read
57071 + # hptxfsiz Get the value of the Host Periodic Transmit FIFO Read
57072 + # hprt0 Get or Set the value in the Host Port Control and Status Register Read/Write
57074 + test_status("TEST NYI") or die;